diff --git a/README.md b/README.md index 87cf1c639..5f07f45e3 100644 --- a/README.md +++ b/README.md @@ -128,5 +128,3 @@ Nightly builds of Ship of Harkinian are available [here](https://builds.shipofha MicTheMicrophone | Gwonam / The King Amphibibro | Link AceHeart | Zelda - -###### Lemons diff --git a/libultraship/libultraship/Cvar.cpp b/libultraship/libultraship/Cvar.cpp index 891ee73af..55fc70793 100644 --- a/libultraship/libultraship/Cvar.cpp +++ b/libultraship/libultraship/Cvar.cpp @@ -64,7 +64,7 @@ void CVar_SetFloat(const char* name, float value) { cvar->value.valueFloat = value; } -void CVar_SetString(const char* name, const char* value) { +extern "C" void CVar_SetString(const char* name, const char* value) { auto& cvar = cvars[name]; if (!cvar) { cvar = std::make_unique(); diff --git a/libultraship/libultraship/Cvar.h b/libultraship/libultraship/Cvar.h index e16f4469f..f9583ef0c 100644 --- a/libultraship/libultraship/Cvar.h +++ b/libultraship/libultraship/Cvar.h @@ -27,6 +27,7 @@ s32 CVar_GetS32(const char* name, s32 defaultValue); float CVar_GetFloat(const char* name, float defaultValue); const char* CVar_GetString(const char* name, const char* defaultValue); void CVar_SetS32(const char* name, s32 value); +void CVar_SetString(const char* name, const char* value); void CVar_RegisterS32(const char* name, s32 defaultValue); void CVar_RegisterFloat(const char* name, float defaultValue); @@ -44,6 +45,5 @@ void CVar_RegisterString(const char* name, const char* defaultValue); extern std::map, std::less<>> cvars; void CVar_SetFloat(const char* name, float value); -void CVar_SetString(const char* name, const char* value); #endif #endif diff --git a/libultraship/libultraship/GameSettings.cpp b/libultraship/libultraship/GameSettings.cpp index 7b22c7bf4..0cfbbd21a 100644 --- a/libultraship/libultraship/GameSettings.cpp +++ b/libultraship/libultraship/GameSettings.cpp @@ -56,7 +56,7 @@ namespace Game { void InitSettings() { ModInternal::RegisterHook(UpdateAudio); ModInternal::RegisterHook([] { - gfx_get_current_rendering_api()->set_texture_filter((FilteringMode) CVar_GetS32("gTextureFilter", THREE_POINT)); + gfx_get_current_rendering_api()->set_texture_filter((FilteringMode) CVar_GetS32("gTextureFilter", FILTER_THREE_POINT)); SohImGui::console->opened = CVar_GetS32("gConsoleEnabled", 0); UpdateAudio(); }); diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index fd4e298b3..20ae3f2e1 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -276,12 +276,12 @@ namespace SohImGui { u8 b = (current_hue / 60.0f + (1 - i)) * 255; switch (i) { - case 1: NewColor.x = 255; NewColor.y = b; NewColor.z = 0; break; - case 2: NewColor.x = a; NewColor.y = 255; NewColor.z = 0; break; - case 3: NewColor.x = 0; NewColor.y = 255; NewColor.z = b; break; - case 4: NewColor.x = 0; NewColor.y = a; NewColor.z = 255; break; - case 5: NewColor.x = b; NewColor.y = 0; NewColor.z = 255; break; - case 6: NewColor.x = 255; NewColor.y = 0; NewColor.z = a; break; + case 1: NewColor.x = 255; NewColor.y = b; NewColor.z = 0; break; + case 2: NewColor.x = a; NewColor.y = 255; NewColor.z = 0; break; + case 3: NewColor.x = 0; NewColor.y = 255; NewColor.z = b; break; + case 4: NewColor.x = 0; NewColor.y = a; NewColor.z = 255; break; + case 5: NewColor.x = b; NewColor.y = 0; NewColor.z = 255; break; + case 6: NewColor.x = 255; NewColor.y = 0; NewColor.z = a; break; } if (CVar_GetS32(Cvar_RBM.c_str(), 0) != 0) { @@ -389,7 +389,7 @@ namespace SohImGui { LoadTexture("C-Right", "assets/ship_of_harkinian/buttons/CRight.png"); LoadTexture("C-Up", "assets/ship_of_harkinian/buttons/CUp.png"); LoadTexture("C-Down", "assets/ship_of_harkinian/buttons/CDown.png"); - }); + }); for (const auto& [i, controllers] : Ship::Window::Controllers) { @@ -400,8 +400,14 @@ namespace SohImGui { ModInternal::RegisterHook([](OSContPad* cont_pad) { pads = cont_pad; - }); + }); Game::InitSettings(); + + CVar_SetS32("gRandoGenerating", 0); + CVar_SetS32("gNewSeedGenerated", 0); + CVar_SetS32("gNewFileDropped", 0); + CVar_SetString("gDroppedFile", ""); + Game::SaveSettings(); } void Update(EventImpl event) { @@ -492,9 +498,9 @@ namespace SohImGui { } } - void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format) + void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue) { - int val = CVar_GetS32(cvarName, 0); + int val = CVar_GetS32(cvarName, defaultValue); ImGui::Text(text, val); @@ -662,8 +668,7 @@ namespace SohImGui { CVar_SetS32(Cvar_Blue.c_str(), ClampFloatToInt(ColorRGBA.z * 255, 0, 255)); needs_save = true; } - } - else { + } else { if (ImGui::ColorEdit4(text, (float*)&ColorRGBA, flags)) { CVar_SetS32(Cvar_Red.c_str(), ClampFloatToInt(ColorRGBA.x * 255, 0, 255)); CVar_SetS32(Cvar_Green.c_str(), ClampFloatToInt(ColorRGBA.y * 255, 0, 255)); @@ -800,14 +805,13 @@ namespace SohImGui { ImGui::Separator(); - // TODO mutual exclusions -- gDpadEquips and gDpadPauseName cause conflicts, but nothing stops a user from selecting both - // There should be some system to prevent conclifting enhancements from being selected + // TODO mutual exclusions -- There should be some system to prevent conclifting enhancements from being selected EnhancementCheckbox("D-pad Support on Pause and File Select", "gDpadPauseName"); + Tooltip("Enables Pause and File Select screen navigation with the D-pad\nIf used with D-pad as Equip Items, you must hold C-Up\nto equip instead of navigate"); EnhancementCheckbox("D-pad Support in Ocarina and Text Choice", "gDpadOcarinaText"); EnhancementCheckbox("D-pad Support for Browsing Shop Items", "gDpadShop"); EnhancementCheckbox("D-pad as Equip Items", "gDpadEquips"); - Tooltip("Allows the D-pad to be used as extra C buttons\nNote: Incompatible with D-pad on pause and file select"); - + Tooltip("Allows the D-pad to be used as extra C buttons"); ImGui::Separator(); EnhancementCheckbox("Show Inputs", "gInputEnabled"); @@ -931,7 +935,9 @@ namespace SohImGui { Tooltip("Skip first-time pickup messages for consumable items"); EnhancementCheckbox("Better Owl", "gBetterOwl"); Tooltip("The default response to Kaepora Gaebora is\nalways that you understood what he said"); - + EnhancementCheckbox("Fast Ocarina Playback", "gFastOcarinaPlayback"); + Tooltip("Skip the part where the Ocarina playback is called when you play\na song"); + ImGui::EndMenu(); } @@ -1007,7 +1013,19 @@ namespace SohImGui { ImGui::EndMenu(); } - + + if (ImGui::BeginMenu("Fishing")) { + EnhancementCheckbox("Instant Fishing", "gInstantFishing"); + Tooltip("All fish will be caught instantly"); + EnhancementCheckbox("Guarantee Bite", "gGuaranteeFishingBite"); + Tooltip("When a line is stable, guarantee bite. Otherwise use default logic"); + EnhancementSliderInt("Child Minimum Weight: %d", "##cMinimumWeight", "gChildMinimumWeightFish", 6, 10, "", 10); + Tooltip("The minimum weight for the unique fishing reward as a child"); + EnhancementSliderInt("Adult Minimum Weight: %d", "##aMinimumWeight", "gAdultMinimumWeightFish", 8, 13, "", 13); + Tooltip("The minimum weight for the unique fishing reward as an adult"); + ImGui::EndMenu(); + } + ImGui::EndMenu(); } @@ -1033,6 +1051,8 @@ namespace SohImGui { EnhancementCheckbox("Enable passage of time on file select", "gTimeFlowFileSelect"); EnhancementCheckbox("Allow the cursor to be on any slot", "gPauseAnyCursor"); Tooltip("Allows the cursor on the pause menu to be over any slot\nSimilar to Rando and Spaceworld 97"); + EnhancementCheckbox("Count Golden Skulltulas", "gInjectSkulltulaCount"); + Tooltip("Injects Golden Skulltula total count in pickup messages"); EnhancementCheckbox("Pull grave during the day", "gDayGravePull"); Tooltip("Allows graves to be pulled when child during the day"); ImGui::EndMenu(); diff --git a/libultraship/libultraship/ImGuiImpl.h b/libultraship/libultraship/ImGuiImpl.h index 00f494180..11d38a7b8 100644 --- a/libultraship/libultraship/ImGuiImpl.h +++ b/libultraship/libultraship/ImGuiImpl.h @@ -68,7 +68,7 @@ namespace SohImGui { void EnhancementRadioButton(const char* text, const char* cvarName, int id); void EnhancementCheckbox(const char* text, const char* cvarName); void EnhancementButton(const char* text, const char* cvarName); - void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format); + void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0); void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage); void EnhancementCombobox(const char* name, const char* ComboArray[], size_t arraySize, uint8_t FirstTimeValue); void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha=false, bool TitleSameLine=false); diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp index b8ee8291d..5d71e6ac5 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp @@ -137,7 +137,7 @@ static struct { //uint32_t current_width, current_height; uint32_t render_target_height; int current_framebuffer; - FilteringMode current_filter_mode = NONE; + FilteringMode current_filter_mode = FILTER_NONE; int8_t depth_test; int8_t depth_mask; @@ -413,7 +413,7 @@ static struct ShaderProgram *gfx_d3d11_create_and_load_new_shader(uint64_t shade char buf[4096]; size_t len, num_floats; - gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, d3d.current_filter_mode == THREE_POINT); + gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, d3d.current_filter_mode == FILTER_THREE_POINT); ComPtr vs, ps; ComPtr error_blob; @@ -580,7 +580,7 @@ static void gfx_d3d11_set_sampler_parameters(int tile, bool linear_filter, uint3 D3D11_SAMPLER_DESC sampler_desc; ZeroMemory(&sampler_desc, sizeof(D3D11_SAMPLER_DESC)); - sampler_desc.Filter = linear_filter && d3d.current_filter_mode == LINEAR ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT; + sampler_desc.Filter = linear_filter && d3d.current_filter_mode == FILTER_LINEAR ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT; sampler_desc.AddressU = gfx_cm_to_d3d11(cms); sampler_desc.AddressV = gfx_cm_to_d3d11(cmt); @@ -685,7 +685,7 @@ static void gfx_d3d11_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t d3d.last_resource_views[i] = d3d.textures[d3d.current_texture_ids[i]].resource_view.Get(); d3d.context->PSSetShaderResources(i, 1, d3d.textures[d3d.current_texture_ids[i]].resource_view.GetAddressOf()); - if (d3d.current_filter_mode == THREE_POINT) { + if (d3d.current_filter_mode == FILTER_THREE_POINT) { d3d.per_draw_cb_data.textures[i].width = d3d.textures[d3d.current_texture_ids[i]].width; d3d.per_draw_cb_data.textures[i].height = d3d.textures[d3d.current_texture_ids[i]].height; d3d.per_draw_cb_data.textures[i].linear_filtering = d3d.textures[d3d.current_texture_ids[i]].linear_filtering; diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp index f2a401f6b..06ff5f60a 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp @@ -27,9 +27,11 @@ #include "gfx_screen_config.h" #include "gfx_pc.h" #include "../../ImGuiImpl.h" +#include "../../Cvar.h" #define DECLARE_GFX_DXGI_FUNCTIONS #include "gfx_dxgi.h" +#include "../../GameSettings.h" #define WINCLASS_NAME L"N64GAME" #define GFX_API_NAME "DirectX" @@ -85,8 +87,8 @@ static struct { static void load_dxgi_library(void) { dxgi.dxgi_module = LoadLibraryW(L"dxgi.dll"); - *(FARPROC *)&dxgi.CreateDXGIFactory1 = GetProcAddress(dxgi.dxgi_module, "CreateDXGIFactory1"); - *(FARPROC *)&dxgi.CreateDXGIFactory2 = GetProcAddress(dxgi.dxgi_module, "CreateDXGIFactory2"); + *(FARPROC*)&dxgi.CreateDXGIFactory1 = GetProcAddress(dxgi.dxgi_module, "CreateDXGIFactory1"); + *(FARPROC*)&dxgi.CreateDXGIFactory2 = GetProcAddress(dxgi.dxgi_module, "CreateDXGIFactory2"); } template @@ -110,8 +112,8 @@ static void run_as_dpi_aware(Fun f) { #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) #define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((DPI_AWARENESS_CONTEXT)-5) - DPI_AWARENESS_CONTEXT (WINAPI *SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT dpiContext); - *(FARPROC *)&SetThreadDpiAwarenessContext = GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetThreadDpiAwarenessContext"); + DPI_AWARENESS_CONTEXT(WINAPI * SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT dpiContext); + *(FARPROC*)&SetThreadDpiAwarenessContext = GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetThreadDpiAwarenessContext"); DPI_AWARENESS_CONTEXT old_awareness_context = nullptr; if (SetThreadDpiAwarenessContext != nullptr) { old_awareness_context = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); @@ -121,8 +123,8 @@ static void run_as_dpi_aware(Fun f) { if (!dxgi.process_dpi_awareness_done) { HMODULE shcore_module = LoadLibraryW(L"SHCore.dll"); if (shcore_module != nullptr) { - HRESULT (WINAPI *SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS value); - *(FARPROC *)&SetProcessDpiAwareness = GetProcAddress(shcore_module, "SetProcessDpiAwareness"); + HRESULT(WINAPI * SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS value); + *(FARPROC*)&SetProcessDpiAwareness = GetProcAddress(shcore_module, "SetProcessDpiAwareness"); if (SetProcessDpiAwareness != nullptr) { SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); // Ignore result, will fail if already called or manifest already specifies dpi awareness. @@ -226,6 +228,8 @@ static void onkeyup(WPARAM w_param, LPARAM l_param) { } } +char fileName[256]; + static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_param, LPARAM l_param) { SohImGui::EventImpl event_impl; event_impl.win32 = { h_wnd, static_cast(message), static_cast(w_param), static_cast(l_param) }; @@ -265,6 +269,12 @@ static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_par case WM_KEYUP: onkeyup(w_param, l_param); break; + case WM_DROPFILES: + DragQueryFileA((HDROP)w_param, 0, fileName, 256); + CVar_SetString("gDroppedFile", fileName); + CVar_SetS32("gNewFileDropped", 1); + Game::SaveSettings(); + break; case WM_SYSKEYDOWN: if ((w_param == VK_RETURN) && ((l_param & 1 << 30) == 0)) { toggle_borderless_window_full_screen(!dxgi.is_full_screen, true); @@ -334,6 +344,8 @@ void gfx_dxgi_init(const char *game_name, bool start_in_fullscreen, uint32_t wid if (start_in_fullscreen) { toggle_borderless_window_full_screen(true, false); } + + DragAcceptFiles(dxgi.h_wnd, TRUE); } static void gfx_dxgi_set_fullscreen_changed_callback(void (*on_fullscreen_changed)(bool is_now_fullscreen)) { diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp index 45118b2b3..d79c3aa8f 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp @@ -81,7 +81,7 @@ static uint32_t frame_count; static vector framebuffers; static size_t current_framebuffer; static float current_noise_scale; -static FilteringMode current_filter_mode = THREE_POINT; +static FilteringMode current_filter_mode = FILTER_THREE_POINT; GLuint pixel_depth_rb, pixel_depth_fb; size_t pixel_depth_rb_size; @@ -376,7 +376,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad append_line(fs_buf, &fs_len, "}"); } - if (current_filter_mode == THREE_POINT) { + if (current_filter_mode == FILTER_THREE_POINT) { #if __APPLE__ append_line(fs_buf, &fs_len, "#define TEX_OFFSET(off) texture(tex, texCoord - (off)/texSize)"); #else @@ -638,6 +638,7 @@ static void gfx_opengl_select_texture(int tile, GLuint texture_id) { glActiveTexture(GL_TEXTURE0 + tile); glBindTexture(GL_TEXTURE_2D, texture_id); } + static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, uint32_t width, uint32_t height) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); } @@ -657,7 +658,7 @@ static uint32_t gfx_cm_to_opengl(uint32_t val) { } static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) { - const GLint filter = linear_filter && current_filter_mode == LINEAR ? GL_LINEAR : GL_NEAREST; + const GLint filter = linear_filter && current_filter_mode == FILTER_LINEAR ? GL_LINEAR : GL_NEAREST; glActiveTexture(GL_TEXTURE0 + tile); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h b/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h index 02bb5afbc..772aa9904 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h +++ b/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h @@ -17,9 +17,9 @@ struct GfxClipParameters { }; enum FilteringMode { - THREE_POINT, - LINEAR, - NONE + FILTER_THREE_POINT, + FILTER_LINEAR, + FILTER_NONE }; // A hash function used to hash a: pair diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp index 07b3d8061..44ad9ec37 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp @@ -22,6 +22,7 @@ #endif #include "../../ImGuiImpl.h" +#include "../../Cvar.h" #include "gfx_window_manager_api.h" #include "gfx_screen_config.h" @@ -29,6 +30,7 @@ #include #endif #include +#include "../../GameSettings.h" #define GFX_API_NAME "SDL2 - OpenGL" @@ -106,7 +108,7 @@ static void set_fullscreen(bool on, bool call_callback) { SDL_GetDesktopDisplayMode(0, &mode); window_width = mode.w; window_height = mode.h; - SDL_ShowCursor(false); + //SDL_ShowCursor(false); } else { window_width = DESIRED_SCREEN_WIDTH; window_height = DESIRED_SCREEN_HEIGHT; @@ -133,6 +135,8 @@ static int target_fps = 60; static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen, uint32_t width, uint32_t height) { SDL_Init(SDL_INIT_VIDEO); + SDL_EventState(SDL_DROPFILE, SDL_ENABLE); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); @@ -260,6 +264,11 @@ static void gfx_sdl_handle_events(void) { SDL_GL_GetDrawableSize(wnd, &window_width, &window_height); } break; + case SDL_DROPFILE: + CVar_SetString("gDroppedFile", event.drop.file); + CVar_SetS32("gNewFileDropped", 1); + Game::SaveSettings(); + break; case SDL_QUIT: SDL_Quit(); // bandaid fix for linux window closing issue exit(0); diff --git a/libultraship/libultraship/PulseAudioPlayer.cpp b/libultraship/libultraship/PulseAudioPlayer.cpp index 21603c2b9..d33e62ea1 100644 --- a/libultraship/libultraship/PulseAudioPlayer.cpp +++ b/libultraship/libultraship/PulseAudioPlayer.cpp @@ -182,4 +182,4 @@ namespace Ship } } -#endif \ No newline at end of file +#endif diff --git a/soh/include/functions.h b/soh/include/functions.h index 3dcf5f936..73f366bb5 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -448,6 +448,7 @@ u32 Actor_TextboxIsClosing(Actor* actor, GlobalContext* globalCtx); s8 func_8002F368(GlobalContext* globalCtx); void Actor_GetScreenPos(GlobalContext* globalCtx, Actor* actor, s16* x, s16* y); u32 Actor_HasParent(Actor* actor, GlobalContext* globalCtx); +s32 GiveItemWithoutActor(GlobalContext* globalCtx, s32 getItemId); s32 func_8002F434(Actor* actor, GlobalContext* globalCtx, s32 getItemId, f32 xzRange, f32 yRange); void func_8002F554(Actor* actor, GlobalContext* globalCtx, s32 getItemId); void func_8002F580(Actor* actor, GlobalContext* globalCtx); diff --git a/soh/include/z64.h b/soh/include/z64.h index 5057def3d..2d8a6f4a8 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -1293,6 +1293,7 @@ typedef struct { /* 0x1C9EC */ Vtx* keyboardVtx; /* 0x1C9F0 */ Vtx* nameEntryVtx; /* 0x1C9F4 */ u8 n64ddFlag; + /* 0x1CA28 */ s16 n64ddFlags[3]; /* 0x1CA38 */ s16 buttonIndex; /* 0x1CA3A */ s16 confirmButtonIndex; // 0: yes, 1: quit /* 0x1CA3C */ s16 menuMode; diff --git a/soh/include/z64actor.h b/soh/include/z64actor.h index d13069029..6ecb10c49 100644 --- a/soh/include/z64actor.h +++ b/soh/include/z64actor.h @@ -289,6 +289,7 @@ typedef struct EnItem00 { /* 0x15A */ s16 unk_15A; /* 0x15C */ f32 scale; /* 0x160 */ ColliderCylinder collider; + s16 ogParams; } EnItem00; // size = 0x1AC // Only A_OBJ_SIGNPOST_OBLONG and A_OBJ_SIGNPOST_ARROW are used in room files. diff --git a/soh/include/z64item.h b/soh/include/z64item.h index b42a2efc9..9e78487db 100644 --- a/soh/include/z64item.h +++ b/soh/include/z64item.h @@ -211,9 +211,9 @@ typedef enum { /* 0x78 */ ITEM_MAGIC_SMALL, /* 0x79 */ ITEM_MAGIC_LARGE, /* 0x7A */ ITEM_HEART_PIECE_2, - /* 0x7B */ ITEM_INVALID_1, - /* 0x7C */ ITEM_INVALID_2, - /* 0x7D */ ITEM_INVALID_3, + /* 0x7B */ ITEM_SINGLE_MAGIC, + /* 0x7C */ ITEM_DOUBLE_MAGIC, + /* 0x7D */ ITEM_DOUBLE_DEFENSE, /* 0x7E */ ITEM_INVALID_4, /* 0x7F */ ITEM_INVALID_5, /* 0x80 */ ITEM_INVALID_6, @@ -244,6 +244,15 @@ typedef enum { /* 0x99 */ ITEM_STICK_UPGRADE_30, /* 0x9A */ ITEM_NUT_UPGRADE_30, /* 0x9B */ ITEM_NUT_UPGRADE_40, + /* 0x9C */ ITEM_BOTTLE_WITH_RED_POTION, + /* 0x9D */ ITEM_BOTTLE_WITH_GREEN_POTION, + /* 0x9E */ ITEM_BOTTLE_WITH_BLUE_POTION, + /* 0x9F */ ITEM_BOTTLE_WITH_FAIRY, + /* 0xA0 */ ITEM_BOTTLE_WITH_FISH, + /* 0xA1 */ ITEM_BOTTLE_WITH_BLUE_FIRE, + /* 0xA2 */ ITEM_BOTTLE_WITH_BUGS, + /* 0xA3 */ ITEM_BOTTLE_WITH_POE, + /* 0xA4 */ ITEM_BOTTLE_WITH_BIG_POE, /* 0xFC */ ITEM_LAST_USED = 0xFC, /* 0xFE */ ITEM_NONE_FE = 0xFE, /* 0xFF */ ITEM_NONE = 0xFF @@ -380,7 +389,47 @@ typedef enum { /* 0x7B */ GI_BULLET_BAG_50, /* 0x7C */ GI_ICE_TRAP, // freezes link when opened from a chest /* 0x7D */ GI_TEXT_0, // no model appears over Link, shows text id 0 (pocket egg) - /* 0x7E */ GI_MAX + + /* 0x7E */ GI_MEDALLION_LIGHT, + /* 0x7F */ GI_MEDALLION_FOREST, + /* 0x80 */ GI_MEDALLION_FIRE, + /* 0x81 */ GI_MEDALLION_WATER, + /* 0x82 */ GI_MEDALLION_SHADOW, + /* 0x83 */ GI_MEDALLION_SPIRIT, + + /* 0x81 */ GI_STONE_KOKIRI, + /* 0x82 */ GI_STONE_GORON, + /* 0x83 */ GI_STONE_ZORA, + + /* 0x81 */ GI_ZELDAS_LULLABY, + /* 0x82 */ GI_SUNS_SONG, + /* 0x83 */ GI_EPONAS_SONG, + /* 0x81 */ GI_SONG_OF_STORMS, + /* 0x82 */ GI_SONG_OF_TIME, + /* 0x83 */ GI_SARIAS_SONG, + + /* 0x81 */ GI_MINUET_OF_FOREST, + /* 0x82 */ GI_BOLERO_OF_FIRE, + /* 0x83 */ GI_SERENADE_OF_WATER, + /* 0x81 */ GI_NOCTURNE_OF_SHADOW, + /* 0x82 */ GI_REQUIEM_OF_SPIRIT, + /* 0x83 */ GI_PRELUDE_OF_LIGHT, + + GI_SINGLE_MAGIC, + GI_DOUBLE_MAGIC, + GI_DOUBLE_DEFENSE, + + GI_BOTTLE_WITH_RED_POTION, + GI_BOTTLE_WITH_GREEN_POTION, + GI_BOTTLE_WITH_BLUE_POTION, + GI_BOTTLE_WITH_FAIRY, + GI_BOTTLE_WITH_FISH, + GI_BOTTLE_WITH_BLUE_FIRE, + GI_BOTTLE_WITH_BUGS, + GI_BOTTLE_WITH_POE, + GI_BOTTLE_WITH_BIG_POE, + + /* 0x84 */ GI_MAX } GetItemID; typedef enum { @@ -501,7 +550,18 @@ typedef enum { /* 0x72 */ GID_BULLET_BAG_50, /* 0x73 */ GID_SWORD_KOKIRI, /* 0x74 */ GID_SKULL_TOKEN_2, - /* 0x75 */ GID_MAXIMUM + /* 0x74 */ GID_KOKIRI_EMERALD, + /* 0x74 */ GID_GORON_RUBY, + /* 0x74 */ GID_ZORA_SAPPHIRE, + /* 0x75 */ GID_SONG_GENERIC, + /* 0x76 */ GID_SONG_ZELDA, + /* 0x77 */ GID_SONG_EPONA, + /* 0x78 */ GID_SONG_SARIA, + /* 0x79 */ GID_SONG_SUN, + /* 0x7A */ GID_SONG_TIME, + /* 0x7B */ GID_SONG_STORM, + /* 0x7C */ GID_MAXIMUM + } GetItemDrawID; typedef enum { diff --git a/soh/include/z64player.h b/soh/include/z64player.h index 9bce60ffe..954c36c14 100644 --- a/soh/include/z64player.h +++ b/soh/include/z64player.h @@ -481,7 +481,7 @@ typedef struct Player { /* 0x042D */ s8 doorDirection; /* 0x042E */ s16 doorTimer; /* 0x0430 */ Actor* doorActor; - /* 0x0434 */ s8 getItemId; + /* 0x0434 */ s16 getItemId; /* 0x0436 */ u16 getItemDirection; /* 0x0438 */ Actor* interactRangeActor; /* 0x043C */ s8 mountSide; @@ -614,4 +614,4 @@ typedef struct Player { /* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position } Player; // size = 0xA94 -#endif \ No newline at end of file +#endif diff --git a/soh/include/z64save.h b/soh/include/z64save.h index daf316e0a..86e962799 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -3,6 +3,7 @@ #include "ultra64.h" #include "z64math.h" +#include typedef struct { /* 0x00 */ u8 buttonItems[8]; @@ -60,6 +61,21 @@ typedef struct { /* 0x24 */ s32 tempCollectFlags; } FaroresWindData; // size = 0x28 +typedef struct { + RandomizerCheck check; + RandomizerGet get; +} ItemLocationRando; + +typedef struct { + RandomizerCheck check; + char hintText[200]; +} HintLocationRando; + +typedef struct { + RandomizerSettingKey key; + u8 value; +} RandoSetting; + typedef struct { /* 0x0000 */ s32 entranceIndex; // start of `save` substruct, originally called "memory" /* 0x0004 */ s32 linkAge; // 0: Adult; 1: Child @@ -157,6 +173,17 @@ typedef struct { /* 0x1420 */ s16 worldMapArea; /* 0x1422 */ s16 sunsSongState; // controls the effects of suns song /* 0x1424 */ s16 healthAccumulator; + RandoSetting randoSettings[300]; + ItemLocationRando itemLocations[500]; + HintLocationRando hintLocations[50]; + char childAltarText[250]; + char adultAltarText[750]; + char ganonHintText[150]; + char ganonText[250]; + u8 seedIcons[5]; + u8 dungeonsDone[8]; + u8 trialsDone[6]; + u8 temporaryWeapon; } SaveContext; // size = 0x1428 typedef enum { diff --git a/soh/randomizerTypes.h b/soh/randomizerTypes.h new file mode 100644 index 000000000..551966828 --- /dev/null +++ b/soh/randomizerTypes.h @@ -0,0 +1,1000 @@ +#pragma once + +typedef struct { + char tex[512]; + uint16_t width; + uint16_t height; + uint8_t im_fmt; + uint8_t im_siz; + uint8_t id; +} Sprite; + +typedef enum { + RC_LINKS_POCKET, + RC_QUEEN_GOHMA, + RC_KING_DODONGO, + RC_BARINADE, + RC_PHANTOM_GANON, + RC_VOLVAGIA, + RC_MORPHA, + RC_BONGO_BONGO, + RC_TWINROVA, + RC_GANON, + RC_GIFT_FROM_SAGES, + RC_SONG_FROM_IMPA, + RC_SONG_FROM_MALON, + RC_SONG_FROM_SARIA, + RC_SONG_FROM_ROYAL_FAMILYS_TOMB, + RC_SONG_FROM_OCARINA_OF_TIME, + RC_SONG_FROM_WINDMILL, + RC_SHEIK_IN_FOREST, + RC_SHEIK_IN_CRATER, + RC_SHEIK_IN_ICE_CAVERN, + RC_SHEIK_AT_COLOSSUS, + RC_SHEIK_IN_KAKARIKO, + RC_SHEIK_AT_TEMPLE, + RC_KF_MIDOS_TOP_LEFT_CHEST, + RC_KF_MIDOS_TOP_RIGHT_CHEST, + RC_KF_MIDOS_BOTTOM_LEFT_CHEST, + RC_KF_MIDOS_BOTTOM_RIGHT_CHEST, + RC_KF_KOKIRI_SWORD_CHEST, + RC_KF_STORMS_GROTTO_CHEST, + RC_KF_LINKS_HOUSE_COW, + RC_KF_GS_KNOW_IT_ALL_HOUSE, + RC_KF_GS_BEAN_PATCH, + RC_KF_GS_HOUSE_OF_TWINS, + RC_KF_SHOP_ITEM_1, + RC_KF_SHOP_ITEM_2, + RC_KF_SHOP_ITEM_3, + RC_KF_SHOP_ITEM_4, + RC_KF_SHOP_ITEM_5, + RC_KF_SHOP_ITEM_6, + RC_KF_SHOP_ITEM_7, + RC_KF_SHOP_ITEM_8, + RC_LW_GIFT_FROM_SARIA, + RC_LW_OCARINA_MEMORY_GAME, + RC_LW_TARGET_IN_WOODS, + RC_LW_NEAR_SHORTCUTS_GROTTO_CHEST, + RC_LW_TRADE_COJIRO, + RC_DEKU_THEATER_SKULL_MASK, + RC_DEKU_THEATER_MASK_OF_TRUTH, + RC_LW_SKULL_KID, + RC_LW_TRADE_ODD_POTION, + RC_LW_DEKU_SCRUB_NEAR_BRIDGE, + RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, + RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, + RC_LW_DEKU_SCRUB_GROTTO_FRONT, + RC_LW_DEKU_SCRUB_GROTTO_REAR, + RC_LW_GS_BEAN_PATCH_NEAR_BRIDGE, + RC_LW_GS_BEAN_PATCH_NEAR_THEATER, + RC_LW_GS_ABOVE_THEATER, + RC_SFM_WOLFOS_GROTTO_CHEST, + RC_SFM_DEKU_SCRUB_GROTTO_FRONT, + RC_SFM_DEKU_SCRUB_GROTTO_REAR, + RC_SFM_GS, + RC_HF_OCARINA_OF_TIME_ITEM, + RC_HF_NEAR_MARKET_GROTTO_CHEST, + RC_HF_TEKTITE_GROTTO_FREESTANDING_POH, + RC_HF_SOUTHEAST_GROTTO_CHEST, + RC_HF_OPEN_GROTTO_CHEST, + RC_HF_DEKU_SCRUB_GROTTO, + RC_HF_COW_GROTTO_COW, + RC_HF_GS_COW_GROTTO, + RC_HF_GS_NEAR_KAK_GROTTO, + RC_MARKET_SHOOTING_GALLERY_REWARD, + RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, + RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, + RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, + RC_MARKET_LOST_DOG, + RC_MARKET_TREASURE_CHEST_GAME_REWARD, + RC_MARKET_10_BIG_POES, + RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, + RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, + RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, + RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, + RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, + RC_MARKET_GS_GUARD_HOUSE, + RC_MARKET_BAZAAR_ITEM_1, + RC_MARKET_BAZAAR_ITEM_2, + RC_MARKET_BAZAAR_ITEM_3, + RC_MARKET_BAZAAR_ITEM_4, + RC_MARKET_BAZAAR_ITEM_5, + RC_MARKET_BAZAAR_ITEM_6, + RC_MARKET_BAZAAR_ITEM_7, + RC_MARKET_BAZAAR_ITEM_8, + RC_MARKET_POTION_SHOP_ITEM_1, + RC_MARKET_POTION_SHOP_ITEM_2, + RC_MARKET_POTION_SHOP_ITEM_3, + RC_MARKET_POTION_SHOP_ITEM_4, + RC_MARKET_POTION_SHOP_ITEM_5, + RC_MARKET_POTION_SHOP_ITEM_6, + RC_MARKET_POTION_SHOP_ITEM_7, + RC_MARKET_POTION_SHOP_ITEM_8, + RC_MARKET_BOMBCHU_SHOP_ITEM_1, + RC_MARKET_BOMBCHU_SHOP_ITEM_2, + RC_MARKET_BOMBCHU_SHOP_ITEM_3, + RC_MARKET_BOMBCHU_SHOP_ITEM_4, + RC_MARKET_BOMBCHU_SHOP_ITEM_5, + RC_MARKET_BOMBCHU_SHOP_ITEM_6, + RC_MARKET_BOMBCHU_SHOP_ITEM_7, + RC_MARKET_BOMBCHU_SHOP_ITEM_8, + RC_TOT_LIGHT_ARROWS_CUTSCENE, + RC_HC_MALON_EGG, + RC_HC_ZELDAS_LETTER, + RC_HC_GREAT_FAIRY_REWARD, + RC_HC_GS_TREE, + RC_HC_GS_STORMS_GROTTO, + RC_LLR_TALONS_CHICKENS, + RC_LLR_FREESTANDING_POH, + RC_LLR_DEKU_SCRUB_GROTTO_LEFT, + RC_LLR_DEKU_SCRUB_GROTTO_CENTER, + RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, + RC_LLR_STABLES_LEFT_COW, + RC_LLR_STABLES_RIGHT_COW, + RC_LLR_TOWER_LEFT_COW, + RC_LLR_TOWER_RIGHT_COW, + RC_LLR_GS_HOUSE_WINDOW, + RC_LLR_GS_TREE, + RC_LLR_GS_RAIN_SHED, + RC_LLR_GS_BACK_WALL, + RC_KAK_ANJU_AS_CHILD, + RC_KAK_ANJU_AS_ADULT, + RC_KAK_IMPAS_HOUSE_FREESTANDING_POH, + RC_KAK_WINDMILL_FREESTANDING_POH, + RC_KAK_MAN_ON_ROOF, + RC_KAK_OPEN_GROTTO_CHEST, + RC_KAK_REDEAD_GROTTO_CHEST, + RC_KAK_SHOOTING_GALLERY_REWARD, + RC_KAK_TRADE_ODD_MUSHROOM, + RC_KAK_TRADE_POCKET_CUCCO, + RC_KAK_10_GOLD_SKULLTULA_REWARD, + RC_KAK_20_GOLD_SKULLTULA_REWARD, + RC_KAK_30_GOLD_SKULLTULA_REWARD, + RC_KAK_40_GOLD_SKULLTULA_REWARD, + RC_KAK_50_GOLD_SKULLTULA_REWARD, + RC_KAK_IMPAS_HOUSE_COW, + RC_KAK_GS_TREE, + RC_KAK_GS_GUARDS_HOUSE, + RC_KAK_GS_WATCHTOWER, + RC_KAK_GS_SKULLTULA_HOUSE, + RC_KAK_GS_HOUSE_UNDER_CONSTRUCTION, + RC_KAK_GS_ABOVE_IMPAS_HOUSE, + RC_KAK_BAZAAR_ITEM_1, + RC_KAK_BAZAAR_ITEM_2, + RC_KAK_BAZAAR_ITEM_3, + RC_KAK_BAZAAR_ITEM_4, + RC_KAK_BAZAAR_ITEM_5, + RC_KAK_BAZAAR_ITEM_6, + RC_KAK_BAZAAR_ITEM_7, + RC_KAK_BAZAAR_ITEM_8, + RC_KAK_POTION_SHOP_ITEM_1, + RC_KAK_POTION_SHOP_ITEM_2, + RC_KAK_POTION_SHOP_ITEM_3, + RC_KAK_POTION_SHOP_ITEM_4, + RC_KAK_POTION_SHOP_ITEM_5, + RC_KAK_POTION_SHOP_ITEM_6, + RC_KAK_POTION_SHOP_ITEM_7, + RC_KAK_POTION_SHOP_ITEM_8, + RC_GRAVEYARD_SHIELD_GRAVE_CHEST, + RC_GRAVEYARD_HEART_PIECE_GRAVE_CHEST, + RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_CHEST, + RC_GRAVEYARD_FREESTANDING_POH, + RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, + RC_GRAVEYARD_HOOKSHOT_CHEST, + RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, + RC_GRAVEYARD_GS_BEAN_PATCH, + RC_GRAVEYARD_GS_WALL, + RC_DMT_FREESTANDING_POH, + RC_DMT_CHEST, + RC_DMT_STORMS_GROTTO_CHEST, + RC_DMT_TRADE_BROKEN_SWORD, + RC_DMT_TRADE_EYEDROPS, + RC_DMT_TRADE_CLAIM_CHECK, + RC_DMT_GREAT_FAIRY_REWARD, + RC_DMT_COW_GROTTO_COW, + RC_DMT_GS_NEAR_KAK, + RC_DMT_GS_BEAN_PATCH, + RC_DMT_GS_ABOVE_DODONGOS_CAVERN, + RC_DMT_GS_FALLING_ROCKS_PATH, + RC_GC_DARUNIAS_JOY, + RC_GC_POT_FREESTANDING_POH, + RC_GC_ROLLING_GORON_AS_CHILD, + RC_GC_ROLLING_GORON_AS_ADULT, + RC_GC_MEDIGORON, + RC_GC_MAZE_LEFT_CHEST, + RC_GC_MAZE_RIGHT_CHEST, + RC_GC_MAZE_CENTER_CHEST, + RC_GC_DEKU_SCRUB_GROTTO_LEFT, + RC_GC_DEKU_SCRUB_GROTTO_CENTER, + RC_GC_DEKU_SCRUB_GROTTO_RIGHT, + RC_GC_GS_CENTER_PLATFORM, + RC_GC_GS_BOULDER_MAZE, + RC_GC_SHOP_ITEM_1, + RC_GC_SHOP_ITEM_2, + RC_GC_SHOP_ITEM_3, + RC_GC_SHOP_ITEM_4, + RC_GC_SHOP_ITEM_5, + RC_GC_SHOP_ITEM_6, + RC_GC_SHOP_ITEM_7, + RC_GC_SHOP_ITEM_8, + RC_DMC_VOLCANO_FREESTANDING_POH, + RC_DMC_WALL_FREESTANDING_POH, + RC_DMC_UPPER_GROTTO_CHEST, + RC_DMC_GREAT_FAIRY_REWARD, + RC_DMC_DEKU_SCRUB, + RC_DMC_DEKU_SCRUB_GROTTO_LEFT, + RC_DMC_DEKU_SCRUB_GROTTO_CENTER, + RC_DMC_DEKU_SCRUB_GROTTO_RIGHT, + RC_DMC_GS_CRATE, + RC_DMC_GS_BEAN_PATCH, + RC_ZR_MAGIC_BEAN_SALESMAN, + RC_ZR_OPEN_GROTTO_CHEST, + RC_ZR_FROGS_ZELDAS_LULLABY, + RC_ZR_FROGS_EPONAS_SONG, + RC_ZR_FROGS_SARIAS_SONG, + RC_ZR_FROGS_SUNS_SONG, + RC_ZR_FROGS_SONG_OF_TIME, + RC_ZR_FROGS_IN_THE_RAIN, + RC_ZR_FROGS_OCARINA_GAME, + RC_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, + RC_ZR_NEAR_DOMAIN_FREESTANDING_POH, + RC_ZR_DEKU_SCRUB_GROTTO_FRONT, + RC_ZR_DEKU_SCRUB_GROTTO_REAR, + RC_ZR_GS_TREE, + RC_ZR_GS_LADDER, + RC_ZR_GS_NEAR_RAISED_GROTTOS, + RC_ZR_GS_ABOVE_BRIDGE, + RC_ZD_DIVING_MINIGAME, + RC_ZD_CHEST, + RC_ZD_KING_ZORA_THAWED, + RC_ZD_TRADE_PRESCRIPTION, + RC_ZD_GS_FROZEN_WATERFALL, + RC_ZD_SHOP_ITEM_1, + RC_ZD_SHOP_ITEM_2, + RC_ZD_SHOP_ITEM_3, + RC_ZD_SHOP_ITEM_4, + RC_ZD_SHOP_ITEM_5, + RC_ZD_SHOP_ITEM_6, + RC_ZD_SHOP_ITEM_7, + RC_ZD_SHOP_ITEM_8, + RC_ZF_GREAT_FAIRY_REWARD, + RC_ZF_ICEBERC_FREESTANDING_POH, + RC_ZF_BOTTOM_FREESTANDING_POH, + RC_ZF_GS_ABOVE_THE_LOG, + RC_ZF_GS_TREE, + RC_ZF_GS_HIDDEN_CAVE, + RC_LH_UNDERWATER_ITEM, + RC_LH_CHILD_FISHING, + RC_LH_ADULT_FISHING, + RC_LH_LAB_DIVE, + RC_LH_TRADE_FROG, + RC_LH_FREESTANDING_POH, + RC_LH_SUN, + RC_LH_DEKU_SCRUB_GROTTO_LEFT, + RC_LH_DEKU_SCRUB_GROTTO_CENTER, + RC_LH_DEKU_SCRUB_GROTTO_RIGHT, + RC_LH_GS_BEAN_PATCH, + RC_LH_GS_LAB_WALL, + RC_LH_GS_SMALL_ISLAND, + RC_LH_GS_LAB_CRATE, + RC_LH_GS_TREE, + RC_GV_CRATE_FREESTANDING_POH, + RC_GV_WATERFALL_FREESTANDING_POH, + RC_GV_CHEST, + RC_GV_TRADE_SAW, + RC_GV_DEKU_SCRUB_GROTTO_FRONT, + RC_GV_DEKU_SCRUB_GROTTO_REAR, + RC_GV_COW, + RC_GV_GS_SMALL_BRIDGE, + RC_GV_GS_BEAN_PATCH, + RC_GV_GS_BEHIND_TENT, + RC_GV_GS_PILLAR, + RC_GF_CHEST, + RC_GF_HBA_1000_POINTS, + RC_GF_HBA_1500_POINTS, + RC_GF_GERUDO_MEMBERSHIP_CARD, + RC_GF_NORTH_F1_CARPENTER, + RC_GF_NORTH_F2_CARPENTER, + RC_GF_SOUTH_F1_CARPENTER, + RC_GF_SOUTH_F2_CARPENTER, + RC_GF_GS_TOP_FLOOR, + RC_GF_GS_ARCHERY_RANGE, + RC_HIDEOUT_JAIL_GUARD_1_TORCH, + RC_HIDEOUT_JAIL_GUARD_2_TORCHES, + RC_HIDEOUT_JAIL_GUARD_3_TORCHES, + RC_HIDEOUT_JAIL_GUARD_4_TORCHES, + RC_HIDEOUT_GERUDO_MEMBERSHIP_CARD, + RC_WASTELAND_BOMBCHU_SALESMAN, + RC_WASTELAND_CHEST, + RC_WASTELAND_GS, + RC_COLOSSUS_GREAT_FAIRY_REWARD, + RC_COLOSSUS_FREESTANDING_POH, + RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, + RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR, + RC_COLOSSUS_GS_BEAN_PATCH, + RC_COLOSSUS_GS_TREE, + RC_COLOSSUS_GS_HILL, + RC_OGC_GREAT_FAIRY_REWARD, + RC_OGC_GS, + RC_DEKU_TREE_MAP_CHEST, + RC_DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, + RC_DEKU_TREE_SLINGSHOT_CHEST, + RC_DEKU_TREE_COMPASS_CHEST, + RC_DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, + RC_DEKU_TREE_BASEMENT_CHEST, + RC_DEKU_TREE_GS_COMPASS_ROOM, + RC_DEKU_TREE_GS_BASEMENT_VINES, + RC_DEKU_TREE_GS_BASEMENT_GATE, + RC_DEKU_TREE_GS_BASEMENT_BACK_ROOM, + RC_DEKU_TREE_MQ_MAP_CHEST, + RC_DEKU_TREE_MQ_SLINGSHOT_CHEST, + RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, + RC_DEKU_TREE_MQ_COMPASS_CHEST, + RC_DEKU_TREE_MQ_BASEMENT_CHEST, + RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, + RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, + RC_DEKU_TREE_MQ_DEKU_SCRUB, + RC_DEKU_TREE_MQ_GS_LOBBY, + RC_DEKU_TREE_MQ_GS_COMPASS_ROOM, + RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, + RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, + RC_DEKU_TREE_QUEEN_GOHMA_HEART, + RC_DODONGOS_CAVERN_MAP_CHEST, + RC_DODONGOS_CAVERN_COMPASS_CHEST, + RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, + RC_DODONGOS_CAVERN_BOMB_BAG_CHEST, + RC_DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, + RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, + RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, + RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, + RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, + RC_DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + RC_DODONGOS_CAVERN_GS_SCARECROW, + RC_DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, + RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, + RC_DODONGOS_CAVERN_GS_BACK_ROOM, + RC_DODONGOS_CAVERN_MQ_MAP_CHEST, + RC_DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, + RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, + RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, + RC_DODONGOS_CAVERN_MQ_COMPASS_CHEST, + RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, + RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, + RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, + RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, + RC_DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, + RC_DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, + RC_DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, + RC_DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, + RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA, + RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST, + RC_DODONGOS_CAVERN_KING_DODONGO_HEART, + RC_JABU_JABUS_BELLY_BOOMERANG_CHEST, + RC_JABU_JABUS_BELLY_MAP_CHEST, + RC_JABU_JABUS_BELLY_COMPASS_CHEST, + RC_JABU_JABUS_BELLY_DEKU_SCRUB, + RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, + RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, + RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, + RC_JABU_JABUS_BELLY_GS_NEAR_BOSS, + RC_JABU_JABUS_BELLY_MQ_MAP_CHEST, + RC_JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, + RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, + RC_JABU_JABUS_BELLY_MQ_COMPASS_CHEST, + RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, + RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, + RC_JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, + RC_JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, + RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, + RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, + RC_JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, + RC_JABU_JABUS_BELLY_MQ_COW, + RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, + RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, + RC_JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, + RC_JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, + RC_JABU_JABUS_BELLY_BARINADE_HEART, + RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, + RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, + RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, + RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, + RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, + RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST, + RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, + RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, + RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, + RC_BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, + RC_BOTTOM_OF_THE_WELL_MAP_CHEST, + RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, + RC_BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, + RC_BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, + RC_BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, + RC_BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, + RC_BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, + RC_BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, + RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, + RC_BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, + RC_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, + RC_BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, + RC_BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, + RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, + RC_BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, + RC_FOREST_TEMPLE_FIRST_ROOM_CHEST, + RC_FOREST_TEMPLE_FIRST_STALFOS_CHEST, + RC_FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, + RC_FOREST_TEMPLE_MAP_CHEST, + RC_FOREST_TEMPLE_WELL_CHEST, + RC_FOREST_TEMPLE_EYE_SWITCH_CHEST, + RC_FOREST_TEMPLE_BOSS_KEY_CHEST, + RC_FOREST_TEMPLE_FLOORMASTER_CHEST, + RC_FOREST_TEMPLE_RED_POE_CHEST, + RC_FOREST_TEMPLE_BOW_CHEST, + RC_FOREST_TEMPLE_BLUE_POE_CHEST, + RC_FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, + RC_FOREST_TEMPLE_BASEMENT_CHEST, + RC_FOREST_TEMPLE_GS_FIRST_ROOM, + RC_FOREST_TEMPLE_GS_LOBBY, + RC_FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, + RC_FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, + RC_FOREST_TEMPLE_GS_BASEMENT, + RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, + RC_FOREST_TEMPLE_MQ_WOLFOS_CHEST, + RC_FOREST_TEMPLE_MQ_WELL_CHEST, + RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, + RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, + RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, + RC_FOREST_TEMPLE_MQ_REDEAD_CHEST, + RC_FOREST_TEMPLE_MQ_MAP_CHEST, + RC_FOREST_TEMPLE_MQ_BOW_CHEST, + RC_FOREST_TEMPLE_MQ_COMPASS_CHEST, + RC_FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, + RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST, + RC_FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, + RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, + RC_FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, + RC_FOREST_TEMPLE_MQ_GS_WELL, + RC_FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, + RC_FOREST_TEMPLE_PHANTOM_GANON_HEART, + RC_FIRE_TEMPLE_NEAR_BOSS_CHEST, + RC_FIRE_TEMPLE_FLARE_DANCER_CHEST, + RC_FIRE_TEMPLE_BOSS_KEY_CHEST, + RC_FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, + RC_FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + RC_FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, + RC_FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, + RC_FIRE_TEMPLE_MAP_CHEST, + RC_FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, + RC_FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, + RC_FIRE_TEMPLE_SCARECROW_CHEST, + RC_FIRE_TEMPLE_COMPASS_CHEST, + RC_FIRE_TEMPLE_MEGATON_HAMMER_CHEST, + RC_FIRE_TEMPLE_HIGHEST_GORON_CHEST, + RC_FIRE_TEMPLE_GS_BOSS_KEY_LOOP, + RC_FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, + RC_FIRE_TEMPLE_GS_BOULDER_MAZE, + RC_FIRE_TEMPLE_GS_SCARECROW_CLIMB, + RC_FIRE_TEMPLE_GS_SCARECROW_TOP, + RC_FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, + RC_FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, + RC_FIRE_TEMPLE_MQ_MAP_CHEST, + RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, + RC_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + RC_FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, + RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, + RC_FIRE_TEMPLE_MQ_COMPASS_CHEST, + RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, + RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, + RC_FIRE_TEMPLE_MQ_FREESTANDING_KEY, + RC_FIRE_TEMPLE_MQ_CHEST_ON_FIRE, + RC_FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, + RC_FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, + RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, + RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, + RC_FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, + RC_FIRE_TEMPLE_VOLVAGIA_HEART, + RC_WATER_TEMPLE_COMPASS_CHEST, + RC_WATER_TEMPLE_MAP_CHEST, + RC_WATER_TEMPLE_CRACKED_WALL_CHEST, + RC_WATER_TEMPLE_TORCHES_CHEST, + RC_WATER_TEMPLE_BOSS_KEY_CHEST, + RC_WATER_TEMPLE_CENTRAL_PILLAR_CHEST, + RC_WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, + RC_WATER_TEMPLE_LONGSHOT_CHEST, + RC_WATER_TEMPLE_RIVER_CHEST, + RC_WATER_TEMPLE_DRAGON_CHEST, + RC_WATER_TEMPLE_GS_BEHIND_GATE, + RC_WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, + RC_WATER_TEMPLE_GS_CENTRAL_PILLAR, + RC_WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, + RC_WATER_TEMPLE_GS_RIVER, + RC_WATER_TEMPLE_MQ_LONGSHOT_CHEST, + RC_WATER_TEMPLE_MQ_MAP_CHEST, + RC_WATER_TEMPLE_MQ_COMPASS_CHEST, + RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, + RC_WATER_TEMPLE_MQ_BOSS_KEY_CHEST, + RC_WATER_TEMPLE_MQ_FREESTANDING_KEY, + RC_WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, + RC_WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, + RC_WATER_TEMPLE_MQ_GS_RIVER, + RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, + RC_WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, + RC_WATER_TEMPLE_MORPHA_HEART, + RC_SHADOW_TEMPLE_MAP_CHEST, + RC_SHADOW_TEMPLE_HOVER_BOOTS_CHEST, + RC_SHADOW_TEMPLE_COMPASS_CHEST, + RC_SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, + RC_SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, + RC_SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, + RC_SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, + RC_SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, + RC_SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, + RC_SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, + RC_SHADOW_TEMPLE_FREESTANDING_KEY, + RC_SHADOW_TEMPLE_WIND_HINT_CHEST, + RC_SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, + RC_SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, + RC_SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, + RC_SHADOW_TEMPLE_BOSS_KEY_CHEST, + RC_SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, + RC_SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, + RC_SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, + RC_SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, + RC_SHADOW_TEMPLE_GS_NEAR_SHIP, + RC_SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, + RC_SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, + RC_SHADOW_TEMPLE_MQ_MAP_CHEST, + RC_SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, + RC_SHADOW_TEMPLE_MQ_COMPASS_CHEST, + RC_SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, + RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, + RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, + RC_SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, + RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, + RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, + RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, + RC_SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, + RC_SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, + RC_SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, + RC_SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, + RC_SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, + RC_SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, + RC_SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, + RC_SHADOW_TEMPLE_MQ_FREESTANDING_KEY, + RC_SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, + RC_SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, + RC_SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, + RC_SHADOW_TEMPLE_MQ_GS_AFTER_WIND, + RC_SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, + RC_SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, + RC_SHADOW_TEMPLE_BONGO_BONGO_HEART, + RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, + RC_SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, + RC_SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, + RC_SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, + RC_SPIRIT_TEMPLE_MAP_CHEST, + RC_SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, + RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, + RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, + RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, + RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, + RC_SPIRIT_TEMPLE_MQ_MAP_CHEST, + RC_SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, + RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, + RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, + RC_SPIRIT_TEMPLE_MQ_COMPASS_CHEST, + RC_SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, + RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, + RC_SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, + RC_SPIRIT_TEMPLE_COMPASS_CHEST, + RC_SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, + RC_SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, + RC_SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, + RC_SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, + RC_SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, + RC_SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, + RC_SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, + RC_SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, + RC_SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, + RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, + RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, + RC_SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, + RC_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, + RC_SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, + RC_SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, + RC_SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, + RC_SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, + RC_SPIRIT_TEMPLE_BOSS_KEY_CHEST, + RC_SPIRIT_TEMPLE_TOPMOST_CHEST, + RC_SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, + RC_SPIRIT_TEMPLE_GS_METAL_FENCE, + RC_SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, + RC_SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, + RC_SPIRIT_TEMPLE_GS_LOBBY, + RC_SPIRIT_TEMPLE_GS_BOULDER_ROOM, + RC_SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, + RC_SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, + RC_SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, + RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, + RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, + RC_SPIRIT_TEMPLE_TWINROVA_HEART, + RC_ICE_CAVERN_MAP_CHEST, + RC_ICE_CAVERN_COMPASS_CHEST, + RC_ICE_CAVERN_FREESTANDING_POH, + RC_ICE_CAVERN_IRON_BOOTS_CHEST, + RC_ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, + RC_ICE_CAVERN_GS_HEART_PIECE_ROOM, + RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM, + RC_ICE_CAVERN_MQ_MAP_CHEST, + RC_ICE_CAVERN_MQ_COMPASS_CHEST, + RC_ICE_CAVERN_MQ_FREESTANDING_POH, + RC_ICE_CAVERN_MQ_IRON_BOOTS_CHEST, + RC_ICE_CAVERN_MQ_GS_RED_ICE, + RC_ICE_CAVERN_MQ_GS_ICE_BLOCK, + RC_ICE_CAVERN_MQ_GS_SCARECROW, + RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST, + RC_GERUDO_TRAINING_GROUND_LOBBY_RIGHT_CHEST, + RC_GERUDO_TRAINING_GROUND_STALFOS_CHEST, + RC_GERUDO_TRAINING_GROUND_BEFORE_HEAVY_BLOCK_CHEST, + RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FIRST_CHEST, + RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_SECOND_CHEST, + RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_THIRD_CHEST, + RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FOURTH_CHEST, + RC_GERUDO_TRAINING_GROUND_EYE_STATUE_CHEST, + RC_GERUDO_TRAINING_GROUND_NEAR_SCARECROW_CHEST, + RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_CLEAR_CHEST, + RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_SWITCH_CHEST, + RC_GERUDO_TRAINING_GROUND_FREESTANDING_KEY, + RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_CENTRAL_CHEST, + RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_SIDE_CHEST, + RC_GERUDO_TRAINING_GROUND_UNDERWATER_SILVER_RUPEE_CHEST, + RC_GERUDO_TRAINING_GROUND_BEAMOS_CHEST, + RC_GERUDO_TRAINING_GROUND_HIDDEN_CEILING_CHEST, + RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FIRST_CHEST, + RC_GERUDO_TRAINING_GROUND_MAZE_PATH_SECOND_CHEST, + RC_GERUDO_TRAINING_GROUND_MAZE_PATH_THIRD_CHEST, + RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FINAL_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_BEFORE_HEAVY_BLOCK_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_EYE_STATUE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_ICE_ARROWS_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_SECOND_IRON_KNUCKLE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_FLAME_CIRCLE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_CENTRAL_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_SIDE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_THIRD_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST, + RC_GANONS_CASTLE_FOREST_TRIAL_CHEST, + RC_GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, + RC_GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, + RC_GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, + RC_GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, + RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, + RC_GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, + RC_GANONS_CASTLE_DEKU_SCRUB_LEFT, + RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, + RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, + RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT, + RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, + RC_GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, + RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, + RC_GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, + RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, + RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, + RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, + RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, + RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, + RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, + RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, + RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, + RC_GANONS_TOWER_BOSS_KEY_CHEST, + RC_PIERRE, + RC_DELIVER_RUTOS_LETTER, + RC_MASTER_SWORD_PEDESTAL, + RC_COLOSSUS_GOSSIP_STONE, + RC_DMC_GOSSIP_STONE, + RC_DMC_UPPER_GROTTO_GOSSIP_STONE, + RC_DMT_GOSSIP_STONE, + RC_DMT_STORMS_GROTTO_GOSSIP_STONE, + RC_DODONGOS_CAVERN_GOSSIP_STONE, + RC_FAIRY_GOSSIP_STONE, + RC_GC_MAZE_GOSSIP_STONE, + RC_GC_MEDIGORON_GOSSIP_STONE, + RC_GV_GOSSIP_STONE, + RC_GY_GOSSIP_STONE, + RC_HC_MALON_GOSSIP_STONE, + RC_HC_ROCK_WALL_GOSSIP_STONE, + RC_HC_STORMS_GROTTO_GOSSIP_STONE, + RC_HF_COW_GROTTO_GOSSIP_STONE, + RC_HF_NEAR_MARKET_GOSSIP_STONE, + RC_HF_OPEN_GROTTO_GOSSIP_STONE, + RC_HF_SOUTHEAST_GOSSIP_STONE, + RC_JABU_GOSSIP_STONE, + RC_KF_DEKU_TREE_LEFT_GOSSIP_STONE, + RC_KF_DEKU_TREE_RIGHT_GOSSIP_STONE, + RC_KF_GOSSIP_STONE, + RC_KF_STORMS_GOSSIP_STONE, + RC_KAK_OPEN_GROTTO_GOSSIP_STONE, + RC_LH_LAB_GOSSIP_STONE, + RC_LH_SOUTHEAST_GOSSIP_STONE, + RC_LH_SOUTHWEST_GOSSIP_STONE, + RC_LW_GOSSIP_STONE, + RC_LW_NEAR_SHORTCUTS_GOSSIP_STONE, + RC_SFM_MAZE_LOWER_GOSSIP_STONE, + RC_SFM_MAZE_UPPER_GOSSIP_STONE, + RC_SFM_SARIA_GOSSIP_STONE, + RC_TOT_LEFT_CENTER_GOSSIP_STONE, + RC_TOT_LEFT_GOSSIP_STONE, + RC_TOT_RIGHT_CENTER_GOSSIP_STONE, + RC_TOT_RIGHT_GOSSIP_STONE, + RC_ZD_GOSSIP_STONE, + RC_ZR_NEAR_DOMAIN_GOSSIP_STONE, + RC_ZR_NEAR_GROTTOS_GOSSIP_STONE, + RC_ZR_OPEN_GROTTO_GOSSIP_STONE, + RC_UNKNOWN_CHECK +} RandomizerCheck; + +// based on https://github.com/TestRunnerSRL/OoT-Randomizer/blob/e337d7f603b91a6bacb618fb32cc7fd70ed9ffca/ItemList.py +typedef enum { + RG_NONE, + RG_KOKIRI_SWORD, + RG_GIANTS_KNIFE, + RG_BIGGORON_SWORD, + RG_DEKU_SHIELD, + RG_HYLIAN_SHIELD, + RG_MIRROR_SHIELD, + RG_GORON_TUNIC, + RG_ZORA_TUNIC, + RG_IRON_BOOTS, + RG_HOVER_BOOTS, + RG_BOOMERANG, + RG_LENS_OF_TRUTH, + RG_MEGATON_HAMMER, + RG_STONE_OF_AGONY, + RG_DINS_FIRE, + RG_FARORES_WIND, + RG_NAYRUS_LOVE, + RG_FIRE_ARROWS, + RG_ICE_ARROWS, + RG_LIGHT_ARROWS, + RG_GERUDO_MEMBERSHIP_CARD, + RG_MAGIC_BEAN, + RG_MAGIC_BEAN_PACK, + RG_DOUBLE_DEFENSE, + RG_WEIRD_EGG, + RG_ZELDAS_LETTER, + RG_POCKET_EGG, + RG_COJIRO, + RG_ODD_MUSHROOM, + RG_ODD_POTION, + RG_POACHERS_SAW, + RG_BROKEN_SWORD, + RG_PRESCRIPTION, + RG_EYEBALL_FROG, + RG_EYEDROPS, + RG_CLAIM_CHECK, + RG_GOLD_SKULLTULA_TOKEN, + RG_PROGRESSIVE_HOOKSHOT, + RG_PROGRESSIVE_STRENGTH, + RG_PROGRESSIVE_BOMB_BAG, + RG_PROGRESSIVE_BOW, + RG_PROGRESSIVE_SLINGSHOT, + RG_PROGRESSIVE_WALLET, + RG_PROGRESSIVE_SCALE, + RG_PROGRESSIVE_NUT_UPGRADE, + RG_PROGRESSIVE_STICK_UPGRADE, + RG_PROGRESSIVE_BOMBCHUS, + RG_PROGRESSIVE_MAGIC_METER, + RG_PROGRESSIVE_OCARINA, + RG_PROGRESSIVE_GORONSWORD, + RG_EMPTY_BOTTLE, + RG_BOTTLE_WITH_MILK, + RG_BOTTLE_WITH_RED_POTION, + RG_BOTTLE_WITH_GREEN_POTION, + RG_BOTTLE_WITH_BLUE_POTION, + RG_BOTTLE_WITH_FAIRY, + RG_BOTTLE_WITH_FISH, + RG_BOTTLE_WITH_BLUE_FIRE, + RG_BOTTLE_WITH_BUGS, + RG_BOTTLE_WITH_POE, + RG_RUTOS_LETTER, + RG_BOTTLE_WITH_BIG_POE, + RG_ZELDAS_LULLABY, + RG_EPONAS_SONG, + RG_SARIAS_SONG, + RG_SUNS_SONG, + RG_SONG_OF_TIME, + RG_SONG_OF_STORMS, + RG_MINUET_OF_FOREST, + RG_BOLERO_OF_FIRE, + RG_SERENADE_OF_WATER, + RG_REQUIEM_OF_SPIRIT, + RG_NOCTURNE_OF_SHADOW, + RG_PRELUDE_OF_LIGHT, + RG_DEKU_TREE_MAP, + RG_DODONGOS_CAVERN_MAP, + RG_JABU_JABUS_BELLY_MAP, + RG_FOREST_TEMPLE_MAP, + RG_FIRE_TEMPLE_MAP, + RG_WATER_TEMPLE_MAP, + RG_SPIRIT_TEMPLE_MAP, + RG_SHADOW_TEMPLE_MAP, + RG_BOTTOM_OF_THE_WELL_MAP, + RG_ICE_CAVERN_MAP, + RG_DEKU_TREE_COMPASS, + RG_DODONGOS_CAVERN_COMPASS, + RG_JABU_JABUS_BELLY_COMPASS, + RG_FOREST_TEMPLE_COMPASS, + RG_FIRE_TEMPLE_COMPASS, + RG_WATER_TEMPLE_COMPASS, + RG_SPIRIT_TEMPLE_COMPASS, + RG_SHADOW_TEMPLE_COMPASS, + RG_BOTTOM_OF_THE_WELL_COMPASS, + RG_ICE_CAVERN_COMPASS, + RG_FOREST_TEMPLE_BOSS_KEY, + RG_FIRE_TEMPLE_BOSS_KEY, + RG_WATER_TEMPLE_BOSS_KEY, + RG_SPIRIT_TEMPLE_BOSS_KEY, + RG_SHADOW_TEMPLE_BOSS_KEY, + RG_GANONS_CASTLE_BOSS_KEY, + RG_FOREST_TEMPLE_SMALL_KEY, + RG_FIRE_TEMPLE_SMALL_KEY, + RG_WATER_TEMPLE_SMALL_KEY, + RG_SPIRIT_TEMPLE_SMALL_KEY, + RG_SHADOW_TEMPLE_SMALL_KEY, + RG_BOTTOM_OF_THE_WELL_SMALL_KEY, + RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, + RG_GERUDO_FORTRESS_SMALL_KEY, + RG_GANONS_CASTLE_SMALL_KEY, + RG_TREASURE_GAME_SMALL_KEY, + RG_FOREST_TEMPLE_KEY_RING, + RG_FIRE_TEMPLE_KEY_RING, + RG_WATER_TEMPLE_KEY_RING, + RG_SPIRIT_TEMPLE_KEY_RING, + RG_SHADOW_TEMPLE_KEY_RING, + RG_BOTTOM_OF_THE_WELL_KEY_RING, + RG_GERUDO_TRAINING_GROUNDS_KEY_RING, + RG_GERUDO_FORTRESS_KEY_RING, + RG_GANONS_CASTLE_KEY_RING, + RG_KOKIRI_EMERALD, + RG_GORON_RUBY, + RG_ZORA_SAPPHIRE, + RG_FOREST_MEDALLION, + RG_FIRE_MEDALLION, + RG_WATER_MEDALLION, + RG_SPIRIT_MEDALLION, + RG_SHADOW_MEDALLION, + RG_LIGHT_MEDALLION, + RG_RECOVERY_HEART, + RG_GREEN_RUPEE, + RG_BLUE_RUPEE, + RG_RED_RUPEE, + RG_PURPLE_RUPEE, + RG_HUGE_RUPEE, + RG_PIECE_OF_HEART, + RG_HEART_CONTAINER, + RG_ICE_TRAP, + RG_MILK, + RG_BOMBS_5, + RG_BOMBS_10, + RG_BOMBS_20, + RG_BOMBCHU_5, + RG_BOMBCHU_10, + RG_BOMBCHU_20, + RG_BOMBCHU_DROP, + RG_ARROWS_5, + RG_ARROWS_10, + RG_ARROWS_30, + RG_DEKU_NUTS_5, + RG_DEKU_NUTS_10, + RG_DEKU_SEEDS_30, + RG_DEKU_STICK_1, + RG_RED_POTION_REFILL, + RG_GREEN_POTION_REFILL, + RG_BLUE_POTION_REFILL, + RG_TREASURE_GAME_HEART, + RG_TREASURE_GAME_GREEN_RUPEE, + RG_BUY_DEKU_NUT_5, + RG_BUY_ARROWS_30, + RG_BUY_ARROWS_50, + RG_BUY_BOMBS_525, + RG_BUY_DEKU_NUT_10, + RG_BUY_DEKU_STICK_1, + RG_BUY_BOMBS_10, + RG_BUY_FISH, + RG_BUY_RED_POTION_30, + RG_BUY_GREEN_POTION, + RG_BUY_BLUE_POTION, + RG_BUY_HYLIAN_SHIELD, + RG_BUY_DEKU_SHIELD, + RG_BUY_GORON_TUNIC, + RG_BUY_ZORA_TUNIC, + RG_BUY_HEART, + RG_BUY_BOMBCHU_10, + RG_BUY_BOMBCHU_20, + RG_BUY_BOMBCHU_5, + RG_BUY_DEKU_SEEDS_30, + RG_SOLD_OUT, + RG_BUY_BLUE_FIRE, + RG_BUY_BOTTLE_BUG, + RG_BUY_POE, + RG_BUY_FAIRYS_SPIRIT, + RG_BUY_ARROWS_10, + RG_BUY_BOMBS_20, + RG_BUY_BOMBS_30, + RG_BUY_BOMBS_535, + RG_BUY_RED_POTION_40, + RG_BUY_RED_POTION_50, + RG_TRIFORCE, + RG_HINT +} RandomizerGet; + +typedef enum { + RSK_NONE, + RSK_FOREST, + RSK_KAK_GATE, + RSK_DOOR_OF_TIME, + RSK_ZORAS_FOUNTAIN, + RSK_GERUDO_FORTRESS, + RSK_RAINBOW_BRIDGE, + RSK_RAINBOW_BRIDGE_STONE_COUNT, + RSK_RAINBOW_BRIDGE_MEDALLION_COUNT, + RSK_RAINBOW_BRIDGE_REWARD_COUNT, + RSK_RAINBOW_BRIDGE_DUNGEON_COUNT, + RSK_RAINBOW_BRIDGE_TOKEN_COUNT, + RSK_RANDOM_TRIALS, + RSK_TRIAL_COUNT, + RSK_STARTING_OCARINA, + RSK_SHUFFLE_OCARINA, + RSK_STARTING_DEKU_SHIELD, + RSK_STARTING_KOKIRI_SWORD, + RSK_SHUFFLE_KOKIRI_SWORD, + RSK_STARTING_MAPS_COMPASSES, //RANDOTODO more options for this, rn it's just start with or own dungeon + RSK_SHUFFLE_DUNGEON_REWARDS, + RSK_SHUFFLE_SONGS, + RSK_SHUFFLE_WEIRD_EGG, + RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD, + RSK_ITEM_POOL, + RSK_ICE_TRAPS, + RSK_GOSSIP_STONE_HINTS, + RSK_HINT_CLARITY, + RSK_HINT_DISTRIBUTION, + RSK_GANONS_BOSS_KEY, + RSK_SKIP_CHILD_STEALTH, + RSK_SKIP_CHILD_ZELDA, + RSK_STARTING_CONSUMABLES, + RSK_FULL_WALLETS, + RSK_EXCLUDE_DEKU_THEATER_MASK_OF_TRUTH, + RSK_LANGUAGE, + RSK_EXCLUDE_KAK_10_GOLD_SKULLTULA_REWARD, + RSK_EXCLUDE_KAK_20_GOLD_SKULLTULA_REWARD, + RSK_EXCLUDE_KAK_30_GOLD_SKULLTULA_REWARD, + RSK_EXCLUDE_KAK_40_GOLD_SKULLTULA_REWARD, + RSK_EXCLUDE_KAK_50_GOLD_SKULLTULA_REWARD, + RSK_SHUFFLE_CHEST_MINIGAME, + RSK_CUCCO_COUNT, + RSK_BIG_POE_COUNT, + RSK_SKIP_EPONA_RACE, + RSK_SKIP_TOWER_ESCAPE +} RandomizerSettingKey; diff --git a/soh/randomizer_generation.cpp b/soh/randomizer_generation.cpp new file mode 100644 index 000000000..a55d5fcf0 --- /dev/null +++ b/soh/randomizer_generation.cpp @@ -0,0 +1,19 @@ +#include + +void GenerateRandomizer() { + int ret = Playthrough::Playthrough_Init(std::hash{}(Settings::seed)); + + if (ret < 0) { + if (ret == -1) { // Failed to generate after 5 tries + SPDLOG_ERROR( + "\n\nFailed to generate after 5 tries.\nPress B to go back to the menu.\nA different seed might be " + "successful."); + return; + } else { + SPDLOG_ERROR("\n\nError %d with fill.\nPress Select to exit or B to go back to the menu.\n", ret); + return; + } + } + + const auto& randomizerHash = GetRandomizerHash(); +} \ No newline at end of file diff --git a/soh/soh.vcxproj b/soh/soh.vcxproj index b7a2a32de..5f7ea818f 100644 --- a/soh/soh.vcxproj +++ b/soh/soh.vcxproj @@ -181,6 +181,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -890,6 +945,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/soh.vcxproj.filters b/soh/soh.vcxproj.filters index 08d6f332f..bbe6578f2 100644 --- a/soh/soh.vcxproj.filters +++ b/soh/soh.vcxproj.filters @@ -2211,6 +2211,174 @@ Header Files\include + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Header Files + + + Header Files\soh\Enhancements + + + Source Files\src + @@ -3788,6 +3956,120 @@ Header Files\include + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\soh\Enhancements + + + Source Files\src + @@ -3800,4 +4082,4 @@ - \ No newline at end of file + diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 0c9d0f25b..60c3e6c4e 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -130,6 +130,9 @@ std::map itemMapping = { ITEM_MAP_ENTRY(ITEM_COMPASS), ITEM_MAP_ENTRY(ITEM_DUNGEON_MAP), ITEM_MAP_ENTRY(ITEM_KEY_SMALL), + ITEM_MAP_ENTRY(ITEM_HEART_CONTAINER), + ITEM_MAP_ENTRY(ITEM_MAGIC_SMALL), + ITEM_MAP_ENTRY(ITEM_MAGIC_LARGE) }; // Maps entries in the GS flag array to the area name it represents @@ -196,6 +199,7 @@ std::map questMapping = { QUEST_MAP_ENTRY(QUEST_ZORA_SAPPHIRE, dgZoraSapphireIconTex), QUEST_MAP_ENTRY(QUEST_STONE_OF_AGONY, dgStoneOfAgonyIconTex), QUEST_MAP_ENTRY(QUEST_GERUDO_CARD, dgGerudosCardIconTex), + QUEST_MAP_ENTRY(QUEST_SKULL_TOKEN, dgGoldSkulltulaIconTex), }; typedef struct { @@ -212,12 +216,12 @@ typedef struct { // Maps song ids to info for use in ImGui std::array songMapping = { { - SONG_MAP_ENTRY(QUEST_SONG_LULLABY, 255, 255, 255), - SONG_MAP_ENTRY(QUEST_SONG_EPONA, 255, 255, 255), - SONG_MAP_ENTRY(QUEST_SONG_SARIA, 255, 255, 255), - SONG_MAP_ENTRY(QUEST_SONG_SUN, 255, 255, 255), - SONG_MAP_ENTRY(QUEST_SONG_TIME, 255, 255, 255), - SONG_MAP_ENTRY(QUEST_SONG_STORMS, 255, 255, 255), + SONG_MAP_ENTRY(QUEST_SONG_LULLABY, 224, 107, 255), + SONG_MAP_ENTRY(QUEST_SONG_EPONA, 255, 195, 60), + SONG_MAP_ENTRY(QUEST_SONG_SARIA, 127, 255, 137), + SONG_MAP_ENTRY(QUEST_SONG_SUN, 255, 255, 60), + SONG_MAP_ENTRY(QUEST_SONG_TIME, 119, 236, 255), + SONG_MAP_ENTRY(QUEST_SONG_STORMS, 165, 165, 165), SONG_MAP_ENTRY(QUEST_SONG_MINUET, 150, 255, 100), SONG_MAP_ENTRY(QUEST_SONG_BOLERO, 255, 80, 40), SONG_MAP_ENTRY(QUEST_SONG_SERENADE, 100, 150, 255), @@ -226,6 +230,27 @@ std::array songMapping = { { SONG_MAP_ENTRY(QUEST_SONG_PRELUDE, 255, 240, 100), } }; +#define VANILLA_SONG_MAP_ENTRY(id, r, g, b) \ + { \ + id, #id "_Vanilla", #id "_Vanilla_Faded", ImVec4(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f) \ + } + +// Maps song ids to info for use in ImGui +std::array vanillaSongMapping = { { + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_LULLABY, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_EPONA, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_SARIA, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_SUN, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_TIME, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_STORMS, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_MINUET, 150, 255, 100), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_BOLERO, 255, 80, 40), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_SERENADE, 100, 150, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_REQUIEM, 255, 160, 0), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_NOCTURNE, 255, 100, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_PRELUDE, 255, 240, 100), +} }; + // Encapsulates what is drawn by the passed-in function within a border template void DrawGroupWithBorder(T&& drawFunc) { @@ -1610,4 +1635,10 @@ void InitSaveEditor() { fadedCol.w = 0.3f; SohImGui::LoadResource(entry.nameFaded, gSongNoteTex, fadedCol); } + for (const auto& entry : vanillaSongMapping) { + SohImGui::LoadResource(entry.name, gSongNoteTex, entry.color); + ImVec4 fadedCol = entry.color; + fadedCol.w = 0.3f; + SohImGui::LoadResource(entry.nameFaded, gSongNoteTex, fadedCol); + } } diff --git a/soh/soh/Enhancements/gfx.c b/soh/soh/Enhancements/gfx.c new file mode 100644 index 000000000..d63827a91 --- /dev/null +++ b/soh/soh/Enhancements/gfx.c @@ -0,0 +1,63 @@ +#include "gfx.h" + +#include "global.h" +#include "z64.h" + +extern GlobalContext* gGlobalCtx; + +/** + * Simple wrapper to load a texture to be drawn. + */ +void sprite_load(sprite_t* sprite) { + OPEN_DISPS(gGlobalCtx->state.gfxCtx); + + if (sprite->im_siz == G_IM_SIZ_16b) { + gDPLoadTextureBlock( + OVERLAY_DISP++, + sprite->tex, + sprite->im_fmt, + G_IM_SIZ_16b, // @TEMP until I figure out how to use sprite->im_siz + sprite->width, sprite->height, + 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD + ); + } else { + gDPLoadTextureBlock( + OVERLAY_DISP++, + sprite->tex, + sprite->im_fmt, + G_IM_SIZ_32b, // @TEMP until I figure out how to use sprite->im_siz + sprite->width, sprite->height, + 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD + ); + } + + CLOSE_DISPS(gGlobalCtx->state.gfxCtx); +} + +/** + * Simple wrapper to draw a sprite/texture on the screen. + * sprite_load needs to be ran right before this. + */ +void sprite_draw(sprite_t* sprite, int left, int top, int width, int height) { + int width_factor = (1 << 10) * sprite->width / width; + int height_factor = (1 << 10) * sprite->height / height; + + OPEN_DISPS(gGlobalCtx->state.gfxCtx); + + gSPWideTextureRectangle( + OVERLAY_DISP++, + OTRGetRectDimensionFromRightEdge(left) << 2, top << 2, + (OTRGetRectDimensionFromRightEdge(left) + width) << 2, (top + height) << 2, + G_TX_RENDERTILE, + 0, 0, + width_factor, height_factor + ); + + CLOSE_DISPS(gGlobalCtx->state.gfxCtx); +} diff --git a/soh/soh/Enhancements/gfx.h b/soh/soh/Enhancements/gfx.h new file mode 100644 index 000000000..e4fb27cf0 --- /dev/null +++ b/soh/soh/Enhancements/gfx.h @@ -0,0 +1,17 @@ +#ifndef GFX_ENHANCEMENT_H +#define GFX_EHHANCEMENT_H + +#include "z64.h" + +typedef struct { + void *tex; + uint16_t width; + uint16_t height; + uint8_t im_fmt; + uint8_t im_siz; +} sprite_t; + +void sprite_load(sprite_t *sprite); +void sprite_draw(sprite_t *sprite, int left, int top, int width, int height); + +#endif diff --git a/soh/soh/Enhancements/randomizer/3drando/category.hpp b/soh/soh/Enhancements/randomizer/3drando/category.hpp new file mode 100644 index 000000000..f49f06edc --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/category.hpp @@ -0,0 +1,71 @@ +#pragma once + +enum class Category { + cNull, + cKokiriForest, + cForest, + cGrotto, + cMinigame, + cChestMinigame, + cLostWoods, + cDekuScrub, + cDekuScrubUpgrades, + cNeedSpiritualStones, + cSacredForestMeadow, + cHyruleField, + cLakeHylia, + cGerudo, + cGerudoValley, + cGerudoFortress, + cHauntedWasteland, + cDesertColossus, + cInnerMarket, + cMarket, + cHyruleCastle, + cKakarikoVillage, + cKakariko, + cSkulltulaHouse, + cGraveyard, + cDeathMountainTrail, + cDeathMountain, + cGoronCity, + cDeathMountainCrater, + cZorasRiver, + cZorasDomain, + cZorasFountain, + cLonLonRanch, + cDekuTree, + cDodongosCavern, + cJabuJabusBelly, + cForestTemple, + cFireTemple, + cWaterTemple, + cSpiritTemple, + cShadowTemple, + cBottomOfTheWell, + cIceCavern, + cGerudoTrainingGrounds, + cGanonsCastle, + cSkulltula, + cBossHeart, + cTempleOfTime, + cFairies, + cOutsideGanonsCastle, + cSong, + cSongDungeonReward, + cCow, + cShop, + cMerchant, + cVanillaSmallKey, + cVanillaGFSmallKey, + cVanillaBossKey, + cVanillaMap, + cVanillaCompass, + cAdultTrade, +}; + +enum class OptionCategory { + Setting, + Cosmetic, + Toggle, +}; diff --git a/soh/soh/Enhancements/randomizer/3drando/cosmetics.cpp b/soh/soh/Enhancements/randomizer/3drando/cosmetics.cpp new file mode 100644 index 000000000..227fb2161 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/cosmetics.cpp @@ -0,0 +1,152 @@ +#include "cosmetics.hpp" +#include "random.hpp" +#include + +namespace Cosmetics { + + bool ValidHexString(std::string_view hexStr) { + return hexStr.find_first_not_of("0123456789ABCDEFabcdef") == std::string_view::npos && hexStr.length() == 6; + } + + Color_RGBAf HexStrToColorRGBAf(const std::string& hexStr) { + uint32_t hex = std::stoi(hexStr, nullptr, 16); + + return Color_RGBAf{ + .r = ((hex & 0xFF0000) >> 16) / 255.0f, + .g = ((hex & 0x00FF00) >> 8) / 255.0f, + .b = (hex & 0x0000FF) / 255.0f, + .a = 1.0f, + }; + } + + Color_RGBA8 HexStrToColorRGBA8(const std::string& hexStr) { + uint32_t hex = std::stoi(hexStr, nullptr, 16); + + return Color_RGBA8{ + .r = (uint8_t)((hex & 0xFF0000) >> 16), + .g = (uint8_t)((hex & 0x00FF00) >> 8), + .b = (uint8_t)(hex & 0x0000FF), + .a = 0xFF, + }; + } + + std::string CustomColorOptionText(std::string_view color) { + return std::string(CUSTOM_COLOR_STR.substr(0, CUSTOM_COLOR_STR.length() - 6)).append(color); + } + + std::string GetCustomColor(const std::string& str) { + return str.substr(str.length() - 6); + } + + const std::array gauntletColors = { + "FFFFFF", //Silver + "FECF0F", //Gold + "000006", //Black + "025918", //Green + "06025A", //Blue + "600602", //Bronze + "FF0000", //Red + "025DB0", //Sky Blue + "FA6A90", //Pink + "FF00FF", //Magenta + "D83A00", //Orange + "5B8A06", //Lime + "800080", //Purple + }; + const std::array tunicColors = { + "168A0E", //Kokiri Green + "96000E", //Goron Red + "002A8E", //Zora Blue + "202020", //Black + "FFFFFF", //White + "FF4A0A", //Orange + "86FF23", //Yellow + "0094B0", //Cyan + "362076", //Indigo + "7B0080", //Purple + "F04F7D", //Pink + "323232", //Dark Gray + "E44B4B", //Salmon + "5A1A20", //Wine Red + "7E705B", //Beige + "583923", //Brown + "72602B", //Sand + "6b7E5D", //Tea Green + "3C5800", //Dark Green + "6CFFF8", //Powder Blue + "005A4B", //Teal + "0259FF", //Sky Blue + "33405E", //Faded Blue + "635AD2", //Lavender + "9C1B4B", //Magenta + "52314F", //Mauve + "505A59", //Silver + "F16F16", //Gold + }; + const std::array naviInnerColors = { + "FFFFFF", //White + "00FF00", //Green + "9696FF", //Light Blue + "FFFF00", //Yellow + "FF0000", //Red + "FF00FF", //Magenta + "FECC3C", //Gold + "000000", //Black + "FFFFFF", //Tatl + "49146C", //Tael + "2C9EC4", //Fi + "E6DE83", //Ciela + "D14902", //Epona + "629C5F", //Ezlo + "A83317", //KoRL + "032660", //Linebeck + "D62E31", //Loftwing + "192426", //Midna + "977A6C", //Phantom Zelda + "FF0000", //Rainbow (starts at red) + }; + const std::array naviOuterColors = { + "0000FF", //White + "00FF00", //Green + "9696FF", //Light Blue + "C89B00", //Yellow + "FF0000", //Red + "C8009B", //Magenta + "FEC007", //Gold + "000000", //Black + "C89800", //Tatl + "FF0000", //Tael + "2C1983", //Fi + "C6BE5B", //Ciela + "551F08", //Epona + "3F5D37", //Ezlo + "DED7C5", //KoRL + "EFFFFF", //Linebeck + "FDE6CC", //Loftwing + "D28330", //Midna + "6F4667", //Phantom Zelda + "FF0000", //Rainbow (starts at red) + }; + const std::array weaponTrailColors = { + "FFFFFF", //White + "000000", //Black + "FF0000", //Red + "00FF00", //Green + "0000FF", //Blue + "FFFF00", //Yellow + "00FFFF", //Cyan + "FF00FF", //Magenta + "FFA500", //Orange + "FFD700", //Gold + "800080", //Purple + "FF69B4", //Pink + "FF0000", //Rainbow (starts at red) + }; + + //Generate random hex color + std::string RandomColor() { + std::ostringstream color; + color << std::hex << (rand() % 0x1000000); //use default rand to not interfere with main settings + return color.str(); + } +} //namespace Cosmetics diff --git a/soh/soh/Enhancements/randomizer/3drando/cosmetics.hpp b/soh/soh/Enhancements/randomizer/3drando/cosmetics.hpp new file mode 100644 index 000000000..6f770f011 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/cosmetics.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +namespace Cosmetics { + constexpr std::string_view RANDOM_CHOICE_STR = "Random Choice"; + constexpr std::string_view RANDOM_COLOR_STR = "Random Color"; + constexpr std::string_view CUSTOM_COLOR_STR = "Custom #FFFFFF"; + constexpr std::string_view CUSTOM_COLOR_PREFIX = "Custom #"; + + constexpr std::string_view RANDOM_CHOICE_DESC = "A random color from the list of colors will be\nchosen."; + constexpr std::string_view RANDOM_COLOR_DESC = "A completely random color will be chosen."; + constexpr std::string_view CUSTOM_COLOR_DESC = "Press A and type in a custom 6 digit hex color."; + + enum CosmeticSettings { + RANDOM_CHOICE, + RANDOM_COLOR, + CUSTOM_COLOR, + NON_COLOR_COUNT, + }; + + struct Color_RGBAf { + float r; + float g; + float b; + float a; + }; + + struct Color_RGBA8 { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; + + extern const std::array gauntletColors; + extern const std::array tunicColors; + extern const std::array naviInnerColors; + extern const std::array naviOuterColors; + extern const std::array weaponTrailColors; + + bool ValidHexString(std::string_view hexStr); + Color_RGBAf HexStrToColorRGBAf(const std::string& hexStr); + Color_RGBA8 HexStrToColorRGBA8(const std::string& hexStr); + std::string CustomColorOptionText(std::string_view color); + std::string GetCustomColor(const std::string& str); + std::string RandomColor(); +} //namespace Cosmetics diff --git a/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp b/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp new file mode 100644 index 000000000..e7b2ef7aa --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp @@ -0,0 +1,495 @@ +#include "custom_messages.hpp" +#include "debug.hpp" +#include "shops.hpp" +#include "z64item.h" + +#include +#include +#include + +namespace CustomMessages { + +using namespace std::literals::string_literals; + +class MessageEntryComp { +public: + bool operator()(const MessageEntry& lhs, const MessageEntry& rhs) const { + return lhs.id < rhs.id; + } +}; + +constexpr std::array EnglishDungeonNames = { + "Deku Tree", + "Dodongo's Cavern", + "Jabu Jabu's Belly", + "Forest Temple", + "Fire Temple", + "Water Temple", + "Spirit Temple", + "Shadow Temple", + "Bottom of the Well", + "Ice Cavern", + "Ganon's Tower", + "Gerudo Training Grounds", + "Gerudo Fortress", + "Ganon's Castle", +}; + +constexpr std::array FrenchDungeonNames = { + "Vénérable Arbre Mojo", + "Caverne Dodongo", + "Ventre de Jabu-Jabu", + "Temple de la Forêt", + "Temple du Feu", + "Temple de l'Eau", + "Temple de l'Esprit", + "Temple de l'Ombre", + "Puits", + "Caverne Polaire", + "Tour de Ganon", + "Gymnase Gerudo", + "Repaire des Voleurs", + "Château de Ganon", +}; + +constexpr std::array FrenchDungeonArticles = { + "du ", + "de la ", + "du ", + "du ", + "du ", + "du ", + "du ", + "du ", + "du ", + "de la ", + "", + "du ", + "de la ", + "du ", +}; + +constexpr std::array SpanishDungeonNames = { + "Gran Árbol Deku", + "Cueva de los Dodongos", + "Tripa de Jabu-Jabu", + "Templo del Bosque", + "Templo del Fuego", + "Templo del Agua", + "Templo del Espíritu", + "Templo de las Sombras", + "Fondo del pozo", + "Caverna de hielo", + "Torre de Ganon", + "Centro de Instrucción Gerudo", + "Fortaleza Gerudo", + "Castillo de Ganon", +}; + +constexpr std::array SpanishDungeonArticles = { + "del", + "de la", + "de la", + "del", + "del", + "del", + "del", + "del", + "del", + "de la", + "de la", + "del", + "de la", + "del", +}; + +constexpr std::array DungeonColors = { + QM_GREEN, + QM_RED, + QM_BLUE, + QM_GREEN, + QM_RED, + QM_BLUE, + QM_YELLOW, + QM_PINK, + QM_PINK, + QM_LBLUE, + QM_BLACK, + QM_YELLOW, + QM_YELLOW, + QM_RED, +}; + + std::set messageEntries; + std::vector arrangedMessageEntries; + std::stringstream messageData; + std::string arrangedMessageData; + + //textBoxType and textBoxPosition are defined here: https://wiki.cloudmodding.com/oot/Text_Format#Message_Id + void CreateMessage(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, + std::string englishText, std::string frenchText, std::string spanishText) { + MessageEntry newEntry = { textId, unk_04, textBoxType, textBoxPosition, { 0 } }; + + while ((englishText.size() % 4) != 0) { + englishText += "\0"s; + } + messageData.seekg(0, messageData.end); + newEntry.info[ENGLISH_U].offset = (char*)((int)messageData.tellg()); + newEntry.info[ENGLISH_U].length = englishText.size(); + messageData << englishText; + + while ((frenchText.size() % 4) != 0) { + frenchText += "\0"s; + } + messageData.seekg(0, messageData.end); + newEntry.info[FRENCH_U].offset = (char*)((int)messageData.tellg()); + newEntry.info[FRENCH_U].length = frenchText.size(); + messageData << frenchText; + + while ((spanishText.size() % 4) != 0) { + spanishText += "\0"s; + } + messageData.seekg(0, messageData.end); + newEntry.info[SPANISH_U].offset = (char*)((int)messageData.tellg()); + newEntry.info[SPANISH_U].length = spanishText.size(); + messageData << spanishText; + + messageEntries.insert(newEntry); + } + + void CreateMessageFromTextObject(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, const Text& text) { + CreateMessage(textId, unk_04, textBoxType, textBoxPosition, text.GetEnglish(), text.GetFrench(), text.GetSpanish()); + } + + uint32_t NumMessages() { + return messageEntries.size(); + } + + std::pair RawMessageEntryData() { + arrangedMessageEntries.assign(messageEntries.begin(), messageEntries.end()); + const char* data = (const char*)arrangedMessageEntries.data(); + uint32_t size = arrangedMessageEntries.size() * sizeof(MessageEntry); + return { data, size }; + } + + std::pair RawMessageData() { + arrangedMessageData = messageData.str(); + const char* data = arrangedMessageData.data(); + uint32_t size = arrangedMessageData.size(); + return { data, size }; + } + + void CreateAlwaysIncludedMessages() { + // Bombchu (10) Purchase Prompt + CreateMessage(0x8C, 0, 2, 3, + INSTANT_TEXT_ON()+"Bombchu (10): 99 Rupees"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Buy"+NEWLINE()+"Don't buy"+COLOR(QM_WHITE)+MESSAGE_END(), + INSTANT_TEXT_ON()+"Bombchus (10): 99 rubis"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Acheter"+NEWLINE()+"Ne pas acheter"+COLOR(QM_WHITE)+MESSAGE_END(), + INSTANT_TEXT_ON()+"Bombchus (10): 99 rupias"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Comprar"+NEWLINE()+"No comprar"+COLOR(QM_WHITE)+MESSAGE_END()); + //Gold Skulltula Tokens (there are two text IDs the game uses) + for (const uint32_t textId : {0xB4, 0xB5}) { + CreateMessage(textId, 0, 2, 3, + INSTANT_TEXT_ON()+"You destroyed a "+COLOR(QM_RED)+"Gold Skulltula"+COLOR(QM_WHITE)+". You got a"+NEWLINE()+"token proving you destroyed it!"+NEWLINE()+NEWLINE()+"You have "+COLOR(QM_RED)+SKULLTULAS_DESTROYED()+COLOR(QM_WHITE)+" tokens!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+"Vous venez de détruire une "+COLOR(QM_RED)+"Skulltula d'or"+COLOR(QM_WHITE)+"!"+NEWLINE()+"Ce symbole prouve votre prouesse!"+NEWLINE()+NEWLINE()+"Vous avez "+COLOR(QM_RED)+SKULLTULAS_DESTROYED()+COLOR(QM_WHITE)+" jetons!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+"¡Has eliminado una "+COLOR(QM_RED)+"skulltula dorada"+COLOR(QM_WHITE)+" y has"+NEWLINE()+"conseguido un símbolo para probarlo!"+NEWLINE()+NEWLINE()+"¡Tienes "+COLOR(QM_RED)+SKULLTULAS_DESTROYED()+COLOR(QM_WHITE)+" símbolos!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + + //Bombchu (10) Description + CreateMessage(0xBC, 0, 2, 3, + INSTANT_TEXT_ON()+COLOR(QM_RED)+"Bombchu (10): 99 Rupees"+NEWLINE()+COLOR(QM_WHITE)+"These look like toy mice, but they're"+NEWLINE()+"actually self-propelled time bombs!"+INSTANT_TEXT_OFF()+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+"Bombchus (10): 99 rubis"+NEWLINE()+COLOR(QM_WHITE)+"Profilée comme une souris mécanique, il"+NEWLINE()+"s'agit en fait d'une bombe à retardement"+NEWLINE()+"autopropulsée!"+INSTANT_TEXT_OFF()+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+"Bombchus (10): 99 rupias"+NEWLINE()+COLOR(QM_WHITE)+"Aunque parezcan ratoncitos de juguete,"+NEWLINE()+"¡son bombas de relojería autopropulsadas!"+INSTANT_TEXT_OFF()+SHOP_MESSAGE_BOX()+MESSAGE_END()); + //Boss Keys + for (uint32_t bossKey = 0; bossKey <= (DUNGEON_SHADOW_TEMPLE - DUNGEON_FOREST_TEMPLE); bossKey++) { + uint32_t dungeon = DUNGEON_FOREST_TEMPLE + bossKey; + CreateMessage(0x9D4 + bossKey, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"You got the "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Boss Key"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"Vous trouvez la "+COLOR(DungeonColors[dungeon])+"Clé d'Or "+NEWLINE()+FrenchDungeonArticles[dungeon]+" "+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"¡Tienes la "+COLOR(DungeonColors[dungeon])+"gran llave "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + CreateMessage(0x9D9, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"You got the "+COLOR(DungeonColors[DUNGEON_GANONS_CASTLE_FIRST_PART])+EnglishDungeonNames[DUNGEON_GANONS_CASTLE_FIRST_PART]+NEWLINE()+"Boss Key"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"Vous trouvez la "+COLOR(DungeonColors[DUNGEON_GANONS_CASTLE_FIRST_PART])+"Clé d'Or "+NEWLINE()+FrenchDungeonArticles[DUNGEON_GANONS_CASTLE_FIRST_PART]+" "+FrenchDungeonNames[DUNGEON_GANONS_CASTLE_FIRST_PART]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"¡Tienes la "+COLOR(DungeonColors[DUNGEON_GANONS_CASTLE_FIRST_PART])+"gran llave "+SpanishDungeonArticles[DUNGEON_GANONS_CASTLE_FIRST_PART]+NEWLINE()+SpanishDungeonNames[DUNGEON_GANONS_CASTLE_FIRST_PART]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + //Compasses + for (uint32_t dungeon = DUNGEON_DEKU_TREE; dungeon <= DUNGEON_ICE_CAVERN; dungeon++) { + CreateMessage(0x9DA + dungeon, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_COMPASS)+INSTANT_TEXT_ON()+"You got the "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Compass"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_COMPASS)+INSTANT_TEXT_ON()+"Vous trouvez la "+COLOR(DungeonColors[dungeon])+"boussole "+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_COMPASS)+INSTANT_TEXT_ON()+"¡Tienes la "+COLOR(DungeonColors[dungeon])+"brújula "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //Maps + for (uint32_t dungeon = DUNGEON_DEKU_TREE; dungeon <= DUNGEON_ICE_CAVERN; dungeon++) { + CreateMessage(0x9E4 + dungeon, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_DUNGEON_MAP)+INSTANT_TEXT_ON()+"You got the "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Map"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_DUNGEON_MAP)+INSTANT_TEXT_ON()+"Vous trouvez la "+COLOR(DungeonColors[dungeon])+"carte "+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_DUNGEON_MAP)+INSTANT_TEXT_ON()+"¡Has obtenido el "+COLOR(DungeonColors[dungeon])+"mapa "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //Small Keys + for (uint32_t smallKey = 0; smallKey <= (DUNGEON_BOTTOM_OF_THE_WELL - DUNGEON_FOREST_TEMPLE); smallKey++) { + uint32_t dungeon = DUNGEON_FOREST_TEMPLE + smallKey; + CreateMessage(0x9EE + smallKey, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got a "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Small Key"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez une "+COLOR(DungeonColors[dungeon])+"Petite Clé"+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido una "+COLOR(DungeonColors[dungeon])+"llave pequeña "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + for (uint32_t smallKey = 0; smallKey <= (DUNGEON_GANONS_CASTLE_FIRST_PART - DUNGEON_GERUDO_TRAINING_GROUNDS); smallKey++) { + uint32_t dungeon = DUNGEON_GERUDO_TRAINING_GROUNDS + smallKey; + CreateMessage(0x9F4 + smallKey, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got a "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Small Key"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez une "+COLOR(DungeonColors[dungeon])+"Petite Clé"+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido una "+COLOR(DungeonColors[dungeon])+"llave pequeña "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //Key Rings + for (uint32_t smallKey = 0; smallKey <= (DUNGEON_BOTTOM_OF_THE_WELL - DUNGEON_FOREST_TEMPLE); smallKey++) { + uint32_t dungeon = DUNGEON_FOREST_TEMPLE + smallKey; + CreateMessage(0x9300 + smallKey, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got a "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Key Ring"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez un "+COLOR(DungeonColors[dungeon])+"trousseau"+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido un "+COLOR(DungeonColors[dungeon])+"llavero "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + for (uint32_t smallKey = 0; smallKey <= (DUNGEON_GANONS_CASTLE_FIRST_PART - DUNGEON_GERUDO_TRAINING_GROUNDS); smallKey++) { + uint32_t dungeon = DUNGEON_GERUDO_TRAINING_GROUNDS + smallKey; + CreateMessage(0x9306 + smallKey, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got a "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Key Ring"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez un "+COLOR(DungeonColors[dungeon])+"trousseau"+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido un "+COLOR(DungeonColors[dungeon])+"llavero "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //Tycoon's Wallet + CreateMessage(0x09F7, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_WALLET_GIANT)+INSTANT_TEXT_ON()+"You got a "+COLOR(QM_RED)+"Tycoon's Wallet"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+NEWLINE()+"It's gigantic! Now you can carry"+NEWLINE()+"up to "+COLOR(QM_YELLOW)+"999 "+COLOR(QM_WHITE)+COLOR(QM_YELLOW)+"Rupees"+COLOR(QM_WHITE)+"!"+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_WALLET_GIANT)+INSTANT_TEXT_ON()+"Vous obtenez la "+COLOR(QM_RED)+"Bourse de star"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+NEWLINE()+"Elle peut contenir jusqu'à "+COLOR(QM_YELLOW)+"999 "+COLOR(QM_WHITE)+COLOR(QM_YELLOW)+"rubis"+COLOR(QM_WHITE)+"!"+NEWLINE()+"C'est gigantesque!"+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_WALLET_GIANT)+INSTANT_TEXT_ON()+"¡Has conseguido una "+COLOR(QM_RED)+"bolsa para ricachones"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+NEWLINE()+"¡Qué descomunal! Ya puedes llevar"+NEWLINE()+"hasta "+COLOR(QM_YELLOW)+"999 "+COLOR(QM_WHITE)+COLOR(QM_YELLOW)+"rupias"+COLOR(QM_WHITE)+"!"+MESSAGE_END()); + //Saria's Song Default Hint + CreateMessage(0x0A00, 0, 2, 3, + UNSKIPPABLE()+"Have you tried talking to the gossip"+NEWLINE()+ "stones around Hyrule? They might have"+NEWLINE()+"some good advice... Hee hee!"+WAIT_FOR_INPUT()+"If you learn something from the gossip stones,"+NEWLINE()+"I will remember it!"+EVENT_TRIGGER()+MESSAGE_END(), + UNSKIPPABLE()+"As-tu parlé aux pierres à potins"+NEWLINE()+ "dans Hyrule? Elles sont de bons conseils..."+NEWLINE()+"Hi hi!"+WAIT_FOR_INPUT()+"Si elles te révèlent quelque chose,"+NEWLINE()+"je m'en souviendrai!"+EVENT_TRIGGER()+MESSAGE_END(), + UNSKIPPABLE()+"¿Has probado a consultarle a las"+NEWLINE()+ "piedras chismosas esparcidas por Hyrule? Puede"+NEWLINE()+"que sean de ayuda a tu empresa... ¡Ji, ji!"+WAIT_FOR_INPUT()+"¡Puedo recordarte todo lo que aprendas de ellas,"+NEWLINE()+"si así lo deseas!"+EVENT_TRIGGER()+MESSAGE_END()); + //Poe Collector (when enough has been sold) + CreateMessage(0x70F8, 0, 0, 0, + UNSKIPPABLE()+"Wait a minute! WOW!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"You have earned enough points!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Young man, you are a genuine "+COLOR(QM_RED)+"ghost hunter"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Is that what you expected me to say?"+NEWLINE()+"Heh heh heh!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Because of you, I have extra inventory of"+NEWLINE()+COLOR(QM_RED)+"Big Poes"+COLOR(QM_WHITE)+", so this will be the last time I can"+NEWLINE() + +"buy one of these ghosts."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"You're thinking about what I promised would"+NEWLINE()+"happen when you earned enough points."+NEWLINE()+"Heh heh."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Don't worry. I didn't forget. Just take this."+MESSAGE_END(), + UNSKIPPABLE()+"Ooooh! WHOA!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Tu as obtenu suffisamment de points!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Tu es un véritable "+COLOR(QM_RED)+"chasseur de fantômes"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Il est content, hein?"+NEWLINE()+"Il est content le monsieur?"+NEWLINE()+"Hé hé hé!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Grâce à toi, mon stock d'"+COLOR(QM_RED)+"Âmes"+COLOR(QM_WHITE)+" est plein!"+NEWLINE()+"C'est donc la dernière fois que nous"+NEWLINE()+"faisons affaire."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Je sais, je sais..."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Nous avions passé un pacte..."+NEWLINE()+"Tu as eu tes points et je t'en félicite..."+NEWLINE()+"Hé hé hé!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Alors prends donc ceci, mon bon ami!"+MESSAGE_END(), + UNSKIPPABLE()+"¡Un momento! ¡OYE!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¡Has conseguido los puntos suficientes!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¡Jovencito, eres un auténtico "+COLOR(QM_RED)+"cazador de"+NEWLINE()+"fantasmas"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"¿Era eso lo que esperabas que dijera?"+NEWLINE()+"¡Je, je je!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Gracias a ti, ya tengo la cantidad necesaria"+NEWLINE()+"de "+COLOR(QM_RED)+"grandes poes"+COLOR(QM_WHITE)+", así que esta será la"+NEWLINE() + +"última vez que te compre unos de ese tipo."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¿Recuerdas lo que te dije que ocurriría"+NEWLINE()+"cuando tuvieses suficientes puntos?"+NEWLINE()+"Je, je, je."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Tranquilo, que no se me ha olvidado."+NEWLINE()+"Toma esto."+MESSAGE_END()); + //Ice Trap + CreateMessage(0x9002, 0, 2, 3, + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+COLOR(QM_RED)+"FOOL!"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+COLOR(QM_RED)+"IDIOT!"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+COLOR(QM_RED)+"¡TONTO!"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END()); + //Business Scrubs + //The less significant byte represents the price of the item + for (uint32_t price = 0; price <= 95; price += 5) { + CreateMessage(0x9000 + price, 0, 0, 0, + INSTANT_TEXT_ON()+"I'll sell you something good for "+COLOR(QM_RED)+std::to_string(price)+" Rupees"+COLOR(QM_WHITE)+"!"+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"OK"+NEWLINE()+"No way"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+"Je te vends un truc super pour "+COLOR(QM_RED)+std::to_string(price)+" Rubis"+COLOR(QM_WHITE)+"!"+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"D'accord"+NEWLINE()+"Hors de question"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+"¡Te puedo vender algo bueno por "+COLOR(QM_RED)+std::to_string(price)+" rupias"+COLOR(QM_WHITE)+"!"+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Vale"+NEWLINE()+"Ni hablar"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //Poe Collector + //The last digit represent the number of poes needed to collect + for (uint32_t poes = 1; poes <= 10; poes++) { + CreateMessage(0x9080 + poes, 0, 0, 0, + UNSKIPPABLE()+"Oh, you brought a Poe today!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Hmmmm!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Very interesting! This is a "+COLOR(QM_RED)+"Big Poe"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"I'll buy it for "+COLOR(QM_RED)+"50 Rupees"+COLOR(QM_WHITE)+"."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"On top of that, I'll put "+COLOR(QM_RED)+"100 points "+COLOR(QM_WHITE)+"on"+NEWLINE()+"your card."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"If you earn "+COLOR(QM_RED)+std::to_string(poes * 100)+" points"+COLOR(QM_WHITE)+", you'll be a"+NEWLINE()+"happy man! Heh heh."+MESSAGE_END(), + + UNSKIPPABLE()+"Oh! Tu as apporté un fantôme!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Hmmmm!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Magnifique!"+NEWLINE()+"C'est une "+COLOR(QM_RED)+"Âme"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Je t'en donne "+COLOR(QM_RED)+"50 Rubis"+COLOR(QM_WHITE)+"."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Et en plus, j'inscris "+COLOR(QM_RED)+"100 points "+COLOR(QM_WHITE)+NEWLINE()+"sur ta carte."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Obtiens "+COLOR(QM_RED)+std::to_string(poes * 100)+" points"+COLOR(QM_WHITE)+" et tu ne"+NEWLINE()+"seras pas déçu..."+NEWLINE()+"Hé hé hé."+MESSAGE_END(), + + UNSKIPPABLE()+"¡Vaya! ¡Traes un poe!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¡Mmm! ¿A ver?"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¡Qué interesante! ¡Es un "+COLOR(QM_RED)+"gran poe"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Te daré "+COLOR(QM_RED)+"50 rupias "+COLOR(QM_WHITE)+"por él."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Y además agregaré "+COLOR(QM_RED)+"100 puntos "+COLOR(QM_WHITE)+"a tu"+NEWLINE()+"tarjeta."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"¡Si llegas a "+COLOR(QM_RED)+std::to_string(poes * 100)+" puntos"+COLOR(QM_WHITE)+", serás muy feliz!"+NEWLINE()+"Je, je, je..."+MESSAGE_END()); + } + + //Talon (this is to prevent accidentally skipping Malon in HC) + CreateMessage(0x9100, 0, 2, 0, + UNSKIPPABLE()+"You should go talk to my daughter Malon,"+NEWLINE()+"she has an item for you."+NEWLINE()+SET_SPEED(3)+"........."+SET_SPEED(0)+WAIT_FOR_INPUT()+"I have to think about some stuff now,"+NEWLINE()+"please don't distract me."+MESSAGE_END(), + UNSKIPPABLE()+"Zzzz... Muh... Malon..."+NEWLINE()+"Parler avec... Malon..."+NEWLINE()+SET_SPEED(3)+"........."+SET_SPEED(0)+WAIT_FOR_INPUT()+"Si fatigué..."+NEWLINE()+"Quelle vie..."+MESSAGE_END(), + UNSKIPPABLE()+"Habla con Malon, tiene algo que darte..."+SET_SPEED(3)+"........."+SET_SPEED(0)+MESSAGE_END()); + + //Bow Shooting Gallery reminder + CreateMessage(0x9140, 0, 0, 0, + UNSKIPPABLE()+"Wonderful! Bravo! Perfect!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Here's a fantastic present! But I have"+COLOR(QM_RED)+NEWLINE()+"something else "+COLOR(QM_WHITE)+"for you once you have a bow."+SET_SPEED(30)+" "+EVENT_TRIGGER()+MESSAGE_END(), + UNSKIPPABLE()+"Merveilleux! Bravo! C'est parfait!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Voici un prix fantastique! J'aurai "+COLOR(QM_RED)+"autre chose"+COLOR(QM_WHITE)+NEWLINE()+"pour toi quand tu auras un arc."+SET_SPEED(30)+" "+EVENT_TRIGGER()+MESSAGE_END(), + UNSKIPPABLE()+"¡Espectacular! ¡Bravo! ¡Perfecto!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¡Toma este sensacional regalo! Pero te tengo"+NEWLINE()+"guardado "+COLOR(QM_RED)+"algo más "+COLOR(QM_WHITE)+"para cuando traigas tu"+NEWLINE()+"propio arco."+SET_SPEED(30)+" "+EVENT_TRIGGER()+MESSAGE_END()); + + //Shopsanity items + //64 textboxes, 2 for each of 32 potential shopsanity items + for(uint32_t shopitems = 0; shopitems < NonShopItems.size(); shopitems++) { + Text name = NonShopItems[shopitems].Name; + std::string price = std::to_string(NonShopItems[shopitems].Price); + //Prevent names from being too long and overflowing textbox + if (name.GetEnglish() == "Piece of Heart (Treasure Chest Minigame)") { + name = Text{"Piece of Heart", "Quart de Coeur", "Pieza de corazón"}; + } else if (name.GetEnglish() == "Green Rupee (Treasure Chest Minigame)") { + name = Text{"Green Rupee", "Rubis Vert", "Rupia verde"}; + } + //Message to display when hovering over the item + if (NonShopItems[shopitems].Repurchaseable) { //Different checkbox for repurchaseable items + CreateMessage(0x9200+shopitems*2, 0, 0, 0, + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetEnglish()+": "+price+" Rupees"+NEWLINE()+COLOR(QM_WHITE)+"Special deal!"+NEWLINE()+"Buy as many as you want!"+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetFrench()+": "+price+" rubis"+NEWLINE()+COLOR(QM_WHITE)+"Offre spéciale!"+NEWLINE()+"Achetez-en à volonté!"+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetSpanish()+": "+price+" rupias"+NEWLINE()+COLOR(QM_WHITE)+"¡Oferta especial!"+NEWLINE()+"¡Compra todo lo que quieras!"+SHOP_MESSAGE_BOX()+MESSAGE_END()); + } + else { //Normal textbox + CreateMessage(0x9200+shopitems*2, 0, 0, 0, + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetEnglish()+": "+price+" Rupees"+NEWLINE()+COLOR(QM_WHITE)+"Special deal! ONE LEFT!"+NEWLINE()+"Get it while it lasts!"+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetFrench()+": "+price+" rubis"+NEWLINE()+COLOR(QM_WHITE)+"Offre spéciale! DERNIER EN STOCK!"+NEWLINE()+"Faites vite!"+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetSpanish()+": "+price+" rupias"+NEWLINE()+COLOR(QM_WHITE)+"¡Oferta especial! ¡SOLO QUEDA UNA UNIDAD!"+NEWLINE()+"¡Hazte con ella antes de que se agote!"+SHOP_MESSAGE_BOX()+MESSAGE_END()); + } + //Message to display when going to buy the item + CreateMessage(0x9200+shopitems*2+1, 0, 0, 0, + INSTANT_TEXT_ON()+name.GetEnglish()+": "+price+" Rupees"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Buy"+NEWLINE()+"Don't buy"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+name.GetFrench()+": "+price+" rubis"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Acheter"+NEWLINE()+"Ne pas acheter"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+name.GetSpanish()+": "+price+" rupias"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Comprar"+NEWLINE()+"No comprar"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //easter egg + CreateMessage(0x96F, 0, 2, 2, + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Oh hey, you watched all the credits!"+NEWLINE()+CENTER_TEXT()+"Here's a prize for your patience."+NEWLINE()+CENTER_TEXT()+"Unlocking MQ and saving..."+NEWLINE()+NEWLINE()+CENTER_TEXT()+COLOR(QM_RED)+"Do not remove the Game Card"+NEWLINE()+CENTER_TEXT()+"or turn the power off."+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"The Legend of Zelda Ocarina of Time 3D"+NEWLINE()+CENTER_TEXT()+"Master Quest va être déverrouillé."+NEWLINE()+CENTER_TEXT()+"Sauvegarde... Veuillez patienter."+NEWLINE()+NEWLINE()+CENTER_TEXT()+COLOR(QM_RED)+"N'éteignez pas la console et"+NEWLINE()+CENTER_TEXT()+"ne retirez pas la carte de jeu"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Desbloqueando The Legend of Zelda"+NEWLINE()+CENTER_TEXT()+"Ocarina of Time 3D Master Quest."+NEWLINE()+CENTER_TEXT()+"Guardando. Espera un momento..."+NEWLINE()+NEWLINE()+CENTER_TEXT()+COLOR(QM_RED)+"No saques la tarjeta de juego"+NEWLINE()+CENTER_TEXT()+"ni apagues la consola."+INSTANT_TEXT_OFF()+MESSAGE_END()); + CreateMessage(0x970, 0, 2, 3, + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Master Quest doesn't affect the Randomizer,"+NEWLINE()+CENTER_TEXT()+"so you can use 3 more save slots now."+NEWLINE()+NEWLINE()+CENTER_TEXT()+"Thanks for playing!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Vous pouvez désormais jouer à"+NEWLINE()+CENTER_TEXT()+"The Legend of Zelda Ocarina of Time 3D"+NEWLINE()+CENTER_TEXT()+"Master Quest!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"¡Ya puedes jugar The Legend of Zelda"+NEWLINE()+CENTER_TEXT()+"Ocarina of Time 3D Master Quest!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + + //Messages for the new Lake Hylia switch + CreateMessage(0x346, 0, 1, 3, + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Water level control system."+NEWLINE()+CENTER_TEXT()+"Keep away!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Contrôle du niveau d'eau."+NEWLINE()+CENTER_TEXT()+"Ne pas toucher!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Control del nivel del agua."+NEWLINE()+CENTER_TEXT()+"¡No te acerques!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + CreateMessage(0x1B3, 0, 0, 3, + UNSKIPPABLE()+"This switch is rustier than you think."+WAIT_FOR_INPUT()+"Something must be wrong with the pipe"+NEWLINE()+"system in the Water Temple."+MESSAGE_END(), + UNSKIPPABLE()+"Cet interrupteur est très rouillé."+WAIT_FOR_INPUT()+"Quelque chose ne va pas avec"+NEWLINE()+"la tuyauterie du Temple de l'Eau."+MESSAGE_END(), + UNSKIPPABLE()+"El interruptor está más oxidado de lo que"+NEWLINE()+"aparenta."+WAIT_FOR_INPUT()+"Algo debe andar mal en el sistema de"+NEWLINE()+"cañerías del Templo del Agua."+MESSAGE_END()); + + //Treasure chest shop keys. If they're not randomized leave the base game text + if (Settings::ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS)) { + CreateMessage(0x0F3, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got a "+COLOR(QM_RED)+"Treasure Chest Shop"+NEWLINE()+"Small Key"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez une "+COLOR(QM_RED)+"Petite Clé"+NEWLINE()+"de la Chasse-aux-Trésors"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido una "+COLOR(QM_RED)+"llave pequeña del"+NEWLINE()+"Cofre del Tesoro"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } else if (Settings::ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK)) { + CreateMessage(0x0F3, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got all 6 "+COLOR(QM_RED)+"Treasure Chest Shop"+NEWLINE()+"Small Keys"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez les "+COLOR(QM_RED)+"petites clés"+NEWLINE()+"de la Chasse-aux-Trésors"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido todas las 6 "+COLOR(QM_RED)+"llaves"+NEWLINE()+"pequeñas del Cofre del Tesoro"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + } + + Text AddColorsAndFormat(Text text, const std::vector& colors /*= {}*/) { + + //for each language + for (std::string* textStr : {&text.english, &text.french, &text.spanish}) { + + //insert playername + size_t atSymbol = textStr->find('@'); + while (atSymbol != std::string::npos) { + textStr->replace(atSymbol, 1, PLAYER_NAME()); + atSymbol = textStr->find('@'); + } + //insert newlines either manually or when encountering a '&' + constexpr size_t lineLength = 44; + size_t lastNewline = 0; + while (lastNewline + lineLength < textStr->length()) { + size_t carrot = textStr->find('^', lastNewline); + size_t ampersand = textStr->find('&', lastNewline); + size_t lastSpace = textStr->rfind(' ', lastNewline + lineLength); + size_t lastPeriod = textStr->rfind('.', lastNewline + lineLength); + //replace '&' first if it's within the newline range + if (ampersand < lastNewline + lineLength) { + textStr->replace(ampersand, 1, NEWLINE()); + lastNewline = ampersand + NEWLINE().length(); + //or move the lastNewline cursor to the next line if a '^' is encountered + } else if (carrot < lastNewline + lineLength) { + lastNewline = carrot + 1; + //some lines need to be split but don't have spaces, look for periods instead + } else if (lastSpace == std::string::npos) { + textStr->replace(lastPeriod, 1, "."+NEWLINE()); + lastNewline = lastPeriod + NEWLINE().length() + 1; + } else { + textStr->replace(lastSpace, 1, NEWLINE()); + lastNewline = lastSpace + NEWLINE().length(); + } + } + //clean up any remaining '&' characters + size_t ampersand = textStr->find('&'); + while (ampersand != std::string::npos) { + textStr->replace(ampersand, 1, NEWLINE()); + ampersand = textStr->find('&'); + } + + //insert box break + size_t carrotSymbol = textStr->find('^'); + while (carrotSymbol != std::string::npos) { + textStr->replace(carrotSymbol, 1, INSTANT_TEXT_OFF()+WAIT_FOR_INPUT()+INSTANT_TEXT_ON()); + carrotSymbol = textStr->find('^'); + } + //add colors + for (auto color : colors) { + size_t firstHashtag = textStr->find('#'); + if (firstHashtag != std::string::npos) { + textStr->replace(firstHashtag, 1, COLOR(color)); + size_t secondHashtag = textStr->find('#'); + if (secondHashtag == std::string::npos) { + CitraPrint("ERROR: Couldn't find second '#' in " + (*textStr)); + } else { + textStr->replace(secondHashtag, 1, COLOR(QM_WHITE)); + } + } + } + } + return Text{"","",""}+UNSKIPPABLE()+INSTANT_TEXT_ON()+text+INSTANT_TEXT_OFF()+MESSAGE_END(); + } + + void ClearMessages() { + messageEntries.clear(); + arrangedMessageEntries.clear(); + messageData.str(""); + arrangedMessageData = ""; + } + + std::string MESSAGE_END() { return "\x7F\x00"s; } + std::string WAIT_FOR_INPUT() { return "\x7F\x01"s; } + std::string HORIZONTAL_SPACE(uint8_t x) { + return "\x7F\x02"s + char(x); + } + std::string GO_TO(uint16_t x) { + return "\x7F\x03"s + char(x >> 8) + char(x & 0x00FF); + } + std::string INSTANT_TEXT_ON() { return "\x7F\x04"s; } + std::string INSTANT_TEXT_OFF() { return "\x7F\x05"s; } + std::string SHOP_MESSAGE_BOX() { return "\x7F\x06\x00"s; } + std::string EVENT_TRIGGER() { return "\x7F\x07"s; } + std::string DELAY_FRAMES(uint8_t x) { + return "\x7F\x08"s + char(x); + } + std::string CLOSE_AFTER(uint8_t x) { + return "\x7F\x0A"s + char(x); + } + std::string PLAYER_NAME() { return "\x7F\x0B"s; } + std::string PLAY_OCARINA() { return "\x7F\x0C"s; } + std::string ITEM_OBTAINED(uint8_t x) { + return "\x7F\x0F"s + char(x); + } + std::string SET_SPEED(uint8_t x) { + return "\x7F\x10"s + char(x); + } + std::string SKULLTULAS_DESTROYED() { return "\x7F\x15"s; } + std::string CURRENT_TIME() { return "\x7F\x17"s; } + std::string UNSKIPPABLE() { return "\x7F\x19"s; } + std::string TWO_WAY_CHOICE() { return "\x7F\x1A\xFF\xFF\xFF\xFF"s; } + std::string NEWLINE() { return "\x7F\x1C"s; } + std::string COLOR(uint8_t x) { return "\x7F\x1D"s + char(x); } + std::string CENTER_TEXT() { return "\x7F\x1E"s; } + std::string IF_NOT_MQ() { return "\x7F\x29"s; } + std::string MQ_ELSE() { return "\x7F\x2A"s; } + std::string MQ_END() { return "\x7F\x2B"s; } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp b/soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp new file mode 100644 index 000000000..2f17b62ef --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include +#include +#include + +#include "text.hpp" + +#define QM_WHITE 0x00 +#define QM_RED 0x41 +#define QM_GREEN 0x42 +#define QM_BLUE 0x43 +#define QM_LBLUE 0x44 +#define QM_PINK 0x45 +#define QM_YELLOW 0x46 +#define QM_BLACK 0x47 + +namespace CustomMessages { +typedef struct { + // In the true file format, offset is the offset into the QM file. + // In randomizer, offset will be a pointer to the text in the game's address space. + // Since these pointers will be much larger as u32 than the original script's offsets, + // We will be able to distinguish between original and custom text using their numerical value. + const char* offset; + uint32_t length; +} MessageLanguageInfo; + +typedef enum { + /* 0x00 */ JAPANESE_J, + /* 0x01 */ ENGLISH_U, + /* 0x02 */ ENGLISH_E, + /* 0x03 */ GERMAN_E, + /* 0x04 */ FRENCH_E, + /* 0x05 */ FRENCH_U, + /* 0x06 */ SPANISH_E, + /* 0x07 */ SPANISH_U, + /* 0x08 */ ITALIAN_E, + /* 0x09 */ DUTCH_E, +} MessageLanguage; + +typedef struct { + uint32_t id; + uint32_t unk_04; + uint32_t unk_08; + uint32_t unk_0C; + MessageLanguageInfo info[10]; +} MessageEntry; // size = 0x60 + +typedef struct { + char magic[4]; //"QM\0\0" + uint32_t unk_04; + uint32_t numEntries; + uint32_t unk_0C; +} MessageFileHeader; + + void CreateMessage(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, + std::string englishText, std::string frenchText, std::string spanishText); + void CreateMessageFromTextObject(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, const Text& text); + + uint32_t NumMessages(); + + std::pair RawMessageEntryData(); + std::pair RawMessageData(); + + void CreateAlwaysIncludedMessages(); + Text AddColorsAndFormat(Text text, const std::vector& colors = {}); + void ClearMessages(); + + std::string MESSAGE_END(); + std::string WAIT_FOR_INPUT(); + std::string HORIZONTAL_SPACE(uint8_t x); + std::string GO_TO(uint16_t x); + std::string INSTANT_TEXT_ON(); + std::string INSTANT_TEXT_OFF(); + std::string SHOP_MESSAGE_BOX(); + std::string EVENT_TRIGGER(); + std::string DELAY_FRAMES(uint8_t x); + std::string CLOSE_AFTER(uint8_t x); + std::string PLAYER_NAME(); + std::string PLAY_OCARINA(); + std::string ITEM_OBTAINED(uint8_t x); + std::string SET_SPEED(uint8_t x); + std::string SKULLTULAS_DESTROYED(); + std::string CURRENT_TIME(); + std::string UNSKIPPABLE(); + std::string TWO_WAY_CHOICE(); + std::string NEWLINE(); + std::string COLOR(uint8_t x); + std::string CENTER_TEXT(); + std::string IF_NOT_MQ(); + std::string MQ_ELSE(); + std::string MQ_END(); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/debug.cpp b/soh/soh/Enhancements/randomizer/3drando/debug.cpp new file mode 100644 index 000000000..a51181c1e --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/debug.cpp @@ -0,0 +1,5 @@ +#include "debug.hpp" + +void CitraPrint (std::string_view str) { + +} diff --git a/soh/soh/Enhancements/randomizer/3drando/debug.hpp b/soh/soh/Enhancements/randomizer/3drando/debug.hpp new file mode 100644 index 000000000..ebce65e0a --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/debug.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +void CitraPrint(std::string_view str); diff --git a/soh/soh/Enhancements/randomizer/3drando/dungeon.cpp b/soh/soh/Enhancements/randomizer/3drando/dungeon.cpp new file mode 100644 index 000000000..4ab26aba0 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/dungeon.cpp @@ -0,0 +1,616 @@ +#include "dungeon.hpp" + +#include "category.hpp" +#include "item_location.hpp" +#include "pool_functions.hpp" +#include "keys.hpp" + +namespace Dungeon { + +DungeonInfo::DungeonInfo(std::string name_, uint32_t map_, uint32_t compass_, uint32_t smallKey_, uint32_t keyRing_, + uint32_t bossKey_, uint8_t vanillaKeyCount_, uint8_t mqKeyCount_, + std::vector vanillaLocations_, + std::vector mqLocations_, + std::vector sharedLocations_) + : name(std::move(name_)), + map(map_), + compass(compass_), + smallKey(smallKey_), + keyRing(keyRing_), + bossKey(bossKey_), + vanillaKeyCount(vanillaKeyCount_), + mqKeyCount(mqKeyCount_), + vanillaLocations(std::move(vanillaLocations_)), + mqLocations(std::move(mqLocations_)), + sharedLocations(std::move(sharedLocations_)) {} + +DungeonInfo::~DungeonInfo() = default; + +uint32_t DungeonInfo::GetSmallKey() const { + return smallKey; +} + +uint32_t DungeonInfo::GetKeyRing() const { + return keyRing; +} + +uint32_t DungeonInfo::GetMap() const { + return map; +} + +uint32_t DungeonInfo::GetCompass() const { + return compass; +} + +uint32_t DungeonInfo::GetBossKey() const { + return bossKey; +} + +void DungeonInfo::PlaceVanillaMap() { + if (map == NONE) { + return; + } + + auto dungeonLocations = GetDungeonLocations(); + auto mapLocation = FilterFromPool(dungeonLocations, [](const uint32_t loc){ return Location(loc)->IsCategory(Category::cVanillaMap); })[0]; + PlaceItemInLocation(mapLocation, map); +} + +void DungeonInfo::PlaceVanillaCompass() { + if (compass == NONE) { + return; + } + + auto dungeonLocations = GetDungeonLocations(); + auto compassLocation = FilterFromPool(dungeonLocations, [](const uint32_t loc){ return Location(loc)->IsCategory(Category::cVanillaCompass); })[0]; + PlaceItemInLocation(compassLocation, compass); +} + +void DungeonInfo::PlaceVanillaBossKey() { + if (bossKey == NONE || bossKey == GANONS_CASTLE_BOSS_KEY) { + return; + } + + auto dungeonLocations = GetDungeonLocations(); + auto bossKeyLocation = FilterFromPool(dungeonLocations, [](const uint32_t loc){ return Location(loc)->IsCategory(Category::cVanillaBossKey); })[0]; + PlaceItemInLocation(bossKeyLocation, bossKey); +} + +void DungeonInfo::PlaceVanillaSmallKeys() { + if (smallKey == NONE) { + return; + } + + auto dungeonLocations = GetDungeonLocations(); + auto smallKeyLocations = FilterFromPool(dungeonLocations, [](const uint32_t loc){ return Location(loc)->IsCategory(Category::cVanillaSmallKey); }); + for (auto location : smallKeyLocations) { + PlaceItemInLocation(location, smallKey); + } +} + +//Gets the chosen dungeon locations for a playthrough (so either MQ or Vanilla) +std::vector DungeonInfo::GetDungeonLocations() const { + auto locations = masterQuest ? mqLocations : vanillaLocations; + AddElementsToPool(locations, sharedLocations); + return locations; +} + +//Gets all dungeon locations (MQ + Vanilla) +std::vector DungeonInfo::GetEveryLocation() const { + auto locations = vanillaLocations; + AddElementsToPool(locations, mqLocations); + AddElementsToPool(locations, sharedLocations); + return locations; +} + + DungeonInfo DekuTree = DungeonInfo("Deku Tree", DEKU_TREE_MAP, DEKU_TREE_COMPASS, NONE, NONE, NONE, 0, 0, { + //Vanilla Locations + DEKU_TREE_MAP_CHEST, + DEKU_TREE_COMPASS_CHEST, + DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, + DEKU_TREE_BASEMENT_CHEST, + DEKU_TREE_SLINGSHOT_CHEST, + DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, + DEKU_TREE_GS_BASEMENT_BACK_ROOM, + DEKU_TREE_GS_BASEMENT_GATE, + DEKU_TREE_GS_BASEMENT_VINES, + DEKU_TREE_GS_COMPASS_ROOM, + }, { + //MQ Locations + DEKU_TREE_MQ_MAP_CHEST, + DEKU_TREE_MQ_COMPASS_CHEST, + DEKU_TREE_MQ_SLINGSHOT_CHEST, + DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, + DEKU_TREE_MQ_BASEMENT_CHEST, + DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, + DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, + DEKU_TREE_MQ_DEKU_SCRUB, + DEKU_TREE_MQ_GS_LOBBY, + DEKU_TREE_MQ_GS_COMPASS_ROOM, + DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, + DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, + }, { + //Shared Locations + DEKU_TREE_QUEEN_GOHMA_HEART, + QUEEN_GOHMA, + }); + + DungeonInfo DodongosCavern = DungeonInfo("Dodongo's Cavern", DODONGOS_CAVERN_MAP, DODONGOS_CAVERN_COMPASS, NONE, NONE, NONE, 0, 0, { + //Vanilla Locations + DODONGOS_CAVERN_MAP_CHEST, + DODONGOS_CAVERN_COMPASS_CHEST, + DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, + DODONGOS_CAVERN_BOMB_BAG_CHEST, + DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, + DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, + DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, + DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, + DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, + DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, + DODONGOS_CAVERN_GS_SCARECROW, + DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, + DODONGOS_CAVERN_GS_BACK_ROOM, + DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + }, { + //MQ Locations + DODONGOS_CAVERN_MQ_MAP_CHEST, + DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, + DODONGOS_CAVERN_MQ_COMPASS_CHEST, + DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, + DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, + DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, + DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, + DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, + DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, + DODONGOS_CAVERN_MQ_GS_BACK_AREA, + }, { + //Shared Locations + DODONGOS_CAVERN_BOSS_ROOM_CHEST, + DODONGOS_CAVERN_KING_DODONGO_HEART, + KING_DODONGO, + }); + + DungeonInfo JabuJabusBelly = DungeonInfo("Jabu Jabu's Belly", JABU_JABUS_BELLY_MAP, JABU_JABUS_BELLY_COMPASS, NONE, NONE, NONE, 0, 0, { + //Vanilla Locations + JABU_JABUS_BELLY_MAP_CHEST, + JABU_JABUS_BELLY_COMPASS_CHEST, + JABU_JABUS_BELLY_BOOMERANG_CHEST, + JABU_JABUS_BELLY_DEKU_SCRUB, + JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, + JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, + JABU_JABUS_BELLY_GS_NEAR_BOSS, + JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, + }, { + //MQ Locations + JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, + JABU_JABUS_BELLY_MQ_MAP_CHEST, + JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, + JABU_JABUS_BELLY_MQ_COMPASS_CHEST, + JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, + JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, + JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, + JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, + JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, + JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, + JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, + JABU_JABUS_BELLY_MQ_COW, + JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, + JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, + JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, + JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, + }, { + //Shared Locations + JABU_JABUS_BELLY_BARINADE_HEART, + BARINADE, + }); + + DungeonInfo ForestTemple = DungeonInfo("Forest Temple", FOREST_TEMPLE_MAP, FOREST_TEMPLE_COMPASS, FOREST_TEMPLE_SMALL_KEY, FOREST_TEMPLE_KEY_RING, FOREST_TEMPLE_BOSS_KEY, 5, 6, { + //Vanilla Locations + FOREST_TEMPLE_FIRST_ROOM_CHEST, + FOREST_TEMPLE_FIRST_STALFOS_CHEST, + FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, + FOREST_TEMPLE_MAP_CHEST, + FOREST_TEMPLE_WELL_CHEST, + FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, + FOREST_TEMPLE_EYE_SWITCH_CHEST, + FOREST_TEMPLE_BOSS_KEY_CHEST, + FOREST_TEMPLE_FLOORMASTER_CHEST, + FOREST_TEMPLE_BOW_CHEST, + FOREST_TEMPLE_RED_POE_CHEST, + FOREST_TEMPLE_BLUE_POE_CHEST, + FOREST_TEMPLE_BASEMENT_CHEST, + FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, + FOREST_TEMPLE_GS_FIRST_ROOM, + FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, + FOREST_TEMPLE_GS_LOBBY, + FOREST_TEMPLE_GS_BASEMENT, + }, { + //MQ Locations + FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, + FOREST_TEMPLE_MQ_WOLFOS_CHEST, + FOREST_TEMPLE_MQ_BOW_CHEST, + FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, + FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, + FOREST_TEMPLE_MQ_WELL_CHEST, + FOREST_TEMPLE_MQ_MAP_CHEST, + FOREST_TEMPLE_MQ_COMPASS_CHEST, + FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, + FOREST_TEMPLE_MQ_BASEMENT_CHEST, + FOREST_TEMPLE_MQ_REDEAD_CHEST, + FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, + FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, + FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, + FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, + FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, + FOREST_TEMPLE_MQ_GS_WELL, + }, { + //Shared Locations + FOREST_TEMPLE_PHANTOM_GANON_HEART, + PHANTOM_GANON, + }); + + DungeonInfo FireTemple = DungeonInfo("Fire Temple", FIRE_TEMPLE_MAP, FIRE_TEMPLE_COMPASS, FIRE_TEMPLE_SMALL_KEY, FIRE_TEMPLE_KEY_RING, FIRE_TEMPLE_BOSS_KEY, 8, 5, { + //Vanilla Locations + FIRE_TEMPLE_NEAR_BOSS_CHEST, + FIRE_TEMPLE_FLARE_DANCER_CHEST, + FIRE_TEMPLE_BOSS_KEY_CHEST, + FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, + FIRE_TEMPLE_SCARECROW_CHEST, + FIRE_TEMPLE_MAP_CHEST, + FIRE_TEMPLE_COMPASS_CHEST, + FIRE_TEMPLE_HIGHEST_GORON_CHEST, + FIRE_TEMPLE_MEGATON_HAMMER_CHEST, + FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, + FIRE_TEMPLE_GS_BOSS_KEY_LOOP, + FIRE_TEMPLE_GS_BOULDER_MAZE, + FIRE_TEMPLE_GS_SCARECROW_TOP, + FIRE_TEMPLE_GS_SCARECROW_CLIMB, + }, { + //MQ Locations + FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, + FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, + FIRE_TEMPLE_MQ_COMPASS_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, + FIRE_TEMPLE_MQ_CHEST_ON_FIRE, + FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, + FIRE_TEMPLE_MQ_MAP_CHEST, + FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, + FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, + FIRE_TEMPLE_MQ_FREESTANDING_KEY, + FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, + FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, + FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, + FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, + FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, + }, { + //Shared Locations + FIRE_TEMPLE_VOLVAGIA_HEART, + VOLVAGIA, + }); + + DungeonInfo WaterTemple = DungeonInfo("Water Temple", WATER_TEMPLE_MAP, WATER_TEMPLE_COMPASS, WATER_TEMPLE_SMALL_KEY, WATER_TEMPLE_KEY_RING, WATER_TEMPLE_BOSS_KEY, 6, 2, { + //Vanilla Locations + WATER_TEMPLE_MAP_CHEST, + WATER_TEMPLE_COMPASS_CHEST, + WATER_TEMPLE_TORCHES_CHEST, + WATER_TEMPLE_DRAGON_CHEST, + WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, + WATER_TEMPLE_CENTRAL_PILLAR_CHEST, + WATER_TEMPLE_CRACKED_WALL_CHEST, + WATER_TEMPLE_BOSS_KEY_CHEST, + WATER_TEMPLE_LONGSHOT_CHEST, + WATER_TEMPLE_RIVER_CHEST, + WATER_TEMPLE_GS_BEHIND_GATE, + WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, + WATER_TEMPLE_GS_CENTRAL_PILLAR, + WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, + WATER_TEMPLE_GS_RIVER, + }, { + //MQ Locations + WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, + WATER_TEMPLE_MQ_BOSS_KEY_CHEST, + WATER_TEMPLE_MQ_LONGSHOT_CHEST, + WATER_TEMPLE_MQ_COMPASS_CHEST, + WATER_TEMPLE_MQ_MAP_CHEST, + WATER_TEMPLE_MQ_FREESTANDING_KEY, + WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, + WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, + WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, + WATER_TEMPLE_MQ_GS_RIVER, + WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, + }, { + //Shared Locations + WATER_TEMPLE_MORPHA_HEART, + MORPHA, + }); + + DungeonInfo SpiritTemple = DungeonInfo("Spirit Temple", SPIRIT_TEMPLE_MAP, SPIRIT_TEMPLE_COMPASS, SPIRIT_TEMPLE_SMALL_KEY, SPIRIT_TEMPLE_KEY_RING, SPIRIT_TEMPLE_BOSS_KEY, 5, 7, { + //Vanilla Locations + SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, + SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, + SPIRIT_TEMPLE_COMPASS_CHEST, + SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, + SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, + SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, + SPIRIT_TEMPLE_MAP_CHEST, + SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, + SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, + SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, + SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, + SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, + SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, + SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, + SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, + SPIRIT_TEMPLE_BOSS_KEY_CHEST, + SPIRIT_TEMPLE_TOPMOST_CHEST, + SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, + SPIRIT_TEMPLE_GS_BOULDER_ROOM, + SPIRIT_TEMPLE_GS_LOBBY, + SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, + SPIRIT_TEMPLE_GS_METAL_FENCE, + }, { + //MQ Locations + SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, + SPIRIT_TEMPLE_MQ_MAP_CHEST, + SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, + SPIRIT_TEMPLE_MQ_COMPASS_CHEST, + SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, + SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, + SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, + SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, + SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, + SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, + SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, + SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, + SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, + SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, + SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, + }, { + //Shared Locations + SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, + SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, + SPIRIT_TEMPLE_TWINROVA_HEART, + TWINROVA, + }); + + DungeonInfo ShadowTemple = DungeonInfo("Shadow Temple", SHADOW_TEMPLE_MAP, SHADOW_TEMPLE_COMPASS, SHADOW_TEMPLE_SMALL_KEY, SHADOW_TEMPLE_KEY_RING, SHADOW_TEMPLE_BOSS_KEY, 5, 6, { + //Vanilla Locations + SHADOW_TEMPLE_MAP_CHEST, + SHADOW_TEMPLE_HOVER_BOOTS_CHEST, + SHADOW_TEMPLE_COMPASS_CHEST, + SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, + SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, + SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, + SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, + SHADOW_TEMPLE_WIND_HINT_CHEST, + SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, + SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, + SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, + SHADOW_TEMPLE_BOSS_KEY_CHEST, + SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, + SHADOW_TEMPLE_FREESTANDING_KEY, + SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, + SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, + SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, + SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, + SHADOW_TEMPLE_GS_NEAR_SHIP, + }, { + //MQ Locations + SHADOW_TEMPLE_MQ_COMPASS_CHEST, + SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, + SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, + SHADOW_TEMPLE_MQ_MAP_CHEST, + SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, + SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, + SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, + SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, + SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, + SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, + SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, + SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, + SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, + SHADOW_TEMPLE_MQ_FREESTANDING_KEY, + SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, + SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, + SHADOW_TEMPLE_MQ_GS_AFTER_WIND, + SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, + SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, + }, { + //Shared Locations + SHADOW_TEMPLE_BONGO_BONGO_HEART, + BONGO_BONGO, + }); + + DungeonInfo BottomOfTheWell = DungeonInfo("Bottom of the Well", BOTTOM_OF_THE_WELL_MAP, BOTTOM_OF_THE_WELL_COMPASS, BOTTOM_OF_THE_WELL_SMALL_KEY, BOTTOM_OF_THE_WELL_KEY_RING, NONE, 3, 2, { + //Vanilla Locations + BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, + BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, + BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, + BOTTOM_OF_THE_WELL_COMPASS_CHEST, + BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, + BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, + BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, + BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, + BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, + BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, + BOTTOM_OF_THE_WELL_MAP_CHEST, + BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, + BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, + BOTTOM_OF_THE_WELL_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, + BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, + BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, + }, { + //MQ Locations + BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, + BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, + BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, + BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, + BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, + BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, + }, {}); + + DungeonInfo IceCavern = DungeonInfo("Ice Cavern", ICE_CAVERN_MAP, ICE_CAVERN_COMPASS, NONE, NONE, NONE, 0, 0, { + //Vanilla Locations + ICE_CAVERN_MAP_CHEST, + ICE_CAVERN_COMPASS_CHEST, + ICE_CAVERN_IRON_BOOTS_CHEST, + ICE_CAVERN_FREESTANDING_POH, + ICE_CAVERN_GS_PUSH_BLOCK_ROOM, + ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, + ICE_CAVERN_GS_HEART_PIECE_ROOM, + }, { + //MQ Locations + ICE_CAVERN_MQ_IRON_BOOTS_CHEST, + ICE_CAVERN_MQ_COMPASS_CHEST, + ICE_CAVERN_MQ_MAP_CHEST, + ICE_CAVERN_MQ_FREESTANDING_POH, + ICE_CAVERN_MQ_GS_SCARECROW, + ICE_CAVERN_MQ_GS_ICE_BLOCK, + ICE_CAVERN_MQ_GS_RED_ICE, + }, { + //Shared Locations + SHEIK_IN_ICE_CAVERN, + }); + + DungeonInfo GerudoTrainingGrounds = DungeonInfo("Gerudo Training Grounds", NONE, NONE, GERUDO_TRAINING_GROUNDS_SMALL_KEY, GERUDO_TRAINING_GROUNDS_KEY_RING, NONE, 9, 3, { + //Vanilla Locations + GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST, + GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST, + GERUDO_TRAINING_GROUNDS_STALFOS_CHEST, + GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST, + GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST, + GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST, + GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST, + GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST, + GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY, + }, { + //MQ Locations + GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST, + }, {}); + + DungeonInfo GanonsCastle = DungeonInfo("Ganon's Castle", NONE, NONE, GANONS_CASTLE_SMALL_KEY, GANONS_CASTLE_KEY_RING, GANONS_CASTLE_BOSS_KEY, 2, 3, { + //Vanilla Locations + GANONS_CASTLE_FOREST_TRIAL_CHEST, + GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, + GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, + GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, + GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, + GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, + GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, + GANONS_CASTLE_DEKU_SCRUB_LEFT, + GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, + GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, + GANONS_CASTLE_DEKU_SCRUB_RIGHT, + }, { + //MQ Locations + GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, + GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, + GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, + GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, + GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, + GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, + GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, + }, { + //Shared Locations + GANONS_TOWER_BOSS_KEY_CHEST, + GANON, + }); + + const DungeonArray dungeonList = { + &DekuTree, + &DodongosCavern, + &JabuJabusBelly, + &ForestTemple, + &FireTemple, + &WaterTemple, + &SpiritTemple, + &ShadowTemple, + &BottomOfTheWell, + &IceCavern, + &GerudoTrainingGrounds, + &GanonsCastle, + }; + +} //namespace Dungeon diff --git a/soh/soh/Enhancements/randomizer/3drando/dungeon.hpp b/soh/soh/Enhancements/randomizer/3drando/dungeon.hpp new file mode 100644 index 000000000..dad3cc938 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/dungeon.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include +#include +#include + +#include "keys.hpp" + +namespace Dungeon { +class DungeonInfo { +public: + DungeonInfo(std::string name_, uint32_t map_, uint32_t compass_, uint32_t smallKey_, uint32_t keyRing_, uint32_t bossKey_, + uint8_t vanillaKeyCount_, uint8_t mqKeyCount_, + std::vector vanillaLocations_, + std::vector mqLocations_, + std::vector sharedLocations_); + ~DungeonInfo(); + + const std::string& GetName() const { + return name; + } + + void SetMQ() { + masterQuest = true; + } + + void ClearMQ() { + masterQuest = false; + } + + bool IsMQ() const { + return masterQuest; + } + + void SetKeyRing() { + hasKeyRing = true; + } + + void ClearKeyRing() { + hasKeyRing = false; + } + + bool HasKeyRing() const { + return hasKeyRing; + } + + bool IsVanilla() const { + return !masterQuest; + } + + uint8_t GetSmallKeyCount() const { + return (masterQuest) ? mqKeyCount : vanillaKeyCount; + } + + uint32_t GetSmallKey() const; + uint32_t GetKeyRing() const; + uint32_t GetMap() const; + uint32_t GetCompass() const; + uint32_t GetBossKey() const; + + void PlaceVanillaMap(); + void PlaceVanillaCompass(); + void PlaceVanillaBossKey(); + void PlaceVanillaSmallKeys(); + + // Gets the chosen dungeon locations for a playthrough (so either MQ or Vanilla) + std::vector GetDungeonLocations() const; + + // Gets all dungeon locations (MQ + Vanilla) + std::vector GetEveryLocation() const; + +private: + std::string name; + uint32_t map; + uint32_t compass; + uint32_t smallKey; + uint32_t keyRing; + uint32_t bossKey; + uint8_t vanillaKeyCount; + uint8_t mqKeyCount; + bool masterQuest = false; + bool hasKeyRing = false; + std::vector vanillaLocations; + std::vector mqLocations; + std::vector sharedLocations; +}; + +extern DungeonInfo DekuTree; +extern DungeonInfo DodongosCavern; +extern DungeonInfo JabuJabusBelly; +extern DungeonInfo ForestTemple; +extern DungeonInfo FireTemple; +extern DungeonInfo WaterTemple; +extern DungeonInfo SpiritTemple; +extern DungeonInfo ShadowTemple; +extern DungeonInfo BottomOfTheWell; +extern DungeonInfo IceCavern; +extern DungeonInfo GerudoTrainingGrounds; +extern DungeonInfo GanonsCastle; + +using DungeonArray = std::array; + +extern const DungeonArray dungeonList; +} // namespace Dungeon diff --git a/soh/soh/Enhancements/randomizer/3drando/entrance.cpp b/soh/soh/Enhancements/randomizer/3drando/entrance.cpp new file mode 100644 index 000000000..51be29bdf --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/entrance.cpp @@ -0,0 +1,877 @@ +#include "entrance.hpp" + +#include "fill.hpp" +#include "settings.hpp" +#include "item_list.hpp" +#include "item_pool.hpp" +#include "item_location.hpp" +#include "debug.hpp" +#include "spoiler_log.hpp" +#include "hints.hpp" +#include "location_access.hpp" + +#include +#include +#include +#include +#include + +std::list entranceOverrides = {}; +bool noRandomEntrances = false; +static bool entranceShuffleFailure = false; +static int totalRandomizableEntrances = 0; +static int curNumRandomizedEntrances = 0; + +typedef struct { + EntranceType type; + uint32_t parentRegion; + uint32_t connectedRegion; + int16_t index; + int16_t blueWarp; +} EntranceLinkInfo; + //primary, secondary +using EntranceInfoPair = std::pair; +using EntrancePair = std::pair; + +//The entrance randomization algorithm used here is a direct copy of +//the algorithm used in the original N64 randomizer (except now in C++ instead +//of python). It may be easier to understand the algorithm by looking at the +//base randomizer's code instead: +// https://github.com/TestRunnerSRL/OoT-Randomizer/blob/Dev/EntranceShuffle.py + +// Updates the user on how many entrances are currently shuffled +static void DisplayEntranceProgress() { + std::string dots = "."; + float progress = (float)curNumRandomizedEntrances / (float)totalRandomizableEntrances; + if (progress > 0.33) { + dots += "."; + } else { + dots += " "; + } + if (progress > 0.66) { + dots += "."; + } else { + dots += " "; + } + printf("\x1b[7;29H%s", dots.c_str()); + #ifdef ENABLE_DEBUG + if (curNumRandomizedEntrances == totalRandomizableEntrances) { + Areas::DumpWorldGraph("Finish Validation"); + } + #endif +} + +void SetAllEntrancesData(std::vector& entranceShuffleTable) { + for (auto& entrancePair: entranceShuffleTable) { + + auto& forwardEntry = entrancePair.first; + auto& returnEntry = entrancePair.second; + + //set data + Entrance* forwardEntrance = AreaTable(forwardEntry.parentRegion)->GetExit(forwardEntry.connectedRegion); + forwardEntrance->SetIndex(forwardEntry.index); + forwardEntrance->SetBlueWarp(forwardEntry.blueWarp); + forwardEntrance->SetType(forwardEntry.type); + forwardEntrance->SetAsPrimary(); + // if type == 'Grotto': + // forward_entrance.data['index'] = 0x0700 + forward_entrance.data['grotto_id'] + if (returnEntry.parentRegion != NONE) { + Entrance* returnEntrance = AreaTable(returnEntry.parentRegion)->GetExit(returnEntry.connectedRegion); + returnEntrance->SetIndex(returnEntry.index); + returnEntrance->SetBlueWarp(returnEntry.blueWarp); + returnEntrance->SetType(returnEntry.type); + forwardEntrance->BindTwoWay(returnEntrance); + // if type == 'Grotto': + // return_entrance.data['index'] = 0x0800 + return_entrance.data['grotto_id'] + } + } +} + +static std::vector AssumeEntrancePool(std::vector& entrancePool) { + std::vector assumedPool = {}; + for (Entrance* entrance : entrancePool) { + Entrance* assumedForward = entrance->AssumeReachable(); + if (entrance->GetReverse() != nullptr /*&& entrances are not decoupled*/) { + Entrance* assumedReturn = entrance->GetReverse()->AssumeReachable(); + //mixed pool assumption stuff + assumedForward->BindTwoWay(assumedReturn); + } + assumedPool.push_back(assumedForward); + } + return assumedPool; +} + +//returns restrictive entrances and soft entrances in an array of size 2 (restrictive vector is index 0, soft is index 1) +static std::array, 2> SplitEntrancesByRequirements(std::vector& entrancesToSplit, std::vector& assumedEntrances) { + //First, disconnect all root assumed entrances and save which regions they were originally connected to, so we can reconnect them later + std::map originalConnectedRegions = {}; + std::set entrancesToDisconnect = {}; + for (Entrance* entrance : assumedEntrances) { + entrancesToDisconnect.insert(entrance); + if (entrance->GetReverse() != nullptr) { + entrancesToDisconnect.insert(entrance->GetReverse()); + } + } + + //disconnect each entrance temporarily to find restrictive vs soft entrances + //soft entrances are ones that can be accessed by both ages (child/adult) at both times of day (day/night) + //restrictive entrances are ones that do not meet this criteria + for (Entrance* entrance : entrancesToDisconnect) { + if (entrance->GetConnectedRegionKey() != NONE) { + originalConnectedRegions[entrance] = entrance->Disconnect(); + } + } + + std::vector restrictiveEntrances = {}; + std::vector softEntrances = {}; + + Logic::LogicReset(); + // //Apply the effects of all advancement items to search for entrance accessibility + std::vector items = FilterFromPool(ItemPool, [](const auto i){ return ItemTable(i).IsAdvancement();}); + for (uint32_t unplacedItem : items) { + ItemTable(unplacedItem).ApplyEffect(); + } + // run a search to see what's accessible + GetAccessibleLocations({}); + + for (Entrance* entrance : entrancesToSplit) { + // if an entrance is accessible at all times of day by both ages, it's a soft entrance with no restrictions + if (entrance->ConditionsMet(true)) { + softEntrances.push_back(entrance); + } else { + restrictiveEntrances.push_back(entrance); + } + } + + //Reconnect all disconnected entrances + for (Entrance* entrance : entrancesToDisconnect) { + entrance->Connect(originalConnectedRegions[entrance]); + } + + return {restrictiveEntrances, softEntrances}; +} + +static bool AreEntrancesCompatible(Entrance* entrance, Entrance* target, std::vector& rollbacks) { + + //Entrances shouldn't connect to their own scene, fail in this situation + if (entrance->GetParentRegion()->scene != "" && entrance->GetParentRegion()->scene == target->GetConnectedRegion()->scene) { + auto message = "Entrance " + entrance->GetName() + " attempted to connect with own scene target " + target->to_string() + ". Connection failed.\n"; + SPDLOG_INFO(message); + return false; + } + + //one-way entrance stuff + + return true; +} + +//Change connections between an entrance and a target assumed entrance, in order to test the connections afterwards if necessary +static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) { + auto message = "Attempting to connect " + entrance->GetName() + " to " + targetEntrance->to_string() + "\n"; + SPDLOG_INFO(message); + entrance->Connect(targetEntrance->Disconnect()); + entrance->SetReplacement(targetEntrance->GetReplacement()); + if (entrance->GetReverse() != nullptr /*&& entrances aren't decoupled*/) { + targetEntrance->GetReplacement()->GetReverse()->Connect(entrance->GetReverse()->GetAssumed()->Disconnect()); + targetEntrance->GetReplacement()->GetReverse()->SetReplacement(entrance->GetReverse()); + } +} + +static void RestoreConnections(Entrance* entrance, Entrance* targetEntrance) { + targetEntrance->Connect(entrance->Disconnect()); + entrance->SetReplacement(nullptr); + if (entrance->GetReverse() != nullptr /*&& entrances are not decoupled*/) { + entrance->GetReverse()->GetAssumed()->Connect(targetEntrance->GetReplacement()->GetReverse()->Disconnect()); + targetEntrance->GetReplacement()->GetReverse()->SetReplacement(nullptr); + } +} + +static void DeleteTargetEntrance(Entrance* targetEntrance) { + if (targetEntrance->GetConnectedRegionKey() != NONE) { + targetEntrance->Disconnect(); + } + if (targetEntrance->GetParentRegionKey() != NONE) { + targetEntrance->GetParentRegion()->RemoveExit(targetEntrance); + targetEntrance->SetParentRegion(NONE); + } +} + +static void ConfirmReplacement(Entrance* entrance, Entrance* targetEntrance) { + DeleteTargetEntrance(targetEntrance); + if (entrance->GetReverse() != nullptr /*&& entrances are not decoupled*/) { + auto replacedReverse = targetEntrance->GetReplacement()->GetReverse(); + DeleteTargetEntrance(replacedReverse->GetReverse()->GetAssumed()); + } +} + +// Returns whether or not we can affirm the entrance can never be accessed as the given age +static bool EntranceUnreachableAs(Entrance* entrance, uint8_t age, std::vector& alreadyChecked) { + + if (entrance == nullptr) { + SPDLOG_INFO("Entrance is nullptr in EntranceUnreachableAs()"); + return true; + } + + alreadyChecked.push_back(entrance); + auto type = entrance->GetType(); + + // The following cases determine when we say an entrance is not safe to affirm unreachable as the given age + if (type == EntranceType::WarpSong || type == EntranceType::Overworld) { + // Note that we consider all overworld entrances as potentially accessible as both ages, to be completely safe + return false; + } else if (type == EntranceType::OwlDrop) { + return age == AGE_ADULT; + } else if (type == EntranceType::Spawn && entrance->GetConnectedRegionKey() == KF_LINKS_HOUSE) { + return age == AGE_ADULT; + } else if (type == EntranceType::Spawn && entrance->GetConnectedRegionKey() == TEMPLE_OF_TIME) { + return age == AGE_CHILD; + } + + // Other entrances such as Interior, Dungeon or Grotto are fine unless they have a parent which is one of the above + // cases Recursively check parent entrances to verify that they are also not reachable as the wrong age + auto& parentEntrances = entrance->GetParentRegion()->entrances; + for (Entrance* parentEntrance : parentEntrances) { + + // if parentEntrance is in alreadyChecked, then continue + if (ElementInContainer(parentEntrance, alreadyChecked)) { + continue; + } + + bool unreachable = EntranceUnreachableAs(parentEntrance, age, alreadyChecked); + if (!unreachable) { + return false; + } + } + + return true; +} + +static bool ValidateWorld(Entrance* entrancePlaced) { + SPDLOG_INFO("Validating world\n"); + + //check certain conditions when certain types of ER are enabled + EntranceType type = EntranceType::None; + if (entrancePlaced != nullptr) { + type = entrancePlaced->GetType(); + } + + bool checkPoeCollectorAccess = (Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances.Is(SHUFFLEINTERIORS_ALL)) && (entrancePlaced == nullptr /*|| Settings::MixedEntrancePools.IsNot(MIXEDENTRANCES_OFF)*/ || + type == EntranceType::Interior || type == EntranceType::SpecialInterior || type == EntranceType::Overworld || type == EntranceType::Spawn || type == EntranceType::WarpSong || type == EntranceType::OwlDrop); + bool checkOtherEntranceAccess = (Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances.Is(SHUFFLEINTERIORS_ALL) /*|| Settings::ShuffleOverworldSpawns*/) && (entrancePlaced == nullptr /*|| Settings::MixedEntrancePools.IsNot(MIXEDENTRANCES_OFF)*/ || + type == EntranceType::SpecialInterior || type == EntranceType::Overworld || type == EntranceType::Spawn || type == EntranceType::WarpSong || type == EntranceType::OwlDrop); + + // Check to make sure all locations are still reachable + Logic::LogicReset(); + GetAccessibleLocations({}, SearchMode::ValidateWorld, "", checkPoeCollectorAccess, checkOtherEntranceAccess); + + // if not world.decouple_entrances: + // Unless entrances are decoupled, we don't want the player to end up through certain entrances as the wrong age + // This means we need to hard check that none of the relevant entrances are ever reachable as that age + // This is mostly relevant when mixing entrance pools or shuffling special interiors (such as windmill or kak potion shop) + // Warp Songs and Overworld Spawns can also end up inside certain indoors so those need to be handled as well + std::array childForbidden = {"OGC Great Fairy Fountain -> Castle Grounds", "GV Carpenter Tent -> GV Fortress Side"}; + std::array adultForbidden = {"HC Great Fairy Fountain -> Castle Grounds", "HC Storms Grotto -> Castle Grounds"}; + + auto allShuffleableEntrances = GetShuffleableEntrances(EntranceType::All, false); + for (auto& entrance: allShuffleableEntrances) { + + std::vector alreadyChecked = {}; + + if (entrance->IsShuffled()) { + if (entrance->GetReplacement() != nullptr) { + + auto replacementName = entrance->GetReplacement()->GetName(); + alreadyChecked.push_back(entrance->GetReplacement()->GetReverse()); + + if (ElementInContainer(replacementName, childForbidden) && !EntranceUnreachableAs(entrance, AGE_CHILD, alreadyChecked)) { + auto message = replacementName + " is replaced by an entrance with a potential child access\n"; + SPDLOG_INFO(message); + return false; + } else if (ElementInContainer(replacementName, adultForbidden) && !EntranceUnreachableAs(entrance, AGE_ADULT, alreadyChecked)) { + auto message = replacementName + " is replaced by an entrance with a potential adult access\n"; + SPDLOG_INFO(message); + return false; + } + } + } else { + auto name = entrance->GetName(); + alreadyChecked.push_back(entrance->GetReverse()); + + if (ElementInContainer(name, childForbidden) && !EntranceUnreachableAs(entrance, AGE_CHILD, alreadyChecked)) { + auto message = name + " is potentially accessible as child\n"; + SPDLOG_INFO(message); + return false; + } else if (ElementInContainer(name, adultForbidden) && !EntranceUnreachableAs(entrance, AGE_ADULT, alreadyChecked)) { + auto message = name + " is potentially accessible as adult\n"; + SPDLOG_INFO(message); + return false; + } + } + } + + if (Settings::ShuffleInteriorEntrances.IsNot(SHUFFLEINTERIORS_OFF) && Settings::GossipStoneHints.IsNot(HINTS_NO_HINTS) && + (entrancePlaced == nullptr || type == EntranceType::Interior || type == EntranceType::SpecialInterior)) { + //When cows are shuffled, ensure both Impa's House entrances are in the same hint area because the cow is reachable from both sides + if (Settings::ShuffleCows) { + auto impasHouseFrontHintRegion = GetHintRegionHintKey(KAK_IMPAS_HOUSE); + auto impasHouseBackHintRegion = GetHintRegionHintKey(KAK_IMPAS_HOUSE_BACK); + if (impasHouseFrontHintRegion != NONE && impasHouseBackHintRegion != NONE && impasHouseBackHintRegion != LINKS_POCKET && impasHouseFrontHintRegion != LINKS_POCKET && impasHouseBackHintRegion != impasHouseFrontHintRegion) { + auto message = "Kak Impas House entrances are not in the same hint area\n"; + SPDLOG_INFO(message); + return false; + } + } + } + + // If all locations aren't reachable, that means that one of the conditions failed when searching + if (!allLocationsReachable) { + if (checkOtherEntranceAccess) { + // At least one valid starting region with all basic refills should be reachable without using any items at the beginning of the seed + if (!AreaTable(KOKIRI_FOREST)->HasAccess() && !AreaTable(KAKARIKO_VILLAGE)->HasAccess()) { + SPDLOG_INFO("Invalid starting area\n"); + return false; + } + + // Check that a region where time passes is always reachable as both ages without having collected any items + if (!Areas::HasTimePassAccess(AGE_CHILD) || !Areas::HasTimePassAccess(AGE_ADULT)) { + SPDLOG_INFO("Time passing is not guaranteed as both ages\n"); + return false; + } + + // The player should be able to get back to ToT after going through time, without having collected any items + // This is important to ensure that the player never loses access to the pedestal after going through time + if (Settings::ResolvedStartingAge == AGE_CHILD && !AreaTable(TEMPLE_OF_TIME)->Adult()) { + SPDLOG_INFO("Path to Temple of Time as adult is not guaranteed\n"); + return false; + } else if (Settings::ResolvedStartingAge == AGE_ADULT && !AreaTable(TEMPLE_OF_TIME)->Child()) { + SPDLOG_INFO("Path to Temple of Time as child is not guaranteed\n"); + return false; + } + } + + // The Big Poe shop should always be accessible as adult without the need to use any bottles + // This is important to ensure that players can never lock their only bottles by filling them with Big Poes they can't sell + if (checkPoeCollectorAccess) { + if (!AreaTable(MARKET_GUARD_HOUSE)->Adult()) { + SPDLOG_INFO("Big Poe Shop access is not guarenteed as adult\n"); + return false; + } + } + SPDLOG_INFO("All Locations NOT REACHABLE\n"); + return false; + } + return true; +} + +static bool ReplaceEntrance(Entrance* entrance, Entrance* target, std::vector& rollbacks) { + + if (!AreEntrancesCompatible(entrance, target, rollbacks)) { + return false; + } + ChangeConnections(entrance, target); + if (ValidateWorld(entrance)) { + #ifdef ENABLE_DEBUG + std::string ticks = std::to_string(svcGetSystemTick()); + auto message = "Dumping World Graph at " + ticks + "\n"; + //PlacementLog_Msg(message); + //Areas::DumpWorldGraph(ticks); + #endif + rollbacks.push_back(EntrancePair{entrance, target}); + curNumRandomizedEntrances++; + DisplayEntranceProgress(); + return true; + } else { + #ifdef ENABLE_DEBUG + std::string ticks = std::to_string(svcGetSystemTick()); + auto message = "Dumping World Graph at " + ticks + "\n"; + //PlacementLog_Msg(message); + //Areas::DumpWorldGraph(ticks); + #endif + if (entrance->GetConnectedRegionKey() != NONE) { + RestoreConnections(entrance, target); + } + } + DisplayEntranceProgress(); + return false; +} + +// Shuffle entrances by placing them instead of entrances in the provided target entrances list +static bool ShuffleEntrances(std::vector& entrances, std::vector& targetEntrances, std::vector& rollbacks) { + + Shuffle(entrances); + + //place all entrances in the pool, validating after every placement + for (Entrance* entrance : entrances) { + if (entrance->GetConnectedRegionKey() != NONE) { + continue; + } + + Shuffle(targetEntrances); + for (Entrance* target : targetEntrances) { + if (target->GetConnectedRegionKey() == NONE) { + continue; + } + + if (ReplaceEntrance(entrance, target, rollbacks)) { + break; + } + } + + if (entrance->GetConnectedRegionKey() == NONE) { + return false; + } + } + + //all entrances were validly connected + return true; +} + +static void ShuffleEntrancePool(std::vector& entrancePool, std::vector& targetEntrances) { + noRandomEntrances = false; + + auto splitEntrances = SplitEntrancesByRequirements(entrancePool, targetEntrances); + + auto& restrictiveEntrances = splitEntrances[0]; + auto& softEntrances = splitEntrances[1]; + + int retries = 20; + while (retries > 0) { + if (retries != 20) { + #ifdef ENABLE_DEBUG + std::string ticks = std::to_string(svcGetSystemTick()); + auto message = "Failed to connect entrances. Retrying " + std::to_string(retries) + " more times.\nDumping World Graph at " + ticks + "\n"; + PlacementLog_Msg(message); + Areas::DumpWorldGraph(ticks); + #endif + } + retries--; + + std::vector rollbacks = {}; + + //Shuffle Restrictive Entrances first while more regions are available in + //order to heavily reduce the chances of the placement failing + bool success = ShuffleEntrances(restrictiveEntrances, targetEntrances, rollbacks); + if (success) { + success = ShuffleEntrances(softEntrances, targetEntrances, rollbacks); + if(!success) { + for (auto& pair : rollbacks) { + RestoreConnections(pair.first, pair.second); + curNumRandomizedEntrances--; + } + continue; + } + } else { + for (auto& pair : rollbacks) { + RestoreConnections(pair.first, pair.second); + curNumRandomizedEntrances--; + } + continue; + } + + //If there are no issues, log the connections and continue + for (auto& pair : rollbacks) { + ConfirmReplacement(pair.first, pair.second); + } + break; + } + + if (retries <= 0) { + SPDLOG_INFO("Entrance placement attempt count exceeded. Restarting randomization completely"); + entranceShuffleFailure = true; + } +} + +//Process for setting up the shuffling of all entrances to be shuffled +int ShuffleAllEntrances() { + + totalRandomizableEntrances = 0; + curNumRandomizedEntrances = 0; + + std::vector entranceShuffleTable = { + //Parent Region Connected Region index blue warp + {{EntranceType::Dungeon, KF_OUTSIDE_DEKU_TREE, DEKU_TREE_ENTRYWAY, 0x0000}, + {EntranceType::Dungeon, DEKU_TREE_ENTRYWAY, KF_OUTSIDE_DEKU_TREE, 0x0209, 0x0457}}, + {{EntranceType::Dungeon, DEATH_MOUNTAIN_TRAIL, DODONGOS_CAVERN_ENTRYWAY, 0x0004}, + {EntranceType::Dungeon, DODONGOS_CAVERN_ENTRYWAY, DEATH_MOUNTAIN_TRAIL, 0x0242, 0x047A}}, + {{EntranceType::Dungeon, ZORAS_FOUNTAIN, JABU_JABUS_BELLY_ENTRYWAY, 0x0028}, + {EntranceType::Dungeon, JABU_JABUS_BELLY_ENTRYWAY, ZORAS_FOUNTAIN, 0x0221, 0x010E}}, + {{EntranceType::Dungeon, SACRED_FOREST_MEADOW, FOREST_TEMPLE_ENTRYWAY, 0x0169}, + {EntranceType::Dungeon, FOREST_TEMPLE_ENTRYWAY, SACRED_FOREST_MEADOW, 0x0215, 0x0608}}, + {{EntranceType::Dungeon, DMC_CENTRAL_LOCAL, FIRE_TEMPLE_ENTRYWAY, 0x0165}, + {EntranceType::Dungeon, FIRE_TEMPLE_ENTRYWAY, DMC_CENTRAL_LOCAL, 0x024A, 0x0564}}, + {{EntranceType::Dungeon, LAKE_HYLIA, WATER_TEMPLE_ENTRYWAY, 0x0010}, + {EntranceType::Dungeon, WATER_TEMPLE_ENTRYWAY, LAKE_HYLIA, 0x021D, 0x060C}}, + {{EntranceType::Dungeon, DESERT_COLOSSUS, SPIRIT_TEMPLE_ENTRYWAY, 0x0082}, + {EntranceType::Dungeon, SPIRIT_TEMPLE_ENTRYWAY, DESERT_COLOSSUS, 0x01E1, 0x0610}}, + {{EntranceType::Dungeon, GRAVEYARD_WARP_PAD_REGION, SHADOW_TEMPLE_ENTRYWAY, 0x0037}, + {EntranceType::Dungeon, SHADOW_TEMPLE_ENTRYWAY, GRAVEYARD_WARP_PAD_REGION, 0x0205, 0x0580}}, + {{EntranceType::Dungeon, KAKARIKO_VILLAGE, BOTTOM_OF_THE_WELL_ENTRYWAY, 0x0098}, + {EntranceType::Dungeon, BOTTOM_OF_THE_WELL_ENTRYWAY, KAKARIKO_VILLAGE, 0x02A6}}, + {{EntranceType::Dungeon, ZORAS_FOUNTAIN, ICE_CAVERN_ENTRYWAY, 0x0088}, + {EntranceType::Dungeon, ICE_CAVERN_ENTRYWAY, ZORAS_FOUNTAIN, 0x03D4}}, + {{EntranceType::Dungeon, GERUDO_FORTRESS, GERUDO_TRAINING_GROUNDS_ENTRYWAY, 0x0008}, + {EntranceType::Dungeon, GERUDO_TRAINING_GROUNDS_ENTRYWAY, GERUDO_FORTRESS, 0x03A8}}, + {{EntranceType::GanonDungeon, GANONS_CASTLE_GROUNDS, GANONS_CASTLE_ENTRYWAY, 0x0467}, + {EntranceType::GanonDungeon, GANONS_CASTLE_ENTRYWAY, GANONS_CASTLE_GROUNDS, 0x023D}}, + + {{EntranceType::Interior, KOKIRI_FOREST, KF_MIDOS_HOUSE, 0x0433}, + {EntranceType::Interior, KF_MIDOS_HOUSE, KOKIRI_FOREST, 0x0443}}, + {{EntranceType::Interior, KOKIRI_FOREST, KF_SARIAS_HOUSE, 0x0437}, + {EntranceType::Interior, KF_SARIAS_HOUSE, KOKIRI_FOREST, 0x0447}}, + {{EntranceType::Interior, KOKIRI_FOREST, KF_HOUSE_OF_TWINS, 0x009C}, + {EntranceType::Interior, KF_HOUSE_OF_TWINS, KOKIRI_FOREST, 0x033C}}, + {{EntranceType::Interior, KOKIRI_FOREST, KF_KNOW_IT_ALL_HOUSE, 0x00C9}, + {EntranceType::Interior, KF_KNOW_IT_ALL_HOUSE, KOKIRI_FOREST, 0x026A}}, + {{EntranceType::Interior, KOKIRI_FOREST, KF_KOKIRI_SHOP, 0x00C1}, + {EntranceType::Interior, KF_KOKIRI_SHOP, KOKIRI_FOREST, 0x0266}}, + {{EntranceType::Interior, LAKE_HYLIA, LH_LAB, 0x0043}, + {EntranceType::Interior, LH_LAB, LAKE_HYLIA, 0x03CC}}, + {{EntranceType::Interior, LH_FISHING_ISLAND, LH_FISHING_HOLE, 0x045F}, + {EntranceType::Interior, LH_FISHING_HOLE, LH_FISHING_ISLAND, 0x0309}}, + {{EntranceType::Interior, GV_FORTRESS_SIDE, GV_CARPENTER_TENT, 0x03A0}, + {EntranceType::Interior, GV_CARPENTER_TENT, GV_FORTRESS_SIDE, 0x03D0}}, + {{EntranceType::Interior, MARKET_ENTRANCE, MARKET_GUARD_HOUSE, 0x007E}, + {EntranceType::Interior, MARKET_GUARD_HOUSE, MARKET_ENTRANCE, 0x026E}}, + {{EntranceType::Interior, THE_MARKET, MARKET_MASK_SHOP, 0x0530}, + {EntranceType::Interior, MARKET_MASK_SHOP, THE_MARKET, 0x01D1}}, + {{EntranceType::Interior, THE_MARKET, MARKET_BOMBCHU_BOWLING, 0x0507}, + {EntranceType::Interior, MARKET_BOMBCHU_BOWLING, THE_MARKET, 0x03BC}}, + {{EntranceType::Interior, THE_MARKET, MARKET_POTION_SHOP, 0x0388}, + {EntranceType::Interior, MARKET_POTION_SHOP, THE_MARKET, 0x02A2}}, + {{EntranceType::Interior, THE_MARKET, MARKET_TREASURE_CHEST_GAME, 0x0063}, + {EntranceType::Interior, MARKET_TREASURE_CHEST_GAME, THE_MARKET, 0x01D5}}, + {{EntranceType::Interior, MARKET_BACK_ALLEY, MARKET_BOMBCHU_SHOP, 0x0528}, + {EntranceType::Interior, MARKET_BOMBCHU_SHOP, MARKET_BACK_ALLEY, 0x03C0}}, + {{EntranceType::Interior, MARKET_BACK_ALLEY, MARKET_MAN_IN_GREEN_HOUSE, 0x043B}, + {EntranceType::Interior, MARKET_MAN_IN_GREEN_HOUSE, MARKET_BACK_ALLEY, 0x0067}}, + {{EntranceType::Interior, KAKARIKO_VILLAGE, KAK_CARPENTER_BOSS_HOUSE, 0x02FD}, + {EntranceType::Interior, KAK_CARPENTER_BOSS_HOUSE, KAKARIKO_VILLAGE, 0x0349}}, + {{EntranceType::Interior, KAKARIKO_VILLAGE, KAK_HOUSE_OF_SKULLTULA, 0x0550}, + {EntranceType::Interior, KAK_HOUSE_OF_SKULLTULA, KAKARIKO_VILLAGE, 0x04EE}}, + {{EntranceType::Interior, KAKARIKO_VILLAGE, KAK_IMPAS_HOUSE, 0x039C}, + {EntranceType::Interior, KAK_IMPAS_HOUSE, KAKARIKO_VILLAGE, 0x0345}}, + {{EntranceType::Interior, KAK_IMPAS_LEDGE, KAK_IMPAS_HOUSE_BACK, 0x05C8}, + {EntranceType::Interior, KAK_IMPAS_HOUSE_BACK, KAK_IMPAS_LEDGE, 0x05DC}}, + {{EntranceType::Interior, KAK_BACKYARD, KAK_ODD_POTION_BUILDING, 0x0072}, + {EntranceType::Interior, KAK_ODD_POTION_BUILDING, KAK_BACKYARD, 0x034D}}, + {{EntranceType::Interior, THE_GRAVEYARD, GRAVEYARD_DAMPES_HOUSE, 0x030D}, + {EntranceType::Interior, GRAVEYARD_DAMPES_HOUSE, THE_GRAVEYARD, 0x0355}}, + {{EntranceType::Interior, GORON_CITY, GC_SHOP, 0x037C}, + {EntranceType::Interior, GC_SHOP, GORON_CITY, 0x03FC}}, + {{EntranceType::Interior, ZORAS_DOMAIN, ZD_SHOP, 0x0380}, + {EntranceType::Interior, ZD_SHOP, ZORAS_DOMAIN, 0x03C4}}, + {{EntranceType::Interior, LON_LON_RANCH, LLR_TALONS_HOUSE, 0x004F}, + {EntranceType::Interior, LLR_TALONS_HOUSE, LON_LON_RANCH, 0x0378}}, + {{EntranceType::Interior, LON_LON_RANCH, LLR_STABLES, 0x02F9}, + {EntranceType::Interior, LLR_STABLES, LON_LON_RANCH, 0x042F}}, + {{EntranceType::Interior, LON_LON_RANCH, LLR_TOWER, 0x05D0}, + {EntranceType::Interior, LLR_TOWER, LON_LON_RANCH, 0x05D4}}, + {{EntranceType::Interior, THE_MARKET, MARKET_BAZAAR, 0x052C}, + {EntranceType::Interior, MARKET_BAZAAR, THE_MARKET, 0x03B8}}, + {{EntranceType::Interior, THE_MARKET, MARKET_SHOOTING_GALLERY, 0x016D}, + {EntranceType::Interior, MARKET_SHOOTING_GALLERY, THE_MARKET, 0x01CD}}, + {{EntranceType::Interior, KAKARIKO_VILLAGE, KAK_BAZAAR, 0x00B7}, + {EntranceType::Interior, KAK_BAZAAR, KAKARIKO_VILLAGE, 0x0201}}, + {{EntranceType::Interior, KAKARIKO_VILLAGE, KAK_SHOOTING_GALLERY, 0x003B}, + {EntranceType::Interior, KAK_SHOOTING_GALLERY, KAKARIKO_VILLAGE, 0x0463}}, + {{EntranceType::Interior, DESERT_COLOSSUS, COLOSSUS_GREAT_FAIRY_FOUNTAIN, 0x0588}, + {EntranceType::Interior, COLOSSUS_GREAT_FAIRY_FOUNTAIN, DESERT_COLOSSUS, 0x057C}}, + {{EntranceType::Interior, HYRULE_CASTLE_GROUNDS, HC_GREAT_FAIRY_FOUNTAIN, 0x0578}, + {EntranceType::Interior, HC_GREAT_FAIRY_FOUNTAIN, CASTLE_GROUNDS, 0x0340}}, + {{EntranceType::Interior, GANONS_CASTLE_GROUNDS, OGC_GREAT_FAIRY_FOUNTAIN, 0x04C2}, + {EntranceType::Interior, OGC_GREAT_FAIRY_FOUNTAIN, CASTLE_GROUNDS, 0x03E8}}, //0x3E8 is an unused entrance index repruposed to differentiate between the HC and OGC fairy fountain exits (normally they both use 0x340) + {{EntranceType::Interior, DMC_LOWER_NEARBY, DMC_GREAT_FAIRY_FOUNTAIN, 0x04BE}, + {EntranceType::Interior, DMC_GREAT_FAIRY_FOUNTAIN, DMC_LOWER_LOCAL, 0x0482}}, + {{EntranceType::Interior, DEATH_MOUNTAIN_SUMMIT, DMT_GREAT_FAIRY_FOUNTAIN, 0x0315}, + {EntranceType::Interior, DMT_GREAT_FAIRY_FOUNTAIN, DEATH_MOUNTAIN_SUMMIT, 0x045B}}, + {{EntranceType::Interior, ZORAS_FOUNTAIN, ZF_GREAT_FAIRY_FOUNTAIN, 0x0371}, + {EntranceType::Interior, ZF_GREAT_FAIRY_FOUNTAIN, ZORAS_FOUNTAIN, 0x0394}}, + + {{EntranceType::SpecialInterior, KOKIRI_FOREST, KF_LINKS_HOUSE, 0x0272}, + {EntranceType::SpecialInterior, KF_LINKS_HOUSE, KOKIRI_FOREST, 0x0211}}, + {{EntranceType::SpecialInterior, TOT_ENTRANCE, TEMPLE_OF_TIME, 0x0053}, + {EntranceType::SpecialInterior, TEMPLE_OF_TIME, TOT_ENTRANCE, 0x0472}}, + {{EntranceType::SpecialInterior, KAKARIKO_VILLAGE, KAK_WINDMILL, 0x0453}, + {EntranceType::SpecialInterior, KAK_WINDMILL, KAKARIKO_VILLAGE, 0x0351}}, + {{EntranceType::SpecialInterior, KAKARIKO_VILLAGE, KAK_POTION_SHOP_FRONT, 0x0384}, + {EntranceType::SpecialInterior, KAK_POTION_SHOP_FRONT, KAKARIKO_VILLAGE, 0x044B}}, + {{EntranceType::SpecialInterior, KAK_BACKYARD, KAK_POTION_SHOP_BACK, 0x03EC}, + {EntranceType::SpecialInterior, KAK_POTION_SHOP_BACK, KAK_BACKYARD, 0x04FF}}, + + // Grotto Loads use an entrance index of 0x0700 + their grotto id. The id is used as index for the + // grottoLoadTable in src/grotto.c + // Grotto Returns use an entrance index of 0x0800 + their grotto id. The id is used as index for the + // grottoReturnTable in src/grotto.c + {{EntranceType::GrottoGrave, DESERT_COLOSSUS, COLOSSUS_GROTTO, 0x0700}, + {EntranceType::GrottoGrave, COLOSSUS_GROTTO, DESERT_COLOSSUS, 0x0800}}, + {{EntranceType::GrottoGrave, LAKE_HYLIA, LH_GROTTO, 0x0701}, + {EntranceType::GrottoGrave, LH_GROTTO, LAKE_HYLIA, 0x0801}}, + {{EntranceType::GrottoGrave, ZORAS_RIVER, ZR_STORMS_GROTTO, 0x0702}, + {EntranceType::GrottoGrave, ZR_STORMS_GROTTO, ZORAS_RIVER, 0x0802}}, + {{EntranceType::GrottoGrave, ZORAS_RIVER, ZR_FAIRY_GROTTO, 0x0703}, + {EntranceType::GrottoGrave, ZR_FAIRY_GROTTO, ZORAS_RIVER, 0x0803}}, + {{EntranceType::GrottoGrave, ZORAS_RIVER, ZR_OPEN_GROTTO, 0x0704}, + {EntranceType::GrottoGrave, ZR_OPEN_GROTTO, ZORAS_RIVER, 0x0804}}, + {{EntranceType::GrottoGrave, DMC_LOWER_NEARBY, DMC_HAMMER_GROTTO, 0x0705}, + {EntranceType::GrottoGrave, DMC_HAMMER_GROTTO, DMC_LOWER_LOCAL, 0x0805}}, + {{EntranceType::GrottoGrave, DMC_UPPER_NEARBY, DMC_UPPER_GROTTO, 0x0706}, + {EntranceType::GrottoGrave, DMC_UPPER_GROTTO, DMC_UPPER_LOCAL, 0x0806}}, + {{EntranceType::GrottoGrave, GC_GROTTO_PLATFORM, GC_GROTTO, 0x0707}, + {EntranceType::GrottoGrave, GC_GROTTO, GC_GROTTO_PLATFORM, 0x0807}}, + {{EntranceType::GrottoGrave, DEATH_MOUNTAIN_TRAIL, DMT_STORMS_GROTTO, 0x0708}, + {EntranceType::GrottoGrave, DMT_STORMS_GROTTO, DEATH_MOUNTAIN_TRAIL, 0x0808}}, + {{EntranceType::GrottoGrave, DEATH_MOUNTAIN_SUMMIT, DMT_COW_GROTTO, 0x0709}, + {EntranceType::GrottoGrave, DMT_COW_GROTTO, DEATH_MOUNTAIN_SUMMIT, 0x0809}}, + {{EntranceType::GrottoGrave, KAK_BACKYARD, KAK_OPEN_GROTTO, 0x070A}, + {EntranceType::GrottoGrave, KAK_OPEN_GROTTO, KAK_BACKYARD, 0x080A}}, + {{EntranceType::GrottoGrave, KAKARIKO_VILLAGE, KAK_REDEAD_GROTTO, 0x070B}, + {EntranceType::GrottoGrave, KAK_REDEAD_GROTTO, KAKARIKO_VILLAGE, 0x080B}}, + {{EntranceType::GrottoGrave, HYRULE_CASTLE_GROUNDS, HC_STORMS_GROTTO, 0x070C}, + {EntranceType::GrottoGrave, HC_STORMS_GROTTO, CASTLE_GROUNDS, 0x080C}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_TEKTITE_GROTTO, 0x070D}, + {EntranceType::GrottoGrave, HF_TEKTITE_GROTTO, HYRULE_FIELD, 0x080D}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_NEAR_KAK_GROTTO, 0x070E}, + {EntranceType::GrottoGrave, HF_NEAR_KAK_GROTTO, HYRULE_FIELD, 0x080E}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_FAIRY_GROTTO, 0x070F}, + {EntranceType::GrottoGrave, HF_FAIRY_GROTTO, HYRULE_FIELD, 0x080F}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_NEAR_MARKET_GROTTO, 0x0710}, + {EntranceType::GrottoGrave, HF_NEAR_MARKET_GROTTO, HYRULE_FIELD, 0x0810}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_COW_GROTTO, 0x0711}, + {EntranceType::GrottoGrave, HF_COW_GROTTO, HYRULE_FIELD, 0x0811}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_INSIDE_FENCE_GROTTO, 0x0712}, + {EntranceType::GrottoGrave, HF_INSIDE_FENCE_GROTTO, HYRULE_FIELD, 0x0812}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_OPEN_GROTTO, 0x0713}, + {EntranceType::GrottoGrave, HF_OPEN_GROTTO, HYRULE_FIELD, 0x0813}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_SOUTHEAST_GROTTO, 0x0714}, + {EntranceType::GrottoGrave, HF_SOUTHEAST_GROTTO, HYRULE_FIELD, 0x0814}}, + {{EntranceType::GrottoGrave, LON_LON_RANCH, LLR_GROTTO, 0x0715}, + {EntranceType::GrottoGrave, LLR_GROTTO, LON_LON_RANCH, 0x0815}}, + {{EntranceType::GrottoGrave, SFM_ENTRYWAY, SFM_WOLFOS_GROTTO, 0x0716}, + {EntranceType::GrottoGrave, SFM_WOLFOS_GROTTO, SFM_ENTRYWAY, 0x0816}}, + {{EntranceType::GrottoGrave, SACRED_FOREST_MEADOW, SFM_STORMS_GROTTO, 0x0717}, + {EntranceType::GrottoGrave, SFM_STORMS_GROTTO, SACRED_FOREST_MEADOW, 0x0817}}, + {{EntranceType::GrottoGrave, SACRED_FOREST_MEADOW, SFM_FAIRY_GROTTO, 0x0718}, + {EntranceType::GrottoGrave, SFM_FAIRY_GROTTO, SACRED_FOREST_MEADOW, 0x0818}}, + {{EntranceType::GrottoGrave, LW_BEYOND_MIDO, LW_SCRUBS_GROTTO, 0x0719}, + {EntranceType::GrottoGrave, LW_SCRUBS_GROTTO, LW_BEYOND_MIDO, 0x0819}}, + {{EntranceType::GrottoGrave, THE_LOST_WOODS, LW_NEAR_SHORTCUTS_GROTTO, 0x071A}, + {EntranceType::GrottoGrave, LW_NEAR_SHORTCUTS_GROTTO, THE_LOST_WOODS, 0x081A}}, + {{EntranceType::GrottoGrave, KOKIRI_FOREST, KF_STORMS_GROTTO, 0x071B}, + {EntranceType::GrottoGrave, KF_STORMS_GROTTO, KOKIRI_FOREST, 0x081B}}, + {{EntranceType::GrottoGrave, ZORAS_DOMAIN, ZD_STORMS_GROTTO, 0x071C}, + {EntranceType::GrottoGrave, ZD_STORMS_GROTTO, ZORAS_DOMAIN, 0x081C}}, + {{EntranceType::GrottoGrave, GERUDO_FORTRESS, GF_STORMS_GROTTO, 0x071D}, + {EntranceType::GrottoGrave, GF_STORMS_GROTTO, GERUDO_FORTRESS, 0x081D}}, + {{EntranceType::GrottoGrave, GV_FORTRESS_SIDE, GV_STORMS_GROTTO, 0x071E}, + {EntranceType::GrottoGrave, GV_STORMS_GROTTO, GV_FORTRESS_SIDE, 0x081E}}, + {{EntranceType::GrottoGrave, GV_GROTTO_LEDGE, GV_OCTOROK_GROTTO, 0x071F}, + {EntranceType::GrottoGrave, GV_OCTOROK_GROTTO, GV_GROTTO_LEDGE, 0x081F}}, + {{EntranceType::GrottoGrave, LW_BEYOND_MIDO, DEKU_THEATER, 0x0720}, + {EntranceType::GrottoGrave, DEKU_THEATER, LW_BEYOND_MIDO, 0x0820}}, + + // Graves have their own specified entrance indices + {{EntranceType::GrottoGrave, THE_GRAVEYARD, GRAVEYARD_SHIELD_GRAVE, 0x004B}, + {EntranceType::GrottoGrave, GRAVEYARD_SHIELD_GRAVE, THE_GRAVEYARD, 0x035D}}, + {{EntranceType::GrottoGrave, THE_GRAVEYARD, GRAVEYARD_HEART_PIECE_GRAVE, 0x031C}, + {EntranceType::GrottoGrave, GRAVEYARD_HEART_PIECE_GRAVE, THE_GRAVEYARD, 0x0361}}, + {{EntranceType::GrottoGrave, THE_GRAVEYARD, GRAVEYARD_COMPOSERS_GRAVE, 0x002D}, + {EntranceType::GrottoGrave, GRAVEYARD_COMPOSERS_GRAVE, THE_GRAVEYARD, 0x050B}}, + {{EntranceType::GrottoGrave, THE_GRAVEYARD, GRAVEYARD_DAMPES_GRAVE, 0x044F}, + {EntranceType::GrottoGrave, GRAVEYARD_DAMPES_GRAVE, THE_GRAVEYARD, 0x0359}}, + + {{EntranceType::Overworld, KOKIRI_FOREST, LW_BRIDGE_FROM_FOREST, 0x05E0}, + {EntranceType::Overworld, LW_BRIDGE, KOKIRI_FOREST, 0x020D}}, + {{EntranceType::Overworld, KOKIRI_FOREST, THE_LOST_WOODS, 0x011E}, + {EntranceType::Overworld, LW_FOREST_EXIT, KOKIRI_FOREST, 0x0286}}, + {{EntranceType::Overworld, THE_LOST_WOODS, GC_WOODS_WARP, 0x04E2}, + {EntranceType::Overworld, GC_WOODS_WARP, THE_LOST_WOODS, 0x04D6}}, + {{EntranceType::Overworld, THE_LOST_WOODS, ZORAS_RIVER, 0x01DD}, + {EntranceType::Overworld, ZORAS_RIVER, THE_LOST_WOODS, 0x04DA}}, + {{EntranceType::Overworld, LW_BEYOND_MIDO, SFM_ENTRYWAY, 0x00FC}, + {EntranceType::Overworld, SFM_ENTRYWAY, LW_BEYOND_MIDO, 0x01A9}}, + {{EntranceType::Overworld, LW_BRIDGE, HYRULE_FIELD, 0x0185}, + {EntranceType::Overworld, HYRULE_FIELD, LW_BRIDGE, 0x04DE}}, + {{EntranceType::Overworld, HYRULE_FIELD, LAKE_HYLIA, 0x0102}, + {EntranceType::Overworld, LAKE_HYLIA, HYRULE_FIELD, 0x0189}}, + {{EntranceType::Overworld, HYRULE_FIELD, GERUDO_VALLEY, 0x0117}, + {EntranceType::Overworld, GERUDO_VALLEY, HYRULE_FIELD, 0x018D}}, + {{EntranceType::Overworld, HYRULE_FIELD, MARKET_ENTRANCE, 0x0276}, + {EntranceType::Overworld, MARKET_ENTRANCE, HYRULE_FIELD, 0x01FD}}, + {{EntranceType::Overworld, HYRULE_FIELD, KAKARIKO_VILLAGE, 0x00DB}, + {EntranceType::Overworld, KAKARIKO_VILLAGE, HYRULE_FIELD, 0x017D}}, + {{EntranceType::Overworld, HYRULE_FIELD, ZR_FRONT, 0x00EA}, + {EntranceType::Overworld, ZR_FRONT, HYRULE_FIELD, 0x0181}}, + {{EntranceType::Overworld, HYRULE_FIELD, LON_LON_RANCH, 0x0157}, + {EntranceType::Overworld, LON_LON_RANCH, HYRULE_FIELD, 0x01F9}}, + {{EntranceType::Overworld, LAKE_HYLIA, ZORAS_DOMAIN, 0x0328}, + {EntranceType::Overworld, ZORAS_DOMAIN, LAKE_HYLIA, 0x0560}}, + {{EntranceType::Overworld, GV_FORTRESS_SIDE, GERUDO_FORTRESS, 0x0129}, + {EntranceType::Overworld, GERUDO_FORTRESS, GV_FORTRESS_SIDE, 0x022D}}, + {{EntranceType::Overworld, GF_OUTSIDE_GATE, WASTELAND_NEAR_FORTRESS, 0x0130}, + {EntranceType::Overworld, WASTELAND_NEAR_FORTRESS, GF_OUTSIDE_GATE, 0x03AC}}, + {{EntranceType::Overworld, WASTELAND_NEAR_COLOSSUS, DESERT_COLOSSUS, 0x0123}, + {EntranceType::Overworld, DESERT_COLOSSUS, WASTELAND_NEAR_COLOSSUS, 0x0365}}, + {{EntranceType::Overworld, MARKET_ENTRANCE, THE_MARKET, 0x00B1}, + {EntranceType::Overworld, THE_MARKET, MARKET_ENTRANCE, 0x0033}}, + {{EntranceType::Overworld, THE_MARKET, CASTLE_GROUNDS, 0x0138}, + {EntranceType::Overworld, CASTLE_GROUNDS, THE_MARKET, 0x025A}}, + {{EntranceType::Overworld, THE_MARKET, TOT_ENTRANCE, 0x0171}, + {EntranceType::Overworld, TOT_ENTRANCE, THE_MARKET, 0x025E}}, + {{EntranceType::Overworld, KAKARIKO_VILLAGE, THE_GRAVEYARD, 0x00E4}, + {EntranceType::Overworld, THE_GRAVEYARD, KAKARIKO_VILLAGE, 0x0195}}, + {{EntranceType::Overworld, KAK_BEHIND_GATE, DEATH_MOUNTAIN_TRAIL, 0x013D}, + {EntranceType::Overworld, DEATH_MOUNTAIN_TRAIL, KAK_BEHIND_GATE, 0x0191}}, + {{EntranceType::Overworld, DEATH_MOUNTAIN_TRAIL, GORON_CITY, 0x014D}, + {EntranceType::Overworld, GORON_CITY, DEATH_MOUNTAIN_TRAIL, 0x01B9}}, + {{EntranceType::Overworld, GC_DARUNIAS_CHAMBER, DMC_LOWER_LOCAL, 0x0246}, + {EntranceType::Overworld, DMC_LOWER_NEARBY, GC_DARUNIAS_CHAMBER, 0x01C1}}, + {{EntranceType::Overworld, DEATH_MOUNTAIN_SUMMIT, DMC_UPPER_LOCAL, 0x0147}, + {EntranceType::Overworld, DMC_UPPER_NEARBY, DEATH_MOUNTAIN_SUMMIT, 0x01BD}}, + {{EntranceType::Overworld, ZR_BEHIND_WATERFALL, ZORAS_DOMAIN, 0x0108}, + {EntranceType::Overworld, ZORAS_DOMAIN, ZR_BEHIND_WATERFALL, 0x019D}}, + {{EntranceType::Overworld, ZD_BEHIND_KING_ZORA, ZORAS_FOUNTAIN, 0x0225}, + {EntranceType::Overworld, ZORAS_FOUNTAIN, ZD_BEHIND_KING_ZORA, 0x01A1}}, + }; + + entranceShuffleFailure = false; + SetAllEntrancesData(entranceShuffleTable); + + // one_way_entrance_pools = OrderedDict() + std::map> entrancePools = {}; + // one_way_priorities = {} + + //owl drops + + //spawns + + //warpsongs + + //Shuffle Dungeon Entrances + if (Settings::ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) { + entrancePools[EntranceType::Dungeon] = GetShuffleableEntrances(EntranceType::Dungeon); + //Add Ganon's Castle, if set to On + Ganon + if (Settings::ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_GANON)) { + AddElementsToPool(entrancePools[EntranceType::Dungeon], GetShuffleableEntrances(EntranceType::GanonDungeon)); + } + //If forest is closed don't allow a forest escape via spirit temple hands + if (Settings::OpenForest.Is(OPENFOREST_CLOSED) && !(Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances)) { + FilterAndEraseFromPool(entrancePools[EntranceType::Dungeon], [](const Entrance* entrance){return entrance->GetParentRegionKey() == KF_OUTSIDE_DEKU_TREE && + entrance->GetConnectedRegionKey() == DEKU_TREE_ENTRYWAY;}); + } + + //decoupled entrances stuff + } + + //interior entrances + if (Settings::ShuffleInteriorEntrances.IsNot(SHUFFLEINTERIORS_OFF)) { + entrancePools[EntranceType::Interior] = GetShuffleableEntrances(EntranceType::Interior); + //special interiors + if (Settings::ShuffleInteriorEntrances.Is(SHUFFLEINTERIORS_ALL)) { + AddElementsToPool(entrancePools[EntranceType::Interior], GetShuffleableEntrances(EntranceType::SpecialInterior)); + } + + //decoupled entrance stuff + } + + //grotto entrances + if (Settings::ShuffleGrottoEntrances) { + entrancePools[EntranceType::GrottoGrave] = GetShuffleableEntrances(EntranceType::GrottoGrave); + + //decoupled entrance stuff + } + + //overworld entrances + if (Settings::ShuffleOverworldEntrances) { + bool excludeOverworldReverse = false; //mix_entrance_pools == all && !decouple_entrances + entrancePools[EntranceType::Overworld] = GetShuffleableEntrances(EntranceType::Overworld, excludeOverworldReverse); + // if not worlds[0].decouple_entrances: + // entrance_pools['Overworld'].remove(world.get_entrance('GV Lower Stream -> Lake Hylia')) + if (!excludeOverworldReverse) { + totalRandomizableEntrances -= 26; //Only count each overworld entrance once + } + } + + //Set shuffled entrances as such + for (auto& pool : entrancePools) { + for (Entrance* entrance : pool.second) { + entrance->SetAsShuffled(); + totalRandomizableEntrances++; + if (entrance->GetReverse() != nullptr) { + entrance->GetReverse()->SetAsShuffled(); + } + } + } + + //combine entrance pools if mixing pools + + //Build target entrance pools and set the assumption for entrances being reachable + //one way entrance stuff + + //assume entrance pools for each type + std::map> targetEntrancePools = {}; + for (auto& pool : entrancePools) { + targetEntrancePools[pool.first] = AssumeEntrancePool(pool.second); + } + + //distribution stuff + + //check placed on-way entrances + //remove replaced entrances so we don't place two in one target + //remvoe priority targets if any placed entrances point at their regions + + //place priority entrances + + //delete all targets that we just placed from one way target pools so multiple one way entrances don't use the same target + + //shuffle all entrances among pools to shuffle + for (auto& pool : entrancePools) { + ShuffleEntrancePool(pool.second, targetEntrancePools[pool.first]); + if (entranceShuffleFailure) { + return ENTRANCE_SHUFFLE_FAILURE; + } + } + + return ENTRANCE_SHUFFLE_SUCCESS; +} + +//Create the set of entrances that will be overridden +void CreateEntranceOverrides() { + entranceOverrides.clear(); + if (noRandomEntrances) { + return; + } + SPDLOG_INFO("\nCREATING ENTRANCE OVERRIDES\n"); + auto allShuffleableEntrances = GetShuffleableEntrances(EntranceType::All, false); + + for (Entrance* entrance : allShuffleableEntrances) { + + //Double-check to make sure the entrance is actually shuffled + if (!entrance->IsShuffled()) { + continue; + } + + auto message = "Setting " + entrance->to_string() + "\n"; + SPDLOG_INFO(message); + + int16_t originalIndex = entrance->GetIndex(); + int16_t destinationIndex = entrance->GetReverse()->GetIndex(); + int16_t originalBlueWarp = entrance->GetBlueWarp(); + int16_t replacementIndex = entrance->GetReplacement()->GetIndex(); + int16_t replacementDestinationIndex = entrance->GetReplacement()->GetReverse()->GetIndex(); + + entranceOverrides.push_back({ + .index = originalIndex, + .destination = destinationIndex, + .blueWarp = originalBlueWarp, + .override = replacementIndex, + .overrideDestination = replacementDestinationIndex, + }); + + message = "\tOriginal: " + std::to_string(originalIndex) + "\n"; + SPDLOG_INFO(message); + message = "\tReplacement " + std::to_string(replacementIndex) + "\n"; + SPDLOG_INFO(message); + } +} + +std::vector> playthroughEntrances; diff --git a/soh/soh/Enhancements/randomizer/3drando/entrance.hpp b/soh/soh/Enhancements/randomizer/3drando/entrance.hpp new file mode 100644 index 000000000..a9b29bca5 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/entrance.hpp @@ -0,0 +1,320 @@ +#pragma once + +#include "keys.hpp" +#include "location_access.hpp" +#include "debug.hpp" + +#include +#include + +#define ENTRANCE_SHUFFLE_SUCCESS 0 +#define ENTRANCE_SHUFFLE_FAILURE 1 + + +typedef struct { + int16_t index; + int16_t destination; + int16_t blueWarp; + int16_t override; + int16_t overrideDestination; +} EntranceOverride; + +typedef enum { + ENTRANCE_GROUP_NO_GROUP, + ENTRANCE_GROUP_KOKIRI_FOREST, + ENTRANCE_GROUP_LOST_WOODS, + ENTRANCE_GROUP_KAKARIKO, + ENTRANCE_GROUP_GRAVEYARD, + ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, + ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, + ENTRANCE_GROUP_GORON_CITY, + ENTRANCE_GROUP_ZORAS_DOMAIN, + ENTRANCE_GROUP_HYRULE_FIELD, + ENTRANCE_GROUP_LON_LON_RANCH, + ENTRANCE_GROUP_LAKE_HYLIA, + ENTRANCE_GROUP_GERUDO_VALLEY, + ENTRANCE_GROUP_HAUNTED_WASTELAND, + ENTRANCE_GROUP_MARKET, + ENTRANCE_GROUP_HYRULE_CASTLE, + SPOILER_ENTRANCE_GROUP_COUNT, +} SpoilerEntranceGroup; + +typedef enum { + ENTRANCE_TYPE_OVERWORLD, + ENTRANCE_TYPE_INTERIOR, + ENTRANCE_TYPE_GROTTO, + ENTRANCE_TYPE_DUNGEON, + ENTRANCE_TYPE_COUNT, +} TrackerEntranceType; + +typedef struct { + int16_t index; + char* name; + SpoilerEntranceGroup group; + TrackerEntranceType type; + uint8_t oneExit; +} EntranceData; + +typedef struct { + uint8_t EntranceCount; + uint16_t GroupEntranceCounts[SPOILER_ENTRANCE_GROUP_COUNT]; + uint16_t GroupOffsets[SPOILER_ENTRANCE_GROUP_COUNT]; +} EntranceTrackingData; + +extern std::list entranceOverrides; + +enum class EntranceType { + None, + OwlDrop, + Spawn, + WarpSong, + Dungeon, + GanonDungeon, + Interior, + SpecialInterior, + GrottoGrave, + Overworld, + Extra, + All, +}; + +class Entrance { +public: + + Entrance(uint32_t connectedRegion_, std::vector conditions_met_) + : connectedRegion(connectedRegion_) { + conditions_met.resize(2); + for (size_t i = 0; i < conditions_met_.size(); i++) { + conditions_met[i] = conditions_met_[i]; + } + } + + bool GetConditionsMet() const { + if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) { + return true; + } else if (Settings::Logic.Is(LOGIC_GLITCHLESS)) { + return conditions_met[0](); + } else if (Settings::Logic.Is(LOGIC_GLITCHED)) { + if (conditions_met[0]()) { + return true; + } else if (conditions_met[1] != NULL) { + return conditions_met[1](); + } + } + return false; + } + + std::string to_string() const { + return AreaTable(parentRegion)->regionName + " -> " + AreaTable(connectedRegion)->regionName; + } + + void SetName(std::string name_ = "") { + if (name_ == "") { + name = AreaTable(parentRegion)->regionName + " -> " + AreaTable(connectedRegion)->regionName; + } else { + name = std::move(name_); + } + + } + + std::string GetName() const { + return name; + } + + void printAgeTimeAccess() { + CitraPrint("Name: "); + CitraPrint(name); + auto message = "Child Day: " + std::to_string(CheckConditionAtAgeTime(Logic::IsChild, Logic::AtDay)) + "\t" + "Child Night: " + std::to_string(CheckConditionAtAgeTime(Logic::IsChild, Logic::AtNight)) + "\t" + "Adult Day: " + std::to_string(CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtDay)) + "\t" + "Adult Night: " + std::to_string(CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtNight)); + CitraPrint(message); + } + + bool ConditionsMet(bool allAgeTimes = false) const { + + Area* parent = AreaTable(parentRegion); + int conditionsMet = 0; + + if (allAgeTimes && !parent->AllAccess()) { + return false; + } + + //check all possible day/night condition combinations + conditionsMet = (parent->childDay && CheckConditionAtAgeTime(Logic::IsChild, Logic::AtDay, allAgeTimes)) + + (parent->childNight && CheckConditionAtAgeTime(Logic::IsChild, Logic::AtNight, allAgeTimes)) + + (parent->adultDay && CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtDay, allAgeTimes)) + + (parent->adultNight && CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtNight, allAgeTimes)); + + return conditionsMet && (!allAgeTimes || conditionsMet == 4); + } + + uint32_t Getuint32_t() const { + return connectedRegion; + } + + //set the logic to be a specific age and time of day and see if the condition still holds + bool CheckConditionAtAgeTime(bool& age, bool& time, bool passAnyway = false) const { + + Logic::IsChild = false; + Logic::IsAdult = false; + Logic::AtDay = false; + Logic::AtNight = false; + + time = true; + age = true; + + Logic::UpdateHelpers(); + return GetConditionsMet() && (connectedRegion != NONE || passAnyway); + } + + uint32_t GetConnectedRegionKey() const { + return connectedRegion; + } + + Area* GetConnectedRegion() const { + return AreaTable(connectedRegion); + } + + void SetParentRegion(uint32_t newParent) { + parentRegion = newParent; + } + + uint32_t GetParentRegionKey() const { + return parentRegion; + } + + Area* GetParentRegion() const { + return AreaTable(parentRegion); + } + + void SetNewEntrance(uint32_t newRegion) { + connectedRegion = newRegion; + } + + void SetAsShuffled() { + shuffled = true; + } + + bool IsShuffled() const { + return shuffled; + } + + bool IsAddedToPool() const { + return addedToPool; + } + + void AddToPool() { + addedToPool = true; + } + + void RemoveFromPool() { + addedToPool = false; + } + + void SetAsPrimary() { + primary = true; + } + + bool IsPrimary() const { + return primary; + } + + int16_t GetIndex() const { + return index; + } + + void SetIndex(int16_t newIndex) { + index = newIndex; + } + + int16_t GetBlueWarp() const { + return blueWarp; + } + + void SetBlueWarp(int16_t newBlueWarp) { + blueWarp = newBlueWarp; + } + + Entrance* GetAssumed() const { + return assumed; + } + + void SetReplacement(Entrance* newReplacement) { + replacement = newReplacement; + } + + Entrance* GetReplacement() const { + return replacement; + } + + EntranceType GetType() const { + return type; + } + + void SetType(EntranceType newType) { + type = newType; + } + + Entrance* GetReverse() const { + return reverse; + } + + void Connect(uint32_t newConnectedRegion) { + connectedRegion = newConnectedRegion; + AreaTable(newConnectedRegion)->entrances.push_front(this); + } + + uint32_t Disconnect() { + AreaTable(connectedRegion)->entrances.remove_if([this](const auto entrance){return this == entrance;}); + uint32_t previouslyConnected = connectedRegion; + connectedRegion = NONE; + return previouslyConnected; + } + + void BindTwoWay(Entrance* otherEntrance) { + reverse = otherEntrance; + otherEntrance->reverse = this; + } + + Entrance* GetNewTarget() { + AreaTable(ROOT)->AddExit(ROOT, connectedRegion, []{return true;}); + Entrance* targetEntrance = AreaTable(ROOT)->GetExit(connectedRegion); + targetEntrance->SetReplacement(this); + targetEntrance->SetName(GetParentRegion()->regionName + " -> " + GetConnectedRegion()->regionName); + return targetEntrance; + } + + Entrance* AssumeReachable() { + if (assumed == nullptr) { + assumed = GetNewTarget(); + Disconnect(); + } + return assumed; + } + +private: + uint32_t parentRegion; + uint32_t connectedRegion; + std::vector conditions_met; + + //Entrance Randomizer stuff + EntranceType type = EntranceType::None; + Entrance* target = nullptr; + Entrance* reverse = nullptr; + Entrance* assumed = nullptr; + Entrance* replacement = nullptr; + int16_t index = 0xFFFF; + int16_t blueWarp = 0; + bool shuffled = false; + bool primary = false; + bool addedToPool = false; + std::string name = ""; +}; + +int ShuffleAllEntrances(); +void CreateEntranceOverrides(); +EntranceTrackingData* GetEntranceTrackingData(); + +extern std::vector> playthroughEntrances; +extern bool noRandomEntrances; diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp new file mode 100644 index 000000000..b9cf75518 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -0,0 +1,1074 @@ +#include "fill.hpp" + +#include "custom_messages.hpp" +#include "dungeon.hpp" +#include "item_location.hpp" +#include "item_pool.hpp" +#include "location_access.hpp" +#include "logic.hpp" +#include "random.hpp" +#include "spoiler_log.hpp" +#include "starting_inventory.hpp" +#include "hints.hpp" +#include "hint_list.hpp" +#include "entrance.hpp" +#include "shops.hpp" +#include "debug.hpp" + +#include +#include +#include + +using namespace CustomMessages; +using namespace Logic; +using namespace Settings; + +static bool placementFailure = false; + +static void RemoveStartingItemsFromPool() { + for (uint32_t startingItem : StartingInventory) { + for (size_t i = 0; i < ItemPool.size(); i++) { + if (startingItem == BIGGORON_SWORD) { + if (ItemPool[i] == GIANTS_KNIFE || ItemPool[i] == BIGGORON_SWORD) { + ItemPool[i] = GetJunkItem(); + } + continue; + } else if (startingItem == ItemPool[i] || (ItemTable(startingItem).IsBottleItem() && ItemTable(ItemPool[i]).IsBottleItem())) { + if (AdditionalHeartContainers > 0 && (startingItem == PIECE_OF_HEART || startingItem == TREASURE_GAME_HEART)) { + ItemPool[i] = HEART_CONTAINER; + AdditionalHeartContainers--; + } else { + ItemPool[i] = GetJunkItem(); + } + break; + } + } + } +} + +//This function will propogate Time of Day access through the entrance +static bool UpdateToDAccess(Entrance* entrance, SearchMode mode) { + + bool ageTimePropogated = false; + + //propogate childDay, childNight, adultDay, and adultNight separately + Area* parent = entrance->GetParentRegion(); + Area* connection = entrance->GetConnectedRegion(); + + if (!connection->childDay && parent->childDay && entrance->CheckConditionAtAgeTime(Logic::IsChild, AtDay)) { + connection->childDay = true; + ageTimePropogated = true; + } + if (!connection->childNight && parent->childNight && entrance->CheckConditionAtAgeTime(Logic::IsChild, AtNight)) { + connection->childNight = true; + ageTimePropogated = true; + } + if (!connection->adultDay && parent->adultDay && entrance->CheckConditionAtAgeTime(IsAdult, AtDay)) { + connection->adultDay = true; + ageTimePropogated = true; + } + if (!connection->adultNight && parent->adultNight && entrance->CheckConditionAtAgeTime(IsAdult, AtNight)) { + connection->adultNight = true; + ageTimePropogated = true; + } + + //special check for temple of time + bool propogateTimeTravel = mode != SearchMode::TimePassAccess && mode != SearchMode::TempleOfTimeAccess; + if (!AreaTable(ROOT)->Adult() && AreaTable(TOT_BEYOND_DOOR_OF_TIME)->Child() && propogateTimeTravel) { + AreaTable(ROOT)->adultDay = AreaTable(TOT_BEYOND_DOOR_OF_TIME)->childDay; + AreaTable(ROOT)->adultNight = AreaTable(TOT_BEYOND_DOOR_OF_TIME)->childNight; + } else if (!AreaTable(ROOT)->Child() && AreaTable(TOT_BEYOND_DOOR_OF_TIME)->Adult() && propogateTimeTravel){ + AreaTable(ROOT)->childDay = AreaTable(TOT_BEYOND_DOOR_OF_TIME)->adultDay; + AreaTable(ROOT)->childNight = AreaTable(TOT_BEYOND_DOOR_OF_TIME)->adultNight; + } + + return ageTimePropogated; +} + +// Various checks that need to pass for the world to be validated as completable +static void ValidateWorldChecks(SearchMode& mode, bool checkPoeCollectorAccess, bool checkOtherEntranceAccess, std::vector& areaPool) { + // Condition for validating Temple of Time Access + if (mode == SearchMode::TempleOfTimeAccess && ((Settings::ResolvedStartingAge == AGE_CHILD && AreaTable(TEMPLE_OF_TIME)->Adult()) || (Settings::ResolvedStartingAge == AGE_ADULT && AreaTable(TEMPLE_OF_TIME)->Child()) || !checkOtherEntranceAccess)) { + mode = SearchMode::ValidStartingRegion; + } + // Condition for validating a valid starting region + if (mode == SearchMode::ValidStartingRegion) { + bool childAccess = Settings::ResolvedStartingAge == AGE_CHILD || AreaTable(TOT_BEYOND_DOOR_OF_TIME)->Child(); + bool adultAccess = Settings::ResolvedStartingAge == AGE_ADULT || AreaTable(TOT_BEYOND_DOOR_OF_TIME)->Adult(); + + Area* kokiri = AreaTable(KOKIRI_FOREST); + Area* kakariko = AreaTable(KAKARIKO_VILLAGE); + + if ((childAccess && (kokiri->Child() || kakariko->Child())) || + (adultAccess && (kokiri->Adult() || kakariko->Adult())) || + !checkOtherEntranceAccess) { + mode = SearchMode::PoeCollectorAccess; + ApplyStartingInventory(); + Logic::NoBottles = true; + } + } + // Condition for validating Poe Collector Access + if (mode == SearchMode::PoeCollectorAccess && (AreaTable(MARKET_GUARD_HOUSE)->Adult() || !checkPoeCollectorAccess)) { + // Apply all items that are necessary for checking all location access + std::vector itemsToPlace = + FilterFromPool(ItemPool, [](const auto i) { return ItemTable(i).IsAdvancement(); }); + for (uint32_t unplacedItem : itemsToPlace) { + ItemTable(unplacedItem).ApplyEffect(); + } + // Reset access as the non-starting age + if (Settings::ResolvedStartingAge == AGE_CHILD) { + for (uint32_t areaKey : areaPool) { + AreaTable(areaKey)->adultDay = false; + AreaTable(areaKey)->adultNight = false; + } + } else { + for (uint32_t areaKey : areaPool) { + AreaTable(areaKey)->childDay = false; + AreaTable(areaKey)->childNight = false; + } + } + mode = SearchMode::AllLocationsReachable; + } else { + Logic::NoBottles = false; + } +} + +//Get the max number of tokens that can possibly be useful +static int GetMaxGSCount() { + //If bridge or LACS is set to tokens, get how many are required + int maxBridge = 0; + int maxLACS = 0; + if (Settings::Bridge.Is(RAINBOWBRIDGE_TOKENS)) { + maxBridge = Settings::BridgeTokenCount.Value(); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_TOKENS)) { + maxLACS = Settings::LACSTokenCount.Value(); + } + maxBridge = std::max(maxBridge, maxLACS); + //Get the max amount of GS which could be useful from token reward locations + int maxUseful = 0; + //If the highest advancement item is a token, we know it is useless since it won't lead to an otherwise useful item + if (Location(KAK_50_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_50_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) { + maxUseful = 50; + } + else if (Location(KAK_40_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_40_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) { + maxUseful = 40; + } + else if (Location(KAK_30_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_30_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) { + maxUseful = 30; + } + else if (Location(KAK_20_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_20_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) { + maxUseful = 20; + } + else if (Location(KAK_10_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_10_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) { + maxUseful = 10; + } + //Return max of the two possible reasons tokens could be important + return std::max(maxUseful, maxBridge); +} + +std::string GetShopItemBaseName(std::string itemName) { + std::string baseName = itemName.erase(0, 4); //Delete "Buy " + //Delete amount, if present (so when it looks like Buy Deku Nut (10) remove the (10)) + if (baseName.find("(") != std::string::npos) { + baseName = baseName.erase(baseName.find("(")); + } + //Do the same for [] (only applies to red potions, other things with [] also have a ()) + if (baseName.find("[") != std::string::npos) { + baseName = baseName.erase(baseName.find("[")); + } + return baseName; +} + +std::vector GetEmptyLocations(std::vector allowedLocations) { + return FilterFromPool(allowedLocations, [](const auto loc){ return Location(loc)->GetPlaceduint32_t() == NONE;}); +} + +std::vector GetAllEmptyLocations() { + return FilterFromPool(allLocations, [](const auto loc) { return Location(loc)->GetPlaceduint32_t() == NONE; }); +} + +//This function will return a vector of ItemLocations that are accessible with +//where items have been placed so far within the world. The allowedLocations argument +//specifies the pool of locations that we're trying to search for an accessible location in +std::vector GetAccessibleLocations(const std::vector& allowedLocations, SearchMode mode /* = SearchMode::ReachabilitySearch*/, std::string ignore /*= ""*/, bool checkPoeCollectorAccess /*= false*/, bool checkOtherEntranceAccess /*= false*/) { + std::vector accessibleLocations; + // Reset all access to begin a new search + if (mode < SearchMode::ValidateWorld) { + ApplyStartingInventory(); + } + Areas::AccessReset(); + LocationReset(); + std::vector areaPool = {ROOT}; + + if (mode == SearchMode::ValidateWorld) { + mode = SearchMode::TimePassAccess; + AreaTable(ROOT)->childNight = true; + AreaTable(ROOT)->adultNight = true; + AreaTable(ROOT)->childDay = true; + AreaTable(ROOT)->adultDay = true; + allLocationsReachable = false; + } + + //Variables for playthrough + int gsCount = 0; + const int maxGsCount = mode == SearchMode::GeneratePlaythrough ? GetMaxGSCount() : 0; //If generating playthrough want the max that's possibly useful, else doesn't matter + bool bombchusFound = false; + std::vector buyIgnores; + + //Variables for search + std::vector newItemLocations; + bool updatedEvents = false; + bool ageTimePropogated = false; + bool firstIteration = true; + + //Variables for Time Pass access + bool timePassChildDay = false; + bool timePassChildNight = false; + bool timePassAdultDay = false; + bool timePassAdultNight = false; + + // Main access checking loop + while (newItemLocations.size() > 0 || updatedEvents || ageTimePropogated || firstIteration) { + firstIteration = false; + ageTimePropogated = false; + updatedEvents = false; + + for (ItemLocation* location : newItemLocations) { + location->ApplyPlacedItemEffect(); + } + newItemLocations.clear(); + + std::vector itemSphere; + std::list entranceSphere; + + for (size_t i = 0; i < areaPool.size(); i++) { + Area* area = AreaTable(areaPool[i]); + + if (area->UpdateEvents(mode)){ + updatedEvents = true; + } + + // If we're checking for TimePass access do that for each area as it's being updated. + // TimePass Access is satisfied when every AgeTime can reach an area with TimePass + // without the aid of TimePass. During this mode, TimePass won't update ToD access + // in any area. + if (mode == SearchMode::TimePassAccess) { + if (area->timePass) { + if (area->childDay) { + timePassChildDay = true; + } + if (area->childNight) { + timePassChildNight = true; + } + if (area->adultDay) { + timePassAdultDay = true; + } + if (area->adultNight) { + timePassAdultNight = true; + } + } + // Condition for validating that all startring AgeTimes have timepass access + // Once satisifed, change the mode to begin checking for Temple of Time Access + if ((timePassChildDay && timePassChildNight && timePassAdultDay && timePassAdultNight) || !checkOtherEntranceAccess) { + mode = SearchMode::TempleOfTimeAccess; + } + } + + //for each exit in this area + for (auto& exit : area->exits) { + + //Update Time of Day Access for the exit + if (UpdateToDAccess(&exit, mode)) { + ageTimePropogated = true; + ValidateWorldChecks(mode, checkPoeCollectorAccess, checkOtherEntranceAccess, areaPool); + } + + //If the exit is accessible and hasn't been added yet, add it to the pool + Area* exitArea = exit.GetConnectedRegion(); + if (!exitArea->addedToPool && exit.ConditionsMet()) { + exitArea->addedToPool = true; + areaPool.push_back(exit.Getuint32_t()); + } + + // Add shuffled entrances to the entrance playthrough + if (mode == SearchMode::GeneratePlaythrough && exit.IsShuffled() && !exit.IsAddedToPool() && !noRandomEntrances) { + entranceSphere.push_back(&exit); + exit.AddToPool(); + // Don't list a coupled entrance from both directions + if (exit.GetReplacement()->GetReverse() != nullptr /*&& !DecoupleEntrances*/) { + exit.GetReplacement()->GetReverse()->AddToPool(); + } + } + } + + //for each ItemLocation in this area + if (mode < SearchMode::ValidateWorld) { + for (size_t k = 0; k < area->locations.size(); k++) { + LocationAccess& locPair = area->locations[k]; + uint32_t loc = locPair.GetLocation(); + ItemLocation* location = Location(loc); + + if (!location->IsAddedToPool() && locPair.ConditionsMet()) { + + location->AddToPool(); + + if (location->GetPlaceduint32_t() == NONE) { + accessibleLocations.push_back(loc); //Empty location, consider for placement + } else { + //If ignore has a value, we want to check if the item location should be considered or not + //This is necessary due to the below preprocessing for playthrough generation + if (ignore != "") { + ItemType type = location->GetPlacedItem().GetItemType(); + std::string itemName(location->GetPlacedItemName().GetEnglish()); + //If we want to ignore tokens, only add if not a token + if (ignore == "Tokens" && type != ITEMTYPE_TOKEN) { + newItemLocations.push_back(location); + } + //If we want to ignore bombchus, only add if bombchu is not in the name + else if (ignore == "Bombchus" && itemName.find("Bombchu") == std::string::npos) { + newItemLocations.push_back(location); + } + //We want to ignore a specific Buy item name + else if (ignore != "Tokens" && ignore != "Bombchus") { + if ((type == ITEMTYPE_SHOP && ignore != GetShopItemBaseName(itemName)) || type != ITEMTYPE_SHOP) { + newItemLocations.push_back(location); + } + } + } + //If it doesn't, we can just add the location + else { + newItemLocations.push_back(location); //Add item to cache to be considered in logic next iteration + } + } + + //Playthrough stuff + //Generate the playthrough, so we want to add advancement items, unless we know to ignore them + if (mode == SearchMode::GeneratePlaythrough) { + //Item is an advancement item, figure out if it should be added to this sphere + if (!playthroughBeatable && location->GetPlacedItem().IsAdvancement()) { + ItemType type = location->GetPlacedItem().GetItemType(); + std::string itemName(location->GetPlacedItemName().GetEnglish()); + bool bombchus = itemName.find("Bombchu") != std::string::npos; //Is a bombchu location + + //Decide whether to exclude this location + //This preprocessing is done to reduce the amount of searches performed in PareDownPlaythrough + //Want to exclude: + //1) Tokens after the last potentially useful one (the last one that gives an advancement item or last for token bridge) + //2) Bombchus after the first (including buy bombchus) + //3) Buy items of the same type, after the first (So only see Buy Deku Nut of any amount once) + bool exclude = true; + //Exclude tokens after the last possibly useful one + if (type == ITEMTYPE_TOKEN && gsCount < maxGsCount) { + gsCount++; + exclude = false; + } + //Only print first bombchu location found + else if (bombchus && !bombchusFound) { + bombchusFound = true; + exclude = false; + } + //Handle buy items + //If ammo drops are off, don't do this step, since buyable ammo becomes logically important + else if (AmmoDrops.IsNot(AMMODROPS_NONE) && !(bombchus && bombchusFound) && type == ITEMTYPE_SHOP) { + //Only check each buy item once + std::string buyItem = GetShopItemBaseName(itemName); + //Buy item not in list to ignore, add it to list and write to playthrough + if (std::find(buyIgnores.begin(), buyIgnores.end(), buyItem) == buyIgnores.end()) { + exclude = false; + buyIgnores.push_back(buyItem); + } + } + //Add all other advancement items + else if (!bombchus && type != ITEMTYPE_TOKEN && (AmmoDrops.Is(AMMODROPS_NONE) || type != ITEMTYPE_SHOP)) { + exclude = false; + } + //Has not been excluded, add to playthrough + if (!exclude) { + itemSphere.push_back(loc); + } + } + //Triforce has been found, seed is beatable, nothing else in this or future spheres matters + else if (location->GetPlaceduint32_t() == TRIFORCE) { + itemSphere.clear(); + itemSphere.push_back(loc); + playthroughBeatable = true; + } + } + //All we care about is if the game is beatable, used to pare down playthrough + else if (location->GetPlaceduint32_t() == TRIFORCE && mode == SearchMode::CheckBeatable) { + playthroughBeatable = true; + return {}; //Return early for efficiency + } + } + } + } + } + + if (mode == SearchMode::GeneratePlaythrough && itemSphere.size() > 0) { + playthroughLocations.push_back(itemSphere); + } + if (mode == SearchMode::GeneratePlaythrough && entranceSphere.size() > 0 && !noRandomEntrances) { + playthroughEntrances.push_back(entranceSphere); + } + } + + //Check to see if all locations were reached + if (mode == SearchMode::AllLocationsReachable) { + allLocationsReachable = true; + for (const uint32_t loc : allLocations) { + if (!Location(loc)->IsAddedToPool()) { + allLocationsReachable = false; + auto message = "Location " + Location(loc)->GetName() + " not reachable\n"; + SPDLOG_INFO(message); + #ifndef ENABLE_DEBUG + break; + #endif + } + } + return {}; + } + + erase_if(accessibleLocations, [&allowedLocations](uint32_t loc){ + for (uint32_t allowedLocation : allowedLocations) { + if (loc == allowedLocation || Location(loc)->GetPlaceduint32_t() != NONE) { + return false; + } + } + return true; + }); + return accessibleLocations; +} + +static void GeneratePlaythrough() { + playthroughBeatable = false; + LogicReset(); + GetAccessibleLocations(allLocations, SearchMode::GeneratePlaythrough); +} + +//Remove unnecessary items from playthrough by removing their location, and checking if game is still beatable +//To reduce searches, some preprocessing is done in playthrough generation to avoid adding obviously unnecessary items +static void PareDownPlaythrough() { + std::vector toAddBackItem; + //Start at sphere before Ganon's and count down + for (int i = playthroughLocations.size() - 2; i >= 0; i--) { + //Check each item location in sphere + std::vector erasableIndices; + std::vector sphere = playthroughLocations.at(i); + for (int j = sphere.size() - 1; j >= 0; j--) { + uint32_t loc = sphere.at(j); + uint32_t copy = Location(loc)->GetPlaceduint32_t(); //Copy out item + Location(loc)->SetPlacedItem(NONE); //Write in empty item + playthroughBeatable = false; + LogicReset(); + + std::string ignore = ""; + if (ItemTable(copy).GetItemType() == ITEMTYPE_TOKEN) { + ignore = "Tokens"; + } + else if (ItemTable(copy).GetName().GetEnglish().find("Bombchu") != std::string::npos) { + ignore = "Bombchus"; + } + else if (ItemTable(copy).GetItemType() == ITEMTYPE_SHOP) { + ignore = GetShopItemBaseName(ItemTable(copy).GetName().GetEnglish()); + } + + GetAccessibleLocations(allLocations, SearchMode::CheckBeatable, ignore); //Check if game is still beatable + + //Playthrough is still beatable without this item, therefore it can be removed from playthrough section. + if (playthroughBeatable) { + //Uncomment to print playthrough deletion log in citra + // std::string itemname(ItemTable(copy).GetName().GetEnglish()); + // std::string locationname(Location(loc)->GetName()); + // std::string removallog = itemname + " at " + locationname + " removed from playthrough"; + // CitraPrint(removallog); + playthroughLocations[i].erase(playthroughLocations[i].begin() + j); + Location(loc)->SetDelayedItem(copy); //Game is still beatable, don't add back until later + toAddBackItem.push_back(loc); + } + else { + Location(loc)->SetPlacedItem(copy); //Immediately put item back so game is beatable again + } + } + } + + //Some spheres may now be empty, remove these + for (int i = playthroughLocations.size() - 2; i >= 0; i--) { + if (playthroughLocations.at(i).size() == 0) { + playthroughLocations.erase(playthroughLocations.begin() + i); + } + } + + //Now we can add back items which were removed previously + for (uint32_t loc : toAddBackItem) { + Location(loc)->SaveDelayedItem(); + } +} + +//Very similar to PareDownPlaythrough except it creates the list of Way of the Hero items +//Way of the Hero items are more specific than playthrough items in that they are items which *must* +// be obtained to logically be able to complete the seed, rather than playthrough items which +// are just possible items you *can* collect to complete the seed. +static void CalculateWotH() { + //First copy locations from the 2-dimensional playthroughLocations into the 1-dimensional wothLocations + //size - 1 so Triforce is not counted + for (size_t i = 0; i < playthroughLocations.size() - 1; i++) { + for (size_t j = 0; j < playthroughLocations[i].size(); j++) { + if (Location(playthroughLocations[i][j])->IsHintable()) { + wothLocations.push_back(playthroughLocations[i][j]); + } + } + } + + //Now go through and check each location, seeing if it is strictly necessary for game completion + for (int i = wothLocations.size() - 1; i >= 0; i--) { + uint32_t loc = wothLocations[i]; + uint32_t copy = Location(loc)->GetPlaceduint32_t(); //Copy out item + Location(loc)->SetPlacedItem(NONE); //Write in empty item + playthroughBeatable = false; + LogicReset(); + GetAccessibleLocations(allLocations, SearchMode::CheckBeatable); //Check if game is still beatable + Location(loc)->SetPlacedItem(copy); //Immediately put item back + //If removing this item and no other item caused the game to become unbeatable, then it is strictly necessary, so keep it + //Else, delete from wothLocations + if (playthroughBeatable) { + wothLocations.erase(wothLocations.begin() + i); + } + } + + playthroughBeatable = true; + LogicReset(); + GetAccessibleLocations(allLocations); +} + +//Will place things completely randomly, no logic checks are performed +static void FastFill(std::vector items, std::vector locations, bool endOnItemsEmpty = false) { + //Loop until locations are empty, or also end if items are empty and the parameters specify to end then + while (!locations.empty() && (!endOnItemsEmpty || !items.empty())) { + uint32_t loc = RandomElement(locations, true); + Location(loc)->SetAsHintable(); + PlaceItemInLocation(loc, RandomElement(items, true)); + + if (items.empty() && !endOnItemsEmpty) { + items.push_back(GetJunkItem()); + } + } +} + +/* +| The algorithm places items in the world in reverse. +| This means we first assume we have every item in the item pool and +| remove an item and try to place it somewhere that is still reachable +| This method helps distribution of items locked behind many requirements. +| - OoT Randomizer +*/ +static void AssumedFill(const std::vector& items, const std::vector& allowedLocations, + bool setLocationsAsHintable = false) { + + if (items.size() > allowedLocations.size()) { + printf("\x1b[2;2HERROR: MORE ITEMS THAN LOCATIONS IN GIVEN LISTS"); + SPDLOG_INFO("Items:\n"); + for (const uint32_t item : items) { + SPDLOG_INFO("\t"); + SPDLOG_INFO(ItemTable(item).GetName().GetEnglish()); + SPDLOG_INFO("\n"); + } + SPDLOG_INFO("\nAllowed Locations:\n"); + for (const uint32_t loc : allowedLocations) { + SPDLOG_INFO("\t"); + SPDLOG_INFO(Location(loc)->GetName()); + SPDLOG_INFO("\n"); + } + placementFailure = true; + return; + } + + if (Settings::Logic.Is(LOGIC_NONE)) { + FastFill(items, GetEmptyLocations(allowedLocations), true); + return; + } + + // keep retrying to place everything until it works or takes too long + int retries = 10; + bool unsuccessfulPlacement = false; + std::vector attemptedLocations; + do { + retries--; + if (retries <= 0) { + placementFailure = true; + return; + } + unsuccessfulPlacement = false; + std::vector itemsToPlace = items; + + // copy all not yet placed advancement items so that we can apply their effects for the fill algorithm + std::vector itemsToNotPlace = + FilterFromPool(ItemPool, [](const auto i) { return ItemTable(i).IsAdvancement(); }); + + // shuffle the order of items to place + Shuffle(itemsToPlace); + while (!itemsToPlace.empty()) { + uint32_t item = std::move(itemsToPlace.back()); + ItemTable(item).SetAsPlaythrough(); + itemsToPlace.pop_back(); + + // assume we have all unplaced items + LogicReset(); + for (uint32_t unplacedItem : itemsToPlace) { + ItemTable(unplacedItem).ApplyEffect(); + } + for (uint32_t unplacedItem : itemsToNotPlace) { + ItemTable(unplacedItem).ApplyEffect(); + } + + // get all accessible locations that are allowed + const std::vector accessibleLocations = GetAccessibleLocations(allowedLocations); + + // retry if there are no more locations to place items + if (accessibleLocations.empty()) { + + SPDLOG_INFO("\nCANNOT PLACE "); + SPDLOG_INFO(ItemTable(item).GetName().GetEnglish()); + SPDLOG_INFO(". TRYING AGAIN...\n"); + +#ifdef ENABLE_DEBUG + Areas::DumpWorldGraph(ItemTable(item).GetName().GetEnglish()); + PlacementLog_Write(); +#endif + + // reset any locations that got an item + for (uint32_t loc : attemptedLocations) { + Location(loc)->SetPlacedItem(NONE); + itemsPlaced--; + } + attemptedLocations.clear(); + + unsuccessfulPlacement = true; + break; + } + + // place the item within one of the allowed locations + uint32_t selectedLocation = RandomElement(accessibleLocations); + PlaceItemInLocation(selectedLocation, item); + attemptedLocations.push_back(selectedLocation); + + // This tells us the location went through the randomization algorithm + // to distinguish it from locations which did not or that the player already + // knows + if (setLocationsAsHintable) { + Location(selectedLocation)->SetAsHintable(); + } + + // If ALR is off, then we check beatability after placing the item. + // If the game is beatable, then we can stop placing items with logic. + if (!LocationsReachable) { + playthroughBeatable = false; + LogicReset(); + GetAccessibleLocations(allLocations, SearchMode::CheckBeatable); + if (playthroughBeatable) { + SPDLOG_INFO("Game beatable, now placing items randomly. " + std::to_string(itemsToPlace.size()) + + " major items remaining.\n\n"); + FastFill(itemsToPlace, GetEmptyLocations(allowedLocations), true); + return; + } + } + } + } while (unsuccessfulPlacement); +} + +//This function will specifically randomize dungeon rewards for the End of Dungeons +//setting, or randomize one dungeon reward to Link's Pocket if that setting is on +static void RandomizeDungeonRewards() { + + //quest item bit mask of each stone/medallion for the savefile + static constexpr std::array bitMaskTable = { + 0x00040000, //Kokiri Emerald + 0x00080000, //Goron Ruby + 0x00100000, //Zora Sapphire + 0x00000001, //Forest Medallion + 0x00000002, //Fire Medallion + 0x00000004, //Water Medallion + 0x00000008, //Spirit Medallion + 0x00000010, //Shadow Medallion + 0x00000020, //Light Medallion + }; + int baseOffset = ItemTable(KOKIRI_EMERALD).GetItemID(); + + //End of Dungeons includes Link's Pocket + if (ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON)) { + //get stones and medallions + std::vector rewards = FilterAndEraseFromPool(ItemPool, [](const auto i) {return ItemTable(i).GetItemType() == ITEMTYPE_DUNGEONREWARD;}); + + // If there are less than 9 dungeon rewards, prioritize the actual dungeons + // for placement instead of Link's Pocket + if (rewards.size() < 9) { + PlaceItemInLocation(LINKS_POCKET, GREEN_RUPEE); + } + + if (Settings::Logic.Is(LOGIC_VANILLA)) { //Place dungeon rewards in vanilla locations + for (uint32_t loc : dungeonRewardLocations) { + Location(loc)->PlaceVanillaItem(); + } + } else { //Randomize dungeon rewards with assumed fill + AssumedFill(rewards, dungeonRewardLocations); + } + + for (size_t i = 0; i < dungeonRewardLocations.size(); i++) { + const auto index = Location(dungeonRewardLocations[i])->GetPlacedItem().GetItemID() - baseOffset; + rDungeonRewardOverrides[i] = index; + + //set the player's dungeon reward on file creation instead of pushing it to them at the start. + //This is done mainly because players are already familiar with seeing their dungeon reward + //before opening up their file + if (i == dungeonRewardLocations.size()-1) { + LinksPocketRewardBitMask = bitMaskTable[index]; + } + } + } else if (LinksPocketItem.Is(LINKSPOCKETITEM_DUNGEON_REWARD)) { + //get 1 stone/medallion + std::vector rewards = FilterFromPool(ItemPool, [](const auto i) {return ItemTable(i).GetItemType() == ITEMTYPE_DUNGEONREWARD;}); + // If there are no remaining stones/medallions, then Link's pocket won't get one + if (rewards.empty()) { + PlaceItemInLocation(LINKS_POCKET, GREEN_RUPEE); + return; + } + uint32_t startingReward = RandomElement(rewards, true); + + LinksPocketRewardBitMask = bitMaskTable[ItemTable(startingReward).GetItemID() - baseOffset]; + PlaceItemInLocation(LINKS_POCKET, startingReward); + //erase the stone/medallion from the Item Pool + FilterAndEraseFromPool(ItemPool, [startingReward](const uint32_t i) {return i == startingReward;}); + } +} + +//Fills any locations excluded by the player with junk items so that advancement items +//can't be placed there. +static void FillExcludedLocations() { + //Only fill in excluded locations that don't already have something and are forbidden + std::vector excludedLocations = FilterFromPool(allLocations, [](const auto loc){ + return Location(loc)->IsExcluded(); + }); + + for (uint32_t loc : excludedLocations) { + PlaceJunkInExcludedLocation(loc); + } +} + +//Function to handle the Own Dungeon setting +static void RandomizeOwnDungeon(const Dungeon::DungeonInfo* dungeon) { + std::vector dungeonLocations = dungeon->GetDungeonLocations(); + std::vector dungeonItems; + + //filter out locations that may be required to have songs placed at them + dungeonLocations = FilterFromPool(dungeonLocations, [](const auto loc){ + if (ShuffleSongs.Is(SONGSHUFFLE_SONG_LOCATIONS)) { + return !(Location(loc)->IsCategory(Category::cSong)); + } + if (ShuffleSongs.Is(SONGSHUFFLE_DUNGEON_REWARDS)) { + return !(Location(loc)->IsCategory(Category::cSongDungeonReward)); + } + return true; + }); + + //Add specific items that need be randomized within this dungeon + if (Keysanity.Is(KEYSANITY_OWN_DUNGEON) && dungeon->GetSmallKey() != NONE) { + std::vector dungeonSmallKeys = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){ return i == dungeon->GetSmallKey();}); + AddElementsToPool(dungeonItems, dungeonSmallKeys); + } + + if ((BossKeysanity.Is(BOSSKEYSANITY_OWN_DUNGEON) && dungeon->GetBossKey() != GANONS_CASTLE_BOSS_KEY) || + (GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON) && dungeon->GetBossKey() == GANONS_CASTLE_BOSS_KEY)) { + auto dungeonBossKey = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){ return i == dungeon->GetBossKey();}); + AddElementsToPool(dungeonItems, dungeonBossKey); + } + + //randomize boss key and small keys together for even distribution + AssumedFill(dungeonItems, dungeonLocations); + + //randomize map and compass separately since they're not progressive + if (MapsAndCompasses.Is(MAPSANDCOMPASSES_OWN_DUNGEON) && dungeon->GetMap() != NONE && dungeon->GetCompass() != NONE) { + auto dungeonMapAndCompass = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){ return i == dungeon->GetMap() || i == dungeon->GetCompass();}); + AssumedFill(dungeonMapAndCompass, dungeonLocations); + } +} + +/*Randomize items restricted to a certain set of locations. + The fill order of location groups is as follows: + - Own Dungeon + - Any Dungeon + - Overworld + Small Keys, Gerudo Keys, Boss Keys, Ganon's Boss Key, and/or dungeon rewards + will be randomized together if they have the same setting. Maps and Compasses + are randomized separately once the dungeon advancement items have all been placed.*/ +static void RandomizeDungeonItems() { + using namespace Dungeon; + + //Get Any Dungeon and Overworld group locations + std::vector anyDungeonLocations = FilterFromPool(allLocations, [](const auto loc){return Location(loc)->IsDungeon();}); + //overworldLocations defined in item_location.cpp + + //Create Any Dungeon and Overworld item pools + std::vector anyDungeonItems; + std::vector overworldItems; + + for (auto dungeon : dungeonList) { + if (Keysanity.Is(KEYSANITY_ANY_DUNGEON)) { + auto dungeonKeys = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetSmallKey();}); + AddElementsToPool(anyDungeonItems, dungeonKeys); + } else if (Keysanity.Is(KEYSANITY_OVERWORLD)) { + auto dungeonKeys = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetSmallKey();}); + AddElementsToPool(overworldItems, dungeonKeys); + } + + if (BossKeysanity.Is(BOSSKEYSANITY_ANY_DUNGEON) && dungeon->GetBossKey() != GANONS_CASTLE_BOSS_KEY) { + auto bossKey = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetBossKey();}); + AddElementsToPool(anyDungeonItems, bossKey); + } else if (BossKeysanity.Is(BOSSKEYSANITY_OVERWORLD) && dungeon->GetBossKey() != GANONS_CASTLE_BOSS_KEY) { + auto bossKey = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetBossKey();}); + AddElementsToPool(overworldItems, bossKey); + } + + if (GanonsBossKey.Is(GANONSBOSSKEY_ANY_DUNGEON)) { + auto ganonBossKey = FilterAndEraseFromPool(ItemPool, [](const auto i){return i == GANONS_CASTLE_BOSS_KEY;}); + AddElementsToPool(anyDungeonItems, ganonBossKey); + } else if (GanonsBossKey.Is(GANONSBOSSKEY_OVERWORLD)) { + auto ganonBossKey = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == GANONS_CASTLE_BOSS_KEY; }); + AddElementsToPool(overworldItems, ganonBossKey); + } + } + + if (GerudoKeys.Is(GERUDOKEYS_ANY_DUNGEON)) { + auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == GERUDO_FORTRESS_SMALL_KEY; }); + AddElementsToPool(anyDungeonItems, gerudoKeys); + } else if (GerudoKeys.Is(GERUDOKEYS_OVERWORLD)) { + auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == GERUDO_FORTRESS_SMALL_KEY; }); + AddElementsToPool(overworldItems, gerudoKeys); + } + + if (ShuffleRewards.Is(REWARDSHUFFLE_ANY_DUNGEON)) { + auto rewards = FilterAndEraseFromPool( + ItemPool, [](const auto i) { return ItemTable(i).GetItemType() == ITEMTYPE_DUNGEONREWARD; }); + AddElementsToPool(anyDungeonItems, rewards); + } else if (ShuffleRewards.Is(REWARDSHUFFLE_OVERWORLD)) { + auto rewards = FilterAndEraseFromPool( + ItemPool, [](const auto i) { return ItemTable(i).GetItemType() == ITEMTYPE_DUNGEONREWARD; }); + AddElementsToPool(overworldItems, rewards); + } + + //Randomize Any Dungeon and Overworld pools + AssumedFill(anyDungeonItems, anyDungeonLocations, true); + AssumedFill(overworldItems, overworldLocations, true); + + //Randomize maps and compasses after since they're not advancement items + for (auto dungeon : dungeonList) { + if (MapsAndCompasses.Is(MAPSANDCOMPASSES_ANY_DUNGEON)) { + auto mapAndCompassItems = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetMap() || i == dungeon->GetCompass();}); + AssumedFill(mapAndCompassItems, anyDungeonLocations, true); + } else if (MapsAndCompasses.Is(MAPSANDCOMPASSES_OVERWORLD)) { + auto mapAndCompassItems = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetMap() || i == dungeon->GetCompass();}); + AssumedFill(mapAndCompassItems, overworldLocations, true); + } + } +} + +static void RandomizeLinksPocket() { + if (LinksPocketItem.Is(LINKSPOCKETITEM_ADVANCEMENT)) { + //Get all the advancement items don't include tokens + std::vector advancementItems = FilterAndEraseFromPool(ItemPool, [](const auto i) { + return ItemTable(i).IsAdvancement() && ItemTable(i).GetItemType() != ITEMTYPE_TOKEN; + }); + //select a random one + uint32_t startingItem = RandomElement(advancementItems, true); + //add the others back + AddElementsToPool(ItemPool, advancementItems); + + PlaceItemInLocation(LINKS_POCKET, startingItem); + } else if (LinksPocketItem.Is(LINKSPOCKETITEM_NOTHING)) { + PlaceItemInLocation(LINKS_POCKET, GREEN_RUPEE); + } +} + +void VanillaFill() { + //Perform minimum needed initialization + AreaTable_Init(); + GenerateLocationPool(); + GenerateItemPool(); + GenerateStartingInventory(); + //Place vanilla item in each location + RandomizeDungeonRewards(); + for (uint32_t loc : allLocations) { + Location(loc)->PlaceVanillaItem(); + } + //If necessary, handle ER stuff + if (ShuffleEntrances) { + printf("\x1b[7;10HShuffling Entrances..."); + ShuffleAllEntrances(); + printf("\x1b[7;32HDone"); + } + //Finish up + CreateItemOverrides(); + CreateEntranceOverrides(); + CreateAlwaysIncludedMessages(); +} + +void ClearProgress() { + printf("\x1b[7;32H "); // Done + printf("\x1b[8;10H "); // Placing Items...Done + printf("\x1b[9;10H "); // Calculating Playthrough...Done + printf("\x1b[10;10H "); // Creating Hints...Done + printf("\x1b[11;10H "); // Writing Spoiler Log...Done +} + +int Fill() { + + int retries = 0; + while(retries < 5) { + placementFailure = false; + showItemProgress = false; + playthroughLocations.clear(); + playthroughEntrances.clear(); + wothLocations.clear(); + AreaTable_Init(); //Reset the world graph to intialize the proper locations + ItemReset(); //Reset shops incase of shopsanity random + GenerateLocationPool(); + GenerateItemPool(); + GenerateStartingInventory(); + RemoveStartingItemsFromPool(); + FillExcludedLocations(); + + //Temporarily add shop items to the ItemPool so that entrance randomization + //can validate the world using deku/hylian shields + AddElementsToPool(ItemPool, GetMinVanillaShopItems(32)); //assume worst case shopsanity 4 + if (ShuffleEntrances) { + printf("\x1b[7;10HShuffling Entrances"); + if (ShuffleAllEntrances() == ENTRANCE_SHUFFLE_FAILURE) { + retries++; + ClearProgress(); + continue; + } + printf("\x1b[7;32HDone"); + } + //erase temporary shop items + FilterAndEraseFromPool(ItemPool, [](const auto item) { return ItemTable(item).GetItemType() == ITEMTYPE_SHOP; }); + + showItemProgress = true; + //Place shop items first, since a buy shield is needed to place a dungeon reward on Gohma due to access + NonShopItems = {}; + if (Shopsanity.Is(SHOPSANITY_OFF)) { + PlaceVanillaShopItems(); //Place vanilla shop items in vanilla location + } else { + int total_replaced = 0; + if (Shopsanity.IsNot(SHOPSANITY_ZERO)) { //Shopsanity 1-4, random + //Initialize NonShopItems + ItemAndPrice init; + init.Name = Text{"No Item", "Sin objeto", "Pas d'objet"}; + init.Price = -1; + init.Repurchaseable = false; + NonShopItems.assign(32, init); + //Indices from OoTR. So shopsanity one will overwrite 7, three will overwrite 7, 5, 8, etc. + const std::array indices = {7, 5, 8, 6}; + //Overwrite appropriate number of shop items + for (size_t i = 0; i < ShopLocationLists.size(); i++) { + int num_to_replace = GetShopsanityReplaceAmount(); //1-4 shop items will be overwritten, depending on settings + total_replaced += num_to_replace; + for (int j = 0; j < num_to_replace; j++) { + int itemindex = indices[j]; + int shopsanityPrice = GetRandomShopPrice(); + NonShopItems[TransformShopIndex(i*8+itemindex-1)].Price = shopsanityPrice; //Set price to be retrieved by the patch and textboxes + Location(ShopLocationLists[i][itemindex - 1])->SetShopsanityPrice(shopsanityPrice); + } + } + } + //Get all locations and items that don't have a shopsanity price attached + std::vector shopLocations = {}; + //Get as many vanilla shop items as the total number of shop items minus the number of replaced items + //So shopsanity 0 will get all 64 vanilla items, shopsanity 4 will get 32, etc. + std::vector shopItems = GetMinVanillaShopItems(total_replaced); + + for (size_t i = 0; i < ShopLocationLists.size(); i++) { + for (size_t j = 0; j < ShopLocationLists[i].size(); j++) { + uint32_t loc = ShopLocationLists[i][j]; + if (!(Location(loc)->HasShopsanityPrice())) { + shopLocations.push_back(loc); + } + } + } + //Place the shop items which will still be at shop locations + AssumedFill(shopItems, shopLocations); + } + + //Place dungeon rewards + RandomizeDungeonRewards(); + + //Place dungeon items restricted to their Own Dungeon + for (auto dungeon : Dungeon::dungeonList) { + RandomizeOwnDungeon(dungeon); + } + + //Then Place songs if song shuffle is set to specific locations + if (ShuffleSongs.IsNot(SONGSHUFFLE_ANYWHERE)) { + + //Get each song + std::vector songs = + FilterAndEraseFromPool(ItemPool, [](const auto i) { return ItemTable(i).GetItemType() == ITEMTYPE_SONG; }); + + //Get each song location + std::vector songLocations; + if (ShuffleSongs.Is(SONGSHUFFLE_SONG_LOCATIONS)) { + songLocations = + FilterFromPool(allLocations, [](const auto loc) { return Location(loc)->IsCategory(Category::cSong); }); + + } else if (ShuffleSongs.Is(SONGSHUFFLE_DUNGEON_REWARDS)) { + songLocations = FilterFromPool( + allLocations, [](const auto loc) { return Location(loc)->IsCategory(Category::cSongDungeonReward); }); + } + + AssumedFill(songs, songLocations, true); + } + + //Then place dungeon items that are assigned to restrictive location pools + RandomizeDungeonItems(); + + //Then place Link's Pocket Item if it has to be an advancement item + RandomizeLinksPocket(); + //Then place the rest of the advancement items + std::vector remainingAdvancementItems = + FilterAndEraseFromPool(ItemPool, [](const auto i) { return ItemTable(i).IsAdvancement(); }); + AssumedFill(remainingAdvancementItems, allLocations, true); + + //Fast fill for the rest of the pool + std::vector remainingPool = FilterAndEraseFromPool(ItemPool, [](const auto i) { return true; }); + FastFill(remainingPool, GetAllEmptyLocations(), false); + GeneratePlaythrough(); + //Successful placement, produced beatable result + if(playthroughBeatable && !placementFailure) { + printf("Done"); + printf("\x1b[9;10HCalculating Playthrough..."); + PareDownPlaythrough(); + CalculateWotH(); + printf("Done"); + CreateItemOverrides(); + CreateEntranceOverrides(); + CreateAlwaysIncludedMessages(); + if (GossipStoneHints.IsNot(HINTS_NO_HINTS)) { + printf("\x1b[10;10HCreating Hints..."); + CreateAllHints(); + printf("Done"); + } + if (ShuffleMerchants.Is(SHUFFLEMERCHANTS_HINTS)) { + CreateMerchantsHints(); + } + return 1; + } + //Unsuccessful placement + if(retries < 4) { + SPDLOG_INFO("\nGOT STUCK. RETRYING...\n"); + Areas::ResetAllLocations(); + LogicReset(); + ClearProgress(); + } + retries++; + } + //All retries failed + return -1; +} diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.hpp b/soh/soh/Enhancements/randomizer/3drando/fill.hpp new file mode 100644 index 000000000..427668985 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/fill.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "keys.hpp" + +#include +#include + +enum class SearchMode { + ReachabilitySearch, + GeneratePlaythrough, + CheckBeatable, + AllLocationsReachable, + ValidateWorld, + TimePassAccess, + TempleOfTimeAccess, + ValidStartingRegion, + PoeCollectorAccess, +}; + +void ClearProgress(); +void VanillaFill(); +int Fill(); + +std::vector GetAccessibleLocations(const std::vector& allowedLocations, + SearchMode mode = SearchMode::ReachabilitySearch, std::string ignore = "", + bool checkPoeCollectorAccess = false, + bool checkOtherEntranceAccess = false); diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp new file mode 100644 index 000000000..19329675a --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp @@ -0,0 +1,2268 @@ +#include "hint_list.hpp" +#include "custom_messages.hpp" + +#include + +using namespace CustomMessages; + +//Big thanks to Lioncache, Gabyelnuevo, Danius88, and Charade for their translations! + +//Text is {english, french, spanish} + +// there are special characters that are read for certain in game commands: +// ^ is a box break +// & is a new line +// @ will print the player name +// surrounding text with '#' will make it a different color +// - OoT Randomizer + +// '%d' indicates a number will be placed there. + +std::array hintTable; + +void HintTable_Init() { + /*-------------------------- + | GENERAL TEXT | + ---------------------------*/ + hintTable[NONE] = HintText::Exclude({Text{"No Hint","Pas d'Indice",""}}); + hintTable[PREFIX] = HintText::Exclude({Text{"They say that ", /*french*/"Selon moi, ", /*spanish*/"Según dicen, "}}); + hintTable[WAY_OF_THE_HERO] = HintText::Exclude({Text{" is on the way of the hero.", /*french*/" est sur la voie du héros." , /*spanish*/" conduce a la senda del héroe."}}); + hintTable[PLUNDERING] = HintText::Exclude({Text{"plundering ", /*french*/"explorer ", /*spanish*/"inspeccionar "}}); + hintTable[FOOLISH] = HintText::Exclude({Text{" is a foolish choice.", /*french*/" est futile.", /*spanish*/" no es una sabia decisión."}}); + hintTable[CAN_BE_FOUND_AT] = HintText::Exclude({Text{"can be found at", /*french*/"se trouve dans", /*spanish*/"aguarda en"}}); + hintTable[HOARDS] = HintText::Exclude({Text{"hoards", /*french*/"recèle", /*spanish*/"acapara"}}); + + HintTable_Init_Item(); + HintTable_Init_Exclude_Overworld(); + HintTable_Init_Exclude_Dungeon(); + + /*-------------------------- + | ALWAYS HINT TEXT | + ---------------------------*/ + + hintTable[ZR_FROGS_OCARINA_GAME] = HintText::Always({ + //obscure text + Text{"an #amphibian feast# yields", /*french*/"un #festin d'amphibiens# donne", /*spanish*/"una #fiesta anfibia# brinda"}, + Text{"the #croaking choir's magnum opus# awards", /*french*/"la #chorale coassante# donne", /*spanish*/"un #coro maestro de ancas# premia"}, + Text{"the #froggy finale# yields", /*french*/"la #finale amphibienne# donne", /*spanish*/"el #gran final batracio# brinda"}, + }, {}, + //clear text + Text{"the final reward from the #Frogs of Zora's River# is", /*french*/"la dernière récompense des #grenouilles de la Rivière Zora# est", /*spanish*/"la recompensa final de las #ranas del Río Zora# premia"} + ); + + hintTable[KF_LINKS_HOUSE_COW] = HintText::Always({ + //obscure text + Text{"the #bovine bounty of a horseback hustle# gifts", /*french*/"le cadeau #qui découle d'une réussite équestre# est", /*spanish*/"la #recompensa bovina de un paseo a caballo# brinda"}, + }, {}, + //clear text + Text{"#Malon's obstacle course# leads to", /*french*/"la #course à obstacle de Malon# amène à", /*spanish*/"la #carrera de obstáculos de Malon# brinda"} + ); + + /*-------------------------- + | SOMETIMES HINT TEXT | + ---------------------------*/ + + hintTable[SONG_FROM_OCARINA_OF_TIME] = HintText::Sometimes({ + //obscure text + Text{"the #Ocarina of Time# teaches", /*french*/"l'#Ocarina du Temps# est accompagné par", /*spanish*/"la #Ocarina del Tiempo# enseña"}, + }); + + hintTable[SONG_FROM_COMPOSERS_GRAVE] = HintText::Sometimes({ + //obscure text + Text{"#ReDead in the Composers' Grave# guard", /*french*/"les #Éffrois du tombeau des compositeurs# protègent", /*spanish*/"los #ReDeads del Panteón Real# guardan"}, + Text{"the #Composer Brothers wrote#", /*french*/"le #trésor des compositeurs# est", /*spanish*/"los #hermanos compositores escribieron#"}, + }); + + hintTable[SHEIK_IN_FOREST] = HintText::Sometimes({ + //obscure text + Text{"#in a meadow# Sheik teaches", /*french*/"Sheik confiera, #dans un bosquet#,", /*spanish*/"#en la pradera sagrada# Sheik enseña"}, + }); + + hintTable[SHEIK_AT_TEMPLE] = HintText::Sometimes({ + //obscure text + Text{"Sheik waits at a #monument to time# to teach", /*french*/"Sheik confiera, #au pied de l'épée légendaire#,", /*spanish*/"Sheik espera en el #momumento del tiempo# para enseñar"}, + }); + + hintTable[SHEIK_IN_CRATER] = HintText::Sometimes({ + //obscure text + Text{"the #crater's melody# is", /*french*/"Sheik confiera, #entouré de lave#,", /*spanish*/"la #melodía del cráter# otorga"}, + }); + + hintTable[SHEIK_IN_ICE_CAVERN] = HintText::Sometimes({ + //obscure text + Text{"the #frozen cavern# echoes with", /*french*/"Sheik confiera, #dans une caverne enneigée#,", /*spanish*/"en la #caverna de hielo# retumban los ecos de"}, + }); + + hintTable[SHEIK_IN_KAKARIKO] = HintText::Sometimes({ + //obscure text + Text{"a #ravaged village# mourns with", /*french*/"Sheik confirera, #au coeur d'un village ravagé#,", /*spanish*/"un #arrasado pueblo# llora"}, + }); + + hintTable[SHEIK_AT_COLOSSUS] = HintText::Sometimes({ + //obscure text + Text{"a hero ventures #beyond the wasteland# to learn", /*french*/"Sheik confiera, #au bout d'un chemin sableux#,", /*spanish*/"el héroe que se adentre #más allá del desierto# aprenderá"}, + }); + + + hintTable[MARKET_10_BIG_POES] = HintText::Sometimes({ + //obscure text + Text{"#ghost hunters# will be rewarded with", /*french*/"#les chasseurs de fantômes# sont récompensés avec", /*spanish*/"los #cazafantasmas# son premiados con"}, + }, {}, + //clear text + Text{"catching #Big Poes# leads to", /*french*/"#d'attraper des Àmes# donne", /*spanish*/"hacerte con #Grandes Poes# conduce a"} + ); + + hintTable[DEKU_THEATER_SKULL_MASK] = HintText::Sometimes({ + //obscure text + Text{"the #Skull Mask# yields", /*french*/"le #Masque de Mort# donne", /*spanish*/"la #máscara de calavera# otorga"}, + }); + + hintTable[DEKU_THEATER_MASK_OF_TRUTH] = HintText::Sometimes({ + //obscure text + Text{"showing a #truthful eye to the crowd# rewards", /*french*/"montrer #l'oeil de vérité à la foule# donne", /*spanish*/"#mostrarle el ojo verdadero# a una multitud brinda"}, + }, {}, + //clear text + Text{"the #Mask of Truth# yields", /*french*/"le #Masque de Vérité# donne", /*spanish*/"la #máscara de la verdad# premia"} + ); + + hintTable[HF_OCARINA_OF_TIME_ITEM] = HintText::Sometimes({ + //obscure text + Text{"the #treasure thrown by Princess Zelda# is", /*french*/"le trésor #laissé par la princesse# est", /*spanish*/"el #tesoro arrojado por la Princesa Zelda# se trata de"}, + }); + + hintTable[DMT_TRADE_BROKEN_SWORD] = HintText::Sometimes({ + //obscure text + Text{"a #blinded Biggoron# entrusts", /*french*/"un #Grogoron aveuglé# confie", /*spanish*/"un #miope Biggoron# otorga"}, + }); + + hintTable[DMT_TRADE_EYEDROPS] = HintText::Sometimes({ + //obscure text + Text{"while you wait, #Biggoron# gives", /*french*/"pendant que tu attends, #Biggoron# donne", /*spanish*/"#Biggoron# está a la espera de otorgar"}, + }); + + hintTable[DMT_TRADE_CLAIM_CHECK] = HintText::Sometimes({ + //obscure text + Text{"#Biggoron# crafts", /*french*/"#Biggoron# fabrique", /*spanish*/"#Biggoron# forja"}, + }); + + hintTable[KAK_50_GOLD_SKULLTULA_REWARD] = HintText::Sometimes({ + //obscure text + Text{"#50 bug badges# rewards", /*french*/"#50 écussons# donnent", /*spanish*/"#50 medallas de insectos# otorgan"}, + Text{"#50 spider souls# yields", /*french*/"#50 âmes d'arachnide# donnent", /*spanish*/"#50 almas de araña# otorgan"}, + Text{"#50 auriferous arachnids# lead to", /*french*/"#50 arachnides aurifères# donnent", /*spanish*/"#50 arácnidos auríferos# otorgan"}, + }, {}, + //clear text + Text{"slaying #50 Gold Skulltulas# reveals", /*french*/"détruire #50 Skulltulas d'or# donne", /*spanish*/"exterminar #50 skulltulas doradas# revela"} + ); + + hintTable[KAK_40_GOLD_SKULLTULA_REWARD] = HintText::Sometimes({ + //obscure text + Text{"#40 bug badges# rewards", /*french*/"#40 écussons# donnent", /*spanish*/"#40 medallas de insectos# otorgan"}, + Text{"#40 spider souls# yields", /*french*/"#40 âmes d'arachnide# donnent", /*spanish*/"#40 almas de araña# otorgan"}, + Text{"#40 auriferous arachnids# lead to", /*french*/"#40 arachnides aurifères# donnent", /*spanish*/"#40 arácnidos auríferos# otorgan"}, + }, {}, + //clear text + Text{"slaying #40 Gold Skulltulas# reveals", /*french*/"détruire #40 Skulltulas d'or# donne", /*spanish*/"exterminar #40 skulltulas doradas# revela"} + ); + + hintTable[KAK_30_GOLD_SKULLTULA_REWARD] = HintText::Sometimes({ + //obscure text + Text{"#30 bug badges# rewards", /*french*/"#30 écussons# donnent", /*spanish*/"#30 medallas de insectos# otorgan"}, + Text{"#30 spider souls# yields", /*french*/"#30 âmes d'arachnide# donnent", /*spanish*/"#30 almas de araña# otorgan"}, + Text{"#30 auriferous arachnids# lead to", /*french*/"#30 arachnides aurifères# donnent", /*spanish*/"#30 arácnidos auríferos# otorgan"}, + }, {}, + //clear text + Text{"slaying #30 Gold Skulltulas# reveals", /*french*/"détruire #30 Skulltulas d'or# donne", /*spanish*/"exterminar #30 skulltulas doradas# revela"} + ); + + hintTable[KAK_20_GOLD_SKULLTULA_REWARD] = HintText::Sometimes({ + //obscure text + Text{"#20 bug badges# rewards", /*french*/"#20 écussons# donnent", /*spanish*/"#20 medallas de insectos# otorgan"}, + Text{"#20 spider souls# yields", /*french*/"#20 âmes d'arachnide# donnent", /*spanish*/"#20 almas de araña# otorgan"}, + Text{"#20 auriferous arachnids# lead to", /*french*/"#20 arachnides aurifères# donnent", /*spanish*/"#20 arácnidos auríferos# otorgan"}, + }, {}, + //clear text + Text{"slaying #20 Gold Skulltulas# reveals", /*french*/"détruire #20 Skulltulas d'or# donne", /*spanish*/"exterminar #20 skulltulas doradas# revela"} + ); + + hintTable[KAK_ANJU_AS_CHILD] = HintText::Sometimes({ + //obscure text + Text{"#wrangling roosters# rewards", /*french*/"#plumer des poulets# donne", /*spanish*/"#atrapar a las gallinas# premia"}, + Text{"#chucking chickens# gifts", /*french*/"#lancer des poulets# donne", /*spanish*/"#reunir a unos emplumados# premia"}, + }, {}, + //clear text + Text{"#collecting cuccos# rewards", /*french*/"#rapporter les Cocottes# donne", /*spanish*/"#hacerte con todos los cucos# premia"} + ); + + hintTable[KAK_TRADE_POCKET_CUCCO] = HintText::Sometimes({ + //obscure text + Text{"an adult's #happy Cucco# awards", /*french*/"un adulte avec une #poulette joyeuse# obtient", /*spanish*/"un #alegre cuco# en la madurez otorga"}, + }); + + hintTable[KAK_TRADE_ODD_MUSHROOM] = HintText::Sometimes({ + //obscure text + Text{"the #potion shop lady# entrusts", /*french*/"la #gribiche du magasin de potion# confie", /*spanish*/"la #señora de la tienda de pociones# otorga"}, + }); + + hintTable[GC_DARUNIAS_JOY] = HintText::Sometimes({ + //obscure text + Text{"a #groovin' goron# gifts", /*french*/"#le Goron joyeux# donne", /*spanish*/"#un goron marchoso# otorga"}, + }, {}, + //clear text + Text{"#Darunia's dance# leads to", /*french*/"#la dance de Darunia# donne", /*spanish*/"#el baile de Darunia# conduce a"} + ); + + hintTable[LW_SKULL_KID] = HintText::Sometimes({ + //obscure text + Text{"the #Skull Kid# grants", /*french*/"le #Skull Kid# donne", /*spanish*/"#Skull Kid# otorga"}, + }); + + hintTable[LW_TRADE_COJIRO] = HintText::Sometimes({ + //obscure text + Text{"returning a #special Cucco# awards", /*french*/"ramener une #poulette précieuse# donne", /*spanish*/"quien devuelva un #cuco especial# encontrará"}, + }); + + hintTable[LW_TRADE_ODD_POTION] = HintText::Sometimes({ + //obscure text + Text{"a #Kokiri girl in the woods# leaves", /*french*/"la #fillette Kokiri dans les bois# laisse", /*spanish*/"una #chica kokiri del bosque# otorga"}, + }); + + hintTable[LH_SUN] = HintText::Sometimes({ + //obscure text + Text{"staring into #the sun# grants", /*french*/"regarder #le soleil# donne", /*spanish*/"#mirar al sol# revela"}, + }, {}, + //clear text + Text{"shooting #the sun# grants", /*french*/"tirer une flèche dans #sur le soleil# donne", /*spanish*/"#disparar al sol# revela"} + ); + + hintTable[LH_TRADE_FROG] = HintText::Sometimes({ + //obscure text + Text{"#Lake Hylia's scientist# hurriedly entrusts", /*french*/"le #scientifique du lac# confie rapidement", /*spanish*/"el #científico del Lago Hylia# otorga con prisa"}, + }); + + hintTable[MARKET_TREASURE_CHEST_GAME_REWARD] = HintText::Sometimes({ + //obscure text + Text{"#gambling# grants", /*french*/"#parier# donne", /*spanish*/"#los juegos de azar# revelan"}, + Text{"there is a #1/32 chance# to win", /*french*/"être #le gagnant parmi 32# donne", /*spanish*/"hay una #probabilidad de 1/32# de ganar"}, + }, {}, + //clear text + Text{"the #treasure chest game# grants", /*french*/"la #Chasse-aux-Trésors# donne", /*spanish*/"#el Cofre del Tesoro# premia"} + ); + + hintTable[MARKET_TREASURE_CHEST_GAME_ITEM_1] = HintText::Sometimes({ + //obscure text + Text{"#gambling once# grants", /*french*/"#parier une fois# donne", /*spanish*/"#apostar solo una vez# revelará"}, + Text{"the #first or second game chest# contains", /*french*/"le #premier ou deuxième coffre à jeu# contient", /*spanish*/"#el primer o segundo cofre del azar# revela"}, + }, {}, + //clear text + Text{"the #first locked room# in the chest game contains", /*french*/"la #première salle# de la Chasse-aux-Trésors contient", /*spanish*/"#en la primera sala del Cofre del Tesoro# aguarda"} + ); + + hintTable[MARKET_TREASURE_CHEST_GAME_ITEM_2] = HintText::Sometimes({ + //obscure text + Text{"#gambling twice# grants", /*french*/"#parier deux fois# donne", /*spanish*/"#apostar dos veces# revelará"}, + Text{"the #third or fourth game chest# contains", /*french*/"le #troisième ou quatrième coffre à jeu# contient", /*spanish*/"#el tercer o cuarto cofre del azar# revela"}, + }, {}, + //clear text + Text{"the #second locked room# in the chest game contains", /*french*/"la #deuxième salle# de la Chasse-aux-Trésors contient", /*spanish*/"#en la segunda sala del Cofre del Tesoro# aguarda"} + ); + + hintTable[MARKET_TREASURE_CHEST_GAME_ITEM_3] = HintText::Sometimes({ + //obscure text + Text{"#gambling 3 times# grants", /*french*/"#parier trois fois# donne", /*spanish*/"#apostar tres veces# revelará"}, + Text{"the #fifth or sixth game chest# contains", /*french*/"le #cinquième ou sixième coffre à jeu# contient", /*spanish*/"#el quinto o sexto cofre del azar# revela"}, + }, {}, + //clear text + Text{"the #third locked room# in the chest game contains", /*french*/"la #troisième salle# de la Chasse-aux-Trésors contient", /*spanish*/"#en la tercera sala del Cofre del Tesoro# aguarda"} + ); + + hintTable[MARKET_TREASURE_CHEST_GAME_ITEM_4] = HintText::Sometimes({ + //obscure text + Text{"#gambling 4 times# grants", /*french*/"#parier quatre fois# donne", /*spanish*/"#apostar cuatro veces# revelará"}, + Text{"the #seventh or eighth game chest# contains", /*french*/"le #septième ou huitième coffre à jeu# contient", /*spanish*/"#el séptimo u octavo cofre del azar# revela"}, + }, {}, + //clear text + Text{"the #fourth locked room# in the chest game contains", /*french*/"la #quatrième salle# de la Chasse-aux-Trésors contient", /*spanish*/"#en la cuarta sala del Cofre del Tesoro# aguarda"} + ); + + hintTable[MARKET_TREASURE_CHEST_GAME_ITEM_5] = HintText::Sometimes({ + //obscure text + Text{"#gambling 5 times# grants", /*french*/"#parier cinq fois# donne", /*spanish*/"#apostar cinco veces# revelará"}, + Text{"the #ninth or tenth game chest# contains", /*french*/"le #neuvième ou dixième coffre à jeu# contient", /*spanish*/"#el noveno o décimo cofre del azar# revela"}, + }, {}, + //clear text + Text{"the #fifth locked room# in the chest game contains", /*french*/"la #cinquième salle# de la Chasse-aux-Trésors contient", /*spanish*/"#en la quinta sala del Cofre del Tesoro# aguarda"} + ); + + hintTable[GF_HBA_1500_POINTS] = HintText::Sometimes({ + //obscure text + Text{"mastery of #horseback archery# grants", /*french*/"maîtriser l'#archerie équestre# donne", /*spanish*/"dominar el #tiro con arco a caballo# premia con"}, + }, {}, + //clear text + Text{"scoring 1500 in #horseback archery# grants", /*french*/"obtenir 1500 points dans l'#archerie équestre# donne", /*spanish*/"conseguir 1500 puntos en el #tiro con arco a caballo# premia"} + ); + + hintTable[GRAVEYARD_HEART_PIECE_GRAVE_CHEST] = HintText::Sometimes({ + //obscure text + Text{"playing #Sun's Song# in a grave spawns", /*french*/"jouer le #chant du soleil# dans un tombeau donne", /*spanish*/"#tocar la Canción del Sol# en una cripta conduce a"}, + }); + + hintTable[GC_MAZE_LEFT_CHEST] = HintText::Sometimes({ + //obscure text + Text{"in #Goron City# the hammer unlocks", /*french*/"dans le #village Goron#, le marteau donne accès à", /*spanish*/"en la #Ciudad Goron# el martillo desbloquea"}, + }); + + hintTable[GV_CHEST] = HintText::Sometimes({ + //obscure text + Text{"in #Gerudo Valley# the hammer unlocks", /*french*/"dans la #Vallée Gerudo#, le marteau donne accès à", /*spanish*/"en el #Valle Gerudo# el martillo desbloquea"}, + }); + + hintTable[GV_TRADE_SAW] = HintText::Sometimes({ + //obscure text + Text{"the #boss of the carpenters# leaves", /*french*/"le #patron des ouvriers# laisse", /*spanish*/"el #capataz de los carpinteros# otorga"}, + }); + + hintTable[GV_COW] = HintText::Sometimes({ + //obscure text + Text{"a #cow in Gerudo Valley# gifts", /*french*/"la #vache de la Vallée Gerudo# donne", /*spanish*/"una #vaca del Valle Gerudo# brinda"}, + }); + + hintTable[HC_GS_STORMS_GROTTO] = HintText::Sometimes({ + //obscure text + Text{"a #spider behind a muddy wall# in a grotto holds", /*french*/"l'#araignée derrière un mur de boue# dans une grotte donne", /*spanish*/"una #Skulltula tras la agrietada pared# de una cueva otorga"}, + }); + + hintTable[HF_GS_COW_GROTTO] = HintText::Sometimes({ + //obscure text + Text{"a #spider behind webs# in a grotto holds", /*french*/"l'#araignée derrière une toile# dans une grotte donne", /*spanish*/"una #Skulltula tras la telaraña# de una cueva otorga"}, + }); + + hintTable[HF_COW_GROTTO_COW] = HintText::Sometimes({ + //obscure text + Text{"the #cobwebbed cow# gifts", /*french*/"la #vache prisonnière d'araignées# donne", /*spanish*/"una #vaca tras una telaraña# brinda"}, + }, {}, + //clear text + Text{"a #cow behind webs# in a grotto gifts", /*french*/"la #vache derrière les toiles# d'une grotte donne", /*spanish*/"una #vaca tras la telaraña# de una cueva brinda"} + ); + + hintTable[ZF_GS_HIDDEN_CAVE] = HintText::Sometimes({ + //obscure text + Text{"a spider high #above the icy waters# holds", /*french*/"l'araignée #en haut des eaux glacées# donne", /*spanish*/"una Skulltula en lo #alto de las congeladas aguas# otorga"}, + }); + + hintTable[WASTELAND_CHEST] = HintText::Sometimes({ + //obscure text + Text{"#deep in the wasteland# is", /*french*/"#loin dans le désert# gît", /*spanish*/"en lo #profundo del desierto encantado# yace"}, + Text{"beneath #the sands#, flames reveal", /*french*/"#sous le désert#, les flammes font apparaître", /*spanish*/"tras las #arenas# unas llamas revelan"}, + }); + + hintTable[WASTELAND_GS] = HintText::Sometimes({ + //obscure text + Text{"a #spider in the wasteland# holds", /*french*/"#l'araignée dans le désert# donne", /*spanish*/"una #Skulltula del desierto encantado# otorga"}, + }); + + hintTable[GRAVEYARD_COMPOSERS_GRAVE_CHEST] = HintText::Sometimes({ + //obscure text + Text{"#flames in the Composers' Grave# reveal", /*french*/"#les flammes dans le tombeau des compositeurs# cachent", /*spanish*/"#las llamas del Panteón Real# revelan"}, + Text{"the #Composer Brothers hid#", /*french*/"#les Frères compositeurs on caché#", /*spanish*/"los #hermanos compositores esconden#"}, + }); + + hintTable[ZF_BOTTOM_FREESTANDING_POH] = HintText::Sometimes({ + //obscure text + Text{"#under the icy waters# lies", /*french*/"#sous les eaux glacées# se cache", /*spanish*/"#bajo las congeladas aguas# yace"}, + }); + + hintTable[GC_POT_FREESTANDING_POH] = HintText::Sometimes({ + //obscure text + Text{"spinning #Goron pottery# contains", /*french*/"la #potterie Goron# contient", /*spanish*/"una #cerámica goron# contiene"}, + }); + + hintTable[ZD_KING_ZORA_THAWED] = HintText::Sometimes({ + //obscure text + Text{"a #defrosted dignitary# gifts", /*french*/"le #monarque libéré# donne", /*spanish*/"una #liberación monárquica# brinda"}, + }, {}, + //clear text + Text{"unfreezing #King Zora# grants", /*french*/"dégeler # le Roi Zora# donne", /*spanish*/"#descongelar al Rey Zora# conduce a"} + ); + + hintTable[ZD_TRADE_PRESCRIPTION] = HintText::Sometimes({ + //obscure text + Text{"#King Zora# hurriedly entrusts", /*french*/"le #roi Zora# confie rapidement", /*spanish*/"el #Rey Zora# otorga con prisa"}, + }); + + hintTable[DMC_DEKU_SCRUB] = HintText::Sometimes({ + //obscure text + Text{"a single #scrub in the crater# sells", /*french*/"la #peste Mojo dans le cratère# vend", /*spanish*/"un solitario #deku del cráter# vende"}, + }); + + hintTable[DMC_GS_CRATE] = HintText::Sometimes({ + //obscure text + Text{"a spider under a #crate in the crater# holds", /*french*/"la Skulltula dans une #boîte volcanique# a", /*spanish*/"una Skulltula bajo una #caja del cráter# otorga"}, + }); + + + hintTable[DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST] = HintText::Sometimes({ + //obscure text + Text{"a #temporal stone within a tree# contains", /*french*/"la #pierre bleue dans un arbre# mène à", /*spanish*/"un #bloque temporal de un árbol# contiene"}, + }, {}, + //clear text + Text{"a #temporal stone within the Deku Tree# contains", /*french*/"la #pierre temporelle dans l'Arbre Mojo# cache", /*spanish*/"un #bloque temporal del Gran Árbol Deku# contiene"} + ); + + hintTable[DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM] = HintText::Sometimes({ + //obscure text + Text{"a #spider on a ceiling in a tree# holds", /*french*/"l'#araignée haut-perchée dans un arbre# a", /*spanish*/"una #Skulltula en el techo de un árbol# otorga"}, + }, {}, + //clear text + Text{"a #spider on a ceiling in the Deku Tree# holds", /*french*/"la#Skulltula dans le Cimetière de l'Arbre Mojo# a", /*spanish*/"una #Skulltula en el techo del Gran Árbol Deku# otorga"} + ); + + hintTable[DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM] = HintText::Sometimes({ + //obscure text + Text{"a spider under #temporal stones in a cavern# holds", /*french*/"l'araignée sous #une pierre bleue dans une caverne# a", /*spanish*/"una Skulltula bajo #bloques temporales de una cueva# otorga"}, + }, {}, + //clear text + Text{"a spider under #temporal stones in Dodongo's Cavern# holds", /*french*/"la Skulltula sous #la pierre temporelle dans la Caverne Dodongo# a", /*spanish*/"una Skulltula bajo #bloques temporales de la Cueva de los Dodongos# otorga"} + ); + + hintTable[JABU_JABUS_BELLY_BOOMERANG_CHEST] = HintText::Sometimes({ + //obscure text + Text{"a school of #stingers swallowed by a deity# guard", /*french*/"les #raies dans un gardien# protègent", /*spanish*/"unos de #stingers engullidos por cierta deidad# guardan"}, + }, {}, + //clear text + Text{"a school of #stingers swallowed by Jabu-Jabu# guard", /*french*/"les #raies dans Jabu-Jabu# protègent", /*spanish*/"unos #stingers engullidos por Jabu-Jabu# guardan"} + ); + + hintTable[JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM] = HintText::Sometimes({ + //obscure text + Text{"a spider surrounded by #shadows in the belly of a deity# holds", /*french*/"l'araignée entourée d'#ombres dans le ventre du gardien# possède", /*spanish*/"una Skulltula rodeada de #sombras en la tripa de cierta diedad# otorga"}, + }, {}, + //clear text + Text{"a spider surrounded by #shadows in Jabu-Jabu's Belly# holds", /*french*/"la Skulltula entourée d'#ombres dans Jabu-Jabu# possède", /*spanish*/"una Skulltula rodeada de #sombras en la Tripa de Jabu-Jabu# otorga"} + ); + + hintTable[JABU_JABUS_BELLY_MQ_COW] = HintText::Sometimes({ + //obscure text + Text{"a #cow swallowed by a deity# gifts", /*french*/"la #vache dans le gardien# donne", /*spanish*/"una #vaca engullida por cierta deidad# brinda"}, + }, {}, + //clear text + Text{"a #cow swallowed by Jabu-Jabu# gifts", /*french*/"la #vache avallée par Jabu-Jabu# donne", /*spanish*/"una #vaca engullida por Jabu-Jabu# brinda"} + ); + + hintTable[FIRE_TEMPLE_SCARECROW_CHEST] = HintText::Sometimes({ + //obscure text + Text{"a #scarecrow atop the volcano# hides", /*french*/"l'#épouvantail au sommet d'un volcan# donne", /*spanish*/"un #espantapájaros en lo alto del volcán# esconde"}, + }, {}, + //clear text + Text{"#Pierre atop the Fire Temple# hides", /*french*/"#Pierre au sommet du Temple du Feu# donne", /*spanish*/"#Pierre en lo alto del Templo del Fuego# esconde"} + ); + + hintTable[FIRE_TEMPLE_MEGATON_HAMMER_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the #Flare Dancer atop the volcano# guards a chest containing", /*french*/"le #danseur au sommet du volcan# protège", /*spanish*/"el #Bailafuego en lo alto del volcán# otorga"}, + }, {}, + //clear text + Text{"the #Flare Dancer atop the Fire Temple# guards a chest containing", /*french*/"le #Danse-Flamme au sommet du Temple du Feu# protège", /*spanish*/"el #Bailaguego en lo alto del Templo del Fuego# otorga"} + ); + + hintTable[FIRE_TEMPLE_MQ_CHEST_ON_FIRE] = HintText::Sometimes({ + //obscure text + Text{"the #Flare Dancer atop the volcano# guards a chest containing", /*french*/"le #danseur au sommet du volcan# protège", /*spanish*/"el #Bailafuego en lo alto del volcán# otorga"}, + }, {}, + //clear text + Text{"the #Flare Dancer atop the Fire Temple# guards a chest containing", /*french*/"le #Danse-Flamme au sommet du Temple du Feu# protège", /*spanish*/"el #Bailafuego en lo alto del Templo del Fuego# otorga"} + ); + + hintTable[FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE] = HintText::Sometimes({ + //obscure text + Text{"a #spider under a block in the volcano# holds", /*french*/"l'#araignée sous un bloc dans le volcan# a", /*spanish*/"una #Skulltula bajo el bloque de un volcán# otorga"}, + }, {}, + //clear text + Text{"a #spider under a block in the Fire Temple# holds", /*french*/"une #Skulltula sous un bloc dans le Temple du Feu# a", /*spanish*/"una #Skulltula bajo un bloque del Templo del Fuego# otorga"} + ); + + hintTable[WATER_TEMPLE_RIVER_CHEST] = HintText::Sometimes({ + //obscure text + Text{"beyond the #river under the lake# waits", /*french*/"au delà de #la rivière sous le lac# se cache", /*spanish*/"tras el #río bajo el lago# yace"}, + }, {}, + //clear text + Text{"beyond the #river in the Water Temple# waits", /*french*/"au delà de #la rivière dans le Temple de l'Eau# se cache", /*spanish*/"tras el #río del Templo del Agua# yace"} + ); + + hintTable[WATER_TEMPLE_BOSS_KEY_CHEST] = HintText::Sometimes({ + //obscure text + Text{"dodging #rolling boulders under the lake# leads to", /*french*/"éviter des #rochers roulants sous le lac# mène à", /*spanish*/"esquivar #rocas rodantes bajo el lago# conduce a"}, + }, {}, + //clear text + Text{"dodging #rolling boulders in the Water Temple# leads to", /*french*/"éviter des #rochers roulants dans le Temple de l'Eau# mène à", /*spanish*/"esquivar #rocas rondantes del Templo del Agua# conduce a"} + ); + + hintTable[WATER_TEMPLE_GS_BEHIND_GATE] = HintText::Sometimes({ + //obscure text + Text{"a spider behind a #gate under the lake# holds", /*french*/"l'araignée derrière une #barrière sous le lac# a", /*spanish*/"una Skulltula tras #una valla bajo el lago# otorga"}, + }, {}, + //clear text + Text{"a spider behind a #gate in the Water Temple# holds", /*french*/"la Skulltula derrière une #barrière dans le Temple de l'Eau# a", /*spanish*/"una Skulltula tras #una valla del Templo del Agua# otorga"} + ); + + hintTable[WATER_TEMPLE_MQ_FREESTANDING_KEY] = HintText::Sometimes({ + //obscure text + Text{"hidden in a #box under the lake# lies", /*french*/"dans une #boîte sous le lac# gît", /*spanish*/"en una #caja bajo el lago# yace"}, + }, {}, + //clear text + Text{"hidden in a #box in the Water Temple# lies", /*french*/"dans une #boîte dans le Temple de l'Eau# gît", /*spanish*/"en una #caja del Templo del Agua# yace"} + ); + + hintTable[WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA] = HintText::Sometimes({ + //obscure text + Text{"the #locked spider under the lake# holds", /*french*/"l'#araignée emprisonnée sous le lac# a", /*spanish*/"la #Skulltula enjaulada bajo el lago# otorga"}, + }, {}, + //clear text + Text{"the #locked spider in the Water Temple# holds", /*french*/"une #Skulltula emprisonnée dans le Temple de l'Eau# a", /*spanish*/"la #Skulltula enjaulada del Templo del Agua# otorga"} + ); + + hintTable[WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH] = HintText::Sometimes({ + //obscure text + Text{"a spider behind a #gate under the lake# holds", /*french*/"l'#araignée derrière une barrière sous le lac# a", /*spanish*/"una Skulltula tras una #valla bajo el lago# otorga"}, + }, {}, + //clear text + Text{"a spider behind a #gate in the Water Temple# holds", /*french*/"une #Skulltula derrière une barrière dans le Temple de l'Eau# a", /*spanish*/"una Skulltula tras una #valla del Templo del Agua#"} + ); + + hintTable[GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST] = HintText::Sometimes({ + //obscure text + Text{"those who seek #sunken silver rupees# will find", /*french*/"ceux qui pêchent les #joyaux argentés# trouveront", /*spanish*/"aquellos que busquen las #rupias plateadas sumergidas# encontrarán"}, + Text{"the #thieves' underwater training# rewards", /*french*/"l'#épreuve de plongée des voleurs# recèle", /*spanish*/"la #instrucción submarina de las bandidas# premia"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST] = HintText::Sometimes({ + //obscure text + Text{"those who seek #sunken silver rupees# will find", /*french*/"ceux qui pêchent les #joyaux argentés# trouveront", /*spanish*/"aquellos que busquen las #rupias plateadas sumergidas# encontrarán"}, + Text{"the #thieves' underwater training# rewards", /*french*/"l'#épreuve de plongée des voleurs# recèle", /*spanish*/"la #instrucción submarina de las bandidas# premia"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the final prize of #the thieves' training# is", /*french*/"la récompense ultime de #l'épreuve des voleurs# est", /*spanish*/"la recompensa final de la #instrucción de las bandida# brinda"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the final prize of #the thieves' training# is", /*french*/"la récompense ultime de #l'épreuve des voleurs# est", /*spanish*/"el premio final de la #instrucción de las bandidas# brinda"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the well's #grasping ghoul# hides", /*french*/"la #terreur du Puits# cache", /*spanish*/"en las #profundidades del pozo# se esconde"}, + Text{"a #nether dweller in the well# holds", /*french*/"le #spectre qui réside dans le Puits# a", /*spanish*/"el #temido morador del pozo# concede"}, + }, {}, + //clear text + Text{"#Dead Hand in the well# holds", /*french*/"le #Poigneur dans le Puits# cache", /*spanish*/"la #Mano Muerta del pozo# concede"} + ); + + hintTable[BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the well's #grasping ghoul# hides", /*french*/"la #terreur du Puits# cache", /*spanish*/"en las #profundidades del pozo# se esconde"}, + Text{"a #nether dweller in the well# holds", /*french*/"le #spectre qui réside dans le Puits# a", /*spanish*/"el #temido morador del pozo# concede"}, + }, {}, + //clear text + Text{"#Dead Hand in the well# holds", /*french*/"le #Poigneur dans le Puits# cache", /*spanish*/"la #Mano Muerta del pozo# concede"} + ); + + hintTable[SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the treasure #sought by Nabooru# is", /*french*/"le trésor que #recherche Nabooru# est", /*spanish*/"el #ansiado tesoro de Nabooru# brinda"}, + }, {}, + //clear text + Text{"upon the #Colossus's right hand# is", /*french*/"sur la #main droite du colosse# repose", /*spanish*/"en la #mano derecha del Coloso# yace"} + ); + + hintTable[SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST] = HintText::Sometimes({ + //obscure text + Text{"upon the #Colossus's left hand# is", /*french*/"sur la #main gauche du colosse# repose", /*spanish*/"en la #mano izquierda del Coloso# yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST] = HintText::Sometimes({ + //obscure text + Text{"a #temporal paradox in the Colossus# yields", /*french*/"un #paradoxe temporel dans le colosse# révèle", /*spanish*/"una #paradoja temporal del Coloso# conduce a"}, + }, {}, + //clear text + Text{"a #temporal paradox in the Spirit Temple# yields", /*french*/"le #paradoxe temporel dans le Temple de l'Esprit# révèle", /*spanish*/"una #paradoja temporal del Coloso# conduce a"} + ); + + hintTable[SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST] = HintText::Sometimes({ + //obscure text + Text{"a #symphony in the Colossus# yields", /*french*/"la #symphonie du colosse# révèle", /*spanish*/"una #sinfonía del Coloso# conduce a"}, + }, {}, + //clear text + Text{"a #symphony in the Spirit Temple# yields", /*french*/"les #cinq chansons du Temple de l'Esprit# révèlent", /*spanish*/"una #sinfonía del Coloso# conduce a"} + ); + + hintTable[SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM] = HintText::Sometimes({ + //obscure text + Text{"a #spider's symphony in the Colossus# yields", /*french*/"la #mélodie de l'araignée du colosse# révèle", /*spanish*/"la #Skulltula de la sinfonía del Coloso# otorga"}, + }, {}, + //clear text + Text{"a #spider's symphony in the Spirit Temple# yields", /*french*/"la #mélodie de la Skulltula du Temple de l'Esprit# révèle", /*spanish*/"la #Skulltula de la sinfonía del Coloso# otorga"} + ); + + hintTable[SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST] = HintText::Sometimes({ + //obscure text + Text{"shadows in an #invisible maze# guard", /*french*/"les ombres dans le #labyrinthe invisible# protègent", /*spanish*/"las sombras del #laberinto misterioso# esconden"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST] = HintText::Sometimes({ + //obscure text + Text{"shadows in an #invisible maze# guard", /*french*/"les ombres dans le #labyrinthe invisible# protègent", /*spanish*/"las sombras del #laberinto invisible# esconden"}, + }); + + /*-------------------------- + | ENTRANCE HINT TEXT | + ---------------------------*/ + + hintTable[DESERT_COLOSSUS_TO_COLOSSUS_GROTTO] = HintText::Entrance({ + //obscure text + Text{"lifting a #rock in the desert# reveals", /*french*/"soulever une #roche dans le désert# révèle", /*spanish*/"levantar una #roca del desierto# revela"}, + }); + + hintTable[GV_GROTTO_LEDGE_TO_GV_OCTOROK_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a rock on #a ledge in the valley# hides", /*french*/"soulever une #roche dans la vallée# révèle", /*spanish*/"levantar una #roca al borde del valle# esconde"}, + }); + + hintTable[GC_GROTTO_PLATFORM_TO_GC_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a #pool of lava# in Goron City blocks the way to", /*french*/"l'#étang de lave# dans le village Goron renferme", /*spanish*/"un #estanque de lava# en la Ciudad Goron bloquea el paso a"}, + }); + + hintTable[GERUDO_FORTRESS_TO_GF_STORMS_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a #storm within Gerudo's Fortress# reveals", /*french*/"la #tempête dans la forteresse# révèle", /*spanish*/"una #tormenta en la Fortaleza Gerudo# revela"}, + }); + + hintTable[ZORAS_DOMAIN_TO_ZD_STORMS_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a #storm within Zora's Domain# reveals", /*french*/"la #tempête dans le Domaine Zora# révèle", /*spanish*/"una #tormenta en la Región de los Zora# revela"}, + }); + + hintTable[HYRULE_CASTLE_GROUNDS_TO_HC_STORMS_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a #storm near the castle# reveals", /*french*/"la #tempête près du château# révèle", /*spanish*/"una #tormenta junto al castillo# revela"}, + }); + + hintTable[GV_FORTRESS_SIDE_TO_GV_STORMS_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a #storm in the valley# reveals", /*french*/"la #tempête dans la vallée# révèle", /*spanish*/"una #tormenta en el valle# revela"}, + }); + + hintTable[DESERT_COLOSSUS_TO_COLOSSUS_GREAT_FAIRY_FOUNTAIN] = HintText::Entrance({ + //obscure text + Text{"a #fractured desert wall# hides", /*french*/"le #mur fragile du désert# cache", /*spanish*/"una #agrietada pared del desierto# esconde"}, + }); + + hintTable[GANONS_CASTLE_GROUNDS_TO_OGC_GREAT_FAIRY_FOUNTAIN] = HintText::Entrance({ + //obscure text + Text{"a #heavy pillar# outside the castle obstructs", /*french*/"le #rocher fragile près du château# cache", /*spanish*/"una #pesada columna# fuera del castillo obstruye"}, + }); + + hintTable[ZORAS_FOUNTAIN_TO_ZF_GREAT_FAIRY_FOUNTAIN] = HintText::Entrance({ + //obscure text + Text{"a #fountain wall# hides", /*french*/"le #mur fragile du réservoir# cache", /*spanish*/"una #pared de la fuente# esconde"}, + }); + + hintTable[GV_FORTRESS_SIDE_TO_GV_CARPENTER_TENT] = HintText::Entrance({ + //obscure text + Text{"a #tent in the valley# covers", /*french*/"la #tente dans la vallée# recouvre", /*spanish*/"una #tienda de campaña del valle# cubre"}, + }); + + hintTable[GRAVEYARD_WARP_PAD_REGION_TO_SHADOW_TEMPLE_ENTRYWAY] = HintText::Entrance({ + //obscure text + Text{"at the #back of the Graveyard#, there is", /*french*/"#derrière le Cimetière# gît", /*spanish*/"en la #parte trasera del cementerio# se halla"}, + }); + + hintTable[LAKE_HYLIA_TO_WATER_TEMPLE_LOBBY] = HintText::Entrance({ + //obscure text + Text{"deep #under a vast lake#, one can find", /*french*/"#sous le lac# gît", /*spanish*/"en las #profundidades de un lago inmenso# se halla"}, + }); + + hintTable[GERUDO_FORTRESS_TO_GERUDO_TRAINING_GROUNDS_LOBBY] = HintText::Entrance({ + //obscure text + Text{"paying a #fee to the Gerudos# grants access to", /*french*/"l'#entrée payante des Gerudo# donne accès à", /*spanish*/"pagarle una #tasa a las gerudo# da acceso a"}, + }); + + hintTable[ZORAS_FOUNTAIN_TO_JABU_JABUS_BELLY_BEGINNING] = HintText::Entrance({ + //obscure text + Text{"inside #Jabu-Jabu#, one can find", /*french*/"#dans Jabu-Jabu# se trouve", /*spanish*/"dentro de #Jabu-Jabu# se halla"}, + }); + + hintTable[KAKARIKO_VILLAGE_TO_BOTTOM_OF_THE_WELL] = HintText::Entrance({ + //obscure text + Text{"a #village well# leads to", /*french*/"dans le fond du #Puits du village# gît", /*spanish*/"el #pozo de un pueblo# conduce a"}, + }); + + /*-------------------------- + | EXIT HINT TEXT | + ---------------------------*/ + //maybe make a new type for this? I'm not sure if it really matters + + hintTable[LINKS_POCKET] = HintText::Exclude({ + //obscure text + Text{"Link's Pocket", /*french*/"les Poches de @", /*spanish*/"el bolsillo de @"}, + }); + + hintTable[KOKIRI_FOREST] = HintText::Exclude({ + //obscure text + Text{"Kokiri Forest", /*french*/"la forêt Kokiri", /*spanish*/"el Bosque Kokiri"}, + }); + + hintTable[THE_LOST_WOODS] = HintText::Exclude({ + //obscure text + Text{"the Lost Woods", /*french*/"les Bois Perdus", /*spanish*/"el Bosque Perdido"}, + }); + + hintTable[SACRED_FOREST_MEADOW] = HintText::Exclude({ + //obscure text + Text{"Sacred Forest Meadow", /*french*/"le Bosquet Sacré", /*spanish*/"la pradera sagrada del bosque"}, + }); + + hintTable[HYRULE_FIELD] = HintText::Exclude({ + //obscure text + Text{"Hyrule Field", /*french*/"la Plaine d'Hyrule", /*spanish*/"la Llanura de Hyrule"}, + }); + + hintTable[LAKE_HYLIA] = HintText::Exclude({ + //obscure text + Text{"Lake Hylia", /*french*/"le Lac Hylia", /*spanish*/"el Lago Hylia"}, + }); + + hintTable[GERUDO_VALLEY] = HintText::Exclude({ + //obscure text + Text{"Gerudo Valley", /*french*/"la Vallée Gerudo", /*spanish*/"el Valle Gerudo"}, + }); + + hintTable[GERUDO_FORTRESS] = HintText::Exclude({ + //obscure text + Text{"Gerudo's Fortress", /*french*/"la Repaire des Voleurs", /*spanish*/"la Fortaleza Gerudo"}, + }); + + hintTable[HAUNTED_WASTELAND] = HintText::Exclude({ + //obscure text + Text{"Haunted Wasteland", /*french*/"le Désert Hanté", /*spanish*/"el desierto encantado"}, + }); + + hintTable[DESERT_COLOSSUS] = HintText::Exclude({ + //obscure text + Text{"Desert Colossus", /*french*/"le Colosse du Désert", /*spanish*/"el Coloso del Desierto"}, + }); + + hintTable[THE_MARKET] = HintText::Exclude({ + //obscure text + Text{"the Market", /*french*/"la Place du Marché", /*spanish*/"la plaza del mercado"}, + }); + + hintTable[TEMPLE_OF_TIME] = HintText::Exclude({ + //obscure text + Text{"Temple of Time", /*french*/"le Temple du Temps", /*spanish*/"el Templo del Tiempo"}, + }); + + hintTable[HYRULE_CASTLE] = HintText::Exclude({ + //obscure text + Text{"Hyrule Castle", /*french*/"le Château d'Hyrule", /*spanish*/"el Castillo de Hyrule"}, + }); + + hintTable[OUTSIDE_GANONS_CASTLE] = HintText::Exclude({ + //obscure text + Text{"outside Ganon's Castle", /*french*/"les alentours du Château&de Ganon", /*spanish*/"el exterior del Castillo de Ganon"}, + }); + + hintTable[KAKARIKO_VILLAGE] = HintText::Exclude({ + //obscure text + Text{"Kakariko Village", /*french*/"le Village Cocorico", /*spanish*/"Kakariko"}, + }); + + hintTable[THE_GRAVEYARD] = HintText::Exclude({ + //obscure text + Text{"the Graveyard", /*french*/"le Cimetière", /*spanish*/"el cementerio"}, + }); + + hintTable[DEATH_MOUNTAIN_TRAIL] = HintText::Exclude({ + //obscure text + Text{"Death Mountain Trail", /*french*/"le Chemin du Péril", /*spanish*/"el sendero de la Montaña de la Muerte"}, + }); + + hintTable[GORON_CITY] = HintText::Exclude({ + //obscure text + Text{"Goron City", /*french*/"le Village Goron", /*spanish*/"la Ciudad Goron"}, + }); + + hintTable[DEATH_MOUNTAIN_CRATER] = HintText::Exclude({ + //obscure text + Text{"Death Mountain Crater", /*french*/"le Cratère du Péril", /*spanish*/"el cráter de la Montaña de la Muerte"}, + }); + + hintTable[ZORAS_RIVER] = HintText::Exclude({ + //obscure text + Text{"Zora's River", /*french*/"la Rivière Zora", /*spanish*/"el Río Zora"}, + }); + + hintTable[ZORAS_DOMAIN] = HintText::Exclude({ + //obscure text + Text{"Zora's Domain", /*french*/"le Domaine Zora", /*spanish*/"la Región de los Zora"}, + }); + + hintTable[ZORAS_FOUNTAIN] = HintText::Exclude({ + //obscure text + Text{"Zora's Fountain", /*french*/"la Fontaine Zora", /*spanish*/"la Fuente Zora"}, + }); + + hintTable[LON_LON_RANCH] = HintText::Exclude({ + //obscure text + Text{"Lon Lon Ranch", /*french*/"le Ranch Lon Lon", /*spanish*/"el Rancho Lon Lon"}, + }); + + + /*-------------------------- + | REGION HINT TEXT | + ---------------------------*/ + + hintTable[KF_LINKS_HOUSE] = HintText::Region({ + //obscure text + Text{"Link's House", /*french*/"la #maison de @#", /*spanish*/"la casa de @"}, + }); + + // hintTable[TOT_MAIN] = HintText::Region({ + // //obscure text + // Text{"the #Temple of Time#", /*french*/"le #Temple du Temps#", /*spanish*/"el Templo del Tiempo"}, + // }); + + hintTable[KF_MIDOS_HOUSE] = HintText::Region({ + //obscure text + Text{"Mido's house", /*french*/"la #Cabane du Grand Mido#", /*spanish*/"la casa de Mido"}, + }); + + hintTable[KF_SARIAS_HOUSE] = HintText::Region({ + //obscure text + Text{"Saria's House", /*french*/"la #Cabane de Saria#", /*spanish*/"la casa de Saria"}, + }); + + hintTable[KF_HOUSE_OF_TWINS] = HintText::Region({ + //obscure text + Text{"the #House of Twins#", /*french*/"la #Cabane des Jumelles#", /*spanish*/"la casa de las gemelas"}, + }); + + hintTable[KF_KNOW_IT_ALL_HOUSE] = HintText::Region({ + //obscure text + Text{"Know-It-All Brothers' House", /*french*/"la #Cabane des frères Je-Sais-Tout#", /*spanish*/"la casa de los hermanos Sabelotodo"}, + }); + + hintTable[KF_KOKIRI_SHOP] = HintText::Region({ + //obscure text + Text{"the #Kokiri Shop#", /*french*/"le #Magasin Kokiri#", /*spanish*/"la tienda kokiri"}, + }); + + hintTable[LH_LAB] = HintText::Region({ + //obscure text + Text{"the #Lakeside Laboratory#", /*french*/"le #Laboratoire du Lac#", /*spanish*/"el laboratorio del lago"}, + }); + + hintTable[LH_FISHING_HOLE] = HintText::Region({ + //obscure text + Text{"the #Fishing Pond#", /*french*/"l'#Étang#", /*spanish*/"el estanque"}, + }); + + hintTable[GV_CARPENTER_TENT] = HintText::Region({ + //obscure text + Text{"the #Carpenters' tent#", /*french*/"la #Tente des charpentiers#", /*spanish*/"la #tienda de campaña de los carpinteros#"}, + }); + + hintTable[MARKET_GUARD_HOUSE] = HintText::Region({ + //obscure text + Text{"the #Guard House#", /*french*/"le #poste de garde#", /*spanish*/"la caseta de guardia"}, + }); + + hintTable[MARKET_MASK_SHOP] = HintText::Region({ + //obscure text + Text{"the #Happy Mask Shop#", /*french*/"la #Foire Aux Masques#", /*spanish*/"la tienda de La Máscara Feliz"}, + }); + + hintTable[MARKET_BOMBCHU_BOWLING] = HintText::Region({ + //obscure text + Text{"the #Bombchu Bowling Alley#", /*french*/"le #Bowling Teigneux#", /*spanish*/"la Bolera Bombchu"}, + }); + + hintTable[MARKET_POTION_SHOP] = HintText::Region({ + //obscure text + Text{"the #Market Potion Shop#", /*french*/"l'#apothicaire de la Place du Marché#", /*spanish*/"la tienda de pociones de la plaza del mercado"}, + }); + + hintTable[MARKET_TREASURE_CHEST_GAME] = HintText::Region({ + //obscure text + Text{"the #Treasure Chest Shop#", /*french*/"la #Chasse-aux-Trésors#", /*spanish*/"el Cofre del Tesoro"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP] = HintText::Region({ + //obscure text + Text{"the #Bombchu Shop#", /*french*/"le #Magasin de Missiles#", /*spanish*/"la Tienda Bombchu"}, + }); + + hintTable[MARKET_MAN_IN_GREEN_HOUSE] = HintText::Region({ + //obscure text + Text{"Man in Green's House", /*french*/"la #Maison de l'Homme en Vert#", /*spanish*/"la casa del hombre de verde"}, + }); + + hintTable[KAK_WINDMILL] = HintText::Region({ + //obscure text + Text{"the #Windmill#", /*french*/"le #Moulin#", /*spanish*/"el #molino#"}, + }); + + hintTable[KAK_CARPENTER_BOSS_HOUSE] = HintText::Region({ + //obscure text + Text{"the #Carpenters' Boss House#", /*french*/"la #Maison du Chef des ouvriers#", /*spanish*/"la casa del capataz de los carpinteros"}, + }); + + hintTable[KAK_HOUSE_OF_SKULLTULA] = HintText::Region({ + //obscure text + Text{"the #House of Skulltula#", /*french*/"la #Maison des Skulltulas#", /*spanish*/"la casa de las Skulltulas"}, + }); + + hintTable[KAK_IMPAS_HOUSE] = HintText::Region({ + //obscure text + Text{"Impa's House", /*french*/"la #Maison d'Impa#", /*spanish*/"la casa de Impa"}, + }); + + hintTable[KAK_IMPAS_HOUSE_BACK] = HintText::Region({ + //obscure text + Text{"Impa's cow cage", /*french*/"la #cage à vache d'Impa#", /*spanish*/"la jaula de la vaca de Impa"}, + }); + + hintTable[KAK_ODD_POTION_BUILDING] = HintText::Region({ + //obscure text + Text{"Granny's Potion Shop", /*french*/"la #maison bleue de Cocorico#", /*spanish*/"la tienda de pociones de la abuela"}, + }); + + hintTable[GRAVEYARD_DAMPES_HOUSE] = HintText::Region({ + //obscure text + Text{"Dampé's Hut", /*french*/"la #Cabane du Fossoyeur#", /*spanish*/"la cabaña de Dampé"}, + }); + + hintTable[GC_SHOP] = HintText::Region({ + //obscure text + Text{"the #Goron Shop#", /*french*/"la #Boutique Goron#", /*spanish*/"la #tienda goron#"}, + }); + + hintTable[ZD_SHOP] = HintText::Region({ + //obscure text + Text{"the #Zora Shop#", /*french*/"la #Boutique Zora#", /*spanish*/"la #tienda zora#"}, + }); + + hintTable[LLR_TALONS_HOUSE] = HintText::Region({ + //obscure text + Text{"Talon's House", /*french*/"la #Maison de Talon#", /*spanish*/"la casa de Talon"}, + }); + + hintTable[LLR_STABLES] = HintText::Region({ + //obscure text + Text{"a #stable#", /*french*/"l'#Étable#", /*spanish*/"el establo"}, + }); + + hintTable[LLR_TOWER] = HintText::Region({ + //obscure text + Text{"the #Lon Lon Tower#", /*french*/"le #silo du Ranch Lon Lon#", /*spanish*/"la torre Lon Lon"}, + }); + + hintTable[MARKET_BAZAAR] = HintText::Region({ + //obscure text + Text{"the #Market Bazaar#", /*french*/"le #Bazar de la Place du Marché#", /*spanish*/"el bazar de la plaza del mercado"}, + }); + + hintTable[MARKET_SHOOTING_GALLERY] = HintText::Region({ + //obscure text + Text{"a #Slingshot Shooting Gallery#", /*french*/"le #Jeu d'Adresse de la Place du Marché#", /*spanish*/"el Tiro al Blanco con tirachinas"}, + }); + + hintTable[KAK_BAZAAR] = HintText::Region({ + //obscure text + Text{"the #Kakariko Bazaar#", /*french*/"le #Bazar de Cocorico#", /*spanish*/"el bazar de Kakariko"}, + }); + + hintTable[KAK_POTION_SHOP_FRONT] = HintText::Region({ + //obscure text + Text{"the #Kakariko Potion Shop#", /*french*/"l'#apothicaire de Cocorico#", /*spanish*/"la tienda de pociones de Kakariko"}, + }); + + hintTable[KAK_POTION_SHOP_BACK] = HintText::Region({ + //obscure text + Text{"the #Kakariko Potion Shop#", /*french*/"l'#apothicaire de Cocorico#", /*spanish*/"la tienda de pociones de Kakariko"}, + }); + + hintTable[KAK_SHOOTING_GALLERY] = HintText::Region({ + //obscure text + Text{"a #Bow Shooting Gallery#", /*french*/"le #jeu d'adresse de Cocorico#", /*spanish*/"el Tiro al Blanco con arco"}, + }); + + hintTable[COLOSSUS_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[HC_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[OGC_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[DMC_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[DMT_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[ZF_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[GRAVEYARD_SHIELD_GRAVE] = HintText::Region({ + //obscure text + Text{"a #grave with a free chest#", /*french*/"le #tombeau avec un trésor#", /*spanish*/"la #tumba con un cofre#"}, + }); + + hintTable[GRAVEYARD_HEART_PIECE_GRAVE] = HintText::Region({ + //obscure text + Text{"a chest spawned by #Sun's Song#", /*french*/"un #coffre apparaît avec le Chant du Soleil#", /*spanish*/"la #tumba de la Canción del Sol#"}, + }); + + hintTable[GRAVEYARD_COMPOSERS_GRAVE] = HintText::Region({ + //obscure text + Text{"the #Composers' Grave#", /*french*/"la #Tombe royale#", /*spanish*/"el #Panteón Real#"}, + }); + + hintTable[GRAVEYARD_DAMPES_GRAVE] = HintText::Region({ + //obscure text + Text{"Dampé's Grave", /*french*/"la #Tombe d'Igor#", /*spanish*/"la #tumba de Dampé#"}, + }); + + hintTable[DMT_COW_GROTTO] = HintText::Region({ + //obscure text + Text{"a solitary #Cow#", /*french*/"la #grotte avec une vache#", /*spanish*/"una #vaca# solitaria"}, + }); + + hintTable[HC_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"a sandy grotto with #fragile walls#", /*french*/"la #grotte avec des murs fragiles#", /*spanish*/"la arenosa gruta de #frágiles paredes#"}, + }); + + hintTable[HF_TEKTITE_GROTTO] = HintText::Region({ + //obscure text + Text{"a pool guarded by a #Tektite#", /*french*/"l'#étang sous-terrain avec un Araknon#", /*spanish*/"un charco custodiado por un #Tektite#"}, + }); + + hintTable[HF_NEAR_KAK_GROTTO] = HintText::Region({ + //obscure text + Text{"a #Big Skulltula# guarding a Gold one", /*french*/"la #grotte d'araignées#", /*spanish*/"una #gran Skulltula# custodiando una dorada"}, + }); + + hintTable[HF_COW_GROTTO] = HintText::Region({ + //obscure text + Text{"a grotto full of #spider webs#", /*french*/"la #grotte couverte de toiles d'araignées#", /*spanish*/"una gruta llena de #telarañas#"}, + }); + + hintTable[KAK_REDEAD_GROTTO] = HintText::Region({ + //obscure text + Text{"#ReDeads# guarding a chest", /*french*/"le tombeau de #deux morts#", /*spanish*/"los #ReDeads# que custodian un cofre"}, + }); + + hintTable[SFM_WOLFOS_GROTTO] = HintText::Region({ + //obscure text + Text{"#Wolfos# guarding a chest", /*french*/"la #grotte iridescente#", /*spanish*/"los #Wolfos# que custodian un cofre"}, + }); + + hintTable[GV_OCTOROK_GROTTO] = HintText::Region({ + //obscure text + Text{"an #Octorok# guarding a rich pool", /*french*/"un #étang sous-terrain avec un Octorok#", /*spanish*/"un #Octorok# que custodia un lujoso charco"}, + }); + + hintTable[DEKU_THEATER] = HintText::Region({ + //obscure text + Text{"the #Lost Woods Stage#", /*french*/"le #théâtre sylvestre#", /*spanish*/"el #escenario del Bosque Perdido#"}, + }); + + hintTable[ZR_OPEN_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[DMC_UPPER_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[DMT_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[KAK_OPEN_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[HF_NEAR_MARKET_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[HF_OPEN_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[HF_SOUTHEAST_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[KF_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[LW_NEAR_SHORTCUTS_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[HF_INSIDE_FENCE_GROTTO] = HintText::Region({ + //obscure text + Text{"a #single Upgrade Deku Scrub#", /*french*/"une #grotte avec une peste Mojo#", /*spanish*/"una cueva con un #solitario mercader deku#"}, + }); + + hintTable[LW_SCRUBS_GROTTO] = HintText::Region({ + //obscure text + Text{"#2 Deku Scrubs# including an Upgrade one", /*french*/"une #grotte avec deux pestes Mojo#", /*spanish*/"una cueva con #dos mercaderes deku#"}, + }); + + hintTable[COLOSSUS_GROTTO] = HintText::Region({ + //obscure text + Text{"2 Deku Scrubs", /*french*/"une #grotte avec deux pestes Mojo#", /*spanish*/"una cueva con #dos mercaderes deku#"}, + }); + + hintTable[ZR_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"2 Deku Scrubs", /*french*/"une #grotte avec deux pestes Mojo#", /*spanish*/"una cueva con #dos mercaderes deku#"}, + }); + + hintTable[SFM_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"2 Deku Scrubs", /*french*/"une #grotte avec deux pestes Mojo#", /*spanish*/"una cueva con #dos mercaderes deku#"}, + }); + + hintTable[GV_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"2 Deku Scrubs", /*french*/"une #grotte avec deux pestes Mojo#", /*spanish*/"una cueva con #dos mercaderes deku#"}, + }); + + hintTable[LH_GROTTO] = HintText::Region({ + //obscure text + Text{"3 Deku Scrubs", /*french*/"une #grotte avec trois pestes Mojo#", /*spanish*/"una cueva con #tres mercaderes deku#"}, + }); + + hintTable[DMC_HAMMER_GROTTO] = HintText::Region({ + //obscure text + Text{"3 Deku Scrubs", /*french*/"une #grotte avec trois pestes Mojo#", /*spanish*/"una cueva con #tres mercaderes deku#"}, + }); + + hintTable[GC_GROTTO] = HintText::Region({ + //obscure text + Text{"3 Deku Scrubs", /*french*/"une #grotte avec trois pestes Mojo#", /*spanish*/"una cueva con #tres mercaderes deku#"}, + }); + + hintTable[LLR_GROTTO] = HintText::Region({ + //obscure text + Text{"3 Deku Scrubs", /*french*/"une #grotte avec trois pestes Mojo#", /*spanish*/"una cueva con #tres mercaderes deku#"}, + }); + + hintTable[ZR_FAIRY_GROTTO] = HintText::Region({ + //obscure text + Text{"a small #Fairy Fountain#", /*french*/"une #fontaine de fées#", /*spanish*/"una pequeña #fuente de hadas#"}, + }); + + hintTable[HF_FAIRY_GROTTO] = HintText::Region({ + //obscure text + Text{"a small #Fairy Fountain#", /*french*/"une #fontaine de fées#", /*spanish*/"una pequeña #fuente de hadas#"}, + }); + + hintTable[SFM_FAIRY_GROTTO] = HintText::Region({ + //obscure text + Text{"a small #Fairy Fountain#", /*french*/"une #fontaine de fées#", /*spanish*/"una pequeña #fuente de hadas#"}, + }); + + hintTable[ZD_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"a small #Fairy Fountain#", /*french*/"une #fontaine de fées#", /*spanish*/"una pequeña #fuente de hadas#"}, + }); + + hintTable[GF_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"a small #Fairy Fountain#", /*french*/"une #fontaine de fées#", /*spanish*/"una pequeña #fuente de hadas#"}, + }); + + /*-------------------------- + | JUNK HINT TEXT | + ---------------------------*/ + + hintTable[JUNK01] = HintText::Junk({ + //obscure text + Text{"Remember to check your 3DS battery level&and save often.", /*french*/"Surveillez votre batterie 3DS et sauvegardez souvent!", /*spanish*/"No te olvides de revisar la batería de la 3DS y guarda partida de vez en cuando."}, + }); + + hintTable[JUNK02] = HintText::Junk({ + //obscure text + Text{"They say you must read the names of \"Special Deal\" shop items carefully.", /*french*/"Selon moi, les « Offres spéciales » sont parfois trompeuses... Lisez attentivement!", /*spanish*/"Según dicen, se debería prestar atención a los nombres de las ofertas especiales."}, + }); + + hintTable[JUNK03] = HintText::Junk({ + //obscure text + Text{"They say that Zelda is a poor leader.", /*french*/"Selon moi, Zelda ne ferait pas un bon monarque.", /*spanish*/"Según dicen, Zelda es mala líder."}, + }); + + hintTable[JUNK04] = HintText::Junk({ + //obscure text + Text{"These hints can be quite useful. This is an exception.", /*french*/"Ces indices sont très utiles, à l'exception de celui-ci.", /*spanish*/"Las pistas suelen servir de ayuda. En cambio, esta no."}, + }); + + hintTable[JUNK05] = HintText::Junk({ + //obscure text + Text{"They say that the Lizalfos in Dodongo's Cavern like to play in lava.", /*french*/"Selon moi, les Lézalfos de la Caverne Dodongo aiment patauger dans la lave.", /*spanish*/"Según dicen, a los Lizalfos de la Cueva de los Dodongos les gusta jugar en la lava."}, + }); + + hintTable[JUNK06] = HintText::Junk({ + //obscure text + Text{"They say that all the Zora drowned in Wind Waker.", /*french*/"Selon moi, les Zoras se sont noyés dans Wind Waker.", /*spanish*/"Según dicen, en Wind Waker todos los zora se ahogaron."}, + }); + + hintTable[JUNK07] = HintText::Junk({ + //obscure text + Text{"If Gorons eat rocks, does that mean I'm in danger?", /*french*/"Ne dis pas au Gorons que je suis ici. Ils mangent des roches, tu sais!", /*spanish*/"Si los Goron se tragan las piedras, ¿no me hace ser una especia vulnarable o algo así"}, + }); + + hintTable[JUNK08] = HintText::Junk({ + //obscure text + Text{"'Member when Ganon was a blue pig?^I 'member.", /*french*/"Dans mon temps, Ganon était un cochon bleu...^Pff! Les jeunes de nos jours, et leur Ganondorf!", /*spanish*/"¿T'acuerdas cuando Ganon era un cerdo azul?^Qué tiempos, chico."}, + }); + + hintTable[JUNK09] = HintText::Junk({ + //obscure text + Text{"One who does not have Triforce can't go in.", /*french*/"Ceux sans Triforce doivent rebrousser chemin.", /*spanish*/"Aquel que no porte la Trifuerza no podrá pasar."}, + }); + + hintTable[JUNK10] = HintText::Junk({ + //obscure text + Text{"Save your future, end the Happy Mask Salesman.", /*french*/"Selon moi, tu t'éviteras des jours de malheur si tu vaincs le vendeur de masques...", /*spanish*/"Salva tu futuro, acaba con el dueño de La Máscara Feliz."}, + }); + + hintTable[JUNK11] = HintText::Junk({ + //obscure text + Text{"Glitches are a pathway to many abilities some consider to be... Unnatural.", /*french*/"Les glitchs sont un moyen d'acquérir de nombreuses facultés considérées par certains comme... contraire à la nature.", /*spanish*/"Los glitches son el camino a muchas habilidades que varios consideran... nada natural."}, + }); + + hintTable[JUNK12] = HintText::Junk({ + //obscure text + Text{"I'm stoned. Get it?", /*french*/"Allez, roche, papier, ciseau...&Roche.", /*spanish*/"Me he quedado de piedra. ¿Lo pillas?"}, + }); + + hintTable[JUNK13] = HintText::Junk({ + //obscure text + Text{"Hoot! Hoot! Would you like me to repeat that?", /*french*/"Hou hou! Veux-tu que je répète tout ça?", /*spanish*/"¡Buuu, buuu! ¿Te lo vuelvo a repetir?"}, + }); + + hintTable[JUNK14] = HintText::Junk({ + //obscure text + Text{"Gorons are stupid. They eat rocks.", /*french*/"Les Gorons sont des vraies têtes dures.", /*spanish*/"Los Goron son tontos. Se comen las piedras."}, + }); + + hintTable[JUNK15] = HintText::Junk({ + //obscure text + Text{"They say that Lon Lon Ranch prospered under Ingo.", /*french*/"Selon moi, le Ranch Lon Lon était plus prospère sous Ingo.", /*spanish*/"Según dicen, el Rancho Lon Lon prosperó gracias a Ingo."}, + }); + + hintTable[JUNK16] = HintText::Junk({ + //obscure text + Text{"The single rupee is a unique item.", /*french*/"Nul objet n'est plus unique que le rubis vert.", /*spanish*/"La rupia de uno es un objeto singular."}, + }); + + hintTable[JUNK17] = HintText::Junk({ + //obscure text + Text{"Without the Lens of Truth, the Treasure Chest Mini-Game is a 1 out of 32 chance.^Good luck!", /*french*/"Gagner la Chasse-aux-Trésors est 1 chance sur 32.^Bonne chance!", /*spanish*/"Sin la Lupa de la Verdad, ganarías 1/32 veces en el Cofre del Tesoro.^¡Buena suerte con ello!"}, + }); + + hintTable[JUNK18] = HintText::Junk({ + //obscure text + Text{"Use bombs wisely.", /*french*/"Utilise les bombes avec précaution.", /*spanish*/"No desperdicies las bombas."}, + }); + + hintTable[JUNK19] = HintText::Junk({ + //obscure text + Text{"They say that Volvagia hates splinters", /*french*/"Selon moi, Volvagia déteste les échardes.", /*spanish*/"Según dicen, Volvagia le teme a las astillas."}, + }); + + hintTable[JUNK20] = HintText::Junk({ + //obscure text + Text{"They say that funky monkeys can be spotted on Friday.", /*french*/"Selon moi, des capucins coquins sortent le vendredi.", /*spanish*/"Según dicen, en los viernes puedes hallar monos marchosos."}, + }); + + hintTable[JUNK21] = HintText::Junk({ + //obscure text + Text{"I found you, faker!", /*french*/"Ah-ha! Je t'ai trouvé!", /*spanish*/"¡Ahí estás, impostor!"}, + }); + + hintTable[JUNK22] = HintText::Junk({ + //obscure text + Text{"They say the Groose is loose.", /*french*/"Selon moi, Hergo est le vrai héros.", /*spanish*/"Según dicen, Malton es un espanto."}, + }); + + hintTable[JUNK23] = HintText::Junk({ + //obscure text + Text{"They say that players who select the \"ON\" option for \"MOTION CONTROL\" are the real \"Zelda players!\"", /*french*/"Selon moi, ceux qui utilisent les contrôles gyroscopiques sont les VRAIS joueurs.", /*spanish*/"Según dicen, aquellos que juegan usando el control por movimiento son los verdaderos jugadores de Zelda."}, + }); + + hintTable[JUNK24] = HintText::Junk({ + //obscure text + Text{"What happened to Sheik?", /*french*/"Donc... Qu'est-ce qui arrive avec Sheik?", /*spanish*/"¿Qué la habrá pasado a Sheik?"}, + }); + + hintTable[JUNK25] = HintText::Junk({ + //obscure text + Text{"L2P @.", /*french*/"Arrête de lire les indices et joue comme un grand, @.", /*spanish*/"Mira que eres novato, @."}, + }); + + hintTable[JUNK26] = HintText::Junk({ + //obscure text + Text{"I've heard you can cheat at Sploosh Kaboom.", /*french*/"Selon moi, il y a une carte aux trésors à Mercantîle... Duh!", /*spanish*/"He oído por ahí que puedes hacer trampa en el Sploosh Kaboom."}, + }); + + hintTable[JUNK27] = HintText::Junk({ + //obscure text + Text{"I'm Lonk from Pennsylvania.", /*french*/"Je suis Lonk, le héros de Pennsylvanie!", /*spanish*/"Soy Lonk, de Pensilvania."}, + }); + + hintTable[JUNK28] = HintText::Junk({ + //obscure text + Text{"I bet you'd like to have more bombs.", /*french*/"Je parie que tu veux plus de bombes.", /*spanish*/"Me apuesto a que quisieras tener más bombas."}, + }); + + hintTable[JUNK29] = HintText::Junk({ + //obscure text + Text{"When all else fails, use Fire.", /*french*/"Quand rien ne marche, utilise le feu.", /*spanish*/"Cuando nada funcione, usa el fuego."}, + }); + + hintTable[JUNK30] = HintText::Junk({ + //obscure text + Text{"Here's a hint, @. Don't be bad.", /*french*/"Selon moi, la #Triforce# n'est pas dans le jeu... Duh!", /*spanish*/"Aquí tienes una pista, @: deja de ser manco."}, + }); + + hintTable[JUNK31] = HintText::Junk({ + //obscure text + Text{"Game Over. Return of Ganon.", /*french*/"Partie terminée. RETour de Ganon.", /*spanish*/"Fin de la partida. El regreso de Ganon."}, + }); + + hintTable[JUNK32] = HintText::Junk({ + //obscure text + Text{"May the way of the Hero lead to the Triforce.", /*french*/"Que le chemin du héros te mène à la Triforce.", /*spanish*/"Puede que la senda del héroe te lleve hacia la Trifuerza."}, + }); + + hintTable[JUNK33] = HintText::Junk({ + //obscure text + Text{"Can't find an item? Scan an Amiibo.", /*french*/"Tu cherches de quoi? Utilise un Amiibo!", /*spanish*/"¿No encuentras algo? Escanea un amiibo."}, + }); + + hintTable[JUNK34] = HintText::Junk({ + //obscure text + Text{"They say this game has just a few glitches.", /*french*/"Selon moi, ce jeu est complètement exempt de glitchs.", /*spanish*/"Dicen que este juego apenas tiene glitches."}, + }); + + hintTable[JUNK35] = HintText::Junk({ + //obscure text + Text{"BRRING BRRING This is Ulrira. Wrong number?", /*french*/"DRING DRING!! Pépé le Ramollo à l'appareil... Quoi? Faux numéro?", /*spanish*/"¡Ring! ¡Ring! Al habla Ulrira. ¿Me he equivocado de número?"}, + }); + + hintTable[JUNK36] = HintText::Junk({ + //obscure text + Text{"Tingle Tingle Kooloo Limpah!", /*french*/"Tingle! Tingle! Kooloolin... Pah!", /*spanish*/"Tingle, Tingle, Kurulín... ¡PA!"}, + }); + + hintTable[JUNK37] = HintText::Junk({ + //obscure text + Text{"L is real 2401", /*french*/"L is real 2401", /*spanish*/"L es real 2401."}, + }); + + hintTable[JUNK38] = HintText::Junk({ + //obscure text + Text{"They say that Ganondorf will appear in the next Mario Tennis.", /*french*/"Selon moi, Ganondorf sera la nouvelle recrue dans Mario Tennis.", /*spanish*/"Según dicen, Ganondorf estará en el próximo Mario Tennis."}, + }); + + hintTable[JUNK39] = HintText::Junk({ + //obscure text + Text{"Medigoron sells the earliest Breath of the Wild demo.", /*french*/"Selon moi, Medigoron vend une démo de #Breath of the Wild#.", /*spanish*/"Medigoron vende la primera demo del Breath of the Wild."}, + }); + + hintTable[JUNK40] = HintText::Junk({ + //obscure text + Text{"Can you move me? I don't get great service here.", /*french*/"Peux-tu me déplacer? J'ai pas une bonne réception ici.", /*spanish*/"¿Puedes llevarme a otro lado? Aquí nadie me presta atención."}, + }); + + hintTable[JUNK41] = HintText::Junk({ + //obscure text + Text{"They say if you use Strength on the truck, you can find Mew.", /*french*/"Selon moi, #Mew# se trouve dessous le camion... Duh!", /*spanish*/"Según dicen, puedes hallar un Mew usando Fuerza contra el camión de Ciudad Carmín."}, + }); + + hintTable[JUNK42] = HintText::Junk({ + //obscure text + Text{"I'm a helpful hint Gossip Stone!^See, I'm helping.", /*french*/"Salut! Je suis une pierre de bons conseils!^Tiens, tu vois? J'aide bien, hein?", /*spanish*/"Soy una Piedra Sheikah muy útil.^¡Mira cómo te ayudo!"}, + }); + + hintTable[JUNK43] = HintText::Junk({ + //obscure text + Text{"Dear @, please come to the castle. I've baked a cake for you.&Yours truly, Princess Zelda.", /*french*/"Mon très cher @:&Viens vite au château, je t'ai préparé&un délicieux gâteau...^À bientôt, Princesse Zelda", /*spanish*/"Querido @: Por favor, ven al castillo. He hecho una tarta para ti.&Sinceramente tuya: Princesa Zelda."}, + }); + + hintTable[JUNK44] = HintText::Junk({ + //obscure text + Text{"They say all toasters toast toast.", /*french*/"Selon moi, les grille-pains grillent du pain.", /*spanish*/"Según dicen, todas las tostadoras tostan tostadas tostadas."}, + }); + + hintTable[JUNK45] = HintText::Junk({ + //obscure text + Text{"You thought it would be a useful hint, but it was me, junk hint!", /*french*/"Tu t'attendais à un bon indice... Mais c'était moi, un mauvais indice!", /*spanish*/"Je... Creeías que iba a ser una piedra de utilidad, ¡pero no, era yo, la piedra de la agonía!"}, + }); + + hintTable[JUNK46] = HintText::Junk({ + //obscure text + Text{"They say that quest guidance can be found at a talking rock.", /*french*/"Selon moi, des #indices# se trouvent auprès d'une pierre parlante... Duh!", /*spanish*/"Según dicen, puedes consultarle ayuda a rocas parlanchinas."}, + }); + + hintTable[JUNK47] = HintText::Junk({ + //obscure text + Text{"They say that the final item you're looking for can be found somewhere in Hyrule.", /*french*/"Selon moi, le #dernier objet# se trouve quelque part dans Hyrule... Duh!", /*spanish*/"Según dicen, el último objeto que te falte puede estar en cualquier rincón de Hyrule."}, + }); + + hintTable[JUNK48] = HintText::Junk({ + //obscure text + Text{"Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.", /*french*/"Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.", /*spanish*/"Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep."}, + }); + + hintTable[JUNK49] = HintText::Junk({ + //obscure text + Text{"They say that Barinade fears Deku Nuts.", /*french*/"Selon moi, Barinade a la frousse des noix Mojo.", /*spanish*/"Según dicen, lo que más teme a Barinade son las nueces deku."}, + }); + + hintTable[JUNK50] = HintText::Junk({ + //obscure text + Text{"They say that Flare Dancers do not fear Goron-crafted blades.", /*french*/"Selon moi, le danse-flamme n'a pas peur des armes de Goron.", /*spanish*/"Según dicen, los Bailafuegos no le temen a las armas forjadas por Gorons."}, + }); + + hintTable[JUNK51] = HintText::Junk({ + //obscure text + Text{"They say that Morpha is easily trapped in a corner.", /*french*/"Selon moi, Morpha est facilement coincé.", /*spanish*/"Según dicen, puedes atrapar a Morpha con facilidad en una esquina."}, + }); + + hintTable[JUNK52] = HintText::Junk({ + //obscure text + Text{"They say that Bongo Bongo really hates the cold.", /*french*/"Selon moi, Bongo Bongo a facilement froid aux doigts.", /*spanish*/"Según dicen, Bongo Bongo odia a muerte el frío."}, + }); + + hintTable[JUNK53] = HintText::Junk({ + //obscure text + Text{"They say that your sword is most powerful when you put it away.", /*french*/"Selon moi, ton épée est à pleine puissance quand tu la rengaines.", /*spanish*/"Según dicen, tu espada se vuelve más poderosa si la guardas."}, + }); + + hintTable[JUNK54] = HintText::Junk({ + //obscure text + Text{"They say that bombing the hole Volvagia last flew into can be rewarding.", /*french*/"Selon moi, le trou où se creuse Volvagia est vulnérable aux bombes.", /*spanish*/"Según dicen, trae buena suerte colocar una bomba en el último agujero de donde salió Volvagia."}, + }); + + hintTable[JUNK55] = HintText::Junk({ + //obscure text + Text{"They say that invisible ghosts can be exposed with Deku Nuts.", /*french*/"Selon moi, des fantômes invisibles apparaissent avec des noix Mojo.", /*spanish*/"Según dicen, puedes exponer a los espectros invisibles con nueces deku."}, + }); + + hintTable[JUNK56] = HintText::Junk({ + //obscure text + Text{"They say that the real Phantom Ganon is bright and loud.", /*french*/"Selon moi, le vrai spectre de Ganon est clair et bruyant.", /*spanish*/"Según dicen, el verdadero Ganon Fantasma es brillante y ruidoso."}, + }); + + hintTable[JUNK57] = HintText::Junk({ + //obscure text + Text{"They say that walking backwards is very fast.", /*french*/"Selon moi, tu fais marche arrière très rapidement pour un héros.", /*spanish*/"Según dicen, es más rápido caminar hacia atrás."}, + }); + + hintTable[JUNK58] = HintText::Junk({ + //obscure text + Text{"They say that leaping above the Market entrance enriches most children.", /*french*/"Selon moi, les enfants riches se pavanent en haut du pont-levis.", /*spanish*/"Según dicen, saltar por las cadenas a la entrada de la plaza enriquece a muchos chiquillos."}, + }); + + hintTable[JUNK59] = HintText::Junk({ + //obscure text + Text{"They say Ingo is not very good at planning ahead.", /*french*/"Selon moi, Ingo ne fait pas un très bon geôlier.", /*spanish*/"Según dicen, a Ingo no se le da especialmente bien planificar con antelación."}, + }); + + hintTable[JUNK60] = HintText::Junk({ + //obscure text + Text{"You found a spiritual Stone! By which I mean, I worship Nayru.", /*french*/"Vous avez trouvé une Pierre Ancestrale! En effet, je vénère la déesse Hylia.", /*spanish*/"¡Has encontrado una piedra espiritual! Es que le rindo culto a Nayru..."}, + }); + + hintTable[JUNK61] = HintText::Junk({ + //obscure text + Text{"They say that a flying strike with a Deku Stick is no stronger than a grounded one.", /*french*/"Selon moi, un coup de bâton sauté n'est pas meilleur qu'au sol.", /*spanish*/"Según dicen, los golpes aéreos con palos deku son tan fuertes como los normales."}, + }); + + hintTable[JUNK62] = HintText::Junk({ + //obscure text + Text{"Open your eyes.^Open your eyes.^Wake up, @.", /*french*/"Réveille-toi...^Réveille-toi.^Ouvre les yeux, @.", /*spanish*/"Abre los ojos...^Abre los ojos...^Despierta, @..."}, + }); + + hintTable[JUNK63] = HintText::Junk({ + //obscure text + Text{"They say that the Nocturne of Shadow can bring you very close to Ganon.", /*french*/"Selon moi, le nocturne de l'ombre peut t'amener très près de Ganon.", /*spanish*/"Según dicen, el Nocturno de la sombra te puede acercar mucho a Ganon."}, + }); + + hintTable[JUNK64] = HintText::Junk({ + //obscure text + Text{"They say that Twinrova always casts the same spell the first three times.", /*french*/"Selon moi, Twinrova lance toujours les mêmes trois premiers sorts.", /*spanish*/"Según dicen, Birova siempre lanza el mismo hechizo las tres primeras veces."}, + }); + + hintTable[JUNK65] = HintText::Junk({ + //obscure text + Text{"They say that the nightly builds may be unstable.", /*french*/"Selon moi, les « nightly builds » peuvent être instables.", /*spanish*/"Según dicen, las últimas nightlies pueden llegar a ser algo inestables."}, + }); + + hintTable[JUNK66] = HintText::Junk({ + //obscure text + Text{"You're playing a Randomizer. I'm randomized!^Here's a random number: #4#.&Enjoy your Randomizer!", /*french*/"Tu joues à un randomizer. Je suis aléatoire!^Voici un nombre aléatoire: #4#.&Bonne partie!", /*spanish*/"¡Estás jugando un Randomizer! ¡Yo también estoy aleatorizada!^Aquí tienes un número aleatorio: #8#.&¡Diviértete!"}, + }); + + hintTable[JUNK67] = HintText::Junk({ + //obscure text + Text{"They say Ganondorf's bolts can be reflected with glass or steel.", /*french*/"Selon moi, les éclairs de Ganon se reflètent sur l'acier et le verre.", /*spanish*/"Según dicen, puedes reflejar las esferas de energía de Ganondorf con cristal y acero."}, + }); + + hintTable[JUNK68] = HintText::Junk({ + //obscure text + Text{"They say Ganon's tail is vulnerable to nuts, arrows, swords, explosives, hammers...^...sticks, seeds, boomerangs...^...rods, shovels, iron balls, angry bees...", /*french*/"Selon moi, la queue de Ganon est vulnérable aux noix, flèches, épées, bombes, marteaux...^...bâtons, graines, boomerangs...^...baguettes, pelles, boulets de fer, abeilles enragées...", /*spanish*/"Según dicen, la cola de Ganon es vulnerable a nueces, flechas, espadas, explosivos, martillos...^...palos, semillas, bumeráns...^...cetros, palas, bolas de hierro, abejas..."}, + }); + + hintTable[JUNK69] = HintText::Junk({ + //obscure text + Text{"They say that you're wasting time reading this hint, but I disagree. Talk to me again!", /*french*/"Selon moi... tu sais quoi? Parle-moi encore, et je te le dirai!", /*spanish*/"Según dicen, pierdes el tiempo en leer esta pista, pero no pienso igual. ¡Vuelve a hablarme, ya verás!"}, + }); + + hintTable[JUNK70] = HintText::Junk({ + //obscure text + Text{"They say Ganondorf knows where to find the instrument of his doom.", /*french*/"Selon moi, Ganondorf sait où il a caché son point faible.", /*spanish*/"Según dicen, Ganondorf sabe dónde hallar el instrumento de su perdición."}, + }); + + hintTable[JUNK71] = HintText::Junk({ + //obscure text + Text{"I heard @ is pretty good at Zelda.", /*french*/"Apparemment, @ est super bon à Zelda.", /*spanish*/"He oído que a @ se le dan muy bien los Zelda."}, + }); + + hintTable[JUNK72] = HintText::Junk({ + //obscure text + Text{"Hi @, we've been trying to reach you about your car's extended warranty. ", /*french*/"Bonjour, @. Vous avez une voiture? Vous savez, nous offrons des assurances abordables...", /*spanish*/"Buenas, @. Le llamamos para ofrecerle un nuevo seguro de hogar que puede pagar en cómodos plazos, sin intereses ni comisiones."}, + }); + + hintTable[JUNK73] = HintText::Junk({ + //obscure text + Text{"They say that the best weapon against Iron Knuckles is item 176.", /*french*/"Selon moi, les hache-viandes sont vulnérables contre l'objet 176.", /*spanish*/"Según dicen, la mejor arma para enfrentarse a los Nudillos de hierro es el objeto 176."}, + }); + + hintTable[JUNK74] = HintText::Junk({ + //obscure text + Text{"They say that it's actually possible to beat the running man.", /*french*/"Selon moi, il est possible de battre le coureur.&Donc, tu prends ton arc, et...", /*spanish*/"Según dicen, con mucha perseverancia puedes ganarle al corredor con la capucha de conejo."}, + }); + + hintTable[JUNK75] = HintText::Junk({ + //obscure text + Text{"They say that the stone-cold guardian of the Well is only present during work hours.", /*french*/"Selon moi, le gardien de pierre du Puits quitte le soir pour aller se coucher.", /*spanish*/"Según dicen, la inmensa roca que bloquea el pozo solo trabaja en horas laborales."}, + }); + + hintTable[JUNK76] = HintText::Junk({ + //obscure text + Text{"They say this hint makes more sense in other languages.", /*french*/"Selon moi, ces indices auraient pu être mieux traduits... Duh!", /*spanish*/"Según dicen, esta pista revela algo de vital importancia si cambias el idioma del juego..."}, + }); + + hintTable[JUNK77] = HintText::Junk({ + //obscure text + Text{"BOK? No way.", /*french*/"BD'accord? Hors de question.", /*spanish*/"¿BVale? Ni hablar."}, + }); + + // ^ junk hints above are from 3drando + // v junk hints below are new to soh rando + + #define HINT_TEXT_NEEDS_TRANSLATION_FR "Erreur 0x69a504:&Traduction manquante^C'est de la faute à Purple Hato!&J'vous jure!" + + hintTable[JUNK78] = HintText::Junk({ + //obscure text + Text{"They say blarg...^...or at least briaguya does.", /*french*/HINT_TEXT_NEEDS_TRANSLATION_FR, /*spanish*/"blarg"}, + }); + + hintTable[JUNK79] = HintText::Junk({ + //obscure text + Text{"They say this peace is what all true warriors strive for.", /*french*/HINT_TEXT_NEEDS_TRANSLATION_FR, /*spanish*/"blarg"}, + }); + + hintTable[JUNK80] = HintText::Junk({ + //obscure text + Text{"They say this ship is what all true gamers strive for.", /*french*/HINT_TEXT_NEEDS_TRANSLATION_FR, /*spanish*/"blarg"}, + }); + + hintTable[JUNK81] = HintText::Junk({ + //obscure text + Text{"They say that Glowsticks can be found in the Raveyard.", /*french*/"On peut trouver des Bâton Lumineux sur le dancefloor du cimetière.", /*spanish*/"blarg"}, + }); + + /*-------------------------- + | DUNGEON HINT TEXT | + ---------------------------*/ + + hintTable[DEKU_TREE] = HintText::DungeonName({ + //obscure text + Text{"an ancient tree", /*french*/"le vieil arbre", /*spanish*/"un ancestral árbol"}, + }, {}, + //clear text + Text{"Deku Tree", /*french*/"l'Arbre Mojo", /*spanish*/"el Gran Árbol Deku"} + ); + + hintTable[DODONGOS_CAVERN] = HintText::DungeonName({ + //obscure text + Text{"an immense cavern", /*french*/"l'immense caverne", /*spanish*/"una descomunal cueva"}, + }, {}, + //clear text + Text{ "Dodongo's Cavern", /*french*/"la Caverne Dodongo", /*spanish*/"la Cueva de los Dodongos"} + ); + + hintTable[JABU_JABUS_BELLY] = HintText::DungeonName({ + //obscure text + Text{"the belly of a deity", /*french*/"le ventre d'un gardien", /*spanish*/"la tripa de cierta deidad"}, + }, {}, + //clear text + Text{"Jabu-Jabu's Belly", /*french*/"le Ventre de Jabu-Jabu", /*spanish*/"tripa de Jabu-Jabu"} + ); + + hintTable[FOREST_TEMPLE] = HintText::DungeonName({ + //obscure text + Text{"a deep forest", /*french*/"la profonde forêt", /*spanish*/"las profundidades del bosque"}, + }, {}, + //clear text + Text{"Forest Temple", /*french*/"le Temple de la Forêt", /*spanish*/"el Templo del Bosque"} + ); + + hintTable[FIRE_TEMPLE] = HintText::DungeonName({ + //obscure text + Text{"a high mountain", /*french*/"la grande montagne", /*spanish*/"una alta montaña"}, + }, {}, + //clear text + Text{"Fire Temple", /*french*/"le Temple du Feu", /*spanish*/"el Templo del Fuego"} + ); + + hintTable[WATER_TEMPLE] = HintText::DungeonName({ + //obscure text + Text{"a vast lake", /*french*/"le vaste lac", /*spanish*/"un lago inmenso"}, + }, {}, + //clear text + Text{"Water Temple", /*french*/"le Temple de l'Eau", /*spanish*/"el Templo del Agua"} + ); + + hintTable[SPIRIT_TEMPLE] = HintText::DungeonName({ + //obscure text + Text{"the goddess of the sand", /*french*/"la déesse des sables", /*spanish*/"la diosa de las arenas"}, + }, {}, + //clear text + Text{"Spirit Temple", /*french*/"le Temple de l'Esprit", /*spanish*/"el Templo del Espíritu"} + + ); + + hintTable[SHADOW_TEMPLE] = HintText::DungeonName({ + //obscure text + Text{"the house of the dead", /*french*/"la maison des morts", /*spanish*/"la casa de la muerte"}, + }, {}, + //clear text + Text{"Shadow Temple", /*french*/"le Temple de l'Ombre", /*spanish*/"el Templo de las Sombras"} + ); + + hintTable[ICE_CAVERN] = HintText::DungeonName({ + //obscure text + Text{"a frozen maze", /*french*/"le dédale glacé", /*spanish*/"un gélido laberinto"}, + }, {}, + //clear text + Text{"Ice Cavern", /*french*/"la caverne de glace", /*spanish*/"la caverna de hielo"} + ); + + hintTable[BOTTOM_OF_THE_WELL] = HintText::DungeonName({ + //obscure text + Text{"a shadow\'s prison", /*french*/"la prison d'une ombre", /*spanish*/"la prisión de las sombras"}, + }, {}, + //clear text + Text{"Bottom of the Well", /*french*/"le fonds du Puits", /*spanish*/"el fondo del pozo"} + ); + + hintTable[GERUDO_TRAINING_GROUNDS] = HintText::DungeonName({ + //obscure text + Text{"the test of thieves", /*french*/"l'épreuve des voleurs", /*spanish*/"la prueba de las bandidas"}, + }, {}, + //clear text + Text{"Gerudo Training Grounds", /*french*/"le Gymnase Gerudo", /*spanish*/"el Centro de Instrucción Gerudo"} + ); + + hintTable[GANONS_CASTLE] = HintText::DungeonName({ + //obscure text + Text{"a conquered citadel", /*french*/"la citadelle assiégée", /*spanish*/"una conquistada ciudadela"}, + }, {}, + //clear text + Text{"Inside Ganon's Castle", /*french*/"l'intérieur du Château de Ganon", /*spanish*/"el interior del Castillo de Ganon"} + ); + + /*-------------------------- + | BOSS HINT TEXT | + ---------------------------*/ + + hintTable[QUEEN_GOHMA] = HintText::Boss({ + //obscure text + Text{"An #ancient tree# rewards", /*french*/"le #vieil arbre# octroie", /*spanish*/"un #ancestral árbol# premia con"}, + }, {}, + //clear text + Text{"the #Deku Tree# rewards", /*french*/"l'#Arbre Mojo# octroie", /*spanish*/"el #Gran Árbol Deku# premia con"} + ); + + hintTable[KING_DODONGO] = HintText::Boss({ + //obscure text + Text{"An #immense cavern# rewards", /*french*/"l'#immense caverne# octroie", /*spanish*/"una #descomunal cueva# premia con"}, + }, {}, + //clear text + Text{"#Dodongo's Cavern# rewards", /*french*/"la #Caverne Dodongo# octroie", /*spanish*/"la #Cueva de los Dodongos# premia con"} + ); + + hintTable[BARINADE] = HintText::Boss({ + //obscure text + Text{"the #belly of a deity# rewards", /*french*/"le #ventre du gardien# octroie", /*spanish*/"la #tripa de cierta deidad# premia con"}, + }, {}, + //clear text + Text{"#Jabu-Jabu's Belly# rewards", /*french*/"le #Ventre de Jabu-Jabu# octroie", /*spanish*/"la #tripa de Jabu-Jabu# premia con"} + ); + + hintTable[PHANTOM_GANON] = HintText::Boss({ + //obscure text + Text{"a #deep forest# rewards", /*french*/"la #profonde forêt# octroie", /*spanish*/"el #profundo bosque# premia con"}, + }, {}, + //clear text + Text{"the #Forest Temple# rewards", /*french*/"le #Temple de la Forêt# octroie", /*spanish*/"el #Templo del Bosque# premia con"} + ); + + hintTable[VOLVAGIA] = HintText::Boss({ + //obscure text + Text{"a #high mountain# rewards", /*french*/"la #grande montagne# octroie", /*spanish*/"una #alta montaña# premia con"}, + }, {}, + //clear text + Text{"the #Fire Temple# rewards", /*french*/"le #Temple du Feu# octroie", /*spanish*/"el #Templo del Fuego# premia con"} + ); + + hintTable[MORPHA] = HintText::Boss({ + //obscure text + Text{"a #vast lake# rewards", /*french*/"le #vaste lac# octroie", /*spanish*/"un #lago inmenso# premia con"}, + }, {}, + //clear text + Text{"the #Water Temple# rewards", /*french*/"le #Temple de l'Eau# octroie", /*spanish*/"el #Templo del Agua# premia con"} + ); + + hintTable[BONGO_BONGO] = HintText::Boss({ + //obscure text + Text{"the #house of the dead# rewards", /*french*/"la #maison des morts# octroie", /*spanish*/"la #casa de la muerte# premia con"}, + }, {}, + //clear text + Text{"the #Shadow Temple# rewards", /*french*/"le #Temple de l'Ombre# octroie", /*spanish*/"el #Templo de las Sombras#"} + ); + + hintTable[TWINROVA] = HintText::Boss({ + //obscure text + Text{"a #goddess of the sand# rewards", /*french*/"la #déesse des sables# octroie", /*spanish*/"la #diosa de la arena# premia con"}, + }, {}, + //clear text + Text{"the #Spirit Temple# rewards", /*french*/"le #Temple de l'Esprit# octroie", /*spanish*/"el #Templo del Espíritu# premia con"} + ); + // + // [LINKS_POCKET_BOSS] = HintText::Boss({ + // //obscure text + // Text{"#@'s pocket# rewards", /*french*/"#@ débute avec#", /*spanish*/"el #bolsillo de @# premia con"}, + // }, + // //clear text + // Text{"#@ already has#", /*french*/"#@ a déjà#", /*spanish*/"el #bolsillo de @ ya tiene#"} + // ); + + /*-------------------------- + | BRIDGE HINT TEXT | + ---------------------------*/ + + hintTable[BRIDGE_OPEN_HINT] = HintText::Bridge({ + //obscure text + Text{"The awakened ones have already&created a bridge to the castle&where the evil dwells.", + /*french*/"Les êtres de sagesse ont&déjà créé un pont vers&le repaire du mal.", + /*spanish*/"Los sabios #ya habrán creado un puente#&al castillo, de donde emana el mal."}, + }); + + hintTable[BRIDGE_VANILLA_HINT] = HintText::Bridge({ + //obscure text + Text{"The awakened ones require&the Shadow and Spirit Medallions&as well as the Light Arrows.", + /*french*/"Les êtres de sagesse attendront&le héros muni des #Médaillons de&l'Ombre et l'Esprit# et des&#Flèches de Lumière#.", + /*spanish*/"Los sabios aguardarán a que el héroe&obtenga tanto el #Medallón de las&Sombras y el del Espíritu# junto a la #flecha de luz#."}, + }); + + hintTable[BRIDGE_STONES_HINT] = HintText::Bridge({ + //obscure text singular plural + Text{"The awakened ones will&await for the Hero to collect&%d |Spiritual Stone|Spiritual Stones|.", + /*french*/"Les êtres de sagesse attendront&le héros muni de #%d |Pierre&Ancestrale|Pierres&Ancestrales|#.", + /*spanish*/"Los sabios aguardarán a que el héroe&obtenga #%d |piedra espiritual|piedras espirituales|#."}, + }); + + hintTable[BRIDGE_MEDALLIONS_HINT] = HintText::Bridge({ + //obscure text singular plural + Text{"The awakened ones will await&for the Hero to collect&%d |Medallion|Medallions|.", + /*french*/"Les êtres de sagesse attendront&le héros muni de #%d |médaillon|médaillons|#.", + /*spanish*/"Los sabios aguardarán a que el héroe&obtenga #%d |medallón|medallones|#."}, + }); + + hintTable[BRIDGE_REWARDS_HINT] = HintText::Bridge({ + //obscure text singular plural + Text{"The awakened ones will await&for the Hero to collect&%d |Spiritual Stone or Medallion|Spiritual Stones and Medallions|.", + /*french*/"Les êtres de sagesse attendront&le héros muni de #%d |Pierre&Ancestrale ou Médaillon|Pierres&Ancestrales ou Médaillons|#.", + /*spanish*/"Los sabios aguardarán a que el héroe&obtenga #%d |piedra espiritual o medallón|piedras espirtuales y medallones|#."}, + }); + + hintTable[BRIDGE_DUNGEONS_HINT] = HintText::Bridge({ + //obscure text singular plural + Text{"The awakened ones will await&for the Hero to conquer&%d |Dungeon|Dungeons|.", + /*french*/"Les êtres de sagesse attendront&la conquête de #%d |Donjon|Donjons|#.", + /*spanish*/"Los sabios aguardarán a que el héroe& complete #%d |mazmorra|mazmorras|#."}, + }); + + hintTable[BRIDGE_TOKENS_HINT] = HintText::Bridge({ + //obscure text + Text{"The awakened ones will await&for the Hero to collect&%d |Gold Skulltula Token|Gold Skulltula Tokens|.", + /*french*/"Les êtres de sagesse attendront&le héros muni de #%d |Symbole|Symboles| &de Skulltula d'or#.", + /*spanish*/"Los sabios aguardarán a que el héroe&obtenga #%d |símbolo|símbolos| de&skulltula dorada#."}, + }); + + /*-------------------------- + | GANON BOSS KEY HINT TEXT | + ---------------------------*/ + + hintTable[GANON_BK_START_WITH_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the evil one's key will&be given from the start.", + /*french*/"Aussi, la clé du Malin sera&possession même du héros.", + /*spanish*/"Y obtendrás la llave del #señor del mal# desde el #inicio#."}, + }); + + hintTable[GANON_BK_VANILLA_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the evil one's key will&be kept in a big chest&inside its tower.", + /*french*/"Aussi, la clé du #Malin# sera&encoffrée #dans sa tour#.", + /*spanish*/"Y la llave del #señor del mal# aguardará en un gran cofre de #su torre#."}, + }); + + hintTable[GANON_BK_OWN_DUNGEON_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the evil one's key will&be hidden somewhere inside&its castle.", + /*french*/"Aussi, la clé du #Malin# sera&cachée #dans son vaste château#.", + /*spanish*/"Y la llave del #señor del mal# aguardará en #algún lugar de su castillo#."}, + }); + + hintTable[GANON_BK_OVERWORLD_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the #evil one#'s key will be hidden #outside of dungeons# in Hyrule.", + /*french*/"Aussi, la clé du #Malin# se&trouve #hors des donjons# d'Hyrule.", + /*spanish*/"Y la llave del #señor del mal# aguardará #fuera de las mazmorras# de Hyrule."}, + }); + + hintTable[GANON_BK_ANY_DUNGEON_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the #evil one#'s key will be hidden #inside a dungeon# in Hyrule.", + /*french*/"Aussi, la clé du #Malin# se&trouve #dans un donjon# d'Hyrule.", + /*spanish*/"Y la llave del #señor del mal# aguardará #en una mazmorra# de Hyrule."}, + }); + + hintTable[GANON_BK_ANYWHERE_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the #evil one#'s key will be hidden somewhere #in Hyrule#.", + /*french*/"Aussi, la clé du #Malin# se&trouve quelque part #dans Hyrule#.", + /*spanish*/"Y la llave del #señor del mal# aguardará en #cualquier lugar de Hyrule#."}, + }); + + hintTable[GANON_BK_TRIFORCE_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the #evil one#'s key will be given to the Hero once the #Triforce# is completed.", + /*french*/"Aussi, la clé du #Malin# se&révèlera une fois la #Triforce#&assemblée.", + /*spanish*/"Y el héroe recibirá la llave del #señor del mal# cuando haya completado la #Trifuerza#."}, + }); + + /*-------------------------- + | LACS HINT TEXT | + ---------------------------*/ + + hintTable[LACS_VANILLA_HINT] = HintText::LACS({ + //obscure text + Text{"And the #evil one#'s key will be&provided by Zelda once the #Shadow&and Spirit Medallions# are retrieved.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# avec les #médaillons de&l'ombre et de l'esprit#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras obtener&#el medallón de las sombras y del espíritu#."}, + }); + + hintTable[LACS_MEDALLIONS_HINT] = HintText::LACS({ + //obscure text singular plural + Text{"And the #evil one#'s key will be&provided by Zelda once #%d&|Medallion# is|Medallions# are| retrieved.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# avec #%d |médaillon|médaillons|#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras obtener&#%d |medallón|medallones|#."}, + }); + + hintTable[LACS_STONES_HINT] = HintText::LACS({ + //obscure text singular plural + Text{"And the #evil one#'s key will be&provided by Zelda once #%d |Spiritual&Stone# is|Spiritual&Stones# are| retrieved.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# avec #%d des |pierre&spirituelle|pierres&spirituelles|#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras obtener&#%d |piedra espiritual|piedras espirituales|#."}, + }); + + hintTable[LACS_REWARDS_HINT] = HintText::LACS({ + //obscure text singular plural + Text{"And the #evil one#'s key will be&provided by Zelda once #%d |Spiritual&Stone or Medallion# is|Spiritual&Stones and Medallions# are| retrieved.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# avec #%d |Pierre Ancestrale&et des médaillon|Pierres Ancestrales&et des médaillons|#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras obtener&#%d |piedra espiritual o medallón|piedras espirituales o medallones|#."}, + }); + + hintTable[LACS_DUNGEONS_HINT] = HintText::LACS({ + //obscure text singular plural + Text{"And the #evil one#'s key will be&provided by Zelda once #%d |Dungeon#&is|Dungeons#&are| conquered.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# une fois #%d |donjon conquéri|donjons conquéris|#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras completar&#%d |mazmorra|mazmorras|#."}, + }); + + hintTable[LACS_TOKENS_HINT] = HintText::LACS({ + //obscure text singular plural + Text{"And the #evil one#'s key will be&provided by Zelda once #%d |Gold&Skulltula Token# is|Gold&Skulltula Tokens# are| retrieved.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# avec #%d |symbole|symboles| de&Skulltula d'or#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras obtener&#%d |símbolo|símbolos| de&skulltula dorada#."}, + }); + /*-------------------------- + | TRIAL HINT TEXT | + ---------------------------*/ + + hintTable[SIX_TRIALS] = HintText::Exclude({ + //obscure text + Text{"#Ganon's Tower# is protected by a powerful barrier.", /*french*/"#la Tour de Ganon# est protégée par une puissante barrière", /*spanish*/"la #torre de Ganon# está protegida por una poderosa barrera"}, + }); + + hintTable[ZERO_TRIALS] = HintText::Exclude({ + //obscure text + Text{"Sheik dispelled the barrier around #Ganon's Tower#.", /*french*/"Sheik a dissipé la barrière autour de #la Tour de Ganon#", /*spanish*/"Sheik disipó la barrera alrededor de la #torre de Ganon#."}, + }); + + hintTable[FOUR_TO_FIVE_TRIALS] = HintText::Exclude({ + //obscure text + Text{" was dispelled by Sheik.", /*french*/" a été dissipée par Sheik.", /*spanish*/" se disipó gracias a Sheik."}, + }); + + hintTable[ONE_TO_THREE_TRIALS] = HintText::Exclude({ + //obscure text + Text{" protects Ganons Tower.", /*french*/" protège la Tour de Ganon.", /*spanish*/" protege la torre de Ganon"}, + }); + + /*-------------------------- + | ALTAR TEXT | + ---------------------------*/ + + hintTable[SPIRITUAL_STONE_TEXT_START] = HintText::Altar({ + //obscure text + Text{"3 Spiritual Stones found in Hyrule...", + /*french*/"Les trois Pierres Ancestrales cachées&dans Hyrule...", + /*spanish*/"Tres piedras espirituales halladas por Hyrule..."}, + }); + + hintTable[CHILD_ALTAR_TEXT_END_DOTOPEN] = HintText::Altar({ + //obscure text + Text{"Ye who may become a Hero...&The path to the future is open...", + /*french*/"À celui qui a quête de devenir&héros...&Le futur vous accueille béant...", + /*spanish*/"Para aquel que se convierta en el héroe...&La puerta al futuro está a su disposición..."}, + }); + + hintTable[CHILD_ALTAR_TEXT_END_DOTCLOSED] = HintText::Altar({ + //obscure text + Text{"Ye who may become a Hero...&Stand with the Ocarina and&play the Song of Time.", + /*french*/"À celui qui a quête de devenir&héros...&Portez l'Ocarina et jouez&le chant du temps.", + /*spanish*/"Para aquel que se convierta en el héroe...&Tome la ocarina y&entone la Canción del Tiempo."}, + }); + + hintTable[CHILD_ALTAR_TEXT_END_DOTINTENDED] = HintText::Altar({ + //obscure text + Text{"Ye who may become a Hero...&Offer the spiritual stones and&play the Song of Time.", + /*french*/"À celui qui a quête de devenir&héros... Présentez les Pierres&Ancestrales et jouez&le chant du temps.", + /*spanish*/"Para aquel que se convierta en el héroe...&Tome las piedras espirituales y&entone la Canción del Tiempo."}, + }); + + hintTable[ADULT_ALTAR_TEXT_START] = HintText::Altar({ + //obscure text + Text{"An awakening voice from the Sacred&Realm will call those destined to be&Sages, who dwell in the five temples.", + /*french*/"Quand le mal aura triomphé, une voix&du Saint Royaume appellera ceux&cachés dans les cinq temples, destinés^à être Sages.", + /*spanish*/"Cuando el mal lo impregne todo, desde el Reino Sagrado surgirá una voz que hará despertar a los sabios que moran en los #cinco templos#."}, + }); + + hintTable[ADULT_ALTAR_TEXT_END] = HintText::Altar({ + //obscure text + Text{"$kTogether with the Hero of Time,&the awakened ones will return&the light of peace to the world...", + /*french*/"$kEnsemble avec le Héros du &Temps, ces Sages emprisonneront&le mal et réinstaureront la&lumière de paix dans le monde...", + /*spanish*/"Con el Héroe del Tiempo, aquellos&que despierten detendrán el mal y&volverán al mundo de luz la paz..."}, + }); + + /*-------------------------- + | VALIDATION LINE TEXT | + ---------------------------*/ + + hintTable[VALIDATION_LINE] = HintText::Validation({ + //obscure text + Text{"Hmph... Since you made it this far, I'll let you know what glorious prize of Ganon's you likely missed out on in my tower.^Behold...^", + /*french*/"Pah! Puisque tu t'es rendu ici, je te dirai quel trésor tu as manqué dans ma tour.^Et c'est...^", + /*spanish*/"Mmm... Ya que has llegado hasta aquí, te diré qué preciado objeto de mi propiedad puedes haberte dejado en mi torre.^He aquí...^"}, + }); + + /*-------------------------- + | LIGHT ARROW LOCATION TEXT| + ---------------------------*/ + + hintTable[LIGHT_ARROW_LOCATION_HINT] = HintText::LightArrow({ + //obscure text + Text{"Ha ha ha... You'll never beat me by reflecting my lightning bolts and unleashing the arrows from ", + /*french*/"Ha ha ha... Pauvre fou! Tu ne pourras jamais me vaincre sans les flèches que j'ai cachées dans ", + /*spanish*/"Ja, ja, ja... Nunca me derrotarás reflejando mis esferas de energía y desplegando la flecha de luz de "}, + }); + + hintTable[YOUR_POCKET] = HintText::Exclude({ + //obscure text + Text{"your pocket", /*french*/"tes poches", /*spanish*/"tu bolsillo"}, + }); + + /*-------------------------- + | GANON LINE TEXT | + ---------------------------*/ + + hintTable[GANON_LINE01] = HintText::GanonLine({ + //obscure text + Text{"Oh! It's @.&I was expecting someone called Sheik.&Do you know what happened to them?", + /*french*/"Ah, c'est @.&J'attendais un certain Sheik.&Tu sais ce qui lui est arrivé?", + /*spanish*/"¡Oh! Pero si es @.&Estaba esperando a alguien llamado Sheik. ¿Sabes qué puede haberle pasado?"}, + }); + + hintTable[GANON_LINE02] = HintText::GanonLine({ + //obscure text + Text{"I knew I shouldn't have put the key on the other side of my door.", + /*french*/"J'aurais dû garder la clé ici. Hélas...", + /*spanish*/"Sabía que no tendría que haber dejado la llave al otro lado de la puerta."}, + }); + + hintTable[GANON_LINE03] = HintText::GanonLine({ + //obscure text + Text{"Looks like it's time for a round of tennis.", + /*french*/"C'est l'heure de jouer au tennis.", + /*spanish*/"Parece que es hora de una pachanga de tenis."}, + }); + + hintTable[GANON_LINE04] = HintText::GanonLine({ + //obscure text + Text{"You'll never deflect my bolts of energy with your sword, then shoot me with those Light Arrows you happen to have.", + /*french*/"Ne perds pas ton temps à frapper mes éclairs d'énergie avec ton épée et me tirer avec tes flèches de Lumière!", + /*spanish*/"Nunca reflejarás mis esferas de energía con tu espada, para después dispararme con las flechas de luz que tendrás."}, + }); + + hintTable[GANON_LINE05] = HintText::GanonLine({ + //obscure text + Text{"Why did I leave my trident back in the desert?", + /*french*/"Sale bêtise... Et j'ai oublié mon trident dans le désert!", + /*spanish*/"Santa Hylia... ¿Por qué me habré dejado el tridente en el desierto?"}, + }); + + hintTable[GANON_LINE06] = HintText::GanonLine({ + //obscure text + Text{"Zelda is probably going to do something stupid, like send you back to your own timeline.^So this is quite meaningless. Do you really want to save this moron?", + /*french*/"Même si je suis vaincu... Zelda te renverra dans ton ère, et je reviendrai conquérir!^Telle est la prophécie d'Hyrule Historia!", + /*spanish*/"Seguro que Zelda trata de hacer alguna tontería, como enviarte de vuelta a tu línea temporal.^No tiene ningún sentido alguno. ¿De verdad quieres salvar a esa tonta?"}, + }); + + hintTable[GANON_LINE07] = HintText::GanonLine({ + //obscure text + Text{"What about Zelda makes you think she'd be a better ruler than I?^I saved Lon Lon Ranch,&fed the hungry,&and my castle floats.", + /*french*/"Zelda ne sera jamais un meilleur monarque que moi!^J'ai un château volant, mes sujets sont des belles amazones... et mes Moblins sont clairement plus puissants que jamais!", + /*spanish*/"¿Qué te hace pensar que Zelda gobierna mejor que yo?^Yo he salvado el Rancho Lon Lon,&he alimentado a los hambrientos&y hasta hago que mi castillo flote."}, + }); + + hintTable[GANON_LINE08] = HintText::GanonLine({ + //obscure text + Text{"I've learned this spell,&it's really neat,&I'll keep it later&for your treat!", + /*french*/"Gamin, ton destin achève,&sous mon sort tu périras!&Cette partie ne fut pas brève,&et cette mort, tu subiras!", + /*spanish*/"Veamos ahora que harás,&la batalla ha de comenzar,&te enviaré de una vez al más allá,&¿listo para afrontar la verdad?"}, + }); + + hintTable[GANON_LINE09] = HintText::GanonLine({ + //obscure text + Text{"Many tricks are up my sleeve,&to save yourself&you'd better leave!", + /*french*/"Sale petit garnement,&tu fais erreur!&C'est maintenant que marque&ta dernière heure!", + /*spanish*/"¿No osarás a mí enfrentarte?&Rimas aparte,&¡voy a matarte!"}, + }); + + hintTable[GANON_LINE10] = HintText::GanonLine({ + //obscure text + Text{"After what you did to Koholint Island, how can you call me the bad guy?", + /*french*/"J'admire ce que tu as fait à l'Île Koholint... Toi et moi, nous devrions faire équipe!", + /*spanish*/"Después de lo que le hiciste a la Isla Koholint, ¿cómo te atreves a llamarme malvado?"}, + }); + + hintTable[GANON_LINE11] = HintText::GanonLine({ + //obscure text + Text{"Today, let's begin down&'The Hero is Defeated' timeline.", + /*french*/"Si tu me vaincs, Hyrule sera englouti... mais si tu meurs, on aura A Link to the Past, le meilleur opus de la série!", + /*spanish*/"Hoy daremos lugar a la línea temporal del Héroe Derrotado.&¡Prepárate para el culmen de esta saga!"}, + }); + + /*-------------------------- + | MERCHANTS' ITEMS | + ---------------------------*/ + + hintTable[MEDIGORON_DIALOG_FIRST] = HintText::MerchantsDialogs({ + //obscure text + Text{"How about buying ", + /*french*/"Veux-tu acheter ", + /*spanish*/"¿Me compras "}, + }); + + hintTable[MEDIGORON_DIALOG_SECOND] = HintText::MerchantsDialogs({ + //obscure text + Text{" for #200 Rupees#?&"+TWO_WAY_CHOICE()+"#Buy&Don't buy#", + /*french*/" pour #200 rubis#?&"+TWO_WAY_CHOICE()+"#Acheter&Ne pas acheter#", + /*spanish*/" por #200 rupias#?&"+TWO_WAY_CHOICE()+"#Comprar&No comprar#"}, + }); + + hintTable[CARPET_SALESMAN_DIALOG_FIRST] = HintText::MerchantsDialogs({ + //obscure text + Text{"Welcome!^I am selling stuff, strange and rare, from&all over the world to everybody. Today's&special is...^", + /*french*/"Bienvenue!^Je vends des objets rares et merveilleux du&monde entier. En spécial aujourd'hui...^", + /*spanish*/"¡Acércate!^Vendo productos extraños y difíciles de&encontrar... De todo el mundo a todo el&mundo. La oferta de hoy es...^¡"}, + }); + + hintTable[CARPET_SALESMAN_DIALOG_SECOND] = HintText::MerchantsDialogs({ + //obscure text + Text{"! Terrifying!&I won't tell you what it is until I see the&money...^How about #200 Rupees#?&&"+TWO_WAY_CHOICE()+"#Buy&Don't buy#", + /*french*/"! Un&concentré de puissance! Mais montre tes&rubis avant que je te dise ce que c'est...^Disons #200 rubis#?&&"+TWO_WAY_CHOICE()+"#Acheter&Ne pas acheter#", + /*spanish*/"! ¡Terrorífico!&No te revelaré su nombre hasta que&vea el dinero...^#200 rupias#, ¿qué te parece?&&"+TWO_WAY_CHOICE()+"#Comprar&No comprar#"}, + }); + + hintTable[CARPET_SALESMAN_DIALOG_THIRD] = HintText::MerchantsDialogs({ + //obscure text + Text{"Thank you very much!^What I'm selling is... #", + /*french*/"Merci beaucoup!^Cet objet extraordinaire est... #", + /*spanish*/"¡Muchas gracias!^Lo que vendo es... #¡"}, + }); + + hintTable[CARPET_SALESMAN_DIALOG_FOURTH] = HintText::MerchantsDialogs({ + //obscure text + Text{"!#^The mark that will lead you to the #Spirit&Temple# is the #flag on the "+IF_NOT_MQ()+"left"+MQ_ELSE()+"right"+MQ_END()+"# outside the shop. Be seeing you!", + /*french*/"!#^La marque qui te mènera au #Temple de l'Esprit# est le #drapeau "+IF_NOT_MQ()+"gauche"+MQ_ELSE()+"droite"+MQ_END()+"# en sortant d'ici. À la prochaine!", + /*spanish*/"!#^La marca que te guiará al #Templo del&Espíritu# es la #bandera que está a la&"+IF_NOT_MQ()+"izquierda"+MQ_ELSE()+"derecha"+MQ_END()+"# al salir de aquí. ¡Nos vemos!"}, + }); +} + +int32_t StonesRequiredBySettings() { + int32_t stones = 0; + if (Settings::Bridge.Is(RAINBOWBRIDGE_STONES)) { + stones = std::max({ stones, (int32_t)Settings::BridgeStoneCount.Value() }); + } + if (Settings::Bridge.Is(RAINBOWBRIDGE_REWARDS)) { + stones = std::max({ stones, (int32_t)Settings::BridgeRewardCount.Value() - 6 }); + } + if ((Settings::Bridge.Is(RAINBOWBRIDGE_DUNGEONS)) && (Settings::ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON))) { + stones = std::max({ stones, (int32_t)Settings::BridgeDungeonCount.Value() - 6 }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_STONES)) { + stones = std::max({ stones, (int32_t)Settings::LACSStoneCount.Value() }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_REWARDS)) { + stones = std::max({ stones, (int32_t)Settings::LACSRewardCount.Value() - 6 }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_DUNGEONS)) { + stones = std::max({ stones, (int32_t)Settings::LACSDungeonCount.Value() - 6 }); + } + return stones; +} + +int32_t MedallionsRequiredBySettings() { + int32_t medallions = 0; + if (Settings::Bridge.Is(RAINBOWBRIDGE_MEDALLIONS)) { + medallions = std::max({ medallions, (int32_t)Settings::BridgeMedallionCount.Value() }); + } + if (Settings::Bridge.Is(RAINBOWBRIDGE_REWARDS)) { + medallions = std::max({ medallions, (int32_t)Settings::BridgeRewardCount.Value() - 3 }); + } + if ((Settings::Bridge.Is(RAINBOWBRIDGE_DUNGEONS)) && (Settings::ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON))) { + medallions = std::max({ medallions, (int32_t)Settings::BridgeDungeonCount.Value() - 3 }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_MEDALLIONS)) { + medallions = std::max({ medallions, (int32_t)Settings::LACSMedallionCount.Value() }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_REWARDS)) { + medallions = std::max({ medallions, (int32_t)Settings::LACSRewardCount.Value() - 3 }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_DUNGEONS)) { + medallions = std::max({ medallions, (int32_t)Settings::LACSDungeonCount.Value() - 3 }); + } + return medallions; +} + +int32_t TokensRequiredBySettings() { + int32_t tokens = 0; + if (Settings::Bridge.Is(RAINBOWBRIDGE_TOKENS)) { + tokens = std::max({ tokens, (int32_t)Settings::BridgeTokenCount.Value() }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_TOKENS)) { + tokens = std::max({ tokens, (int32_t)Settings::LACSTokenCount.Value() }); + } + return tokens; +} + +std::array conditionalAlwaysHints = { + std::make_pair(MARKET_10_BIG_POES, [](){ return Settings::BigPoeTargetCount.Value() >= 3; }), // Remember, the option's value being 3 means 4 are required + std::make_pair(DEKU_THEATER_MASK_OF_TRUTH, [](){ return !Settings::CompleteMaskQuest; }), + std::make_pair(SONG_FROM_OCARINA_OF_TIME, [](){ return StonesRequiredBySettings() < 2; }), + std::make_pair(HF_OCARINA_OF_TIME_ITEM, [](){ return StonesRequiredBySettings() < 2; }), + std::make_pair(SHEIK_IN_KAKARIKO, [](){ return MedallionsRequiredBySettings() < 5; }), + std::make_pair(DMT_TRADE_CLAIM_CHECK, [](){ return false; }), + std::make_pair(KAK_30_GOLD_SKULLTULA_REWARD, [](){ return TokensRequiredBySettings() < 30; }), + std::make_pair(KAK_40_GOLD_SKULLTULA_REWARD, [](){ return TokensRequiredBySettings() < 40; }), + std::make_pair(KAK_50_GOLD_SKULLTULA_REWARD, [](){ return TokensRequiredBySettings() < 50; }) +}; + +const HintText& Hint(const uint32_t hintKey) { + return hintTable[hintKey]; +} + +std::vector GetHintCategory(HintCategory category) { + + std::vector hintsInCategory = {}; + + for (const auto& hint : hintTable) { + if (hint.GetType() == category) { + hintsInCategory.push_back(hint); + } + } + return hintsInCategory; +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.hpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.hpp new file mode 100644 index 000000000..f60297179 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "hints.hpp" +#include "keys.hpp" + +#include + +extern std::array hintTable; + +void HintTable_Init(); +const HintText& Hint(uint32_t hintKey); +std::vector GetHintCategory(HintCategory category); + +void HintTable_Init_Item(); +void HintTable_Init_Exclude_Overworld(); +void HintTable_Init_Exclude_Dungeon(); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_dungeon.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_dungeon.cpp new file mode 100644 index 000000000..ed54508ca --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_dungeon.cpp @@ -0,0 +1,1964 @@ +#include "../hint_list.hpp" + +void HintTable_Init_Exclude_Dungeon() { + /*-------------------------- + | DEKU TREE | + ---------------------------*/ + hintTable[DEKU_TREE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"in the #center of the Deku Tree# lies", /*french*/"#le coeur de l'Arbre Mojo# recèle", /*spanish*/"al #centro del Gran Árbol Deku# yace"}, + }); + + hintTable[DEKU_TREE_SLINGSHOT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #treasure guarded by a scrub# in the Deku Tree is", /*french*/"le #trésor protégé par une peste# dans l'Arbre Mojo est", /*spanish*/"un #deku del Gran Árbol Deku# esconde"}, + }); + + hintTable[DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #treasure guarded by a scrub# in the Deku Tree is", /*french*/"le #trésor protégé par une peste# dans l'Arbre Mojo est", /*spanish*/"un #deku del Gran Árbol Deku# esconde"}, + }); + + hintTable[DEKU_TREE_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#pillars of wood# in the Deku Tree lead to", /*french*/"les #piliers de bois# dans l'Arbre Mojo indiquent", /*spanish*/"los #salientes del Gran Árbol Deku# conducen a"}, + }); + + hintTable[DEKU_TREE_COMPASS_ROOM_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#pillars of wood# in the Deku Tree lead to", /*french*/"les #piliers de bois# dans l'Arbre Mojo indiquent", /*spanish*/"los #salientes del Gran Árbol Deku# conducen a"}, + }); + + hintTable[DEKU_TREE_BASEMENT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#webs in the Deku Tree# hide", /*french*/"les #toiles dans l'Arbre Mojo# cachent", /*spanish*/"entre #telarañas del Gran Árbol Deku# yace"}, + }); + + + hintTable[DEKU_TREE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"in the #center of the Deku Tree# lies", /*french*/"#le coeur de l'Arbre Mojo# recèle", /*spanish*/"al #centro del Gran Árbol Deku# yace"}, + }); + + hintTable[DEKU_TREE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #treasure guarded by a large spider# in the Deku Tree is", /*french*/"le #trésor protégé par une grosse araignée# dans l'Arbre Mojo est", /*spanish*/"una #gran araña del Gran Árbol Deku# esconde"}, + }); + + hintTable[DEKU_TREE_MQ_SLINGSHOT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#pillars of wood# in the Deku Tree lead to", /*french*/"les #piliers de bois# dans l'Arbre Mojo indiquent", /*spanish*/"los #salientes del Gran Árbol Deku# conducen a"}, + }); + + hintTable[DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST] = HintText::Exclude({ + //obscure text + Text{"#pillars of wood# in the Deku Tree lead to", /*french*/"les #piliers de bois# dans l'Arbre Mojo indiquent", /*spanish*/"los #salientes del Gran Árbol Deku# conducen a"}, + }); + + hintTable[DEKU_TREE_MQ_BASEMENT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#webs in the Deku Tree# hide", /*french*/"les #toiles dans l'Arbre Mojo# cachent", /*spanish*/"entre #telarañas del Gran Árbol Deku# yace"}, + }); + + hintTable[DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST] = HintText::Exclude({ + //obscure text + Text{"#magical fire in the Deku Tree# leads to", /*french*/"le #feu magique dans l'Arbre Mojo# éclaire", /*spanish*/"el #fuego mágico en el Gran Árbol Deku# conduce a"}, + }); + + hintTable[DEKU_TREE_QUEEN_GOHMA_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Parasitic Armored Arachnid# holds", /*french*/"le #monstre insectoïde géant# possède", /*spanish*/"el #arácnido parasitario acorazado# porta"}, + }, {}, + //clear text + Text{"#Queen Gohma# holds", /*french*/"la #Reine Gohma# possède", /*spanish*/"la #Reina Goma# porta"} + ); + + hintTable[DEKU_TREE_GS_BASEMENT_BACK_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider deep within the Deku Tree# hides", /*french*/"une #Skulltula au coeur de l'Arbre Mojo# a", /*spanish*/"una #Skulltula en las profundidades del Árbol Deku# otorga"}, + }); + + hintTable[DEKU_TREE_GS_BASEMENT_GATE] = HintText::Exclude({ + //obscure text + Text{"a #web protects a spider# within the Deku Tree holding", /*french*/"une #Skulltula derrière une toile dans l'Arbre Mojo# a", /*spanish*/"una #Skulltula protegida por su tela# del Árbol Deku otorga"}, + }); + + hintTable[DEKU_TREE_GS_BASEMENT_VINES] = HintText::Exclude({ + //obscure text + Text{"a #web protects a spider# within the Deku Tree holding", /*french*/"une #Skulltula derrière une toile dans l'Arbre Mojo# a", /*spanish*/"una #Skulltula protegida por su tela# del Árbol Deku otorga"}, + }); + + hintTable[DEKU_TREE_GS_COMPASS_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider atop the Deku Tree# holds", /*french*/"une #Skulltula au sommet de l'Arbre Mojo# a", /*spanish*/"una #Skulltula en lo alto del Árbol Deku# otorga"}, + }); + + + hintTable[DEKU_TREE_MQ_GS_LOBBY] = HintText::Exclude({ + //obscure text + Text{"a #spider in a crate# within the Deku Tree hides", /*french*/"une #Skulltula dans une boîte dans l'Arbre Mojo# a", /*spanish*/"una #Skulltula bajo una caja# del Árbol Deku otorga"}, + }); + + hintTable[DEKU_TREE_MQ_GS_COMPASS_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #wall of rock protects a spider# within the Deku Tree holding", /*french*/"une #Skulltula derrière des rochers dans l'Arbre Mojo# a", /*spanish*/"una #Skulltula protegida por una pared rocosa# del Árbol Deku otorga"}, + }); + + hintTable[DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider deep within the Deku Tree# hides", /*french*/"une #Skulltula au coeur de l'Arbre Mojo# a", /*spanish*/"una #Skulltula en las profundidades del Árbol Deku# otorga"}, + }); + + hintTable[DEKU_TREE_MQ_DEKU_SCRUB] = HintText::Exclude({ + //obscure text + Text{"a #scrub in the Deku Tree# sells", /*french*/"la #peste Mojo dans l'Arbre Mojo# vend", /*spanish*/"un #deku del Gran Árbol Deku# vende"}, + }); + + /*-------------------------- + | DODONGOS CAVERN | + ---------------------------*/ + hintTable[DODONGOS_CAVERN_BOSS_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#above King Dodongo# lies", /*french*/"#par dessus le Roi Dodongo# gît", /*spanish*/"#sobre el Rey Dodongo# yace"}, + }); + + hintTable[DODONGOS_CAVERN_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #muddy wall in Dodongo's Cavern# hides", /*french*/"le #mur fragile dans la Caverne Dodongo# recèle", /*spanish*/"tras una #agrietada pared en la Cueva de los Dodongos# yace"}, + }); + + hintTable[DODONGOS_CAVERN_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #statue in Dodongo's Cavern# guards", /*french*/"la #statue dans la Caverne Dodongo# protège", /*spanish*/"una #estatua de la Cueva de los Dodongos# esconde"}, + }); + + hintTable[DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST] = HintText::Exclude({ + //obscure text + Text{"above a #maze of stone# in Dodongo's Cavern lies", /*french*/"sur #un labyrinthe de pierre# dans la Caverne Dodongo gît", /*spanish*/"entre un #laberinto de piedra# en la Cueva de los Dodongos yace"}, + }); + + hintTable[DODONGOS_CAVERN_BOMB_BAG_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #second lizard cavern battle# yields", /*french*/"le #deuxième duel de lézards de caverne# octroie", /*spanish*/"#luchar dos veces contra reptiles en una cueva# conduce a"}, + }); + + hintTable[DODONGOS_CAVERN_END_OF_BRIDGE_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest at the end of a bridge# yields", /*french*/"le #trésor à l'extrémité d'un pont# contient", /*spanish*/"un #cofre al final de un quebrado puente# contiene"}, + }); + + + hintTable[DODONGOS_CAVERN_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #muddy wall in Dodongo's Cavern# hides", /*french*/"le #mur fragile dans la Caverne Dodongo# recèle", /*spanish*/"una #agrietada pared en la Cueva de los Dodongos# esconde"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #elevated alcove# in Dodongo's Cavern holds", /*french*/"l'#alcove haut perchée# dans la Caverne Dodongo cache", /*spanish*/"una #elevada alcoba# en la Cueva de los Dodongos brinda"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#fire-breathing lizards# in Dodongo's Cavern guard", /*french*/"les #lézards cracheurs de feu# dans la Caverne Dodongo protègent", /*spanish*/"unos #flamígeros reptiles# en la Cueva de los Dodongos esconden"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#baby spiders# in Dodongo's Cavern guard", /*french*/"les #petites araignées dans la Caverne Dodongo# protègent", /*spanish*/"unas #pequeñas larvas# en la Cueva de los Dodongos esconden"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"above a #maze of stone# in Dodongo's Cavern lies", /*french*/"sur #un labyrinthe de pierre# dans la Caverne Dodongo gît", /*spanish*/"sobre un #laberinto de piedra# en la Cueva de los Dodongos yace"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#beneath a headstone# in Dodongo's Cavern lies", /*french*/"#sous une pierre tombale# dans la Caverne Dodongo gît", /*spanish*/"#bajo una lápida# en la Cueva de los Dodongos yace"}, + }); + + hintTable[DODONGOS_CAVERN_KING_DODONGO_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Infernal Dinosaur# holds", /*french*/"le #dinosaure infernal# possède", /*spanish*/"el #dinosaurio infernal# porta"}, + }, {}, + //clear text + Text{"#King Dodongo# holds", /*french*/"le #Roi Dodongo# possède", /*spanish*/"el #Rey Dodongo# porta"} + ); + + hintTable[DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS] = HintText::Exclude({ + //obscure text + Text{"a #spider entangled in vines# in Dodongo's Cavern guards", /*french*/"une #Skulltula sur les vignes dans la Caverne Dodongo# a", /*spanish*/"una #Skulltula sobre unas cepas# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_GS_SCARECROW] = HintText::Exclude({ + //obscure text + Text{"a #spider among explosive slugs# hides", /*french*/"une #Skulltula dans l'alcove du couloir dans la Caverne Dodongo# a", /*spanish*/"una #Skulltula rodeada de explosivos gusanos# otorga"}, + }); + + hintTable[DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS] = HintText::Exclude({ + //obscure text + Text{"a #spider just out of reach# in Dodongo's Cavern holds", /*french*/"une #Skulltula au haut des escaliers de la Caverne Dodongo# a", /*spanish*/"una #Skulltula fuera del alcance# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_GS_BACK_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider behind a statue# in Dodongo's Cavern holds", /*french*/"une #Skulltula au coeur de la Caverne Dodongo# a", /*spanish*/"una #Skulltula tras una estatua# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS] = HintText::Exclude({ + //obscure text + Text{"a #spider among bats# in Dodongo's Cavern holds", /*french*/"une #Skulltula entourée de Saigneurs dans la Caverne Dodongo# a", /*spanish*/"una #Skulltula rodeada de murciélagos# de la Cueva de los Dodongos otorga"}, + }); + + + hintTable[DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider high on a wall# in Dodongo's Cavern holds", /*french*/"une #Skulltula haut perchée dans la Caverne Dodongo# a", /*spanish*/"una #Skulltula en lo alto de una pared# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider on top of a pillar of rock# in Dodongo's Cavern holds", /*french*/"une #Skulltula sur l'énorme pilier de roc de la Caverne Dodongo# a", /*spanish*/"una #Skulltula en lo alto de un pilar# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider in a crate# in Dodongo's Cavern holds", /*french*/"une #Skulltula dans une boîte de la Caverne Dodongo# a", /*spanish*/"una #Skulltula bajo una caja# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_GS_BACK_AREA] = HintText::Exclude({ + //obscure text + Text{"a #spider among graves# in Dodongo's Cavern holds", /*french*/"une #Skulltula parmi les tombes de la Caverne Dodongo# a", /*spanish*/"una #Skulltula entre lápidas# en la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in Dodongo's Cavern# sells", /*french*/"le #duo de peste Mojo dans la Caverne Dodongo# vend", /*spanish*/"un #par de dekus en la Cueva de los Dodongos# venden"}, + }); + + hintTable[DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS] = HintText::Exclude({ + //obscure text + Text{"a #scrub guarded by Lizalfos# sells", /*french*/"la #peste Mojo au coeur de la Caverne Dodongo# vend", /*spanish*/"un #deku custodiado por Lizalfos# vende"}, + }); + + hintTable[DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in Dodongo's Cavern# sells", /*french*/"le #duo de peste Mojo dans la Caverne Dodongo# vend", /*spanish*/"un #par de dekus en la Cueva de los Dodongos# venden"}, + }); + + hintTable[DODONGOS_CAVERN_DEKU_SCRUB_LOBBY] = HintText::Exclude({ + //obscure text + Text{"a #scrub in Dodongo's Cavern# sells", /*french*/"la #peste Mojo dans l'entrée de la Caverne Dodongo# vend", /*spanish*/"un #deku en la Cueva de los Dodongos# vende"}, + }); + + + hintTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in Dodongo's Cavern# sells", /*french*/"le #duo de peste Mojo dans l'entrée de la Caverne Dodongo# vend", /*spanish*/"un #par de dekus en la Cueva de los Dodongos# venden"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in Dodongo's Cavern# sells", /*french*/"le #duo de peste Mojo dans l'entrée de la Caverne Dodongo# vend", /*spanish*/"un #par de dekus en la Cueva de los Dodongos# venden"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE] = HintText::Exclude({ + //obscure text + Text{"a #scrub in Dodongo's Cavern# sells", /*french*/"la #peste Mojo au sommet des escaliers dans la Caverne Dodongo# vend", /*spanish*/"un #deku en la Cueva de los Dodongos# vende"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS] = HintText::Exclude({ + //obscure text + Text{"a #scrub guarded by Lizalfos# sells", /*french*/"la #peste Mojo au coeur de la Caverne Dodongo# vend", /*spanish*/"un #deku custodiado por Lizalfos# vende"}, + }); + + /*-------------------------- + | JABU JABUS BELLY | + ---------------------------*/ + hintTable[JABU_JABUS_BELLY_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#tentacle trouble# in a deity's belly guards", /*french*/"la #membrane# dans le ventre du gardien protège", /*spanish*/"un #problema tentaculoso# en la tripa de cierta deidad esconde"}, + }, {}, + //clear text + Text{"a #slimy thing# guards", /*french*/"la #chose gluante# gardien protège", /*spanish*/"un #tentáculo parasitario# protege"} + ); + + hintTable[JABU_JABUS_BELLY_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#bubble trouble# in a deity's belly guards", /*french*/"un #horde de bulles# dans le ventre du gardien protègent", /*spanish*/"un #problema burbujesco# en la tripa de cierta deidad esconde"}, + }, {}, + //clear text + Text{"#bubbles# guard", /*french*/"des #bulles# entourent", /*spanish*/"unas #burbujas# protegen"} + ); + + + hintTable[JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"shooting a #mouth cow# reveals", /*french*/"tirer sur une #vache# révèle", /*spanish*/"#dispararle a una vaca# revela"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#pop rocks# hide", /*french*/"des #pierres aux reins# cachent", /*spanish*/"#cepillarse los dientes con explosivos# revela"}, + Text{"an #explosive palate# holds", /*french*/"des #gargouillis explosifs# cachent", /*spanish*/"un #paladar explosivo# esconde"}, + }, {}, + //clear text + Text{"a #boulder before cows# hides", /*french*/"des #rochers près des vaches# cachent", /*spanish*/"cierta #roca rodeada de vacas# esconde"} + ); + + hintTable[JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"near a #spiked elevator# lies", /*french*/"près d'un #ascenseur visqueux# gît", /*spanish*/"cerca de un #ascensor puntiagudo# yace"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #drowning cow# unveils", /*french*/"une #vache à l'eau# a", /*spanish*/"una #vaca sumergida# revela"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#moving anatomy# creates a path to", /*french*/"un #organe descendant# mène à", /*spanish*/"un #ser movedizo entre paredes# conduce a"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #pair of digested cows# hold", /*french*/"#deux boeufs digérés# détiennent", /*spanish*/"un #par de digeridas vacas# otorgan"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #pair of digested cows# hold", /*french*/"#deux boeufs digérés# détiennent", /*spanish*/"un #par de digeridas vacas# otorgan"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #final cows' reward# in a deity's belly is", /*french*/"le #cadeau des dernières vaches# estomacales est", /*spanish*/"las #vacas al final# de la tripa de cierta deidad otorgan"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#cows protected by falling monsters# in a deity's belly guard", /*french*/"des #vaches protégées par des monstres tombants# cachent", /*spanish*/"unas #vacas custodiadas por monstruos del techo# de la tripa de cierta deidad otorgan"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST] = HintText::Exclude({ + //obscure text + Text{"a school of #stingers swallowed by a deity# guard", /*french*/"les #raies avallées par le gardien# protègent", /*spanish*/"unos #stingers engullidos por cierta deidad# guardan"}, + }, {}, + //clear text + Text{"a school of #stingers swallowed by Jabu-Jabu# guard", /*french*/"les #raies avallées par Jabu-Jabu# protègent", /*spanish*/"unos #stingers engullidos por Jabu-Jabu# guardan"} + ); + + hintTable[JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST] = HintText::Exclude({ + //obscure text + Text{"a school of #stingers swallowed by a deity# guard", /*french*/"les #raies avallées par le gardien# protègent", /*spanish*/"unos #stingers engullidos por cierta deidad# guardan"}, + }, {}, + //clear text + Text{"a school of #stingers swallowed by Jabu-Jabu# guard", /*french*/"les #raies avallées par Jabu-Jabu# protègent", /*spanish*/"unos #stingers engullidos por Jabu-Jabu# guardan"} + ); + + hintTable[JABU_JABUS_BELLY_BARINADE_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Bio-Electric Anemone# holds", /*french*/"l'#anémone bioélectrique# possède", /*spanish*/"la #anémona bioeléctrica# porta"}, + }, {}, + //clear text + Text{"#Barinade# holds", /*french*/"#Barinade# possède", /*spanish*/"#Barinade# porta"} + ); + + hintTable[JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER] = HintText::Exclude({ + //obscure text + Text{"a #spider resting near a princess# in Jabu-Jabu's Belly holds", /*french*/"une #Skulltula près de la princesse dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula junto a una princesa# en la Tripa de Jabu-Jabu otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER] = HintText::Exclude({ + //obscure text + Text{"a #spider resting near a princess# in Jabu-Jabu's Belly holds", /*french*/"une #Skulltula près de la princesse dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula junto a una princesa# en la Tripa de Jabu-Jabu otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_GS_NEAR_BOSS] = HintText::Exclude({ + //obscure text + Text{"#jellyfish surround a spider# holding", /*french*/"une #Skulltula entourée de méduses dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula rodeada de medusas# otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider guarded by a school of stingers# in Jabu-Jabu's Belly holds", /*french*/"une #Skulltula protégée par des raies dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula rodeada por unos stingers# en la Tripa de Jabu-Jabu otorga"}, + }); + + + hintTable[JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider surrounded by electricity# in Jabu-Jabu's Belly holds", /*french*/"une #Skulltula entourée d'électricité dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula rodeada de electricidad# en la Tripa de Jabu-Jabu otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider guarded by a school of stingers# in Jabu-Jabu's Belly holds", /*french*/"une #Skulltula protégée par des raies dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula protegida por unos stingers# en la Tripa de Jabu-Jabu otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS] = HintText::Exclude({ + //obscure text + Text{"a #spider in a web within Jabu-Jabu's Belly# holds", /*french*/"une #Skulltula sur une toile dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula sobre una red# en la Tripa de Jabu-Jabu otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_DEKU_SCRUB] = HintText::Exclude({ + //obscure text + Text{"a #scrub in a deity# sells", /*french*/"la #peste Mojo dans le ventre du gardien# vend", /*spanish*/"un #deku dentro de cierta deidad# vende"}, + }); + + /*-------------------------- + | FOREST TEMPLE | + ---------------------------*/ + hintTable[FOREST_TEMPLE_FIRST_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #tree in the Forest Temple# supports", /*french*/"sur l'#arbre dans le Temple de la Forêt# gît", /*spanish*/"sobre un #árbol del Templo del Bosque# yace"}, + }); + + hintTable[FOREST_TEMPLE_FIRST_STALFOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#defeating enemies beneath a falling ceiling# in Forest Temple yields", /*french*/"#deux squelettes# dans le Temple de la Forêt protègent", /*spanish*/"#derrotar enemigos caídos de lo alto# del Templo del Bosque revela"}, + }); + + hintTable[FOREST_TEMPLE_WELL_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #sunken chest deep in the woods# contains", /*french*/"le #coffre submergé dans la forêt# contient", /*spanish*/"un #sumergido cofre en lo profundo del bosque# contiene"}, + }); + + hintTable[FOREST_TEMPLE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #fiery skull# in Forest Temple guards", /*french*/"le #crâne enflammé# dans le Temple de la Forêt protège", /*spanish*/"una #ardiente calavera# del Templo del Bosque esconde"}, + }); + + hintTable[FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest on a small island# in the Forest Temple holds", /*french*/"le #coffre sur l'îlot# du Temple de la Forêt contient", /*spanish*/"un #cofre sobre una isla# del Templo del Bosque contiene"}, + }); + + hintTable[FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"beneath a #checkerboard falling ceiling# lies", /*french*/"sous #l'échiquier tombant# gît", /*spanish*/"tras un #techo de ajedrez# yace"}, + }); + + hintTable[FOREST_TEMPLE_EYE_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #sharp eye# will spot", /*french*/"l'#oeil perçant# dans la forêt verra", /*spanish*/"un #afilado ojo# revela"}, + }, {}, + //clear text + Text{"#blocks of stone# in the Forest Temple surround", /*french*/"les #blocs dans le Temple de la Forêt# entourent", /*spanish*/"cerca de unos #bloques de piedra# del Templo del Bosque yace"} + ); + + hintTable[FOREST_TEMPLE_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #turned trunk# contains", /*french*/"le #coffre pivoté# contient", /*spanish*/"en una #sala con otro punto de vista# se esconde"}, + }); + + hintTable[FOREST_TEMPLE_FLOORMASTER_CHEST] = HintText::Exclude({ + //obscure text + Text{"deep in the forest #shadows guard a chest# containing", /*french*/"l'#ombre de la forêt# protège un coffre contenant", /*spanish*/"en lo profundo del bosque #unas sombras# esconden"}, + }); + + hintTable[FOREST_TEMPLE_BOW_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #army of the dead# guards", /*french*/"des #squelettes sylvestres# protègent", /*spanish*/"un #ejército de soldados caídos# guarda"}, + }, {}, + //clear text + Text{"#Stalfos deep in the Forest Temple# guard", /*french*/"#trois squelettes dans le Temple de la Forêt# protègent", /*spanish*/"los #Stalfos en lo profundo del Templo del Bosque# guardan"} + ); + + hintTable[FOREST_TEMPLE_RED_POE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Joelle# guards", /*french*/"#Joelle# protège", /*spanish*/"#Joelle# guarda"}, + }, {}, + //clear text + Text{"a #red ghost# guards", /*french*/"le #fantôme rouge# protège", /*spanish*/"un #espectro rojo# guarda"} + ); + + hintTable[FOREST_TEMPLE_BLUE_POE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Beth# guards", /*french*/"#Beth# protège", /*spanish*/"#Beth# guarda"}, + }, {}, + //clear text + Text{"a #blue ghost# guards", /*french*/"le #fantôme bleu# protège", /*spanish*/"un #espectro azul# guarda"} + ); + + hintTable[FOREST_TEMPLE_BASEMENT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#revolving walls# in the Forest Temple conceal", /*french*/"des #murs rotatifs dans la forêt# recèlent", /*spanish*/"las #paredes giratorias# del Templo del Bosque conceden"}, + }); + + + hintTable[FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #tree in the Forest Temple# supports", /*french*/"sur l'#arbre dans le Temple de la Forêt# gît", /*spanish*/"sobre un #árbol del Templo del Bosque# yace"}, + }); + + hintTable[FOREST_TEMPLE_MQ_WOLFOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#defeating enemies beneath a falling ceiling# in Forest Temple yields", /*french*/"#deux squelettes# dans le Temple de la Forêt protègent", /*spanish*/"#derrotar enemigos caídos de lo alto# del Templo del Bosque revela"}, + }); + + hintTable[FOREST_TEMPLE_MQ_BOW_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #army of the dead# guards", /*french*/"des #squelettes sylvestres# protègent", /*spanish*/"un #ejército de soldados caídos# guarda"}, + }, {}, + //clear text + Text{"#Stalfos deep in the Forest Temple# guard", /*french*/"#trois squelettes dans le Temple de la Forêt# protègent", /*spanish*/"los #Stalfos en lo profundo del Templo del Bosque# guardan"} + ); + + hintTable[FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest on a small island# in the Forest Temple holds", /*french*/"le #coffre sur l'îlot# du Temple de la Forêt contient", /*spanish*/"un #cofre sobre una isla# del Templo del Bosque contiene"}, + }); + + hintTable[FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#high in a courtyard# within the Forest Temple is", /*french*/"#haut perché dans le jardin# du Temple de la Forêt gît", /*spanish*/"un #cofre en lo alto de un patio# del Templo del Bosque contiene"}, + }); + + hintTable[FOREST_TEMPLE_MQ_WELL_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #sunken chest deep in the woods# contains", /*french*/"le #coffre submergé dans la forêt# contient", /*spanish*/"un #sumergido cofre en lo profundo del bosque# contiene"}, + }); + + hintTable[FOREST_TEMPLE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Joelle# guards", /*french*/"#Joelle# protège", /*spanish*/"#Joelle# guarda"}, + }, {}, + //clear text + Text{"a #red ghost# guards", /*french*/"le #fantôme rouge# protège", /*spanish*/"un #fantasma rojo# guarda"} + ); + + hintTable[FOREST_TEMPLE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Beth# guards", /*french*/"#Beth# protège", /*spanish*/"#Beth# guarda"}, + }, {}, + //clear text + Text{"a #blue ghost# guards", /*french*/"le #fantôme bleu# protège", /*spanish*/"un #fantasma azul# guarda"} + ); + + hintTable[FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"beneath a #checkerboard falling ceiling# lies", /*french*/"sous #l'échiquier tombant# gît", /*spanish*/"tras un #techo de ajedrez# yace"}, + }); + + hintTable[FOREST_TEMPLE_MQ_BASEMENT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#revolving walls# in the Forest Temple conceal", /*french*/"des #murs rotatifs dans la forêt# recèlent", /*spanish*/"las #paredes giratorias# del Templo del Bosque conceden"}, + }); + + hintTable[FOREST_TEMPLE_MQ_REDEAD_CHEST] = HintText::Exclude({ + //obscure text + Text{"deep in the forest #undead guard a chest# containing", /*french*/"des #revenants dans le Temple de la Forêt# protègent", /*spanish*/"en lo profundo del bosque #guardias del más allá# guardan"}, + }); + + hintTable[FOREST_TEMPLE_MQ_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #turned trunk# contains", /*french*/"le #coffre pivoté# contient", /*spanish*/"en una #sala con otro punto de vista# se esconde"}, + }); + + hintTable[FOREST_TEMPLE_PHANTOM_GANON_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Evil Spirit from Beyond# holds", /*french*/"l'#esprit maléfique de l'au-delà# possède", /*spanish*/"el #espíritu maligno de ultratumba# porta"}, + }, {}, + //clear text + Text{"#Phantom Ganon# holds", /*french*/"#Ganon Spectral# possède", /*spanish*/"#Ganon Fantasma# porta"} + ); + + hintTable[FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD] = HintText::Exclude({ + //obscure text + Text{"a #spider on a small island# in the Forest Temple holds", /*french*/"une #Skulltula sur l'îlot du Temple de la Forêt# a", /*spanish*/"una #Skulltula sobre una pequeña isla# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_GS_FIRST_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider high on a wall of vines# in the Forest Temple holds", /*french*/"une #Skulltula sur un mur de vignes du Temple de la Forêt# a", /*spanish*/"una #Skulltula en lo alto de una pared de cepas# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD] = HintText::Exclude({ + //obscure text + Text{"#stone columns# lead to a spider in the Forest Temple hiding", /*french*/"une #Skulltula haut perchée dans le jardin du Temple de la Forêt# a", /*spanish*/"unas #columnas del Templo del Bosque# conducen a una Skulltula que otorga"}, + }); + + hintTable[FOREST_TEMPLE_GS_LOBBY] = HintText::Exclude({ + //obscure text + Text{"a #spider among ghosts# in the Forest Temple guards", /*french*/"une #Skulltula dans la grande salle du Temple de la Forêt# a", /*spanish*/"una #Skulltula rodeada de fantasmas# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_GS_BASEMENT] = HintText::Exclude({ + //obscure text + Text{"a #spider within revolving walls# in the Forest Temple holds", /*french*/"une #Skulltula derrière les murs pivotants du Temple de la Forêt# a", /*spanish*/"una #Skulltula entre paredes giratorias# del Templo del Bosque otorga"}, + }); + + + hintTable[FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY] = HintText::Exclude({ + //obscure text + Text{"an #ivy-hidden spider# in the Forest Temple hoards", /*french*/"une #Skulltula près de l'entrée du Temple de la Forêt# a", /*spanish*/"una #Skulltula escondida entre cepas# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider in a hidden nook# within the Forest Temple holds", /*french*/"une #Skulltula dans un recoin caché du Temple de la Forêt# a", /*spanish*/"una #Skulltula en una esquina oculta# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD] = HintText::Exclude({ + //obscure text + Text{"a #spider on an arch# in the Forest Temple holds", /*french*/"une #Skulltula sur une arche du Temple de la Forêt# a", /*spanish*/"una #Skulltula sobre un arco# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD] = HintText::Exclude({ + //obscure text + Text{"a #spider on a ledge# in the Forest Temple holds", /*french*/"une #Skulltula dans le jardin du Temple de la Forêt# a", /*spanish*/"una #Skulltula en un borde# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_MQ_GS_WELL] = HintText::Exclude({ + //obscure text + Text{"#draining a well# in Forest Temple uncovers a spider with", /*french*/"une #Skulltula au fond du Puits du Temple de la Forêt# a", /*spanish*/"#vaciar el pozo# del Templo del Bosque desvela una Skulltula que otorga"}, + }); + + /*-------------------------- + | FIRE TEMPLE | + ---------------------------*/ + hintTable[FIRE_TEMPLE_NEAR_BOSS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#near a dragon# is", /*french*/"#près d'un dragon# gît", /*spanish*/"#cerca de un dragón# yace"}, + }); + + hintTable[FIRE_TEMPLE_FLARE_DANCER_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Flare Dancer behind a totem# guards", /*french*/"le #Danse-Flamme derrière un totem# protège", /*spanish*/"el #Bailafuego tras unos tótems# esconde"}, + }); + + hintTable[FIRE_TEMPLE_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #prison beyond a totem# holds", /*french*/"la #prison derrière un totem# contient", /*spanish*/"en una #prisión tras unos tótems# yace"}, + }); + + hintTable[FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST] = HintText::Exclude({ + //obscure text + Text{"#explosives over a lava pit# unveil", /*french*/"des #explosifs dans un lac de lave# révèlent", /*spanish*/"los #explosivos en un mar de llamas# revelan"}, + }); + + hintTable[FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron trapped near lava# holds", /*french*/"le #Goron emprisonné près de la lave# a", /*spanish*/"un #goron atrapado cerca de un mar de llamas# guarda"}, + }); + + hintTable[FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron at the end of a maze# holds", /*french*/"le #Goron dans le labyrinthe# a", /*spanish*/"un #goron al final de un laberinto# guarda"}, + }); + + hintTable[FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron above a maze# holds", /*french*/"le #Goron au dessus du labyrinthe# a", /*spanish*/"un #goron sobre un laberinto# guarda"}, + }); + + hintTable[FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron hidden near a maze# holds", /*french*/"le #Goron caché près du labyrinthe# a", /*spanish*/"un #goron escondido tras un laberinto# guarda"}, + }); + + hintTable[FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #blocked path# in Fire Temple holds", /*french*/"un #sol fragile dans le Temple du Feu# contient", /*spanish*/"en un #camino bloqueado# del Templo del Fuego yace"}, + }); + + hintTable[FIRE_TEMPLE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #caged chest# in the Fire Temple hoards", /*french*/"un #coffre emprisonné# dans le Temple du Feu contient", /*spanish*/"un #cofre entre rejas# del Templo del Fuego contiene"}, + }); + + hintTable[FIRE_TEMPLE_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest in a fiery maze# contains", /*french*/"un #coffre dans un labyrinthe enflammé# contient", /*spanish*/"un #cofre de un ardiente laberinto# contiene"}, + }); + + hintTable[FIRE_TEMPLE_HIGHEST_GORON_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron atop the Fire Temple# holds", /*french*/"le #Goron au sommet du Temple du Feu# a", /*spanish*/"un #goron en lo alto del Templo del Fuego# guarda"}, + }); + + + hintTable[FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#near a dragon# is", /*french*/"#près d'un dragon# gît", /*spanish*/"#cerca de un dragón# yace"}, + }); + + hintTable[FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Flare Dancer in the depths of a volcano# guards", /*french*/"le #Danse-Flamme au coeur du volcan# a", /*spanish*/"el #Bailafuego en lo profundo del volcán# esconde"}, + }, {}, + //clear text + Text{"the #Flare Dancer in the depths of the Fire Temple# guards", /*french*/"le #Danse-Flamme au coeur du volcan# a", /*spanish*/"el #Bailafuego en lo profundo del Templo del Fuego# esconde"} + ); + + hintTable[FIRE_TEMPLE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #blocked path# in Fire Temple holds", /*french*/"le #chemin scellé# dans le Temple du Feu contient", /*spanish*/"en un #camino bloqueado# del Templo del Fuego yace"}, + }); + + hintTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#crates in a maze# contain", /*french*/"des #boîtes dans le labyrinthe# contiennent", /*spanish*/"las #cajas de un laberinto# contienen"}, + }); + + hintTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#crates in a maze# contain", /*french*/"des #boîtes dans le labyrinthe# contiennent", /*spanish*/"las #cajas de un laberinto# contienen"}, + }); + + hintTable[FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #falling slug# in the Fire Temple guards", /*french*/"la #limace tombante# dans le Temple du Feu protège", /*spanish*/"una #babosa del techo# del Templo del Fuego guarda"}, + }); + + hintTable[FIRE_TEMPLE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"using a #hammer in the depths of the Fire Temple# reveals", "frapper du #marteau au coeur du volcan# révèle", /*spanish*/"usar el #martillo en lo profundo del Templo del Fuego# revela"}, + }); + + hintTable[FIRE_TEMPLE_MQ_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#illuminating a lava pit# reveals the path to", /*french*/"#éclairer le lac de lave# révèle", /*spanish*/"#iluminar un mar de llamas# revela"}, + }); + + hintTable[FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST] = HintText::Exclude({ + //obscure text + Text{"#explosives over a lava pit# unveil", /*french*/"des #explosifs dans un lac de lave# révèlent", /*spanish*/"los #explosivos en un mar de llamas# revelan"}, + }); + + hintTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron hidden near a maze# holds", /*french*/"le #Goron caché près du labyrinthe# a", /*spanish*/"un #goron cerca de un laberinto# guarda"}, + }); + + hintTable[FIRE_TEMPLE_MQ_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"hidden #beneath a block of stone# lies", /*french*/"caché #derrière un bloc de pierre# gît", /*spanish*/"#bajo unos bloques de piedra# yace"}, + }); + + hintTable[FIRE_TEMPLE_VOLVAGIA_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Subterranean Lava Dragon# holds", /*french*/"le #dragon des profondeurs# possède", /*spanish*/"el #dragón de lava subterráneo# porta"}, + }, {}, + //clear text + Text{"#Volvagia# holds", /*french*/"#Volvagia# possède", /*spanish*/"#Volvagia# porta"} + ); + + hintTable[FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM] = HintText::Exclude({ + //obscure text + Text{"#eight tiles of malice# guard a spider holding", /*french*/"une #Skulltula protégée par huit tuiles dans le Temple du Feu# a", /*spanish*/"#ocho baldosas de maldad# custodian una Skulltula que otorga"}, + }); + + hintTable[FIRE_TEMPLE_GS_BOSS_KEY_LOOP] = HintText::Exclude({ + //obscure text + Text{"#five tiles of malice# guard a spider holding", /*french*/"une #Skulltula protégée par cinq tuiles dans le Temple du Feu# a", /*spanish*/"#cinco baldosas de maldad# custodian una Skulltula que otorga"}, + }); + + hintTable[FIRE_TEMPLE_GS_BOULDER_MAZE] = HintText::Exclude({ + //obscure text + Text{"#explosives in a maze# unveil a spider hiding", /*french*/"une #Skulltula derrière un mur fragile du Temple du Feu# a", /*spanish*/"los #explosivos en un laberinto# desvelan una Skulltula que otorga"}, + }); + + hintTable[FIRE_TEMPLE_GS_SCARECROW_TOP] = HintText::Exclude({ + //obscure text + Text{"a #spider-friendly scarecrow# atop a volcano hides", /*french*/"une #Skulltula repérée par l'épouvantail du volcan# a", /*spanish*/"un #espantapájaros en lo alto de un volcán# custodia una Skulltula que otorga"}, + }, {}, + //clear text + Text{"a #spider-friendly scarecrow# atop the Fire Temple hides", /*french*/"une #Skulltula repérée par l'épouvantail du Temple du Feu# a", /*spanish*/"un #espantapájaros del Templo del Fuego# custodia una Skulltula que otorga"} + ); + + hintTable[FIRE_TEMPLE_GS_SCARECROW_CLIMB] = HintText::Exclude({ + //obscure text + Text{"a #spider-friendly scarecrow# atop a volcano hides", /*french*/"une #Skulltula repérée par l'épouvantail du volcan# a", /*spanish*/"un #espantapájaros en lo alto de un volcán# custodia una Skulltula que otorga"}, + }, {}, + //clear text + Text{"a #spider-friendly scarecrow# atop the Fire Temple hides", /*french*/"une #Skulltula repérée par l'épouvantail du Temple du Feu# a", /*spanish*/"un #espantapájaros del Templo del Fuego# custodia una Skulltula que otorga"} + ); + + + hintTable[FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE] = HintText::Exclude({ + //obscure text + Text{"a #spider above a fiery maze# holds", /*french*/"une #Skulltula au dessus du labyrinthe enflammé du Temple du Feu# a", /*spanish*/"una #Skulltula sobre un ardiente laberinto# otorga"}, + }); + + hintTable[FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER] = HintText::Exclude({ + //obscure text + Text{"a #spider within a fiery maze# holds", /*french*/"une #Skulltula dans le labyrinthe enflammé du Temple du Feu# a", /*spanish*/"una #Skulltula en el interior de un ardiente laberinto# otorga"}, + }); + + hintTable[FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR] = HintText::Exclude({ + //obscure text + Text{"a #Goron trapped near lava# befriended a spider with", /*french*/"une #Skulltula emprisonnée près du lac de lave du Temple du Feu# a", /*spanish*/"una #Skulltula amiga de un Goron atrapado junto a la lava# otorga"}, + }); + + hintTable[FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider beside a fiery maze# holds", /*french*/"une #Skulltula près du labyrinthe enflammé du Temple du Feu# a", /*spanish*/"una #Skulltula junto a un ardiente laberinto# otorga"}, + }); + + /*-------------------------- + | WATER TEMPLE | + ---------------------------*/ + hintTable[WATER_TEMPLE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#rolling spikes# in the Water Temple surround", /*french*/"des #Spikes# dans le Temple de l'Eau entourent", /*spanish*/"unas #rodantes púas# del Templo del Agua guardan"}, + }); + + hintTable[WATER_TEMPLE_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#roaming stingers in the Water Temple# guard", /*french*/"des #raies dans le Temple de l'Eau# protègent", /*spanish*/"unos #errantes stingers# del Templo del Agua guardan"}, + }); + + hintTable[WATER_TEMPLE_TORCHES_CHEST] = HintText::Exclude({ + //obscure text + Text{"#fire in the Water Temple# reveals", /*french*/"des #flammes dans le Temple de l'Eau# révèlent", /*spanish*/"el #fuego en el Templo del Agua# revela"}, + }); + + hintTable[WATER_TEMPLE_DRAGON_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #serpent's prize# in the Water Temple is", /*french*/"la #récompense du dragon submergé# est", /*spanish*/"el #escamado premio# del Templo del Agua se trata de"}, + }); + + hintTable[WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST] = HintText::Exclude({ + //obscure text + Text{"#blinding an eye# in the Water Temple leads to", /*french*/"#l'oeil# du Temple de l'Eau voit", /*spanish*/"#cegar un ojo# del Templo del Agua conduce a"}, + }); + + hintTable[WATER_TEMPLE_CENTRAL_PILLAR_CHEST] = HintText::Exclude({ + //obscure text + Text{"in the #depths of the Water Temple# lies", /*french*/"le #coeur du Temple de l'Eau# cache", /*spanish*/"en las #profundidades del Templo del Agua# yace"}, + }); + + hintTable[WATER_TEMPLE_CRACKED_WALL_CHEST] = HintText::Exclude({ + //obscure text + Text{"#through a crack# in the Water Temple is", /*french*/"le #mur fragile# du Temple de l'Eau cache", /*spanish*/"tras una #agrietada pared# del Templo del Agua yace"}, + }); + + hintTable[WATER_TEMPLE_LONGSHOT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#facing yourself# reveals", /*french*/"se #vaincre soi-même# révèle", /*spanish*/"#luchar contra ti mismo# revela"}, + Text{"a #dark reflection# of yourself guards", /*french*/"son #propre reflet# cache", /*spanish*/"el #oscuro reflejo de ti mismo# guarda"}, + }, {}, + //clear text + Text{"#Dark Link# guards", /*french*/"l'#Ombre de @# protège", /*spanish*/"#@ Oscuro# guarda"} + ); + + + hintTable[WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST] = HintText::Exclude({ + //obscure text + Text{"in the #depths of the Water Temple# lies", /*french*/"le #coeur du Temple de l'Eau# cache", /*spanish*/"en las #profundidades del Templo del Agua# yace"}, + }); + + hintTable[WATER_TEMPLE_MQ_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"fire in the Water Temple unlocks a #vast gate# revealing a chest with", /*french*/"des #flammes au coeur du Temple de l'Eau# révèlent", /*spanish*/"el fuego en el Templo del Agua alza una #gran valla# con"}, + }); + + hintTable[WATER_TEMPLE_MQ_LONGSHOT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#through a crack# in the Water Temple is", /*french*/"le #mur fragile# du Temple de l'Eau cache", /*spanish*/"tras una #agrietada pared# del Templo del Agua yace"}, + }); + + hintTable[WATER_TEMPLE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#fire in the Water Temple# reveals", /*french*/"des #flammes dans le Temple de l'Eau# révèlent", /*spanish*/"el #fuego en el Templo del Agua# revela"}, + }); + + hintTable[WATER_TEMPLE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#sparring soldiers# in the Water Temple guard", /*french*/"les #soldats du Temple de l'Eau# protègent", /*spanish*/"#acabar con unos soldados# del Templo del Agua revela"}, + }); + + hintTable[WATER_TEMPLE_MORPHA_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Giant Aquatic Amoeba# holds", /*french*/"l'#amibe aquatique géante# possède", /*spanish*/"la #ameba acuática gigante# porta"}, + }, {}, + //clear text + Text{"#Morpha# holds", /*french*/"#Morpha# possède", /*spanish*/"#Morpha# porta"} + ); + + hintTable[WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider over a waterfall# in the Water Temple holds", /*french*/"une #Skulltula au dessus d'une cascade du Temple de l'Eau# a", /*spanish*/"una #Skulltula tras una cascada# del Templo del Agua otorga"}, + }); + + hintTable[WATER_TEMPLE_GS_CENTRAL_PILLAR] = HintText::Exclude({ + //obscure text + Text{"a #spider in the center of the Water Temple# holds", /*french*/"une #Skulltula au centre du Temple de l'Eau# a", /*spanish*/"una #Skulltula en el centro del Templo del Agua# otorga"}, + }); + + hintTable[WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a spider protected by #rolling boulders under the lake# hides", /*french*/"une #Skulltula derrière les rochers roulants sous le lac# a", /*spanish*/"una #Skulltula protegida por rocas rodantes# bajo el lago otorga"}, + }, {}, + //clear text + Text{"a spider protected by #rolling boulders in the Water Temple# hides", /*french*/"une #Skulltula derrière les rochers roulants du Temple de l'Eau# a", /*spanish*/"una #Skulltula protegida por rocas rodantes# del Templo del Agua otorga"} + ); + + hintTable[WATER_TEMPLE_GS_RIVER] = HintText::Exclude({ + //obscure text + Text{"a #spider over a river# in the Water Temple holds", /*french*/"une #Skulltula au dessus de la rivière du Temple de l'Eau# a", /*spanish*/"una #Skulltula sobre un río# del Templo del Agua otorga"}, + }); + + + hintTable[WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH] = HintText::Exclude({ + //obscure text + Text{"#beyond a pit of lizards# is a spider holding", /*french*/"une #Skulltula près des lézards du Temple de l'Eau# a", /*spanish*/"#más allá de un pozo de reptiles# una Skulltula otorga"}, + }); + + hintTable[WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY] = HintText::Exclude({ + //obscure text + Text{"#lizards guard a spider# in the Water Temple with", /*french*/"une #Skulltula dans les couloirs croisés du Temple de l'Eau# a", /*spanish*/"unos #reptiles custodian una Skulltula# del Templo del Agua que otorga"}, + }); + + hintTable[WATER_TEMPLE_MQ_GS_RIVER] = HintText::Exclude({ + //obscure text + Text{"a #spider over a river# in the Water Temple holds", /*french*/"une #Skulltula au dessus de la rivière du Temple de l'Eau# a", /*spanish*/"una #Skulltula sobre un río# del Templo del Agua otorga"}, + }); + + /*-------------------------- + | SPIRIT TEMPLE | + ---------------------------*/ + hintTable[SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST] = HintText::Exclude({ + //obscure text + Text{"a child conquers a #skull in green fire# in the Spirit Temple to reach", /*french*/"le #crâne au halo vert dans le colosse# cache", /*spanish*/"el joven que #baje el puente# del Templo del Espíritu encontrará"}, + }); + + hintTable[SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST] = HintText::Exclude({ + //obscure text + Text{"a child can find a #caged chest# in the Spirit Temple with", /*french*/"le #coffre embarré dans le colosse# contient", /*spanish*/"un joven puede encontrar un #cofre entre rejas# del Templo del Espíritu con"}, + }); + + hintTable[SPIRIT_TEMPLE_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#across a pit of sand# in the Spirit Temple lies", /*french*/"le #trou sableux dans le colosse# a", /*spanish*/"tras un #pozo de arena# del Templo del Espíritu yace"}, + }); + + hintTable[SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#dodging boulders to collect silver rupees# in the Spirit Temple yields", /*french*/"les #pièces argentées entourées de rochers dans le colosse# révèlent", /*spanish*/"#esquivar rocas y conseguir plateadas rupias# en el Templo del Espíritu conduce a"}, + }); + + hintTable[SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #shadow circling reflected light# in the Spirit Temple guards", /*french*/"l'#ombre près d'un miroir# protège", /*spanish*/"un #círculo de reflectante luz# del Templo del Espíritu guarda"}, + }); + + hintTable[SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #shadow circling reflected light# in the Spirit Temple guards", /*french*/"l'#ombre près d'un miroir# protège", /*spanish*/"un #círculo de reflectante luz# del Templo del Espíritu guarda"}, + }); + + hintTable[SPIRIT_TEMPLE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#before a giant statue# in the Spirit Temple lies", /*french*/"#devant la statue# dans le colosse gît", /*spanish*/"#ante una gran estatua# del Templo del Espíritu aguarda"}, + }); + + hintTable[SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#lizards in the Spirit Temple# guard", /*french*/"les #lézards dans le colosse# protègent", /*spanish*/"los #reptiles del Templo del Espíritu# guardan"}, + }); + + hintTable[SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST] = HintText::Exclude({ + //obscure text + Text{"#lizards in the Spirit Temple# guard", /*french*/"les #lézards dans le colosse# protègent", /*spanish*/"los #reptiles del Templo del Espíritu# guardan"}, + }); + + hintTable[SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#torchlight among Beamos# in the Spirit Temple reveals", /*french*/"les #torches autour des Sentinelles# éclairent", /*spanish*/"las #antorchas junto a Beamos# del Templo del Espíritu revelan"}, + }); + + hintTable[SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #statue in the Spirit Temple# holds", /*french*/"la #statue dans le colosse# tient", /*spanish*/"una #estatua del Templo del Espíritu# esconde"}, + }); + + hintTable[SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST] = HintText::Exclude({ + //obscure text + Text{"on a #ledge by a statue# in the Spirit Temple rests", /*french*/"#haut perché près de la statue# dans le colosse gît", /*spanish*/"al #borde de una estatua# del Templo del Espíritu yace"}, + }); + + hintTable[SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"those who #show the light among statues# in the Spirit Temple find", /*french*/"le #soleil près des statues# cache", /*spanish*/"aquellos que #iluminen ante las estatuas# del Templo del Espíritu encontrarán"}, + }); + + hintTable[SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth in the Spirit Temple# reveals", /*french*/"le #trésor invisible près du Hache-Viande# contient", /*spanish*/"el #Ojo de la Verdad# en el Templo del Espíritu revela"}, + }); + + hintTable[SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth in the Spirit Temple# reveals", /*french*/"le #trésor invisible près du Hache-Viande# contient", /*spanish*/"el #Ojo de la Verdad# en el Templo del Espíritu revela"}, + }); + + hintTable[SPIRIT_TEMPLE_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest engulfed in flame# in the Spirit Temple holds", /*french*/"le #coffre enflammé dans le colosse# contient", /*spanish*/"un #cofre rodeado de llamas# del Templo del Espíritu contiene"}, + }); + + hintTable[SPIRIT_TEMPLE_TOPMOST_CHEST] = HintText::Exclude({ + //obscure text + Text{"those who #show the light above the Colossus# find", /*french*/"le #soleil au sommet du colosse# révèle", /*spanish*/"aquellos que #iluminen en lo alto del Coloso# encontrarán"}, + }); + + + hintTable[SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#lying unguarded# in the Spirit Temple is", /*french*/"dans #l'entrée du colosse# se trouve", /*spanish*/"en la #entrada del Templo del Espíritu# yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #switch in a pillar# within the Spirit Temple drops", /*french*/"l'#interrupteur dans un pilier# du colosse cache", /*spanish*/"el #interruptor de un pilar# del Templo del Espíritu revela"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#collecting rupees through a water jet# reveals", /*french*/"les #pièces argentées dans le jet d'eau# du colosse révèlent", /*spanish*/"#hacerte con rupias tras un géiser# revela"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #eye blinded by stone# within the Spirit Temple conceals", /*french*/"#l'oeil derrière le rocher# dans le colosse voit", /*spanish*/"#cegar a un ojo# del Templo del Espíritu revela"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"surrounded by #fire and wrappings# lies", /*french*/"près des #pierres tombales dans le colosse# gît", /*spanish*/"rodeado de #fuego y vendas# yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a child defeats a #gauntlet of monsters# within the Spirit Temple to find", /*french*/"l'enfant qui vainc #plusieurs monstres# dans le colosse trouvera", /*spanish*/"el joven que derrote #unos monstruos# del Templo del Espíritu encontrará"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#explosive sunlight# within the Spirit Temple uncovers", /*french*/"le #rayon de lumière explosif dans le colosse# révèle", /*spanish*/"una #explosiva luz solar# del Templo del Espíritu revela"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#trapped by falling enemies# within the Spirit Temple is", /*french*/"des #ennemis tombants# dans le colosse protègent", /*spanish*/"#rodeado de enemigos del cielo# del Templo del Espíritu yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#blinding the colossus# unveils", /*french*/"#l'oeil dans le colosse# voit", /*spanish*/"#cegar al coloso# revela"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #royal melody awakens the colossus# to reveal", /*french*/"la #mélodie royale éveille le colosse# et révèle", /*spanish*/"la #melodía real que despierte al coloso# revelará"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth# finds the colossus's hidden", /*french*/"#l'oeil de vérité# verra dans le colosse", /*spanish*/"el #Ojo de la Verdad# en el Templo del Espíritu encontrará"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#the old hide what the young find# to reveal", /*french*/"l'#oeil dans le trou du bloc argent# dans le colosse voit", /*spanish*/"el #adulto esconde lo que el joven anhela#, revelando"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#sunlight in a maze of fire# hides", /*french*/"#la lumière dans le labyrinthe de feu# du colosse révèle", /*spanish*/"la #luz solar de un ígneo laberinto# esconde"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#across a pit of sand# in the Spirit Temple lies", /*french*/"le #trou sableux# dans le colosse a", /*spanish*/"#a través del pozo de arena# del Templo del Espíritu yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"where #temporal stone blocks the path# within the Spirit Temple lies", /*french*/"les #pierres temporelles# dans le colosse cachent", /*spanish*/"donde los #bloques temporales bloquean# en el Templo del Espíritu yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest of double purpose# holds", /*french*/"le #coffre à usage double# du colosse contient", /*spanish*/"un #cofre de doble uso# contiene"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #temporal stone blocks the light# leading to", /*french*/"la #pierre temporelle# le colosse fait ombre sur", /*spanish*/"un #bloque temporal bloquea la luz# que conduce a"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"those who #show the light above the Colossus# find", /*french*/"le trésor invisible #au sommet du colosse# contient", /*spanish*/"aquellos que #revelen la luz sobre el Coloso# encontrarán"}, + }); + + hintTable[SPIRIT_TEMPLE_TWINROVA_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Sorceress Sisters# hold", /*french*/"#les sorcières jumelles# possède", /*spanish*/"las #hermanas hechiceras# portan"}, + }, {}, + //clear text + Text{"#Twinrova# holds", /*french*/"#Twinrova# possède", /*spanish*/"#Birova# porta"} + ); + + hintTable[SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM] = HintText::Exclude({ + //obscure text + Text{"a spider in the #hall of a knight# guards", /*french*/"une #Skulltula au dessus d'un escalier du Temple de l'Esprit# a", /*spanish*/"una #Skulltula en el salón de un guerrero# otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_GS_BOULDER_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider behind a temporal stone# in the Spirit Temple yields", /*french*/"une #Skulltula derrière une pierre temporelle du Temple de l'Esprit# a", /*spanish*/"una #Skulltula tras un bloque temporal# del Templo del Espíritu otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_GS_LOBBY] = HintText::Exclude({ + //obscure text + Text{"a #spider beside a statue# holds", /*french*/"une #Skulltula dans la grande salle du Temple de l'Esprit# a", /*spanish*/"una #Skulltula junto a una estatua# del Templo del Espíritu otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider at the top of a deep shaft# in the Spirit Temple holds", /*french*/"une #Skulltula près d'un mur d'escalade du Temple de l'Esprit# a", /*spanish*/"una #Skulltula en lo alto de un gran hueco# del Templo del Espíritu otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_GS_METAL_FENCE] = HintText::Exclude({ + //obscure text + Text{"a child defeats a #spider among bats# in the Spirit Temple to gain", /*french*/"une #Skulltula sur le grillage du Temple de l'Esprit# a", /*spanish*/"el joven que derrote la #Skulltula entre murciélagos# del Templo del Espíritu hallará"}, + }); + + + hintTable[SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM] = HintText::Exclude({ + //obscure text + Text{"#above a pit of sand# in the Spirit Temple hides", /*french*/"une #Skulltula au dessus du trou sableux du Temple de l'Esprit# a", /*spanish*/"una #Skulltula sobre un pozo de arena# del Templo del Espíritu otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST] = HintText::Exclude({ + //obscure text + Text{"a spider in the #hall of a knight# guards", /*french*/"une #Skulltula dans la salle aux neuf trônes du Temple de l'Esprit# a", /*spanish*/"una #Skulltula en el salón de un guerrero# otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH] = HintText::Exclude({ + //obscure text + Text{"a spider in the #hall of a knight# guards", /*french*/"une #Skulltula dans la salle aux neuf trônes du Temple de l'Esprit# a", /*spanish*/"una #Skulltula en el salón de un guerrero# otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM] = HintText::Exclude({ + //obscure text + Text{"#upon a web of glass# in the Spirit Temple sits a spider holding", /*french*/"une #Skulltula sur une paroi de verre du Temple de l'Esprit# a", /*spanish*/"#sobre una plataforma de cristal# yace una Skulltula que otorga"}, + }); + + /*-------------------------- + | SHADOW TEMPLE | + ---------------------------*/ + hintTable[SHADOW_TEMPLE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth# pierces a hall of faces to reveal", /*french*/"l'#oeil de vérité# voit dans les couloirs du Temple de l'Ombre", /*spanish*/"el #Ojo de la Verdad# descubrirá un pasillo de facetas con"}, + }); + + hintTable[SHADOW_TEMPLE_HOVER_BOOTS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #nether dweller in the Shadow Temple# holds", /*french*/"le #spectre du Temple de l'Ombre# a", /*spanish*/"un #temido morador del Templo de las Sombras# guarda"}, + }, {}, + //clear text + Text{"#Dead Hand in the Shadow Temple# holds", /*french*/"le #Poigneur dans le Temple de l'Ombre# cache", /*spanish*/"la #Mano Muerta del Templo de las Sombras# guarda"} + ); + + hintTable[SHADOW_TEMPLE_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies revealed by the Eye of Truth# guard", /*french*/"les #Gibdos dans les couloirs# du Temple de l'Ombre protègent", /*spanish*/"las #momias reveladas por el Ojo de la Verdad# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#spinning scythes# protect", /*french*/"les #faucheurs danseurs# du Temple de l'Ombre protègent", /*spanish*/"las #giratorias guadañas# protegen"}, + }); + + hintTable[SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#invisible blades# guard", /*french*/"les #faucheurs invisibles# du Temple de l'Ombre protègent", /*spanish*/"las #hojas invisibles# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#invisible blades# guard", /*french*/"les #faucheurs invisibles# du Temple de l'Ombre protègent", /*spanish*/"las #hojas invisibles# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #dead roam among invisible spikes# guarding", /*french*/"#parmi les clous invisibles# du Temple de l'Ombre se cache", /*spanish*/"los #muertos que vagan por pinchos invisibles# protegen"}, + }); + + hintTable[SHADOW_TEMPLE_WIND_HINT_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #invisible chest guarded by the dead# holds", /*french*/"le #trésor invisible du cul-de-sac# du Temple de l'Ombre contient", /*spanish*/"un #cofre invisible custodiado por los del más allá# contiene"}, + }); + + hintTable[SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies guarding a ferry# hide", /*french*/"les #Gibdos qui bloquent le traversier# cachent", /*spanish*/"las #momias que protegen un navío# esconden"}, + }); + + hintTable[SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies guarding a ferry# hide", /*french*/"les #Gibdos qui bloquent le traversier# cachent", /*spanish*/"las #momias que protegen un navío# esconden"}, + }); + + hintTable[SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#walls consumed by a ball of fire# reveal", /*french*/"le #piège de bois# du Temple de l'Ombre cache", /*spanish*/"las #paredes consumidas por una esfera ígnea# revelan"}, + }); + + hintTable[SHADOW_TEMPLE_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#walls consumed by a ball of fire# reveal", /*french*/"le #piège de bois# du Temple de l'Ombre cache", /*spanish*/"las #paredes consumidas por una esfera ígnea# revelan"}, + }); + + hintTable[SHADOW_TEMPLE_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"#inside a burning skull# lies", /*french*/"#dans un crâne enflammé# gît", /*spanish*/"en el #interior de una calavera en llamas# aguarda"}, + }); + + + hintTable[SHADOW_TEMPLE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth# pierces a hall of faces to reveal", /*french*/"l'#oeil de vérité# voit dans les couloirs du Temple de l'Ombre", /*spanish*/"el #Ojo de la Verdad# descubre un pasillo de facetas con"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Dead Hand in the Shadow Temple# holds", /*french*/"le #Poigneur dans le Temple de l'Ombre# cache", /*spanish*/"la #Mano Muerta del Templo de las Sombras# guarda"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies revealed by the Eye of Truth# guard", /*french*/"les #Gibdos dans les couloirs# du Temple de l'Ombre protègent", /*spanish*/"las #momias reveladas por el Ojo de la Verdad# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#spinning scythes# protect", /*french*/"les #faucheurs danseurs# du Temple de l'Ombre protègent", /*spanish*/"las #giratorias guadañas# protegen"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST] = HintText::Exclude({ + //obscure text + Text{"#collecting rupees in a vast cavern# with the Shadow Temple unveils", /*french*/"les #pièces argentées dans le Temple de l'Ombre# révèlent", /*spanish*/"hacerte con las #rupias en una gran caverna# del Templo de las Sombras revela"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #dead roam among invisible spikes# guarding", /*french*/"#parmi les clous invisibles# du Temple de l'Ombre se cache", /*spanish*/"los #muertos que vagan por pinchos invisibles# protegen"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#walls consumed by a ball of fire# reveal", /*french*/"le #piège de bois# du Temple de l'Ombre cache", /*spanish*/"las #paredes consumidas por una esfera ígnea# revelan"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#walls consumed by a ball of fire# reveal", /*french*/"le #piège de bois# du Temple de l'Ombre cache", /*spanish*/"las #paredes consumidas por una esfera ígnea# revelan"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"near an #empty pedestal# within the Shadow Temple lies", /*french*/"#près d'un pédestal vide du Temple de l'Ombre# gît", /*spanish*/"cerca de un #vacío pedestal# del Templo de las Sombras yace"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#invisible blades# guard", /*french*/"les #faucheurs invisibles# du Temple de l'Ombre protègent", /*spanish*/"unas #hojas invisibles# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#invisible blades# guard", /*french*/"les #faucheurs invisibles# du Temple de l'Ombre protègent", /*spanish*/"unas #hojas invisibles# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_WIND_HINT_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #invisible chest guarded by the dead# holds", /*french*/"le #trésor invisible du cul-de-sac# du Temple de l'Ombre contient", /*spanish*/"un #cofre invisible custodiado por los del más allá# contiene"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies guarding a ferry# hide", /*french*/"les #Gibdos qui bloquent le traversier# cachent", /*spanish*/"las #momias que protegen un navío# esconden"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies guarding a ferry# hide", /*french*/"les #Gibdos qui bloquent le traversier# cachent", /*spanish*/"las #momias que protegen un navío# esconden"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#caged near a ship# lies", /*french*/"#dans une cage près du traversier# gît", /*spanish*/"#entre rejas al lado de un navío# yace"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"#behind three burning skulls# lies", /*french*/"#derrière trois crânes enflammés# gît", /*spanish*/"tras #tres ardientes calaveras# yace"}, + }); + + hintTable[SHADOW_TEMPLE_BONGO_BONGO_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Phantom Shadow Beast# holds", /*french*/"le #monstre de l'ombre# possède", /*spanish*/"la #alimaña oscura espectral# porta"}, + }, {}, + //clear text + Text{"#Bongo Bongo# holds", /*french*/"#Bongo Bongo# possède", /*spanish*/"#Bongo Bongo# porta"} + ); + + hintTable[SHADOW_TEMPLE_GS_SINGLE_GIANT_POT] = HintText::Exclude({ + //obscure text + Text{"#beyond a burning skull# lies a spider with", /*french*/"une #Skulltula derrière un crâne enflammé du Temple de l'Ombre# a", /*spanish*/"#tras una ardiente calavera# yace una Skulltula que otorga"}, + }); + + hintTable[SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider beyond falling spikes# holds", /*french*/"une #Skulltula au delà de la pluie de clous du Temple de l'Ombre# a", /*spanish*/"una #Skulltula tras los pinchos del techo# otorga"}, + }); + + hintTable[SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT] = HintText::Exclude({ + //obscure text + Text{"#beyond three burning skulls# lies a spider with", /*french*/"une #Skulltula derrière trois crânes enflammés du Temple de l'Ombre# a", /*spanish*/"#tras tres ardientes calaveras# yace una Skulltula que otorga"}, + }); + + hintTable[SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM] = HintText::Exclude({ + //obscure text + Text{"a spider guarded by #invisible blades# holds", /*french*/"une #Skulltula protégée par les faucheurs invisibles du Temple de l'Ombre# a", /*spanish*/"una #Skulltula custodiada por hojas invisibles# otorga"}, + }); + + hintTable[SHADOW_TEMPLE_GS_NEAR_SHIP] = HintText::Exclude({ + //obscure text + Text{"a spider near a #docked ship# hoards", /*french*/"une #Skulltula près du traversier du Temple de l'Ombre# a", /*spanish*/"una #Skulltula cercana a un navío# otorga"}, + }); + + + hintTable[SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider beyond falling spikes# holds", /*french*/"une #Skulltula au delà de la pluie de clous du Temple de l'Ombre# a", /*spanish*/"una #Skulltula tras los pinchos del techo# otorga"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider amidst roaring winds# in the Shadow Temple holds", /*french*/"une #Skulltula près des vents du Temple de l'Ombre# a", /*spanish*/"una #Skulltula entre ventarrones# del Templo de las Sombras otorga"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_GS_AFTER_WIND] = HintText::Exclude({ + //obscure text + Text{"a #spider beneath gruesome debris# in the Shadow Temple hides", /*french*/"une #Skulltula sous des débris du Temple de l'Ombre# a", /*spanish*/"una #Skulltula bajo unos horripilantes escombros# del Templo de las Sombras otorga"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_GS_AFTER_SHIP] = HintText::Exclude({ + //obscure text + Text{"a #fallen statue# reveals a spider with", /*french*/"une #Skulltula près de la statue écroulée du Temple de l'Ombre# a", /*spanish*/"una #estatua caída# revelará una Skulltula que otorgue"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_GS_NEAR_BOSS] = HintText::Exclude({ + //obscure text + Text{"a #suspended spider# guards", /*french*/"une #Skulltula près du repère du Temple de l'Ombre# a", /*spanish*/"una #Skulltula flotante# del Templo de las Sombras otorga"}, + }); + + /*-------------------------- + | BOTTOM OF THE WELL | + ---------------------------*/ + hintTable[BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth in the well# reveals", /*french*/"l'#oeil de vérité dans le Puits# révèle", /*spanish*/"el #Ojo de la Verdad en el pozo# revela"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#gruesome debris# in the well hides", /*french*/"des #débris dans le Puits# cachent", /*spanish*/"unos #horripilantes escombros# del pozo esconden"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth in the well# reveals", /*french*/"l'#oeil de vérité dans le Puits# révèle", /*spanish*/"el #Ojo de la Verdad en el pozo# revela"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hidden entrance to a cage# in the well leads to", /*french*/"dans un #chemin caché dans le Puits# gît", /*spanish*/"la #entrada oculta de una celda# del pozo conduce a"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #spider guarding a cage# in the well protects", /*french*/"l'#araignée dans la cage du Puits# protège", /*spanish*/"una #araña protegiendo una celda# del pozo guarda"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#gruesome debris# in the well hides", /*french*/"des #débris dans le Puits# cachent", /*spanish*/"unos #horripilantes escombros# del pozo esconden"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Dead Hand's invisible secret# is", /*french*/"le #trésor invisible du Poigneur# est", /*spanish*/"el #secreto invisible de la Mano Muerta# esconde"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #royal melody in the well# uncovers", /*french*/"la #mélodie royale révèle dans le Puits#", /*spanish*/"una #melodía real en el pozo# revela"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #royal melody in the well# uncovers", /*french*/"la #mélodie royale révèle dans le Puits#", /*spanish*/"una #melodía real en el pozo# revela"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"in the #depths of the well# lies", /*french*/"#dans le coeur du Puits# gît", /*spanish*/"en las #profundidades del pozo# yace"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#perilous pits# in the well guard the path to", /*french*/"#trois trous# dans le Puits protègent", /*spanish*/"#peligrosos fosos# del pozo conducen a"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#locked in a cage# in the well lies", /*french*/"#dans une cage# du Puits gît", /*spanish*/"#entre rejas# en el pozo yace"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"#inside a coffin# hides", /*french*/"dans #un cercueil# gît", /*spanish*/"en el #interior de un ataúd# yace"}, + }); + + + hintTable[BOTTOM_OF_THE_WELL_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #royal melody in the well# uncovers", /*french*/"la #mélodie royale révèle dans le Puits#", /*spanish*/"una #melodía real en el pozo# revela"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #army of the dead# in the well guards", /*french*/"l'#armée des morts# dans le Puits protège", /*spanish*/"un #ejército del más allá# del pozo guarda"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"#Dead Hand's explosive secret# is", /*french*/"le #secret explosif du Poigneur# est", /*spanish*/"el #explosivo secreto de la Mano Muerta# esconde"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"an #invisible path in the well# leads to", /*french*/"dans un #chemin caché dans le Puits# gît", /*spanish*/"un #camino invisible del pozo# conduce a"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE] = HintText::Exclude({ + //obscure text + Text{"a #spider locked in a cage# in the well holds", /*french*/"une #Skulltula dans une cage au fonds du Puits# a", /*spanish*/"una #Skulltula enjaulada# del pozo otorga"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM] = HintText::Exclude({ + //obscure text + Text{"an #invisible path in the well# leads to", /*french*/"une #Skulltula dans le chemin invisible au fonds du Puits# a", /*spanish*/"un #camino invisible del pozo# conduce a una Skulltula que otorga"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider locked in a crypt# within the well guards", /*french*/"une #Skulltula embarrée dans la crypte au fonds du Puits# a", /*spanish*/"una #Skulltula encerrada en una cripta# del pozo otorga"}, + }); + + + hintTable[BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT] = HintText::Exclude({ + //obscure text + Text{"a #gauntlet of invisible spiders# protects", /*french*/"une #Skulltula protégée par les araignées invisibles au fonds du Puits# a", /*spanish*/"unas #arañas invisibles# custodian una Skulltula que otorga"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider crawling near the dead# in the well holds", /*french*/"une #Skulltula près des cercueils au fonds du Puits# a", /*spanish*/"una #Skulltula junto a los muertos# del pozo otorga"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider locked in a crypt# within the well guards", /*french*/"une #Skulltula embarrée dans la crypte au fonds du Puits# a", /*spanish*/"una #Skulltula encerrada en una cripta# del pozo otorga"}, + }); + + /*-------------------------- + | ICE CAVERN | + ---------------------------*/ + hintTable[ICE_CAVERN_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#winds of ice# surround", /*french*/"#figé dans la glace rouge# gît", /*spanish*/"#heladas borrascas# rodean"}, + }); + + hintTable[ICE_CAVERN_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #wall of ice# protects", /*french*/"#un mur de glace rouge# cache", /*spanish*/"una #gélida pared# protege"}, + }); + + hintTable[ICE_CAVERN_IRON_BOOTS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #monster in a frozen cavern# guards", /*french*/"le #monstre de la caverne de glace# protège", /*spanish*/"un #monstruo de una helada caverna# guarda"}, + }); + + hintTable[ICE_CAVERN_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"a #wall of ice# protects", /*french*/"un #mur de glace rouge# cache", /*spanish*/"una #gélida pared# protege"}, + }); + + + hintTable[ICE_CAVERN_MQ_IRON_BOOTS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #monster in a frozen cavern# guards", /*french*/"le #monstre de la caverne de glace# protège", /*spanish*/"un #monstruo de una helada caverna# guarda"}, + }); + + hintTable[ICE_CAVERN_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#winds of ice# surround", /*french*/"#entouré de vent glacial# gît", /*spanish*/"#heladas borrascas# rodean"}, + }); + + hintTable[ICE_CAVERN_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #wall of ice# protects", /*french*/"#un mur de glace rouge# cache", /*spanish*/"una #gélida pared# protege"}, + }); + + hintTable[ICE_CAVERN_MQ_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"#winds of ice# surround", /*french*/"#entouré de vent glacial# gît", /*spanish*/"#heladas borrascas# rodean"}, + }); + + hintTable[ICE_CAVERN_GS_PUSH_BLOCK_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider above icy pits# holds", /*french*/"une #Skulltula au dessus d'un goufre glacial# a", /*spanish*/"una #Skulltula sobre gélidos vacíos# otorga"}, + }); + + hintTable[ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM] = HintText::Exclude({ + //obscure text + Text{"#spinning ice# guards a spider holding", /*french*/"une #Skulltula près de deux lames de glace# a", /*spanish*/"unos #témpanos giratorios# custodian una Skulltula que otorga"}, + }); + + hintTable[ICE_CAVERN_GS_HEART_PIECE_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider behind a wall of ice# hides", /*french*/"une #Skulltula derrière un mur de glace# a", /*spanish*/"una #Skulltula tras una gélida pared# otorga"}, + }); + + + hintTable[ICE_CAVERN_MQ_GS_SCARECROW] = HintText::Exclude({ + //obscure text + Text{"a #spider above icy pits# holds", /*french*/"une #Skulltula au dessus d'un goufre glacial# a", /*spanish*/"una #Skulltula sobre gélidos vacíos# otorga"}, + }); + + hintTable[ICE_CAVERN_MQ_GS_ICE_BLOCK] = HintText::Exclude({ + //obscure text + Text{"a #web of ice# surrounds a spider with", /*french*/"une #Skulltula protégée d'une toile glacée# a", /*spanish*/"una #gélida red# rodea a una Skulltula que otorga"}, + }); + + hintTable[ICE_CAVERN_MQ_GS_RED_ICE] = HintText::Exclude({ + //obscure text + Text{"a #spider in fiery ice# hoards", /*french*/"une #Skulltula figée dans la glace rouge# a", /*spanish*/"una #Skulltula tras un ardiente hielo# otorga"}, + }); + + /*-------------------------- + | GERUDO TRAINING GROUNDS | + ---------------------------*/ + hintTable[GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #blinded eye in the Gerudo Training Grounds# drops", /*french*/"l'#Oeil dans le Gymnase Gerudo# voit", /*spanish*/"#cegar un ojo en el Centro de Instrucción Gerudo# revela"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #blinded eye in the Gerudo Training Grounds# drops", /*french*/"l'#Oeil dans le Gymnase Gerudo# voit", /*spanish*/"#cegar un ojo en el Centro de Instrucción Gerudo# revela"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_STALFOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#soldiers walking on shifting sands# in the Gerudo Training Grounds guard", /*french*/"les #squelettes# du Gymnase Gerudo protègent", /*spanish*/"#soldados en resbaladizas arenas# del Centro de Instrucción Gerudo protegen"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reptilian warriors# in the Gerudo Training Grounds protect", /*french*/"les #lézards# dans le Gymnase Gerudo protègent", /*spanish*/"#unos escamosos guerreros# del Centro de Instrucción Gerudo protegen"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth# in the Gerudo Training Grounds reveals", /*french*/"#bien caché# dans le Gymnase Gerudo gît", /*spanish*/"el #Ojo de la Verdad# en el Centro de Instrucción Gerudo revela"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST] = HintText::Exclude({ + //obscure text + Text{"the first prize of #the thieves' training# is", /*french*/"le #premier trésor du Gymnase Gerudo# est", /*spanish*/"el primer premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST] = HintText::Exclude({ + //obscure text + Text{"the second prize of #the thieves' training# is", /*french*/"le #deuxième trésor du Gymnase Gerudo# est", /*spanish*/"el segundo premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST] = HintText::Exclude({ + //obscure text + Text{"the third prize of #the thieves' training# is", /*french*/"le #troisième trésor du Gymnase Gerudo# est", /*spanish*/"el tercer premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Song of Time# in the Gerudo Training Grounds leads to", /*french*/"le #chant du temps# révèle dans le Gymnase Gerudo", /*spanish*/"la #Canción del Tiempo# en el Centro de Instrucción Gerudo conduce a"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Song of Time# in the Gerudo Training Grounds leads to", /*french*/"le #chant du temps# révèle dans le Gymnase Gerudo", /*spanish*/"la #Canción del Tiempo# en el Centro de Instrucción Gerudo conduce a"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST] = HintText::Exclude({ + //obscure text + Text{"#fiery foes# in the Gerudo Training Grounds guard", /*french*/"les #limaces de feu# du Gymnase Gerudo protègent", /*spanish*/"unos #flamígeros enemigos# del Centro de Instrucción Gerudo guardan"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#engulfed in flame# where thieves train lies", /*french*/"le #trésor enflammé# du Gymnase Gerudo est", /*spanish*/"donde entrenan las bandidas #entre llamas# yace"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST] = HintText::Exclude({ + //obscure text + Text{"thieves #blind four faces# to find", /*french*/"l'#épreuve d'archerie# du Gymnase Gerudo donne", /*spanish*/"las bandidas #ciegan cuatro bustos# para hallar"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST] = HintText::Exclude({ + //obscure text + Text{"thieves #blind four faces# to find", /*french*/"l'#épreuve d'archerie# du Gymnase Gerudo donne", /*spanish*/"las bandidas #ciegan cuatro bustos# para hallar"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST] = HintText::Exclude({ + //obscure text + Text{"#before a block of silver# thieves can find", /*french*/"#près d'un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"#ante un plateado bloque# las bandidas hallan"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #feat of strength# rewards thieves with", /*french*/"#derrière un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"una #hazaña de fuerza# premia a las bandidas con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #feat of strength# rewards thieves with", /*french*/"#derrière un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"una #hazaña de fuerza# premia a las bandidas con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #feat of strength# rewards thieves with", /*french*/"#derrière un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"una #hazaña de fuerza# premia a las bandidas con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #feat of strength# rewards thieves with", /*french*/"#derrière un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"una #hazaña de fuerza# premia a las bandidas con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"the #Song of Time# in the Gerudo Training Grounds leads to", /*french*/"le #chant du temps# révèle dans le Gymnase Gerudo", /*spanish*/"la #Canción del Tiempo# en el Centro de Instrucción Gerudo conduce a"}, + }); + + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#thieves prepare for training# with", /*french*/"dans #l'entrée du Gymnase Gerudo# gît", /*spanish*/"las #bandidas se instruyen# con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#thieves prepare for training# with", /*french*/"dans #l'entrée du Gymnase Gerudo# gît", /*spanish*/"las #bandidas se instruyen# con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#soldiers walking on shifting sands# in the Gerudo Training Grounds guard", /*french*/"les #squelettes# du Gymnase Gerudo protègent", /*spanish*/"#soldados en resbaladizas arenas# del Centro de Instrucción Gerudo protegen"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST] = HintText::Exclude({ + //obscure text + Text{"#before a block of silver# thieves can find", /*french*/"#près d'un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"#ante un plateado bloque# las bandidas hallan"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST] = HintText::Exclude({ + //obscure text + Text{"thieves #blind four faces# to find", /*french*/"l'#épreuve d'archerie# du Gymnase Gerudo donne", /*spanish*/"las bandidas #ciegan cuatro bustos# para hallar"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#engulfed in flame# where thieves train lies", /*french*/"le #trésor enflammé# du Gymnase Gerudo est", /*spanish*/"donde entrenan las bandidas #entre llamas# yace"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#fiery foes# in the Gerudo Training Grounds guard", /*french*/"les #ennemis de feu# du Gymnase Gerudo protègent", /*spanish*/"unos #flamígeros enemigos# del Centro de Instrucción Gerudo guardan"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reptilian warriors# in the Gerudo Training Grounds protect", /*french*/"les #lézards# dans le Gymnase Gerudo protègent", /*spanish*/"#unos escamosos guerreros# del Centro de Instrucción Gerudo protegen"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #path of fire# leads thieves to", /*french*/"dans le #chemin enflammé# dans le Gymnase Gerudo gît", /*spanish*/"un #camino de fuego# conduce a las bandidas a"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST] = HintText::Exclude({ + //obscure text + Text{"the first prize of #the thieves' training# is", /*french*/"le #premier trésor du Gymnase Gerudo# est", /*spanish*/"el primer premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #path of fire# leads thieves to", /*french*/"dans le #chemin enflammé# dans le Gymnase Gerudo gît", /*spanish*/"un #camino de fuego# conduce a las bandidas a"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST] = HintText::Exclude({ + //obscure text + Text{"the third prize of #the thieves' training# is", /*french*/"le #troisième trésor du Gymnase Gerudo# est", /*spanish*/"el tercer premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST] = HintText::Exclude({ + //obscure text + Text{"the second prize of #the thieves' training# is", /*french*/"le #deuxième trésor du Gymnase Gerudo# est", /*spanish*/"el segundo premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth# in the Gerudo Training Grounds reveals", /*french*/"#bien caché# dans le Gymnase Gerudo gît", /*spanish*/"el #Ojo de la Verdad# en el Centro de Instrucción Gerudo revela"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #feat of strength# rewards thieves with", /*french*/"#derrière un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"una #hazaña de fuerza# premia a las bandidas con"}, + }); + + /*-------------------------- + | GANONS CASTLE | + ---------------------------*/ + hintTable[GANONS_TOWER_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Evil King# hoards", /*french*/"le #Roi du Mal# possède", /*spanish*/"el #Rey del Mal# acapara"}, + }); + + + hintTable[GANONS_CASTLE_FOREST_TRIAL_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the wilds# holds", /*french*/"l'#épreuve des bois# contient", /*spanish*/"la #prueba de la naturaleza# brinda"}, + }); + + hintTable[GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the seas# holds", /*french*/"l'#épreuve des mers# contient", /*spanish*/"la #prueba del mar# brinda"}, + }); + + hintTable[GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the seas# holds", /*french*/"l'#épreuve des mers# contient", /*spanish*/"la #prueba del mar# brinda"}, + }); + + hintTable[GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#music in the test of darkness# unveils", /*french*/"la #musique dans l'épreuve des ténèbres# révèle", /*spanish*/"la #música en la prueba de la oscuridad# revela"}, + }); + + hintTable[GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#light in the test of darkness# unveils", /*french*/"la #lumière dans l'épreuve des ténèbres# révèle", /*spanish*/"la #luz en la prueba de la oscuridad# revela"}, + }); + + hintTable[GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the sands# holds", /*french*/"l'#épreuve des sables# contient", /*spanish*/"la #prueba de las arenas# brinda"}, + }); + + hintTable[GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the sands# holds", /*french*/"l'#épreuve des sables# contient", /*spanish*/"la #prueba de las arenas# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#music in the test of radiance# reveals", /*french*/"la #musique dans l'épreuve du ciel# révèle", /*spanish*/"la #música en la prueba del resplandor# revela"}, + }); + + + hintTable[GANONS_CASTLE_MQ_WATER_TRIAL_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the seas# holds", /*french*/"l'#épreuve des mers# contient", /*spanish*/"la #prueba del mar# brinda"}, + }); + + hintTable[GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the wilds# holds", /*french*/"l'#épreuve des bois# contient", /*spanish*/"la #prueba de la naturaleza# brinda"}, + }); + + hintTable[GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the wilds# holds", /*french*/"l'#épreuve des bois# contient", /*spanish*/"la #prueba de la naturaleza# brinda"}, + }); + + hintTable[GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#music in the test of radiance# reveals", /*french*/"la #musique dans l'épreuve du ciel# révèle", /*spanish*/"la #música en la prueba del resplandor# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of darkness# holds", /*french*/"l'#épreuve des ténèbres# contient", /*spanish*/"la #prueba de la oscuridad# brinda"}, + }); + + hintTable[GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of darkness# holds", /*french*/"l'#épreuve des ténèbres# contient", /*spanish*/"la #prueba de la oscuridad# brinda"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"the #test of the wilds# holds", /*french*/"l'#épreuve des bois# révèle", /*spanish*/"la #prueba de la naturaleza# brinda"}, + }); + + hintTable[GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_DEKU_SCRUB_RIGHT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_DEKU_SCRUB_LEFT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + + hintTable[GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp new file mode 100644 index 000000000..5adf816a8 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp @@ -0,0 +1,1272 @@ +#include "../hint_list.hpp" + +void HintTable_Init_Exclude_Overworld() { + hintTable[KF_KOKIRI_SWORD_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #hidden treasure of the Kokiri# is", /*french*/"le #trésor des Kokiri# est", /*spanish*/"el #tesoro oculto de los Kokiri# esconde"}, + }); + + hintTable[KF_MIDOS_TOP_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #leader of the Kokiri# hides", /*french*/"le #chef des Kokiri# possède", /*spanish*/"el #líder de los Kokiri# esconde"}, + }, {}, + //clear text + Text{"#inside Mido's house# is", /*french*/"#dans la maison de Mido# gît", /*spanish*/"en la #casa de Mido# yace"} + ); + + hintTable[KF_MIDOS_TOP_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #leader of the Kokiri# hides", /*french*/"le #chef des Kokiri# possède", /*spanish*/"el #líder de los Kokiri# esconde"}, + }, {}, + //clear text + Text{"#inside Mido's house# is", /*french*/"#dans la maison de Mido# gît", /*spanish*/"en la #casa de Mido# yace"} + ); + + hintTable[KF_MIDOS_BOTTOM_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #leader of the Kokiri# hides", /*french*/"le #chef des Kokiri# possède", /*spanish*/"el #líder de los Kokiri# esconde"}, + }, {}, + //clear text + Text{"#inside Mido's house# is", /*french*/"#dans la maison de Mido# gît", /*spanish*/"en la #casa de Mido# yace"} + ); + + hintTable[KF_MIDOS_BOTTOM_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #leader of the Kokiri# hides", /*french*/"le #chef des Kokiri# possède", /*spanish*/"el #líder de los Kokiri# esconde"}, + }, {}, + //clear text + Text{"#inside Mido's house# is", /*french*/"#dans la maison de Mido# gît", /*spanish*/"en la #casa de Mido# yace"} + ); + + hintTable[GRAVEYARD_SHIELD_GRAVE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #treasure of a fallen soldier# is", /*french*/"le #trésor du soldat mort# est", /*spanish*/"el #tesoro de un soldado caído# esconde"}, + }); + + hintTable[DMT_CHEST] = HintText::Exclude({ + //obscure text + Text{"hidden behind a wall on a #mountain trail# is", /*french*/"derrière une façade du #chemin montagneux# est", /*spanish*/"tras una pared del #sendero de la montaña# yace"}, + }); + + hintTable[GC_MAZE_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"in #Goron City# explosives unlock", /*french*/"des explosions dans le #village Goron# révèlent", /*spanish*/"en la #Ciudad Goron# unos explosivos desbloquean"}, + }); + + hintTable[GC_MAZE_CENTER_CHEST] = HintText::Exclude({ + //obscure text + Text{"in #Goron City# explosives unlock", /*french*/"des explosions dans le #village Goron# révèlent", /*spanish*/"en la #Ciudad Goron# unos explosivos desbloquean"}, + }); + + hintTable[ZD_CHEST] = HintText::Exclude({ + //obscure text + Text{"fire #beyond a waterfall# reveals", /*french*/"du feu #derrière la cascade# éclaire", /*spanish*/"las #llamas tras una una cascada# revelan"}, + }); + + hintTable[GRAVEYARD_HOOKSHOT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a chest hidden by a #speedy spectre# holds", /*french*/"le #coffre du rapide revenant# contient", /*spanish*/"un cofre custodiado por un #espectro veloz# contiene"}, + }, {}, + //clear text + Text{"#dead Dampé's first prize# is", /*french*/"la #première course d'Igor# donne", /*spanish*/"el primer premio de #la carrera de Dampé# se trata de"} + ); + + hintTable[GF_CHEST] = HintText::Exclude({ + //obscure text + Text{"on a #rooftop in the desert# lies", /*french*/"sur un #toit du désert# gît", /*spanish*/"en una #azotea del desierto# yace"}, + }); + + hintTable[KAK_REDEAD_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"#zombies beneath the earth# guard", /*french*/"les #revenants sous terre# protègent", /*spanish*/"unos #zombis subterráneos# esconden"}, + }); + + hintTable[SFM_WOLFOS_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"#wolves beneath the earth# guard", /*french*/"les #loups sous terre# protègent", /*spanish*/"unos #lobos subterráneos# esconden"}, + }); + + hintTable[HF_NEAR_MARKET_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole in a field near a drawbridge# holds", /*french*/"la #grotte près d'un pont# contient", /*spanish*/"bajo el #hoyo de una llanura cercano a un puente# yace"}, + }); + + hintTable[HF_SOUTHEAST_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole amongst trees in a field# holds", /*french*/"la #grotte près des arbres# contient", /*spanish*/"bajo el #hoyo de una llanura rodeado de árboles# yace"}, + }); + + hintTable[HF_OPEN_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #open hole in a field# holds", /*french*/"la #grotte dans les plaines# contient", /*spanish*/"bajo el #hoyo descubierto de una llanura# yace"}, + }); + + hintTable[KAK_OPEN_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #open hole in a town# holds", /*french*/"la #grotte dans le village# contient", /*spanish*/"bajo el #hoyo descubierto de un pueblo# yace"}, + }); + + hintTable[ZR_OPEN_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole along a river# holds", /*french*/"la #grotte près du fleuve# contient", /*spanish*/"bajo un #hoyo junto a un río# yace"}, + }); + + hintTable[KF_STORMS_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole in a forest village# holds", /*french*/"la #grotte inondée de pluie dans le Village Kokiri# révèle", /*spanish*/"bajo el #hoyo de una tribu del bosque# yace"}, + }); + + hintTable[LW_NEAR_SHORTCUTS_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole in a wooded maze# holds", /*french*/"la #grotte dans le labyrinthe sylvestre# contient", /*spanish*/"bajo un #hoyo de un laberinto forestal# yace"}, + }); + + hintTable[DMT_STORMS_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"#hole flooded with rain on a mountain# holds", /*french*/"la #grotte inondée de pluie sur la montagne# contient", /*spanish*/"bajo un #hoyo de una montaña inundado de lluvia# yace"}, + }); + + hintTable[DMC_UPPER_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole in a volcano# holds", /*french*/"la #grotte dans le volcan# contient", /*spanish*/"bajo el #hoyo de un volcán# yace"}, + }); + + + hintTable[TOT_LIGHT_ARROWS_CUTSCENE] = HintText::Exclude({ + //obscure text + Text{"the #final gift of a princess# is", /*french*/"le #cadeau d'adieu de la princesse# est", /*spanish*/"el #obsequio final de la princesa# se trata de"}, + }); + + hintTable[LW_GIFT_FROM_SARIA] = HintText::Exclude({ + //obscure text + Text{"a #potato hoarder# holds", /*french*/"le #panini mélodieux# est en fait", /*spanish*/"cierta #jovencita verde# concede"}, + Text{"a rooty tooty #flutey cutey# gifts", /*french*/"la #patate musicale# est en fait", /*spanish*/"una #gran amiga# concede"}, + }, {}, + //clear text + Text{"#Saria's Gift# is", /*french*/"le #cadeau de Saria# est", /*spanish*/"el #regalo de Saria# se trata de"} + ); + + hintTable[ZF_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"the #fairy of winds# holds", /*french*/"la #fée du vent# a", /*spanish*/"el #hada del viento# brinda"}, + }); + + hintTable[HC_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"the #fairy of fire# holds", /*french*/"la #fée du feu# a", /*spanish*/"el #hada del fuego# brinda"}, + }); + + hintTable[COLOSSUS_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"the #fairy of love# holds", /*french*/"la #fée de l'amour# a", /*spanish*/"el #hada del amor# brinda"}, + }); + + hintTable[DMT_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"a #magical fairy# gifts", /*french*/"la #fée de la magie# a", /*spanish*/"un #hada mágica# brinda"}, + }); + + hintTable[DMC_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"a #magical fairy# gifts", /*french*/"la #fée de la magie# a", /*spanish*/"un #hada mágica# brinda"}, + }); + + hintTable[OGC_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"the #fairy of strength# holds", /*french*/"la #fée de la force# a", /*spanish*/"el #hada de la fuerza# brinda"}, + }); + + + hintTable[SONG_FROM_IMPA] = HintText::Exclude({ + //obscure text + Text{"#deep in a castle#, Impa teaches", /*french*/"#la gardienne de la princesse# donne", /*spanish*/"en el #jardín del castillo Impa enseña#"}, + }); + + hintTable[SONG_FROM_MALON] = HintText::Exclude({ + //obscure text + Text{"#a farm girl# sings", /*french*/"la #fillette de la ferme# donne", /*spanish*/"una #chica rupestre# canta"}, + }); + + hintTable[SONG_FROM_SARIA] = HintText::Exclude({ + //obscure text + Text{"#deep in the forest#, Saria teaches", /*french*/"la #fille de la forêt# donne", /*spanish*/"al #fondo del bosque# Saria enseña"}, + }); + + hintTable[SONG_FROM_WINDMILL] = HintText::Exclude({ + //obscure text + Text{"a man #in a windmill# is obsessed with", /*french*/"l'#homme du moulin# donne", /*spanish*/"el #hombre del molino# está obsesionado con"}, + }); + + + hintTable[HC_MALON_EGG] = HintText::Exclude({ + //obscure text + Text{"a #girl looking for her father# gives", /*french*/"la #fillette qui cherche son père# donne", /*spanish*/"una #chica en busca de su padre# otorga"}, + }); + + hintTable[HC_ZELDAS_LETTER] = HintText::Exclude({ + //obscure text + Text{"a #princess in a castle# gifts", /*french*/"la #princesse dans le château# donne", /*spanish*/"la #princesa de un castillo# otorga"}, + }); + + hintTable[ZD_DIVING_MINIGAME] = HintText::Exclude({ + //obscure text + Text{"an #unsustainable business model# gifts", /*french*/"le #mauvais modèle d'affaires# donne", /*spanish*/"un #mal modelo de negocio# premia con"}, + }, {}, + //clear text + Text{"those who #dive for Zora rupees# will find", /*french*/"ceux qui #plongent pour des rubis Zora# trouveront", /*spanish*/"aquellos que se #sumergan por las rupias zora# encontrarán"} + ); + + hintTable[LH_CHILD_FISHING] = HintText::Exclude({ + //obscure text + Text{"#fishing in youth# bestows", /*french*/"#pêcher dans sa jeunesse# promet", /*spanish*/"#pescar en la juventud# conduce a"}, + }); + + hintTable[LH_ADULT_FISHING] = HintText::Exclude({ + //obscure text + Text{"#fishing in maturity# bestows", /*french*/"#pêcher dans sa maturité# promet", /*spanish*/"#pescar en la madurez# conduce a"}, + }); + + hintTable[LH_LAB_DIVE] = HintText::Exclude({ + //obscure text + Text{"a #diving experiment# is rewarded with", /*french*/"l'#expérience de plongée# donne", /*spanish*/"#bucear para un experimento# se premia con"}, + }); + + hintTable[GC_ROLLING_GORON_AS_ADULT] = HintText::Exclude({ + //obscure text + Text{"#comforting yourself# provides", /*french*/"se #réconforter soi-même# donne", /*spanish*/"#confrontarte a ti mismo# otorga"}, + }, {}, + //clear text + Text{"#reassuring a young Goron# is rewarded with", /*french*/"#rassurer un jeune Goron# donne", /*spanish*/"#calmar a un joven Goron# otorga"} + ); + + hintTable[MARKET_BOMBCHU_BOWLING_FIRST_PRIZE] = HintText::Exclude({ + //obscure text + Text{"the #first explosive prize# is", /*french*/"le #premier prix explosif# est", /*spanish*/"el #primer premio explosivo# se trata de"}, + }); + + hintTable[MARKET_BOMBCHU_BOWLING_SECOND_PRIZE] = HintText::Exclude({ + //obscure text + Text{"the #second explosive prize# is", /*french*/"le #deuxième prix explosif# est", /*spanish*/"el #segundo premio explosivo# se trata de"}, + }); + + hintTable[MARKET_LOST_DOG] = HintText::Exclude({ + //obscure text + Text{"#puppy lovers# will find", /*french*/"les #amoureux canins# trouveront", /*spanish*/"los #amantes caninos# encontrarán"}, + }, {}, + //clear text + Text{"#rescuing Richard the Dog# is rewarded with", /*french*/"#retrouver Kiki le chien# promet", /*spanish*/"#rescatar al perrito Ricardo# conduce a"} + ); + + hintTable[LW_OCARINA_MEMORY_GAME] = HintText::Exclude({ + //obscure text + Text{"the prize for a #game of Simon Says# is", /*french*/"la #récompense de Jean Dit# est", /*spanish*/"#repetir ciertas melodías# otorga"}, + Text{"a #child sing-a-long# holds", /*french*/"les #jeunes flûtistes# donnent", /*spanish*/"#tocar junto a otros# otorga"}, + }, {}, + //clear text + Text{"#playing an Ocarina in Lost Woods# is rewarded with", /*french*/"#jouer l'ocarina dans les Bois Perdus# donne", /*spanish*/"#tocar la ocarina en el Bosque Perdido# otorga"} + ); + + hintTable[KAK_10_GOLD_SKULLTULA_REWARD] = HintText::Exclude({ + //obscure text + Text{"#10 bug badges# rewards", /*french*/"#10 écussons# donnent", /*spanish*/"#10 medallas de insectos# otorgan"}, + Text{"#10 spider souls# yields", /*french*/"#10 âmes# donnent", /*spanish*/"#10 almas de araña# otorgan"}, + Text{"#10 auriferous arachnids# lead to", /*french*/"#10 arachnides aurifères# donnent", /*spanish*/"#10 arácnidos auríferos# otorgan"}, + }, {}, + //clear text + Text{"slaying #10 Gold Skulltulas# reveals", /*french*/"détruire #10 Skulltulas d'or# donne", /*spanish*/"#exterminar 10 skulltulas doradas# revela"} + ); + + hintTable[KAK_MAN_ON_ROOF] = HintText::Exclude({ + //obscure text + Text{"a #rooftop wanderer# holds", /*french*/"une #rencontre sur un toit# donne", /*spanish*/"#alguien sobre un tejado# otorga"}, + }); + + hintTable[ZR_MAGIC_BEAN_SALESMAN] = HintText::Exclude({ + //obscure text + Text{"a seller of #colorful crops# has", /*french*/"le #marchand de légumes# vend", /*spanish*/"el vendedor de un #colorido cultivo# ofrece"}, + }, {}, + //clear text + Text{"a #bean seller# offers", /*french*/"le #marchand de haricots magiques# vend en fait", /*spanish*/"el #vendedor de judías# ofrece"} + ); + + hintTable[ZR_FROGS_IN_THE_RAIN] = HintText::Exclude({ + //obscure text + Text{"#frogs in a storm# gift", /*french*/"#des grenouilles mouillées# donnent", /*spanish*/"las #ancas bajo la tormenta# otorgan"}, + }); + + hintTable[GF_HBA_1000_POINTS] = HintText::Exclude({ + //obscure text + Text{"scoring 1000 in #horseback archery# grants", /*french*/"obtenir 1000 points dans l'#archerie équestre# donne", /*spanish*/"conseguir 1000 puntos en el #tiro con arco a caballo# premia"}, + }); + + hintTable[MARKET_SHOOTING_GALLERY_REWARD] = HintText::Exclude({ + //obscure text + Text{"#shooting in youth# grants", /*french*/"#faire du tir dans sa jeunesse# donne", /*spanish*/"#disparar en la juventud# otorga"}, + }); + + hintTable[KAK_SHOOTING_GALLERY_REWARD] = HintText::Exclude({ + //obscure text + Text{"#shooting in maturity# grants", /*french*/"#faire du tir dans sa maturité# donne", /*spanish*/"#disparar en la madurez# otorga"}, + }); + + hintTable[LW_TARGET_IN_WOODS] = HintText::Exclude({ + //obscure text + Text{"shooting a #target in the woods# grants", /*french*/"#tirer une cible dans les bois# donne", /*spanish*/"disparar a un #blanco forestal# brinda"}, + }); + + hintTable[KAK_ANJU_AS_ADULT] = HintText::Exclude({ + //obscure text + Text{"a #chicken caretaker# offers adults", /*french*/"devenir un #éleveur de Cocottes# donne", /*spanish*/"una #cuidadora de emplumados# le ofrece a los mayores"}, + }); + + hintTable[LLR_TALONS_CHICKENS] = HintText::Exclude({ + //obscure text + Text{"#finding Super Cuccos# is rewarded with", /*french*/"#trouver des Super Cocottes# donne", /*spanish*/"#hallar los supercucos# conduce a"}, + }); + + hintTable[GC_ROLLING_GORON_AS_CHILD] = HintText::Exclude({ + //obscure text + Text{"the prize offered by a #large rolling Goron# is", /*french*/"la récompense d'un #gros Goron roulant# est", /*spanish*/"un #gran Goron rodante# otorga"}, + }); + + hintTable[LH_UNDERWATER_ITEM] = HintText::Exclude({ + //obscure text + Text{"the #sunken treasure in a lake# is", /*french*/"le #trésor au fond du lac# est", /*spanish*/"el #tesoro hundido del lago# se trata de"}, + }); + + hintTable[GF_GERUDO_MEMBERSHIP_CARD] = HintText::Exclude({ + //obscure text + Text{"#rescuing captured carpenters# is rewarded with", /*french*/"#secourir les charpentiers capturés# assure", /*spanish*/"#rescatar los apresados carpinteros# se premia con"}, + }); + + hintTable[WASTELAND_BOMBCHU_SALESMAN] = HintText::Exclude({ + //obscure text + Text{"a #carpet guru# sells", /*french*/"#un marchand du désert# vend", /*spanish*/"el #genio de una alfombra# vende"}, + }); + + + hintTable[KAK_IMPAS_HOUSE_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"#imprisoned in a house# lies", /*french*/"#encagé dans une maison# gît", /*spanish*/"#en una casa entre rejas# yace"}, + }); + + hintTable[HF_TEKTITE_GROTTO_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"#deep underwater in a hole# is", /*french*/"#dans les profondeurs d'une grotte# gît", /*spanish*/"#en lo hondo bajo un hoyo# yace"}, + }); + + hintTable[KAK_WINDMILL_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"on a #windmill ledge# lies", /*french*/"#haut perché dans le moulin# gît", /*spanish*/"al #borde de un molino# yace"}, + }); + + hintTable[GRAVEYARD_DAMPE_RACE_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"#racing a ghost# leads to", /*french*/"le défi du #revenant rapide# donne", /*spanish*/"#perseguir a un fantasma# conduce a"}, + }, {}, + //clear text + Text{"#dead Dampe's second# prize is", /*french*/"la #deuxième course d'Igor# donne", /*spanish*/"el segundo premio de #la carrera de Dampé# se trata de"} + ); + + hintTable[LLR_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"in a #ranch silo# lies", /*french*/"#dans l'entrepôt de la ferme# gît", /*spanish*/"en un #granero rupestre# yace"}, + }); + + hintTable[GRAVEYARD_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"a #crate in a graveyard# hides", /*french*/"#la boîte dans le Cimetière# contient", /*spanish*/"bajo la #caja de un cementerio# yace"}, + }); + + hintTable[GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR] = HintText::Exclude({ + //obscure text + Text{"a #gravekeeper digs up#", /*french*/"#le jeu du fossoyeur# cache", /*spanish*/"cierto #sepultero desentierra#"}, + }); + + hintTable[ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"on top of a #pillar in a river# lies", /*french*/"#sur un pilier au dessus du fleuve# gît", /*spanish*/"en lo alto del #pilar de un río# yace"}, + }); + + hintTable[ZR_NEAR_DOMAIN_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"on a #river ledge by a waterfall# lies", /*french*/"#sur la falaise au dessus du fleuve# gît", /*spanish*/"al borde de #la entrada a una cascada# yace"}, + }); + + hintTable[LH_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"high on a #lab rooftop# one can find", /*french*/"#la tour d'observation du lac# cache", /*spanish*/"en lo #alto de un laboratorio# yace"}, + }); + + hintTable[ZF_ICEBERG_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"#floating on ice# is", /*french*/"#gisant sur la glace# gît", /*spanish*/"#flotando sobre hielo# yace"}, + }); + + hintTable[GV_WATERFALL_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"behind a #desert waterfall# is", /*french*/"#derrière la cascade du désert# se cache", /*spanish*/"tras una #desierta cascada# yace"}, + }); + + hintTable[GV_CRATE_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"a #crate in a valley# hides", /*french*/"la #boîte dans la vallée# contient", /*spanish*/"bajo la #caja de un valle# yace"}, + }); + + hintTable[COLOSSUS_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"on top of an #arch of stone# lies", /*french*/"#gisant sur une arche de pierre# gît", /*spanish*/"en lo alto de un #arco de piedra# yace"}, + }); + + hintTable[DMT_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"above a #mountain cavern entrance# is", /*french*/"gisant #au dessus de la caverne montagneuse# gît", /*spanish*/"en lo alto de la #entrada de una cueva en la montaña# yace"}, + }); + + hintTable[DMC_WALL_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"nestled in a #volcanic wall# is", /*french*/"dans une #alcove volcanique# gît", /*spanish*/"entre unas #murallas volcánicas# yace"}, + }); + + hintTable[DMC_VOLCANO_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"obscured by #volcanic ash# is", /*french*/"#recouvert de cendres volcaniques# gît", /*spanish*/"bajo la #ceniza volcánica# yace"}, + }); + + hintTable[GF_NORTH_F1_CARPENTER] = HintText::Exclude({ + //obscure text + Text{"#defeating Gerudo guards# reveals", /*french*/"les #geôliers Gerudo# détiennent", /*spanish*/"#derrotar a las guardas Gerudo# revela"}, + }); + + hintTable[GF_NORTH_F2_CARPENTER] = HintText::Exclude({ + //obscure text + Text{"#defeating Gerudo guards# reveals", /*french*/"les #geôliers Gerudo# détiennent", /*spanish*/"#derrotar a las guardas Gerudo# revela"}, + }); + + hintTable[GF_SOUTH_F1_CARPENTER] = HintText::Exclude({ + //obscure text + Text{"#defeating Gerudo guards# reveals", /*french*/"les #geôliers Gerudo# détiennent", /*spanish*/"#derrotar a las guardas Gerudo# revela"}, + }); + + hintTable[GF_SOUTH_F2_CARPENTER] = HintText::Exclude({ + //obscure text + Text{"#defeating Gerudo guards# reveals", /*french*/"les #geôliers Gerudo# détiennent", /*spanish*/"#derrotar a las guardas Gerudo# revela"}, + }); + + + hintTable[HF_GS_NEAR_KAK_GROTTO] = HintText::Exclude({ + //obscure text + Text{"a #spider-guarded spider in a hole# hoards", /*french*/"une #Skulltula dans un trou d'arachnides# a", /*spanish*/"una #Skulltula custodiada por otra# de un hoyo otorga"}, + }); + + + hintTable[LLR_GS_BACK_WALL] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a ranch# holding", /*french*/"une #Skulltula sur la façade de la ferme# a", /*spanish*/"la noche revela una #Skulltula del rancho# que otorga"}, + }); + + hintTable[LLR_GS_RAIN_SHED] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a ranch# holding", /*french*/"une #Skulltula sur le mur de l'enclos# a", /*spanish*/"la noche revela una #Skulltula del rancho# que otorga"}, + }); + + hintTable[LLR_GS_HOUSE_WINDOW] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a ranch# holding", /*french*/"une #Skulltula sur la maison de ferme# a", /*spanish*/"la noche revela una #Skulltula del rancho# que otorga"}, + }); + + hintTable[LLR_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"a spider hiding in a #ranch tree# holds", /*french*/"une #Skulltula dans l'arbre de la ferme# a", /*spanish*/"una Skulltula escondida en el #árbol de un rancho# otorga"}, + }); + + + hintTable[KF_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried in a forest# holds", /*french*/"une #Skulltula enterrée dans la forêt# a", /*spanish*/"una #Skulltula enterrada en un bosque# otorga"}, + }); + + hintTable[KF_GS_KNOW_IT_ALL_HOUSE] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a forest# holding", /*french*/"une #Skulltula derrière une cabane de la forêt# a", /*spanish*/"la noche revela en el pasado una #Skulltula del bosque# que otorga"}, + }); + + hintTable[KF_GS_HOUSE_OF_TWINS] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a forest# holding", /*french*/"une #Skulltula sur une cabane de la forêt# a", /*spanish*/"la noche revela en el futuro una #Skulltula del rancho# que otorga"}, + }); + + + hintTable[LW_GS_BEAN_PATCH_NEAR_BRIDGE] = HintText::Exclude({ + //obscure text + Text{"a #spider buried deep in a forest maze# holds", /*french*/"une #Skulltula enterrée dans les bois# a", /*spanish*/"una #Skulltula enterrada en un laberinto forestal# otorga"}, + }); + + hintTable[LW_GS_BEAN_PATCH_NEAR_THEATER] = HintText::Exclude({ + //obscure text + Text{"a #spider buried deep in a forest maze# holds", /*french*/"une #Skulltula enterrée dans les bois# a", /*spanish*/"una #Skulltula enterrada en un laberinto forestal# otorga"}, + }); + + hintTable[LW_GS_ABOVE_THEATER] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider deep in a forest maze# holding", /*french*/"une #Skulltula haut perchée dans les bois# a", /*spanish*/"la noche revela una #Skulltula del laberinto forestal# que otorga"}, + }); + + hintTable[SFM_GS] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a forest meadow# holding", /*french*/"une #Skulltula dans le sanctuaire des bois# a", /*spanish*/"la noche revela una #Skulltula de la pradera del bosque# que otorga"}, + }); + + + hintTable[OGC_GS] = HintText::Exclude({ + //obscure text + Text{"a #spider outside a tyrant's tower# holds", /*french*/"une #Skulltula parmi les ruines du château# a", /*spanish*/"una #Skulltula a las afueras de la torre de un tirano# otorga"}, + }); + + hintTable[HC_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"a spider hiding in a #tree outside of a castle# holds", /*french*/"une #Skulltula dans l'arbre près du château# a", /*spanish*/"una Skulltula escondida en el #árbol de las afueras de un castillo# otorga"}, + }); + + hintTable[MARKET_GS_GUARD_HOUSE] = HintText::Exclude({ + //obscure text + Text{"a #spider in a guarded crate# holds", /*french*/"une #Skulltula dans une boîte en ville# a", /*spanish*/"una #Skulltula bajo una custodiada caja# otorga"}, + }); + + + hintTable[DMC_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried in a volcano# holds", /*french*/"une #Skulltula enterrée dans un volcan# a", /*spanish*/"una #Skulltula enterrada en un volcán# otorga"}, + }); + + + hintTable[DMT_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried outside a cavern# holds", /*french*/"une #Skulltula enterrée près d'une caverne# a", /*spanish*/"una #Skulltula enterrada a la entrada de una cueva# otorga"}, + }); + + hintTable[DMT_GS_NEAR_KAK] = HintText::Exclude({ + //obscure text + Text{"a #spider hidden in a mountain nook# holds", /*french*/"une #Skulltula cachée dans le flanc d'une montagne# a", /*spanish*/"una #Skulltula oculta en el rincón de la montaña# otorga"}, + }); + + hintTable[DMT_GS_ABOVE_DODONGOS_CAVERN] = HintText::Exclude({ + //obscure text + Text{"the hammer reveals a #spider on a mountain# holding", /*french*/"une #Skulltula derrière un rocher massif près d'une caverne# a", /*spanish*/"el martillo revela #una Skulltula de la montaña# que otorga"}, + }); + + hintTable[DMT_GS_FALLING_ROCKS_PATH] = HintText::Exclude({ + //obscure text + Text{"the hammer reveals a #spider on a mountain# holding", /*french*/"une #Skulltula derrière un rocher massif près du sommet d'un volcan# a", /*spanish*/"el martillo revela #una Skulltula de la montaña# que otorga"}, + }); + + + hintTable[GC_GS_CENTER_PLATFORM] = HintText::Exclude({ + //obscure text + Text{"a #suspended spider# in Goron City holds", /*french*/"une #Skulltula perchée dans le village Goron# a", /*spanish*/"una #Skulltula suspendida# en la Ciudad Goron otorga"}, + }); + + hintTable[GC_GS_BOULDER_MAZE] = HintText::Exclude({ + //obscure text + Text{"a spider in a #Goron City crate# holds", /*french*/"une #Skulltula dans une boîte du village Goron# a", /*spanish*/"una #Skulltula bajo una caja# de la Ciudad Goron otorga"}, + }); + + + hintTable[KAK_GS_HOUSE_UNDER_CONSTRUCTION] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a town# holding", /*french*/"une #Skulltula dans le chantier de construction# a", /*spanish*/"la noche del pasado revela una #Skulltula del pueblo# que otorga"}, + }); + + hintTable[KAK_GS_SKULLTULA_HOUSE] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a town# holding", /*french*/"une #Skulltula sur une maison maudite# a", /*spanish*/"la noche del pasado revela una #Skulltula del pueblo# que otorga"}, + }); + + hintTable[KAK_GS_GUARDS_HOUSE] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a town# holding", /*french*/"une #Skulltula sur une maison de village# a", /*spanish*/"la noche del pasado revela una #Skulltula del pueblo# que otorga"}, + }); + + hintTable[KAK_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a town# holding", /*french*/"une #Skulltula dans un arbre de village# a", /*spanish*/"la noche del pasado revela una #Skulltula del pueblo# que otorga"}, + }); + + hintTable[KAK_GS_WATCHTOWER] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a town# holding", /*french*/"une #Skulltula sur une échelle dans un village# a", /*spanish*/"la noche del pasado revela una #Skulltula del pueblo# que otorga"}, + }); + + hintTable[KAK_GS_ABOVE_IMPAS_HOUSE] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a town# holding", /*french*/"une #Skulltula au dessus d'une grande maison# a", /*spanish*/"la noche del futuro revela una #Skulltula del pueblo# que otorga"}, + }); + + + hintTable[GRAVEYARD_GS_WALL] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a graveyard# holding", /*french*/"une #Skulltula sur une façade du Cimetière# a", /*spanish*/"la noche revela una #Skulltula del cementerio# que otorga"}, + }); + + hintTable[GRAVEYARD_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried in a graveyard# holds", /*french*/"une #Skulltula enterrée dans le Cimetière# a", /*spanish*/"una #Skulltula enterrada en el cementerio# otorga"}, + }); + + + hintTable[ZR_GS_LADDER] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a river# holding", /*french*/"une #Skulltula sur une échelle près d'une cascade# a", /*spanish*/"la noche del pasado revela una #Skulltula del río# que otorga"}, + }); + + hintTable[ZR_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"a spider hiding in a #tree by a river# holds", /*french*/"une #Skulltula dans un arbre près du fleuve# a", /*spanish*/"una Skulltula escondida en el #árbol de un río# otorga"}, + }); + + hintTable[ZR_GS_ABOVE_BRIDGE] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a river# holding", /*french*/"une #Skulltula sur une façade près d'une cascade# a", /*spanish*/"la noche del futuro revela una #Skulltula del río# que otorga"}, + }); + + hintTable[ZR_GS_NEAR_RAISED_GROTTOS] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a river# holding", /*french*/"une #Skulltula sur une façade près d'une grotte du fleuve# a", /*spanish*/"la noche del futuro revela una #Skulltula del río# que otorga"}, + }); + + + hintTable[ZD_GS_FROZEN_WATERFALL] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider by a frozen waterfall# holding", /*french*/"une #Skulltula près d'une cascade gelée# a", /*spanish*/"la noche revela una #Skulltula junto a una congelada cascada# que otorga"}, + }); + + hintTable[ZF_GS_ABOVE_THE_LOG] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider near a deity# holding", /*french*/"une #Skulltula près du gardien aquatique# a", /*spanish*/"la noche revela una #Skulltula junto a cierta deidad# que otorga"}, + }); + + hintTable[ZF_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"a spider hiding in a #tree near a deity# holds", /*french*/"une #Skulltula dans un arbre dans un réservoir# a", /*spanish*/"una Skulltula escondida en el #árbol junto a cierta deidad# otorga"}, + }); + + + hintTable[LH_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried by a lake# holds", /*french*/"une #Skulltula enterrée près d'un lac# a", /*spanish*/"una #Skulltula enterrada junto a un lago# otorga"}, + }); + + hintTable[LH_GS_SMALL_ISLAND] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider by a lake# holding", /*french*/"une #Skulltula sur un îlot du lac# a", /*spanish*/"la noche revela una #Skulltula junto a un lago# que otorga"}, + }); + + hintTable[LH_GS_LAB_WALL] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider by a lake# holding", /*french*/"une #Skulltula sur le mur d'un centre de recherche# a", /*spanish*/"la noche revela una #Skulltula junto a un lago# que otorga"}, + }); + + hintTable[LH_GS_LAB_CRATE] = HintText::Exclude({ + //obscure text + Text{"a spider deed underwater in a #lab crate# holds", /*french*/"une #Skulltula dans une boîte au fond d'une cuve d'eau# a", /*spanish*/"una #Skulltula bajo la sumergida caja de un laboratorio# otorga"}, + }); + + hintTable[LH_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider by a lake high in a tree# holding", /*french*/"une #Skulltula dans un grand arbre du lac# a", /*spanish*/"la noche revela #una Skulltula del lago sobre un árbol# que otorga"}, + }); + + + hintTable[GV_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried in a valley# holds", /*french*/"une #Skulltula enterré dans une vallée# a", /*spanish*/"una #Skulltula enterrada en un valle# otorga"}, + }); + + hintTable[GV_GS_SMALL_BRIDGE] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a valley# holding", /*french*/"une #Skulltula au dessus d'une petite cascade# a", /*spanish*/"la noche del pasado revela una #Skulltula del valle# que otorga"}, + }); + + hintTable[GV_GS_PILLAR] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a valley# holding", /*french*/"une #Skulltula sur une arche de pierre dans une vallée# a", /*spanish*/"la noche del futuro revela una #Skulltula del valle# que otorga"}, + }); + + hintTable[GV_GS_BEHIND_TENT] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a valley# holding", /*french*/"une #Skulltula derrière une tente# a", /*spanish*/"la noche del futuro revela una #Skulltula del valle# que otorga"}, + }); + + + hintTable[GF_GS_ARCHERY_RANGE] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a fortress# holding", /*french*/"une #Skulltula sur une cible de tir# a", /*spanish*/"la noche revela una #Skulltula de una fortaleza# que otorga"}, + }); + + hintTable[GF_GS_TOP_FLOOR] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a fortress# holding", /*french*/"une #Skulltula au sommet d'une forteresse# a", /*spanish*/"la noche revela una #Skulltula de una fortaleza# que otorga"}, + }); + + + hintTable[COLOSSUS_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried in the desert# holds", /*french*/"une #Skulltula enterrée au pied du colosse# a", /*spanish*/"una #Skulltula enterrada en el desierto# otorga"}, + }); + + hintTable[COLOSSUS_GS_HILL] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider deep in the desert# holding", /*french*/"une #Skulltula sur une colline dans le désert# a", /*spanish*/"la noche revela una #Skulltula en las profundidades del desierto# que otorga"}, + }); + + hintTable[COLOSSUS_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider deep in the desert# holding", /*french*/"une #Skulltula dans un arbre du désert# a", /*spanish*/"la noche revela una #Skulltula en las profundidades del desierto# que otorga"}, + }); + + + hintTable[KF_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + + hintTable[KAK_POTION_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + + hintTable[MARKET_POTION_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + + hintTable[MARKET_BAZAAR_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + + hintTable[KAK_BAZAAR_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + + hintTable[ZD_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + + hintTable[GC_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + + hintTable[HF_DEKU_SCRUB_GROTTO] = HintText::Exclude({ + //obscure text + Text{"a lonely #scrub in a hole# sells", /*french*/"la #peste Mojo dans une grotte de la plaine# vend", /*spanish*/"un #singular deku bajo un hoyo# de la llanura vende"}, + }); + + hintTable[LLR_DEKU_SCRUB_GROTTO_LEFT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo à la ferme# vend", /*spanish*/"un #trío de dekus# de una granja venden"}, + }); + + hintTable[LLR_DEKU_SCRUB_GROTTO_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo à la ferme# vend", /*spanish*/"un #trío de dekus# de una granja venden"}, + }); + + hintTable[LLR_DEKU_SCRUB_GROTTO_CENTER] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo à la ferme# vend", /*spanish*/"un #trío de dekus# de una granja venden"}, + }); + + + hintTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in the woods# sells", /*french*/"le #duo de peste Mojo près du théâtre# vend", /*spanish*/"un par de #dekus del bosque# venden"}, + }); + + hintTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in the woods# sells", /*french*/"le #duo de peste Mojo près du théâtre# vend", /*spanish*/"un par de #dekus del bosque# venden"}, + }); + + hintTable[LW_DEKU_SCRUB_NEAR_BRIDGE] = HintText::Exclude({ + //obscure text + Text{"a #scrub by a bridge# sells", /*french*/"la #peste Mojo près du pont dans les bois# vend", /*spanish*/"un #deku bajo un puente# del bosque venden"}, + }); + + hintTable[LW_DEKU_SCRUB_GROTTO_REAR] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo dans les sous-bois# vend", /*spanish*/"un #par de dekus subterráneos# del bosque venden"}, + }); + + hintTable[LW_DEKU_SCRUB_GROTTO_FRONT] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo dans les sous-bois# vend", /*spanish*/"un #par de dekus subterráneos# del bosque venden"}, + }); + + + hintTable[SFM_DEKU_SCRUB_GROTTO_REAR] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo au cœur du sanctuaire sylvestre# vend", /*spanish*/"un #par de dekus subterráneos# de la pradera sagrada venden"}, + }); + + hintTable[SFM_DEKU_SCRUB_GROTTO_FRONT] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo au cœur du sanctuaire sylvestre# vend", /*spanish*/"un #par de dekus subterráneos# de la pradera sagrada venden"}, + }); + + + hintTable[GC_DEKU_SCRUB_GROTTO_LEFT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le village Goron# vend", /*spanish*/"un #trío de dekus# de la Ciudad Goron venden"}, + }); + + hintTable[GC_DEKU_SCRUB_GROTTO_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le village Goron# vend", /*spanish*/"un #trío de dekus# de la Ciudad Goron venden"}, + }); + + hintTable[GC_DEKU_SCRUB_GROTTO_CENTER] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le village Goron# vend", /*spanish*/"un #trío de dekus# de la Ciudad Goron venden"}, + }); + + + hintTable[DMC_DEKU_SCRUB_GROTTO_LEFT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le volcan# vend", /*spanish*/"un #trío de dekus# del volcán venden"}, + }); + + hintTable[DMC_DEKU_SCRUB_GROTTO_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le volcan# vend", /*spanish*/"un #trío de dekus# del volcán venden"}, + }); + + hintTable[DMC_DEKU_SCRUB_GROTTO_CENTER] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le volcan# vend", /*spanish*/"un #trío de dekus# del volcán venden"}, + }); + + + hintTable[ZR_DEKU_SCRUB_GROTTO_REAR] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo près du fleuve# vend", /*spanish*/"un #par de dekus subterráneos# del río venden"}, + }); + + hintTable[ZR_DEKU_SCRUB_GROTTO_FRONT] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo près du fleuve# vend", /*spanish*/"un #par de dekus subterráneos# del río venden"}, + }); + + + hintTable[LH_DEKU_SCRUB_GROTTO_LEFT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo près du lac# vend", /*spanish*/"un #trío de dekus# del lago venden"}, + }); + + hintTable[LH_DEKU_SCRUB_GROTTO_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo près du lac# vend", /*spanish*/"un #trío de dekus# del lago venden"}, + }); + + hintTable[LH_DEKU_SCRUB_GROTTO_CENTER] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo près du lac# vend", /*spanish*/"un #trío de dekus# del lago venden"}, + }); + + + hintTable[GV_DEKU_SCRUB_GROTTO_REAR] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo près de la vallée# vend", /*spanish*/"un #par de dekus subterráneos# del valle venden"}, + }); + + hintTable[GV_DEKU_SCRUB_GROTTO_FRONT] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo près de la vallée# vend", /*spanish*/"un #par de dekus subterráneos# del valle venden"}, + }); + + + hintTable[COLOSSUS_DEKU_SCRUB_GROTTO_FRONT] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo dans le désert# vend", /*spanish*/"un #par de dekus subterráneos# del desierto venden"}, + }); + + hintTable[COLOSSUS_DEKU_SCRUB_GROTTO_REAR] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo dans le désert# vend", /*spanish*/"un #par de dekus subterráneos# del desierto venden"}, + }); + + + hintTable[LLR_STABLES_LEFT_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow in a stable# gifts", /*french*/"la #vache dans l'étable# donne", /*spanish*/"una #vaca del establo# brinda"}, + }); + + hintTable[LLR_STABLES_RIGHT_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow in a stable# gifts", /*french*/"la #vache dans l'étable# donne", /*spanish*/"una #vaca del establo# brinda"}, + }); + + hintTable[LLR_TOWER_RIGHT_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow in a ranch silo# gifts", /*french*/"la #vache dans le silo de la ferme# donne", /*spanish*/"una #vaca del granero# brinda"}, + }); + + hintTable[LLR_TOWER_LEFT_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow in a ranch silo# gifts", /*french*/"la #vache dans le silo de la ferme# donne", /*spanish*/"una #vaca del granero# brinda"}, + }); + + hintTable[KAK_IMPAS_HOUSE_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow imprisoned in a house# protects", /*french*/"la #vache en cage# donne", /*spanish*/"una #vaca enjaulada de una casa# brinda"}, + }); + + hintTable[DMT_COW_GROTTO_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow in a luxurious hole# offers", /*french*/"la #vache dans une grotte luxueuse# donne", /*spanish*/"una #vaca de un lujoso hoyo# brinda"}, + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp new file mode 100644 index 000000000..182948828 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp @@ -0,0 +1,1952 @@ +#include "../hint_list.hpp" + +void HintTable_Init_Item() { + hintTable[KOKIRI_SWORD] = HintText::Item({ + //obscure text + Text{"a butter knife", /*french*/"un couteau à beurre", /*spanish*/"un ágil puñal"}, + Text{"a starter slasher", /*french*/"une arme de débutant", /*spanish*/"una hoja de principiantes"}, + Text{"a switchblade", /*french*/"un canif", /*spanish*/"una navaja"}, + }, { + //ambiguous text + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"the Kokiri Sword", /*french*/"l'Épée Kokiri", /*spanish*/"la Espada Kokiri"} + ); + + hintTable[MASTER_SWORD] = HintText::Item({ + //obscure text + Text{"evil's bane", /*french*/"le fléau du mal", /*spanish*/"la destructora del mal"}, + Text{"a seven year limbo", /*french*/"une stase de sept ans", /*spanish*/"unos siete años de espera"}, + }, { + //ambiguous text + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"the Master Sword", /*french*/"l'Épée de Légende", /*spanish*/"la Espada Maestra"} + ); + + hintTable[GIANTS_KNIFE] = HintText::Item({ + //obscure text + Text{"a fragile blade", /*french*/"une lame fragile", /*spanish*/"una frágil hoja"}, + Text{"a breakable cleaver", /*french*/"un espadon de verre", /*spanish*/"un rompible acero"}, + }, { + //ambiguous text + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"the Giant's Knife", /*french*/"la Lame des Géants", /*spanish*/"la daga gigante"} + ); + + hintTable[BIGGORON_SWORD] = HintText::Item({ + //obscure text + Text{"the biggest blade", /*french*/"une lame gigantesque", /*spanish*/"el mayor mandoble"}, + Text{"a colossal cleaver", /*french*/"un espadon colossal", /*spanish*/"un estoque colosal"}, + }, { + //ambiguous text + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"the Biggoron Sword", /*french*/"l'Épée de Biggoron", /*spanish*/"la Espada de Biggoron"} + ); + + hintTable[DEKU_SHIELD] = HintText::Item({ + //obscure text + Text{"a wooden ward", /*french*/"un écu d'écorce", /*spanish*/"una protección del bosque"}, + Text{"a burnable barrier", /*french*/"une protection inflammable", /*spanish*/"una barrera quemable"}, + }, { + //ambiguous text + Text{"a shield", /*french*/"un bouclier", /*spanish*/"un escudo"}, + }, + //clear text + Text{"a Deku Shield", /*french*/"un Bouclier Mojo", /*spanish*/"un escudo deku"} + ); + + hintTable[HYLIAN_SHIELD] = HintText::Item({ + //obscure text + Text{"a steel safeguard", /*french*/"une carapace d'acier", /*spanish*/"una protección de acero"}, + Text{"Like Like's metal meal", /*french*/"un amuse-gueule de Pudding", /*spanish*/"un alimento de Like Like"}, + }, { + //ambiguous text + Text{"a shield", /*french*/"un bouclier", /*spanish*/"un escudo"}, + }, + //clear text + Text{"a Hylian Shield", /*french*/"un Bouclier Hylien", /*spanish*/"un escudo hyliano"} + ); + + hintTable[MIRROR_SHIELD] = HintText::Item({ + //obscure text + Text{"a reflective rampart", /*french*/"un capteur de lumière", /*spanish*/"una muralla reflectora"}, + Text{"Medusa's weakness", /*french*/"la faiblesse de Méduse", /*spanish*/"la debilidad de Medusa"}, + Text{"a silvered surface", /*french*/"une surface argentée", /*spanish*/"una superficie plateada"}, + }, { + //ambiguous text + Text{"a shield", /*french*/"un bouclier", /*spanish*/"un escudo"}, + }, + //clear text + Text{"the Mirror Shield", /*french*/"le Bouclier Miroir", /*spanish*/"el escudo espejo"} + ); + + hintTable[GORON_TUNIC] = HintText::Item({ + //obscure text + Text{"ruby robes", /*french*/"un pigment rouge", /*spanish*/"una vestimenta rubí"}, + Text{"fireproof fabric", /*french*/"un trésor anti-flamme", /*spanish*/"una ignífuga prenda"}, + Text{"cooking clothes", /*french*/"une tenue de cuisine", /*spanish*/"unos abrasantes ropajes"}, + }, { + //ambiguous text + Text{"a tunic", /*french*/"une tunique", /*spanish*/"un sayo"}, + }, + //clear text + Text{"a Goron Tunic", /*french*/"une Tunique Goron", /*spanish*/"un sayo goron"} + ); + + hintTable[ZORA_TUNIC] = HintText::Item({ + //obscure text + Text{"a sapphire suit", /*french*/"un pigment bleuté", /*spanish*/"una vestidura zafiro"}, + Text{"scuba gear", /*french*/"un habit de plongée", /*spanish*/"un traje impermeable"}, + Text{"a swimsuit", /*french*/"un costume de baignade", /*spanish*/"unos ropajes sumergibles"}, + }, { + //ambiguous text + Text{"a tunic", /*french*/"une tunique", /*spanish*/"un sayo"}, + Text{"something expensive", /*french*/"une chose dispendieuse", /*spanish*/"algo caro"}, + }, + //clear text + Text{"a Zora Tunic", /*french*/"une Tunique Zora", /*spanish*/"un sayo zora"} + ); + + hintTable[IRON_BOOTS] = HintText::Item({ + //obscure text + Text{"sink shoes", /*french*/"un boulet de fer", /*spanish*/"un calzado de las profundidades"}, + Text{"clank cleats", /*french*/"une paire de talons bruyants", /*spanish*/"unas suelas férreas"}, + }, { + //ambiguous text + Text{"some boots", /*french*/"une paire de bottes", /*spanish*/"un par de botas"}, + Text{"a feature of the Water Temple", /*french*/"une particularité du Temple de l'Eau", /*spanish*/"algo particular del Templo del Agua"}, + Text{"something heavy", /*french*/"une chose pesante", /*spanish*/"algo de lo más pesado"}, + }, + //clear text + Text{"the Iron Boots", /*french*/"une paire de Bottes de plomb", /*spanish*/"las botas de hierro"} + ); + + hintTable[HOVER_BOOTS] = HintText::Item({ + //obscure text + Text{"butter boots", /*french*/"une paire de patins de beurre", /*spanish*/"unas suelas resvaladizas"}, + Text{"sacred slippers", /*french*/"une paire de pantoufles sacrées", /*spanish*/"unos escurridizos botines"}, + Text{"spacewalkers", /*french*/"une paire de bottes spatiales", /*spanish*/"un calzado antigravitatorio"}, + }, { + //ambiguous text + Text{"some boots", /*french*/"une paire de bottes", /*spanish*/"un par de botas"}, + }, + //clear text + Text{"the Hover Boots", /*french*/"une paire de Bottes des airs", /*spanish*/"las botas voladoras"} + ); + + + hintTable[ZELDAS_LETTER] = HintText::Item({ + //obscure text + Text{"an autograph", /*french*/"un autographe", /*spanish*/"un autógrafo"}, + Text{"royal stationery", /*french*/"du papier royal", /*spanish*/"un escrito real"}, + Text{"royal snail mail", /*french*/"une enveloppe royale", /*spanish*/"correo de la realeza"}, + }, {}, + //clear text + Text{"Zelda's Letter", /*french*/"la Lettre de Zelda", /*spanish*/"la carta de Zelda"} + ); + + hintTable[WEIRD_EGG] = HintText::Item({ + //obscure text + Text{"a chicken dilemma", /*french*/"un drôle d'ovale", /*spanish*/"el dilema de la gallina"}, + }, { + //ambiguous text + Text{"an egg", /*french*/"un oeuf", /*spanish*/"un huevo"}, + }, + //clear text + Text{"the Weird Egg", /*french*/"l'Oeuf Curieux", /*spanish*/"el huevo extraño"} + ); + + hintTable[BOOMERANG] = HintText::Item({ + //obscure text + Text{"a banana", /*french*/"une banane", /*spanish*/"un plátano"}, + Text{"a stun stick", /*french*/"un bâton étourdissant", /*spanish*/"un palo aturdidor"}, + Text{"a yellow angle", /*french*/"un angle jaune", /*spanish*/"un ángulo amarillo"}, + }, { + //ambiguous text + Text{"something that can grab things", /*french*/"une chose qui peut attraper", /*spanish*/"algo que pueda agarrar cosas"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"the Boomerang", /*french*/"le Boomerang", /*spanish*/"el bumerán"} + ); + + hintTable[LENS_OF_TRUTH] = HintText::Item({ + //obscure text + Text{"a lie detector", /*french*/"un détecteur de mensonges", /*spanish*/"el detector de ilusiones"}, + Text{"a ghost tracker", /*french*/"un trouve-fantôme", /*spanish*/"el rastreador paranormal"}, + Text{"true sight", /*french*/"le troisième œil", /*spanish*/"el ojo que todo ve"}, + Text{"a detective's tool", /*french*/"un trésor Sheikah", /*spanish*/"la revelación verdadera"}, + }, { + //ambiguous text + Text{"a secret-finding tool", /*french*/"un cherche-secrets", /*spanish*/"un instrumento para hallar objetos"}, + }, + //clear text + Text{"the Lens of Truth", /*french*/"le Monocle de Vérité", /*spanish*/"la Lupa de la Verdad"} + ); + + hintTable[MEGATON_HAMMER] = HintText::Item({ + //obscure text + Text{"the dragon smasher", /*french*/"le tueur de dragons", /*spanish*/"un destructor de dragones"}, + Text{"the metal mallet", /*french*/"un outil de construction", /*spanish*/"un mazo de metal"}, + Text{"the heavy hitter", /*french*/"un poids lourd", /*spanish*/"un machacador"}, + }, { + //ambiguous text + Text{"something that can remove boulders", /*french*/"une chose qui enlève les rochers", /*spanish*/"algo que pueda quitar rocas"}, + }, + //clear text + Text{"the Megaton Hammer", /*french*/"la Masse des Titans", /*spanish*/"el martillo Megatón"} + ); + + hintTable[STONE_OF_AGONY] = HintText::Item({ + //obscure text + Text{"the shake shard", /*french*/"le fragment vibrant", /*spanish*/"el fragmento tintineante"}, + Text{"a blue alarm", /*french*/"une alerte bleue", /*spanish*/"una azul alarma"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + Text{"a secret-finding tool", /*french*/"un cherche-secrets", /*spanish*/"un instrumento para hallar objetos"}, + }, + //clear text + Text{"the Stone of Agony", /*french*/"la Pierre de Souffrance", /*spanish*/"la Piedra de la Agonía"} + ); + + hintTable[DINS_FIRE] = HintText::Item({ + //obscure text + Text{"an inferno", /*french*/"un brasier", /*spanish*/"un incendio"}, + Text{"a heat wave", /*french*/"une vague de chaleur", /*spanish*/"una onda de calor"}, + Text{"a red ball", /*french*/"une explosion de flammes", /*spanish*/"una roja esfera"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + }, + //clear text + Text{"Din's Fire", /*french*/"le Feu de Din", /*spanish*/"el Fuego de Din"} + ); + + hintTable[FARORES_WIND] = HintText::Item({ + //obscure text + Text{"teleportation", /*french*/"la téléportation", /*spanish*/"un teletransportador"}, + Text{"a relocation rune", /*french*/"une rune de relocation", /*spanish*/"una runa de transporte"}, + Text{"a green ball", /*french*/"une boule verte", /*spanish*/"una verde esfera"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + }, + //clear text + Text{"Farore's Wind", /*french*/"le Vent de Farore", /*spanish*/"el Viento de Farore"} + ); + + hintTable[NAYRUS_LOVE] = HintText::Item({ + //obscure text + Text{"a safe space", /*french*/"une bulle de cristal", /*spanish*/"una seguridad temporal"}, + Text{"an impregnable aura", /*french*/"un aura impénétrable", /*spanish*/"un aura impenetrable"}, + Text{"a blue barrier", /*french*/"une toison bleu", /*spanish*/"una barrera azul"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + }, + //clear text + Text{"Nayru's Love", /*french*/"l'Amour de Nayru", /*spanish*/"el Amor de Nayru"} + ); + + hintTable[FIRE_ARROWS] = HintText::Item({ + //obscure text + Text{"the furnace firearm" , /*french*/"une fusée solaire", /*spanish*/"el ardiente aguijón"}, + Text{"the burning bolts", /*french*/"un obus enflammé", /*spanish*/"las puntas ígneas"}, + Text{"a magma missile", /*french*/"un missile volcanique", /*spanish*/"el misil abrasador"}, + }, { + //ambiguous text + Text{"a magic arrow", /*french*/"une flèche magique", /*spanish*/"una flecha mágica"}, + }, + //clear text + Text{"the Fire Arrows", /*french*/"les Flèches de Feu", /*spanish*/"la flecha de fuego"} + ); + + hintTable[ICE_ARROWS] = HintText::Item({ + //obscure text + Text{"the refrigerator rocket", /*french*/"un missile pétrifiant", /*spanish*/"el misil congelador"}, + Text{"the frostbite bolts", /*french*/"un froid mordant", /*spanish*/"las puntas gélidas"}, + Text{"an iceberg maker", /*french*/"une aiguille glaciale", /*spanish*/"el control de escarcha"}, + }, { + //ambiguous text + Text{"a magic arrow", /*french*/"une flèche magique", /*spanish*/"una flecha mágica"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"the Ice Arrows", /*french*/"les Flèches de Glace", /*spanish*/"la flecha de hielo"} + ); + + hintTable[LIGHT_ARROWS] = HintText::Item({ + //obscure text + Text{"the shining shot", /*french*/"l'arme brillante", /*spanish*/"el haz de luz"}, + Text{"the luminous launcher", /*french*/"un jet de lumière", /*spanish*/"el disparo luminoso"}, + Text{"Ganondorf's bane", /*french*/"le fléau de Ganondorf", /*spanish*/"la perdición de Ganondorf"}, + Text{"the lighting bolts", /*french*/"l'éclair sacré", /*spanish*/"las puntas resplandecientes"}, + }, { + //ambiguous text + Text{"a magic arrow", /*french*/"une flèche magique", /*spanish*/"una flecha mágica"}, + }, + //clear text + Text{"the Light Arrows", /*french*/"les Flèches de Lumière", /*spanish*/"la flecha de luz"} + ); + + hintTable[GERUDO_MEMBERSHIP_CARD] = HintText::Item({ + //obscure text + Text{"a girl club membership", /*french*/"une carte de membre", /*spanish*/"una fémina membresía"}, + Text{"a desert tribe's pass", /*french*/"un laissez-passer", /*spanish*/"el vale del desierto"}, + }, { + Text{"a token of recognition", /*french*/"une preuve de reconnaissance", /*spanish*/"una prueba de reconocimiento"}, + }, + //clear text + Text{"the Gerudo Membership Card", /*french*/"la Carte Gerudo", /*spanish*/"el pase de socio gerudo"} + ); + + hintTable[MAGIC_BEAN] = HintText::Item({ + //obscure text + Text{"a wizardly legume", /*french*/"un légume ensorcelé", /*spanish*/"una legumbre hechizada"}, + }, { + //ambiguous text + Text{"something sometimes buried", /*french*/"une chose parfois enterrée", /*spanish*/"algo a veces enterrado"}, + }, + //clear text + Text{"a Magic Bean", /*french*/"un Haricot Magique", /*spanish*/"una judía mágica"} + ); + + hintTable[MAGIC_BEAN_PACK] = HintText::Item({ + //obscure text + Text{"wizardly legumes", /*french*/"un paquet de légumes ensorcelés", /*spanish*/"unas legumbres hechizadas"}, + }, { + //ambiguous text + Text{"something sometimes buried", /*french*/"une chose parfois enterrée", /*spanish*/"algo a veces enterrado"}, + }, + //clear text + Text{"Magic Beans", /*french*/"un Paquet de Haricots Magiques", /*spanish*/"unas judías mágicas"} + ); + + hintTable[DOUBLE_DEFENSE] = HintText::Item({ + //obscure text + Text{"a white outline", /*french*/"un rebord blanc", /*spanish*/"un contorno blanco"}, + Text{"damage decrease", /*french*/"une protection supplémentaire", /*spanish*/"una reducción de daño"}, + Text{"strengthened love", /*french*/"un amour coriace", /*spanish*/"un amor fortalecido"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + Text{"something heart-shaped", /*french*/"une chose en forme de coeur", /*spanish*/"algo con forma de corazón"}, + }, + //clear text + Text{"Double Defense", /*french*/"la Double Défence", /*spanish*/"la doble defensa"} + ); + + hintTable[GOLD_SKULLTULA_TOKEN] = HintText::Item({ + //obscure text + Text{"proof of destruction", /*french*/"un certificat d'élimination", /*spanish*/"una prueba de la destrucción"}, + Text{"an arachnid chip", /*french*/"un symbole cranien", /*spanish*/"una figura arácnida"}, + Text{"spider remains", /*french*/"une dépouille dorée", /*spanish*/"unos restos dorados"}, + Text{"one percent of a curse", /*french*/"un centième de malédiction", /*spanish*/"una centésima de una maldición"}, + }, { + //ambiguous text + Text{"a token of recognition", /*french*/"une preuve de reconnaissance", /*spanish*/"una prueba de reconocimiento"}, + Text{"something sometimes buried", /*french*/"une chose parfois enterrée", /*spanish*/"algo a veces enterrado"}, + }, + //clear text + Text{"a Gold Skulltula Token", /*french*/"un Symbole de Skulltula d'or", /*spanish*/"un símbolo de skulltula dorada"} + ); + + hintTable[POCKET_EGG] = HintText::Item({ + //obscure text + Text{"a Cucco container", /*french*/"un réservoir à Cocotte", /*spanish*/"cuco contenido"}, + Text{"a Cucco, eventually", /*french*/"un poussin éventuel", /*spanish*/"un futuro cuco"}, + Text{"a fowl youth", /*french*/"une omelette crue", /*spanish*/"una dulce juventud"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + Text{"an egg", /*french*/"un oeuf", /*spanish*/"un huevo"}, + }, + //clear text + Text{"the Pocket Egg", /*french*/"l'Oeuf de Poche", /*spanish*/"el huevo de bolsillo"} + ); + + hintTable[POCKET_CUCCO] = HintText::Item({ + //obscure text + Text{"a little clucker", /*french*/"un petit glousseur", /*spanish*/"un pollito chiquito"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Pocket Cucco", /*french*/"la Cocotte de Poche", /*spanish*/"el cuco de bolsillo"} + ); + + hintTable[COJIRO] = HintText::Item({ + //obscure text + Text{"a cerulean capon", /*french*/"un paon azur", /*spanish*/"un cerúleo capón"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"Cojiro", /*french*/"le p'tit poulet", /*spanish*/"a Cojiro"} + ); + + hintTable[ODD_MUSHROOM] = HintText::Item({ + //obscure text + Text{"a powder ingredient", /*french*/"un ingrédient à poudre", /*spanish*/"un oloroso ingrediente"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"an Odd Mushroom", /*french*/"un Champignon Suspect", /*spanish*/"un champiñón extraño"} + ); + + hintTable[ODD_POTION] = HintText::Item({ + //obscure text + Text{"Granny's goodies", /*french*/"la confiserie de mamie", /*spanish*/"la especialidad de la abuela"}, + }, { + //ambiguous text + Text{"something that contains medicine", /*french*/"une chose médicamenteuse", /*spanish*/"algo que contenga medicina"}, + Text{"something with a strange smell", /*french*/"une chose qui sent bizarre", /*spanish*/"algo con un olor extraño"}, + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"an Odd Potion", /*french*/"une Mixture Suspecte", /*spanish*/"una medicina rara"} + ); + + hintTable[POACHERS_SAW] = HintText::Item({ + //obscure text + Text{"a tree killer", /*french*/"un coupeur d'arbres", /*spanish*/"un destructor de árboles"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Poacher's Saw", /*french*/"la Scie du Chasseur", /*spanish*/"la sierra del furtivo"} + ); + + hintTable[BROKEN_SWORD] = HintText::Item({ + //obscure text + Text{"a shattered slicer", /*french*/"une arme cassée", /*spanish*/"una rebanadora rota"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"the Broken Goron's Sword", /*french*/"l'Épée Brisée de Goron", /*spanish*/"la espada goron rota"} + ); + + hintTable[PRESCRIPTION] = HintText::Item({ + //obscure text + Text{"a pill pamphlet", /*french*/"un document urgent", /*spanish*/"un instructivo medicinal"}, + Text{"a doctor's note", /*french*/"un papier médical", /*spanish*/"unas notas del doctor"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Prescription", /*french*/"une Ordonnance", /*spanish*/"la receta"} + ); + + hintTable[EYEBALL_FROG] = HintText::Item({ + //obscure text + Text{"a perceiving polliwog", /*french*/"un amphibien", /*spanish*/"un variopinto batracio"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Eyeball Frog", /*french*/"le Crapaud-qui-louche", /*spanish*/"la rana de ojos saltones"} + ); + + hintTable[EYEDROPS] = HintText::Item({ + //obscure text + Text{"a vision vial", /*french*/"une solution oculaire", /*spanish*/"un remedio para la vista"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Eyedrops", /*french*/"une phiole de Super-Gouttes", /*spanish*/"las supergotas oculares"} + ); + + hintTable[CLAIM_CHECK] = HintText::Item({ + //obscure text + Text{"a three day wait", /*french*/"un rendez-vous dans trois jours", /*spanish*/"unos tres días de espera"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Claim Check", /*french*/"un Certificat", /*spanish*/"el recibo"} + ); + + hintTable[PROGRESSIVE_HOOKSHOT] = HintText::Item({ + //obscure text + Text{"Dampé's keepsake", /*french*/"l'héritage d'Igor", /*spanish*/"un recuerdo de Dampé"}, + Text{"the Grapple Beam", /*french*/"le rayon grippeur", /*spanish*/"una garra metálica"}, + Text{"the BOING! chain", /*french*/"la chaîne de BOING!", /*spanish*/"una cadena retráctil"}, + }, { + //ambiguous text + Text{"something that can grab things", /*french*/"une chose qui peut attraper", /*spanish*/"algo que pueda agarrar cosas"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"a Hookshot", /*french*/"un Grappin", /*spanish*/"un gancho"} + ); + + hintTable[PROGRESSIVE_STRENGTH] = HintText::Item({ + //obscure text + Text{"power gloves", /*french*/"une paire de gants de travail", /*spanish*/"unos poderosos guanteletes"}, + Text{"metal mittens", /*french*/"une paire de mitaines", /*spanish*/"unas manoplas metálicas"}, + Text{"the heavy lifty", /*french*/"la puissance de dix hommes", /*spanish*/"un levantamiento pesado"}, + }, { + //ambiguous text + Text{"something that can remove boulders", /*french*/"une chose qui enlève les rochers", /*spanish*/"algo que pueda quitar rocas"}, + }, + //clear text + Text{"a Strength Upgrade", /*french*/"une Amélioration de Force", /*spanish*/"un aumento de fuerza"} + ); + + hintTable[PROGRESSIVE_BOMB_BAG] = HintText::Item({ + //obscure text + Text{"an explosive container", /*french*/"un porte-grenade", /*spanish*/"un recipiente explosivo"}, + Text{"a blast bag", /*french*/"un estomac de Dodongo", /*spanish*/"un zurrón de estallidos"}, + }, { + //ambiguous text + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + Text{"something that can remove boulders", /*french*/"une chose qui enlève les rochers", /*spanish*/"algo que pueda quitar rocas"}, + }, + //clear text + Text{"a Bomb Bag", /*french*/"un Sac de Bombes", /*spanish*/"un saco de bombas"} + ); + + hintTable[PROGRESSIVE_BOW] = HintText::Item({ + //obscure text + Text{"an archery enabler", /*french*/"un facilitateur de tir", /*spanish*/"un tiro al blanco"}, + Text{"a danger dart launcher", /*french*/"un tire-fléchette", /*spanish*/"un peligroso lanzadardos"}, + }, { + //ambiguous text + Text{"a projectile shooter", /*french*/"un tire-projectile", /*spanish*/"un arma de proyectil"}, + }, + //clear text + Text{"a Bow", /*french*/"l'Arc des Fées", /*spanish*/"un arco de las hadas"} + ); + + hintTable[PROGRESSIVE_SLINGSHOT] = HintText::Item({ + //obscure text + Text{"a seed shooter", /*french*/"un lance-noix", /*spanish*/"un lanzasemillas"}, + Text{"a rubberband", /*french*/"un élastique", /*spanish*/"un tirachinas"}, + Text{"a child's catapult", /*french*/"un jouet d'enfant", /*spanish*/"una catapulta infantil"}, + }, { + //ambiguous text + Text{"a projectile shooter", /*french*/"un tire-projectile", /*spanish*/"un arma de proyectil"}, + }, + //clear text + Text{"a Slingshot", /*french*/"un Lance-Pierre", /*spanish*/"una resortera de las hadas"} + ); + + hintTable[PROGRESSIVE_WALLET] = HintText::Item({ + //obscure text + Text{"a mo' money holder", /*french*/"un sac à sous", /*spanish*/"una cartera de dinero"}, + Text{"a gem purse", /*french*/"une sacoche", /*spanish*/"un zurrón de gemas"}, + Text{"a portable bank", /*french*/"une petite banque", /*spanish*/"un banco portable"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + }, + //clear text + Text{"a Wallet", /*french*/"une Bourse", /*spanish*/"una bolsa de rupias"} + ); + + hintTable[PROGRESSIVE_SCALE] = HintText::Item({ + //obscure text + Text{"a deeper dive", /*french*/"une bulle de plongée", /*spanish*/"un profundo buceo"}, + Text{"a piece of Zora", /*french*/"un morceau de Zora", /*spanish*/"un fragmento de Zora"}, + }, { + //ambiguous text + Text{"a diving tool", /*french*/"un outil de plongée", /*spanish*/"un instrumento de buceo"}, + }, + //clear text + Text{"a Zora Scale", /*french*/"une Écaille Zora", /*spanish*/"una escama Zora"} + ); + + hintTable[PROGRESSIVE_NUT_UPGRADE] = HintText::Item({ + //obscure text + Text{"more nuts", /*french*/"ecnore plus de noix", /*spanish*/"más semillas de nogal"}, + Text{"flashbang storage", /*french*/"un sac à noix", /*spanish*/"más frutos aturdidores"}, + }, { + //ambiguous text + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"Deku Nut Capacity", /*french*/"une Augmentation de Noix Mojo", /*spanish*/"un aumento de nueces deku"} + ); + + hintTable[PROGRESSIVE_STICK_UPGRADE] = HintText::Item({ + //obscure text + Text{"a lumber rack", /*french*/"un paquet de bois", /*spanish*/"más bastones"}, + Text{"more flammable twigs", /*french*/"beaucoup de branches", /*spanish*/"más varas"}, + }, { + //ambiguous text + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + }, + //clear text + Text{"Deku Stick Capacity", /*french*/"une augmentation de bâtons Mojo", /*spanish*/"un aumento de palos deku"} + ); + + hintTable[PROGRESSIVE_MAGIC_METER] = HintText::Item({ + //obscure text + Text{"mystic training", /*french*/"un potentiel magique", /*spanish*/"una maestría mística"}, + Text{"pixie dust", /*french*/"de la poudre de fée", /*spanish*/"un polvo de hada"}, + Text{"a green rectangle", /*french*/"un rectangle vert", /*spanish*/"una verduzca barra"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + }, + //clear text + Text{"a Magic Meter", /*french*/"une Jauge de Magie", /*spanish*/"un aumento de poder mágico"} + ); + + hintTable[PROGRESSIVE_OCARINA] = HintText::Item({ + //obscure text + Text{"a flute", /*french*/"un bec musical", /*spanish*/"un utensilio musical"}, + Text{"a music maker", /*french*/"un porteur de chansons", /*spanish*/"un instrumento"}, + }, { + //ambiguous text + Text{"something given by Saria", /*french*/"un cadeau de Saria", /*spanish*/"un obsequio de Saria"}, + Text{"something kept by the royal family", /*french*/"une chose qui paralyse", /*spanish*/"algo guardado por la familia real"}, + }, + //clear text + Text{"an Ocarina", /*french*/"un ocarina", /*spanish*/"una ocarina"} + ); + + hintTable[PROGRESSIVE_BOMBCHUS] = HintText::Item({ + //obscure text + Text{"mice bombs", /*french*/"un adorable explosif", /*spanish*/"unas bombas roedoras"}, + Text{"proximity mice", /*french*/"une mine anti-rongeur", /*spanish*/"unos explosivos ratoncitos"}, + Text{"wall crawlers", /*french*/"un rapide grimpeur", /*spanish*/"unos trepaparedes"}, + Text{"trail blazers", /*french*/"un zigzag éclatant", /*spanish*/"unas ratas propulsadas"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombchus", /*french*/"un paquet de Missiles", /*spanish*/"unos bombchus"} + ); + + hintTable[PROGRESSIVE_GORONSWORD] = HintText::Item({ + //obscure text + Text{"a long blade", /*french*/"une longue lame", /*spanish*/"una gran hoja"}, + Text{"a Goron weapon", /*french*/"une arme Goron", /*spanish*/"un arma goron"}, + }, { + //ambiguous text + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"a Goron Sword", /*french*/"une épée Goron", /*spanish*/"una espada goron"} + ); + + hintTable[EMPTY_BOTTLE] = HintText::Item({ + //obscure text + Text{"a glass container", /*french*/"un cylindre de cristal", /*spanish*/"un recipiente de cristal"}, + Text{"an empty jar", /*french*/"une jarre incassable", /*spanish*/"un frasco vacío"}, + Text{"encased air", /*french*/"un bocal d'air", /*spanish*/"aire a presión"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Bottle", /*french*/"un flacon vide", /*spanish*/"una botella"} + ); + + hintTable[BOTTLE_WITH_MILK] = HintText::Item({ + //obscure text + Text{"cow juice", /*french*/"une source de calcium", /*spanish*/"una fuente de calcio"}, + Text{"a white liquid", /*french*/"un liquide blanc", /*spanish*/"una bebida nutritiva"}, + Text{"a baby's breakfast", /*french*/"du jus pour bébé", /*spanish*/"un trago para bebés"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Milk Bottle", /*french*/"un flacon de lait", /*spanish*/"una botella de leche"} + ); + + hintTable[BOTTLE_WITH_RED_POTION] = HintText::Item({ + //obscure text + Text{"a vitality vial", /*french*/"un mélange de vitalité", /*spanish*/"una pócima vitalicia"}, + Text{"a red liquid", /*french*/"un liquide rouge", /*spanish*/"un remedio rojizo"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Red Potion Bottle", /*french*/"un flacon de potion rouge", /*spanish*/"una botella de poción roja"} + ); + + hintTable[BOTTLE_WITH_GREEN_POTION] = HintText::Item({ + //obscure text + Text{"a magic mixture", /*french*/"une réserve magique", /*spanish*/"un potingue mágico"}, + Text{"a green liquid", /*french*/"un liquide vert", /*spanish*/"un remedio verduzco"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Green Potion Bottle", /*french*/"un flacon de potion verte", /*spanish*/"una botella de poción verde"} + ); + + hintTable[BOTTLE_WITH_BLUE_POTION] = HintText::Item({ + //obscure text + Text{"an ailment antidote", /*french*/"l'élixir ultime", /*spanish*/"un antídoto para el dolor"}, + Text{"a blue liquid", /*french*/"un liquide bleu", /*spanish*/"un remedio índigo"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Blue Potion Bottle", /*french*/"un flacon de potion bleue", /*spanish*/"una botella de poción azul"} + ); + + hintTable[BOTTLE_WITH_FAIRY] = HintText::Item({ + //obscure text + Text{"an imprisoned fairy", /*french*/"une fée emprisonnée", /*spanish*/"un hada atrapada"}, + Text{"an extra life", /*french*/"une vie de rechange", /*spanish*/"una oportunidad más"}, + Text{"Navi's cousin", /*french*/"le cousin de Navi", /*spanish*/"una prima de Navi"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Fairy Bottle", /*french*/"une fée en flacon", /*spanish*/"un hada en una botella"} + ); + + hintTable[BOTTLE_WITH_FISH] = HintText::Item({ + //obscure text + Text{"an aquarium", /*french*/"un aquarium", /*spanish*/"un escamado ser"}, + Text{"a deity's snack", /*french*/"le repas d'un dieu marin", /*spanish*/"un tentempié de cierta deidad"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Fish Bottle", /*french*/"un poisson en flacon", /*spanish*/"un pez en una botella"} + ); + + hintTable[BOTTLE_WITH_BLUE_FIRE] = HintText::Item({ + //obscure text + Text{"a conflagration canteen", /*french*/"une mystérieuse flamme", /*spanish*/"un incendio retenido"}, + Text{"an icemelt jar", /*french*/"un brasier glacial", /*spanish*/"unas brasas enfrascadas"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Blue Fire Bottle", /*french*/"une flamme bleue en flacon", /*spanish*/"una botella de fuego azul"} + ); + + hintTable[BOTTLE_WITH_BUGS] = HintText::Item({ + //obscure text + Text{"an insectarium", /*french*/"un insectarium", /*spanish*/"unos invertebrados seres"}, + Text{"Skulltula finders", /*french*/"une poignée de trouve-Skulltula", /*spanish*/"unos rastreadores de skulltulas"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Bug Bottle", /*french*/"un insecte en flacon", /*spanish*/"unos insectos en una botella"} + ); + + hintTable[BOTTLE_WITH_POE] = HintText::Item({ + //obscure text + Text{"a spooky ghost", /*french*/"un effroyable fantôme", /*spanish*/"un espantoso espectro"}, + Text{"a face in the jar", /*french*/"un visage dans un bocal", /*spanish*/"una expresión enfrascada"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Poe Bottle", /*french*/"un Esprit en flacon", /*spanish*/"un Poe en una botella"} + ); + + hintTable[BOTTLE_WITH_BIG_POE] = HintText::Item({ + //obscure text + Text{"the spookiest ghost", /*french*/"un épouvantable spectre", /*spanish*/"el espectro más espeluznante"}, + Text{"a sidequest spirit", /*french*/"un précieux esprit", /*spanish*/"un buen valorado espíritu"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Big Poe Bottle", /*french*/"une Ame en flacon", /*spanish*/"un Gran Poe en una botella"} + ); + + hintTable[RUTOS_LETTER] = HintText::Item({ + //obscure text + Text{"a call for help", /*french*/"un appel au secours", /*spanish*/"una llamada de auxilio"}, + Text{"the note that Mweeps", /*french*/"un message qui fait mwip", /*spanish*/"un escrito mweep"}, + Text{"an SOS call", /*french*/"un signal SOS", /*spanish*/"una nota de socorro"}, + Text{"a fishy stationery", /*french*/"un papier mouillé", /*spanish*/"un mensaje de ayuda"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"Ruto's Letter", /*french*/"la lettre de Ruto", /*spanish*/"la carta de Ruto"} + ); + + hintTable[ZELDAS_LULLABY] = HintText::Item({ + //obscure text + Text{"a song of royal slumber", /*french*/"une chanson royale", /*spanish*/"la canción real"}, + Text{"a triforce tune", /*french*/"la musique sacrée", /*spanish*/"la melodía de la trifuerza"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + Text{"something kept by the royal family", /*french*/"une chose qui paralyse", /*spanish*/"algo guardado por la familia real"}, + }, + //clear text + Text{"Zelda's Lullaby", /*french*/"la berceuse de Zelda", /*spanish*/"la Nana de Zelda"} + ); + + hintTable[EPONAS_SONG] = HintText::Item({ + //obscure text + Text{"an equestrian etude", /*french*/"une hymne équestre", /*spanish*/"una copla ecuestre"}, + Text{"Malon's melody", /*french*/"la mélodie des vaches", /*spanish*/"la sonata de Malon"}, + Text{"a ranch song", /*french*/"le chant des champs", /*spanish*/"un canto rupestre"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + }, + //clear text + Text{"Epona's Song", /*french*/"le chant d'Epona", /*spanish*/"la Canción de Epona"} + ); + + hintTable[SARIAS_SONG] = HintText::Item({ + //obscure text + Text{"a song of dancing Gorons", /*french*/"une chanson danceuse", /*spanish*/"un pegadizo tono goron"}, + Text{"Saria's phone number", /*french*/"le téléphone d'une amie", /*spanish*/"una consulta de asistencia"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + Text{"something given by Saria", /*french*/"un cadeau de Saria", /*spanish*/"un obsequio de Saria"}, + }, + //clear text + Text{"Saria's Song", /*french*/"le chant de Saria", /*spanish*/"la Canción de Saria"} + ); + + hintTable[SUNS_SONG] = HintText::Item({ + //obscure text + Text{"Sunny Day", /*french*/"Zénith", /*spanish*/"un día soleado"}, + Text{"the ReDead's bane", /*french*/"le fléau des Éffrois", /*spanish*/"la destructora de Redeads"}, + Text{"the Gibdo's bane", /*french*/"le fléau des Gibdo", /*spanish*/"la destructora de Gibdos"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"the Sun's Song", /*french*/"le chant du soleil", /*spanish*/"la Canción del Sol"} + ); + + hintTable[SONG_OF_TIME] = HintText::Item({ + //obscure text + Text{"a song 7 years long", /*french*/"le flot du temps", /*spanish*/"la setenada canción"}, + Text{"the tune of ages", /*french*/"le Chant des Âges", /*spanish*/"la melodía eónica"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + }, + //clear text + Text{"the Song of Time", /*french*/"le chant du temps", /*spanish*/"la Canción del tiempo"} + ); + + hintTable[SONG_OF_STORMS] = HintText::Item({ + //obscure text + Text{"Rain Dance", /*french*/"Danse Pluie", /*spanish*/"la danza de la lluvia"}, + Text{"a thunderstorm tune", /*french*/"une hymne foudroyante", /*spanish*/"una sonata tormentosa"}, + Text{"windmill acceleration", /*french*/"l'accélérateur de moulins", /*spanish*/"el arranque de molinos"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + }, + //clear text + Text{"the Song of Storms", /*french*/"le chant des tempêtes", /*spanish*/"la Canción de la Tormenta"} + ); + + hintTable[MINUET_OF_FOREST] = HintText::Item({ + //obscure text + Text{"the song of tall trees", /*french*/"le bruit des arbres", /*spanish*/"la canción de las copas"}, + Text{"an arboreal anthem", /*french*/"l'hymne sylvestre", /*spanish*/"el himno forestal"}, + Text{"a green spark trail", /*french*/"une comète verte", /*spanish*/"el sendero esmeralda"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Minuet of Forest", /*french*/"le menuet de la forêt", /*spanish*/"el Minueto del bosque"} + ); + + hintTable[BOLERO_OF_FIRE] = HintText::Item({ + //obscure text + Text{"a song of lethal lava", /*french*/"une musique enflammée", /*spanish*/"la canción de la lava"}, + Text{"a red spark trail", /*french*/"une comète rouge", /*spanish*/"el sendero rubí"}, + Text{"a volcanic verse", /*french*/"le souffle du volcan", /*spanish*/"el verso volcánico"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Bolero of Fire", /*french*/"le boléro du feu", /*spanish*/"el Bolero del fuego"} + ); + + hintTable[SERENADE_OF_WATER] = HintText::Item({ + //obscure text + Text{"a song of a damp ditch", /*french*/"le calme de l'eau", /*spanish*/"la canción del estanque"}, + Text{"a blue spark trail", /*french*/"une comète bleue", /*spanish*/"el sendero zafiro"}, + Text{"the lake's lyric", /*french*/"la voix du lac", /*spanish*/"la letra del lago"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Serenade of Water", /*french*/"la sérénade de l'eau", /*spanish*/"la Serenata del agua"} + ); + + hintTable[REQUIEM_OF_SPIRIT] = HintText::Item({ + //obscure text + Text{"a song of sandy statues", /*french*/"la mélodie d'une grande statue", /*spanish*/"la canción de la gran estatua"}, + Text{"an orange spark trail", /*french*/"une comète orange", /*spanish*/"el sendero ámbar"}, + Text{"the desert ditty", /*french*/"le vent du désert", /*spanish*/"la estrofa del desierto"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Requiem of Spirit", /*french*/"le requiem des esprits", /*spanish*/"el Réquiem del espíritu"} + ); + + hintTable[NOCTURNE_OF_SHADOW] = HintText::Item({ + //obscure text + Text{"a song of spooky spirits", /*french*/"une hymne de chair de poule", /*spanish*/"la canción de los espectros"}, + Text{"a graveyard boogie", /*french*/"un boogie de fantômes", /*spanish*/"una honra fúnebre"}, + Text{"a haunted hymn", /*french*/"une chanson lugubre", /*spanish*/"una estrofa encantada"}, + Text{"a purple spark trail", /*french*/"une comète mauve", /*spanish*/"el sendero malva"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Nocturne of Shadow", /*french*/"le nocturne de l'ombre", /*spanish*/"el Nocturno de la sombra"} + ); + + hintTable[PRELUDE_OF_LIGHT] = HintText::Item({ + //obscure text + Text{"a luminous prologue melody", /*french*/"une matine illuminée", /*spanish*/"la melodía refulgente"}, + Text{"a yellow spark trail", /*french*/"une comète jaune", /*spanish*/"el sendero resplandeciente"}, + Text{"the temple traveler", /*french*/"un chant de sanctuaire", /*spanish*/"la ruta del templo"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Prelude of Light", /*french*/"le prélude de la lumière", /*spanish*/"el Preludio de la luz"} + ); + hintTable[DEKU_TREE_MAP] = HintText::Item({ + //obscure text + Text{"a mossy atlas", /*french*/"un atlas boisé", /*spanish*/"un atlas musgoso"}, + Text{"some mossy blueprints", /*french*/"un plan boisé", /*spanish*/"unos planos musgosos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Deku Tree Map", /*french*/"la carte de l'Arbre Mojo", /*spanish*/"el mapa del Gran Árbol Deku"} + ); + hintTable[DODONGOS_CAVERN_MAP] = HintText::Item({ + //obscure text + Text{"a rocky atlas", /*french*/"un atlas rocheux", /*spanish*/"un atlas rocoso"}, + Text{"some rocky blueprints", /*french*/"un plan rocheux", /*spanish*/"unos planos rocosos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Dodongo's Cavern Map", /*french*/"la carte de la Caverne Dodongo", /*spanish*/"el mapa de la Cueva de los Dodongos"} + ); + hintTable[JABU_JABUS_BELLY_MAP] = HintText::Item({ + //obscure text + Text{"a fishy atlas", /*french*/"un atlas digéré", /*spanish*/"un atlas digesto"}, + Text{"some fishy blueprints", /*french*/"un plan digéré", /*spanish*/"unos planos digestos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Jabu-Jabu's Belly Map", /*french*/"la carte de Jabu-Jabu", /*spanish*/"el mapa de la Tripa de Jabu-Jabu"} + ); + hintTable[FOREST_TEMPLE_MAP] = HintText::Item({ + //obscure text + Text{"a sylvan atlas", /*french*/"un atlas sylvestre", /*spanish*/"un atlas enselvado"}, + Text{"some sylvan blueprints", /*french*/"un plan sylvestre", /*spanish*/"unos planos enselvados"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Forest Temple Map", /*french*/"la carte du Temple de la Forêt", /*spanish*/"el mapa del Templo del Bosque"} + ); + hintTable[FIRE_TEMPLE_MAP] = HintText::Item({ + //obscure text + Text{"a molten atlas", /*french*/"un atlas fondu", /*spanish*/"un atlas fundido"}, + Text{"some molten blueprints", /*french*/"un plan fondu", /*spanish*/"unos planos fundidos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Fire Temple Map", /*french*/"la carte du Temple du Feu", /*spanish*/"el mapa del Templo del Fuego"} + ); + hintTable[WATER_TEMPLE_MAP] = HintText::Item({ + //obscure text + Text{"a wet atlas", /*french*/"un atlas humide", /*spanish*/"un atlas mojado"}, + Text{"some wet blueprints", /*french*/"un plan humide", /*spanish*/"unos planos mojados"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Water Temple Map", /*french*/"la carte du Temple de l'Eau", /*spanish*/"el mapa del Templo del Agua"} + ); + hintTable[SPIRIT_TEMPLE_MAP] = HintText::Item({ + //obscure text + Text{"a sandy atlas", /*french*/"un atlas sableux", /*spanish*/"un atlas arenoso"}, + Text{"some sandy blueprints", /*french*/"un plan sableux", /*spanish*/"unos planos arenosos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Spirit Temple Map", /*french*/"la carte du Temple de l'Esprit", /*spanish*/"el mapa del Templo del Espíritu"} + ); + hintTable[SHADOW_TEMPLE_MAP] = HintText::Item({ + //obscure text + Text{"a creepy atlas", /*french*/"un atlas sinistre", /*spanish*/"un atlas siniestra"}, + Text{"some creepy blueprints", /*french*/"un plan sinistre", /*spanish*/"unos planos siniestras"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Shadow Temple Map", /*french*/"la carte du Temple de l'Ombre", /*spanish*/"el mapa del Templo de las Sombras"} + ); + hintTable[BOTTOM_OF_THE_WELL_MAP] = HintText::Item({ + //obscure text + Text{"a moldy atlas", /*french*/"un atlas moisi", /*spanish*/"un atlas mohoso"}, + Text{"some moldy blueprints", /*french*/"un plan moisi", /*spanish*/"unos planos mohosos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Bottom of the Well Map", /*french*/"la carte du fond du Puits", /*spanish*/"el mapa del Fondo del pozo"} + ); + hintTable[ICE_CAVERN_MAP] = HintText::Item({ + //obscure text + Text{"a polar atlas", /*french*/"un atlas polaire", /*spanish*/"un atlas polar"}, + Text{"some polar blueprints", /*french*/"un plan polaire", /*spanish*/"unos planos polars"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Ice Cavern Map", /*french*/"la carte de la Caverne Polaire", /*spanish*/"el mapa de la Caverna de hielo"} + ); + hintTable[DEKU_TREE_COMPASS] = HintText::Item({ + //obscure text + Text{"a mossy treasure tracker", /*french*/"un cherche-trésor boisé", /*spanish*/"un zahorí musgoso"}, + Text{"a mossy magnetic needle", /*french*/"une aimant boisée", /*spanish*/"un imán musgoso"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Deku Tree Compass", /*french*/"la boussole de l'Arbre Mojo", /*spanish*/"la brújula del Gran Árbol Deku"} + ); + hintTable[DODONGOS_CAVERN_COMPASS] = HintText::Item({ + //obscure text + Text{"a rocky treasure tracker", /*french*/"un cherche-trésor rocheux", /*spanish*/"un zahorí rocoso"}, + Text{"a rocky magnetic needle", /*french*/"une aimant rocheux", /*spanish*/"un imán rocoso"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Dodongo's Cavern Compass", /*french*/"la boussole de la Caverne Dodongo", /*spanish*/"la brújula de la Cueva de los Dodongos"} + ); + hintTable[JABU_JABUS_BELLY_COMPASS] = HintText::Item({ + //obscure text + Text{"a fishy treasure tracker", /*french*/"un cherche-trésor digéré", /*spanish*/"un zahorí digesto"}, + Text{"a fishy magnetic needle", /*french*/"une aimant digéré", /*spanish*/"un imán digesto"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Jabu-Jabu's Belly Compass", /*french*/"la boussole de Jabu-Jabu", /*spanish*/"la brújula de la Tripa de Jabu-Jabu"} + ); + hintTable[FOREST_TEMPLE_COMPASS] = HintText::Item({ + //obscure text + Text{"a sylvan treasure tracker", /*french*/"un cherche-trésor sylvestre", /*spanish*/"un zahorí enselvado"}, + Text{"a sylvan magnetic needle", /*french*/"une aimant sylvestre", /*spanish*/"un imán enselvado"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Forest Temple Compass", /*french*/"la boussole du Temple de la Forêt", /*spanish*/"la brújula del Templo del Bosque"} + ); + hintTable[FIRE_TEMPLE_COMPASS] = HintText::Item({ + //obscure text + Text{"a molten treasure tracker", /*french*/"un cherche-trésor fondu", /*spanish*/"un zahorí fundido"}, + Text{"a molten magnetic needle", /*french*/"une aimant fondu", /*spanish*/"un imán fundido"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Fire Temple Compass", /*french*/"la boussole du Temple du Feu", /*spanish*/"la brújula del Templo del Fuego"} + ); + hintTable[WATER_TEMPLE_COMPASS] = HintText::Item({ + //obscure text + Text{"a wet treasure tracker", /*french*/"un cherche-trésor humide", /*spanish*/"un zahorí mojado"}, + Text{"a wet magnetic needle", /*french*/"une aimant humide", /*spanish*/"un imán mojado"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Water Temple Compass", /*french*/"la boussole du Temple de l'Eau", /*spanish*/"la brújula del Templo del Agua"} + ); + hintTable[SPIRIT_TEMPLE_COMPASS] = HintText::Item({ + //obscure text + Text{"a sandy treasure tracker", /*french*/"un cherche-trésor sableux", /*spanish*/"un zahorí arenoso"}, + Text{"a sandy magnetic needle", /*french*/"une aimant sableux", /*spanish*/"un imán arenoso"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Spirit Temple Compass", /*french*/"la boussole du Temple de l'Esprit", /*spanish*/"la brújula del Templo del Espíritu"} + ); + hintTable[SHADOW_TEMPLE_COMPASS] = HintText::Item({ + //obscure text + Text{"a creepy treasure tracker", /*french*/"un cherche-trésor sinistre", /*spanish*/"un zahorí siniestra"}, + Text{"a creepy magnetic needle", /*french*/"une aimant sinistre", /*spanish*/"un imán siniestra"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Shadow Temple Compass", /*french*/"la boussole du Temple de l'Ombre", /*spanish*/"la brújula del Templo de las Sombras"} + ); + hintTable[BOTTOM_OF_THE_WELL_COMPASS] = HintText::Item({ + //obscure text + Text{"a dank treasure tracker", /*french*/"un cherche-trésor moisi", /*spanish*/"un zahorí mohoso"}, + Text{"a dank magnetic needle", /*french*/"une aimant moisi", /*spanish*/"un imán mohoso"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Bottom of the Well Compass", /*french*/"la boussole du fond du Puits", /*spanish*/"la brújula del Fondo del pozo"} + ); + hintTable[ICE_CAVERN_COMPASS] = HintText::Item({ + //obscure text + Text{"a polar treasure tracker", /*french*/"un cherche-trésor polaire", /*spanish*/"un zahorí polar"}, + Text{"a polar magnetic needle", /*french*/"une aimant polaire", /*spanish*/"un imán polar"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Ice Cavern Compass", /*french*/"la Boussole de la Caverne Polaire", /*spanish*/"la brújula de la Caverna de hielo"} + ); + hintTable[FOREST_TEMPLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a sylvan master of unlocking", /*french*/"un anti-grosse porte sylvestre", /*spanish*/"la clave enselvada de un jefe"}, + Text{"a sylvan dungeon's master pass", /*french*/"une clé maléfique sylvestree", /*spanish*/"el pase maestro enselvado"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Forest Temple Boss Key", /*french*/"la Clé d'Or du Temple de la Forêt", /*spanish*/"la gran llave del Templo del Bosque"} + ); + hintTable[FIRE_TEMPLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a molten master of unlocking", /*french*/"un anti-grosse porte fondu", /*spanish*/"la clave fundido de un jefe"}, + Text{"a molten dungeon's master pass", /*french*/"une clé maléfique fondu", /*spanish*/"el pase maestro fundido"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Fire Temple Boss Key", /*french*/"la Clé d'Or du Temple du Feu", /*spanish*/"la gran llave del Templo del Fuego"} + ); + hintTable[WATER_TEMPLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a wet master of unlocking", /*french*/"un anti-grosse porte humide", /*spanish*/"la clave mojado de un jefe"}, + Text{"a wet dungeon's master pass", /*french*/"une clé maléfique humide", /*spanish*/"el pase maestro mojado"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Water Temple Boss Key", /*french*/"la Clé d'Or du Temple de l'Eau", /*spanish*/"la gran llave del Templo del Agua"} + ); + hintTable[SPIRIT_TEMPLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a sandy master of unlocking", /*french*/"un anti-grosse porte sableux", /*spanish*/"la clave arenoso de un jefe"}, + Text{"a sandy dungeon's master pass", /*french*/"une clé maléfique sableux", /*spanish*/"el pase maestro arenoso"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Spirit Temple Boss Key", /*french*/"la Clé d'Or du Temple de l'Esprit", /*spanish*/"la gran llave del Templo del Espíritu"} + ); + hintTable[SHADOW_TEMPLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a creepy master of unlocking", /*french*/"un anti-grosse porte sinistre", /*spanish*/"la clave siniestra de un jefe"}, + Text{"a creepy dungeon's master pass", /*french*/"une clé maléfique sinistre", /*spanish*/"el pase maestro siniestra"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Shadow Temple Boss Key", /*french*/"la Clé d'Or du Temple de l'Ombre", /*spanish*/"la gran llave del Templo de las Sombras"} + ); + hintTable[GANONS_CASTLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a final master of unlocking", /*french*/"un anti-grosse porte final", /*spanish*/"la clave final de un jefe"}, + Text{"a final dungeon's master pass", /*french*/"une clé maléfique final", /*spanish*/"el pase maestro final"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Ganon's Castle Boss Key", /*french*/"la Clé d'Or du Château de Ganon", /*spanish*/"la gran llave del Castillo de Ganon"} + ); + hintTable[FOREST_TEMPLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a sylvan tool for unlocking", /*french*/"un anti-porte sylvestre", /*spanish*/"una clave de una entrada enselvada"}, + Text{"a sylvan dungeon pass", /*french*/"le rêve sylvestre d'un prisonnier", /*spanish*/"un pase de una mazmorra enselvada"}, + Text{"a sylvan lock remover", /*french*/"un efface-serrure sylvestre", /*spanish*/"un destructor de cerraduras enselvada"}, + Text{"a sylvan lockpick", /*french*/"un crochet à porte sylvestre", /*spanish*/"una apertura portentosa enselvada"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Forest Temple Small Key", /*french*/"une petite clé du Temple de la Forêt", /*spanish*/"una llave pequeña del Templo del Bosque"} + ); + hintTable[FIRE_TEMPLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a molten tool for unlocking", /*french*/"un anti-porte fondu", /*spanish*/"una clave de una entrada fundida"}, + Text{"a molten dungeon pass", /*french*/"le rêve fondu d'un prisonnier", /*spanish*/"un pase de una mazmorra fundida"}, + Text{"a molten lock remover", /*french*/"un efface-serrure fondu", /*spanish*/"un destructor de cerraduras fundida"}, + Text{"a molten lockpick", /*french*/"un crochet à porte fondu", /*spanish*/"una apertura portentosa fundida"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Fire Temple Small Key", /*french*/"une petite clé du Temple du Feu", /*spanish*/"una llave pequeña del Templo del Fuego"} + ); + hintTable[WATER_TEMPLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a wet tool for unlocking", /*french*/"un anti-porte humide", /*spanish*/"una clave de una entrada mojada"}, + Text{"a wet dungeon pass", /*french*/"le rêve humide d'un prisonnier", /*spanish*/"un pase de una mazmorra mojada"}, + Text{"a wet lock remover", /*french*/"un efface-serrure humide", /*spanish*/"un destructor de cerraduras mojada"}, + Text{"a wet lockpick", /*french*/"un crochet à porte humide", /*spanish*/"una apertura portentosa mojada"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Water Temple Small Key", /*french*/"une petite clé du Temple de l'Eau", /*spanish*/"una llave pequeña del Templo del Agua"} + ); + hintTable[SPIRIT_TEMPLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a sandy tool for unlocking", /*french*/"un anti-porte sableux", /*spanish*/"una clave de una entrada arenosa"}, + Text{"a sandy dungeon pass", /*french*/"le rêve sableux d'un prisonnier", /*spanish*/"un pase de una mazmorra arenosa"}, + Text{"a sandy lock remover", /*french*/"un efface-serrure sableux", /*spanish*/"un destructor de cerraduras arenosa"}, + Text{"a sandy lockpick", /*french*/"un crochet à porte sableux", /*spanish*/"una apertura portentosa arenosa"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Spirit Temple Small Key", /*french*/"une petite clé du Temple de l'Esprit", /*spanish*/"una llave pequeña del Templo del Espíritu"} + ); + hintTable[SHADOW_TEMPLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a creepy tool for unlocking", /*french*/"un anti-porte sinistre", /*spanish*/"una clave de una entrada siniestra:a"}, + Text{"a creepy dungeon pass", /*french*/"le rêve sinistre d'un prisonnier", /*spanish*/"un pase de una mazmorra siniestra:a"}, + Text{"a creepy lock remover", /*french*/"un efface-serrure sinistre", /*spanish*/"un destructor de cerraduras siniestra:a"}, + Text{"a creepy lockpick", /*french*/"un crochet à porte sinistre", /*spanish*/"una apertura portentosa siniestra:a"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Shadow Temple Small Key", /*french*/"une petite clé du Temple de l'Ombre", /*spanish*/"una llave pequeña del Templo de las Sombras"} + ); + hintTable[GERUDO_TRAINING_GROUNDS_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a labyrinthian tool for unlocking", /*french*/"un anti-porte labyrinthique", /*spanish*/"una clave de una entrada laberíntica"}, + Text{"a labyrinthian dungeon pass", /*french*/"le rêve labyrinthique d'un prisonnier", /*spanish*/"un pase de una mazmorra laberíntica"}, + Text{"a labyrinthian lock remover", /*french*/"un efface-serrure labyrinthique", /*spanish*/"un destructor de cerraduras laberíntica"}, + Text{"a labyrinthian lockpick", /*french*/"un crochet à porte labyrinthique", /*spanish*/"una apertura portentosa laberíntica"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Gerudo Training Ground Small Key", /*french*/"une petite clé du Gymnase Gerudo", /*spanish*/"una llave pequeña del Centro de Instrucción Gerudo"} + ); + hintTable[GERUDO_FORTRESS_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"an imprisoned tool for unlocking", /*french*/"un anti-porte emprisonné", /*spanish*/"una clave de una entrada encarcelada"}, + Text{"an imprisoned dungeon pass", /*french*/"le rêve emprisonné d'un prisonnier", /*spanish*/"un pase de una mazmorra encarcelada"}, + Text{"an imprisoned lock remover", /*french*/"un efface-serrure emprisonné", /*spanish*/"un destructor de cerraduras encarcelada"}, + Text{"an imprisoned lockpick", /*french*/"un crochet à porte emprisonné", /*spanish*/"una apertura portentosa encarcelada"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Gerudo Fortress Small Key", /*french*/"une petite clé de la Repaire des Voleurs", /*spanish*/"una llave pequeña de la Fortaleza Gerudo"} + ); + hintTable[BOTTOM_OF_THE_WELL_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a moldy tool for unlocking", /*french*/"un anti-porte moisi", /*spanish*/"una clave de una entrada mohosa"}, + Text{"a moldy dungeon pass", /*french*/"le rêve moisi d'un prisonnier", /*spanish*/"un pase de una mazmorra mohosa"}, + Text{"a moldy lock remover", /*french*/"un efface-serrure moisi", /*spanish*/"un destructor de cerraduras mohosa"}, + Text{"a moldy lockpick", /*french*/"un crochet à porte moisi", /*spanish*/"una apertura portentosa mohosa"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Bottom of the Well Small Key", /*french*/"une petite clé du fond du Puits", /*spanish*/"una llave pequeña del Fondo del pozo"} + ); + hintTable[GANONS_CASTLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a final tool for unlocking", /*french*/"un anti-porte final", /*spanish*/"una clave de una entrada final"}, + Text{"a final dungeon pass", /*french*/"le rêve final d'un prisonnier", /*spanish*/"un pase de una mazmorra final"}, + Text{"a final lock remover", /*french*/"un efface-serrure final", /*spanish*/"un destructor de cerraduras final"}, + Text{"a final lockpick", /*french*/"un crochet à porte final", /*spanish*/"una apertura portentosa final"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Ganon's Castle Small Key", /*french*/"une petite clé du Château de Ganon", /*spanish*/"una llave pequeña del Castillo de Ganon"} + ); + hintTable[FOREST_TEMPLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a sylvan toolbox for unlocking", /*french*/"des anti-portes sylvestres", /*spanish*/"un conjunto silvestre de cerrajero"}, + Text{"a sylvan dungeon season pass", /*french*/"les rêves sylvestres d'un prisonnier", /*spanish*/"un pase vip de mazmorras silvestre"}, + Text{"a sylvan jingling ring", /*french*/"des efface-serrures sylvestres", /*spanish*/"una cadena multiusos silvestre"}, + Text{"a sylvan skeleton key", /*french*/"des crochets à porte sylvestres", /*spanish*/"un anillo silvestre contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Forest Temple Key Ring", /*french*/"un trousseau de clés du Temple de la Forêt", /*spanish*/"un llavero del Templo del Bosque"} + ); + hintTable[FIRE_TEMPLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a molten toolbox for unlocking", /*french*/"des anti-portes fondus", /*spanish*/"un conjunto fundido de cerrajero"}, + Text{"a molten dungeon season pass", /*french*/"les rêves fondus d'un prisonnier", /*spanish*/"un pase vip de mazmorras fundido"}, + Text{"a molten jingling ring", /*french*/"des efface-serrures fondus", /*spanish*/"una cadena multiusos fundida"}, + Text{"a molten skeleton key", /*french*/"des crochets à porte fondus", /*spanish*/"un anillo fundido contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Fire Temple Key Ring", /*french*/"un trousseau de clés du Temple du Feu", /*spanish*/"un llavero del Templo del Fuego"} + ); + hintTable[WATER_TEMPLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a wet toolbox for unlocking", /*french*/"des anti-portes humides", /*spanish*/"un conjunto abisal de cerrajero"}, + Text{"a wet dungeon season pass", /*french*/"les rêves humides d'un prisonnier", /*spanish*/"un pase vip de mazmorras abisal"}, + Text{"a wet jingling ring", /*french*/"des efface-serrures humides", /*spanish*/"una cadena multiusos abisal"}, + Text{"a wet skeleton key", /*french*/"des crochets à porte humides", /*spanish*/"un anillo abisal contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Water Temple Key Ring", /*french*/"un trousseau de clés du Temple de l'Eau", /*spanish*/"un llavero del Templo del Agua"} + ); + hintTable[SPIRIT_TEMPLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a sandy toolbox for unlocking", /*french*/"des anti-portes sableux", /*spanish*/"un conjunto arenoso de cerrajero"}, + Text{"a sandy dungeon season pass", /*french*/"les rêves sableux d'un prisonnier", /*spanish*/"un pase vip de mazmorras arenoso"}, + Text{"a sandy jingling ring", /*french*/"des efface-serrures sableux", /*spanish*/"una cadena multiusos arenosa"}, + Text{"a sandy skeleton key", /*french*/"des crochets à porte sableux", /*spanish*/"un anillo arenoso contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Spirit Temple Key Ring", /*french*/"un trousseau de clés du Temple de l'Esprit", /*spanish*/"un llavero del Templo del Espíritu"} + ); + hintTable[SHADOW_TEMPLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a creepy toolbox for unlocking", /*french*/"des anti-portes sinistres", /*spanish*/"un conjunto tenebroso de cerrajero"}, + Text{"a creepy dungeon season pass", /*french*/"les rêves sinistres d'un prisonnier", /*spanish*/"un pase vip de mazmorras tenebroso"}, + Text{"a creepy jingling ring", /*french*/"des efface-serrures sinistres", /*spanish*/"una cadena multiusos tenebrosa"}, + Text{"a creepy skeleton key", /*french*/"des crochets à porte sinistres", /*spanish*/"un anillo tenebroso contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Shadow Temple Key Ring", /*french*/"un trousseau de clés du Temple de l'Ombre", /*spanish*/"un llavero del Templo de las Sombras"} + ); + hintTable[GERUDO_TRAINING_GROUNDS_KEY_RING] = HintText::Item({ + //obscure text + Text{"a labyrinthian toolbox for unlocking", /*french*/"des anti-portes labyrinthiques", /*spanish*/"un conjunto laberíntico de cerrajero"}, + Text{"a labyrinthian dungeon season pass", /*french*/"les rêves labyrinthiques d'un prisonnier", /*spanish*/"un pase vip de mazmorras laberíntico"}, + Text{"a labyrinthian jingling ring", /*french*/"des efface-serrures labyrinthiques", /*spanish*/"una cadena multiusos laberíntica"}, + Text{"a labyrinthian skeleton key", /*french*/"des crochets à porte labyrinthiques", /*spanish*/"un anillo laberíntico contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Gerudo Training Ground Key Ring", /*french*/"un trousseau de clés du Gymnase Gerudo", /*spanish*/"un llavero del Centro de Instrucción Gerudo"} + ); + hintTable[GERUDO_FORTRESS_KEY_RING] = HintText::Item({ + //obscure text + Text{"an imprisoned toolbox for unlocking", /*french*/"des anti-portes emprisonnés", /*spanish*/"un conjunto enjaulado de cerrajero"}, + Text{"an imprisoned dungeon season pass", /*french*/"les rêves emprisonnés d'un prisonnier", /*spanish*/"un pase vip de una mazmorra enjaulado"}, + Text{"an imprisoned jingling ring", /*french*/"des efface-serrures emprisonnés", /*spanish*/"una cadena multiusos enjaulada"}, + Text{"an imprisoned skeleton key", /*french*/"des crochets à porte emprisonnés", /*spanish*/"un anillo enjaulado contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Gerudo Fortress Key Ring", /*french*/"un trousseau de clés de la Repaire des Voleurs", /*spanish*/"un llavero de la Fortaleza Gerudo"} + ); + hintTable[BOTTOM_OF_THE_WELL_KEY_RING] = HintText::Item({ + //obscure text + Text{"a moldy toolbox for unlocking", /*french*/"des anti-portes moisis", /*spanish*/"un conjunto subterráneo de cerrajero"}, + Text{"a moldy dungeon season pass", /*french*/"les rêves moisis d'un prisonnier", /*spanish*/"un pase vip de una mazmorra subterráneo"}, + Text{"a moldy jingling ring", /*french*/"des efface-serrures moisis", /*spanish*/"una cadena multiusos subterránea"}, + Text{"a moldy skeleton key", /*french*/"des crochets à porte moisis", /*spanish*/"un anillo subterráneo contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Bottom of the Well Key Ring", /*french*/"un trousseau de clés du fond du Puits", /*spanish*/"un llavero del Fondo del pozo"} + ); + hintTable[GANONS_CASTLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a final toolbox for unlocking", /*french*/"des anti-portes finaux", /*spanish*/"un conjunto decisivo de cerrajero"}, + Text{"a final dungeon season pass", /*french*/"les rêves finaux d'un prisonnier", /*spanish*/"un pase vip de una mazmorra decisivo"}, + Text{"a final jingling ring", /*french*/"des efface-serrures finaux", /*spanish*/"una cadena multiusos decisiva"}, + Text{"a final skeleton key", /*french*/"des crochets à porte finaux", /*spanish*/"un anillo decisivo multiusos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Ganon's Castle Key Ring", /*french*/"un trousseau de clés du Château de Ganon", /*spanish*/"un llavero del Castillo de Ganon"} + ); + + hintTable[TREASURE_GAME_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a gambler's tool for unlocking", /*french*/"un anti-porte de parieur", /*spanish*/"una clave de un juego de azar"}, + Text{"a gambler's dungeon pass", /*french*/"le rêve d'un prisonnier parieur", /*spanish*/"un pase de un juego de azar"}, + Text{"a gambler's lock remover", /*french*/"un efface-serrure de parieur", /*spanish*/"un destructor de cerraduras del juego de azar"}, + Text{"a gambler's lockpick", /*french*/"un crochet à serrure de parieur", /*spanish*/"una apertura portentosa del juego de azar"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Treasure Chest Shop Small Key", /*french*/"une petite clé de la chasse aux trésors", /*spanish*/"una llave pequeña del Cofre del Tesoro"} + ); + + hintTable[KOKIRI_EMERALD] = HintText::Item({ + //obscure text + Text{"a green stone", /*french*/"une pierre verte", /*spanish*/"una piedra verde"}, + Text{"a gift before death", /*french*/"le dernier souffle d'un arbre", /*spanish*/"un obsequio testamentario"}, + }, { + //ambiguous text + Text{"a spiritual stone", /*french*/"une Pierre Ancestrale", /*spanish*/"una piedra espiritual"}, + }, + //clear text + Text{"the Kokiri Emerald", /*french*/"l'Émeraude Kokiri", /*spanish*/"la Esmeralda de los Kokiri"} + ); + + hintTable[GORON_RUBY] = HintText::Item({ + //obscure text + Text{"a red stone", /*french*/"une pierre rouge", /*spanish*/"una piedra carmín"}, + Text{"sworn brotherhood", /*french*/"un serment de fraternité", /*spanish*/"el juramento de hermanos de sangre"}, + }, { + //ambiguous text + Text{"a spiritual stone", /*french*/"une Pierre Ancestrale", /*spanish*/"una piedra espiritual"}, + }, + //clear text + Text{"the Goron Ruby", /*french*/"le Rubis Goron", /*spanish*/"el Rubí de los Goron"} + ); + + hintTable[ZORA_SAPPHIRE] = HintText::Item({ + //obscure text + Text{"a blue stone", /*french*/"une pierre bleue", /*spanish*/"una piedra celeste"}, + Text{"an engagement gift", /*french*/"un cadeau de mariage", /*spanish*/"un regalo de compromiso"}, + }, { + //ambiguous text + Text{"a spiritual stone", /*french*/"une Pierre Ancestrale", /*spanish*/"una piedra espiritual"}, + }, + //clear text + Text{"the Zora Sapphire", /*french*/"le Saphir Zora", /*spanish*/"el Zafiro de los Zora"} + ); + + hintTable[FOREST_MEDALLION] = HintText::Item({ + //obscure text + Text{"a green coin", /*french*/"une pièce verte", /*spanish*/"una moneda esmeralda"}, + Text{"Saria's friendship", /*french*/"l'amitié de Saria", /*spanish*/"la amistad de Saria"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Forest Medallion", /*french*/"le Médaillon de la Forêt", /*spanish*/"el Medallón del Bosque"} + ); + + hintTable[FIRE_MEDALLION] = HintText::Item({ + //obscure text + Text{"a red coin", /*french*/"une pièce rouge", /*spanish*/"una moneda rubí"}, + Text{"Darunia's power", /*french*/"la fraternité de Darunia", /*spanish*/"la fraternidad de Darunia"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Fire Medallion", /*french*/"le Médaillon du Feu", /*spanish*/"el Medallón del Fuego"} + ); + + hintTable[WATER_MEDALLION] = HintText::Item({ + //obscure text + Text{"a blue coin", /*french*/"une pièce bleue", /*spanish*/"una moneda zafiro"}, + Text{"Ruto's power", /*french*/"l'amour de Ruto", /*spanish*/"el amor de Ruto"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Water Medallion", /*french*/"le Médaillon de l'Eau", /*spanish*/"el Medallón del Agua"} + ); + + hintTable[SPIRIT_MEDALLION] = HintText::Item({ + //obscure text + Text{"an orange coin", /*french*/"une pièce orange", /*spanish*/"una moneda ámbar"}, + Text{"Nabooru's power", /*french*/"le respect de Nabooru", /*spanish*/"el respeto de Nabooru"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Spirit Medallion", /*french*/"le Médaillon de l'Esprit", /*spanish*/"el Medallón del Espíritu"} + ); + + hintTable[SHADOW_MEDALLION] = HintText::Item({ + //obscure text + Text{"a purple coin", /*french*/"une pièce pourpre", /*spanish*/"una moneda malva"}, + Text{"Impa's power", /*french*/"la confiance d'Impa", /*spanish*/"la confianza de Impa"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Shadow Medallion", /*french*/"le Médaillon de l'Ombre", /*spanish*/"el Medallón de la Sombra"} + ); + + hintTable[LIGHT_MEDALLION] = HintText::Item({ + //obscure text + Text{"a yellow coin", /*french*/"une pièce jaune", /*spanish*/"una moneda resplandeciente"}, + Text{"Rauru's power", /*french*/"la foi de Rauru", /*spanish*/"la fe de Rauru"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Light Medallion", /*french*/"le Médaillon de la Lumière", /*spanish*/"el Medallón de la Luz"} + ); + + hintTable[RECOVERY_HEART] = HintText::Item({ + //obscure text + Text{"a free heal", /*french*/"un bec-au-bobo", /*spanish*/"una cura de regalo"}, + Text{"a hearty meal", /*french*/"un petit amour", /*spanish*/"una sanación romántica"}, + Text{"a Band-Aid", /*french*/"un diachylon", /*spanish*/"un corazoncito sanador"}, + }, { + //ambiguous text + Text{"something heart-shaped", /*french*/"une chose en forme de coeur", /*spanish*/"algo con forma de corazón"}, + }, + //clear text + Text{"a Recovery Heart", /*french*/"un coeur de vie", /*spanish*/"un corazón"} + ); + + hintTable[GREEN_RUPEE] = HintText::Item({ + //obscure text + Text{"a unique coin", /*french*/"un rubis bien mérité", /*spanish*/"una singular moneda"}, + Text{"a penny", /*french*/"un sou", /*spanish*/"un peso hyliano"}, + Text{"a green gem", /*french*/"un joyau vert", /*spanish*/"una gema verde"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Green Rupee", /*french*/"un rubis vert", /*spanish*/"una rupia verde"} + ); + + hintTable[BLUE_RUPEE] = HintText::Item({ + //obscure text + Text{"a common coin", /*french*/"quelques sous", /*spanish*/"una moneda usual"}, + Text{"a blue gem", /*french*/"un joyau bleu", /*spanish*/"una gema azul"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Blue Rupee", /*french*/"un rubis bleu", /*spanish*/"una rupia azul"} + ); + + hintTable[RED_RUPEE] = HintText::Item({ + //obscure text + Text{"couch cash", /*french*/"un peu de fric", /*spanish*/"una buena moneda"}, + Text{"a red gem", /*french*/"un joyau rouge", /*spanish*/"una gema roja"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Red Rupee", /*french*/"un rubis rouge", /*spanish*/"una rupia roja"} + ); + + hintTable[PURPLE_RUPEE] = HintText::Item({ + //obscure text + Text{"big bucks", /*french*/"plein de fric", /*spanish*/"plata de calidad"}, + Text{"a purple gem", /*french*/"un joyau mauve", /*spanish*/"una gema morada"}, + Text{"wealth", /*french*/"la richesse", /*spanish*/"una buena riqueza"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Purple Rupee", /*french*/"un rubis pourpre", /*spanish*/"una rupia morada"} + ); + + hintTable[HUGE_RUPEE] = HintText::Item({ + //obscure text + Text{"a juicy jackpot", /*french*/"le jackpot", /*spanish*/"el premio gordo"}, + Text{"a yellow gem", /*french*/"un joyau doré", /*spanish*/"una gema amarilla"}, + Text{"a giant gem", /*french*/"un gros joyau", /*spanish*/"una gema descomunal"}, + Text{"great wealth", /*french*/"l'aisance financière", /*spanish*/"dinero a caudales"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Huge Rupee", /*french*/"un énorme rubis", /*spanish*/"una rupia gigante"} + ); + + hintTable[PIECE_OF_HEART] = HintText::Item({ + //obscure text + Text{"a little love", /*french*/"un peu plus d'amour", /*spanish*/"un cuarto de amor"}, + Text{"a broken heart", /*french*/"un coeur brisé", /*spanish*/"un corazón roto"}, + }, { + //ambiguous text + Text{"something heart-shaped", /*french*/"une chose en forme de coeur", /*spanish*/"algo con forma de corazón"}, + }, + //clear text + Text{"a Piece of Heart", /*french*/"un Quart de Coeur", /*spanish*/"una pieza de corazón"} + ); + + hintTable[HEART_CONTAINER] = HintText::Item({ + //obscure text + Text{"a lot of love", /*french*/"le grand amour", /*spanish*/"amor por doquier"}, + Text{"a Valentine's gift", /*french*/"un cadeau de Saint-Valentin", /*spanish*/"un contenedor de afección"}, + Text{"a boss's organ", /*french*/"un organe de monstre", /*spanish*/"los órganos de un jefe"}, + }, { + //ambiguous text + Text{"something heart-shaped", /*french*/"une chose en forme de coeur", /*spanish*/"algo con forma de corazón"}, + }, + //clear text + Text{"a Heart Container", /*french*/"un Réceptacle de Coeur", /*spanish*/"un contenedor de corazón"} + ); + + hintTable[ICE_TRAP] = HintText::Item({ + //obscure text + Text{"a gift from Ganon", /*french*/"un cadeau de Ganon", /*spanish*/"un regalo de Ganon"}, + Text{"a chilling discovery", /*french*/"une frissonante découverte", /*spanish*/"un escalofriante hallazgo"}, + Text{"frosty fun", /*french*/"une engelure", /*spanish*/"una gélida diversión"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + Text{"a magic arrow", /*french*/"une flèche magique", /*spanish*/"una flecha mágica"}, + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + Text{"a spiritual stone", /*french*/"une Pierre Ancestrale", /*spanish*/"una piedra espiritual"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"an Ice Trap", /*french*/"un Piège de Glace", /*spanish*/"una trampa de hielo"} + ); + + //MILK + + hintTable[BOMBS_5] = HintText::Item({ + //obscure text + Text{"a few explosives", /*french*/"une poignée de pétards", /*spanish*/"un par de explosivos"}, + Text{"a few blast balls", /*french*/"une poignée de boules bleues", /*spanish*/"un par de estallidos"}, + }, { + //ambiguous text + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombs (5 pieces)", /*french*/"une demi-dizaine de bombes", /*spanish*/"unas (5) bombas"} + ); + + hintTable[BOMBS_10] = HintText::Item({ + //obscure text + Text{"some explosives", /*french*/"un paquet de pétards", /*spanish*/"unos cuantos explosivos"}, + Text{"some blast balls", /*french*/"un paquet de boules bleues", /*spanish*/"unos cuantos estallidos"}, + }, { + //ambiguous text + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombs (10 pieces)", /*french*/"une dizaine de bombes", /*spanish*/"unas (10) bombas"} + ); + + hintTable[BOMBS_20] = HintText::Item({ + //obscure text + Text{"lots-o-explosives", /*french*/"une abondance de pétards", /*spanish*/"un puñado de explosivos"}, + Text{"plenty of blast balls", /*french*/"une abondance de boules bleues", /*spanish*/"bastantes estallidos"}, + }, { + //ambiguous text + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombs (20 pieces)", /*french*/"une vingtaine de bombes", /*spanish*/"unas (20) bombas"} + ); + + hintTable[BOMBCHU_5] = HintText::Item({ + //obscure text + Text{"a few mice bombs", /*french*/"une poignée de mignons explosifs", /*spanish*/"un par de bombas roedoras"}, + Text{"a few proximity mice", /*french*/"une poignée de jouets à remonter", /*spanish*/"un par de explosivos ratoncitos"}, + Text{"a few wall crawlers", /*french*/"une poignée de rapides grimpeurs", /*spanish*/"un par de trepaparedes"}, + Text{"a few trail blazers", /*french*/"une poignée de zigzags éclatants", /*spanish*/"un par de ratas propulsadas"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombchus (5 pieces)", /*french*/"une demi-dizaine de Missiles", /*spanish*/"unos (5) bombchus"} + ); + + hintTable[BOMBCHU_10] = HintText::Item({ + //obscure text + Text{"some mice bombs", /*french*/"un paquet de mignons explosifs", /*spanish*/"unas cuantas bombas roedoras"}, + Text{"some proximity mice", /*french*/"un paquet de jouets à remonter", /*spanish*/"unos cuantos explosivos ratoncitos"}, + Text{"some wall crawlers", /*french*/"un paquet de rapides grimpeurs", /*spanish*/"unos cuantos trepaparedes"}, + Text{"some trail blazers", /*french*/"un paquet de zigzags éclatants", /*spanish*/"unas cuantas ratas propulsadas"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombchus (10 pieces)", /*french*/"une dizaine de Missiles", /*spanish*/"unos (10) bombchus"} + ); + + hintTable[BOMBCHU_20] = HintText::Item({ + //obscure text + Text{"plenty of mice bombs", /*french*/"une abondance de mignons explosifs", /*spanish*/"bastantes bombas roedoras"}, + Text{"plenty of proximity mice", /*french*/"une abondance de jouets à remonter", /*spanish*/"bastantes explosivos ratoncitos"}, + Text{"plenty of wall crawlers", /*french*/"une abondance de rapides grimpeurs", /*spanish*/"bastantes trepaparedes"}, + Text{"plenty of trail blazers", /*french*/"une abondance de zigzags éclatants", /*spanish*/"bastantes ratas propulsadas"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombchus (20 pieces)", /*french*/"une vingtaine de Missiles", /*spanish*/"unos (20) bombchus"} + ); + + //BOMBCHU_DROP + + hintTable[ARROWS_5] = HintText::Item({ + //obscure text + Text{"a few danger darts", /*french*/"une poignée d'obus", /*spanish*/"un par de peligrosos dardos"}, + Text{"a few sharp shafts", /*french*/"une poignée de piquets", /*spanish*/"un par de puntas afiladas"}, + }, { + //ambiguous text + Text{"a projectile", /*french*/"un projectile", /*spanish*/"un proyectil"}, + }, + //clear text + Text{"Arrows (5 pieces)", /*french*/"une demi-dizaine de flèches", /*spanish*/"unas (5) flechas"} + ); + + hintTable[ARROWS_10] = HintText::Item({ + //obscure text + Text{"some danger darts", /*french*/"un paquet d'obus", /*spanish*/"unos cuantos peligrosos dardos"}, + Text{"some sharp shafts", /*french*/"un paquet de piquets", /*spanish*/"unas cuantas puntas afiladas"}, + }, { + //ambiguous text + Text{"a projectile", /*french*/"un projectile", /*spanish*/"un proyectil"}, + }, + //clear text + Text{"Arrows (10 pieces)", /*french*/"une dizaine de flèches", /*spanish*/"unas (10) flechas"} + ); + + hintTable[ARROWS_30] = HintText::Item({ + //obscure text + Text{"plenty of danger darts", /*french*/"une abondance d'obus", /*spanish*/"bastantes peligrosos dardos"}, + Text{"plenty of sharp shafts", /*french*/"une abondance de piquets", /*spanish*/"bastantes puntas afiladas"}, + }, { + //ambiguous text + Text{"a projectile", /*french*/"un projectile", /*spanish*/"un proyectil"}, + }, + //clear text + Text{"Arrows (30 pieces)", /*french*/"une trentaine de flèches", /*spanish*/"unas (30) flechas"} + ); + + hintTable[DEKU_NUTS_5] = HintText::Item({ + //obscure text + Text{"some nuts", /*french*/"une poignée de noisettes", /*spanish*/"un par de nueces"}, + Text{"some flashbangs", /*french*/"une poignée d'éclats", /*spanish*/"un par de semillas aturdidoras"}, + Text{"some scrub spit", /*french*/"une poignée de crachats Mojo", /*spanish*/"un par de escupitajos deku"}, + }, { + //ambiguous text + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"Deku Nuts (5 pieces)", /*french*/"une demi-dizaine de noix Mojo", /*spanish*/"unas (5) nueces deku"} + ); + + hintTable[DEKU_NUTS_10] = HintText::Item({ + //obscure text + Text{"lots-o-nuts", /*french*/"un paquet de noisettes", /*spanish*/"un puñado de nueces"}, + Text{"plenty of flashbangs", /*french*/"un paquet d'éclats", /*spanish*/"unas cuantas semillas aturdidoras"}, + Text{"plenty of scrub spit", /*french*/"un paquet de crachats Mojo", /*spanish*/"unos cuantos escupitajos deku"}, + }, { + //ambiguous text + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"Deku Nuts (10 pieces)", /*french*/"une dizaine de noix Mojo", /*spanish*/"unas (10) nueces deku"} + ); + + hintTable[DEKU_SEEDS_30] = HintText::Item({ + //obscure text + Text{"catapult ammo", /*french*/"un paquet de délicieuses munitions", /*spanish*/"un par de munición infantil"}, + Text{"lots-o-seeds", /*french*/"un paquet de germes séchés", /*spanish*/"un puñado de semillas"}, + }, { + //ambiguous text + Text{"a projectile", /*french*/"un projectile", /*spanish*/"un proyectil"}, + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + }, + //clear text + Text{"Deku Seeds (30 pieces)", /*french*/"une trentaine de graines Mojo", /*spanish*/"unas (30) semillas deku"} + ); + + hintTable[DEKU_STICK_1] = HintText::Item({ + //obscure text + Text{"a breakable branch", /*french*/"un bout de bois", /*spanish*/"un pequeño báculo"}, + }, { + //ambiguous text + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + }, + //clear text + Text{"a Deku Stick", /*french*/"un bâton Mojo", /*spanish*/"un palo deku"} + ); + + hintTable[TREASURE_GAME_HEART] = HintText::Item({ + //obscure text + Text{"a victory valentine", /*french*/"un amour gagnant", /*spanish*/"el amor victorioso"}, + }, { + //ambiguous text + Text{"something heart-shaped", /*french*/"une chose en forme de coeur", /*spanish*/"algo con forma de corazón"}, + }, + //clear text + Text{"a Piece of Heart", /*french*/"un Quart de Coeur", /*spanish*/"el amor de la victoria"} + ); + + hintTable[TREASURE_GAME_GREEN_RUPEE] = HintText::Item({ + //obscure text + Text{"the dollar of defeat", /*french*/"le rubis de la défaite", /*spanish*/"el peso de la derrota"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Green Rupee", /*french*/"un rubis vert", /*spanish*/"una rupia verde"} + ); + + hintTable[TRIFORCE_PIECE] = HintText::Item({ + //obscure text + Text{"a triumph fork", /*french*/"la Tribosse", /*spanish*/"un trígono del triunfo"}, + Text{"cheese", /*french*/"du fromage", /*spanish*/"un porción de queso"}, + Text{"a gold fragment", /*french*/"un fragment d'or", /*spanish*/"un fragmento dorado"}, + }, {}, + //clear text + Text{"a Piece of the Triforce", /*french*/"un fragment de la Triforce", /*spanish*/"un fragmento de la Trifuerza"} + ); + + hintTable[EPONA] = HintText::Item({ + //obscure text + Text{"a horse", /*french*/"un fidèle destrier", /*spanish*/"una yegua"}, + Text{"a four legged friend", /*french*/"un puissant animal", /*spanish*/"una amiga cuadrúpeda"}, + }, { + //ambiguous text + Text{"something from Malon", /*french*/"un cadeau de Malon", /*spanish*/"un obsequio de Malon"}, + Text{"a song sung by frogs", /*french*/"une chanson aimée des grenouilles", /*spanish*/"una melodía de ranas"}, + Text{"something to cross a broken bridge", /*french*/"une chose pour traverser un pont brisé", /*spanish*/"algo para cruzar un puente roto"}, + }, + //clear text + Text{"Epona", /*french*/"Epona", /*spanish*/"a Epona"} + ); + + // [HINT_ERROR] = HintText::Item({ + // //obscure text + // Text{"something mysterious", /*french*/"un sacré mystère", /*spanish*/"algo misterioso"}, + // Text{"an unknown treasure", /*french*/"un trésor inconnu", /*spanish*/"un desconocido tesoro"}, + // }, + // //clear text + // Text{"An Error (Please Report This)", /*french*/"une erreur (signaler S.V.P.)", /*spanish*/"un error (repórtelo si es posible)"} + // ); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.cpp b/soh/soh/Enhancements/randomizer/3drando/hints.cpp new file mode 100644 index 000000000..33bd5edf0 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hints.cpp @@ -0,0 +1,878 @@ +#include "hints.hpp" + +#include "custom_messages.hpp" +#include "dungeon.hpp" +#include "item_location.hpp" +#include "item_pool.hpp" +#include "logic.hpp" +#include "random.hpp" +#include "spoiler_log.hpp" +#include "fill.hpp" +#include "hint_list.hpp" +#include "trial.hpp" +#include "entrance.hpp" +#include "z64item.h" +#include + +using namespace CustomMessages; +using namespace Logic; +using namespace Settings; +using namespace Trial; + +constexpr std::array hintSettingTable{{ + // Useless hints + { + .dungeonsWothLimit = 2, + .dungeonsBarrenLimit = 1, + .namedItemsRequired = false, + .distTable = {{ + {.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Woth, .order = 3, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Barren, .order = 4, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Entrance, .order = 5, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Random, .order = 7, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Item, .order = 8, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Song, .order = 9, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Overworld, .order = 10, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Dungeon, .order = 11, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Junk, .order = 12, .weight = 99, .fixed = 0, .copies = 0}, + {.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 0}, + }}, + }, + + // Balanced hints + { + .dungeonsWothLimit = 2, + .dungeonsBarrenLimit = 1, + .namedItemsRequired = true, + .distTable = {{ + {.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Woth, .order = 3, .weight = 7, .fixed = 0, .copies = 1}, + {.type = HintType::Barren, .order = 4, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HintType::Entrance, .order = 5, .weight = 6, .fixed = 0, .copies = 1}, + {.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Random, .order = 7, .weight = 12, .fixed = 0, .copies = 1}, + {.type = HintType::Item, .order = 8, .weight = 10, .fixed = 0, .copies = 1}, + {.type = HintType::Song, .order = 9, .weight = 2, .fixed = 0, .copies = 1}, + {.type = HintType::Overworld, .order = 10, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HintType::Dungeon, .order = 11, .weight = 3, .fixed = 0, .copies = 1}, + {.type = HintType::Junk, .order = 12, .weight = 6, .fixed = 0, .copies = 1}, + {.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 1}, + }}, + }, + + // Strong hints + { + .dungeonsWothLimit = 2, + .dungeonsBarrenLimit = 1, + .namedItemsRequired = true, + .distTable = {{ + {.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 2}, + {.type = HintType::Woth, .order = 3, .weight = 12, .fixed = 0, .copies = 2}, + {.type = HintType::Barren, .order = 4, .weight = 12, .fixed = 0, .copies = 1}, + {.type = HintType::Entrance, .order = 5, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Random, .order = 7, .weight = 8, .fixed = 0, .copies = 1}, + {.type = HintType::Item, .order = 8, .weight = 8, .fixed = 0, .copies = 1}, + {.type = HintType::Song, .order = 9, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HintType::Overworld, .order = 10, .weight = 6, .fixed = 0, .copies = 1}, + {.type = HintType::Dungeon, .order = 11, .weight = 6, .fixed = 0, .copies = 1}, + {.type = HintType::Junk, .order = 12, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 1}, + }}, + }, + + // Very strong hints + { + .dungeonsWothLimit = 40, + .dungeonsBarrenLimit = 40, + .namedItemsRequired = true, + .distTable = {{ + {.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 2}, + {.type = HintType::Woth, .order = 3, .weight = 15, .fixed = 0, .copies = 2}, + {.type = HintType::Barren, .order = 4, .weight = 15, .fixed = 0, .copies = 1}, + {.type = HintType::Entrance, .order = 5, .weight = 10, .fixed = 0, .copies = 1}, + {.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Random, .order = 7, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Item, .order = 8, .weight = 5, .fixed = 0, .copies = 1}, + {.type = HintType::Song, .order = 9, .weight = 2, .fixed = 0, .copies = 1}, + {.type = HintType::Overworld, .order = 10, .weight = 7, .fixed = 0, .copies = 1}, + {.type = HintType::Dungeon, .order = 11, .weight = 7, .fixed = 0, .copies = 1}, + {.type = HintType::Junk, .order = 12, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 1}, + }}, + }, +}}; + +std::array dungeonInfoData; + +Text childAltarText; +Text adultAltarText; +Text ganonText; +Text ganonHintText; + +Text& GetChildAltarText() { + return childAltarText; +} + +Text& GetAdultAltarText() { + return adultAltarText; +} + +Text& GetGanonText() { + return ganonText; +} + +Text& GetGanonHintText() { + return ganonHintText; +} + +static Area* GetHintRegion(const uint32_t area) { + + std::vector alreadyChecked = {}; + std::vector spotQueue = {area}; + + while (!spotQueue.empty()) { + uint32_t region = spotQueue.back(); + alreadyChecked.push_back(region); + spotQueue.pop_back(); + + if (AreaTable(region)->hintKey != NONE) { + return AreaTable(region); + } + + //add unchecked entrances to spot queue + bool checked = false; + for (auto& entrance : AreaTable(region)->entrances) { + for (uint32_t checkedEntrance : alreadyChecked) { + if (entrance->GetParentRegionKey() == checkedEntrance) { + checked = true; + break; + } + } + + if (!checked) { + spotQueue.insert(spotQueue.begin(), entrance->GetParentRegionKey()); + } + } + } + + return AreaTable(NONE); +} + +uint32_t GetHintRegionHintKey(const uint32_t area) { + return GetHintRegion(area)->hintKey; +} + +uint32_t GetHintRegionuint32_t(const uint32_t area) { + return GetHintRegion(area)->hintKey; +} + +uint32_t GetLocationRegionuint32_t(const uint32_t location) { + return GetHintRegion(Location(location)->GetParentRegionKey())->hintKey; +} + +static std::vector GetAccessibleGossipStones(const uint32_t hintedLocation = GANON) { + //temporarily remove the hinted location's item, and then perform a + //reachability search for gossip stone locations. + uint32_t originalItem = Location(hintedLocation)->GetPlaceduint32_t(); + Location(hintedLocation)->SetPlacedItem(NONE); + + LogicReset(); + auto accessibleGossipStones = GetAccessibleLocations(gossipStoneLocations); + //Give the item back to the location + Location(hintedLocation)->SetPlacedItem(originalItem); + + return accessibleGossipStones; +} + +static void AddHint(Text hint, const uint32_t gossipStone, const std::vector& colors = {}) { + //save hints as dummy items for writing to the spoiler log + NewItem(gossipStone, Item{hint, ITEMTYPE_EVENT, GI_RUPEE_BLUE_LOSE, false, &noVariable, NONE}); + Location(gossipStone)->SetPlacedItem(gossipStone); + + //create the in game message + // uint32_t messageId = 0x400 + Location(gossipStone)->GetFlag(); + // uint32_t sariaMessageId = 0xA00 + Location(gossipStone)->GetFlag(); + // CreateMessageFromTextObject(messageId, 0, 2, 3, AddColorsAndFormat(hint, colors)); + // CreateMessageFromTextObject(sariaMessageId, 0, 2, 3, AddColorsAndFormat(hint + EVENT_TRIGGER(), colors)); +} + +static void CreateLocationHint(const std::vector& possibleHintLocations) { + //return if there aren't any hintable locations or gossip stones available + if (possibleHintLocations.empty()) { + SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n"); + return; + } + + uint32_t hintedLocation = RandomElement(possibleHintLocations); + const std::vector accessibleGossipStones = GetAccessibleGossipStones(hintedLocation); + + SPDLOG_INFO("\tLocation: "); + SPDLOG_INFO(Location(hintedLocation)->GetName()); + SPDLOG_INFO("\n"); + + SPDLOG_INFO("\tItem: "); + SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); + SPDLOG_INFO("\n"); + + if (accessibleGossipStones.empty()) { + SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); + return; + } + + uint32_t gossipStone = RandomElement(accessibleGossipStones); + Location(hintedLocation)->SetAsHinted(); + + //make hint text + Text locationHintText = Location(hintedLocation)->GetHint().GetText(); + Text itemHintText = Location(hintedLocation)->GetPlacedItem().GetHint().GetText(); + Text prefix = Hint(PREFIX).GetText(); + + Text finalHint = prefix + locationHintText + " #"+itemHintText+"#."; + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(finalHint.english); + SPDLOG_INFO("\n\n"); + + AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}); +} + +static void CreateWothHint(uint8_t* remainingDungeonWothHints) { + // get locations that are in the current playthrough + std::vector possibleHintLocations = {}; + // iterate through playthrough locations by sphere + std::vector wothHintLocations = + FilterFromPool(wothLocations, [remainingDungeonWothHints](uint32_t loc) { + return Location(loc)->IsHintable() && // only filter hintable locations + !(Location(loc)->IsHintedAt()) && // only filter locations that haven't been hinted at + (Location(loc)->IsOverworld() || + (Location(loc)->IsDungeon() && + (*remainingDungeonWothHints) > 0)); // make sure we haven't surpassed the woth dungeon limit + }); + AddElementsToPool(possibleHintLocations, wothHintLocations); + + // If no more locations can be hinted at for woth, then just try to get another hint + if (possibleHintLocations.empty()) { + SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n"); + return; + } + uint32_t hintedLocation = RandomElement(possibleHintLocations); + + SPDLOG_INFO("\tLocation: "); + SPDLOG_INFO(Location(hintedLocation)->GetName()); + SPDLOG_INFO("\n"); + + SPDLOG_INFO("\tItem: "); + SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); + SPDLOG_INFO("\n"); + + // get an accessible gossip stone + const std::vector gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); + + if (gossipStoneLocations.empty()) { + SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); + return; + } + Location(hintedLocation)->SetAsHinted(); + uint32_t gossipStone = RandomElement(gossipStoneLocations); + + // form hint text + Text locationText; + if (Location(hintedLocation)->IsDungeon()) { + *remainingDungeonWothHints -= 1; + uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); + locationText = AreaTable(parentRegion)->GetHint().GetText(); + + } else { + uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); + locationText = GetHintRegion(parentRegion)->GetHint().GetText(); + } + Text finalWothHint = Hint(PREFIX).GetText() + "#" + locationText + "#" + Hint(WAY_OF_THE_HERO).GetText(); + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(finalWothHint.english); + SPDLOG_INFO("\n\n"); + AddHint(finalWothHint, gossipStone, { QM_LBLUE }); +} + +static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector& barrenLocations) { + // remove dungeon locations if necessary + if (*remainingDungeonBarrenHints < 1) { + barrenLocations = + FilterFromPool(barrenLocations, [](const uint32_t loc) { return !(Location(loc)->IsDungeon()); }); + } + + if (barrenLocations.empty()) { + return; + } + + uint32_t hintedLocation = RandomElement(barrenLocations, true); + + SPDLOG_INFO("\tLocation: "); + SPDLOG_INFO(Location(hintedLocation)->GetName()); + SPDLOG_INFO("\n"); + + SPDLOG_INFO("\tItem: "); + SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); + SPDLOG_INFO("\n"); + + // get an accessible gossip stone + const std::vector gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); + if (gossipStoneLocations.empty()) { + SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); + return; + } + Location(hintedLocation)->SetAsHinted(); + uint32_t gossipStone = RandomElement(gossipStoneLocations); + + // form hint text + Text locationText; + if (Location(hintedLocation)->IsDungeon()) { + *remainingDungeonBarrenHints -= 1; + uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); + locationText = Hint(AreaTable(parentRegion)->hintKey).GetText(); + } else { + uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); + locationText = Hint(GetHintRegion(parentRegion)->hintKey).GetText(); + } + Text finalBarrenHint = + Hint(PREFIX).GetText() + Hint(PLUNDERING).GetText() + "#" + locationText + "#" + Hint(FOOLISH).GetText(); + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(finalBarrenHint.english); + SPDLOG_INFO("\n\n"); + AddHint(finalBarrenHint, gossipStone, { QM_PINK }); + + // get rid of all other locations in this same barren region + barrenLocations = FilterFromPool(barrenLocations, [hintedLocation](uint32_t loc) { + return GetHintRegion(Location(loc)->GetParentRegionKey())->hintKey != + GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->hintKey; + }); +} + +static void CreateRandomLocationHint(const bool goodItem = false) { + const std::vector possibleHintLocations = FilterFromPool(allLocations, [goodItem](const uint32_t loc) { + return Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt()) && (!goodItem || Location(loc)->GetPlacedItem().IsMajorItem()); + }); + //If no more locations can be hinted at, then just try to get another hint + if (possibleHintLocations.empty()) { + SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n"); + return; + } + uint32_t hintedLocation = RandomElement(possibleHintLocations); + + SPDLOG_INFO("\tLocation: "); + SPDLOG_INFO(Location(hintedLocation)->GetName()); + SPDLOG_INFO("\n"); + + SPDLOG_INFO("\tItem: "); + SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); + SPDLOG_INFO("\n"); + + //get an acessible gossip stone + const std::vector gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); + if (gossipStoneLocations.empty()) { + SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); + return; + } + Location(hintedLocation)->SetAsHinted(); + uint32_t gossipStone = RandomElement(gossipStoneLocations); + + //form hint text + Text itemText = Location(hintedLocation)->GetPlacedItem().GetHint().GetText(); + if (Location(hintedLocation)->IsDungeon()) { + uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); + Text locationText = AreaTable(parentRegion)->GetHint().GetText(); + Text finalHint = Hint(PREFIX).GetText()+"#"+locationText+"# "+Hint(HOARDS).GetText()+" #"+itemText+"#."; + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(finalHint.english); + SPDLOG_INFO("\n\n"); + AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}); + } else { + Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); + Text finalHint = Hint(PREFIX).GetText()+"#"+itemText+"# "+Hint(CAN_BE_FOUND_AT).GetText()+" #"+locationText+"#."; + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(finalHint.english); + SPDLOG_INFO("\n\n"); + AddHint(finalHint, gossipStone, {QM_RED, QM_GREEN}); + } +} + +static void CreateGoodItemHint() { + CreateRandomLocationHint(true); +} + +static void CreateJunkHint() { + //duplicate junk hints are possible for now + const HintText junkHint = RandomElement(GetHintCategory(HintCategory::Junk)); + LogicReset(); + const std::vector gossipStones = GetAccessibleLocations(gossipStoneLocations); + if (gossipStones.empty()) { + SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); + return; + } + uint32_t gossipStone = RandomElement(gossipStones); + Text hint = junkHint.GetText(); + + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(hint.english); + SPDLOG_INFO("\n\n"); + + AddHint(hint, gossipStone, {QM_PINK}); +} + +static std::vector CalculateBarrenRegions() { + std::vector barrenLocations = {}; + std::vector potentiallyUsefulLocations = {}; + + for (uint32_t loc : allLocations) { + // If a location has a major item or is a way of the hero location, it is not barren + if (Location(loc)->GetPlacedItem().IsMajorItem() || ElementInContainer(loc, wothLocations)) { + AddElementsToPool(potentiallyUsefulLocations, std::vector{loc}); + } else { + if (loc != LINKS_POCKET) { //Nobody cares to know if Link's Pocket is barren + AddElementsToPool(barrenLocations, std::vector{loc}); + } + } + } + + // Leave only locations at barren regions in the list + auto finalBarrenLocations = FilterFromPool(barrenLocations, [&potentiallyUsefulLocations](uint32_t loc){ + for (uint32_t usefulLoc : potentiallyUsefulLocations) { + uint32_t barrenKey = GetLocationRegionuint32_t(loc); + uint32_t usefulKey = GetLocationRegionuint32_t(usefulLoc); + if (barrenKey == usefulKey) { + return false; + } + } + return true; + }); + + return finalBarrenLocations; +} + +static void CreateTrialHints() { + //six trials + if (RandomGanonsTrials && GanonsTrialsCount.Is(6)) { + + //get a random gossip stone + auto gossipStones = GetAccessibleGossipStones(); + auto gossipStone = RandomElement(gossipStones, false); + + //make hint + auto hint = Hint(PREFIX).GetText() + Hint(SIX_TRIALS).GetText(); + AddHint(hint, gossipStone, {QM_PINK}); + + //zero trials + } else if (RandomGanonsTrials && GanonsTrialsCount.Is(0)) { + + //get a random gossip stone + auto gossipStones = GetAccessibleGossipStones(); + auto gossipStone = RandomElement(gossipStones, false); + + //make hint + auto hint = Hint(PREFIX).GetText() + Hint(ZERO_TRIALS).GetText(); + AddHint(hint, gossipStone, {QM_YELLOW}); + + //4 or 5 required trials + } else if (GanonsTrialsCount.Is(5) || GanonsTrialsCount.Is(4)) { + + //get skipped trials + std::vector trials = {}; + trials.assign(trialList.begin(), trialList.end()); + auto skippedTrials = FilterFromPool(trials, [](TrialInfo* trial){return trial->IsSkipped();}); + + //create a hint for each skipped trial + for (auto& trial : skippedTrials) { + //get a random gossip stone + auto gossipStones = GetAccessibleGossipStones(); + auto gossipStone = RandomElement(gossipStones, false); + + //make hint + auto hint = Hint(PREFIX).GetText()+"#"+trial->GetName()+"#"+Hint(FOUR_TO_FIVE_TRIALS).GetText(); + AddHint(hint, gossipStone, {QM_YELLOW}); + } + //1 to 3 trials + } else if (GanonsTrialsCount.Value() >= 1 && GanonsTrialsCount.Value() <= 3) { + //get requried trials + std::vector trials = {}; + trials.assign(trialList.begin(), trialList.end()); + auto requiredTrials = FilterFromPool(trials, [](TrialInfo* trial){return trial->IsRequired();}); + + //create a hint for each required trial + for (auto& trial : requiredTrials) { + //get a random gossip stone + auto gossipStones = GetAccessibleGossipStones(); + auto gossipStone = RandomElement(gossipStones, false); + + //make hint + auto hint = Hint(PREFIX).GetText()+"#"+trial->GetName()+"#"+Hint(ONE_TO_THREE_TRIALS).GetText(); + AddHint(hint, gossipStone, {QM_PINK}); + } + } +} + +static void CreateGanonText() { + + //funny ganon line + ganonText = RandomElement(GetHintCategory(HintCategory::GanonLine)).GetText(); + CreateMessageFromTextObject(0x70CB, 0, 2, 3, AddColorsAndFormat(ganonText)); + + //Get the location of the light arrows + auto lightArrowLocation = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == LIGHT_ARROWS;}); + + //If there is no light arrow location, it was in the player's inventory at the start + if (lightArrowLocation.empty()) { + ganonHintText = Hint(LIGHT_ARROW_LOCATION_HINT).GetText()+Hint(YOUR_POCKET).GetText(); + } else { + ganonHintText = Hint(LIGHT_ARROW_LOCATION_HINT).GetText()+GetHintRegion(Location(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText(); + } + ganonHintText = ganonHintText + "!"; + + CreateMessageFromTextObject(0x70CC, 0, 2, 3, AddColorsAndFormat(ganonHintText)); +} + +//Find the location which has the given itemKey and create the generic altar text for the reward +static Text BuildDungeonRewardText(const uint32_t itemKey) { + uint32_t location = FilterFromPool(allLocations, [itemKey](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == itemKey;})[0]; + Location(location)->SetAsHinted(); + + std::string rewardString = "$" + std::to_string(itemKey - KOKIRI_EMERALD); + + // RANDOTODO implement colors for locations + return Text()+rewardString+GetHintRegion(Location(location)->GetParentRegionKey())->GetHint().GetText()+"...^"; +} + +static Text BuildDoorOfTimeText() { + std::string itemObtained; + Text doorOfTimeText; + + if (OpenDoorOfTime.Is(OPENDOOROFTIME_OPEN)) { + itemObtained = "$o"; + doorOfTimeText = Hint(CHILD_ALTAR_TEXT_END_DOTOPEN).GetText(); + + } else if (OpenDoorOfTime.Is(OPENDOOROFTIME_CLOSED)) { + itemObtained = "$c"; + doorOfTimeText = Hint(CHILD_ALTAR_TEXT_END_DOTCLOSED).GetText(); + + } else if (OpenDoorOfTime.Is(OPENDOOROFTIME_INTENDED)) { + itemObtained = "$i"; + doorOfTimeText = Hint(CHILD_ALTAR_TEXT_END_DOTINTENDED).GetText(); + } + + return Text()+itemObtained+doorOfTimeText; +} + +//insert the required number into the hint and set the singular/plural form +static Text BuildCountReq(const uint32_t req, const Option& count) { + Text requirement = Hint(req).GetTextCopy(); + if (count.Value() == 1) { + requirement.SetForm(SINGULAR); + } else { + requirement.SetForm(PLURAL); + } + requirement.Replace("%d", std::to_string(count.Value())); + return requirement; +} + +static Text BuildBridgeReqsText() { + Text bridgeText; + + if (Bridge.Is(RAINBOWBRIDGE_OPEN)) { + bridgeText = Hint(BRIDGE_OPEN_HINT).GetText(); + + } else if (Bridge.Is(RAINBOWBRIDGE_VANILLA)) { + bridgeText = Hint(BRIDGE_VANILLA_HINT).GetText(); + + } else if (Bridge.Is(RAINBOWBRIDGE_STONES)) { + bridgeText = BuildCountReq(BRIDGE_STONES_HINT, BridgeStoneCount); + + } else if (Bridge.Is(RAINBOWBRIDGE_MEDALLIONS)) { + bridgeText = BuildCountReq(BRIDGE_MEDALLIONS_HINT, BridgeMedallionCount); + + } else if (Bridge.Is(RAINBOWBRIDGE_REWARDS)) { + bridgeText = BuildCountReq(BRIDGE_REWARDS_HINT, BridgeRewardCount); + + } else if (Bridge.Is(RAINBOWBRIDGE_DUNGEONS)) { + bridgeText = BuildCountReq(BRIDGE_DUNGEONS_HINT, BridgeDungeonCount); + + } else if (Bridge.Is(RAINBOWBRIDGE_TOKENS)) { + bridgeText = BuildCountReq(BRIDGE_TOKENS_HINT, BridgeTokenCount); + } + + return Text()+"$l"+bridgeText+"^"; +} + +static Text BuildGanonBossKeyText() { + Text ganonBossKeyText; + + if (GanonsBossKey.Is(GANONSBOSSKEY_START_WITH)) { + ganonBossKeyText = Hint(GANON_BK_START_WITH_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA)) { + ganonBossKeyText = Hint(GANON_BK_VANILLA_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON)) { + ganonBossKeyText = Hint(GANON_BK_OWN_DUNGEON_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_ANY_DUNGEON)) { + ganonBossKeyText = Hint(GANON_BK_ANY_DUNGEON_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_OVERWORLD)) { + ganonBossKeyText = Hint(GANON_BK_OVERWORLD_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_ANYWHERE)) { + ganonBossKeyText = Hint(GANON_BK_ANYWHERE_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_VANILLA)) { + ganonBossKeyText = Hint(LACS_VANILLA_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_STONES)) { + ganonBossKeyText = BuildCountReq(LACS_STONES_HINT, LACSStoneCount); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_MEDALLIONS)) { + ganonBossKeyText = BuildCountReq(LACS_MEDALLIONS_HINT, LACSMedallionCount); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_REWARDS)) { + ganonBossKeyText = BuildCountReq(LACS_REWARDS_HINT, LACSRewardCount); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_DUNGEONS)) { + ganonBossKeyText = BuildCountReq(LACS_DUNGEONS_HINT, LACSDungeonCount); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_TOKENS)) { + ganonBossKeyText = BuildCountReq(LACS_TOKENS_HINT, LACSTokenCount); + } + + return Text()+"$b"+ganonBossKeyText+"^"; +} + +static void CreateAltarText() { + + //Child Altar Text + childAltarText = Hint(SPIRITUAL_STONE_TEXT_START).GetText()+"^"+ + //Spiritual Stones + (StartingKokiriEmerald.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(KOKIRI_EMERALD)) + + (StartingGoronRuby.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(GORON_RUBY)) + + (StartingZoraSapphire.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(ZORA_SAPPHIRE)) + + //How to open Door of Time, the event trigger is necessary to read the altar multiple times + BuildDoorOfTimeText(); + CreateMessageFromTextObject(0x7040, 0, 2, 3, AddColorsAndFormat(childAltarText, {QM_GREEN, QM_RED, QM_BLUE})); + + //Adult Altar Text + adultAltarText = Hint(ADULT_ALTAR_TEXT_START).GetText()+"^"+ + //Medallion Areas + (StartingLightMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(LIGHT_MEDALLION)) + + (StartingForestMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(FOREST_MEDALLION)) + + (StartingFireMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(FIRE_MEDALLION)) + + (StartingWaterMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(WATER_MEDALLION)) + + (StartingSpiritMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(SPIRIT_MEDALLION)) + + (StartingShadowMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(SHADOW_MEDALLION)) + + + //Bridge requirement + BuildBridgeReqsText()+ + + //Ganons Boss Key requirement + BuildGanonBossKeyText()+ + + //End + Hint(ADULT_ALTAR_TEXT_END).GetText(); + CreateMessageFromTextObject(0x7088, 0, 2, 3, AddColorsAndFormat(adultAltarText, {QM_RED, QM_YELLOW, QM_GREEN, QM_RED, QM_BLUE, QM_YELLOW, QM_PINK, QM_RED, QM_RED, QM_RED, QM_RED})); +} + +void CreateMerchantsHints() { + + Text medigoronItemText = Location(GC_MEDIGORON)->GetPlacedItem().GetHint().GetText(); + Text carpetSalesmanItemText = Location(WASTELAND_BOMBCHU_SALESMAN)->GetPlacedItem().GetHint().GetText(); + Text carpetSalesmanItemClearText = Location(WASTELAND_BOMBCHU_SALESMAN)->GetPlacedItem().GetHint().GetClear(); + + Text medigoronText = Hint(MEDIGORON_DIALOG_FIRST).GetText()+medigoronItemText+Hint(MEDIGORON_DIALOG_SECOND).GetText(); + Text carpetSalesmanTextOne = Hint(CARPET_SALESMAN_DIALOG_FIRST).GetText()+carpetSalesmanItemText+Hint(CARPET_SALESMAN_DIALOG_SECOND).GetText(); + Text carpetSalesmanTextTwo = Hint(CARPET_SALESMAN_DIALOG_THIRD).GetText()+carpetSalesmanItemClearText+Hint(CARPET_SALESMAN_DIALOG_FOURTH).GetText(); + + CreateMessageFromTextObject(0x9120, 0, 2, 3, AddColorsAndFormat(medigoronText, {QM_RED, QM_GREEN})); + CreateMessageFromTextObject(0x6077, 0, 2, 3, AddColorsAndFormat(carpetSalesmanTextOne, {QM_RED, QM_GREEN})); + CreateMessageFromTextObject(0x6078, 0, 2, 3, AddColorsAndFormat(carpetSalesmanTextTwo, {QM_RED, QM_YELLOW, QM_RED})); +} + +void CreateAllHints() { + + CreateGanonText(); + CreateAltarText(); + + SPDLOG_INFO("\nNOW CREATING HINTS\n"); + const HintSetting& hintSetting = hintSettingTable[Settings::HintDistribution.Value()]; + + uint8_t remainingDungeonWothHints = hintSetting.dungeonsWothLimit; + uint8_t remainingDungeonBarrenHints = hintSetting.dungeonsBarrenLimit; + + // Add 'always' location hints + if (hintSetting.distTable[static_cast(HintType::Always)].copies > 0) { + // Only filter locations that had a random item placed at them (e.g. don't get cow locations if shuffle cows is off) + auto alwaysHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){ + return Location(loc)->GetHint().GetType() == HintCategory::Always && + Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt()); + }); + + for (auto& hint : conditionalAlwaysHints) { + uint32_t loc = hint.first; + if (hint.second() && Location(loc)->IsHintable() && !Location(loc)->IsHintedAt()) { + alwaysHintLocations.push_back(loc); + } + } + + for (uint32_t location : alwaysHintLocations) { + CreateLocationHint({location}); + } + } + + //Add 'trial' location hints + if (hintSetting.distTable[static_cast(HintType::Trial)].copies > 0) { + CreateTrialHints(); + } + + //create a vector with each hint type proportional to it's weight in the distribution setting. + //ootr uses a weighted probability function to decide hint types, but selecting randomly from + //this vector will do for now + std::vector remainingHintTypes = {}; + for (HintDistributionSetting hds : hintSetting.distTable) { + remainingHintTypes.insert(remainingHintTypes.end(), hds.weight, hds.type); + } + Shuffle(remainingHintTypes); + + //get barren regions + auto barrenLocations = CalculateBarrenRegions(); + + //Calculate dungeon woth/barren info + + std::vector dungeonNames = {"Deku Tree", "Dodongos Cavern", "Jabu Jabus Belly", "Forest Temple", "Fire Temple", + "Water Temple", "Spirit Temple", "Shadow Temple", "Bottom of the Well", "Ice Cavern"}; + //Get list of all barren dungeons + std::vector barrenDungeons; + for (uint32_t barrenLocation : barrenLocations) { + std::string barrenRegion = GetHintRegion(Location(barrenLocation)->GetParentRegionKey())->scene; + bool isDungeon = std::find(dungeonNames.begin(), dungeonNames.end(), barrenRegion) != dungeonNames.end(); + //If it hasn't already been added to the list and is a dungeon, add to list + if (isDungeon && std::find(barrenDungeons.begin(), barrenDungeons.end(), barrenRegion) == barrenDungeons.end()) { + barrenDungeons.push_back(barrenRegion); + } + } + SPDLOG_INFO("\nBarren Dungeons:\n"); + for (std::string barrenDungeon : barrenDungeons) { + SPDLOG_INFO(barrenDungeon + "\n"); + } + + //Get list of all woth dungeons + std::vector wothDungeons; + for (uint32_t wothLocation : wothLocations) { + std::string wothRegion = GetHintRegion(Location(wothLocation)->GetParentRegionKey())->scene; + bool isDungeon = std::find(dungeonNames.begin(), dungeonNames.end(), wothRegion) != dungeonNames.end(); + //If it hasn't already been added to the list and is a dungeon, add to list + if (isDungeon && std::find(wothDungeons.begin(), wothDungeons.end(), wothRegion) == wothDungeons.end()) { + wothDungeons.push_back(wothRegion); + } + } + SPDLOG_INFO("\nWoth Dungeons:\n"); + for (std::string wothDungeon : wothDungeons) { + SPDLOG_INFO(wothDungeon + "\n"); + } + + //Set DungeonInfo array for each dungeon + for (uint32_t i = 0; i < dungeonInfoData.size(); i++) { + std::string dungeonName = dungeonNames[i]; + if (std::find(barrenDungeons.begin(), barrenDungeons.end(), dungeonName) != barrenDungeons.end()) { + dungeonInfoData[i] = DungeonInfo::DUNGEON_BARREN; + } else if (std::find(wothDungeons.begin(), wothDungeons.end(), dungeonName) != wothDungeons.end()) { + dungeonInfoData[i] = DungeonInfo::DUNGEON_WOTH; + } else { + dungeonInfoData[i] = DungeonInfo::DUNGEON_NEITHER; + } + } + + std::array hintTypeNames = { + "Trial", + "Always", + "WotH", + "Barren", + "Entrance", + "Sometimes", + "Random", + "Item", + "Song", + "Overworld", + "Dungeon", + "Junk", + "NamedItem", + }; + + //while there are still gossip stones remaining + while (FilterFromPool(gossipStoneLocations, [](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == NONE;}).size() != 0) { + //TODO: fixed hint types + + if (remainingHintTypes.empty()) { + break; + } + + //get a random hint type from the remaining hints + HintType type = RandomElement(remainingHintTypes, true); + + SPDLOG_INFO("Attempting to make hint of type: "); + SPDLOG_INFO(hintTypeNames[static_cast(type)]); + SPDLOG_INFO("\n"); + + //create the appropriate hint for the type + if (type == HintType::Woth) { + CreateWothHint(&remainingDungeonWothHints); + + } else if (type == HintType::Barren) { + CreateBarrenHint(&remainingDungeonBarrenHints, barrenLocations); + + } else if (type == HintType::Sometimes){ + std::vector sometimesHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->GetHint().GetType() == HintCategory::Sometimes && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());}); + CreateLocationHint(sometimesHintLocations); + + } else if (type == HintType::Random) { + CreateRandomLocationHint(); + + } else if (type == HintType::Item) { + CreateGoodItemHint(); + + } else if (type == HintType::Song){ + std::vector songHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->IsCategory(Category::cSong) && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());}); + CreateLocationHint(songHintLocations); + + } else if (type == HintType::Overworld){ + std::vector overworldHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->IsOverworld() && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());}); + CreateLocationHint(overworldHintLocations); + + } else if (type == HintType::Dungeon){ + std::vector dungeonHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->IsDungeon() && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());}); + CreateLocationHint(dungeonHintLocations); + + } else if (type == HintType::Junk) { + CreateJunkHint(); + } + } + + //If any gossip stones failed to have a hint placed on them for some reason, place a junk hint as a failsafe. + for (uint32_t gossipStone : FilterFromPool(gossipStoneLocations, [](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == NONE;})) { + const HintText junkHint = RandomElement(GetHintCategory(HintCategory::Junk)); + AddHint(junkHint.GetText(), gossipStone, {QM_PINK}); + } + + //Getting gossip stone locations temporarily sets one location to not be reachable. + //Call the function one last time to get rid of false positives on locations not + //being reachable. + GetAccessibleLocations({}); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.hpp b/soh/soh/Enhancements/randomizer/3drando/hints.hpp new file mode 100644 index 000000000..e1c017284 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hints.hpp @@ -0,0 +1,227 @@ +#pragma once + +#include +#include +#include + +#include "keys.hpp" +#include "text.hpp" +#include "random.hpp" +#include "settings.hpp" +#include + +enum class HintType { + Trial, + Always, + Woth, //Way of the Hero + Barren, + Entrance, + Sometimes, + Random, + Item, + Song, + Overworld, + Dungeon, + Junk, + NamedItem, + MaxCount, +}; + +struct HintDistributionSetting { + HintType type; + uint8_t order; + size_t weight; + uint8_t fixed; + uint8_t copies; +}; + +struct HintSetting { + using DistributionTable = std::array(HintType::MaxCount)>; + + uint8_t dungeonsWothLimit; + uint8_t dungeonsBarrenLimit; + bool namedItemsRequired; + DistributionTable distTable; +}; + +enum class HintCategory { + Item, + Always, + Sometimes, + Exclude, + Entrance, + Region, + Junk, + DungeonName, + Boss, + Bridge, + GanonsBossKey, + LACS, + Altar, + Validation, + LightArrow, + GanonLine, + MerchantsDialogs, +}; + +class HintText { +public: + HintText() = default; + HintText(std::vector obscureText_, std::vector ambiguousText_, Text clearText_, HintCategory type_) + : obscureText(std::move(obscureText_)), + ambiguousText(std::move(ambiguousText_)), + clearText(std::move(clearText_)), + type(type_) {} + + static auto Item(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Item}; + } + + static auto Always(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Always}; + } + + static auto Sometimes(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Sometimes}; + } + + static auto Exclude(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Exclude}; + } + + static auto Entrance(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Entrance}; + } + + static auto Region(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Region}; + } + + static auto Junk(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Junk}; + } + + static auto DungeonName(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::DungeonName}; + } + + static auto Boss(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Boss}; + } + + static auto Bridge(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Bridge}; + } + + static auto GanonsBossKey(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::GanonsBossKey}; + } + + static auto LACS(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::LACS}; + } + + static auto Altar(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Altar}; + } + + static auto Validation(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Validation}; + } + + static auto LightArrow(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::LightArrow}; + } + + static auto GanonLine(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::GanonLine}; + } + + static auto MerchantsDialogs(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::MerchantsDialogs}; + } + + Text& GetObscure() { + return RandomElement(obscureText); + } + + const Text& GetObscure() const { + return RandomElement(obscureText); + } + + Text& GetAmbiguous() { + if (ambiguousText.size() > 0) { + return RandomElement(ambiguousText); + } + return RandomElement(obscureText); + } + + const Text& GetAmbiguous() const { + if (ambiguousText.size() > 0) { + return RandomElement(ambiguousText); + } + return RandomElement(obscureText); + } + + const Text& GetClear() const { + if (clearText.GetEnglish().empty()) { + return GetObscure(); + } + return clearText; + } + + const Text& GetText() const { + if (Settings::ClearerHints.Is(HINTMODE_OBSCURE)) { + return GetObscure(); + } else if (Settings::ClearerHints.Is(HINTMODE_AMBIGUOUS)){ + return GetAmbiguous(); + } else { + return GetClear(); + } + } + + const Text GetTextCopy() const { + if (Settings::ClearerHints.Is(HINTMODE_OBSCURE)) { + return GetObscure(); + } else if (Settings::ClearerHints.Is(HINTMODE_AMBIGUOUS)){ + return GetAmbiguous(); + } else { + return GetClear(); + } + } + + HintCategory GetType() const { + return type; + } + + bool operator==(const HintText& right) const { + return obscureText == right.obscureText && + ambiguousText == right.ambiguousText && + clearText == right.clearText; + } + bool operator!=(const HintText& right) const { + return !operator==(right); + } + +private: + std::vector obscureText = {}; + std::vector ambiguousText = {}; + Text clearText; + HintCategory type; +}; + +using ConditionalAlwaysHint = std::pair>; + +//10 dungeons as GTG and GC are excluded +extern std::array dungeonInfoData; + +extern std::array conditionalAlwaysHints; + +extern uint32_t GetHintRegionHintKey(const uint32_t area); +extern void CreateAllHints(); +extern void CreateMerchantsHints(); + +Text& GetChildAltarText(); +Text& GetAdultAltarText(); +Text& GetGanonText(); +Text& GetGanonHintText(); diff --git a/soh/soh/Enhancements/randomizer/3drando/item.cpp b/soh/soh/Enhancements/randomizer/3drando/item.cpp new file mode 100644 index 000000000..13ddb99df --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item.cpp @@ -0,0 +1,84 @@ +#include "item.hpp" + +#include + +#include "item_location.hpp" +#include "logic.hpp" +#include "random.hpp" +#include "item_pool.hpp" +#include "settings.hpp" +#include "z64item.h" + +Item::Item(Text name_, ItemType type_, int getItemId_, bool advancement_, bool* logicVar_, uint32_t hintKey_, + uint16_t price_) + : name(std::move(name_)), + type(type_), + getItemId(getItemId_), + advancement(advancement_), + logicVar(logicVar_), + hintKey(hintKey_), + price(price_) {} + +Item::Item(Text name_, ItemType type_, int getItemId_, bool advancement_, uint8_t* logicVar_, uint32_t hintKey_, + uint16_t price_) + : name(std::move(name_)), + type(type_), + getItemId(getItemId_), + advancement(advancement_), + logicVar(logicVar_), + hintKey(hintKey_), + price(price_) {} + +Item::~Item() = default; + +void Item::ApplyEffect() { + //If this is a key ring, logically add as many keys as we could need + if (FOREST_TEMPLE_KEY_RING <= hintKey && hintKey <= GANONS_CASTLE_KEY_RING) { + *std::get(logicVar) += 10; + } + else { + if (std::holds_alternative(logicVar)) { + *std::get(logicVar) = true; + } else { + *std::get(logicVar) += 1; + } + } + Logic::UpdateHelpers(); +} + +void Item::UndoEffect() { + if (FOREST_TEMPLE_KEY_RING <= hintKey && hintKey <= GANONS_CASTLE_KEY_RING) { + *std::get(logicVar) -= 10; + } + else { + if (std::holds_alternative(logicVar)) { + *std::get(logicVar) = false; + } else { + *std::get(logicVar) -= 1; + } + } + Logic::UpdateHelpers(); +} + +ItemOverride_Value Item::Value() const { + ItemOverride_Value val; + + val.all = 0; + val.itemId = getItemId; + if (getItemId == GI_ICE_TRAP) { + val.looksLikeItemId = RandomElement(IceTrapModels); + } + if (!Settings::ColoredBossKeys && (getItemId >= 0x95 && getItemId <= 0x9A)) { //Boss keys + val.looksLikeItemId = GI_KEY_BOSS; + } + if (!Settings::ColoredKeys && (getItemId >= 0xAF && getItemId <= 0xB7)) { //Small keys + val.looksLikeItemId = GI_KEY_SMALL; + } + if (type == ITEMTYPE_SHOP) { + // With the current shopsanity implementation, we need a way to detect + // regular shop items. This method should have no unintended side effects + // unless there was a multiworld with 256 players... so, it should be fine. + val.player = 0xFF; + } + return val; +} diff --git a/soh/soh/Enhancements/randomizer/3drando/item.hpp b/soh/soh/Enhancements/randomizer/3drando/item.hpp new file mode 100644 index 000000000..a424dbf2b --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item.hpp @@ -0,0 +1,142 @@ +#pragma once + +#include +#include + +#include "keys.hpp" +#include "hint_list.hpp" +#include "settings.hpp" + +union ItemOverride_Value; + +enum ItemType { + ITEMTYPE_ITEM, + ITEMTYPE_MAP, + ITEMTYPE_COMPASS, + ITEMTYPE_BOSSKEY, + ITEMTYPE_SMALLKEY, + ITEMTYPE_TOKEN, + ITEMTYPE_FORTRESS_SMALLKEY, + ITEMTYPE_EVENT, + ITEMTYPE_DROP, + ITEMTYPE_REFILL, + ITEMTYPE_SONG, + ITEMTYPE_SHOP, + ITEMTYPE_DUNGEONREWARD +}; + +class Item { +public: + Item() = default; + Item(Text name_, ItemType type_, int getItemId_, bool advancement_, bool* logicVar_, uint32_t hintKey_, + uint16_t price_ = 0); + Item(Text name_, ItemType type_, int getItemId_, bool advancement_, uint8_t* logicVar_, uint32_t hintKey_, + uint16_t price_ = 0); + ~Item(); + + void ApplyEffect(); + void UndoEffect(); + + ItemOverride_Value Value() const; + + const Text& GetName() const { + return name; + } + + bool IsAdvancement() const { + return advancement; + } + + int GetItemID() const { + return getItemId; + } + + ItemType GetItemType() const { + return type; + } + + uint16_t GetPrice() const { + return price; + } + + void SetPrice(uint16_t price_) { + price = price_; + } + + void SetAsPlaythrough() { + playthrough = true; + } + + bool IsPlaythrough() const { + return playthrough; + } + + bool IsBottleItem() const { + return getItemId == 0x0F || //Empty Bottle + getItemId == 0X14 || //Bottle with Milk + (getItemId >= 0x8C && getItemId <= 0x94); //Rest of bottled contents + } + + bool IsMajorItem() const { + using namespace Settings; + if (type == ITEMTYPE_TOKEN) { + return Bridge.Is(RAINBOWBRIDGE_TOKENS) || LACSCondition == LACSCONDITION_TOKENS; + } + + if (type == ITEMTYPE_DROP || type == ITEMTYPE_EVENT || type == ITEMTYPE_SHOP || type == ITEMTYPE_MAP || type == ITEMTYPE_COMPASS) { + return false; + } + + if (type == ITEMTYPE_DUNGEONREWARD && (ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON))) { + return false; + } + // PURPLE TODO: LOCALIZATION + if (name.GetEnglish().find("Bombchus") != std::string::npos && !BombchusInLogic) { + return false; + } + + if (type == ITEMTYPE_SMALLKEY && (Keysanity.Is(KEYSANITY_VANILLA) || Keysanity.Is(KEYSANITY_OWN_DUNGEON))) { + return false; + } + + if (type == ITEMTYPE_FORTRESS_SMALLKEY && GerudoKeys.Is(GERUDOKEYS_VANILLA)) { + return false; + } + + if ((type == ITEMTYPE_BOSSKEY && getItemId != 0x9A) && (BossKeysanity.Is(BOSSKEYSANITY_VANILLA) || BossKeysanity.Is(BOSSKEYSANITY_OWN_DUNGEON))) { + return false; + } + //Ganons Castle Boss Key + if (getItemId == 0x9A && (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA) || GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON))) { + return false; + } + + return IsAdvancement(); + } + + const uint32_t GetHintKey() const { + return hintKey; + } + + const HintText& GetHint() const { + return Hint(hintKey); + } + + bool operator== (const Item& right) const { + return type == right.GetItemType() && getItemId == right.GetItemID(); + } + + bool operator!= (const Item& right) const { + return !operator==(right); + } + +private: + Text name; + ItemType type; + int getItemId; + bool advancement; + std::variant logicVar; + uint32_t hintKey; + uint16_t price; + bool playthrough = false; +}; diff --git a/soh/soh/Enhancements/randomizer/3drando/item_list.cpp b/soh/soh/Enhancements/randomizer/3drando/item_list.cpp new file mode 100644 index 000000000..b76f24754 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_list.cpp @@ -0,0 +1,290 @@ +#include "item_list.hpp" + +#include "logic.hpp" +#include +#include "z64item.h" + +using namespace Logic; + +static std::array itemTable; + +void ItemTable_Init() { //English name French Spanish Item Type getItemID advancement logic hint key + itemTable[NONE] = Item(Text{"No Item", "Rien", "Sin Objeto"}, ITEMTYPE_EVENT, GI_RUPEE_GREEN, false, &noVariable, NONE); + itemTable[KOKIRI_SWORD] = Item(Text{"Kokiri Sword", "Épée Kokiri", "Espada Kokiri"}, ITEMTYPE_ITEM, GI_SWORD_KOKIRI, true, &KokiriSword, KOKIRI_SWORD); + //[MASTER_SWORD] + itemTable[GIANTS_KNIFE] = Item(Text{"Giant's Knife", "Lame des Géants", "Espada de Biggoron"}, ITEMTYPE_ITEM, GI_SWORD_KNIFE, false, &noVariable, GIANTS_KNIFE); + itemTable[BIGGORON_SWORD] = Item(Text{"Biggoron's Sword", "Épée de Biggoron", "Espada de Biggoron"}, ITEMTYPE_ITEM, GI_SWORD_BGS, true, &BiggoronSword, BIGGORON_SWORD); + itemTable[DEKU_SHIELD] = Item(Text{"Deku Shield", "Bouclier Mojo", "Escudo deku"}, ITEMTYPE_ITEM, GI_SHIELD_DEKU, false, &noVariable, DEKU_SHIELD); + itemTable[HYLIAN_SHIELD] = Item(Text{"Hylian Shield", "Bouclier Hylien", "Escudo hyliano"}, ITEMTYPE_ITEM, GI_SHIELD_HYLIAN, false, &noVariable, HYLIAN_SHIELD); + itemTable[MIRROR_SHIELD] = Item(Text{"Mirror Shield", "Bouclier Miroir", "Escudo espejo"}, ITEMTYPE_ITEM, GI_SHIELD_MIRROR, true, &MirrorShield, MIRROR_SHIELD); + itemTable[GORON_TUNIC] = Item(Text{"Goron Tunic", "Tunique Goron", "Sayo goron"}, ITEMTYPE_ITEM, GI_TUNIC_GORON, true, &GoronTunic, GORON_TUNIC); + itemTable[ZORA_TUNIC] = Item(Text{"Zora Tunic", "Tunique Zora", "Sayo zora"}, ITEMTYPE_ITEM, GI_TUNIC_ZORA, true, &ZoraTunic, ZORA_TUNIC); + itemTable[IRON_BOOTS] = Item(Text{"Iron Boots", "Bottes de plomb", "Botas de hierro"}, ITEMTYPE_ITEM, GI_BOOTS_IRON, true, &IronBoots, IRON_BOOTS); + itemTable[HOVER_BOOTS] = Item(Text{"Hover Boots", "Bottes des airs", "Botas voladoras"}, ITEMTYPE_ITEM, GI_BOOTS_HOVER, true, &HoverBoots, HOVER_BOOTS); + + + itemTable[BOOMERANG] = Item(Text{"Boomerang", "Boomerang", "Búmeran"}, ITEMTYPE_ITEM, GI_BOOMERANG, true, &Boomerang, BOOMERANG); + itemTable[LENS_OF_TRUTH] = Item(Text{"Lens of Truth", "Monocle de Vérité", "Lupa de la Verdad"}, ITEMTYPE_ITEM, GI_LENS, true, &LensOfTruth, LENS_OF_TRUTH); + itemTable[MEGATON_HAMMER] = Item(Text{"Megaton Hammer", "Masse des Titans", "Martillo Megatón"}, ITEMTYPE_ITEM, GI_HAMMER, true, &Hammer, MEGATON_HAMMER); + itemTable[STONE_OF_AGONY] = Item(Text{"Stone of Agony", "Pierre de Souffrance", "Piedra de la Agonía"}, ITEMTYPE_ITEM, GI_STONE_OF_AGONY, true, &ShardOfAgony, STONE_OF_AGONY); + itemTable[DINS_FIRE] = Item(Text{"Din's Fire", "Feu de Din", "Fuego de Din"}, ITEMTYPE_ITEM, GI_DINS_FIRE, true, &DinsFire, DINS_FIRE); + itemTable[FARORES_WIND] = Item(Text{"Farore's Wind", "Vent de Farore", "Viento de Farore"}, ITEMTYPE_ITEM, GI_FARORES_WIND, true, &FaroresWind, FARORES_WIND); + itemTable[NAYRUS_LOVE] = Item(Text{"Nayru's Love", "Amour de Nayru", "Amor de Nayru"}, ITEMTYPE_ITEM, GI_NAYRUS_LOVE, true, &NayrusLove, NAYRUS_LOVE); + itemTable[FIRE_ARROWS] = Item(Text{"Fire Arrow", "Flèche de Feu", "Flecha de fuego"}, ITEMTYPE_ITEM, GI_ARROW_FIRE, true, &FireArrows, FIRE_ARROWS); + itemTable[ICE_ARROWS] = Item(Text{"Ice Arrow", "Flèche de Glace", "Flecha de hielo"}, ITEMTYPE_ITEM, GI_ARROW_ICE, true, &IceArrows, ICE_ARROWS); + itemTable[LIGHT_ARROWS] = Item(Text{"Light Arrow", "Flèche de Lumière", "Flecha de luz"}, ITEMTYPE_ITEM, GI_ARROW_LIGHT, true, &LightArrows, LIGHT_ARROWS); + itemTable[GERUDO_MEMBERSHIP_CARD] = Item(Text{"Gerudo Membership Card", "Carte Gerudo", "Pase de socio gerudo"}, ITEMTYPE_ITEM, GI_GERUDO_CARD, true, &GerudoToken, GERUDO_MEMBERSHIP_CARD); + itemTable[MAGIC_BEAN] = Item(Text{"Magic Bean", "Haricots Magiques", "Habichuelas mágicas"}, ITEMTYPE_ITEM, GI_BEAN, true, &MagicBean, MAGIC_BEAN); + itemTable[MAGIC_BEAN_PACK] = Item(Text{"Magic Bean Pack", "Paquet de Haricots Magiques", "Lote de habichuelas mágicas"}, ITEMTYPE_ITEM, 0xC9, true, &MagicBeanPack, MAGIC_BEAN_PACK); + itemTable[DOUBLE_DEFENSE] = Item(Text{"Double Defense", "Double Défence", "Doble poder defensivo"}, ITEMTYPE_ITEM, 0xB8, true, &DoubleDefense, DOUBLE_DEFENSE); + + itemTable[WEIRD_EGG] = Item(Text{"Weird Egg", "Oeuf Curieux", "Huevo extraño"}, ITEMTYPE_ITEM, GI_WEIRD_EGG, true, &WeirdEgg, WEIRD_EGG); +// itemTable[CUCCO] = Item(Text{"Cucco", "Cocotte", "Cuco"}, ITEMTYPE_ITEM, GI_CUCCO, true, &Cucco, CUCCO); + itemTable[ZELDAS_LETTER] = Item(Text{"Zelda's Letter", "Lettre de Zelda", "Carta de Zelda"}, ITEMTYPE_ITEM, GI_LETTER_ZELDA, true, &ZeldasLetter, ZELDAS_LETTER); +// itemTable[KEATON_MASK] = Item(Text{"Keaton Mask", "Masque du Renard", "Careta de Keaton"}, ITEMTYPE_ITEM, GI_MASK_KEATON, true, &KeatonMask, KEATON_MASK); +// itemTable[SKULL_MASK] = Item(Text{"Skull Mask", "Masque de Mort", "Máscara de calavera"}, ITEMTYPE_ITEM, GI_MASK_SKULL, true, &SkullMask, SKULL_MASK); +// itemTable[SPOOKY_MASK] = Item(Text{"Spooky Mask", "Masque d'Effroi", "Máscara tenebrosa"}, ITEMTYPE_ITEM, GI_MASK_SPOOKY, true, &SpookyMask, SPOOKY_MASK); +// itemTable[BUNNY_HOOD] = Item(Text{"Bunny Hood", "Masque du Lapin", "Capucha de conejo"}, ITEMTYPE_ITEM, GI_MASK_BUNNY, true, &BunnyHood, BUNNY_HOOD); +// itemTable[GORON_MASK] = Item(Text{"Goron Mask", "Masque de Goron", "Máscara Goron"}, ITEMTYPE_ITEM, GI_MASK_GORON, true, &GoronMask, GORON_MASK); +// itemTable[ZORA_MASK] = Item(Text{"Zora Mask", "Masque de Zora", "Máscara Zora"}, ITEMTYPE_ITEM, GI_MASK_ZORA, true, &ZoraMask, ZORA_MASK); +// itemTable[GERUDO_MASK] = Item(Text{"Gerudo Mask", "Masque de Gerudo", "Máscara Gerudo"}, ITEMTYPE_ITEM, GI_MASK_GERUDO, true, &GerudoMask, GERUDO_MASK); +// itemTable[MASK_OF_TRUTH] = Item(Text{"Mask of Truth", "Masque de Vérité", "Máscara de la Verdad"}, ITEMTYPE_ITEM, GI_MASK_MASK, true, &MaskofTruth, MASK_OF_TRUTH); + itemTable[POCKET_EGG] = Item(Text{"Pocket Egg", "Oeuf de poche", "Huevo de bolsillo"}, ITEMTYPE_ITEM, GI_POCKET_EGG, true, &PocketEgg, POCKET_EGG); +// itemTable[POCKET_CUCCO] = Item(Text{"Pocket Cucco", "Cocotte de poche", "Cuco de bolsillo"}, ITEMTYPE_ITEM, GI_POCKET_CUCCO, true, &PocketCucco, POCKET_CUCCO); + itemTable[COJIRO] = Item(Text{"Cojiro", "P'tit Poulet", "Cojiro"}, ITEMTYPE_ITEM, GI_COJIRO, true, &Cojiro, COJIRO); + itemTable[ODD_MUSHROOM] = Item(Text{"Odd Mushroom", "Champignon Suspect", "Champiñón extraño"}, ITEMTYPE_ITEM, GI_ODD_MUSHROOM, true, &OddMushroom, ODD_MUSHROOM); + itemTable[ODD_POTION] = Item(Text{"Odd Potion", "Mixture Suspecte", "Medicina rara"}, ITEMTYPE_ITEM, GI_ODD_POTION, true, &OddPoultice, ODD_POTION); + itemTable[POACHERS_SAW] = Item(Text{"Poacher's Saw", "Scie du Chasseur", "Sierra del furtivo"}, ITEMTYPE_ITEM, GI_SAW, true, &PoachersSaw, POACHERS_SAW); + itemTable[BROKEN_SWORD] = Item(Text{"Broken Goron's Sword", "Épée Brisée de Goron", "Espada goron rota"}, ITEMTYPE_ITEM, GI_SWORD_BROKEN, true, &BrokenSword, BROKEN_SWORD); + itemTable[PRESCRIPTION] = Item(Text{"Prescription", "Ordonnance", "Receta"}, ITEMTYPE_ITEM, GI_PRESCRIPTION, true, &Prescription, PRESCRIPTION); + itemTable[EYEBALL_FROG] = Item(Text{"Eyeball Frog", "Crapaud-qui-louche", "Rana de ojos saltones"}, ITEMTYPE_ITEM, GI_FROG, true, &EyeballFrog, EYEBALL_FROG); + itemTable[EYEDROPS] = Item(Text{"World's Finest Eyedrops", "Super Gouttes", "Supergotas oculares"}, ITEMTYPE_ITEM, GI_EYEDROPS, true, &Eyedrops, EYEDROPS); + itemTable[CLAIM_CHECK] = Item(Text{"Claim Check", "Certificat", "Recibo"}, ITEMTYPE_ITEM, GI_CLAIM_CHECK, true, &ClaimCheck, CLAIM_CHECK); + + itemTable[GOLD_SKULLTULA_TOKEN] = Item(Text{"Gold Skulltula Token", "Symbole de Skulltula d'Or", "Símbolo de skulltula dorada"}, ITEMTYPE_TOKEN, GI_SKULL_TOKEN, true, &GoldSkulltulaTokens, GOLD_SKULLTULA_TOKEN); + + //Progression Items + itemTable[PROGRESSIVE_HOOKSHOT] = Item(Text{"Progressive Hookshot", "Grappin (prog.)", "Gancho progresivo"}, ITEMTYPE_ITEM, 0x80, true, &ProgressiveHookshot, PROGRESSIVE_HOOKSHOT); + itemTable[PROGRESSIVE_STRENGTH] = Item(Text{"Progressive Strength Upgrade", "Amélioration de Force (prog.)", "Fuerza progresiva"}, ITEMTYPE_ITEM, 0x81, true, &ProgressiveStrength, PROGRESSIVE_STRENGTH); + itemTable[PROGRESSIVE_BOMB_BAG] = Item(Text{"Progressive Bomb Bag", "Sac de Bombes (prog.)", "Saco de bombas progresivo"}, ITEMTYPE_ITEM, 0x82, true, &ProgressiveBombBag, PROGRESSIVE_BOMB_BAG); + itemTable[PROGRESSIVE_BOW] = Item(Text{"Progressive Bow", "Arc (prog.)", "Arco progresivo"}, ITEMTYPE_ITEM, 0x83, true, &ProgressiveBow, PROGRESSIVE_BOW); + itemTable[PROGRESSIVE_SLINGSHOT] = Item(Text{"Progressive Slingshot", "Lance-Pierre (prog.)", "Resortera progresiva"}, ITEMTYPE_ITEM, 0x84, true, &ProgressiveBulletBag, PROGRESSIVE_SLINGSHOT); + itemTable[PROGRESSIVE_WALLET] = Item(Text{"Progressive Wallet", "Bourse (prog.)", "Bolsa de rupias progresiva"}, ITEMTYPE_ITEM, 0x85, true, &ProgressiveWallet, PROGRESSIVE_WALLET); + itemTable[PROGRESSIVE_SCALE] = Item(Text{"Progressive Scale", "Écaille (prog.)", "Escama progresiva"}, ITEMTYPE_ITEM, 0x86, true, &ProgressiveScale, PROGRESSIVE_SCALE); + itemTable[PROGRESSIVE_NUT_UPGRADE] = Item(Text{"Progressive Nut Capacity", "Capacité de Noix (prog.)", "Capacidad de nueces deku progresiva"}, ITEMTYPE_ITEM, 0x87, false, &noVariable, PROGRESSIVE_NUT_UPGRADE); + itemTable[PROGRESSIVE_STICK_UPGRADE] = Item(Text{"Progressive Stick Capacity", "Capacité de Bâtons (prog.)", "Capacidad de palos deku progresiva"}, ITEMTYPE_ITEM, 0x88, false, &noVariable, PROGRESSIVE_STICK_UPGRADE); + itemTable[PROGRESSIVE_BOMBCHUS] = Item(Text{"Progressive Bombchu", "Missiles (prog.)", "Bombchus progresivos"}, ITEMTYPE_ITEM, 0x89, true, &Bombchus, PROGRESSIVE_BOMBCHUS); + itemTable[PROGRESSIVE_MAGIC_METER] = Item(Text{"Progressive Magic Meter", "Jauge de Magie (prog.)", "Poder mágico progresivo"}, ITEMTYPE_ITEM, 0x8A, true, &ProgressiveMagic, PROGRESSIVE_MAGIC_METER); + itemTable[PROGRESSIVE_OCARINA] = Item(Text{"Progressive Ocarina", "Ocarina (prog.)", "Ocarina progresiva"}, ITEMTYPE_ITEM, 0x8B, true, &ProgressiveOcarina, PROGRESSIVE_OCARINA); + itemTable[PROGRESSIVE_GORONSWORD] = Item(Text{"Progressive Goron Sword", "Épée Goron (prog.)", "Espada Goron progresiva"}, ITEMTYPE_ITEM, 0xD4, true, &ProgressiveGiantKnife, PROGRESSIVE_GORONSWORD); + + //Bottles + itemTable[EMPTY_BOTTLE] = Item(Text{"Empty Bottle", "Bouteille Vide", "Botella vacía"}, ITEMTYPE_ITEM, 0x0F, true, &Bottles, EMPTY_BOTTLE); + itemTable[BOTTLE_WITH_MILK] = Item(Text{"Bottle with Milk", "Bouteille avec du Lait", "Botella de leche Lon Lon"}, ITEMTYPE_ITEM, 0x14, true, &Bottles, BOTTLE_WITH_MILK); + itemTable[BOTTLE_WITH_RED_POTION] = Item(Text{"Bottle with Red Potion", "Bouteille avec une Potion Rouge", "Botella de poción roja"}, ITEMTYPE_ITEM, 0x8C, true, &Bottles, BOTTLE_WITH_RED_POTION); + itemTable[BOTTLE_WITH_GREEN_POTION] = Item(Text{"Bottle with Green Potion", "Bouteille avec une Potion Verte", "Botella de poción verde"}, ITEMTYPE_ITEM, 0x8D, true, &Bottles, BOTTLE_WITH_GREEN_POTION); + itemTable[BOTTLE_WITH_BLUE_POTION] = Item(Text{"Bottle with Blue Potion", "Bouteille avec une Potion Bleue", "Botella de poción azul"}, ITEMTYPE_ITEM, 0x8E, true, &Bottles, BOTTLE_WITH_BLUE_POTION); + itemTable[BOTTLE_WITH_FAIRY] = Item(Text{"Bottle with Fairy", "Bouteille avec une Fée", "Hada en una botella"}, ITEMTYPE_ITEM, 0x8F, true, &Bottles, BOTTLE_WITH_FAIRY); + itemTable[BOTTLE_WITH_FISH] = Item(Text{"Bottle with Fish", "Bouteille avec un Poisson", "Pez en una botella"}, ITEMTYPE_ITEM, 0x90, true, &Bottles, BOTTLE_WITH_FISH); + itemTable[BOTTLE_WITH_BLUE_FIRE] = Item(Text{"Bottle with Blue Fire", "Bouteille avec une Flamme Bleue", "Botella de fuego azul"}, ITEMTYPE_ITEM, 0x91, true, &Bottles, BOTTLE_WITH_BLUE_FIRE); + itemTable[BOTTLE_WITH_BUGS] = Item(Text{"Bottle with Bugs", "Bouteille avec des Insectes", "Insecto en una botella"}, ITEMTYPE_ITEM, 0x92, true, &Bottles, BOTTLE_WITH_BUGS); + itemTable[BOTTLE_WITH_POE] = Item(Text{"Bottle with Poe", "Bouteille avec un Esprit", "Poe en una botella"}, ITEMTYPE_ITEM, 0x94, true, &Bottles, BOTTLE_WITH_POE); + + //Special bottles that can't immediately dump contents + itemTable[RUTOS_LETTER] = Item(Text{"Bottle with Ruto's Letter", "Bouteille avec la Lettre de Ruto", "Carta de Ruto"}, ITEMTYPE_ITEM, 0x15, true, &RutosLetter, RUTOS_LETTER); + itemTable[BOTTLE_WITH_BIG_POE] = Item(Text{"Bottle with Big Poe", "Bouteille avec une Âme", "Gran Poe en una botella"}, ITEMTYPE_ITEM, 0x93, true, &BottleWithBigPoe, BOTTLE_WITH_BIG_POE); + + //Songs + itemTable[ZELDAS_LULLABY] = Item(Text{"Zelda's Lullaby", "Berceuse de Zelda", "Nana de Zelda"}, ITEMTYPE_SONG, 0xC1, true, &ZeldasLullaby, ZELDAS_LULLABY); + itemTable[EPONAS_SONG] = Item(Text{"Epona's Song", "Chant d'Épona", "Canción de Epona"}, ITEMTYPE_SONG, 0xC2, true, &EponasSong, EPONAS_SONG); + itemTable[SARIAS_SONG] = Item(Text{"Saria's Song", "Chant de Saria", "Canción de Saria"}, ITEMTYPE_SONG, 0xC3, true, &SariasSong, SARIAS_SONG); + itemTable[SUNS_SONG] = Item(Text{"Sun's Song", "Chant du Soleil", "Canción del Sol"}, ITEMTYPE_SONG, 0xC4, true, &SunsSong, SUNS_SONG); + itemTable[SONG_OF_TIME] = Item(Text{"Song of Time", "Chant du Temps", "Canción del tiempo"}, ITEMTYPE_SONG, 0xC5, true, &SongOfTime, SONG_OF_TIME); + itemTable[SONG_OF_STORMS] = Item(Text{"Song of Storms", "Chant des Tempêtes", "Canción de la tormenta"}, ITEMTYPE_SONG, 0xC6, true, &SongOfStorms, SONG_OF_STORMS); + itemTable[MINUET_OF_FOREST] = Item(Text{"Minuet of Forest", "Menuet des Bois", "Minueto del bosque"}, ITEMTYPE_SONG, 0xBB, true, &MinuetOfForest, MINUET_OF_FOREST); + itemTable[BOLERO_OF_FIRE] = Item(Text{"Bolero of Fire", "Boléro du Feu", "Bolero del fuego"}, ITEMTYPE_SONG, 0xBC, true, &BoleroOfFire, BOLERO_OF_FIRE); + itemTable[SERENADE_OF_WATER] = Item(Text{"Serenade of Water", "Sérénade de l'Eau", "Serenata del agua"}, ITEMTYPE_SONG, 0xBD, true, &SerenadeOfWater, SERENADE_OF_WATER); + itemTable[REQUIEM_OF_SPIRIT] = Item(Text{"Requiem of Spirit", "Requiem des Esprits", "Réquiem del espíritu"}, ITEMTYPE_SONG, 0xBE, true, &RequiemOfSpirit, REQUIEM_OF_SPIRIT); + itemTable[NOCTURNE_OF_SHADOW] = Item(Text{"Nocturne of Shadow", "Nocturne de l'Ombre", "Nocturno de la sombra"}, ITEMTYPE_SONG, 0xBF, true, &NocturneOfShadow, NOCTURNE_OF_SHADOW); + itemTable[PRELUDE_OF_LIGHT] = Item(Text{"Prelude of Light", "Prélude de la Lumière", "Preludio de la luz"}, ITEMTYPE_SONG, 0xC0, true, &PreludeOfLight, PRELUDE_OF_LIGHT); + + //Maps and Compasses + itemTable[DEKU_TREE_MAP] = Item(Text{"Great Deku Tree Map", "Carte de l'Arbre Mojo", "Mapa del Gran Árbol Deku"}, ITEMTYPE_MAP, 0xA5, false, &noVariable, DEKU_TREE_MAP); + itemTable[DODONGOS_CAVERN_MAP] = Item(Text{"Dodongo's Cavern Map", "Carte de la Caverne Dodongo", "Mapa de la Cueva de los Dodongos"}, ITEMTYPE_MAP, 0xA6, false, &noVariable, DODONGOS_CAVERN_MAP); + itemTable[JABU_JABUS_BELLY_MAP] = Item(Text{"Jabu-Jabu's Belly Map", "Carte du Ventre de Jabu-Jabu", "Mapa de la tripa de Jabu-Jabu"}, ITEMTYPE_MAP, 0xA7, false, &noVariable, JABU_JABUS_BELLY_MAP); + itemTable[FOREST_TEMPLE_MAP] = Item(Text{"Forest Temple Map", "Carte du Temple de la Forêt", "Mapa del Templo del Bosque"}, ITEMTYPE_MAP, 0xA8, false, &noVariable, FOREST_TEMPLE_MAP); + itemTable[FIRE_TEMPLE_MAP] = Item(Text{"Fire Temple Map", "Carte du Temple du Feu", "Mapa del Templo del Fuego"}, ITEMTYPE_MAP, 0xA9, false, &noVariable, FIRE_TEMPLE_MAP); + itemTable[WATER_TEMPLE_MAP] = Item(Text{"Water Temple Map", "Carte du Temple de l'Eau", "Mapa del Templo del Agua"}, ITEMTYPE_MAP, 0xAA, false, &noVariable, WATER_TEMPLE_MAP); + itemTable[SPIRIT_TEMPLE_MAP] = Item(Text{"Spirit Temple Map", "Carte du Temple de l'Esprit", "Mapa del Templo del Espíritu"}, ITEMTYPE_MAP, 0xAB, false, &noVariable, SPIRIT_TEMPLE_MAP); + itemTable[SHADOW_TEMPLE_MAP] = Item(Text{"Shadow Temple Map", "Carte du Temple de l'Ombre", "Mapa del Templo de la Sombra"}, ITEMTYPE_MAP, 0xAC, false, &noVariable, SHADOW_TEMPLE_MAP); + itemTable[BOTTOM_OF_THE_WELL_MAP] = Item(Text{"Bottom of the Well Map", "Carte du Puits", "Mapa del fondo del pozo"}, ITEMTYPE_MAP, 0xAD, false, &noVariable, BOTTOM_OF_THE_WELL_MAP); + itemTable[ICE_CAVERN_MAP] = Item(Text{"Ice Cavern Map", "Carte de la Caverne Polaire", "Mapa de la caverna de hielo"}, ITEMTYPE_MAP, 0xAE, false, &noVariable, ICE_CAVERN_MAP); + + itemTable[DEKU_TREE_COMPASS] = Item(Text{"Great Deku Tree Compass", "Boussole de l'Arbre Mojo", "Brújula del Gran Árbol Deku"}, ITEMTYPE_COMPASS, 0x9B, false, &noVariable, DEKU_TREE_COMPASS); + itemTable[DODONGOS_CAVERN_COMPASS] = Item(Text{"Dodongo's Cavern Compass", "Boussole de la Caverne Dodongo", "Brújula de la Cueva de los Dodongos"}, ITEMTYPE_COMPASS, 0x9C, false, &noVariable, DODONGOS_CAVERN_COMPASS); + itemTable[JABU_JABUS_BELLY_COMPASS] = Item(Text{"Jabu-Jabu's Belly Compass", "Boussole du Ventre de Jabu-Jabu", "Brújula de la tripa de Jabu-Jabu"}, ITEMTYPE_COMPASS, 0x9D, false, &noVariable, JABU_JABUS_BELLY_COMPASS); + itemTable[FOREST_TEMPLE_COMPASS] = Item(Text{"Forest Temple Compass", "Boussole du Temple de la Forêt", "Brújula del Templo del Bosque"}, ITEMTYPE_COMPASS, 0x9E, false, &noVariable, FOREST_TEMPLE_COMPASS); + itemTable[FIRE_TEMPLE_COMPASS] = Item(Text{"Fire Temple Compass", "Boussole du Temple du Feu", "Brújula del Templo del Fuego"}, ITEMTYPE_COMPASS, 0x9F, false, &noVariable, FIRE_TEMPLE_COMPASS); + itemTable[WATER_TEMPLE_COMPASS] = Item(Text{"Water Temple Compass", "Boussole du Temple de l'Eau", "Brújula del Templo del Agua"}, ITEMTYPE_COMPASS, 0xA0, false, &noVariable, WATER_TEMPLE_COMPASS); + itemTable[SPIRIT_TEMPLE_COMPASS] = Item(Text{"Spirit Temple Compass", "Boussole du Temple de l'Esprit", "Brújula del Templo del Espíritu"}, ITEMTYPE_COMPASS, 0xA1, false, &noVariable, SPIRIT_TEMPLE_COMPASS); + itemTable[SHADOW_TEMPLE_COMPASS] = Item(Text{"Shadow Temple Compass", "Boussole du Temple de l'Ombre", "Brújula del Templo de las Sombras"}, ITEMTYPE_COMPASS, 0xA2, false, &noVariable, SHADOW_TEMPLE_COMPASS); + itemTable[BOTTOM_OF_THE_WELL_COMPASS] = Item(Text{"Bottom of the Well Compass", "Boussole du Puits", "Brújula del fondo del pozo"}, ITEMTYPE_COMPASS, 0xA3, false, &noVariable, BOTTOM_OF_THE_WELL_COMPASS); + itemTable[ICE_CAVERN_COMPASS] = Item(Text{"Ice Cavern Compass", "Boussole de la Caverne Polaire", "Brújula de la caverna de hielo"}, ITEMTYPE_COMPASS, 0xA4, false, &noVariable, ICE_CAVERN_COMPASS); + + //Boss Keys + itemTable[FOREST_TEMPLE_BOSS_KEY] = Item(Text{"Forest Temple Big Key", "Clé d'Or du Temple de la Forêt", "Gran llave del Templo del Bosque"}, ITEMTYPE_BOSSKEY, 0x95, true, &BossKeyForestTemple, FOREST_TEMPLE_BOSS_KEY); + itemTable[FIRE_TEMPLE_BOSS_KEY] = Item(Text{"Fire Temple Big Key", "Clé d'Or du Temple du Feu", "Gran llave del Templo del Fuego"}, ITEMTYPE_BOSSKEY, 0x96, true, &BossKeyFireTemple, FIRE_TEMPLE_BOSS_KEY); + itemTable[WATER_TEMPLE_BOSS_KEY] = Item(Text{"Water Temple Big Key", "Clé d'Or du Temple de l'Eau", "Gran llave del Templo del Agua"}, ITEMTYPE_BOSSKEY, 0x97, true, &BossKeyWaterTemple, WATER_TEMPLE_BOSS_KEY); + itemTable[SPIRIT_TEMPLE_BOSS_KEY] = Item(Text{"Spirit Temple Big Key", "Clé d'Or du Temple de l'Esprit", "Gran llave del Templo del Espíritu"}, ITEMTYPE_BOSSKEY, 0x98, true, &BossKeySpiritTemple, SPIRIT_TEMPLE_BOSS_KEY); + itemTable[SHADOW_TEMPLE_BOSS_KEY] = Item(Text{"Shadow Temple Big Key", "Clé d'Or du Temple de l'Ombre", "Gran llave del Templo de las Sombras"}, ITEMTYPE_BOSSKEY, 0x99, true, &BossKeyShadowTemple, SHADOW_TEMPLE_BOSS_KEY); + itemTable[GANONS_CASTLE_BOSS_KEY] = Item(Text{"Ganon's Castle Big Key", "Clé d'Or du Château de Ganon", "Gran llave del Castillo de Ganon"}, ITEMTYPE_BOSSKEY, 0x9A, true, &BossKeyGanonsCastle, GANONS_CASTLE_BOSS_KEY); + + //Small Keys + itemTable[FOREST_TEMPLE_SMALL_KEY] = Item(Text{"Forest Temple Small Key", "Petite Clé du Temple de la Forêt", "Llave del Templo del Bosque"}, ITEMTYPE_SMALLKEY, 0xAF, true, &ForestTempleKeys, FOREST_TEMPLE_SMALL_KEY); + itemTable[FIRE_TEMPLE_SMALL_KEY] = Item(Text{"Fire Temple Small Key", "Petite Clé du Temple du Feu", "Llave del Templo del Fuego"}, ITEMTYPE_SMALLKEY, 0xB0, true, &FireTempleKeys, FIRE_TEMPLE_SMALL_KEY); + itemTable[WATER_TEMPLE_SMALL_KEY] = Item(Text{"Water Temple Small Key", "Petite Clé du Temple de l'Eau", "Llave del Templo del Agua"}, ITEMTYPE_SMALLKEY, 0xB1, true, &WaterTempleKeys, WATER_TEMPLE_SMALL_KEY); + itemTable[SPIRIT_TEMPLE_SMALL_KEY] = Item(Text{"Spirit Temple Small Key", "Petite Clé du Temple de l'Esprit", "Llave del Templo del Espíritu"}, ITEMTYPE_SMALLKEY, 0xB2, true, &SpiritTempleKeys, SPIRIT_TEMPLE_SMALL_KEY); + itemTable[SHADOW_TEMPLE_SMALL_KEY] = Item(Text{"Shadow Temple Small Key", "Petite Clé du Temple de l'Ombre", "Llave del Templo de las Sombras"}, ITEMTYPE_SMALLKEY, 0xB3, true, &ShadowTempleKeys, SHADOW_TEMPLE_SMALL_KEY); + itemTable[BOTTOM_OF_THE_WELL_SMALL_KEY] = Item(Text{"Bottom of the Well Small Key", "Petite Clé du Puits", "Llave del fondo del pozo"}, ITEMTYPE_SMALLKEY, 0xB4, true, &BottomOfTheWellKeys, BOTTOM_OF_THE_WELL_SMALL_KEY); + itemTable[GERUDO_TRAINING_GROUNDS_SMALL_KEY] = Item(Text{"Training Grounds Small Key", "Petite Clé du Gymnase Gerudo", "Llave del Centro de Instrucción"}, ITEMTYPE_SMALLKEY, 0xB5, true, &GerudoTrainingGroundsKeys, GERUDO_TRAINING_GROUNDS_SMALL_KEY); + itemTable[GERUDO_FORTRESS_SMALL_KEY] = Item(Text{"Gerudo Fortress Small Key", "Petite Clé du Repaire des Voleurs","Llave de la Fortaleza Gerudo"}, ITEMTYPE_FORTRESS_SMALLKEY, 0xB6, true, &GerudoFortressKeys, GERUDO_FORTRESS_SMALL_KEY); + itemTable[GANONS_CASTLE_SMALL_KEY] = Item(Text{"Ganon's Castle Small Key", "Petite Clé du Château de Ganon", "Llave del Castillo de Ganon"}, ITEMTYPE_SMALLKEY, 0xB7, true, &GanonsCastleKeys, GANONS_CASTLE_SMALL_KEY); + itemTable[TREASURE_GAME_SMALL_KEY] = Item(Text{"Chest Game Small Key", "Petite Clé du jeu la Chasse-aux-Trésors", "Llave del Cofre del Tesoro"}, ITEMTYPE_ITEM, 0xDE, true, &TreasureGameKeys, TREASURE_GAME_SMALL_KEY); + + // Key Rings + itemTable[FOREST_TEMPLE_KEY_RING] = Item(Text{"Forest Temple Key Ring", "Trousseau du Temple de la Forêt", "Llavero del Templo del Bosque"}, ITEMTYPE_SMALLKEY, 0xD5, true, &ForestTempleKeys, FOREST_TEMPLE_KEY_RING); + itemTable[FIRE_TEMPLE_KEY_RING] = Item(Text{"Fire Temple Key Ring", "Trousseau du Temple du Feu", "Llavero del Templo del Fuego"}, ITEMTYPE_SMALLKEY, 0xD6, true, &FireTempleKeys, FIRE_TEMPLE_KEY_RING); + itemTable[WATER_TEMPLE_KEY_RING] = Item(Text{"Water Temple Key Ring", "Trousseau du Temple de l'Eau", "Llavero del Templo del Agua"}, ITEMTYPE_SMALLKEY, 0xD7, true, &WaterTempleKeys, WATER_TEMPLE_KEY_RING); + itemTable[SPIRIT_TEMPLE_KEY_RING] = Item(Text{"Spirit Temple Key Ring", "Trousseau du Temple de l'Esprit", "Llavero del Templo del Espíritu"}, ITEMTYPE_SMALLKEY, 0xD8, true, &SpiritTempleKeys, SPIRIT_TEMPLE_KEY_RING); + itemTable[SHADOW_TEMPLE_KEY_RING] = Item(Text{"Shadow Temple Key Ring", "Trousseau du Temple de l'Ombre", "Llavero del Templo de las Sombras"}, ITEMTYPE_SMALLKEY, 0xD9, true, &ShadowTempleKeys, SHADOW_TEMPLE_KEY_RING); + itemTable[BOTTOM_OF_THE_WELL_KEY_RING] = Item(Text{"Bottom of the Well Key Ring", "Trousseau du Puits", "Llavero del fondo del pozo"}, ITEMTYPE_SMALLKEY, 0xDA, true, &BottomOfTheWellKeys, BOTTOM_OF_THE_WELL_KEY_RING); + itemTable[GERUDO_TRAINING_GROUNDS_KEY_RING] = Item(Text{"Training Grounds Key Ring", "Trousseau du Gymnase Gerudo", "Llavero del Centro de Instrucción"}, ITEMTYPE_SMALLKEY, 0xDB, true, &GerudoTrainingGroundsKeys, GERUDO_TRAINING_GROUNDS_KEY_RING); + itemTable[GERUDO_FORTRESS_KEY_RING] = Item(Text{"Gerudo Fortress Key Ring", "Trousseau du Repaire des Voleurs", "Llavero de la Fortaleza Gerudo"}, ITEMTYPE_FORTRESS_SMALLKEY, 0xDC, true, &GerudoFortressKeys, GERUDO_FORTRESS_KEY_RING); + itemTable[GANONS_CASTLE_KEY_RING] = Item(Text{"Ganon's Castle Key Ring", "Trousseau du Château de Ganon", "Llavero del Castillo de Ganon"}, ITEMTYPE_SMALLKEY, 0xDD, true, &GanonsCastleKeys, GANONS_CASTLE_KEY_RING); + + //Stones and Medallions + itemTable[KOKIRI_EMERALD] = Item(Text{"Kokiri's Emerald", "Émeraude Kokiri", "Esmeralda de los Kokiri"}, ITEMTYPE_DUNGEONREWARD, 0xCB, true, &KokiriEmerald, KOKIRI_EMERALD); + itemTable[GORON_RUBY] = Item(Text{"Goron's Ruby", "Rubis Goron", "Rubí de los Goron"}, ITEMTYPE_DUNGEONREWARD, 0xCC, true, &GoronRuby, GORON_RUBY); + itemTable[ZORA_SAPPHIRE] = Item(Text{"Zora's Sapphire", "Saphir Zora", "Zafiro de los Zora"}, ITEMTYPE_DUNGEONREWARD, 0xCD, true, &ZoraSapphire, ZORA_SAPPHIRE); + itemTable[FOREST_MEDALLION] = Item(Text{"Forest Medallion", "Médaillon de la Forêt", "Medallón del Bosque"}, ITEMTYPE_DUNGEONREWARD, 0xCE, true, &ForestMedallion, FOREST_MEDALLION); + itemTable[FIRE_MEDALLION] = Item(Text{"Fire Medallion", "Médaillon du Feu", "Medallón del Fuego"}, ITEMTYPE_DUNGEONREWARD, 0xCF, true, &FireMedallion, FIRE_MEDALLION); + itemTable[WATER_MEDALLION] = Item(Text{"Water Medallion", "Médaillon de l'Eau", "Medallón del Agua"}, ITEMTYPE_DUNGEONREWARD, 0xD0, true, &WaterMedallion, WATER_MEDALLION); + itemTable[SPIRIT_MEDALLION] = Item(Text{"Spirit Medallion", "Médaillon de l'Esprit", "Medallón del Espíritu"}, ITEMTYPE_DUNGEONREWARD, 0xD1, true, &SpiritMedallion, SPIRIT_MEDALLION); + itemTable[SHADOW_MEDALLION] = Item(Text{"Shadow Medallion", "Médaillon de l'Ombre", "Medallón de la Sombra"}, ITEMTYPE_DUNGEONREWARD, 0xD2, true, &ShadowMedallion, SHADOW_MEDALLION); + itemTable[LIGHT_MEDALLION] = Item(Text{"Light Medallion", "Médaillon de la Lumière", "Medallón de la Luz"}, ITEMTYPE_DUNGEONREWARD, 0xD3, true, &LightMedallion, LIGHT_MEDALLION); + + //Generic Items + itemTable[RECOVERY_HEART] = Item(Text{"Recovery Heart", "Coeur de Vie", "Corazón"}, ITEMTYPE_ITEM, GI_HEART, false, &noVariable, RECOVERY_HEART); + itemTable[GREEN_RUPEE] = Item(Text{"Green Rupee", "Rubis Vert", "Rupia verde"}, ITEMTYPE_ITEM, GI_RUPEE_GREEN, false, &noVariable, GREEN_RUPEE); + itemTable[BLUE_RUPEE] = Item(Text{"Blue Rupee", "Rubis Bleu", "Rupia azul"}, ITEMTYPE_ITEM, GI_RUPEE_BLUE, false, &noVariable, BLUE_RUPEE); + itemTable[RED_RUPEE] = Item(Text{"Red Rupee", "Rubis Rouge", "Rupia roja"}, ITEMTYPE_ITEM, GI_RUPEE_RED, false, &noVariable, RED_RUPEE); + itemTable[PURPLE_RUPEE] = Item(Text{"Purple Rupee", "Rubis Pourpre", "Rupia morada"}, ITEMTYPE_ITEM, GI_RUPEE_PURPLE, false, &noVariable, PURPLE_RUPEE); + itemTable[HUGE_RUPEE] = Item(Text{"Huge Rupee", "Énorme Rubis", "Rupia gigante"}, ITEMTYPE_ITEM, GI_RUPEE_GOLD, false, &noVariable, HUGE_RUPEE); + itemTable[PIECE_OF_HEART] = Item(Text{"Piece of Heart", "Quart de Coeur", "Pieza de corazón"}, ITEMTYPE_ITEM, GI_HEART_PIECE, true, &PieceOfHeart, PIECE_OF_HEART); + itemTable[HEART_CONTAINER] = Item(Text{"Heart Container", "Réceptacle de Coeur", "Contenedor de corazón"}, ITEMTYPE_ITEM, GI_HEART_CONTAINER_2, true, &HeartContainer, HEART_CONTAINER); + itemTable[ICE_TRAP] = Item(Text{"Ice Trap", "Piège de Glace", "Trampa de hielo"}, ITEMTYPE_ITEM, GI_ICE_TRAP, false, &noVariable, ICE_TRAP); + itemTable[MILK] = Item(Text{"Milk", "Lait", "Leche Lon Lon"}, ITEMTYPE_ITEM, GI_MILK, false, &noVariable, NONE); + + //Refills + itemTable[BOMBS_5] = Item(Text{"Bombs (5)", "Bombes (5)", "Bombas (5)"}, ITEMTYPE_REFILL, GI_BOMBS_5, false, &noVariable, BOMBS_5); + itemTable[BOMBS_10] = Item(Text{"Bombs (10)", "Bombes (10)", "Bombas (10)"}, ITEMTYPE_REFILL, GI_BOMBS_10, false, &noVariable, BOMBS_10); + itemTable[BOMBS_20] = Item(Text{"Bombs (20)", "Bombes (20)", "Bombas (20)"}, ITEMTYPE_REFILL, GI_BOMBS_20, false, &noVariable, BOMBS_20); + itemTable[BOMBCHU_5] = Item(Text{"Bombchu (5)", "Missiles (5)", "Bombchus (5)"}, ITEMTYPE_REFILL, GI_BOMBCHUS_5, true, &Bombchus5, BOMBCHU_5); + itemTable[BOMBCHU_10] = Item(Text{"Bombchu (10)", "Missiles (10)", "Bombchus (10)"}, ITEMTYPE_REFILL, GI_BOMBCHUS_10, true, &Bombchus10, BOMBCHU_10); + itemTable[BOMBCHU_20] = Item(Text{"Bombchu (20)", "Missiles (20)", "Bombchus (20)"}, ITEMTYPE_REFILL, GI_BOMBCHUS_20, true, &Bombchus20, BOMBCHU_20); + itemTable[BOMBCHU_DROP] = Item(Text{"Bombchu Drop", "Drop Missiles", "Bombchus"}, ITEMTYPE_DROP, GI_BOMBCHUS_10, true, &BombchuDrop, NONE); + itemTable[ARROWS_5] = Item(Text{"Arrows (5)", "Flèches (5)", "Flechas (5)"}, ITEMTYPE_REFILL, GI_ARROWS_SMALL, false, &noVariable, ARROWS_5); + itemTable[ARROWS_10] = Item(Text{"Arrows (10)", "Flèches (10)", "Flechas (10)"}, ITEMTYPE_REFILL, GI_ARROWS_MEDIUM, false, &noVariable, ARROWS_10); + itemTable[ARROWS_30] = Item(Text{"Arrows (30)", "Flèches (30)", "Flechas (30)"}, ITEMTYPE_REFILL, GI_ARROWS_LARGE, false, &noVariable, ARROWS_30); + itemTable[DEKU_NUTS_5] = Item(Text{"Deku Nuts (5)", "Noix Mojo (5)", "Nueces deku (5)"}, ITEMTYPE_REFILL, GI_NUTS_5, false, &noVariable, DEKU_NUTS_5); + itemTable[DEKU_NUTS_10] = Item(Text{"Deku Nuts (10)", "Noix Mojo (10)", "Nueces deku (10)"}, ITEMTYPE_REFILL, GI_NUTS_10, false, &noVariable, DEKU_NUTS_10); + itemTable[DEKU_SEEDS_30] = Item(Text{"Deku Seeds (30)", "Graines Mojo (30)", "Semillas deku (30)"}, ITEMTYPE_REFILL, GI_SEEDS_30, false, &noVariable, DEKU_SEEDS_30); + itemTable[DEKU_STICK_1] = Item(Text{"Deku Stick (1)", "Bâton Mojo (1)", "Palo deku (1)"}, ITEMTYPE_REFILL, GI_STICKS_1, false, &noVariable, DEKU_STICK_1); + itemTable[RED_POTION_REFILL] = Item(Text{"Red Potion Refill", "Recharge de Potion Rouge", "Recarga de poción roja"}, ITEMTYPE_REFILL, GI_POTION_RED, false, &noVariable, NONE); + itemTable[GREEN_POTION_REFILL] = Item(Text{"Green Potion Refill", "Recharge de Potion Verte", "Recarga de poción verde"}, ITEMTYPE_REFILL, GI_POTION_GREEN, false, &noVariable, NONE); + itemTable[BLUE_POTION_REFILL] = Item(Text{"Blue Potion Refill", "Recharge de Potion Bleue", "Recarga de poción azul"}, ITEMTYPE_REFILL, GI_POTION_BLUE, false, &noVariable, NONE); + + //Treasure Game + itemTable[TREASURE_GAME_HEART] = Item(Text{"Piece of Heart (Treasure Chest Minigame)", "Quart de Coeur (Chasse-aux-Trésors)", "Pieza de corazón (Cofre del Tesoro)"}, ITEMTYPE_ITEM, GI_HEART_PIECE_WIN, true, &PieceOfHeart, TREASURE_GAME_HEART); + itemTable[TREASURE_GAME_GREEN_RUPEE] = Item(Text{"Green Rupee (Treasure Chest Minigame)", "Rubis Vert (Chasse-aux-Trésors)", "Rupia Verde (Cofre del Tesoro)"}, ITEMTYPE_ITEM, GI_RUPEE_GREEN_LOSE, false, &noVariable, TREASURE_GAME_GREEN_RUPEE); + + //Shop Items price + itemTable[BUY_DEKU_NUT_5] = Item(Text{"Buy Deku Nut (5)", "Acheter: Noix Mojo (5)", "Comprar nueces deku (5)"}, ITEMTYPE_SHOP, 0x00, true, &Nuts, DEKU_NUTS_5, 15); + itemTable[BUY_ARROWS_30] = Item(Text{"Buy Arrows (30)", "Acheter: Flèches (30)", "Comprar flechas (30)"}, ITEMTYPE_SHOP, 0x01, true, &BuyArrow, ARROWS_30, 60); + itemTable[BUY_ARROWS_50] = Item(Text{"Buy Arrows (50)", "Acheter: Flèches (50)", "Comprar flechas (50)"}, ITEMTYPE_SHOP, 0x02, true, &BuyArrow, ARROWS_30, 90); + itemTable[BUY_BOMBS_525] = Item(Text{"Buy Bombs (5) [25]", "Acheter: Bombes (5) [25]", "Comprar bombas (5) [25]"}, ITEMTYPE_SHOP, 0x03, true, &BuyBomb, BOMBS_5, 25); + itemTable[BUY_DEKU_NUT_10] = Item(Text{"Buy Deku Nut (10)", "Acheter: Noix Mojo (10)", "Comprar Nueces deku (10)"}, ITEMTYPE_SHOP, 0x04, true, &Nuts, DEKU_NUTS_10, 30); + itemTable[BUY_DEKU_STICK_1] = Item(Text{"Buy Deku Stick (1)", "Acheter: Bâton Mojo (1)", "Comprar palos deku (1)"}, ITEMTYPE_SHOP, 0x05, true, &Sticks, DEKU_STICK_1, 10); + itemTable[BUY_BOMBS_10] = Item(Text{"Buy Bombs (10)", "Acheter: Bombes (10)", "Comprar Bombas (10)"}, ITEMTYPE_SHOP, 0x06, true, &BuyBomb, BOMBS_10, 50); + itemTable[BUY_FISH] = Item(Text{"Buy Fish", "Acheter: Poisson", "Comprar pez"}, ITEMTYPE_SHOP, 0x07, true, &FishAccess, BOTTLE_WITH_FISH, 200); + itemTable[BUY_RED_POTION_30] = Item(Text{"Buy Red Potion [30]", "Acheter: Potion Rouge [30]", "Comprar poción roja [30]"}, ITEMTYPE_SHOP, 0x08, false, &noVariable, BOTTLE_WITH_RED_POTION, 30); + itemTable[BUY_GREEN_POTION] = Item(Text{"Buy Green Potion", "Acheter: Potion Verte", "Comprar poción verde"}, ITEMTYPE_SHOP, 0x09, true, &BuyGPotion, BOTTLE_WITH_GREEN_POTION, 30); + itemTable[BUY_BLUE_POTION] = Item(Text{"Buy Blue Potion", "Acheter: Potion Bleue", "Comprar poción azul"}, ITEMTYPE_SHOP, 0x0A, true, &BuyBPotion, BOTTLE_WITH_BLUE_POTION, 100); + itemTable[BUY_HYLIAN_SHIELD] = Item(Text{"Buy Hylian Shield", "Acheter: Bouclier Hylien", "Comprar escudo hyliano"}, ITEMTYPE_SHOP, 0x0C, true, &HylianShield, HYLIAN_SHIELD, 80); + itemTable[BUY_DEKU_SHIELD] = Item(Text{"Buy Deku Shield", "Acheter: Bouclier Mojo", "Comprar escudo deku"}, ITEMTYPE_SHOP, 0x0D, true, &DekuShield, DEKU_SHIELD, 40); + itemTable[BUY_GORON_TUNIC] = Item(Text{"Buy Goron Tunic", "Acheter: Tunique Goron", "Comprar sayo goron"}, ITEMTYPE_SHOP, 0x0E, true, &GoronTunic, GORON_TUNIC, 200); + itemTable[BUY_ZORA_TUNIC] = Item(Text{"Buy Zora Tunic", "Acheter: Tunique Zora", "Comprar sayo zora"}, ITEMTYPE_SHOP, 0x0F, true, &ZoraTunic, ZORA_TUNIC, 300); + itemTable[BUY_HEART] = Item(Text{"Buy Heart", "Acheter: Coeur de Vie", "Comprar corazón"}, ITEMTYPE_SHOP, 0x10, false, &noVariable, RECOVERY_HEART, 10); + itemTable[BUY_BOMBCHU_10] = Item(Text{"Buy Bombchu (10)", "Acheter: Missiles (10)", "Comprar bombchus (10)"}, ITEMTYPE_SHOP, 0x15, true, &BuyBombchus10, BOMBCHU_10, 99); + itemTable[BUY_BOMBCHU_20] = Item(Text{"Buy Bombchu (20)", "Acheter: Missiles (20)", "Comprar bombchus (20)"}, ITEMTYPE_SHOP, 0x16, true, &BuyBombchus20, BOMBCHU_20, 180); + itemTable[BUY_BOMBCHU_5] = Item(Text{"Buy Bombchu (5)", "Acheter: Missiles (5)", "Comprar bombchus (5)"}, ITEMTYPE_SHOP, 0x18, true, &BuyBombchus5, BOMBCHU_5, 60); + itemTable[BUY_DEKU_SEEDS_30] = Item(Text{"Buy Deku Seeds (30)", "Acheter: Graines Mojo (30)", "Comprar semillas deku (30)"}, ITEMTYPE_SHOP, 0x1D, true, &BuySeed, DEKU_SEEDS_30, 30); + itemTable[SOLD_OUT] = Item(Text{"Sold Out", "Vendu", "Vendido"}, ITEMTYPE_SHOP, 0x26, false, &noVariable, NONE, 0); + itemTable[BUY_BLUE_FIRE] = Item(Text{"Buy Blue Fire", "Acheter: Flamme Bleue", "Comprar fuego azul"}, ITEMTYPE_SHOP, 0x27, true, &BlueFireAccess, BOTTLE_WITH_BLUE_FIRE, 300); + itemTable[BUY_BOTTLE_BUG] = Item(Text{"Buy Bottle Bug", "Acheter: Insecte en bouteille", "Comprar bichos"}, ITEMTYPE_SHOP, 0x28, true, &BugsAccess, BOTTLE_WITH_BUGS, 50); + itemTable[BUY_POE] = Item(Text{"Buy Poe", "Acheter: Esprit", "Comprar Poe"}, ITEMTYPE_SHOP, 0x2A, false, &noVariable, BOTTLE_WITH_BIG_POE, 30); + itemTable[BUY_FAIRYS_SPIRIT] = Item(Text{"Buy Fairy's Spirit", "Acheter: Esprit de Fée", "Comprar hada"}, ITEMTYPE_SHOP, 0x2B, true, &FairyAccess, BOTTLE_WITH_FAIRY, 50); + itemTable[BUY_ARROWS_10] = Item(Text{"Buy Arrows (10)", "Acheter: Flèches (10)", "Comprar flechas (10)"}, ITEMTYPE_SHOP, 0x2C, true, &BuyArrow, ARROWS_10, 20); + itemTable[BUY_BOMBS_20] = Item(Text{"Buy Bombs (20)", "Acheter: Bombes (20)", "Comprar bombas (20)"}, ITEMTYPE_SHOP, 0x2D, true, &BuyBomb, BOMBS_20, 80); + itemTable[BUY_BOMBS_30] = Item(Text{"Buy Bombs (30)", "Acheter: Bombes (30)", "Comprar bombas (30)"}, ITEMTYPE_SHOP, 0x2E, true, &BuyBomb, BOMBS_20, 120); + itemTable[BUY_BOMBS_535] = Item(Text{"Buy Bombs (5) [35]", "Acheter: Bombes (5) [35]", "Comprar bombas (5) [35]"}, ITEMTYPE_SHOP, 0x2F, true, &BuyBomb, BOMBS_5, 35); + itemTable[BUY_RED_POTION_40] = Item(Text{"Buy Red Potion [40]", "Acheter: Potion Rouge [40]", "Comprar poción roja [40]"}, ITEMTYPE_SHOP, 0x30, false, &noVariable, BOTTLE_WITH_RED_POTION, 40); + itemTable[BUY_RED_POTION_50] = Item(Text{"Buy Red Potion [50]", "Acheter: Potion Rouge [50]", "Comprar poción roja [50]"}, ITEMTYPE_SHOP, 0x31, false, &noVariable, BOTTLE_WITH_RED_POTION, 50); + + itemTable[TRIFORCE] = Item(Text{"Triforce", "Triforce", "Trifuerza"}, ITEMTYPE_EVENT, GI_RUPEE_RED_LOSE, false, &noVariable, NONE); + itemTable[HINT] = Item(Text{"Hint", "Indice", "Pista"}, ITEMTYPE_EVENT, GI_RUPEE_BLUE_LOSE, false, &noVariable, NONE); + +// itemTable[HOOKSHOT] = Item(Text{"Hookshot", "Grappin", "Gancho"}, ITEMTYPE_ITEM, 0x80, true, &ProgressiveHookshot, HOOKSHOT); +// itemTable[LONGSHOT] = Item(Text{"Longshot", "Super-Grappin", "Supergancho"}, ITEMTYPE_ITEM, 0x80, true, &ProgressiveHookshot, LONGSHOT); +// itemTable[FAIRY_OCARINA] = Item(Text{"Fairy Ocarina", "Ocarina des fées", "Ocarina de las Hadas"}, ITEMTYPE_ITEM, 0x8B, true, &ProgressiveOcarina, FAIRY_OCARINA); +// itemTable[OCARINA_OF_TIME] = Item(Text{"Ocarina of Time", "Ocarina du Temps", "Ocarina del Tiempo"}, ITEMTYPE_ITEM, 0x8B, true, &ProgressiveOcarina, OCARINA_OF_TIME); +// itemTable[BOMB_BAG] = Item(Text{"Bomb Bag", "Sac de Bombes", "Saco de bombas"}, ITEMTYPE_ITEM, 0x82, true, &ProgressiveBombBag, BOMB_BAG); +// itemTable[BIG_BOMB_BAG] = Item(Text{"Big Bomb Bag", "Grand Sac de Bombes", "Saco de bombas grande"}, ITEMTYPE_ITEM, 0x82, true, &ProgressiveBombBag, BIG_BOMB_BAG); +// itemTable[BIGGEST_BOMB_BAG] = Item(Text{"Biggest Bomb Bag", "Énorme Sac de Bombes", "Saco de bombas gigante"}, ITEMTYPE_ITEM, 0x82, true, &ProgressiveBombBag, BIGGEST_BOMB_BAG); +// itemTable[FAIRY_BOW] = Item(Text{"Fairy Bow", "Arc des Fées", "Arco de las Hadas"}, ITEMTYPE_ITEM, 0x83, true, &ProgressiveBow, FAIRY_BOW); +// itemTable[BIG_QUIVER] = Item(Text{"Big Quiver", "Grand carquois", "Carcaj grande"}, ITEMTYPE_ITEM, 0x83, true, &ProgressiveBow, BIG_QUIVER); +// itemTable[BIGGEST_QUIVER] = Item(Text{"Biggest Quiver", "Énorme carquois", "Carcaj gigante"}, ITEMTYPE_ITEM, 0x83, true, &ProgressiveBow, BIGGEST_QUIVER); +// itemTable[FAIRY_SLINGSHOT] = Item(Text{"Fairy Slingshot", "Lance-Pierre des Fées", "Resortera de las hadas"}, ITEMTYPE_ITEM, 0x84, true, &ProgressiveBulletBag, FAIRY_SLINGSHOT); +// itemTable[BIG_BULLET_BAG] = Item(Text{"Big Deku Seed Bullet Bag", "Grand sac de graines mojo", "Bolsa de semillas deku grande"}, ITEMTYPE_ITEM, 0x84, true, &ProgressiveBulletBag, BIG_BULLET_BAG); +// itemTable[BIGGEST_BULLET_BAD] = Item(Text{"Biggest Deku Seed Bullet Bag", "Énorme sac de graines mojo", "Bolsa de semillas deku gigante"}, ITEMTYPE_ITEM, 0x84, true, &ProgressiveBulletBag, BIGGEST_BULLET_BAD); +// itemTable[GORONS_BRACELET] = Item(Text{"Goron's Bracelet", "Bracelet Goron", "Brazalete de los Goron"}, ITEMTYPE_ITEM, 0x81, true, &ProgressiveStrength, GORONS_BRACELET); +// itemTable[SILVER_GAUNTLETS] = Item(Text{"Silver Gauntlets", "Gantelets d'argent", "Guantes de plata"}, ITEMTYPE_ITEM, 0x81, true, &ProgressiveStrength, SILVER_GAUNTLETS); +// itemTable[GOLDEN_GAUNTLETS] = Item(Text{"Golden Gauntlets", "Gantelets d'or", "Guantes de oro"}, ITEMTYPE_ITEM, 0x81, true, &ProgressiveStrength, GOLDEN_GAUNTLETS); +// itemTable[SILVER_SCALE] = Item(Text{"Silver Scale", "Écaille d'argent", "Escama de Plata"}, ITEMTYPE_ITEM, 0x86, true, &ProgressiveScale, SILVER_SCALE); +// itemTable[GOLDEN_SCALE] = Item(Text{"Golden Scale", "Écaille d'or", "Escama de Oro"}, ITEMTYPE_ITEM, 0x86, true, &ProgressiveScale, GOLDEN_SCALE); +// itemTable[ADULT_WALLET] = Item(Text{"Adult Wallet", "Bourse d'adulte", "Bolsa de adulto"}, ITEMTYPE_ITEM, 0x85, true, &ProgressiveWallet, ADULT_WALLET); +// itemTable[GIANT_WALLET] = Item(Text{"Giant Wallet", "Bourse de géant", "Bolsa gigante"}, ITEMTYPE_ITEM, 0x85, true, &ProgressiveWallet, GIANT_WALLET); +// itemTable[TYCOON_WALLET] = Item(Text{"Tycoon Wallet", "Bourse de star", "Bolsa de ricachón"}, ITEMTYPE_ITEM, 0x85, true, &ProgressiveWallet, TYCOON_WALLET); +// itemTable[DEKU_NUT_CAPACITY_30] = Item(Text{"Deku Nut Capacity (30)", "Capacité de noix Mojo (20)", "Capacidad de nueces deku (40)"}, ITEMTYPE_ITEM, 0x87, false, &noVariable, DEKU_NUT_CAPACITY_30); +// itemTable[DEKU_NUT_CAPACITY_40] = Item(Text{"Deku Nut Capacity (40)", "Capacité de noix Mojo (30)", "Capacidad de nueces deku (50)"}, ITEMTYPE_ITEM, 0x87, false, &noVariable, DEKU_NUT_CAPACITY_40); +// itemTable[DEKU_NUT_CAPACITY_20] = Item(Text{"Deku Stick Capacity (20)", "Capacité de Bâtons Mojo (20)", "Capacidad de palos deku (20)"}, ITEMTYPE_ITEM, 0x88, false, &noVariable, DEKU_NUT_CAPACITY_20); +// itemTable[DEKU_NUT_CAPACITY_30] = Item(Text{"Deku Nut Capacity (30)", "Capacité de noix Mojo (20)", "Capacidad de nueces deku (40)"}, ITEMTYPE_ITEM, 0x88, false, &noVariable, DEKU_NUT_CAPACITY_30); +// itemTable[MAGIC_METER] = Item(Text{"Magic Meter", "Jauge de Magie", "Poder mágico"}, ITEMTYPE_ITEM, 0x8A, true, &ProgressiveMagic, MAGIC_METER); +// itemTable[ENHANCED_MAGIC_METER] = Item(Text{"Enhanced Magic Meter", "Jauge de Magie améliorée", "Poder mágico mejorado"}, ITEMTYPE_ITEM, 0x8A, true, &ProgressiveMagic, ENHANCED_MAGIC_METER); + +} + +Item& ItemTable(const uint32_t itemKey) { + return itemTable[itemKey]; +} + +//This function should only be used to place items containing hint text +//at gossip stone locations. +void NewItem(const uint32_t itemKey, const Item item) { + if (itemKey <= BUY_RED_POTION_50) { + printf("\x1b[25;0HWARNING: ATTEMPTED TO OVERWRITE ITEM %lu\n", itemKey); + return; + } + + itemTable[itemKey] = item; +} diff --git a/soh/soh/Enhancements/randomizer/3drando/item_list.hpp b/soh/soh/Enhancements/randomizer/3drando/item_list.hpp new file mode 100644 index 000000000..c1244c3ce --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_list.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "item.hpp" +#include "keys.hpp" + +void ItemTable_Init(); +Item& ItemTable(uint32_t itemKey); +void NewItem(uint32_t itemKey, Item item); diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp new file mode 100644 index 000000000..18e5e8acf --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp @@ -0,0 +1,1580 @@ +#include "item_location.hpp" + +#include "dungeon.hpp" +#include "settings.hpp" +#include "spoiler_log.hpp" +#include "shops.hpp" +#include "debug.hpp" +#include "keys.hpp" +#include + +//Location definitions +static std::array locationTable; + +void LocationTable_Init() { + locationTable[NONE] = ItemLocation::Base (0xFF, 0xFF, "Invalid Location", NONE, NONE, {}, SpoilerCollectionCheck::None()); + //Kokiri Forest scene flag name hint key (hint_list.cpp) vanilla item categories collection check (if needed) collection check group + locationTable[KF_KOKIRI_SWORD_CHEST] = ItemLocation::Chest (0x55, 0x00, "KF Kokiri Sword Chest", KF_KOKIRI_SWORD_CHEST, KOKIRI_SWORD, {Category::cKokiriForest, Category::cForest,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_MIDOS_TOP_LEFT_CHEST] = ItemLocation::Chest (0x28, 0x00, "KF Mido Top Left Chest", KF_MIDOS_TOP_LEFT_CHEST, BLUE_RUPEE, {Category::cKokiriForest, Category::cForest,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_MIDOS_TOP_RIGHT_CHEST] = ItemLocation::Chest (0x28, 0x01, "KF Mido Top Right Chest", KF_MIDOS_TOP_RIGHT_CHEST, BLUE_RUPEE, {Category::cKokiriForest, Category::cForest,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_MIDOS_BOTTOM_LEFT_CHEST] = ItemLocation::Chest (0x28, 0x02, "KF Mido Bottom Left Chest", KF_MIDOS_BOTTOM_LEFT_CHEST, GREEN_RUPEE, {Category::cKokiriForest, Category::cForest,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_MIDOS_BOTTOM_RIGHT_CHEST] = ItemLocation::Chest (0x28, 0x03, "KF Mido Bottom Right Chest", KF_MIDOS_BOTTOM_RIGHT_CHEST, RECOVERY_HEART, {Category::cKokiriForest, Category::cForest,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_STORMS_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x0C, "KF Storms Grotto Chest", KF_STORMS_GROTTO_CHEST, RED_RUPEE, {Category::cKokiriForest, Category::cForest, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + + //Lost Woods + locationTable[LW_NEAR_SHORTCUTS_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x14, "LW Near Shortcuts Grotto Chest", LW_NEAR_SHORTCUTS_GROTTO_CHEST, BLUE_RUPEE, {Category::cLostWoods, Category::cForest, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_SKULL_KID] = ItemLocation::Base (0x5B, 0x3E, "LW Skull Kid", LW_SKULL_KID, PIECE_OF_HEART, {Category::cLostWoods, Category::cForest,}, SpoilerCollectionCheck::ItemGetInf(30), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_TRADE_COJIRO] = ItemLocation::Base (0x5B, 0x1F, "LW Trade Cojiro", LW_TRADE_COJIRO, ODD_MUSHROOM, {Category::cLostWoods, Category::cForest, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(37), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_TRADE_ODD_POTION] = ItemLocation::Base (0x5B, 0x21, "LW Trade Odd Potion", LW_TRADE_ODD_POTION, ODD_POTION, {Category::cLostWoods, Category::cForest, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(57), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_OCARINA_MEMORY_GAME] = ItemLocation::Base (0x5B, 0x76, "LW Ocarina Memory Game", LW_OCARINA_MEMORY_GAME, PIECE_OF_HEART, {Category::cLostWoods, Category::cForest, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(31), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_TARGET_IN_WOODS] = ItemLocation::Base (0x5B, 0x60, "LW Target in Woods", LW_TARGET_IN_WOODS, PROGRESSIVE_SLINGSHOT, {Category::cLostWoods, Category::cForest,}, SpoilerCollectionCheck::ItemGetInf(21), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT] = ItemLocation::Base (0x5B, 0x30, "LW Deku Scrub Near Deku Theater Right",LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, BUY_DEKU_NUT_5, {Category::cLostWoods, Category::cForest, Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(0x5B, 0x01), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT] = ItemLocation::Base (0x5B, 0x31, "LW Deku Scrub Near Deku Theater Left", LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, BUY_DEKU_STICK_1, {Category::cLostWoods, Category::cForest, Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(0x5B, 0x02), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_DEKU_SCRUB_NEAR_BRIDGE] = ItemLocation::Base (0x5B, 0x77, "LW Deku Scrub Near Bridge", LW_DEKU_SCRUB_NEAR_BRIDGE, PROGRESSIVE_STICK_UPGRADE, {Category::cLostWoods, Category::cForest, Category::cDekuScrub, Category::cDekuScrubUpgrades}, SpoilerCollectionCheck::Scrub(0x5B, 0x0A), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_DEKU_SCRUB_GROTTO_REAR] = ItemLocation::GrottoScrub(0xF5, 0x33, "LW Deku Scrub Grotto Rear", LW_DEKU_SCRUB_GROTTO_REAR, BUY_DEKU_SEEDS_30, {Category::cLostWoods, Category::cForest, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x1F, 0x04), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(0xF5, 0x79, "LW Deku Scrub Grotto Front", LW_DEKU_SCRUB_GROTTO_FRONT, PROGRESSIVE_NUT_UPGRADE, {Category::cLostWoods, Category::cForest, Category::cDekuScrub, Category::cDekuScrubUpgrades, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x1F, 0x0B), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[DEKU_THEATER_SKULL_MASK] = ItemLocation::Base (0x3E, 0x77, "Deku Theater Skull Mask", DEKU_THEATER_SKULL_MASK, PROGRESSIVE_STICK_UPGRADE, {Category::cLostWoods, Category::cForest, Category::cGrotto}, SpoilerCollectionCheck::ItemGetInf(22), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[DEKU_THEATER_MASK_OF_TRUTH] = ItemLocation::Base (0x3E, 0x7A, "Deku Theater Mask of Truth", DEKU_THEATER_MASK_OF_TRUTH, PROGRESSIVE_NUT_UPGRADE, {Category::cLostWoods, Category::cForest, Category::cNeedSpiritualStones, Category::cGrotto}, SpoilerCollectionCheck::ItemGetInf(23), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + + //Sacred Forest Meadow + locationTable[SFM_WOLFOS_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x11, "SFM Wolfos Grotto Chest", SFM_WOLFOS_GROTTO_CHEST, PURPLE_RUPEE, {Category::cSacredForestMeadow, Category::cForest, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[SFM_DEKU_SCRUB_GROTTO_REAR] = ItemLocation::GrottoScrub(0xEE, 0x39, "SFM Deku Scrub Grotto Rear", SFM_DEKU_SCRUB_GROTTO_REAR, BUY_RED_POTION_30, {Category::cSacredForestMeadow, Category::cForest, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x18, 0x08), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[SFM_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(0xEE, 0x3A, "SFM Deku Scrub Grotto Front", SFM_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cSacredForestMeadow, Category::cForest, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x18, 0x09), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + + //Hyrule Field + locationTable[HF_SOUTHEAST_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x02, "HF Southeast Grotto Chest", HF_SOUTHEAST_GROTTO_CHEST, RED_RUPEE, {Category::cHyruleField, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_OPEN_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x03, "HF Open Grotto Chest", HF_OPEN_GROTTO_CHEST, BLUE_RUPEE, {Category::cHyruleField, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_NEAR_MARKET_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x00, "HF Near Market Grotto Chest", HF_NEAR_MARKET_GROTTO_CHEST, BLUE_RUPEE, {Category::cHyruleField, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_OCARINA_OF_TIME_ITEM] = ItemLocation::Base (0x51, 0x0C, "HF Ocarina of Time Item", HF_OCARINA_OF_TIME_ITEM, PROGRESSIVE_OCARINA, {Category::cHyruleField, Category::cNeedSpiritualStones,}, SpoilerCollectionCheck::EventChkInf(0x43), SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_TEKTITE_GROTTO_FREESTANDING_POH] = ItemLocation::Collectable(0x3E, 0x01, "HF Tektite Grotto Freestanding PoH", HF_TEKTITE_GROTTO_FREESTANDING_POH, PIECE_OF_HEART, {Category::cHyruleField, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_DEKU_SCRUB_GROTTO] = ItemLocation::GrottoScrub(0xE6, 0x3E, "HF Deku Scrub Grotto", HF_DEKU_SCRUB_GROTTO, PIECE_OF_HEART, {Category::cHyruleField, Category::cDekuScrub, Category::cDekuScrubUpgrades, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x10, 0x03), SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + + //Lake Hylia + locationTable[LH_CHILD_FISHING] = ItemLocation::Base (0x49, 0x3E, "LH Child Fishing", LH_CHILD_FISHING, PIECE_OF_HEART, {Category::cLakeHylia, Category::cMinigame,}, SpoilerCollectionCheck::Fishing(0x02), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_ADULT_FISHING] = ItemLocation::Base (0x49, 0x38, "LH Adult Fishing", LH_ADULT_FISHING, PROGRESSIVE_SCALE, {Category::cLakeHylia, Category::cMinigame,}, SpoilerCollectionCheck::Fishing(0x03), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_LAB_DIVE] = ItemLocation::Base (0x38, 0x3E, "LH Lab Dive", LH_LAB_DIVE, PIECE_OF_HEART, {Category::cLakeHylia,}, SpoilerCollectionCheck::ItemGetInf(24), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_TRADE_FROG] = ItemLocation::Base (0x38, 0x25, "LH Lab Trade Eyeball Frog", LH_TRADE_FROG, EYEDROPS, {Category::cLakeHylia, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(61), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_UNDERWATER_ITEM] = ItemLocation::Base (0x57, 0x15, "LH Underwater Item", LH_UNDERWATER_ITEM, RUTOS_LETTER, {Category::cLakeHylia,}, SpoilerCollectionCheck::EventChkInf(0x31), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_SUN] = ItemLocation::Base (0x57, 0x58, "LH Sun", LH_SUN, FIRE_ARROWS, {Category::cLakeHylia,}, SpoilerCollectionCheck::Chest(0x57, 0x00), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_FREESTANDING_POH] = ItemLocation::Collectable(0x57, 0x1E, "LH Freestanding PoH", LH_FREESTANDING_POH, PIECE_OF_HEART, {Category::cLakeHylia,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(0xEF, 0x30, "LH Deku Scrub Grotto Left", LH_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cLakeHylia, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x19, 0x01), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(0xEF, 0x37, "LH Deku Scrub Grotto Right", LH_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cLakeHylia, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x19, 0x06), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_DEKU_SCRUB_GROTTO_CENTER] = ItemLocation::GrottoScrub(0xEF, 0x33, "LH Deku Scrub Grotto Center", LH_DEKU_SCRUB_GROTTO_CENTER, BUY_DEKU_SEEDS_30, {Category::cLakeHylia, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x19, 0x04), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + + //Gerudo Valley + locationTable[GV_CHEST] = ItemLocation::Chest (0x5A, 0x00, "GV Chest", GV_CHEST, PURPLE_RUPEE, {Category::cGerudoValley, Category::cGerudo,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_TRADE_SAW] = ItemLocation::Base (0x5A, 0x22, "GV Trade Saw", GV_TRADE_SAW, BROKEN_SWORD, {Category::cGerudoValley, Category::cGerudo, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(58), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_WATERFALL_FREESTANDING_POH] = ItemLocation::Collectable(0x5A, 0x01, "GV Waterfall Freestanding PoH", GV_WATERFALL_FREESTANDING_POH, PIECE_OF_HEART, {Category::cGerudoValley, Category::cGerudo,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_CRATE_FREESTANDING_POH] = ItemLocation::Collectable(0x5A, 0x02, "GV Crate Freestanding PoH", GV_CRATE_FREESTANDING_POH, PIECE_OF_HEART, {Category::cGerudoValley, Category::cGerudo,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_DEKU_SCRUB_GROTTO_REAR] = ItemLocation::GrottoScrub(0xF0, 0x39, "GV Deku Scrub Grotto Rear", GV_DEKU_SCRUB_GROTTO_REAR, BUY_RED_POTION_30, {Category::cGerudoValley, Category::cGerudo, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x1A, 0x08), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(0xF0, 0x3A, "GV Deku Scrub Grotto Front", GV_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cGerudoValley, Category::cGerudo, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x1A, 0x09), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + //Gerudo Fortress + locationTable[GF_CHEST] = ItemLocation::Chest (0x5D, 0x00, "GF Chest", GF_CHEST, PIECE_OF_HEART, {Category::cGerudoFortress, Category::cGerudo,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_HBA_1000_POINTS] = ItemLocation::Base (0x5D, 0x3E, "GF HBA 1000 Points", GF_HBA_1000_POINTS, PIECE_OF_HEART, {Category::cGerudoFortress, Category::cGerudo, Category::cMinigame}, SpoilerCollectionCheck::InfTable(0x19, 0x08), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_HBA_1500_POINTS] = ItemLocation::Base (0x5D, 0x30, "GF HBA 1500 Points", GF_HBA_1500_POINTS, PROGRESSIVE_BOW, {Category::cGerudoFortress, Category::cGerudo, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(7), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_GERUDO_MEMBERSHIP_CARD] = ItemLocation::Base (0x0C, 0x3A, "GF Gerudo Membership Card", GF_GERUDO_MEMBERSHIP_CARD, GERUDO_MEMBERSHIP_CARD, {Category::cGerudoFortress, Category::cGerudo,}, SpoilerCollectionCheck::GerudoToken(), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_NORTH_F1_CARPENTER] = ItemLocation::Collectable(0x0C, 0x0C, "GF North F1 Carpenter", GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cGerudoFortress, Category::cGerudo, Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_NORTH_F2_CARPENTER] = ItemLocation::Collectable(0x0C, 0x0A, "GF North F2 Carpenter", GF_NORTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cGerudoFortress, Category::cGerudo, Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_SOUTH_F1_CARPENTER] = ItemLocation::Collectable(0x0C, 0x0E, "GF South F1 Carpenter", GF_SOUTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cGerudoFortress, Category::cGerudo, Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_SOUTH_F2_CARPENTER] = ItemLocation::Collectable(0x0C, 0x0F, "GF South F2 Carpenter", GF_SOUTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cGerudoFortress, Category::cGerudo, Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + //Haunted Wasteland + locationTable[WASTELAND_CHEST] = ItemLocation::Chest (0x5E, 0x00, "Wasteland Chest", WASTELAND_CHEST, PURPLE_RUPEE, {Category::cHauntedWasteland,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[WASTELAND_BOMBCHU_SALESMAN] = ItemLocation::Base (0x5E, 0x03, "Wasteland Carpet Salesman", WASTELAND_BOMBCHU_SALESMAN, BOMBCHU_10, {Category::cHauntedWasteland, Category::cMerchant,}, SpoilerCollectionCheck::EventChkInf(0x34), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + //Desert Colossus + locationTable[COLOSSUS_FREESTANDING_POH] = ItemLocation::Collectable(0x5C, 0x0D, "Colossus Freestanding PoH", COLOSSUS_FREESTANDING_POH, PIECE_OF_HEART, {Category::cDesertColossus,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[COLOSSUS_DEKU_SCRUB_GROTTO_REAR] = ItemLocation::GrottoScrub(0xFD, 0x39, "Colossus Deku Scrub Grotto Rear", COLOSSUS_DEKU_SCRUB_GROTTO_REAR, BUY_RED_POTION_30, {Category::cDesertColossus, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x27, 0x08), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[COLOSSUS_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(0xFD, 0x3A, "Colossus Deku Scrub Grotto Front", COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cDesertColossus, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x27, 0x09), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + //Market + locationTable[MARKET_TREASURE_CHEST_GAME_REWARD] = ItemLocation::Chest (0x10, 0x0A, "MK Treasure Chest Game Reward", MARKET_TREASURE_CHEST_GAME_REWARD, TREASURE_GAME_HEART, {Category::cInnerMarket, Category::cMarket, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(19), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_BOWLING_FIRST_PRIZE] = ItemLocation::Base (0x4B, 0x33, "MK Bombchu Bowling First Prize", MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, PROGRESSIVE_BOMB_BAG, {Category::cInnerMarket, Category::cMarket, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(25), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_BOWLING_SECOND_PRIZE] = ItemLocation::Base (0x4B, 0x3E, "MK Bombchu Bowling Second Prize", MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, PIECE_OF_HEART, {Category::cInnerMarket, Category::cMarket, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(26), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_BOWLING_BOMBCHUS] = ItemLocation::Base (0x4B, 0xFF, "MK Bombchu Bowling Bombchus", NONE, BOMBCHU_DROP, {Category::cInnerMarket, Category::cMarket, Category::cMinigame}, SpoilerCollectionCheck::None(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_LOST_DOG] = ItemLocation::Base (0x35, 0x3E, "MK Lost Dog", MARKET_LOST_DOG, PIECE_OF_HEART, {Category::cInnerMarket, Category::cMarket,}, SpoilerCollectionCheck::InfTable(0x19, 0x09), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (0x42, 0x60, "MK Shooting Gallery", MARKET_SHOOTING_GALLERY_REWARD, PROGRESSIVE_SLINGSHOT, {Category::cInnerMarket, Category::cMarket, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(5), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_10_BIG_POES] = ItemLocation::Base (0x4D, 0x0F, "MK 10 Big Poes", MARKET_10_BIG_POES, EMPTY_BOTTLE, {Category::cInnerMarket, Category::cMarket,}, SpoilerCollectionCheck::BigPoePoints(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_1] = ItemLocation::Chest (0x10, 0x01, "MK Chest Game First Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_1, TREASURE_GAME_SMALL_KEY, {Category::cInnerMarket, Category::cMarket, Category::cMinigame, Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_2] = ItemLocation::Chest (0x10, 0x03, "MK Chest Game Second Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_2, TREASURE_GAME_SMALL_KEY, {Category::cInnerMarket, Category::cMarket, Category::cMinigame, Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_3] = ItemLocation::Chest (0x10, 0x05, "MK Chest Game Third Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_3, TREASURE_GAME_SMALL_KEY, {Category::cInnerMarket, Category::cMarket, Category::cMinigame, Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_4] = ItemLocation::Chest (0x10, 0x07, "MK Chest Game Fourth Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_4, TREASURE_GAME_SMALL_KEY, {Category::cInnerMarket, Category::cMarket, Category::cMinigame, Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_5] = ItemLocation::Chest (0x10, 0x09, "MK Chest Game Fifth Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_5, TREASURE_GAME_SMALL_KEY, {Category::cInnerMarket, Category::cMarket, Category::cMinigame, Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + //Hyrule Castle + locationTable[HC_MALON_EGG] = ItemLocation::Base (0x5F, 0x47, "HC Malon Egg", HC_MALON_EGG, WEIRD_EGG, {Category::cHyruleCastle, Category::cMarket,}, SpoilerCollectionCheck::EventChkInf(0x12), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[HC_ZELDAS_LETTER] = ItemLocation::Base (0x4A, 0x0B, "HC Zeldas Letter", HC_ZELDAS_LETTER, ZELDAS_LETTER, {Category::cHyruleCastle, Category::cMarket,}, SpoilerCollectionCheck::EventChkInf(0x40), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + //Kakariko + locationTable[KAK_REDEAD_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x0A, "Kak Redead Grotto Chest", KAK_REDEAD_GROTTO_CHEST, HUGE_RUPEE, {Category::cKakarikoVillage, Category::cKakariko, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_OPEN_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x08, "Kak Open Grotto Chest", KAK_OPEN_GROTTO_CHEST, RED_RUPEE, {Category::cKakarikoVillage, Category::cKakariko, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_10_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (0x50, 0x45, "Kak 10 Gold Skulltula Reward", KAK_10_GOLD_SKULLTULA_REWARD, PROGRESSIVE_WALLET, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDA), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_20_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (0x50, 0x39, "Kak 20 Gold Skulltula Reward", KAK_20_GOLD_SKULLTULA_REWARD, STONE_OF_AGONY, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDB), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_30_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (0x50, 0x46, "Kak 30 Gold Skulltula Reward", KAK_30_GOLD_SKULLTULA_REWARD, PROGRESSIVE_WALLET, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDC), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_40_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (0x50, 0x03, "Kak 40 Gold Skulltula Reward", KAK_40_GOLD_SKULLTULA_REWARD, BOMBCHU_10, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDD), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_50_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (0x50, 0x3E, "Kak 50 Gold Skulltula Reward", KAK_50_GOLD_SKULLTULA_REWARD, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDE), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_MAN_ON_ROOF] = ItemLocation::Base (0x52, 0x3E, "Kak Man on Roof", KAK_MAN_ON_ROOF, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheck::ItemGetInf(29), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (0x42, 0x30, "Kak Shooting Gallery Reward", KAK_SHOOTING_GALLERY_REWARD, PROGRESSIVE_BOW, {Category::cKakarikoVillage, Category::cKakariko, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(6), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_TRADE_ODD_MUSHROOM] = ItemLocation::Base (0x4E, 0x20, "Kak Trade Odd Mushroom", KAK_TRADE_ODD_MUSHROOM, ODD_POTION, {Category::cKakarikoVillage, Category::cKakariko, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(56), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_ANJU_AS_ADULT] = ItemLocation::Base (0x52, 0x1D, "Kak Anju as Adult", KAK_ANJU_AS_ADULT, CLAIM_CHECK, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheck::ItemGetInf(36), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_ANJU_AS_CHILD] = ItemLocation::Base (0x52, 0x0F, "Kak Anju as Child", KAK_ANJU_AS_CHILD, EMPTY_BOTTLE, {Category::cKakarikoVillage, Category::cKakariko, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_TRADE_POCKET_CUCCO] = ItemLocation::Base (0x52, 0x0E, "Kak Trade Pocket Cucco", KAK_TRADE_POCKET_CUCCO, COJIRO, {Category::cKakarikoVillage, Category::cKakariko, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(38), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_IMPAS_HOUSE_FREESTANDING_POH] = ItemLocation::Collectable(0x37, 0x01, "Kak Impas House Freestanding PoH", KAK_IMPAS_HOUSE_FREESTANDING_POH, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_WINDMILL_FREESTANDING_POH] = ItemLocation::Collectable(0x48, 0x01, "Kak Windmill Freestanding PoH", KAK_WINDMILL_FREESTANDING_POH, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + //Graveyard + locationTable[GRAVEYARD_SHIELD_GRAVE_CHEST] = ItemLocation::Chest (0x40, 0x00, "GY Shield Grave Chest", GRAVEYARD_SHIELD_GRAVE_CHEST, HYLIAN_SHIELD, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_HEART_PIECE_GRAVE_CHEST] = ItemLocation::Chest (0x3F, 0x00, "GY Heart Piece Grave Chest", GRAVEYARD_HEART_PIECE_GRAVE_CHEST, PIECE_OF_HEART, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_COMPOSERS_GRAVE_CHEST] = ItemLocation::Chest (0x41, 0x00, "GY Composers Grave Chest", GRAVEYARD_COMPOSERS_GRAVE_CHEST, BOMBS_5, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_HOOKSHOT_CHEST] = ItemLocation::Chest (0x48, 0x00, "GY Hookshot Chest", GRAVEYARD_HOOKSHOT_CHEST, PROGRESSIVE_HOOKSHOT, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_DAMPE_RACE_FREESTANDING_POH] = ItemLocation::Collectable(0x48, 0x07, "GY Dampe Race Freestanding PoH", GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, PIECE_OF_HEART, {Category::cGraveyard, Category::cKakariko, Category::cMinigame}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_FREESTANDING_POH] = ItemLocation::Collectable(0x53, 0x04, "GY Freestanding PoH", GRAVEYARD_FREESTANDING_POH, PIECE_OF_HEART, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR] = ItemLocation::Collectable(0x53, 0x08, "GY Dampe Gravedigging Tour", GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, PIECE_OF_HEART, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheck::ItemGetInf(20), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + //Death Mountain + locationTable[DMT_CHEST] = ItemLocation::Chest (0x60, 0x01, "DMT Chest", DMT_CHEST, PURPLE_RUPEE, {Category::cDeathMountainTrail, Category::cDeathMountain,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_STORMS_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x17, "DMT Storms Grotto Chest", DMT_STORMS_GROTTO_CHEST, HUGE_RUPEE, {Category::cDeathMountainTrail, Category::cDeathMountain, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_TRADE_BROKEN_SWORD] = ItemLocation::Base (0x60, 0x23, "DMT Trade Broken Sword", DMT_TRADE_BROKEN_SWORD, PRESCRIPTION, {Category::cDeathMountainTrail, Category::cDeathMountain, Category::cAdultTrade}, SpoilerCollectionCheck::Biggoron(0x4), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_TRADE_EYEDROPS] = ItemLocation::Base (0x60, 0x26, "DMT Trade Eyedrops", DMT_TRADE_EYEDROPS, CLAIM_CHECK, {Category::cDeathMountainTrail, Category::cDeathMountain, Category::cAdultTrade}, SpoilerCollectionCheck::Biggoron(0x2), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_TRADE_CLAIM_CHECK] = ItemLocation::Base (0x60, 0x57, "DMT Trade Claim Check", DMT_TRADE_CLAIM_CHECK, BIGGORON_SWORD, {Category::cDeathMountainTrail, Category::cDeathMountain}, SpoilerCollectionCheck::Biggoron(0x1), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_FREESTANDING_POH] = ItemLocation::Collectable(0x60, 0x1E, "DMT Freestanding PoH", DMT_FREESTANDING_POH, PIECE_OF_HEART, {Category::cDeathMountainTrail, Category::cDeathMountain,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + + //Goron City + locationTable[GC_MAZE_LEFT_CHEST] = ItemLocation::Chest (0x62, 0x00, "GC Maze Left Chest", GC_MAZE_LEFT_CHEST, HUGE_RUPEE, {Category::cGoronCity,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_MAZE_RIGHT_CHEST] = ItemLocation::Chest (0x62, 0x01, "GC Maze Right Chest", GC_MAZE_RIGHT_CHEST, PURPLE_RUPEE, {Category::cGoronCity,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_MAZE_CENTER_CHEST] = ItemLocation::Chest (0x62, 0x02, "GC Maze Center Chest", GC_MAZE_CENTER_CHEST, PURPLE_RUPEE, {Category::cGoronCity,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_ROLLING_GORON_AS_CHILD] = ItemLocation::Base (0x62, 0x34, "GC Rolling Goron as Child", GC_ROLLING_GORON_AS_CHILD, PROGRESSIVE_BOMB_BAG, {Category::cGoronCity,}, SpoilerCollectionCheck::InfTable(0x11, 0x06), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_ROLLING_GORON_AS_ADULT] = ItemLocation::Base (0x62, 0x2C, "GC Rolling Goron as Adult", GC_ROLLING_GORON_AS_ADULT, GORON_TUNIC, {Category::cGoronCity,}, SpoilerCollectionCheck::InfTable(0x10, 0x01), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_DARUNIAS_JOY] = ItemLocation::Base (0x62, 0x54, "GC Darunias Joy", GC_DARUNIAS_JOY, PROGRESSIVE_STRENGTH, {Category::cGoronCity,}, SpoilerCollectionCheck::EventChkInf(0x36), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_POT_FREESTANDING_POH] = ItemLocation::Collectable(0x62, 0x1F, "GC Pot Freestanding PoH", GC_POT_FREESTANDING_POH, PIECE_OF_HEART, {Category::cGoronCity,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(0xFB, 0x30, "GC Deku Scrub Grotto Left", GC_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cGoronCity, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x25, 0x01), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(0xFB, 0x37, "GC Deku Scrub Grotto Right", GC_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cGoronCity, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x25, 0x06), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_DEKU_SCRUB_GROTTO_CENTER] = ItemLocation::GrottoScrub(0xFB, 0x33, "GC Deku Scrub Grotto Center", GC_DEKU_SCRUB_GROTTO_CENTER, BUY_ARROWS_30, {Category::cGoronCity, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x25, 0x04), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_MEDIGORON] = ItemLocation::Base (0x62, 0x51, "GC Medigoron", GC_MEDIGORON, GIANTS_KNIFE, {Category::cGoronCity, Category::cMerchant,}, SpoilerCollectionCheck::EventChkInf(0x35), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + + //Death Mountain Crater + locationTable[DMC_UPPER_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x1A, "DMC Upper Grotto Chest", DMC_UPPER_GROTTO_CHEST, BOMBS_20, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_WALL_FREESTANDING_POH] = ItemLocation::Collectable(0x61, 0x02, "DMC Wall Freestanding PoH", DMC_WALL_FREESTANDING_POH, PIECE_OF_HEART, {Category::cDeathMountainCrater, Category::cDeathMountain,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_VOLCANO_FREESTANDING_POH] = ItemLocation::Collectable(0x61, 0x08, "DMC Volcano Freestanding PoH", DMC_VOLCANO_FREESTANDING_POH, PIECE_OF_HEART, {Category::cDeathMountainCrater, Category::cDeathMountain,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_DEKU_SCRUB] = ItemLocation::Base (0x61, 0x37, "DMC Deku Scrub", DMC_DEKU_SCRUB, BUY_BOMBS_535, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(0x61, 0x06), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(0xF9, 0x30, "DMC Deku Scrub Grotto Left", DMC_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x23, 0x01), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(0xF9, 0x37, "DMC Deku Scrub Grotto Right", DMC_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x23, 0x06), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_DEKU_SCRUB_GROTTO_CENTER] = ItemLocation::GrottoScrub(0xF9, 0x33, "DMC Deku Scrub Grotto Center", DMC_DEKU_SCRUB_GROTTO_CENTER, BUY_ARROWS_30, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x23, 0x04), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + + //Zoras River + locationTable[ZR_OPEN_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x09, "ZR Open Grotto Chest", ZR_OPEN_GROTTO_CHEST, RED_RUPEE, {Category::cZorasRiver, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_MAGIC_BEAN_SALESMAN] = ItemLocation::Base (0x54, 0x16, "ZR Magic Bean Salesman", ZR_MAGIC_BEAN_SALESMAN, MAGIC_BEAN, {Category::cZorasRiver,}, SpoilerCollectionCheck::MagicBeans(0x54, 0x01), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_FROGS_IN_THE_RAIN] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs in the Rain", ZR_FROGS_IN_THE_RAIN, PIECE_OF_HEART, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_FROGS_OCARINA_GAME] = ItemLocation::Base (0x54, 0x76, "ZR Frogs Ocarina Game", ZR_FROGS_OCARINA_GAME, PIECE_OF_HEART, {Category::cZorasRiver, Category::cMinigame,}, SpoilerCollectionCheck::EventChkInf(0xD0), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH] = ItemLocation::Collectable(0x54, 0x04, "ZR Near Open Grotto Freestanding PoH", ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, PIECE_OF_HEART, {Category::cZorasRiver,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_NEAR_DOMAIN_FREESTANDING_POH] = ItemLocation::Collectable(0x54, 0x0B, "ZR Near Domain Freestanding PoH", ZR_NEAR_DOMAIN_FREESTANDING_POH, PIECE_OF_HEART, {Category::cZorasRiver,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_DEKU_SCRUB_GROTTO_REAR] = ItemLocation::GrottoScrub(0xEB, 0x39, "ZR Deku Scrub Grotto Rear", ZR_DEKU_SCRUB_GROTTO_REAR, BUY_RED_POTION_30, {Category::cZorasRiver, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x15, 0x08), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(0xEB, 0x3A, "ZR Deku Scrub Grotto Front", ZR_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cZorasRiver, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x15, 0x09), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + + //Zoras Domain + locationTable[ZD_CHEST] = ItemLocation::Chest (0x58, 0x00, "ZD Chest", ZD_CHEST, PIECE_OF_HEART, {Category::cZorasDomain,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_DIVING_MINIGAME] = ItemLocation::Base (0x58, 0x37, "ZD Diving Minigame", ZD_DIVING_MINIGAME, PROGRESSIVE_SCALE, {Category::cZorasDomain, Category::cMinigame,}, SpoilerCollectionCheck::EventChkInf(0x38), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_KING_ZORA_THAWED] = ItemLocation::Base (0x58, 0x2D, "ZD King Zora Thawed", ZD_KING_ZORA_THAWED, ZORA_TUNIC, {Category::cZorasDomain,}, SpoilerCollectionCheck::InfTable(0x13, 0x01), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_TRADE_PRESCRIPTION] = ItemLocation::Base (0x58, 0x24, "ZD Trade Prescription", ZD_TRADE_PRESCRIPTION, EYEBALL_FROG, {Category::cZorasDomain, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(60), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + + //Zoras Fountain + locationTable[ZF_ICEBERG_FREESTANDING_POH] = ItemLocation::Collectable(0x59, 0x01, "ZF Iceberg Freestanding PoH", ZF_ICEBERG_FREESTANDING_POH, PIECE_OF_HEART, {Category::cZorasFountain,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZF_BOTTOM_FREESTANDING_POH] = ItemLocation::Collectable(0x59, 0x14, "ZF Bottom Freestanding PoH", ZF_BOTTOM_FREESTANDING_POH, PIECE_OF_HEART, {Category::cZorasFountain,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + + //Lon Lon Ranch + locationTable[LLR_TALONS_CHICKENS] = ItemLocation::Base (0x4C, 0x14, "LLR Talons Chickens", LLR_TALONS_CHICKENS, BOTTLE_WITH_MILK, {Category::cLonLonRanch, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(10), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_FREESTANDING_POH] = ItemLocation::Collectable(0x4C, 0x01, "LLR Freestanding PoH", LLR_FREESTANDING_POH, PIECE_OF_HEART, {Category::cLonLonRanch,}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(0xFC, 0x30, "LLR Deku Scrub Grotto Left", LLR_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cLonLonRanch, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x26, 0x01), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(0xFC, 0x37, "LLR Deku Scrub Grotto Right", LLR_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cLonLonRanch, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x26, 0x06), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_DEKU_SCRUB_GROTTO_CENTER] = ItemLocation::GrottoScrub(0xFC, 0x33, "LLR Deku Scrub Grotto Center", LLR_DEKU_SCRUB_GROTTO_CENTER, BUY_DEKU_SEEDS_30, {Category::cLonLonRanch, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x26, 0x04), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + + /*------------------- + --- DUNGEONS --- + -------------------*/ + + //Deku Tree Vanilla + locationTable[DEKU_TREE_MAP_CHEST] = ItemLocation::Chest (0x00, 0x03, "Deku Tree Map Chest", DEKU_TREE_MAP_CHEST, DEKU_TREE_MAP, {Category::cDekuTree, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_COMPASS_CHEST] = ItemLocation::Chest (0x00, 0x02, "Deku Tree Compass Chest", DEKU_TREE_COMPASS_CHEST, DEKU_TREE_COMPASS, {Category::cDekuTree, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_COMPASS_ROOM_SIDE_CHEST] = ItemLocation::Chest (0x00, 0x06, "Deku Tree Compass Room Side Chest", DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, RECOVERY_HEART, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_BASEMENT_CHEST] = ItemLocation::Chest (0x00, 0x04, "Deku Tree Basement Chest", DEKU_TREE_BASEMENT_CHEST, RECOVERY_HEART, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_SLINGSHOT_CHEST] = ItemLocation::Chest (0x00, 0x01, "Deku Tree Slingshot Chest", DEKU_TREE_SLINGSHOT_CHEST, PROGRESSIVE_SLINGSHOT, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST] = ItemLocation::Chest (0x00, 0x05, "Deku Tree Slingshot Room Side Chest", DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, RECOVERY_HEART, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + //Deku Tree MQ + locationTable[DEKU_TREE_MQ_MAP_CHEST] = ItemLocation::Chest (0x00, 0x03, "Deku Tree MQ Map Chest", DEKU_TREE_MQ_MAP_CHEST, DEKU_TREE_MAP, {Category::cDekuTree, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x00, 0x01, "Deku Tree MQ Compass Chest", DEKU_TREE_MQ_COMPASS_CHEST, DEKU_TREE_COMPASS, {Category::cDekuTree, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_SLINGSHOT_CHEST] = ItemLocation::Chest (0x00, 0x06, "Deku Tree MQ Slingshot Chest", DEKU_TREE_MQ_SLINGSHOT_CHEST, PROGRESSIVE_SLINGSHOT, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST] = ItemLocation::Chest (0x00, 0x02, "Deku Tree MQ Slingshot Room Back Chest", DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, DEKU_SHIELD, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_BASEMENT_CHEST] = ItemLocation::Chest (0x00, 0x04, "Deku Tree MQ Basement Chest", DEKU_TREE_MQ_BASEMENT_CHEST, DEKU_SHIELD, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST] = ItemLocation::Chest (0x00, 0x05, "Deku Tree MQ Before Spinning Log Chest", DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, RECOVERY_HEART, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST] = ItemLocation::Chest (0x00, 0x00, "Deku Tree MQ After Spinning Log Chest", DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, PURPLE_RUPEE, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_DEKU_SCRUB] = ItemLocation::Base (0x00, 0x34, "Deku Tree MQ Deku Scrub", DEKU_TREE_MQ_DEKU_SCRUB, BUY_DEKU_SHIELD, {Category::cDekuTree, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x00, 0x05), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + + //Dodongos Cavern Shared + locationTable[DODONGOS_CAVERN_BOSS_ROOM_CHEST] = ItemLocation::Chest (0x12, 0x00, "Dodongos Cavern Boss Room Chest", DODONGOS_CAVERN_BOSS_ROOM_CHEST, BOMBS_5, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + //Dodongos Cavern Vanilla + locationTable[DODONGOS_CAVERN_MAP_CHEST] = ItemLocation::Chest (0x01, 0x08, "Dodongos Cavern Map Chest", DODONGOS_CAVERN_MAP_CHEST, DODONGOS_CAVERN_MAP, {Category::cDodongosCavern, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_COMPASS_CHEST] = ItemLocation::Chest (0x01, 0x05, "Dodongos Cavern Compass Chest", DODONGOS_CAVERN_COMPASS_CHEST, DODONGOS_CAVERN_COMPASS, {Category::cDodongosCavern, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST] = ItemLocation::Chest (0x01, 0x06, "Dodongos Cavern Bomb Flower Platform Chest", DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, RED_RUPEE, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_BOMB_BAG_CHEST] = ItemLocation::Chest (0x01, 0x04, "Dodongos Cavern Bomb Bag Chest", DODONGOS_CAVERN_BOMB_BAG_CHEST, PROGRESSIVE_BOMB_BAG, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_END_OF_BRIDGE_CHEST] = ItemLocation::Chest (0x01, 0x0A, "Dodongos Cavern End Of Bridge Chest", DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, DEKU_SHIELD, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT] = ItemLocation::Base (0x01, 0x30, "Dodongos Cavern Deku Scrub Near Bomb Bag Left", DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, BUY_DEKU_NUT_5, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x01), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS] = ItemLocation::Base (0x01, 0x31, "Dodongos Cavern Deku Scrub Side Room Near Dodongos", DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, BUY_DEKU_STICK_1, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x02), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT] = ItemLocation::Base (0x01, 0x33, "Dodongos Cavern Deku Scrub Near Bomb Bag Right", DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, BUY_DEKU_SEEDS_30, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x04), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_DEKU_SCRUB_LOBBY] = ItemLocation::Base (0x01, 0x34, "Dodongos Cavern Deku Scrub Lobby", DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, BUY_DEKU_SHIELD, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x05), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + //Dodongos Cavern MQ + locationTable[DODONGOS_CAVERN_MQ_MAP_CHEST] = ItemLocation::Chest (0x01, 0x00, "Dodongos Cavern MQ Map Chest", DODONGOS_CAVERN_MQ_MAP_CHEST, DODONGOS_CAVERN_MAP, {Category::cDodongosCavern, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST] = ItemLocation::Chest (0x01, 0x04, "Dodongos Cavern MQ Bomb Bag Chest", DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, PROGRESSIVE_BOMB_BAG, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x01, 0x05, "Dodongos Cavern MQ Compass Chest", DODONGOS_CAVERN_MQ_COMPASS_CHEST, DODONGOS_CAVERN_COMPASS, {Category::cDodongosCavern, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST] = ItemLocation::Chest (0x01, 0x02, "Dodongos Cavern MQ Larvae Room Chest", DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, DEKU_SHIELD, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST] = ItemLocation::Chest (0x01, 0x03, "Dodongos Cavern MQ Torch Puzzle Room Chest", DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, BLUE_RUPEE, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST] = ItemLocation::Chest (0x01, 0x01, "Dodongos Cavern MQ Under Grave Chest", DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, HYLIAN_SHIELD, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR] = ItemLocation::Base (0x01, 0x31, "Dodongos Cavern Deku Scrub Lobby Rear", DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, BUY_DEKU_STICK_1, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x02), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT] = ItemLocation::Base (0x01, 0x33, "Dodongos Cavern Deku Scrub Lobby Front", DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, BUY_DEKU_SEEDS_30, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x04), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE] = ItemLocation::Base (0x01, 0x34, "Dodongos Cavern Deku Scrub Staircase", DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, BUY_DEKU_SHIELD, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x05), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS] = ItemLocation::Base (0x01, 0x39, "Dodongos Cavern Deku Scrub Side Room Near Lower Lizalfos",DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, BUY_RED_POTION_30, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x08), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + + //Jabu Jabus Belly Vanilla + locationTable[JABU_JABUS_BELLY_MAP_CHEST] = ItemLocation::Chest (0x02, 0x02, "Jabu Jabus Belly Map Chest", JABU_JABUS_BELLY_MAP_CHEST, JABU_JABUS_BELLY_MAP, {Category::cJabuJabusBelly, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_COMPASS_CHEST] = ItemLocation::Chest (0x02, 0x04, "Jabu Jabus Belly Compass Chest", JABU_JABUS_BELLY_COMPASS_CHEST, JABU_JABUS_BELLY_COMPASS, {Category::cJabuJabusBelly, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_BOOMERANG_CHEST] = ItemLocation::Chest (0x02, 0x01, "Jabu Jabus Belly Boomerang Chest", JABU_JABUS_BELLY_BOOMERANG_CHEST, BOOMERANG, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_DEKU_SCRUB] = ItemLocation::Base (0x02, 0x30, "Jabu Jabus Belly Deku Scrub", JABU_JABUS_BELLY_DEKU_SCRUB, BUY_DEKU_NUT_5, {Category::cJabuJabusBelly, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x02, 0x01), SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + //Jabu Jabus Belly MQ + locationTable[JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST] = ItemLocation::Chest (0x02, 0x05, "Jabu Jabus Belly MQ First Room Side Chest", JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, DEKU_NUTS_5, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_MAP_CHEST] = ItemLocation::Chest (0x02, 0x03, "Jabu Jabus Belly MQ Map Chest", JABU_JABUS_BELLY_MQ_MAP_CHEST, JABU_JABUS_BELLY_MAP, {Category::cJabuJabusBelly, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST] = ItemLocation::Chest (0x02, 0x02, "Jabu Jabus Belly MQ Second Room Lower Chest", JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, DEKU_NUTS_5, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x02, 0x00, "Jabu Jabus Belly MQ Compass Chest", JABU_JABUS_BELLY_MQ_COMPASS_CHEST, JABU_JABUS_BELLY_COMPASS, {Category::cJabuJabusBelly, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST] = ItemLocation::Chest (0x02, 0x07, "Jabu Jabus Belly MQ Second Room Upper Chest", JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, RECOVERY_HEART, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST] = ItemLocation::Chest (0x02, 0x08, "Jabu Jabus Belly MQ Basement Near Switches Chest", JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, DEKU_NUTS_5, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST] = ItemLocation::Chest (0x02, 0x04, "Jabu Jabus Belly MQ Basement Near Vines Chest", JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, BOMBCHU_10, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST] = ItemLocation::Chest (0x02, 0x0A, "Jabu Jabus Belly MQ Near Boss Chest", JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, DEKU_SHIELD, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST] = ItemLocation::Chest (0x02, 0x09, "Jabu Jabus Belly MQ Falling Like Like Room Chest", JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, DEKU_STICK_1, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST] = ItemLocation::Chest (0x02, 0x01, "Jabu Jabus Belly MQ Boomerang Room Small Chest", JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, DEKU_NUTS_5, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST] = ItemLocation::Chest (0x02, 0x06, "Jabu Jabus Belly MQ Boomerang Chest", JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, BOOMERANG, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + //COW + + //Forest Temple Vanilla + locationTable[FOREST_TEMPLE_FIRST_ROOM_CHEST] = ItemLocation::Chest (0x03, 0x03, "Forest Temple First Room Chest", FOREST_TEMPLE_FIRST_ROOM_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_FIRST_STALFOS_CHEST] = ItemLocation::Chest (0x03, 0x00, "Forest Temple First Stalfos Chest", FOREST_TEMPLE_FIRST_STALFOS_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST] = ItemLocation::Chest (0x03, 0x05, "Forest Temple Raised Island Courtyard Chest", FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, RECOVERY_HEART, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MAP_CHEST] = ItemLocation::Chest (0x03, 0x01, "Forest Temple Map Chest", FOREST_TEMPLE_MAP_CHEST, FOREST_TEMPLE_MAP, {Category::cForestTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_WELL_CHEST] = ItemLocation::Chest (0x03, 0x09, "Forest Temple Well Chest", FOREST_TEMPLE_WELL_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST] = ItemLocation::Chest (0x03, 0x07, "Forest Temple Falling Ceiling Room Chest", FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, ARROWS_10, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_EYE_SWITCH_CHEST] = ItemLocation::Chest (0x03, 0x04, "Forest Temple Eye Switch Chest", FOREST_TEMPLE_EYE_SWITCH_CHEST, ARROWS_30, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_BOSS_KEY_CHEST] = ItemLocation::Chest (0x03, 0x0E, "Forest Temple Boss Key Chest", FOREST_TEMPLE_BOSS_KEY_CHEST, FOREST_TEMPLE_BOSS_KEY, {Category::cForestTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_FLOORMASTER_CHEST] = ItemLocation::Chest (0x03, 0x02, "Forest Temple Floormaster Chest", FOREST_TEMPLE_FLOORMASTER_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_BOW_CHEST] = ItemLocation::Chest (0x03, 0x0C, "Forest Temple Bow Chest", FOREST_TEMPLE_BOW_CHEST, PROGRESSIVE_BOW, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_RED_POE_CHEST] = ItemLocation::Chest (0x03, 0x0D, "Forest Temple Red Poe Chest", FOREST_TEMPLE_RED_POE_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_BLUE_POE_CHEST] = ItemLocation::Chest (0x03, 0x0F, "Forest Temple Blue Poe Chest", FOREST_TEMPLE_BLUE_POE_CHEST, FOREST_TEMPLE_COMPASS, {Category::cForestTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_BASEMENT_CHEST] = ItemLocation::Chest (0x03, 0x0B, "Forest Temple Basement Chest", FOREST_TEMPLE_BASEMENT_CHEST, ARROWS_5, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + //Forest Temple MQ + locationTable[FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST] = ItemLocation::Chest (0x03, 0x03, "Forest Temple MQ First Room Chest", FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_WOLFOS_CHEST] = ItemLocation::Chest (0x03, 0x00, "Forest Temple MQ Wolfos Chest", FOREST_TEMPLE_MQ_WOLFOS_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_BOW_CHEST] = ItemLocation::Chest (0x03, 0x0C, "Forest Temple MQ Bow Chest", FOREST_TEMPLE_MQ_BOW_CHEST, PROGRESSIVE_BOW, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST] = ItemLocation::Chest (0x03, 0x01, "Forest Temple MQ Raised Island Courtyard Lower Chest", FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST] = ItemLocation::Chest (0x03, 0x05, "Forest Temple MQ Raised Island Courtyard Upper Chest", FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_WELL_CHEST] = ItemLocation::Chest (0x03, 0x09, "Forest Temple MQ Well Chest", FOREST_TEMPLE_MQ_WELL_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_MAP_CHEST] = ItemLocation::Chest (0x03, 0x0D, "Forest Temple MQ Map Chest", FOREST_TEMPLE_MQ_MAP_CHEST, FOREST_TEMPLE_MAP, {Category::cForestTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x03, 0x0F, "Forest Temple MQ Compass Chest", FOREST_TEMPLE_MQ_COMPASS_CHEST, FOREST_TEMPLE_COMPASS, {Category::cForestTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST] = ItemLocation::Chest (0x03, 0x06, "Forest Temple MQ Falling Ceiling Room Chest", FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, ARROWS_5, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_BASEMENT_CHEST] = ItemLocation::Chest (0x03, 0x0B, "Forest Temple MQ Basement Chest", FOREST_TEMPLE_MQ_BASEMENT_CHEST, ARROWS_5, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_REDEAD_CHEST] = ItemLocation::Chest (0x03, 0x02, "Forest Temple MQ Redead Chest", FOREST_TEMPLE_MQ_REDEAD_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_BOSS_KEY_CHEST] = ItemLocation::Chest (0x03, 0x0E, "Forest Temple MQ Boss Key Chest", FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, FOREST_TEMPLE_BOSS_KEY, {Category::cForestTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + + //Fire Temple Vanilla + locationTable[FIRE_TEMPLE_NEAR_BOSS_CHEST] = ItemLocation::Chest (0x04, 0x01, "Fire Temple Near Boss Chest", FIRE_TEMPLE_NEAR_BOSS_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_FLARE_DANCER_CHEST] = ItemLocation::Chest (0x04, 0x00, "Fire Temple Flare Dancer Chest", FIRE_TEMPLE_FLARE_DANCER_CHEST, BOMBS_10, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BOSS_KEY_CHEST] = ItemLocation::Chest (0x04, 0x0C, "Fire Temple Boss Key Chest", FIRE_TEMPLE_BOSS_KEY_CHEST, FIRE_TEMPLE_BOSS_KEY, {Category::cFireTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST] = ItemLocation::Chest (0x04, 0x02, "Fire Temple Big Lava Room Blocked Door Chest", FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST] = ItemLocation::Chest (0x04, 0x04, "Fire Temple Big Lava Room Lower Open Door Chest", FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST] = ItemLocation::Chest (0x04, 0x03, "Fire Temple Boulder Maze Lower Chest", FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST] = ItemLocation::Chest (0x04, 0x06, "Fire Temple Boulder Maze Upper Chest", FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST] = ItemLocation::Chest (0x04, 0x08, "Fire Temple Boulder Maze Side Room Chest", FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST] = ItemLocation::Chest (0x04, 0x0B, "Fire Temple Boulder Maze Shortcut Chest", FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_SCARECROW_CHEST] = ItemLocation::Chest (0x04, 0x0D, "Fire Temple Scarecrow Chest", FIRE_TEMPLE_SCARECROW_CHEST, HUGE_RUPEE, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MAP_CHEST] = ItemLocation::Chest (0x04, 0x0A, "Fire Temple Map Chest", FIRE_TEMPLE_MAP_CHEST, FIRE_TEMPLE_MAP, {Category::cFireTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_COMPASS_CHEST] = ItemLocation::Chest (0x04, 0x07, "Fire Temple Compass Chest", FIRE_TEMPLE_COMPASS_CHEST, FIRE_TEMPLE_COMPASS, {Category::cFireTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_HIGHEST_GORON_CHEST] = ItemLocation::Chest (0x04, 0x09, "Fire Temple Highest Goron Chest", FIRE_TEMPLE_HIGHEST_GORON_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MEGATON_HAMMER_CHEST] = ItemLocation::Chest (0x04, 0x05, "Fire Temple Megaton Hammer Chest", FIRE_TEMPLE_MEGATON_HAMMER_CHEST, MEGATON_HAMMER, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + //Fire Temple MQ + locationTable[FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST] = ItemLocation::Chest (0x04, 0x07, "Fire Temple MQ Near Boss Chest", FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST] = ItemLocation::Chest (0x04, 0x00, "Fire Temple MQ Megaton Hammer Chest", FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, MEGATON_HAMMER, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x04, 0x0B, "Fire Temple MQ Compass Chest", FIRE_TEMPLE_MQ_COMPASS_CHEST, FIRE_TEMPLE_COMPASS, {Category::cFireTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST] = ItemLocation::Chest (0x04, 0x03, "Fire Temple MQ Lizalfos Maze Lower Chest", FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, BOMBS_10, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST] = ItemLocation::Chest (0x04, 0x06, "Fire Temple MQ Lizalfos Maze Upper Chest", FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, BOMBS_10, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_CHEST_ON_FIRE] = ItemLocation::Chest (0x04, 0x05, "Fire Temple MQ Chest on Fire", FIRE_TEMPLE_MQ_CHEST_ON_FIRE, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST] = ItemLocation::Chest (0x04, 0x02, "Fire Temple MQ Map Room Side Chest", FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, HYLIAN_SHIELD, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_MAP_CHEST] = ItemLocation::Chest (0x04, 0x0C, "Fire Temple MQ Map Chest", FIRE_TEMPLE_MQ_MAP_CHEST, FIRE_TEMPLE_MAP, {Category::cFireTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_BOSS_KEY_CHEST] = ItemLocation::Chest (0x04, 0x04, "Fire Temple MQ Boss Key Chest", FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, FIRE_TEMPLE_BOSS_KEY, {Category::cFireTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST] = ItemLocation::Chest (0x04, 0x01, "Fire Temple MQ Big Lava Room Blocked Door Chest", FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST] = ItemLocation::Chest (0x04, 0x08, "Fire Temple MQ Lizalfos Maze Side Room Chest", FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_FREESTANDING_KEY] = ItemLocation::Collectable(0x04, 0x1C, "Fire Temple MQ Freestanding Key", FIRE_TEMPLE_MQ_FREESTANDING_KEY, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + + //Water Temple Vanilla + locationTable[WATER_TEMPLE_MAP_CHEST] = ItemLocation::Chest (0x05, 0x02, "Water Temple Map Chest", WATER_TEMPLE_MAP_CHEST, WATER_TEMPLE_MAP, {Category::cWaterTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_COMPASS_CHEST] = ItemLocation::Chest (0x05, 0x09, "Water Temple Compass Chest", WATER_TEMPLE_COMPASS_CHEST, WATER_TEMPLE_COMPASS, {Category::cWaterTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_TORCHES_CHEST] = ItemLocation::Chest (0x05, 0x01, "Water Temple Torches Chest", WATER_TEMPLE_TORCHES_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_DRAGON_CHEST] = ItemLocation::Chest (0x05, 0x0A, "Water Temple Dragon Chest", WATER_TEMPLE_DRAGON_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST] = ItemLocation::Chest (0x05, 0x08, "Water Temple Central Bow Target Chest", WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_CENTRAL_PILLAR_CHEST] = ItemLocation::Chest (0x05, 0x06, "Water Temple Central Pillar Chest", WATER_TEMPLE_CENTRAL_PILLAR_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_CRACKED_WALL_CHEST] = ItemLocation::Chest (0x05, 0x00, "Water Temple Cracked Wall Chest", WATER_TEMPLE_CRACKED_WALL_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_BOSS_KEY_CHEST] = ItemLocation::Chest (0x05, 0x05, "Water Temple Boss Key Chest", WATER_TEMPLE_BOSS_KEY_CHEST, WATER_TEMPLE_BOSS_KEY, {Category::cWaterTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_LONGSHOT_CHEST] = ItemLocation::Chest (0x05, 0x07, "Water Temple Longshot Chest", WATER_TEMPLE_LONGSHOT_CHEST, PROGRESSIVE_HOOKSHOT, {Category::cWaterTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_RIVER_CHEST] = ItemLocation::Chest (0x05, 0x03, "Water Temple River Chest", WATER_TEMPLE_RIVER_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + //Water Temple MQ + locationTable[WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST] = ItemLocation::Chest (0x05, 0x06, "Water Temple MQ Central Pillar Chest", WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_BOSS_KEY_CHEST] = ItemLocation::Chest (0x05, 0x05, "Water Temple MQ Boss Key Chest", WATER_TEMPLE_MQ_BOSS_KEY_CHEST, WATER_TEMPLE_BOSS_KEY, {Category::cWaterTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_LONGSHOT_CHEST] = ItemLocation::Chest (0x05, 0x00, "Water Temple MQ Longshot Chest", WATER_TEMPLE_MQ_LONGSHOT_CHEST, PROGRESSIVE_HOOKSHOT, {Category::cWaterTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x05, 0x01, "Water Temple MQ Compass Chest", WATER_TEMPLE_MQ_COMPASS_CHEST, WATER_TEMPLE_COMPASS, {Category::cWaterTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_MAP_CHEST] = ItemLocation::Chest (0x05, 0x02, "Water Temple MQ Map Chest", WATER_TEMPLE_MQ_MAP_CHEST, WATER_TEMPLE_MAP, {Category::cWaterTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_FREESTANDING_KEY] = ItemLocation::Collectable(0x05, 0x01, "Water Temple MQ Freestanding Key", WATER_TEMPLE_MQ_FREESTANDING_KEY, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + + //Spirit Temple Shared + locationTable[SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST] = ItemLocation::Chest (0x5C, 0x0B, "Spirit Temple Silver Gauntlets Chest", SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, PROGRESSIVE_STRENGTH, {Category::cSpiritTemple, Category::cDesertColossus}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST] = ItemLocation::Chest (0x5C, 0x09, "Spirit Temple Mirror Shield Chest", SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, MIRROR_SHIELD, {Category::cSpiritTemple, Category::cDesertColossus}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + //Spirit Temple Vanilla + locationTable[SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST] = ItemLocation::Chest (0x06, 0x08, "Spirit Temple Child Bridge Chest", SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, DEKU_SHIELD, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST] = ItemLocation::Chest (0x06, 0x00, "Spirit Temple Child Early Torches Chest", SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_COMPASS_CHEST] = ItemLocation::Chest (0x06, 0x04, "Spirit Temple Compass Chest", SPIRIT_TEMPLE_COMPASS_CHEST, SPIRIT_TEMPLE_COMPASS, {Category::cSpiritTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST] = ItemLocation::Chest (0x06, 0x07, "Spirit Temple Early Adult Right Chest", SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST] = ItemLocation::Chest (0x06, 0x0D, "Spirit Temple First Mirror Left Chest", SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, ICE_TRAP, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST] = ItemLocation::Chest (0x06, 0x0E, "Spirit Temple First Mirror Right Chest", SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MAP_CHEST] = ItemLocation::Chest (0x06, 0x03, "Spirit Temple Map Chest", SPIRIT_TEMPLE_MAP_CHEST, SPIRIT_TEMPLE_MAP, {Category::cSpiritTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST] = ItemLocation::Chest (0x06, 0x06, "Spirit Temple Child Climb North Chest", SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, BOMBCHU_10, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST] = ItemLocation::Chest (0x06, 0x0C, "Spirit Temple Child Climb East Chest", SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, DEKU_SHIELD, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST] = ItemLocation::Chest (0x06, 0x01, "Spirit Temple Sun Block Room Chest", SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST] = ItemLocation::Chest (0x06, 0x02, "Spirit Temple Statue Room Hand Chest", SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST] = ItemLocation::Chest (0x06, 0x0F, "Spirit Temple Statue Room Northeast Chest", SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, BLUE_RUPEE, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST] = ItemLocation::Chest (0x06, 0x05, "Spirit Temple Near Four Armos Chest", SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST] = ItemLocation::Chest (0x06, 0x14, "Spirit Temple Hallway Right Invisible Chest", SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST] = ItemLocation::Chest (0x06, 0x15, "Spirit Temple Hallway Left Invisible Chest", SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_BOSS_KEY_CHEST] = ItemLocation::Chest (0x06, 0x0A, "Spirit Temple Boss Key Chest", SPIRIT_TEMPLE_BOSS_KEY_CHEST, SPIRIT_TEMPLE_BOSS_KEY, {Category::cSpiritTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_TOPMOST_CHEST] = ItemLocation::Chest (0x06, 0x12, "Spirit Temple Topmost Chest", SPIRIT_TEMPLE_TOPMOST_CHEST, BOMBS_20, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + //Spirit Temple MQ + locationTable[SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST] = ItemLocation::Chest (0x06, 0x1A, "Spirit Temple MQ Entrance Front Left Chest", SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, BOMBCHU_10, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST] = ItemLocation::Chest (0x06, 0x1F, "Spirit Temple MQ Entrance Back Right Chest", SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, BOMBCHU_10, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST] = ItemLocation::Chest (0x06, 0x1B, "Spirit Temple MQ Entrance Front Right Chest", SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST] = ItemLocation::Chest (0x06, 0x1E, "Spirit Temple MQ Entrance Back Left Chest", SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST] = ItemLocation::Chest (0x06, 0x1D, "Spirit Temple MQ Child Hammer Switch Chest", SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_MAP_CHEST] = ItemLocation::Chest (0x06, 0x00, "Spirit Temple MQ Map Chest", SPIRIT_TEMPLE_MQ_MAP_CHEST, SPIRIT_TEMPLE_MAP, {Category::cSpiritTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST] = ItemLocation::Chest (0x06, 0x08, "Spirit Temple MQ Map Room Enemy Chest", SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST] = ItemLocation::Chest (0x06, 0x06, "Spirit Temple MQ Child Climb North Chest", SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, BOMBCHU_10, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST] = ItemLocation::Chest (0x06, 0x0C, "Spirit Temple MQ Child Climb South Chest", SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x06, 0x03, "Spirit Temple MQ Compass Chest", SPIRIT_TEMPLE_MQ_COMPASS_CHEST, SPIRIT_TEMPLE_COMPASS, {Category::cSpiritTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST] = ItemLocation::Chest (0x06, 0x0F, "Spirit Temple MQ Statue Room Lullaby Chest", SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, BLUE_RUPEE, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST] = ItemLocation::Chest (0x06, 0x02, "Spirit Temple MQ Statue Room Invisible Chest", SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST] = ItemLocation::Chest (0x06, 0x1C, "Spirit Temple MQ Silver Block Hallway Chest", SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST] = ItemLocation::Chest (0x06, 0x01, "Spirit Temple MQ Sun Block Room Chest", SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST] = ItemLocation::Chest (0x06, 0x07, "Spirit Temple MQ Symphony Room Chest", SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, PURPLE_RUPEE, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST] = ItemLocation::Chest (0x06, 0x04, "Spirit Temple MQ Leever Room Chest", SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, PURPLE_RUPEE, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST] = ItemLocation::Chest (0x06, 0x19, "Spirit Temple MQ Beamos Room Chest", SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST] = ItemLocation::Chest (0x06, 0x18, "Spirit Temple MQ Chest Switch Chest", SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, ICE_TRAP, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST] = ItemLocation::Chest (0x06, 0x05, "Spirit Temple MQ Boss Key Chest", SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, SPIRIT_TEMPLE_BOSS_KEY, {Category::cSpiritTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST] = ItemLocation::Chest (0x06, 0x12, "Spirit Temple MQ Mirror Puzzle Invisible Chest", SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + + //Shadow Temple Vanilla + locationTable[SHADOW_TEMPLE_MAP_CHEST] = ItemLocation::Chest (0x07, 0x01, "Shadow Temple Map Chest", SHADOW_TEMPLE_MAP_CHEST, SHADOW_TEMPLE_MAP, {Category::cShadowTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_HOVER_BOOTS_CHEST] = ItemLocation::Chest (0x07, 0x07, "Shadow Temple Hover Boots Chest", SHADOW_TEMPLE_HOVER_BOOTS_CHEST, HOVER_BOOTS, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_COMPASS_CHEST] = ItemLocation::Chest (0x07, 0x03, "Shadow Temple Compass Chest", SHADOW_TEMPLE_COMPASS_CHEST, SHADOW_TEMPLE_COMPASS, {Category::cShadowTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST] = ItemLocation::Chest (0x07, 0x02, "Shadow Temple Early Silver Rupee Chest", SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST] = ItemLocation::Chest (0x07, 0x0C, "Shadow Temple Invisible Blades Visible Chest", SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST] = ItemLocation::Chest (0x07, 0x16, "Shadow Temple Invisible Blades Invisible Chest", SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, ARROWS_30, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST] = ItemLocation::Chest (0x07, 0x05, "Shadow Temple Falling Spikes Lower Chest", SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, ARROWS_10, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST] = ItemLocation::Chest (0x07, 0x06, "Shadow Temple Falling Spikes Upper Chest", SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST] = ItemLocation::Chest (0x07, 0x04, "Shadow Temple Falling Spikes Switch Chest", SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST] = ItemLocation::Chest (0x07, 0x09, "Shadow Temple Invisible Spikes Chest", SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_WIND_HINT_CHEST] = ItemLocation::Chest (0x07, 0x15, "Shadow Temple Wind Hint Chest", SHADOW_TEMPLE_WIND_HINT_CHEST, ARROWS_10, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST] = ItemLocation::Chest (0x07, 0x08, "Shadow Temple After Wind Enemy Chest", SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST] = ItemLocation::Chest (0x07, 0x14, "Shadow Temple After Wind Hidden Chest", SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST] = ItemLocation::Chest (0x07, 0x0A, "Shadow Temple Spike Walls Left Chest", SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_BOSS_KEY_CHEST] = ItemLocation::Chest (0x07, 0x0B, "Shadow Temple Boss Key Chest", SHADOW_TEMPLE_BOSS_KEY_CHEST, SHADOW_TEMPLE_BOSS_KEY, {Category::cShadowTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST] = ItemLocation::Chest (0x07, 0x0D, "Shadow Temple Invisible Floormaster Chest", SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_FREESTANDING_KEY] = ItemLocation::Collectable(0x07, 0x01, "Shadow Temple Freestanding Key", SHADOW_TEMPLE_FREESTANDING_KEY, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + //Shadow Temple MQ + locationTable[SHADOW_TEMPLE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x07, 0x01, "Shadow Temple MQ Compass Chest", SHADOW_TEMPLE_MQ_COMPASS_CHEST, SHADOW_TEMPLE_COMPASS, {Category::cShadowTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST] = ItemLocation::Chest (0x07, 0x07, "Shadow Temple MQ Hover Boots Chest", SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, HOVER_BOOTS, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST] = ItemLocation::Chest (0x07, 0x03, "Shadow Temple MQ Early Gibdos Chest", SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_MAP_CHEST] = ItemLocation::Chest (0x07, 0x02, "Shadow Temple MQ Map Chest", SHADOW_TEMPLE_MQ_MAP_CHEST, SHADOW_TEMPLE_MAP, {Category::cShadowTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST] = ItemLocation::Chest (0x07, 0x0F, "Shadow Temple MQ Beamos Silver Rupees Chest", SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, ARROWS_5, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST] = ItemLocation::Chest (0x07, 0x04, "Shadow Temple MQ Falling Spikes Switch Chest", SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST] = ItemLocation::Chest (0x07, 0x05, "Shadow Temple MQ Falling Spikes Lower Chest", SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, ARROWS_10, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST] = ItemLocation::Chest (0x07, 0x06, "Shadow Temple MQ Falling Spikes Upper Chest", SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, ARROWS_5, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST] = ItemLocation::Chest (0x07, 0x09, "Shadow Temple MQ Invisible Spikes Chest", SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST] = ItemLocation::Chest (0x07, 0x0B, "Shadow Temple MQ Boss Key Chest", SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, SHADOW_TEMPLE_BOSS_KEY, {Category::cShadowTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST] = ItemLocation::Chest (0x07, 0x0A, "Shadow Temple MQ Spike Walls Left Chest", SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST] = ItemLocation::Chest (0x07, 0x10, "Shadow Temple MQ Stalfos Room Chest", SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, RED_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST] = ItemLocation::Chest (0x07, 0x16, "Shadow Temple MQ Invisible Blades Invisible Chest", SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST] = ItemLocation::Chest (0x07, 0x0C, "Shadow Temple MQ Invisible Blades Visible Chest", SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST] = ItemLocation::Chest (0x07, 0x0D, "Shadow Temple MQ Bomb Flower Chest", SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, ARROWS_10, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_WIND_HINT_CHEST] = ItemLocation::Chest (0x07, 0x15, "Shadow Temple MQ Wind Hint Chest", SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST] = ItemLocation::Chest (0x07, 0x14, "Shadow Temple MQ After Wind Hidden Chest", SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, ARROWS_5, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST] = ItemLocation::Chest (0x07, 0x08, "Shadow Temple MQ After Wind Enemy Chest", SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST] = ItemLocation::Chest (0x07, 0x0E, "Shadow Temple MQ Near Ship Invisible Chest", SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_FREESTANDING_KEY] = ItemLocation::Collectable(0x07, 0x06, "Shadow Temple MQ Freestanding Key", SHADOW_TEMPLE_MQ_FREESTANDING_KEY, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + + //Bottom of the Well Vanilla + locationTable[BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST] = ItemLocation::Chest (0x08, 0x08, "Bottom of the Well Front Left Fake Wall Chest", BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, BOTTOM_OF_THE_WELL_SMALL_KEY, {Category::cBottomOfTheWell, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST] = ItemLocation::Chest (0x08, 0x02, "Bottom of the Well Front Center Bombable Chest", BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, BOMBCHU_10, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST] = ItemLocation::Chest (0x08, 0x05, "Bottom of the Well Right Bottom Fake Wall Chest", BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, BOTTOM_OF_THE_WELL_SMALL_KEY, {Category::cBottomOfTheWell, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_COMPASS_CHEST] = ItemLocation::Chest (0x08, 0x01, "Bottom of the Well Compass Chest", BOTTOM_OF_THE_WELL_COMPASS_CHEST, BOTTOM_OF_THE_WELL_COMPASS, {Category::cBottomOfTheWell, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST] = ItemLocation::Chest (0x08, 0x0E, "Bottom of the Well Center Skulltula Chest", BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, DEKU_NUTS_5, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST] = ItemLocation::Chest (0x08, 0x04, "Bottom of the Well Back Left Bombable Chest", BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, DEKU_NUTS_10, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST] = ItemLocation::Chest (0x08, 0x03, "Bottom of the Well Lens of Truth Chest", BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, LENS_OF_TRUTH, {Category::cBottomOfTheWell, Category::cSongDungeonReward}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_INVISIBLE_CHEST] = ItemLocation::Chest (0x08, 0x14, "Bottom of the Well Invisible Chest", BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, HUGE_RUPEE, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST] = ItemLocation::Chest (0x08, 0x10, "Bottom of the Well Underwater Front Chest", BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, BOMBS_10, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST] = ItemLocation::Chest (0x08, 0x09, "Bottom of the Well Underwater Left Chest", BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, RECOVERY_HEART, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MAP_CHEST] = ItemLocation::Chest (0x08, 0x07, "Bottom of the Well Map Chest", BOTTOM_OF_THE_WELL_MAP_CHEST, BOTTOM_OF_THE_WELL_MAP, {Category::cBottomOfTheWell, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST] = ItemLocation::Chest (0x08, 0x0A, "Bottom of the Well Fire Keese Chest", BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, DEKU_SHIELD, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST] = ItemLocation::Chest (0x08, 0x0C, "Bottom of the Well Like Like Chest", BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, HYLIAN_SHIELD, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_FREESTANDING_KEY] = ItemLocation::Collectable(0x08, 0x01, "Bottom of the Well Freestanding Key", BOTTOM_OF_THE_WELL_FREESTANDING_KEY, BOTTOM_OF_THE_WELL_SMALL_KEY, {Category::cBottomOfTheWell, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + //Bottom of the Well MQBottomOfTheWell] + locationTable[BOTTOM_OF_THE_WELL_MQ_MAP_CHEST] = ItemLocation::Chest (0x08, 0x03, "Bottom of the Well MQ Map Chest", BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, BOTTOM_OF_THE_WELL_MAP, {Category::cBottomOfTheWell, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST] = ItemLocation::Chest (0x08, 0x01, "Bottom of the Well MQ Lens of Truth Chest", BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, LENS_OF_TRUTH, {Category::cBottomOfTheWell, Category::cSongDungeonReward}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x08, 0x02, "Bottom of the Well MQ Compass Chest", BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, BOTTOM_OF_THE_WELL_COMPASS, {Category::cBottomOfTheWell, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY] = ItemLocation::Collectable(0x08, 0x02, "Bottom of the Well MQ Dead Hand Freestanding Key", BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, BOTTOM_OF_THE_WELL_SMALL_KEY, {Category::cBottomOfTheWell, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY] = ItemLocation::Collectable(0x08, 0x01, "Bottom of the Well MQ East Inner Room Freestanding Key",BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, BOTTOM_OF_THE_WELL_SMALL_KEY, {Category::cBottomOfTheWell, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + + //Ice Cavern Vanilla + locationTable[ICE_CAVERN_MAP_CHEST] = ItemLocation::Chest (0x09, 0x00, "Ice Cavern Map Chest", ICE_CAVERN_MAP_CHEST, ICE_CAVERN_MAP, {Category::cIceCavern, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_COMPASS_CHEST] = ItemLocation::Chest (0x09, 0x01, "Ice Cavern Compass Chest", ICE_CAVERN_COMPASS_CHEST, ICE_CAVERN_COMPASS, {Category::cIceCavern, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_IRON_BOOTS_CHEST] = ItemLocation::Chest (0x09, 0x02, "Ice Cavern Iron Boots Chest", ICE_CAVERN_IRON_BOOTS_CHEST, IRON_BOOTS, {Category::cIceCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_FREESTANDING_POH] = ItemLocation::Collectable(0x09, 0x01, "Ice Cavern Freestanding PoH", ICE_CAVERN_FREESTANDING_POH, PIECE_OF_HEART, {Category::cIceCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + //Ice Cavern MQIceCavern] + locationTable[ICE_CAVERN_MQ_IRON_BOOTS_CHEST] = ItemLocation::Chest (0x09, 0x02, "Ice Cavern MQ Iron Boots Chest", ICE_CAVERN_MQ_IRON_BOOTS_CHEST, IRON_BOOTS, {Category::cIceCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x09, 0x00, "Ice Cavern MQ Compass Chest", ICE_CAVERN_MQ_COMPASS_CHEST, ICE_CAVERN_COMPASS, {Category::cIceCavern, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_MQ_MAP_CHEST] = ItemLocation::Chest (0x09, 0x01, "Ice Cavern MQ Map Chest", ICE_CAVERN_MQ_MAP_CHEST, ICE_CAVERN_MAP, {Category::cIceCavern, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_MQ_FREESTANDING_POH] = ItemLocation::Collectable(0x09, 0x01, "Ice Cavern MQ Freestanding PoH", ICE_CAVERN_MQ_FREESTANDING_POH, PIECE_OF_HEART, {Category::cIceCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + + //Gerudo Training Ground Vanilla + locationTable[GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST] = ItemLocation::Chest (0x0B, 0x13, "Gerudo Training Grounds Lobby Left Chest", GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST, BLUE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST] = ItemLocation::Chest (0x0B, 0x07, "Gerudo Training Grounds Lobby Right Chest", GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST, ARROWS_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_STALFOS_CHEST] = ItemLocation::Chest (0x0B, 0x00, "Gerudo Training Grounds Stalfos Chest", GERUDO_TRAINING_GROUNDS_STALFOS_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST] = ItemLocation::Chest (0x0B, 0x01, "Gerudo Training Grounds Beamos Chest", GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST] = ItemLocation::Chest (0x0B, 0x0B, "Gerudo Training Grounds Hidden Ceiling Chest", GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST] = ItemLocation::Chest (0x0B, 0x06, "Gerudo Training Grounds Maze Path First Chest", GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST, PURPLE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST] = ItemLocation::Chest (0x0B, 0x0A, "Gerudo Training Grounds Maze Path Second Chest", GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST, RED_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST] = ItemLocation::Chest (0x0B, 0x09, "Gerudo Training Grounds Maze Path Third Chest", GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST, ARROWS_30, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST] = ItemLocation::Chest (0x0B, 0x0C, "Gerudo Training Grounds Maze Path Final Chest", GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST, ICE_ARROWS, {Category::cGerudoTrainingGrounds, Category::cSongDungeonReward}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST] = ItemLocation::Chest (0x0B, 0x05, "Gerudo Training Grounds Maze Right Central Chest", GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST, BOMBCHU_5, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST] = ItemLocation::Chest (0x0B, 0x08, "Gerudo Training Grounds Maze Right Side Chest", GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST, ARROWS_30, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST] = ItemLocation::Chest (0x0B, 0x0D, "Gerudo Training Grounds Underwater Silver Rupee Chest", GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST] = ItemLocation::Chest (0x0B, 0x12, "Gerudo Training Grounds Hammer Room Clear Chest", GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST, ARROWS_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST] = ItemLocation::Chest (0x0B, 0x10, "Gerudo Training Grounds Hammer Room Switch Chest", GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST] = ItemLocation::Chest (0x0B, 0x03, "Gerudo Training Grounds Eye Statue Chest", GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST] = ItemLocation::Chest (0x0B, 0x04, "Gerudo Training Grounds Near Scarecrow Chest", GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST] = ItemLocation::Chest (0x0B, 0x11, "Gerudo Training Grounds Before Heavy Block Chest", GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST, ARROWS_30, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST] = ItemLocation::Chest (0x0B, 0x0F, "Gerudo Training Grounds Heavy Block First Chest", GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST, HUGE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST] = ItemLocation::Chest (0x0B, 0x0E, "Gerudo Training Grounds Heavy Block Second Chest", GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST, BLUE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST] = ItemLocation::Chest (0x0B, 0x14, "Gerudo Training Grounds Heavy Block Third Chest", GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST] = ItemLocation::Chest (0x0B, 0x02, "Gerudo Training Grounds Heavy Block Fourth Chest", GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST, ICE_TRAP, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY] = ItemLocation::Collectable(0x0B, 0x01, "Gerudo Training Grounds Freestanding Key", GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + //Gerudo Training Grounds MQ + locationTable[GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST] = ItemLocation::Chest (0x0B, 0x07, "Gerudo Training Grounds MQ Lobby Right Chest", GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST, BOMBCHU_5, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST] = ItemLocation::Chest (0x0B, 0x13, "Gerudo Training Grounds MQ Lobby Left Chest", GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST, ARROWS_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST] = ItemLocation::Chest (0x0B, 0x00, "Gerudo Training Grounds MQ First Iron Knuckle Chest", GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST, BLUE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST] = ItemLocation::Chest (0x0B, 0x11, "Gerudo Training Grounds MQ Before Heavy Block Chest", GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST, ARROWS_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST] = ItemLocation::Chest (0x0B, 0x03, "Gerudo Training Grounds MQ Eye Statue Chest", GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST, BOMBCHU_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST] = ItemLocation::Chest (0x0B, 0x0E, "Gerudo Training Grounds MQ Flame Circle Chest", GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST] = ItemLocation::Chest (0x0B, 0x12, "Gerudo Training Grounds MQ Second Iron Knuckle Chest", GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST, ARROWS_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST] = ItemLocation::Chest (0x0B, 0x01, "Gerudo Training Grounds MQ Dinolfos Chest", GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST] = ItemLocation::Chest (0x0B, 0x04, "Gerudo Training Grounds MQ Ice Arrows Chest", GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST, ICE_ARROWS, {Category::cGerudoTrainingGrounds, Category::cSongDungeonReward}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST] = ItemLocation::Chest (0x0B, 0x05, "Gerudo Training Grounds MQ Maze Right Central Chest", GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST, BLUE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST] = ItemLocation::Chest (0x0B, 0x06, "Gerudo Training Grounds MQ Maze Path First Chest", GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST, GREEN_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST] = ItemLocation::Chest (0x0B, 0x08, "Gerudo Training Grounds MQ Maze Right Side Chest", GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST, TREASURE_GAME_GREEN_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST] = ItemLocation::Chest (0x0B, 0x09, "Gerudo Training Grounds MQ Maze Path Third Chest", GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST, TREASURE_GAME_GREEN_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST] = ItemLocation::Chest (0x0B, 0x0A, "Gerudo Training Grounds MQ Maze Path Second Chest", GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST, RED_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST] = ItemLocation::Chest (0x0B, 0x0B, "Gerudo Training Grounds MQ Hidden Ceiling Chest", GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST, PURPLE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST] = ItemLocation::Chest (0x0B, 0x0D, "Gerudo Training Grounds MQ Underwater Silver Rupee Chest",GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST, TREASURE_GAME_GREEN_RUPEE, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST] = ItemLocation::Chest (0x0B, 0x02, "Gerudo Training Grounds MQ Heavy Block Chest", GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST, PURPLE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + + //Ganons Castle Shared + locationTable[GANONS_TOWER_BOSS_KEY_CHEST] = ItemLocation::Chest (0x0A, 0x0B, "Ganon's Tower Boss Key Chest", GANONS_TOWER_BOSS_KEY_CHEST, GANONS_CASTLE_BOSS_KEY, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + //Ganons Castle Vanilla + locationTable[GANONS_CASTLE_FOREST_TRIAL_CHEST] = ItemLocation::Chest (0x0D, 0x09, "Ganon's Castle Forest Trial Chest", GANONS_CASTLE_FOREST_TRIAL_CHEST, BLUE_RUPEE, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x07, "Ganon's Castle Water Trial Left Chest", GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, ICE_TRAP, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST] = ItemLocation::Chest (0x0D, 0x06, "Ganon's Castle Water Trial Right Chest", GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, RECOVERY_HEART, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST] = ItemLocation::Chest (0x0D, 0x08, "Ganon's Castle Shadow Trial Front Chest", GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, BLUE_RUPEE, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST] = ItemLocation::Chest (0x0D, 0x05, "Ganon's Castle Shadow Trial Golden Gauntlets Chest", GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, PROGRESSIVE_STRENGTH, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST] = ItemLocation::Chest (0x0D, 0x12, "Ganon's Castle Spirit Trial Crystal Switch Chest", GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, BOMBCHU_20, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST] = ItemLocation::Chest (0x0D, 0x14, "Ganon's Castle Spirit Trial Invisible Chest", GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, ARROWS_10, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x0C, "Ganon's Castle Light Trial First Left Chest", GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, BLUE_RUPEE, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x0B, "Ganon's Castle Light Trial Second Left Chest", GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, ICE_TRAP, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x0D, "Ganon's Castle Light Trial Third Left Chest", GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, RECOVERY_HEART, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST] = ItemLocation::Chest (0x0D, 0x0E, "Ganon's Castle Light Trial First Right Chest", GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, ICE_TRAP, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST] = ItemLocation::Chest (0x0D, 0x0A, "Ganon's Castle Light Trial Second Right Chest", GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, ARROWS_30, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST] = ItemLocation::Chest (0x0D, 0x0F, "Ganon's Castle Light Trial Third Right Chest", GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, ICE_TRAP, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST] = ItemLocation::Chest (0x0D, 0x10, "Ganon's Castle Light Trial Invisible Enemies Chest", GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, GANONS_CASTLE_SMALL_KEY, {Category::cGanonsCastle, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST] = ItemLocation::Chest (0x0D, 0x11, "Ganon's Castle Light Trial Lullaby Chest", GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, GANONS_CASTLE_SMALL_KEY, {Category::cGanonsCastle, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT] = ItemLocation::Base (0x0D, 0x37, "Ganon's Castle Deku Scrub Center-Left", GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, BUY_BOMBS_535, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x06), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT] = ItemLocation::Base (0x0D, 0x33, "Ganon's Castle Deku Scrub Center-Right", GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, BUY_ARROWS_30, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x04), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_DEKU_SCRUB_RIGHT] = ItemLocation::Base (0x0D, 0x39, "Ganon's Castle Deku Scrub Right", GANONS_CASTLE_DEKU_SCRUB_RIGHT, BUY_RED_POTION_30, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x08), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_DEKU_SCRUB_LEFT] = ItemLocation::Base (0x0D, 0x3A, "Ganon's Castle Deku Scrub Left", GANONS_CASTLE_DEKU_SCRUB_LEFT, BUY_GREEN_POTION, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x09), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + //Ganons Castle MQ + locationTable[GANONS_CASTLE_MQ_WATER_TRIAL_CHEST] = ItemLocation::Chest (0x0D, 0x01, "Ganon's Castle MQ Water Trial Chest", GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, RED_RUPEE, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST] = ItemLocation::Chest (0x0D, 0x02, "Ganon's Castle MQ Forest Trial Eye Switch Chest", GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, ARROWS_10, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST] = ItemLocation::Chest (0x0D, 0x03, "Ganon's Castle MQ Forest Trial Frozen Eye Switch Chest",GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, BOMBS_5, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST] = ItemLocation::Chest (0x0D, 0x04, "Ganon's Castle MQ Light Trial Lullaby Chest", GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, RECOVERY_HEART, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST] = ItemLocation::Chest (0x0D, 0x00, "Ganon's Castle MQ Shadow Trial Bomb Flower Chest", GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, ARROWS_10, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST] = ItemLocation::Chest (0x0D, 0x05, "Ganon's Castle MQ Shadow Trial Eye Switch Chest", GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, GANONS_CASTLE_SMALL_KEY, {Category::cGanonsCastle, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST] = ItemLocation::Chest (0x0D, 0x06, "Ganon's Castle MQ Spirit Trial Golden Gauntlets Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, PROGRESSIVE_STRENGTH, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST] = ItemLocation::Chest (0x0D, 0x07, "Ganon's Castle MQ Spirit Trial Sun Back Right Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, RECOVERY_HEART, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x08, "Ganon's Castle MQ Spirit Trial Sun Back Left Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, GANONS_CASTLE_SMALL_KEY, {Category::cGanonsCastle, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x09, "Ganon's Castle MQ Spirit Trial Sun Front Left Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, RECOVERY_HEART, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST] = ItemLocation::Chest (0x0D, 0x0A, "Ganon's Castle MQ Spirit Trial First Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, BOMBCHU_10, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST] = ItemLocation::Chest (0x0D, 0x14, "Ganon's Castle MQ Spirit Trial Invisible Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, ARROWS_10, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY] = ItemLocation::Collectable(0x0D, 0x01, "Ganon's Castle MQ Forest Trial Freestanding Key", GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, GANONS_CASTLE_SMALL_KEY, {Category::cGanonsCastle, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT] = ItemLocation::Base (0x0D, 0x30, "Ganon's Castle MQ Deku Scrub Right", GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, BUY_DEKU_NUT_5, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x01), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT] = ItemLocation::Base (0x0D, 0x37, "Ganon's Castle MQ Deku Scrub Center-Left", GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, BUY_BOMBS_535, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x06), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER] = ItemLocation::Base (0x0D, 0x33, "Ganon's Castle MQ Deku Scrub Center", GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, BUY_ARROWS_30, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x04), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT] = ItemLocation::Base (0x0D, 0x39, "Ganon's Castle MQ Deku Scrub Center-Right", GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, BUY_RED_POTION_30, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x08), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT] = ItemLocation::Base (0x0D, 0x3A, "Ganon's Castle MQ Deku Scrub Left", GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, BUY_GREEN_POTION, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x09), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + + /*------------------------------- + --- GOLD SKULLTULA TOKENS --- + -------------------------------*/ + + //Dungeons + locationTable[DEKU_TREE_GS_BASEMENT_BACK_ROOM] = ItemLocation::GSToken(0x00, 0x01, "Deku Tree GS Basement Back Room", DEKU_TREE_GS_BASEMENT_BACK_ROOM, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_GS_BASEMENT_GATE] = ItemLocation::GSToken(0x00, 0x02, "Deku Tree GS Basement Gate", DEKU_TREE_GS_BASEMENT_GATE, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_GS_BASEMENT_VINES] = ItemLocation::GSToken(0x00, 0x04, "Deku Tree GS Basement Vines", DEKU_TREE_GS_BASEMENT_VINES, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_GS_COMPASS_ROOM] = ItemLocation::GSToken(0x00, 0x08, "Deku Tree GS Compass Room", DEKU_TREE_GS_COMPASS_ROOM, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + + locationTable[DEKU_TREE_MQ_GS_LOBBY] = ItemLocation::GSToken(0x00, 0x02, "Deku Tree MQ GS Lobby", DEKU_TREE_MQ_GS_LOBBY, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_GS_COMPASS_ROOM] = ItemLocation::GSToken(0x00, 0x08, "Deku Tree MQ GS Compass Room", DEKU_TREE_MQ_GS_COMPASS_ROOM, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM] = ItemLocation::GSToken(0x00, 0x04, "Deku Tree MQ GS Basement Graves Room", DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM] = ItemLocation::GSToken(0x00, 0x01, "Deku Tree MQ GS Basement Back Room", DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + + locationTable[DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS] = ItemLocation::GSToken(0x01, 0x01, "Dodongos Cavern GS Vines Above Stairs", DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_GS_SCARECROW] = ItemLocation::GSToken(0x01, 0x02, "Dodongos Cavern GS Scarecrow", DODONGOS_CAVERN_GS_SCARECROW, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS] = ItemLocation::GSToken(0x01, 0x04, "Dodongos Cavern GS Alcove Above Stairs", DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_GS_BACK_ROOM] = ItemLocation::GSToken(0x01, 0x08, "Dodongos Cavern GS Back Room", DODONGOS_CAVERN_GS_BACK_ROOM, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS] = ItemLocation::GSToken(0x01, 0x10, "Dodongos Cavern GS Side Room Near Lower Lizalfos", DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + + locationTable[DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM] = ItemLocation::GSToken(0x01, 0x02, "Dodongos Cavern MQ GS Scrub Room", DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM] = ItemLocation::GSToken(0x01, 0x08, "Dodongos Cavern MQ GS Song of Time Block Room", DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM] = ItemLocation::GSToken(0x01, 0x04, "Dodongos Cavern MQ GS Lizalfos Room", DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM] = ItemLocation::GSToken(0x01, 0x10, "Dodongos Cavern MQ GS Larvae Room", DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_GS_BACK_AREA] = ItemLocation::GSToken(0x01, 0x01, "Dodongos Cavern MQ GS Back Room", DODONGOS_CAVERN_MQ_GS_BACK_AREA, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + + locationTable[JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER] = ItemLocation::GSToken(0x02, 0x01, "Jabu Jabus Belly GS Lobby Basement Lower", JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER] = ItemLocation::GSToken(0x02, 0x02, "Jabu Jabus Belly GS Lobby Basement Upper", JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_GS_NEAR_BOSS] = ItemLocation::GSToken(0x02, 0x04, "Jabu Jabus Belly GS Near Boss", JABU_JABUS_BELLY_GS_NEAR_BOSS, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM] = ItemLocation::GSToken(0x02, 0x08, "Jabu Jabus Belly GS Water Switch Room", JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + + locationTable[JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM] = ItemLocation::GSToken(0x02, 0x04, "Jabu Jabus Belly MQ GS Tail Parasan Room", JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM] = ItemLocation::GSToken(0x02, 0x08, "Jabu Jabus Belly MQ GS Invisible Enemies Room", JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM] = ItemLocation::GSToken(0x02, 0x01, "Jabu Jabus Belly MQ GS Boomerang Chest Room", JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS] = ItemLocation::GSToken(0x02, 0x02, "Jabu Jabus Belly MQ GS Near Boss", JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + + locationTable[FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD] = ItemLocation::GSToken(0x03, 0x01, "Forest Temple GS Raised Island Courtyard", FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_GS_FIRST_ROOM] = ItemLocation::GSToken(0x03, 0x02, "Forest Temple GS First Room", FOREST_TEMPLE_GS_FIRST_ROOM, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD] = ItemLocation::GSToken(0x03, 0x04, "Forest Temple GS Level Island Courtyard", FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_GS_LOBBY] = ItemLocation::GSToken(0x03, 0x08, "Forest Temple GS Lobby", FOREST_TEMPLE_GS_LOBBY, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_GS_BASEMENT] = ItemLocation::GSToken(0x03, 0x10, "Forest Temple GS Basement", FOREST_TEMPLE_GS_BASEMENT, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + + locationTable[FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY] = ItemLocation::GSToken(0x03, 0x02, "Forest Temple MQ GS First Hallway", FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM] = ItemLocation::GSToken(0x03, 0x10, "Forest Temple MQ GS Block Push Room", FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD] = ItemLocation::GSToken(0x03, 0x01, "Forest Temple MQ GS Raised Island Courtyard", FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD] = ItemLocation::GSToken(0x03, 0x04, "Forest Temple MQ GS Level Island Courtyard", FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_GS_WELL] = ItemLocation::GSToken(0x03, 0x08, "Forest Temple MQ GS Well", FOREST_TEMPLE_MQ_GS_WELL, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + + locationTable[FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM] = ItemLocation::GSToken(0x04, 0x01, "Fire Temple GS Song of Time Room", FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_GS_BOSS_KEY_LOOP] = ItemLocation::GSToken(0x04, 0x02, "Fire Temple GS Boss Key Loop", FIRE_TEMPLE_GS_BOSS_KEY_LOOP, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_GS_BOULDER_MAZE] = ItemLocation::GSToken(0x04, 0x04, "Fire Temple GS Boulder Maze", FIRE_TEMPLE_GS_BOULDER_MAZE, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_GS_SCARECROW_TOP] = ItemLocation::GSToken(0x04, 0x08, "Fire Temple GS Scarecrow Top", FIRE_TEMPLE_GS_SCARECROW_TOP, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_GS_SCARECROW_CLIMB] = ItemLocation::GSToken(0x04, 0x10, "Fire Temple GS Scarecrow Climb", FIRE_TEMPLE_GS_SCARECROW_CLIMB, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + + locationTable[FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE] = ItemLocation::GSToken(0x04, 0x02, "Fire Temple MQ GS Above Fire Wall Maze", FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER] = ItemLocation::GSToken(0x04, 0x08, "Fire Temple MQ GS Fire Wall Maze Center", FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR] = ItemLocation::GSToken(0x04, 0x01, "Fire Temple MQ GS Big Lava Room Open Door", FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM] = ItemLocation::GSToken(0x04, 0x10, "Fire Temple MQ GS Fire Wall Maze Side Room", FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE] = ItemLocation::GSToken(0x04, 0x04, "Fire Temple MQ GS Skull on Fire", FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + + locationTable[WATER_TEMPLE_GS_BEHIND_GATE] = ItemLocation::GSToken(0x05, 0x01, "Water Temple GS Behind Gate", WATER_TEMPLE_GS_BEHIND_GATE, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM] = ItemLocation::GSToken(0x05, 0x02, "Water Temple GS Falling Platform Room", WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_GS_CENTRAL_PILLAR] = ItemLocation::GSToken(0x05, 0x04, "Water Temple GS Central Pillar", WATER_TEMPLE_GS_CENTRAL_PILLAR, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST] = ItemLocation::GSToken(0x05, 0x08, "Water Temple GS Near Boss Key Chest", WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_GS_RIVER] = ItemLocation::GSToken(0x05, 0x10, "Water Temple GS River", WATER_TEMPLE_GS_RIVER, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + + locationTable[WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH] = ItemLocation::GSToken(0x05, 0x04, "Water Temple MQ GS Before Upper Water Switch", WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA] = ItemLocation::GSToken(0x05, 0x08, "Water Temple MQ GS Freestanding Key Area", WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY] = ItemLocation::GSToken(0x05, 0x01, "Water Temple MQ GS Lizalfos Hallway", WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_GS_RIVER] = ItemLocation::GSToken(0x05, 0x02, "Water Temple MQ GS River", WATER_TEMPLE_MQ_GS_RIVER, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH] = ItemLocation::GSToken(0x05, 0x10, "Water Temple MQ GS Triple Wall Torch", WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + + locationTable[SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM] = ItemLocation::GSToken(0x06, 0x01, "Spirit Temple GS Hall After Sun Block Room", SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_GS_BOULDER_ROOM] = ItemLocation::GSToken(0x06, 0x02, "Spirit Temple GS Boulder Room", SPIRIT_TEMPLE_GS_BOULDER_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_GS_LOBBY] = ItemLocation::GSToken(0x06, 0x04, "Spirit Temple GS Lobby", SPIRIT_TEMPLE_GS_LOBBY, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM] = ItemLocation::GSToken(0x06, 0x08, "Spirit Temple GS Sun on Floor Room", SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_GS_METAL_FENCE] = ItemLocation::GSToken(0x06, 0x10, "Spirit Temple GS Metal Fence", SPIRIT_TEMPLE_GS_METAL_FENCE, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + + locationTable[SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM] = ItemLocation::GSToken(0x06, 0x08, "Spirit Temple MQ GS Symphony Room", SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM] = ItemLocation::GSToken(0x06, 0x02, "Spirit Temple MQ GS Leever Room", SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST] = ItemLocation::GSToken(0x06, 0x04, "Spirit Temple MQ GS Nine Thrones Room West", SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH] = ItemLocation::GSToken(0x06, 0x10, "Spirit Temple MQ GS Nine Thrones Room North", SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM] = ItemLocation::GSToken(0x06, 0x01, "Spirit Temple MQ GS Sun Block Room", SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + + locationTable[SHADOW_TEMPLE_GS_SINGLE_GIANT_POT] = ItemLocation::GSToken(0x07, 0x01, "Shadow Temple GS Single Giant Pot", SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM] = ItemLocation::GSToken(0x07, 0x02, "Shadow Temple GS Falling Spikes Room", SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT] = ItemLocation::GSToken(0x07, 0x04, "Shadow Temple GS Triple Giant Pot", SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM] = ItemLocation::GSToken(0x07, 0x08, "Shadow Temple GS Like Like Room", SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_GS_NEAR_SHIP] = ItemLocation::GSToken(0x07, 0x10, "Shadow Temple GS Near Ship", SHADOW_TEMPLE_GS_NEAR_SHIP, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + + locationTable[SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM] = ItemLocation::GSToken(0x07, 0x02, "Shadow Temple MQ GS Falling Spikes Room", SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM] = ItemLocation::GSToken(0x07, 0x01, "Shadow Temple MQ GS Wind Hint Room", SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_GS_AFTER_WIND] = ItemLocation::GSToken(0x07, 0x08, "Shadow Temple MQ GS After Wind", SHADOW_TEMPLE_MQ_GS_AFTER_WIND, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_GS_AFTER_SHIP] = ItemLocation::GSToken(0x07, 0x10, "Shadow Temple MQ GS After Ship", SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_GS_NEAR_BOSS] = ItemLocation::GSToken(0x07, 0x04, "Shadow Temple MQ GS Near Boss", SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + + locationTable[BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE] = ItemLocation::GSToken(0x08, 0x01, "Bottom of the Well GS Like Like Cage", BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM] = ItemLocation::GSToken(0x08, 0x02, "Bottom of the Well GS East Inner Room", BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM] = ItemLocation::GSToken(0x08, 0x04, "Bottom of the Well GS West Inner Room", BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + + locationTable[BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT] = ItemLocation::GSToken(0x08, 0x01, "Bottom of the Well MQ GS Basement", BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM] = ItemLocation::GSToken(0x08, 0x04, "Bottom of the Well MQ GS Coffin Room", BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM] = ItemLocation::GSToken(0x08, 0x02, "Bottom of the Well MQ GS West Inner Room", BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + + locationTable[ICE_CAVERN_GS_PUSH_BLOCK_ROOM] = ItemLocation::GSToken(0x09, 0x01, "Ice Cavern GS Push Block Room", ICE_CAVERN_GS_PUSH_BLOCK_ROOM, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM] = ItemLocation::GSToken(0x09, 0x02, "Ice Cavern GS Spinning Scythe Room", ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_GS_HEART_PIECE_ROOM] = ItemLocation::GSToken(0x09, 0x04, "Ice Cavern GS Heart Piece Room", ICE_CAVERN_GS_HEART_PIECE_ROOM, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + + locationTable[ICE_CAVERN_MQ_GS_SCARECROW] = ItemLocation::GSToken(0x09, 0x01, "Ice Cavern MQ GS Scarecrow", ICE_CAVERN_MQ_GS_SCARECROW, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_MQ_GS_ICE_BLOCK] = ItemLocation::GSToken(0x09, 0x04, "Ice Cavern MQ GS Ice Block", ICE_CAVERN_MQ_GS_ICE_BLOCK, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_MQ_GS_RED_ICE] = ItemLocation::GSToken(0x09, 0x02, "Ice Cavern MQ GS Red Ice", ICE_CAVERN_MQ_GS_RED_ICE, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + + //Overworld + locationTable[KF_GS_BEAN_PATCH] = ItemLocation::GSToken(0x0C, 0x01, "KF GS Bean Patch", KF_GS_BEAN_PATCH, {Category::cKokiriForest, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_GS_KNOW_IT_ALL_HOUSE] = ItemLocation::GSToken(0x0C, 0x02, "KF GS Know It All House", KF_GS_KNOW_IT_ALL_HOUSE, {Category::cKokiriForest, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_GS_HOUSE_OF_TWINS] = ItemLocation::GSToken(0x0C, 0x04, "KF GS House of Twins", KF_GS_HOUSE_OF_TWINS, {Category::cKokiriForest, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + + locationTable[LW_GS_BEAN_PATCH_NEAR_BRIDGE] = ItemLocation::GSToken(0x0D, 0x01, "LW GS Bean Patch Near Bridge", LW_GS_BEAN_PATCH_NEAR_BRIDGE, {Category::cLostWoods, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_GS_BEAN_PATCH_NEAR_THEATER] = ItemLocation::GSToken(0x0D, 0x02, "LW GS Bean Patch Near Theater", LW_GS_BEAN_PATCH_NEAR_THEATER, {Category::cLostWoods, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_GS_ABOVE_THEATER] = ItemLocation::GSToken(0x0D, 0x04, "LW GS Above Theater", LW_GS_ABOVE_THEATER, {Category::cLostWoods, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[SFM_GS] = ItemLocation::GSToken(0x0D, 0x08, "SFM GS", SFM_GS, {Category::cSacredForestMeadow, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + + locationTable[HF_GS_COW_GROTTO] = ItemLocation::GSToken(0x0A, 0x01, "HF GS Cow Grotto", HF_GS_COW_GROTTO, {Category::cHyruleField, Category::cSkulltula, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_GS_NEAR_KAK_GROTTO] = ItemLocation::GSToken(0x0A, 0x02, "HF GS Near Kak Grotto", HF_GS_NEAR_KAK_GROTTO, {Category::cHyruleField, Category::cSkulltula, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + + locationTable[LH_GS_BEAN_PATCH] = ItemLocation::GSToken(0x12, 0x01, "LH GS Bean Patch", LH_GS_BEAN_PATCH, {Category::cLakeHylia, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_GS_SMALL_ISLAND] = ItemLocation::GSToken(0x12, 0x02, "LH GS Small Island", LH_GS_SMALL_ISLAND, {Category::cLakeHylia, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_GS_LAB_WALL] = ItemLocation::GSToken(0x12, 0x04, "LH GS Lab Wall", LH_GS_LAB_WALL, {Category::cLakeHylia, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_GS_LAB_CRATE] = ItemLocation::GSToken(0x12, 0x08, "LH GS Lab Crate", LH_GS_LAB_CRATE, {Category::cLakeHylia, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_GS_TREE] = ItemLocation::GSToken(0x12, 0x10, "LH GS Tree", LH_GS_TREE, {Category::cLakeHylia, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + + locationTable[GV_GS_BEAN_PATCH] = ItemLocation::GSToken(0x13, 0x01, "GV GS Bean Patch", GV_GS_BEAN_PATCH, {Category::cGerudoValley, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_GS_SMALL_BRIDGE] = ItemLocation::GSToken(0x13, 0x02, "GV GS Small Bridge", GV_GS_SMALL_BRIDGE, {Category::cGerudoValley, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_GS_PILLAR] = ItemLocation::GSToken(0x13, 0x04, "GV GS Pillar", GV_GS_PILLAR, {Category::cGerudoValley, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_GS_BEHIND_TENT] = ItemLocation::GSToken(0x13, 0x08, "GV GS Behind Tent", GV_GS_BEHIND_TENT, {Category::cGerudoValley, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + locationTable[GF_GS_ARCHERY_RANGE] = ItemLocation::GSToken(0x14, 0x01, "GF GS Archery Range", GF_GS_ARCHERY_RANGE, {Category::cGerudoFortress, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_GS_TOP_FLOOR] = ItemLocation::GSToken(0x14, 0x02, "GF GS Top Floor", GF_GS_TOP_FLOOR, {Category::cGerudoFortress, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + locationTable[WASTELAND_GS] = ItemLocation::GSToken(0x15, 0x02, "Wasteland GS", WASTELAND_GS, {Category::cHauntedWasteland, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[COLOSSUS_GS_BEAN_PATCH] = ItemLocation::GSToken(0x15, 0x01, "Colossus GS Bean Patch", COLOSSUS_GS_BEAN_PATCH, {Category::cDesertColossus, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[COLOSSUS_GS_HILL] = ItemLocation::GSToken(0x15, 0x04, "Colossus GS Hill", COLOSSUS_GS_HILL, {Category::cDesertColossus, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[COLOSSUS_GS_TREE] = ItemLocation::GSToken(0x15, 0x08, "Colossus GS Tree", COLOSSUS_GS_TREE, {Category::cDesertColossus, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + locationTable[OGC_GS] = ItemLocation::GSToken(0x0E, 0x01, "OGC GS", OGC_GS, {Category::cOutsideGanonsCastle, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[HC_GS_STORMS_GROTTO] = ItemLocation::GSToken(0x0E, 0x02, "HC GS Storms Grotto", HC_GS_STORMS_GROTTO, {Category::cHyruleCastle, Category::cSkulltula, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[HC_GS_TREE] = ItemLocation::GSToken(0x0E, 0x04, "HC GS Tree", HC_GS_TREE, {Category::cHyruleCastle, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_GS_GUARD_HOUSE] = ItemLocation::GSToken(0x0E, 0x08, "Market GS Guard House", MARKET_GS_GUARD_HOUSE, {Category::cInnerMarket, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + locationTable[KAK_GS_HOUSE_UNDER_CONSTRUCTION] = ItemLocation::GSToken(0x10, 0x08, "Kak GS House Under Construction", KAK_GS_HOUSE_UNDER_CONSTRUCTION, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GS_SKULLTULA_HOUSE] = ItemLocation::GSToken(0x10, 0x10, "Kak GS Skulltula House", KAK_GS_SKULLTULA_HOUSE, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GS_GUARDS_HOUSE] = ItemLocation::GSToken(0x10, 0x02, "Kak GS Guards House", KAK_GS_GUARDS_HOUSE, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GS_TREE] = ItemLocation::GSToken(0x10, 0x20, "Kak GS Tree", KAK_GS_TREE, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GS_WATCHTOWER] = ItemLocation::GSToken(0x10, 0x04, "Kak GS Watchtower", KAK_GS_WATCHTOWER, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GS_ABOVE_IMPAS_HOUSE] = ItemLocation::GSToken(0x10, 0x40, "Kak GS Above Impas House", KAK_GS_ABOVE_IMPAS_HOUSE, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + locationTable[GRAVEYARD_GS_WALL] = ItemLocation::GSToken(0x10, 0x80, "Graveyard GS Wall", GRAVEYARD_GS_WALL, {Category::cGraveyard, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_GS_BEAN_PATCH] = ItemLocation::GSToken(0x10, 0x01, "Graveyard GS Bean Patch", GRAVEYARD_GS_BEAN_PATCH, {Category::cGraveyard, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + locationTable[DMC_GS_BEAN_PATCH] = ItemLocation::GSToken(0x0F, 0x01, "DMC GS Bean Patch", DMC_GS_BEAN_PATCH, {Category::cDeathMountainCrater, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_GS_CRATE] = ItemLocation::GSToken(0x0F, 0x80, "DMC GS Crate", DMC_GS_CRATE, {Category::cDeathMountainCrater, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + + locationTable[DMT_GS_BEAN_PATCH] = ItemLocation::GSToken(0x0F, 0x02, "DMT GS Bean Patch", DMT_GS_BEAN_PATCH, {Category::cDeathMountainTrail, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_GS_NEAR_KAK] = ItemLocation::GSToken(0x0F, 0x04, "DMT GS Near Kak", DMT_GS_NEAR_KAK, {Category::cDeathMountainTrail, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_GS_ABOVE_DODONGOS_CAVERN] = ItemLocation::GSToken(0x0F, 0x08, "DMT GS Above Dodongos Cavern", DMT_GS_ABOVE_DODONGOS_CAVERN, {Category::cDeathMountainTrail, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_GS_FALLING_ROCKS_PATH] = ItemLocation::GSToken(0x0F, 0x10, "DMT GS Falling Rocks Path", DMT_GS_FALLING_ROCKS_PATH, {Category::cDeathMountainTrail, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + + locationTable[GC_GS_CENTER_PLATFORM] = ItemLocation::GSToken(0x0F, 0x20, "GC GS Center Platform", GC_GS_CENTER_PLATFORM, {Category::cGoronCity, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_GS_BOULDER_MAZE] = ItemLocation::GSToken(0x0F, 0x40, "GC GS Boulder Maze", GC_GS_BOULDER_MAZE, {Category::cGoronCity, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + + locationTable[ZR_GS_LADDER] = ItemLocation::GSToken(0x11, 0x01, "ZR GS Ladder", ZR_GS_LADDER, {Category::cZorasRiver, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_GS_TREE] = ItemLocation::GSToken(0x11, 0x02, "ZR GS Tree", ZR_GS_TREE, {Category::cZorasRiver, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_GS_ABOVE_BRIDGE] = ItemLocation::GSToken(0x11, 0x08, "ZR GS Above Bridge", ZR_GS_ABOVE_BRIDGE, {Category::cZorasRiver, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_GS_NEAR_RAISED_GROTTOS] = ItemLocation::GSToken(0x11, 0x10, "ZR GS Near Raised Grottos", ZR_GS_NEAR_RAISED_GROTTOS, {Category::cZorasRiver, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + + locationTable[ZD_GS_FROZEN_WATERFALL] = ItemLocation::GSToken(0x11, 0x40, "ZD GS Frozen Waterfall", ZD_GS_FROZEN_WATERFALL, {Category::cZorasDomain, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZF_GS_ABOVE_THE_LOG] = ItemLocation::GSToken(0x11, 0x04, "ZF GS Above The Log", ZF_GS_ABOVE_THE_LOG, {Category::cZorasFountain, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZF_GS_HIDDEN_CAVE] = ItemLocation::GSToken(0x11, 0x20, "ZF GS Hidden Cave", ZF_GS_HIDDEN_CAVE, {Category::cZorasFountain, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZF_GS_TREE] = ItemLocation::GSToken(0x11, 0x80, "ZF GS Tree", ZF_GS_TREE, {Category::cZorasFountain, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + + locationTable[LLR_GS_BACK_WALL] = ItemLocation::GSToken(0x0B, 0x01, "LLR GS Back Wall", LLR_GS_BACK_WALL, {Category::cLonLonRanch, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_GS_RAIN_SHED] = ItemLocation::GSToken(0x0B, 0x02, "LLR GS Rain Shed", LLR_GS_RAIN_SHED, {Category::cLonLonRanch, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_GS_HOUSE_WINDOW] = ItemLocation::GSToken(0x0B, 0x04, "LLR GS House Window", LLR_GS_HOUSE_WINDOW, {Category::cLonLonRanch, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_GS_TREE] = ItemLocation::GSToken(0x0B, 0x08, "LLR GS Tree", LLR_GS_TREE, {Category::cLonLonRanch, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + + /*------------------------------- + --- BOSSES --- + -------------------------------*/ + + locationTable[LINKS_POCKET] = ItemLocation::Reward (0xFF, 0xFF, "Link's Pocket", LINKS_POCKET, LIGHT_MEDALLION, {}, SpoilerCollectionCheck::AlwaysCollected(), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[QUEEN_GOHMA] = ItemLocation::Reward (0xFF, DUNGEON_DEKU_TREE, "Queen Gohma", QUEEN_GOHMA, KOKIRI_EMERALD, {}, SpoilerCollectionCheck::EventChkInf(0x09), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[KING_DODONGO] = ItemLocation::Reward (0xFF, DUNGEON_DODONGOS_CAVERN, "King Dodongo", KING_DODONGO, GORON_RUBY, {}, SpoilerCollectionCheck::EventChkInf(0x25), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[BARINADE] = ItemLocation::Reward (0xFF, DUNGEON_JABUJABUS_BELLY, "Barinade", BARINADE, ZORA_SAPPHIRE, {}, SpoilerCollectionCheck::EventChkInf(0x37), SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[PHANTOM_GANON] = ItemLocation::Reward (0xFF, DUNGEON_FOREST_TEMPLE, "Phantom Ganon", PHANTOM_GANON, FOREST_MEDALLION, {}, SpoilerCollectionCheck::EventChkInf(0x48), SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[VOLVAGIA] = ItemLocation::Reward (0xFF, DUNGEON_FIRE_TEMPLE, "Volvagia", VOLVAGIA, FIRE_MEDALLION, {}, SpoilerCollectionCheck::EventChkInf(0x49), SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[MORPHA] = ItemLocation::Reward (0xFF, DUNGEON_WATER_TEMPLE, "Morpha", MORPHA, WATER_MEDALLION, {}, SpoilerCollectionCheck::EventChkInf(0x4A), SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[TWINROVA] = ItemLocation::Reward (0xFF, DUNGEON_SPIRIT_TEMPLE, "Twinrova", TWINROVA, SPIRIT_MEDALLION, {}, SpoilerCollectionCheck::EventChkInf(0x47), SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[BONGO_BONGO] = ItemLocation::Reward (0xFF, DUNGEON_SHADOW_TEMPLE, "Bongo Bongo", BONGO_BONGO, SHADOW_MEDALLION, {}, SpoilerCollectionCheck::EventChkInf(0x46), SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[GANON] = ItemLocation::Reward (0xFF, 0xF0, "Ganon", NONE, TRIFORCE, {}, SpoilerCollectionCheck::None(), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + + /*------------------------------- + ---HEART CONTAINERS --- + -------------------------------*/ + + locationTable[DEKU_TREE_QUEEN_GOHMA_HEART] = ItemLocation::Base (0x11, 0x4F, "Deku Tree Queen Gohma Heart Container", DEKU_TREE_QUEEN_GOHMA_HEART, HEART_CONTAINER, {Category::cDekuTree, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x11, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DODONGOS_CAVERN_KING_DODONGO_HEART] = ItemLocation::Base (0x12, 0x4F, "Dodongos Cavern King Dodongo Heart Container", DODONGOS_CAVERN_KING_DODONGO_HEART, HEART_CONTAINER, {Category::cDodongosCavern, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x12, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[JABU_JABUS_BELLY_BARINADE_HEART] = ItemLocation::Base (0x13, 0x4F, "Jabu Jabus Belly Barinade Heart Container", JABU_JABUS_BELLY_BARINADE_HEART, HEART_CONTAINER, {Category::cJabuJabusBelly, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x13, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[FOREST_TEMPLE_PHANTOM_GANON_HEART] = ItemLocation::Base (0x14, 0x4F, "Forest Temple Phantom Ganon Heart Container", FOREST_TEMPLE_PHANTOM_GANON_HEART, HEART_CONTAINER, {Category::cForestTemple, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x14, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FIRE_TEMPLE_VOLVAGIA_HEART] = ItemLocation::Base (0x15, 0x4F, "Fire Temple Volvagia Heart Container", FIRE_TEMPLE_VOLVAGIA_HEART, HEART_CONTAINER, {Category::cFireTemple, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x15, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[WATER_TEMPLE_MORPHA_HEART] = ItemLocation::Base (0x16, 0x4F, "Water Temple Morpha Heart Container", WATER_TEMPLE_MORPHA_HEART, HEART_CONTAINER, {Category::cWaterTemple, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x16, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[SPIRIT_TEMPLE_TWINROVA_HEART] = ItemLocation::Base (0x17, 0x4F, "Spirit Temple Twinrova Heart Container", SPIRIT_TEMPLE_TWINROVA_HEART, HEART_CONTAINER, {Category::cSpiritTemple, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x17, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SHADOW_TEMPLE_BONGO_BONGO_HEART] = ItemLocation::Base (0x18, 0x4F, "Shadow Temple Bongo Bongo Heart Container", SHADOW_TEMPLE_BONGO_BONGO_HEART, HEART_CONTAINER, {Category::cShadowTemple, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x18, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + + /*------------------------------- + --- CUTSCENES --- + -------------------------------*/ + + locationTable[TOT_LIGHT_ARROWS_CUTSCENE] = ItemLocation::Delayed(0xFF, 0x01, "ToT Light Arrow Cutscene", TOT_LIGHT_ARROWS_CUTSCENE, LIGHT_ARROWS, {Category::cTempleOfTime, Category::cMarket}, SpoilerCollectionCheck::EventChkInf(0xC4), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[LW_GIFT_FROM_SARIA] = ItemLocation::Delayed(0xFF, 0x02, "LW Gift From Saria", LW_GIFT_FROM_SARIA, PROGRESSIVE_OCARINA, {Category::cLostWoods, Category::cForest}, SpoilerCollectionCheck::EventChkInf(0xC1), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[ZF_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x10, "ZF Great Fairy Reward", ZF_GREAT_FAIRY_REWARD, FARORES_WIND, {Category::cZorasFountain, Category::cFairies}, SpoilerCollectionCheck::ItemGetInf(16), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[HC_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x11, "HC Great Fairy Reward", HC_GREAT_FAIRY_REWARD, DINS_FIRE, {Category::cHyruleCastle, Category::cMarket, Category::cFairies}, SpoilerCollectionCheck::ItemGetInf(17), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[COLOSSUS_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x12, "Colossus Great Fairy Reward", COLOSSUS_GREAT_FAIRY_REWARD, NAYRUS_LOVE, {Category::cDesertColossus, Category::cFairies}, SpoilerCollectionCheck::ItemGetInf(18), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[DMT_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x13, "DMT Great Fairy Reward", DMT_GREAT_FAIRY_REWARD, PROGRESSIVE_MAGIC_METER, {Category::cDeathMountainTrail, Category::cDeathMountain, Category::cFairies}, SpoilerCollectionCheck::Chest(0x3B, 0x00), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x14, "DMC Great Fairy Reward", DMC_GREAT_FAIRY_REWARD, PROGRESSIVE_MAGIC_METER, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cFairies}, SpoilerCollectionCheck::Chest(0x3B, 0x01), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[OGC_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x15, "OGC Great Fairy Reward", OGC_GREAT_FAIRY_REWARD, DOUBLE_DEFENSE, {Category::cOutsideGanonsCastle, Category::cFairies}, SpoilerCollectionCheck::Chest(0x3B, 0x02), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + + locationTable[SHEIK_IN_FOREST] = ItemLocation::Delayed(0xFF, 0x20, "Sheik in Forest", SHEIK_IN_FOREST, MINUET_OF_FOREST, {Category::cSacredForestMeadow, Category::cForest, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x50), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[SHEIK_IN_CRATER] = ItemLocation::Delayed(0xFF, 0x21, "Sheik in Crater", SHEIK_IN_CRATER, BOLERO_OF_FIRE, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x51), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[SHEIK_IN_ICE_CAVERN] = ItemLocation::Delayed(0xFF, 0x22, "Sheik in Ice Cavern", SHEIK_IN_ICE_CAVERN, SERENADE_OF_WATER, {Category::cIceCavern, Category::cSong, Category::cSongDungeonReward}, SpoilerCollectionCheck::EventChkInf(0x52), SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[SHEIK_AT_COLOSSUS] = ItemLocation::Delayed(0xFF, 0x23, "Sheik at Colossus", SHEIK_AT_COLOSSUS, REQUIEM_OF_SPIRIT, {Category::cDesertColossus, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0xAC), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[SHEIK_IN_KAKARIKO] = ItemLocation::Delayed(0xFF, 0x24, "Sheik in Kakariko", SHEIK_IN_KAKARIKO, NOCTURNE_OF_SHADOW, {Category::cKakarikoVillage, Category::cKakariko, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0xAA), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[SHEIK_AT_TEMPLE] = ItemLocation::Delayed(0xFF, 0x25, "Sheik at Temple", SHEIK_AT_TEMPLE, PRELUDE_OF_LIGHT, {Category::cTempleOfTime, Category::cMarket, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x55), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[SONG_FROM_IMPA] = ItemLocation::Delayed(0xFF, 0x26, "Song from Impa", SONG_FROM_IMPA, ZELDAS_LULLABY, {Category::cHyruleCastle, Category::cMarket, Category::cSong, Category::cSongDungeonReward}, SpoilerCollectionCheck::EventChkInf(0x59), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[SONG_FROM_MALON] = ItemLocation::Delayed(0xFF, 0x27, "Song from Malon", SONG_FROM_MALON, EPONAS_SONG, {Category::cLonLonRanch, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x58), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[SONG_FROM_SARIA] = ItemLocation::Delayed(0xFF, 0x28, "Song from Saria", SONG_FROM_SARIA, SARIAS_SONG, {Category::cSacredForestMeadow, Category::cForest, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x57), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[SONG_FROM_COMPOSERS_GRAVE] = ItemLocation::Delayed(0xFF, 0x29, "Song from Composers Grave", SONG_FROM_COMPOSERS_GRAVE, SUNS_SONG, {Category::cGraveyard, Category::cKakariko, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x5A), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[SONG_FROM_OCARINA_OF_TIME] = ItemLocation::Delayed(0xFF, 0x2A, "Song from Ocarina of Time", SONG_FROM_OCARINA_OF_TIME, SONG_OF_TIME, {Category::cHyruleField, Category::cSong, Category::cNeedSpiritualStones,}, SpoilerCollectionCheck::EventChkInf(0xA9), SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[SONG_FROM_WINDMILL] = ItemLocation::Delayed(0xFF, 0x2B, "Song from Windmill", SONG_FROM_WINDMILL, SONG_OF_STORMS, {Category::cKakarikoVillage, Category::cKakariko, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x5B), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + /*------------------------------- + --- COWS --- + -------------------------------*/ + + locationTable[KF_LINKS_HOUSE_COW] = ItemLocation::Base (0x34, 0x15, "KF Links House Cow", KF_LINKS_HOUSE_COW, MILK, {Category::cForest, Category::cCow, Category::cMinigame}, SpoilerCollectionCheck::Cow(0x34, 0x15), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[HF_COW_GROTTO_COW] = ItemLocation::Base (0x3E, 0x16, "HF Cow Grotto Cow", HF_COW_GROTTO_COW, MILK, {Category::cHyruleField, Category::cCow, Category::cGrotto}, SpoilerCollectionCheck::Cow(0x3E, 0x16), SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[LLR_STABLES_LEFT_COW] = ItemLocation::Base (0x36, 0x16, "LLR Stables Left Cow", LLR_STABLES_LEFT_COW, MILK, {Category::cLonLonRanch, Category::cCow}, SpoilerCollectionCheck::Cow(0x36, 0x16), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_STABLES_RIGHT_COW] = ItemLocation::Base (0x36, 0x15, "LLR Stables Right Cow", LLR_STABLES_RIGHT_COW, MILK, {Category::cLonLonRanch, Category::cCow}, SpoilerCollectionCheck::Cow(0x36, 0x15), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_TOWER_LEFT_COW] = ItemLocation::Base (0x4C, 0x15, "LLR Tower Left Cow", LLR_TOWER_LEFT_COW, MILK, {Category::cLonLonRanch, Category::cCow}, SpoilerCollectionCheck::Cow(0x4C, 0x16), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_TOWER_RIGHT_COW] = ItemLocation::Base (0x4C, 0x16, "LLR Tower Right Cow", LLR_TOWER_RIGHT_COW, MILK, {Category::cLonLonRanch, Category::cCow}, SpoilerCollectionCheck::Cow(0x4C, 0x15), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[KAK_IMPAS_HOUSE_COW] = ItemLocation::Base (0x37, 0x15, "Kak Impas House Cow", KAK_IMPAS_HOUSE_COW, MILK, {Category::cKakarikoVillage, Category::cKakariko, Category::cCow}, SpoilerCollectionCheck::Cow(0x37, 0x15), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[DMT_COW_GROTTO_COW] = ItemLocation::Base (0x3E, 0x15, "DMT Cow Grotto Cow", DMT_COW_GROTTO_COW, MILK, {Category::cDeathMountainTrail, Category::cDeathMountain, Category::cCow, Category::cGrotto}, SpoilerCollectionCheck::Cow(0x3E, 0x15), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[GV_COW] = ItemLocation::Base (0x5A, 0x15, "GV Cow", GV_COW, MILK, {Category::cGerudoValley, Category::cGerudo, Category::cCow}, SpoilerCollectionCheck::Cow(0x5A, 0x15), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[JABU_JABUS_BELLY_MQ_COW] = ItemLocation::Base (0x02, 0x15, "Jabu Jabus Belly MQ Cow", JABU_JABUS_BELLY_MQ_COW, MILK, {Category::cJabuJabusBelly, Category::cCow}, SpoilerCollectionCheck::Cow(0x02, 0x15), SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + + /*------------------------------- + --- SHOPS --- + 8 6 2 4 + + 7 5 1 3 + -------------------------------*/ + + locationTable[KF_SHOP_ITEM_1] = ItemLocation::Base(0x2D, 0x30, "KF Shop Item 1", KF_SHOP_ITEM_1, BUY_DEKU_SHIELD, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 0), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_2] = ItemLocation::Base(0x2D, 0x31, "KF Shop Item 2", KF_SHOP_ITEM_2, BUY_DEKU_NUT_5, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 1), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_3] = ItemLocation::Base(0x2D, 0x32, "KF Shop Item 3", KF_SHOP_ITEM_3, BUY_DEKU_NUT_10, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 2), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_4] = ItemLocation::Base(0x2D, 0x33, "KF Shop Item 4", KF_SHOP_ITEM_4, BUY_DEKU_STICK_1, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 3), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_5] = ItemLocation::Base(0x2D, 0x34, "KF Shop Item 5", KF_SHOP_ITEM_5, BUY_DEKU_SEEDS_30, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 4), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_6] = ItemLocation::Base(0x2D, 0x35, "KF Shop Item 6", KF_SHOP_ITEM_6, BUY_ARROWS_10, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 5), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_7] = ItemLocation::Base(0x2D, 0x36, "KF Shop Item 7", KF_SHOP_ITEM_7, BUY_ARROWS_30, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 6), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_8] = ItemLocation::Base(0x2D, 0x37, "KF Shop Item 8", KF_SHOP_ITEM_8, BUY_HEART, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 7), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + + locationTable[KAK_POTION_SHOP_ITEM_1] = ItemLocation::Base(0x30, 0x30, "Kak Potion Shop Item 1", KAK_POTION_SHOP_ITEM_1, BUY_DEKU_NUT_5, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 0), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_2] = ItemLocation::Base(0x30, 0x31, "Kak Potion Shop Item 2", KAK_POTION_SHOP_ITEM_2, BUY_FISH, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 1), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_3] = ItemLocation::Base(0x30, 0x32, "Kak Potion Shop Item 3", KAK_POTION_SHOP_ITEM_3, BUY_RED_POTION_30, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 2), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_4] = ItemLocation::Base(0x30, 0x33, "Kak Potion Shop Item 4", KAK_POTION_SHOP_ITEM_4, BUY_GREEN_POTION, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 3), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_5] = ItemLocation::Base(0x30, 0x34, "Kak Potion Shop Item 5", KAK_POTION_SHOP_ITEM_5, BUY_BLUE_FIRE, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_6] = ItemLocation::Base(0x30, 0x35, "Kak Potion Shop Item 6", KAK_POTION_SHOP_ITEM_6, BUY_BOTTLE_BUG, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 5), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_7] = ItemLocation::Base(0x30, 0x36, "Kak Potion Shop Item 7", KAK_POTION_SHOP_ITEM_7, BUY_POE, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 6), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_8] = ItemLocation::Base(0x30, 0x37, "Kak Potion Shop Item 8", KAK_POTION_SHOP_ITEM_8, BUY_FAIRYS_SPIRIT, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 7), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + locationTable[MARKET_BOMBCHU_SHOP_ITEM_1] = ItemLocation::Base(0x32, 0x30, "MK Bombchu Shop Item 1", MARKET_BOMBCHU_SHOP_ITEM_1, BUY_BOMBCHU_5, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 0), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_2] = ItemLocation::Base(0x32, 0x31, "MK Bombchu Shop Item 2", MARKET_BOMBCHU_SHOP_ITEM_2, BUY_BOMBCHU_10, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 1), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_3] = ItemLocation::Base(0x32, 0x32, "MK Bombchu Shop Item 3", MARKET_BOMBCHU_SHOP_ITEM_3, BUY_BOMBCHU_10, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 2), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_4] = ItemLocation::Base(0x32, 0x33, "MK Bombchu Shop Item 4", MARKET_BOMBCHU_SHOP_ITEM_4, BUY_BOMBCHU_10, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 3), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_5] = ItemLocation::Base(0x32, 0x34, "MK Bombchu Shop Item 5", MARKET_BOMBCHU_SHOP_ITEM_5, BUY_BOMBCHU_20, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 4), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_6] = ItemLocation::Base(0x32, 0x35, "MK Bombchu Shop Item 6", MARKET_BOMBCHU_SHOP_ITEM_6, BUY_BOMBCHU_20, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 5), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_7] = ItemLocation::Base(0x32, 0x36, "MK Bombchu Shop Item 7", MARKET_BOMBCHU_SHOP_ITEM_7, BUY_BOMBCHU_20, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 6), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_8] = ItemLocation::Base(0x32, 0x37, "MK Bombchu Shop Item 8", MARKET_BOMBCHU_SHOP_ITEM_8, BUY_BOMBCHU_20, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 7), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + locationTable[MARKET_POTION_SHOP_ITEM_1] = ItemLocation::Base(0x31, 0x30, "MK Potion Shop Item 1", MARKET_POTION_SHOP_ITEM_1, BUY_GREEN_POTION, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 0), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_2] = ItemLocation::Base(0x31, 0x31, "MK Potion Shop Item 2", MARKET_POTION_SHOP_ITEM_2, BUY_BLUE_FIRE, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 1), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_3] = ItemLocation::Base(0x31, 0x32, "MK Potion Shop Item 3", MARKET_POTION_SHOP_ITEM_3, BUY_RED_POTION_30, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 2), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_4] = ItemLocation::Base(0x31, 0x33, "MK Potion Shop Item 4", MARKET_POTION_SHOP_ITEM_4, BUY_FAIRYS_SPIRIT, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 3), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_5] = ItemLocation::Base(0x31, 0x34, "MK Potion Shop Item 5", MARKET_POTION_SHOP_ITEM_5, BUY_DEKU_NUT_5, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 4), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_6] = ItemLocation::Base(0x31, 0x35, "MK Potion Shop Item 6", MARKET_POTION_SHOP_ITEM_6, BUY_BOTTLE_BUG, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 5), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_7] = ItemLocation::Base(0x31, 0x36, "MK Potion Shop Item 7", MARKET_POTION_SHOP_ITEM_7, BUY_POE, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 6), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_8] = ItemLocation::Base(0x31, 0x37, "MK Potion Shop Item 8", MARKET_POTION_SHOP_ITEM_8, BUY_FISH, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 7), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + locationTable[MARKET_BAZAAR_ITEM_1] = ItemLocation::Base(0x2C, 0x30, "MK Bazaar Item 1", MARKET_BAZAAR_ITEM_1, BUY_HYLIAN_SHIELD, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 0), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_2] = ItemLocation::Base(0x2C, 0x31, "MK Bazaar Item 2", MARKET_BAZAAR_ITEM_2, BUY_BOMBS_535, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 1), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_3] = ItemLocation::Base(0x2C, 0x32, "MK Bazaar Item 3", MARKET_BAZAAR_ITEM_3, BUY_DEKU_NUT_5, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 2), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_4] = ItemLocation::Base(0x2C, 0x33, "MK Bazaar Item 4", MARKET_BAZAAR_ITEM_4, BUY_HEART, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 3), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_5] = ItemLocation::Base(0x2C, 0x34, "MK Bazaar Item 5", MARKET_BAZAAR_ITEM_5, BUY_ARROWS_10, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 4), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_6] = ItemLocation::Base(0x2C, 0x35, "MK Bazaar Item 6", MARKET_BAZAAR_ITEM_6, BUY_ARROWS_50, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 5), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_7] = ItemLocation::Base(0x2C, 0x36, "MK Bazaar Item 7", MARKET_BAZAAR_ITEM_7, BUY_DEKU_STICK_1, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 6), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_8] = ItemLocation::Base(0x2C, 0x37, "MK Bazaar Item 8", MARKET_BAZAAR_ITEM_8, BUY_ARROWS_30, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 7), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + locationTable[KAK_BAZAAR_ITEM_1] = ItemLocation::Base(0x2C, 0x38, "Kak Bazaar Item 1", KAK_BAZAAR_ITEM_1, BUY_HYLIAN_SHIELD, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 0), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_2] = ItemLocation::Base(0x2C, 0x39, "Kak Bazaar Item 2", KAK_BAZAAR_ITEM_2, BUY_BOMBS_535, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 1), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_3] = ItemLocation::Base(0x2C, 0x3A, "Kak Bazaar Item 3", KAK_BAZAAR_ITEM_3, BUY_DEKU_NUT_5, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 2), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_4] = ItemLocation::Base(0x2C, 0x3B, "Kak Bazaar Item 4", KAK_BAZAAR_ITEM_4, BUY_HEART, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 3), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_5] = ItemLocation::Base(0x2C, 0x3C, "Kak Bazaar Item 5", KAK_BAZAAR_ITEM_5, BUY_ARROWS_10, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_6] = ItemLocation::Base(0x2C, 0x3D, "Kak Bazaar Item 6", KAK_BAZAAR_ITEM_6, BUY_ARROWS_50, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 5), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_7] = ItemLocation::Base(0x2C, 0x3E, "Kak Bazaar Item 7", KAK_BAZAAR_ITEM_7, BUY_DEKU_STICK_1, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 6), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_8] = ItemLocation::Base(0x2C, 0x3F, "Kak Bazaar Item 8", KAK_BAZAAR_ITEM_8, BUY_ARROWS_30, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 7), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + locationTable[ZD_SHOP_ITEM_1] = ItemLocation::Base(0x2F, 0x30, "ZD Shop Item 1", ZD_SHOP_ITEM_1, BUY_ZORA_TUNIC, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 0), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_2] = ItemLocation::Base(0x2F, 0x31, "ZD Shop Item 2", ZD_SHOP_ITEM_2, BUY_ARROWS_10, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 1), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_3] = ItemLocation::Base(0x2F, 0x32, "ZD Shop Item 3", ZD_SHOP_ITEM_3, BUY_HEART, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 2), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_4] = ItemLocation::Base(0x2F, 0x33, "ZD Shop Item 4", ZD_SHOP_ITEM_4, BUY_ARROWS_30, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 3), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_5] = ItemLocation::Base(0x2F, 0x34, "ZD Shop Item 5", ZD_SHOP_ITEM_5, BUY_DEKU_NUT_5, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 4), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_6] = ItemLocation::Base(0x2F, 0x35, "ZD Shop Item 6", ZD_SHOP_ITEM_6, BUY_ARROWS_50, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 5), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_7] = ItemLocation::Base(0x2F, 0x36, "ZD Shop Item 7", ZD_SHOP_ITEM_7, BUY_FISH, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 6), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_8] = ItemLocation::Base(0x2F, 0x37, "ZD Shop Item 8", ZD_SHOP_ITEM_8, BUY_RED_POTION_50, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 7), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + + locationTable[GC_SHOP_ITEM_1] = ItemLocation::Base(0x2E, 0x30, "GC Shop Item 1", GC_SHOP_ITEM_1, BUY_BOMBS_525, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 0), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_2] = ItemLocation::Base(0x2E, 0x31, "GC Shop Item 2", GC_SHOP_ITEM_2, BUY_BOMBS_10, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 1), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_3] = ItemLocation::Base(0x2E, 0x32, "GC Shop Item 3", GC_SHOP_ITEM_3, BUY_BOMBS_20, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 2), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_4] = ItemLocation::Base(0x2E, 0x33, "GC Shop Item 4", GC_SHOP_ITEM_4, BUY_BOMBS_30, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 3), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_5] = ItemLocation::Base(0x2E, 0x34, "GC Shop Item 5", GC_SHOP_ITEM_5, BUY_GORON_TUNIC, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 4), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_6] = ItemLocation::Base(0x2E, 0x35, "GC Shop Item 6", GC_SHOP_ITEM_6, BUY_HEART, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 5), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_7] = ItemLocation::Base(0x2E, 0x36, "GC Shop Item 7", GC_SHOP_ITEM_7, BUY_RED_POTION_40, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 6), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_8] = ItemLocation::Base(0x2E, 0x37, "GC Shop Item 8", GC_SHOP_ITEM_8, BUY_HEART, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 7), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + + /*------------------------------- + --- GOSSIP STONES --- + -------------------------------*/ + // These are not actual locations, but are filler spots used for hint reachability. - OoT Randomizer + // flag + 0x400 = message ID + locationTable[DMC_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x05, "DMC Gossip Stone", {}); + locationTable[DMT_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x04, "DMT Gossip Stone", {}); + locationTable[COLOSSUS_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x1A, "Colossus Gossip Stone", {}); + locationTable[DODONGOS_CAVERN_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x14, "Dodongo's Cavern Gossip Stone", {}); + locationTable[GV_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x11, "GV Gossip Stone", {}); + locationTable[GC_MAZE_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x15, "GC Maze Gossip Stone", {}); + locationTable[GC_MEDIGORON_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x19, "GC Medigoron Gossip Stone", {}); + locationTable[GRAVEYARD_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x0A, "GY Gossip Stone", {}); + locationTable[HC_MALON_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x12, "HC Malon Gossip Stone", {}); + locationTable[HC_ROCK_WALL_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x0B, "HC Rock Wall Gossip Stone", {}); + locationTable[HC_STORMS_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x13, "HC Storms Grotto Gossip Stone", {}); + locationTable[KF_DEKU_TREE_GOSSIP_STONE_LEFT] = ItemLocation::HintStone(0x00, 0x1F, "KF Deku Tree Left Gossip Stone", {}); + locationTable[KF_DEKU_TREE_GOSSIP_STONE_RIGHT] = ItemLocation::HintStone(0x00, 0x20, "KF Deku Tree Right Gossip Stone", {}); + locationTable[KF_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x1E, "KF Gossip Stone", {}); + locationTable[LH_LAB_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x03, "LH Lab Gossip Stone", {}); + locationTable[LH_GOSSIP_STONE_SOUTHEAST] = ItemLocation::HintStone(0x00, 0x0F, "LH Southeast Gossip Stone", {}); + locationTable[LH_GOSSIP_STONE_SOUTHWEST] = ItemLocation::HintStone(0x00, 0x08, "LH Southwest Gossip Stone", {}); + locationTable[LW_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x1D, "LW Gossip Stone", {}); + locationTable[SFM_MAZE_GOSSIP_STONE_LOWER] = ItemLocation::HintStone(0x00, 0x16, "SFM Maze Lower Gossip Stone", {}); + locationTable[SFM_MAZE_GOSSIP_STONE_UPPER] = ItemLocation::HintStone(0x00, 0x17, "SFM Maze Upper Gossip Stone", {}); + locationTable[SFM_SARIA_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x1C, "SFM Saria Gossip Stone", {}); + locationTable[TOT_GOSSIP_STONE_LEFT] = ItemLocation::HintStone(0x00, 0x06, "ToT Left Gossip Stone", {}); + locationTable[TOT_GOSSIP_STONE_RIGHT] = ItemLocation::HintStone(0x00, 0x07, "ToT Left Center Gossip Stone", {}); + locationTable[TOT_GOSSIP_STONE_RIGHT_CENTER] = ItemLocation::HintStone(0x00, 0x10, "ToT Right Center Gossip Stone", {}); + locationTable[TOT_GOSSIP_STONE_LEFT_CENTER] = ItemLocation::HintStone(0x00, 0x0E, "ToT Right Gossip Stone", {}); + locationTable[ZD_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x09, "ZD Gossip Stone", {}); + locationTable[ZF_FAIRY_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x01, "Fairy Gossip Stone", {}); + locationTable[ZF_JABU_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x02, "Jabu Gossip Stone", {}); + locationTable[ZR_NEAR_GROTTOS_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x0D, "ZR Near Grottos Gossip Stone", {}); + locationTable[ZR_NEAR_DOMAIN_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x0C, "ZR Near Domain Gossip Stone", {}); + locationTable[HF_COW_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x1B, "HF Cow Grotto Gossip Stone", {}); + + locationTable[HF_NEAR_MARKET_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x30, "HF Near Market Gossip Stone", {}); + locationTable[HF_SOUTHEAST_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x32, "HF Southeast Gossip Stone", {}); + locationTable[HF_OPEN_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x33, "HF Open Grotto Gossip Stone", {}); + locationTable[KAK_OPEN_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x38, "Kak Open Grotto Gossip Stone", {}); + locationTable[ZR_OPEN_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x39, "ZR Open Grotto Gossip Stone", {}); + locationTable[KF_STORMS_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x3C, "KF Storms Gossip Stone", {}); + locationTable[LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x34, "LW Near Shortcuts Gossip Stone", {}); + locationTable[DMT_STORMS_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x37, "DMT Storms Grotto Gossip Stone", {}); + locationTable[DMC_UPPER_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x3A, "DMC Upper Grotto Gossip Stone", {}); + + locationTable[GANONDORF_HINT] = ItemLocation::OtherHint(0x00, 0x00, "Ganondorf Hint", {}); +} + +std::vector KF_ShopLocations = { + KF_SHOP_ITEM_1, + KF_SHOP_ITEM_2, + KF_SHOP_ITEM_3, + KF_SHOP_ITEM_4, + KF_SHOP_ITEM_5, + KF_SHOP_ITEM_6, + KF_SHOP_ITEM_7, + KF_SHOP_ITEM_8, +}; +std::vector Kak_PotionShopLocations = { + KAK_POTION_SHOP_ITEM_1, + KAK_POTION_SHOP_ITEM_2, + KAK_POTION_SHOP_ITEM_3, + KAK_POTION_SHOP_ITEM_4, + KAK_POTION_SHOP_ITEM_5, + KAK_POTION_SHOP_ITEM_6, + KAK_POTION_SHOP_ITEM_7, + KAK_POTION_SHOP_ITEM_8, +}; +std::vector MK_BombchuShopLocations = { + MARKET_BOMBCHU_SHOP_ITEM_1, + MARKET_BOMBCHU_SHOP_ITEM_2, + MARKET_BOMBCHU_SHOP_ITEM_3, + MARKET_BOMBCHU_SHOP_ITEM_4, + MARKET_BOMBCHU_SHOP_ITEM_5, + MARKET_BOMBCHU_SHOP_ITEM_6, + MARKET_BOMBCHU_SHOP_ITEM_7, + MARKET_BOMBCHU_SHOP_ITEM_8, +}; +std::vector MK_PotionShopLocations = { + MARKET_POTION_SHOP_ITEM_1, + MARKET_POTION_SHOP_ITEM_2, + MARKET_POTION_SHOP_ITEM_3, + MARKET_POTION_SHOP_ITEM_4, + MARKET_POTION_SHOP_ITEM_5, + MARKET_POTION_SHOP_ITEM_6, + MARKET_POTION_SHOP_ITEM_7, + MARKET_POTION_SHOP_ITEM_8, +}; +std::vector MK_BazaarLocations = { + MARKET_BAZAAR_ITEM_1, + MARKET_BAZAAR_ITEM_2, + MARKET_BAZAAR_ITEM_3, + MARKET_BAZAAR_ITEM_4, + MARKET_BAZAAR_ITEM_5, + MARKET_BAZAAR_ITEM_6, + MARKET_BAZAAR_ITEM_7, + MARKET_BAZAAR_ITEM_8, +}; +std::vector Kak_BazaarLocations = { + KAK_BAZAAR_ITEM_1, + KAK_BAZAAR_ITEM_2, + KAK_BAZAAR_ITEM_3, + KAK_BAZAAR_ITEM_4, + KAK_BAZAAR_ITEM_5, + KAK_BAZAAR_ITEM_6, + KAK_BAZAAR_ITEM_7, + KAK_BAZAAR_ITEM_8, +}; +std::vector ZD_ShopLocations = { + ZD_SHOP_ITEM_1, + ZD_SHOP_ITEM_2, + ZD_SHOP_ITEM_3, + ZD_SHOP_ITEM_4, + ZD_SHOP_ITEM_5, + ZD_SHOP_ITEM_6, + ZD_SHOP_ITEM_7, + ZD_SHOP_ITEM_8, +}; +std::vector GC_ShopLocations = { + GC_SHOP_ITEM_1, + GC_SHOP_ITEM_2, + GC_SHOP_ITEM_3, + GC_SHOP_ITEM_4, + GC_SHOP_ITEM_5, + GC_SHOP_ITEM_6, + GC_SHOP_ITEM_7, + GC_SHOP_ITEM_8, +}; +//List of shop location lists, used for shop shuffle +std::vector> ShopLocationLists = { + KF_ShopLocations, + Kak_PotionShopLocations, + MK_BombchuShopLocations, + MK_PotionShopLocations, + MK_BazaarLocations, + Kak_BazaarLocations, + ZD_ShopLocations, + GC_ShopLocations, +}; + +//List of gossip stone locations for hints +std::vector gossipStoneLocations = { + DMC_GOSSIP_STONE, + DMT_GOSSIP_STONE, + COLOSSUS_GOSSIP_STONE, + DODONGOS_CAVERN_GOSSIP_STONE, + GV_GOSSIP_STONE, + GC_MAZE_GOSSIP_STONE, + GC_MEDIGORON_GOSSIP_STONE, + GRAVEYARD_GOSSIP_STONE, + HC_MALON_GOSSIP_STONE, + HC_ROCK_WALL_GOSSIP_STONE, + HC_STORMS_GROTTO_GOSSIP_STONE, + KF_DEKU_TREE_GOSSIP_STONE_LEFT, + KF_DEKU_TREE_GOSSIP_STONE_RIGHT, + KF_GOSSIP_STONE, + LH_LAB_GOSSIP_STONE, + LH_GOSSIP_STONE_SOUTHEAST, + LH_GOSSIP_STONE_SOUTHWEST, + LW_GOSSIP_STONE, + SFM_MAZE_GOSSIP_STONE_LOWER, + SFM_MAZE_GOSSIP_STONE_UPPER, + SFM_SARIA_GOSSIP_STONE, + TOT_GOSSIP_STONE_LEFT, + TOT_GOSSIP_STONE_RIGHT, + TOT_GOSSIP_STONE_RIGHT_CENTER, + TOT_GOSSIP_STONE_LEFT_CENTER, + ZD_GOSSIP_STONE, + ZF_FAIRY_GOSSIP_STONE, + ZF_JABU_GOSSIP_STONE, + ZR_NEAR_GROTTOS_GOSSIP_STONE, + ZR_NEAR_DOMAIN_GOSSIP_STONE, + HF_COW_GROTTO_GOSSIP_STONE, + HF_NEAR_MARKET_GROTTO_GOSSIP_STONE, + HF_SOUTHEAST_GROTTO_GOSSIP_STONE, + HF_OPEN_GROTTO_GOSSIP_STONE, + KAK_OPEN_GROTTO_GOSSIP_STONE, + ZR_OPEN_GROTTO_GOSSIP_STONE, + KF_STORMS_GROTTO_GOSSIP_STONE, + LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, + DMT_STORMS_GROTTO_GOSSIP_STONE, + DMC_UPPER_GROTTO_GOSSIP_STONE, +}; + +std::vector dungeonRewardLocations = { + //Bosses + QUEEN_GOHMA, + KING_DODONGO, + BARINADE, + PHANTOM_GANON, + VOLVAGIA, + MORPHA, + TWINROVA, + BONGO_BONGO, + LINKS_POCKET, +}; +std::vector overworldLocations = { + //Kokiri Forest + KF_KOKIRI_SWORD_CHEST, + KF_MIDOS_TOP_LEFT_CHEST, + KF_MIDOS_TOP_RIGHT_CHEST, + KF_MIDOS_BOTTOM_LEFT_CHEST, + KF_MIDOS_BOTTOM_RIGHT_CHEST, + KF_STORMS_GROTTO_CHEST, + KF_LINKS_HOUSE_COW, + + //Shop + KF_SHOP_ITEM_1, + KF_SHOP_ITEM_2, + KF_SHOP_ITEM_3, + KF_SHOP_ITEM_4, + KF_SHOP_ITEM_5, + KF_SHOP_ITEM_6, + KF_SHOP_ITEM_7, + KF_SHOP_ITEM_8, + + //Lost Woods + LW_GIFT_FROM_SARIA, + LW_SKULL_KID, + LW_TRADE_COJIRO, + LW_TRADE_ODD_POTION, + LW_OCARINA_MEMORY_GAME, + LW_TARGET_IN_WOODS, + LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, + LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, + LW_DEKU_SCRUB_NEAR_BRIDGE, + LW_NEAR_SHORTCUTS_GROTTO_CHEST, + LW_DEKU_SCRUB_GROTTO_REAR, + LW_DEKU_SCRUB_GROTTO_FRONT, + DEKU_THEATER_SKULL_MASK, + DEKU_THEATER_MASK_OF_TRUTH, + + //Sacred Forest Meadow + SONG_FROM_SARIA, + SHEIK_IN_FOREST, + SFM_WOLFOS_GROTTO_CHEST, + SFM_DEKU_SCRUB_GROTTO_REAR, + SFM_DEKU_SCRUB_GROTTO_FRONT, + + //Hyrule Field + HF_SOUTHEAST_GROTTO_CHEST, + HF_OPEN_GROTTO_CHEST, + HF_NEAR_MARKET_GROTTO_CHEST, + HF_OCARINA_OF_TIME_ITEM, + SONG_FROM_OCARINA_OF_TIME, + HF_TEKTITE_GROTTO_FREESTANDING_POH, + HF_DEKU_SCRUB_GROTTO, + HF_COW_GROTTO_COW, + + //Lake Hylia + LH_CHILD_FISHING, + LH_ADULT_FISHING, + LH_LAB_DIVE, + LH_TRADE_FROG, + LH_UNDERWATER_ITEM, + LH_SUN, + LH_FREESTANDING_POH, + LH_DEKU_SCRUB_GROTTO_LEFT, + LH_DEKU_SCRUB_GROTTO_RIGHT, + LH_DEKU_SCRUB_GROTTO_CENTER, + + //Gerudo Valley + GV_CHEST, + GV_TRADE_SAW, + GV_WATERFALL_FREESTANDING_POH, + GV_CRATE_FREESTANDING_POH, + GV_DEKU_SCRUB_GROTTO_REAR, + GV_DEKU_SCRUB_GROTTO_FRONT, + GV_COW, + + //Gerudo Fortress + GF_CHEST, + GF_HBA_1000_POINTS, + GF_HBA_1500_POINTS, + GF_NORTH_F1_CARPENTER, + GF_NORTH_F2_CARPENTER, + GF_SOUTH_F1_CARPENTER, + GF_SOUTH_F2_CARPENTER, + GF_GERUDO_MEMBERSHIP_CARD, + + //Haunted Wasteland + WASTELAND_CHEST, + WASTELAND_BOMBCHU_SALESMAN, + + //Desert Colossus + SHEIK_AT_COLOSSUS, + COLOSSUS_FREESTANDING_POH, + COLOSSUS_GREAT_FAIRY_REWARD, + COLOSSUS_DEKU_SCRUB_GROTTO_REAR, + COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, + + //Market + MARKET_TREASURE_CHEST_GAME_REWARD, + MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, + MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, + MARKET_BOMBCHU_BOWLING_BOMBCHUS, + MARKET_LOST_DOG, + MARKET_SHOOTING_GALLERY_REWARD, + MARKET_10_BIG_POES, + MARKET_TREASURE_CHEST_GAME_ITEM_1, + MARKET_TREASURE_CHEST_GAME_ITEM_2, + MARKET_TREASURE_CHEST_GAME_ITEM_3, + MARKET_TREASURE_CHEST_GAME_ITEM_4, + MARKET_TREASURE_CHEST_GAME_ITEM_5, + + //Market Shops + MARKET_BOMBCHU_SHOP_ITEM_1, + MARKET_BOMBCHU_SHOP_ITEM_2, + MARKET_BOMBCHU_SHOP_ITEM_3, + MARKET_BOMBCHU_SHOP_ITEM_4, + MARKET_BOMBCHU_SHOP_ITEM_5, + MARKET_BOMBCHU_SHOP_ITEM_6, + MARKET_BOMBCHU_SHOP_ITEM_7, + MARKET_BOMBCHU_SHOP_ITEM_8, + MARKET_POTION_SHOP_ITEM_1, + MARKET_POTION_SHOP_ITEM_2, + MARKET_POTION_SHOP_ITEM_3, + MARKET_POTION_SHOP_ITEM_4, + MARKET_POTION_SHOP_ITEM_5, + MARKET_POTION_SHOP_ITEM_6, + MARKET_POTION_SHOP_ITEM_7, + MARKET_POTION_SHOP_ITEM_8, + MARKET_BAZAAR_ITEM_1, + MARKET_BAZAAR_ITEM_2, + MARKET_BAZAAR_ITEM_3, + MARKET_BAZAAR_ITEM_4, + MARKET_BAZAAR_ITEM_5, + MARKET_BAZAAR_ITEM_6, + MARKET_BAZAAR_ITEM_7, + MARKET_BAZAAR_ITEM_8, + + //Hyrule Castle + HC_MALON_EGG, + HC_ZELDAS_LETTER, + SONG_FROM_IMPA, + HC_GREAT_FAIRY_REWARD, + OGC_GREAT_FAIRY_REWARD, + + //Temple of Time + SHEIK_AT_TEMPLE, + TOT_LIGHT_ARROWS_CUTSCENE, + + //Kakariko + SHEIK_IN_KAKARIKO, + KAK_REDEAD_GROTTO_CHEST, + KAK_OPEN_GROTTO_CHEST, + KAK_10_GOLD_SKULLTULA_REWARD, + KAK_20_GOLD_SKULLTULA_REWARD, + KAK_30_GOLD_SKULLTULA_REWARD, + KAK_40_GOLD_SKULLTULA_REWARD, + KAK_50_GOLD_SKULLTULA_REWARD, + KAK_MAN_ON_ROOF, + KAK_SHOOTING_GALLERY_REWARD, + KAK_TRADE_ODD_MUSHROOM, + KAK_ANJU_AS_CHILD, + KAK_ANJU_AS_ADULT, + KAK_TRADE_POCKET_CUCCO, + KAK_IMPAS_HOUSE_FREESTANDING_POH, + KAK_WINDMILL_FREESTANDING_POH, + SONG_FROM_WINDMILL, + KAK_IMPAS_HOUSE_COW, + + //Kakariko Shops + KAK_POTION_SHOP_ITEM_1, + KAK_POTION_SHOP_ITEM_2, + KAK_POTION_SHOP_ITEM_3, + KAK_POTION_SHOP_ITEM_4, + KAK_POTION_SHOP_ITEM_5, + KAK_POTION_SHOP_ITEM_6, + KAK_POTION_SHOP_ITEM_7, + KAK_POTION_SHOP_ITEM_8, + KAK_BAZAAR_ITEM_1, + KAK_BAZAAR_ITEM_2, + KAK_BAZAAR_ITEM_3, + KAK_BAZAAR_ITEM_4, + KAK_BAZAAR_ITEM_5, + KAK_BAZAAR_ITEM_6, + KAK_BAZAAR_ITEM_7, + KAK_BAZAAR_ITEM_8, + + //Graveyard + GRAVEYARD_HOOKSHOT_CHEST, + GRAVEYARD_SHIELD_GRAVE_CHEST, + GRAVEYARD_HEART_PIECE_GRAVE_CHEST, + GRAVEYARD_COMPOSERS_GRAVE_CHEST, + SONG_FROM_COMPOSERS_GRAVE, + GRAVEYARD_FREESTANDING_POH, + GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, + GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, + + //Death Mountain Trail + DMT_CHEST, + DMT_STORMS_GROTTO_CHEST, + DMT_TRADE_BROKEN_SWORD, + DMT_TRADE_EYEDROPS, + DMT_TRADE_CLAIM_CHECK, + DMT_GREAT_FAIRY_REWARD, + DMT_FREESTANDING_POH, + DMT_COW_GROTTO_COW, + + //Goron City + GC_MAZE_LEFT_CHEST, + GC_MAZE_CENTER_CHEST, + GC_MAZE_RIGHT_CHEST, + GC_ROLLING_GORON_AS_CHILD, + GC_ROLLING_GORON_AS_ADULT, + GC_DARUNIAS_JOY, + GC_POT_FREESTANDING_POH, + GC_DEKU_SCRUB_GROTTO_LEFT, + GC_DEKU_SCRUB_GROTTO_RIGHT, + GC_DEKU_SCRUB_GROTTO_CENTER, + GC_MEDIGORON, + + //Goron City Shop + GC_SHOP_ITEM_1, + GC_SHOP_ITEM_2, + GC_SHOP_ITEM_3, + GC_SHOP_ITEM_4, + GC_SHOP_ITEM_5, + GC_SHOP_ITEM_6, + GC_SHOP_ITEM_7, + GC_SHOP_ITEM_8, + + //Death Mountain + DMC_UPPER_GROTTO_CHEST, + DMC_WALL_FREESTANDING_POH, + DMC_VOLCANO_FREESTANDING_POH, + SHEIK_IN_CRATER, + DMC_DEKU_SCRUB, + DMC_GREAT_FAIRY_REWARD, + DMC_DEKU_SCRUB_GROTTO_LEFT, + DMC_DEKU_SCRUB_GROTTO_RIGHT, + DMC_DEKU_SCRUB_GROTTO_CENTER, + + //Zoras River + ZR_OPEN_GROTTO_CHEST, + ZR_MAGIC_BEAN_SALESMAN, + ZR_FROGS_IN_THE_RAIN, + ZR_FROGS_OCARINA_GAME, + ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, + ZR_NEAR_DOMAIN_FREESTANDING_POH, + ZR_DEKU_SCRUB_GROTTO_REAR, + ZR_DEKU_SCRUB_GROTTO_FRONT, + + //Zoras Domain + ZD_CHEST, + ZD_DIVING_MINIGAME, + ZD_KING_ZORA_THAWED, + ZD_TRADE_PRESCRIPTION, + + //Zora's Domain Shop + ZD_SHOP_ITEM_1, + ZD_SHOP_ITEM_2, + ZD_SHOP_ITEM_3, + ZD_SHOP_ITEM_4, + ZD_SHOP_ITEM_5, + ZD_SHOP_ITEM_6, + ZD_SHOP_ITEM_7, + ZD_SHOP_ITEM_8, + + //Zoras Fountain + ZF_ICEBERG_FREESTANDING_POH, + ZF_BOTTOM_FREESTANDING_POH, + ZF_GREAT_FAIRY_REWARD, + + //Lon Lon Ranch + SONG_FROM_MALON, + LLR_TALONS_CHICKENS, + LLR_FREESTANDING_POH, + LLR_DEKU_SCRUB_GROTTO_LEFT, + LLR_DEKU_SCRUB_GROTTO_RIGHT, + LLR_DEKU_SCRUB_GROTTO_CENTER, + LLR_STABLES_LEFT_COW, + LLR_STABLES_RIGHT_COW, + LLR_TOWER_LEFT_COW, + LLR_TOWER_RIGHT_COW, + + /*------------------------------- + --- GOLD SKULLTULA TOKENS --- + -------------------------------*/ + + //Overworld + KF_GS_BEAN_PATCH, + KF_GS_KNOW_IT_ALL_HOUSE, + KF_GS_HOUSE_OF_TWINS, + + LW_GS_BEAN_PATCH_NEAR_BRIDGE, + LW_GS_BEAN_PATCH_NEAR_THEATER, + LW_GS_ABOVE_THEATER, + SFM_GS, + + HF_GS_COW_GROTTO, + HF_GS_NEAR_KAK_GROTTO, + + LH_GS_BEAN_PATCH, + LH_GS_SMALL_ISLAND, + LH_GS_LAB_WALL, + LH_GS_LAB_CRATE, + LH_GS_TREE, + + GV_GS_BEAN_PATCH, + GV_GS_SMALL_BRIDGE, + GV_GS_PILLAR, + GV_GS_BEHIND_TENT, + + GF_GS_ARCHERY_RANGE, + GF_GS_TOP_FLOOR, + + WASTELAND_GS, + COLOSSUS_GS_BEAN_PATCH, + COLOSSUS_GS_HILL, + COLOSSUS_GS_TREE, + + OGC_GS, + HC_GS_STORMS_GROTTO, + HC_GS_TREE, + MARKET_GS_GUARD_HOUSE, + + KAK_GS_HOUSE_UNDER_CONSTRUCTION, + KAK_GS_SKULLTULA_HOUSE, + KAK_GS_GUARDS_HOUSE, + KAK_GS_TREE, + KAK_GS_WATCHTOWER, + KAK_GS_ABOVE_IMPAS_HOUSE, + + DMC_GS_BEAN_PATCH, + DMC_GS_CRATE, + + DMT_GS_BEAN_PATCH, + DMT_GS_NEAR_KAK, + DMT_GS_ABOVE_DODONGOS_CAVERN, + DMT_GS_FALLING_ROCKS_PATH, + + GC_GS_CENTER_PLATFORM, + GC_GS_BOULDER_MAZE, + GRAVEYARD_GS_WALL, + GRAVEYARD_GS_BEAN_PATCH, + + ZR_GS_LADDER, + ZR_GS_TREE, + ZR_GS_ABOVE_BRIDGE, + ZR_GS_NEAR_RAISED_GROTTOS, + + ZD_GS_FROZEN_WATERFALL, + ZF_GS_ABOVE_THE_LOG, + ZF_GS_HIDDEN_CAVE, + ZF_GS_TREE, + + LLR_GS_BACK_WALL, + LLR_GS_RAIN_SHED, + LLR_GS_HOUSE_WINDOW, + LLR_GS_TREE, +}; + +ItemLocation* Location(uint32_t locKey) { + return &(locationTable[locKey]); +} + +std::vector allLocations = {}; +std::vector everyPossibleLocation = {}; + +//set of overrides to write to the patch +std::set overrides = {}; + +std::vector> playthroughLocations; +std::vector wothLocations; +bool playthroughBeatable = false; +bool allLocationsReachable = false; +bool showItemProgress = false; + +uint16_t itemsPlaced = 0; + +void AddLocation(uint32_t loc, std::vector* destination = &allLocations) { + destination->push_back(loc); +} + +template +void AddLocations(const Container& locations, std::vector* destination = &allLocations) { + destination->insert(destination->end(), std::cbegin(locations), std::cend(locations)); +} + +//sort through Vanilla and MQ dungeon locations +void GenerateLocationPool() { + + allLocations.clear(); + AddLocation(LINKS_POCKET); + AddLocations(overworldLocations); + + for (auto dungeon : Dungeon::dungeonList) { + AddLocations(dungeon->GetDungeonLocations()); + } +} + +void PlaceItemInLocation(uint32_t locKey, uint32_t item, bool applyEffectImmediately /*= false*/, bool setHidden /*= false*/) { + auto loc = Location(locKey); + SPDLOG_INFO("\n"); + SPDLOG_INFO(ItemTable(item).GetName().GetEnglish()); + SPDLOG_INFO(" placed at "); + SPDLOG_INFO(loc->GetName()); + SPDLOG_INFO("\n\n"); + + if (applyEffectImmediately || Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) { + ItemTable(item).ApplyEffect(); + } + + itemsPlaced++; + if (showItemProgress) { + double completion = (double) itemsPlaced / (double)(allLocations.size() + dungeonRewardLocations.size()); + std::string message = "\x1b[8;10HPlacing Items."; + message += completion > 0.25 ? "." : " "; + message += completion > 0.50 ? "." : " "; + printf("%s", message.c_str()); + } + + //If we're placing a non-shop item in a shop location, we want to record it for custom messages + if (ItemTable(item).GetItemType() != ITEMTYPE_SHOP && loc->IsCategory(Category::cShop)) { + int index = TransformShopIndex(GetShopIndex(locKey)); + NonShopItems[index].Name = ItemTable(item).GetName(); + NonShopItems[index].Repurchaseable = ItemTable(item).GetItemType() == ITEMTYPE_REFILL || ItemTable(item).GetHintKey() == PROGRESSIVE_BOMBCHUS; + } + + loc->SetPlacedItem(item); + if (setHidden) { + loc->SetHidden(true); + } +} + +std::vector GetLocations(const std::vector& locationPool, Category categoryInclude, Category categoryExclude /*= Category::cNull*/) { + std::vector locationsInCategory; + for (uint32_t locKey : locationPool) { + if (Location(locKey)->IsCategory(categoryInclude) && !Location(locKey)->IsCategory(categoryExclude)) { + locationsInCategory.push_back(locKey); + } + } + return locationsInCategory; +} + +void LocationReset() { + for (uint32_t il : allLocations) { + Location(il)->RemoveFromPool(); + } + + for (uint32_t il : dungeonRewardLocations) { + Location(il)->RemoveFromPool(); + } + + for (uint32_t il : gossipStoneLocations) { + Location(il)->RemoveFromPool(); + } + + Location(GANONDORF_HINT)->RemoveFromPool(); +} + +void ItemReset() { + for (uint32_t il : allLocations) { + Location(il)->ResetVariables(); + } + + for (uint32_t il : dungeonRewardLocations) { + Location(il)->ResetVariables(); + } + + itemsPlaced = 0; +} + +void HintReset() { + for (uint32_t il : gossipStoneLocations) { + Location(il)->ResetVariables(); + } +} + +//Fills everyPossibleLocation and creates an exclusion option for each location. +//everyPossibleLocation is used in the menu to lock/hide excluding locations +void AddExcludedOptions() { + AddLocations(overworldLocations, &everyPossibleLocation); + + for (auto dungeon : Dungeon::dungeonList) { + AddLocations(dungeon->GetEveryLocation(), &everyPossibleLocation); + } + + for (uint32_t il: everyPossibleLocation) { + Location(il)->AddExcludeOption(); + } +} + +void CreateItemOverrides() { + SPDLOG_INFO("NOW CREATING OVERRIDES\n\n"); + for (uint32_t locKey : allLocations) { + auto loc = Location(locKey); + ItemOverride_Value val = ItemTable(loc->GetPlaceduint32_t()).Value(); + // If this is an ice trap in a shop, change the name based on what the model will look like + if (loc->GetPlaceduint32_t() == ICE_TRAP && loc->IsCategory(Category::cShop)) { + NonShopItems[TransformShopIndex(GetShopIndex(locKey))].Name = GetIceTrapName(val.looksLikeItemId); + } + overrides.insert({ + .key = loc->Key(), + .value = val, + }); + SPDLOG_INFO("\tScene: "); + SPDLOG_INFO(std::to_string(loc->Key().scene)); + SPDLOG_INFO("\tType: "); + SPDLOG_INFO(std::to_string(loc->Key().type)); + SPDLOG_INFO("\tFlag: "); + SPDLOG_INFO(std::to_string(loc->Key().flag)); + SPDLOG_INFO("\t"); + SPDLOG_INFO(loc->GetName()); + SPDLOG_INFO(": "); + SPDLOG_INFO(loc->GetPlacedItemName().GetEnglish()); + SPDLOG_INFO("\n"); + } + SPDLOG_INFO("Overrides Created: "); + SPDLOG_INFO(std::to_string(overrides.size())); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.hpp b/soh/soh/Enhancements/randomizer/3drando/item_location.hpp new file mode 100644 index 000000000..2f6bdc52d --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.hpp @@ -0,0 +1,490 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "spoiler_log.hpp" +#include "item_list.hpp" + +enum ItemOverride_Type { + OVR_BASE_ITEM = 0, + OVR_CHEST = 1, + OVR_COLLECTABLE = 2, + OVR_SKULL = 3, + OVR_GROTTO_SCRUB = 4, + OVR_DELAYED = 5, + OVR_TEMPLE = 6, +}; + +typedef enum { + DUNGEON_DEKU_TREE = 0, + DUNGEON_DODONGOS_CAVERN, + DUNGEON_JABUJABUS_BELLY, + DUNGEON_FOREST_TEMPLE, + DUNGEON_FIRE_TEMPLE, + DUNGEON_WATER_TEMPLE, + DUNGEON_SPIRIT_TEMPLE, + DUNGEON_SHADOW_TEMPLE, + DUNGEON_BOTTOM_OF_THE_WELL, + DUNGEON_ICE_CAVERN, + DUNGEON_GANONS_CASTLE_SECOND_PART, + DUNGEON_GERUDO_TRAINING_GROUNDS, + DUNGEON_GERUDO_FORTRESS, + DUNGEON_GANONS_CASTLE_FIRST_PART, + DUNGEON_GANONS_CASTLE_FLOOR_BENEATH_BOSS_CHAMBER, + DUNGEON_GANONS_CASTLE_CRUMBLING, + DUNGEON_TREASURE_CHEST_SHOP, + DUNGEON_DEKU_TREE_BOSS_ROOM, + DUNGEON_DODONGOS_CAVERN_BOSS_ROOM, + DUNGEON_JABUJABUS_BELLY_BOSS_ROOM, +} DungeonId; + +typedef union ItemOverride_Key { + uint32_t all; + struct { + char pad_; + uint8_t scene; + uint8_t type; + uint8_t flag; + }; +} ItemOverride_Key; + +typedef union ItemOverride_Value { + uint32_t all; + struct { + uint16_t itemId; + uint8_t player; + uint8_t looksLikeItemId; + }; +} ItemOverride_Value; + +typedef struct ItemOverride { + ItemOverride_Key key; + ItemOverride_Value value; +} ItemOverride; + +class Entrance; + +enum class ItemLocationType { + Base, + Chest, + Collectable, + GSToken, + GrottoScrub, + Delayed, + TempleReward, + HintStone, + OtherHint, +}; + +class SpoilerCollectionCheck { +public: + SpoilerCollectionCheckType type = SpoilerCollectionCheckType::SPOILER_CHK_NONE; + uint8_t scene = 0; + uint8_t flag = 0; + + SpoilerCollectionCheck() {} + SpoilerCollectionCheck(SpoilerCollectionCheckType type_, uint8_t scene_, uint8_t flag_) : type(type_), scene(scene_), flag(flag_) {} + + static auto None() { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_NONE, 0x00, 0x00); + } + + static auto AlwaysCollected() { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_ALWAYS_COLLECTED, 0x00, 0x00); + } + + static auto ItemGetInf(uint8_t slot) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_ITEM_GET_INF, 0x00, slot); + } + + static auto EventChkInf(uint8_t flag) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_EVENT_CHK_INF, 0xFF, flag); + } + + static auto InfTable(uint8_t offset, uint8_t bit) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_INF_TABLE, offset, bit); + } + + static auto Collectable(uint8_t scene, uint8_t flag) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_COLLECTABLE, scene, flag); + } + + static auto Chest(uint8_t scene, uint8_t flag) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_CHEST, scene, flag); + } + + static auto Cow(uint8_t scene, uint8_t flag) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_COW, scene, flag); + } + + static auto Fishing(uint8_t bit) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_MINIGAME, 0x00, bit); + } + + static auto Scrub(uint8_t scene, uint8_t bit) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_SCRUB, scene, bit); + } + + static auto Biggoron(uint8_t mask) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_BIGGORON, 0x00, mask); + } + + static auto GerudoToken() { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_GERUDO_MEMBERSHIP_CARD, 0x00, 0x00); + } + + static auto BigPoePoints() { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_POE_POINTS, 0x00, 0x00); + } + + static auto ShopItem(uint8_t scene, uint8_t itemSlot) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_SHOP_ITEM, scene, itemSlot); + } + + static auto MagicBeans(uint8_t scene, uint8_t flag) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_MAGIC_BEANS, scene, flag); + } +}; + +class ItemLocation { +public: + ItemLocation() = default; + ItemLocation(uint8_t scene_, ItemLocationType type_, uint8_t flag_, std::string name_, uint32_t hintKey_, uint32_t vanillaItem_, std::vector categories_, uint16_t price_ = 0, SpoilerCollectionCheck collectionCheck_ = SpoilerCollectionCheck(), SpoilerCollectionCheckGroup collectionCheckGroup_ = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) + : scene(scene_), type(type_), flag(flag_), name(std::move(name_)), hintKey(hintKey_), vanillaItem(vanillaItem_), categories(std::move(categories_)), price(price_), collectionCheck(collectionCheck_), collectionCheckGroup(collectionCheckGroup_) {} + + ItemOverride_Key Key() const { + ItemOverride_Key key; + key.all = 0; + + key.scene = scene; + key.type = static_cast(type); //TODO make sure these match up + key.flag = flag; + return key; + } + + SpoilerCollectionCheck GetCollectionCheck() const { + return collectionCheck; + } + + SpoilerCollectionCheckGroup GetCollectionCheckGroup() const { + return collectionCheckGroup; + } + + uint8_t GetScene() const { + return scene; + } + + uint8_t GetFlag() const { + return flag; + } + + bool IsAddedToPool() const { + return addedToPool; + } + + void AddToPool() { + addedToPool = true; + } + + const uint32_t GetHintKey() const { + return hintKey; + } + + void RemoveFromPool() { + addedToPool = false; + } + + const std::string& GetName() const { + return name; + } + + const Text& GetPlacedItemName() const { + return ItemTable(placedItem).GetName(); + } + + const Item& GetPlacedItem() const { + return ItemTable(placedItem); + } + + uint32_t GetPlacedItemKey() const { + return placedItem; + } + + uint32_t GetPlaceduint32_t() const { + return placedItem; + } + + void SetPlacedItem(const uint32_t item) { + placedItem = item; + SetPrice(ItemTable(placedItem).GetPrice()); + } + + //Saves an item to be set as placedItem later + void SetDelayedItem(const uint32_t item) { + delayedItem = item; + } + + //Place the vanilla item in this location + void PlaceVanillaItem() { + placedItem = vanillaItem; + } + + void ApplyPlacedItemEffect() { + ItemTable(placedItem).ApplyEffect(); + } + + //Set placedItem as item saved in SetDelayedItem + void SaveDelayedItem() { + placedItem = delayedItem; + delayedItem = NONE; + } + + uint16_t GetPrice() const { + if (ItemTable(placedItem).GetItemType() == ITEMTYPE_SHOP) { + return ItemTable(placedItem).GetPrice(); + } + return price; + } + + void SetPrice(uint16_t price_) { + //don't override price if the price was set for shopsanity + if (hasShopsanityPrice) { + return; + } + price = price_; + } + + void SetShopsanityPrice(uint16_t price_) { + price = price_; + hasShopsanityPrice = true; + } + + bool HasShopsanityPrice() const { + return hasShopsanityPrice; + } + + bool IsExcluded() const { + return excludedOption.Value(); + } + + bool IsCategory(Category category) const { + return std::any_of(categories.begin(), categories.end(), + [category](auto entry) { return entry == category; }); + } + + bool IsDungeon() const { + return (type != ItemLocationType::GSToken && (scene < 0x0E || (scene > 0x10 && scene < 0x1A))) || (type == ItemLocationType::GSToken && scene < 0x0A); + } + + bool IsOverworld() const { + return !IsDungeon(); + } + + bool IsShop() const { + return (scene >= 0x2C && scene <= 0x32); + } + + Option * GetExcludedOption() { + return &excludedOption; + } + + const uint32_t Getuint32_t() const { + return hintKey; + } + + const HintText& GetHint() const { + return Hint(hintKey); + } + + bool IsHintedAt() const { + return hintedAt; + } + + void SetAsHinted() { + hintedAt = true; + } + + bool IsHidden() const { + return hidden; + } + + void SetHidden(const bool hidden_) { + hidden = hidden_; + } + + bool IsHintable() const { + return isHintable; + } + + void SetAsHintable() { + isHintable = true; + } + + void SetParentRegion(uint32_t region) { + parentRegion = region; + } + + uint32_t GetParentRegionKey() const { + return parentRegion; + } + + void AddExcludeOption() { + //setting description /*--------------------------------------------------*/ + std::string_view desc = "Decide which locations you want to exclude from\n" + "the location pool. Locations that require an item\n" + "to be placed at them based on your current\n" + "settings cannot be excluded and won't be shown\n" + "unless you change your settings.\n" + "\n" + "If you exclude too many locations, it might not\n" + "be possible to fill the world."; + + //add option to forbid any location from progress items + if (name.length() < 23) { + excludedOption = Option::Bool(name, {"Include", "Exclude"}, {desc}); + } else { + //insert a newline character if the text is too long for one row + size_t lastSpace = name.rfind(' ', 23); + std::string settingText = name; + settingText.replace(lastSpace, 1, "\n "); + + excludedOption = Option::Bool(settingText, {"Include", "Exclude"}, {desc}); + } + + // RANDOTODO: this without string compares and loops + bool alreadyAdded = false; + for(const Option* location : Settings::excludeLocationsOptionsVector[collectionCheckGroup]) { + if (location->GetName() == excludedOption.GetName()) { + alreadyAdded = true; + } + } + if (!alreadyAdded) { + Settings::excludeLocationsOptionsVector[collectionCheckGroup].push_back(&excludedOption); + } + } + + static auto Base(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Base, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto Chest(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Chest, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_CHEST, scene, flag), collectionCheckGroup}; + } + + static auto Chest(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck, SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Chest, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto Collectable(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Collectable, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_COLLECTABLE, scene, flag), collectionCheckGroup}; + } + + static auto Collectable(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck, SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Collectable, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto GSToken(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, std::vector&& categories, SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::GSToken, flag, std::move(name), hintKey, GOLD_SKULLTULA_TOKEN, std::move(categories), 0, SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_GOLD_SKULLTULA, scene, flag), collectionCheckGroup}; + } + + static auto GrottoScrub(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::GrottoScrub, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto Delayed(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Delayed, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto Reward(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::TempleReward, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto OtherHint(uint8_t scene, uint8_t flag, std::string&& name, std::vector&& categories) { + return ItemLocation{scene, ItemLocationType::OtherHint, flag, std::move(name), NONE, NONE, std::move(categories)}; + } + + static auto HintStone(uint8_t scene, uint8_t flag, std::string&& name, std::vector&& categories) { + return ItemLocation{scene, ItemLocationType::HintStone, flag, std::move(name), NONE, NONE, std::move(categories)}; + } + + void ResetVariables() { + checked = false; + addedToPool = false; + placedItem = NONE; + delayedItem = NONE; + hintedAt = false; + isHintable = false; + price = 0; + hasShopsanityPrice = false; + hidden = false; + } + +private: + uint8_t scene; + ItemLocationType type; + uint8_t flag; + bool checked = false; + + std::string name; + uint32_t hintKey = NONE; + uint32_t vanillaItem = NONE; + bool hintedAt = false; + std::vector categories; + bool addedToPool = false; + uint32_t placedItem = NONE; + uint32_t delayedItem = NONE; + Option excludedOption = Option::Bool(name, {"Include", "Exclude"}, {"", ""}); + uint16_t price = 0; + SpoilerCollectionCheck collectionCheck; + SpoilerCollectionCheckGroup collectionCheckGroup; + bool isHintable = false; + uint32_t parentRegion = NONE; + bool hasShopsanityPrice = false; + bool hidden = false; +}; + +class ItemOverride_Compare { +public: + bool operator()(ItemOverride lhs, ItemOverride rhs) const { + return lhs.key.all < rhs.key.all; + } +}; + +void LocationTable_Init(); + +ItemLocation* Location(uint32_t locKey); + +extern std::vector> ShopLocationLists; + +extern std::vector gossipStoneLocations; + +extern std::vector dungeonRewardLocations; +extern std::vector overworldLocations; +extern std::vector allLocations; +extern std::vector everyPossibleLocation; + +//set of overrides to write to the patch +extern std::set overrides; + +extern std::vector> playthroughLocations; +extern std::vector wothLocations; +extern bool playthroughBeatable; +extern bool allLocationsReachable; +extern bool showItemProgress; + +extern uint16_t itemsPlaced; + +void GenerateLocationPool(); +void PlaceItemInLocation(uint32_t loc, uint32_t item, bool applyEffectImmediately = false, bool setHidden = false); +std::vector GetLocations(const std::vector& locationPool, Category categoryInclude, + Category categoryExclude = Category::cNull); +void LocationReset(); +void ItemReset(); +void HintReset(); +void AddExcludedOptions(); +void CreateItemOverrides(); diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp new file mode 100644 index 000000000..b46ad395f --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -0,0 +1,1179 @@ +#include "item_pool.hpp" + +#include "dungeon.hpp" +#include "fill.hpp" +#include "item_list.hpp" +#include "item_location.hpp" +#include "pool_functions.hpp" +#include "random.hpp" +#include "settings.hpp" +#include "spoiler_log.hpp" +#include "z64item.h" +#include + + +using namespace Settings; +using namespace Dungeon; + +std::vector ItemPool = {}; +std::vector PendingJunkPool = {}; +std::vector IceTrapModels = {}; +const std::array dungeonRewards = { + KOKIRI_EMERALD, + GORON_RUBY, + ZORA_SAPPHIRE, + FOREST_MEDALLION, + FIRE_MEDALLION, + WATER_MEDALLION, + SPIRIT_MEDALLION, + SHADOW_MEDALLION, + LIGHT_MEDALLION, +}; +const std::array JunkPoolItems = { + BOMBS_5, + BOMBS_10, + BOMBS_20, + DEKU_NUTS_5, + DEKU_STICK_1, + DEKU_SEEDS_30, + RECOVERY_HEART, + ARROWS_5, + ARROWS_10, + ARROWS_30, + BLUE_RUPEE, + RED_RUPEE, + PURPLE_RUPEE, + HUGE_RUPEE, + DEKU_NUTS_10, + ICE_TRAP, +}; +const std::array alwaysItems = { + BIGGORON_SWORD, + BOOMERANG, + LENS_OF_TRUTH, + MEGATON_HAMMER, + IRON_BOOTS, + GORON_TUNIC, + ZORA_TUNIC, + HOVER_BOOTS, + MIRROR_SHIELD, + STONE_OF_AGONY, + FIRE_ARROWS, + ICE_ARROWS, + LIGHT_ARROWS, + DINS_FIRE, + FARORES_WIND, + NAYRUS_LOVE, + GREEN_RUPEE, + PROGRESSIVE_HOOKSHOT, //2 progressive hookshots + PROGRESSIVE_HOOKSHOT, + DEKU_SHIELD, + HYLIAN_SHIELD, + PROGRESSIVE_STRENGTH, //3 progressive strength upgrades + PROGRESSIVE_STRENGTH, + PROGRESSIVE_STRENGTH, + PROGRESSIVE_SCALE, //2 progressive scales + PROGRESSIVE_SCALE, + PROGRESSIVE_BOW, //3 progressive Bows + PROGRESSIVE_BOW, + PROGRESSIVE_BOW, + PROGRESSIVE_SLINGSHOT, //3 progressive bullet bags + PROGRESSIVE_SLINGSHOT, + PROGRESSIVE_SLINGSHOT, + PROGRESSIVE_BOMB_BAG, //3 progressive bomb bags + PROGRESSIVE_BOMB_BAG, + PROGRESSIVE_BOMB_BAG, + PROGRESSIVE_WALLET, //2 progressive wallets + PROGRESSIVE_WALLET, + PROGRESSIVE_MAGIC_METER, //2 progressive magic meters + PROGRESSIVE_MAGIC_METER, + DOUBLE_DEFENSE, + PROGRESSIVE_STICK_UPGRADE, //2 stick upgrades + PROGRESSIVE_STICK_UPGRADE, + PROGRESSIVE_NUT_UPGRADE, //2 nut upgrades + PROGRESSIVE_NUT_UPGRADE, + RECOVERY_HEART, //6 recovery hearts + RECOVERY_HEART, + RECOVERY_HEART, + RECOVERY_HEART, + RECOVERY_HEART, + RECOVERY_HEART, + BOMBS_5, //2 + BOMBS_5, + BOMBS_10, + BOMBS_20, + ARROWS_5, + ARROWS_10, //5 + ARROWS_10, + ARROWS_10, + TREASURE_GAME_HEART, +}; +const std::array easyItems = { + BIGGORON_SWORD, + KOKIRI_SWORD, + BOOMERANG, + LENS_OF_TRUTH, + MEGATON_HAMMER, + IRON_BOOTS, + GORON_TUNIC, + ZORA_TUNIC, + HOVER_BOOTS, + MIRROR_SHIELD, + FIRE_ARROWS, + LIGHT_ARROWS, + DINS_FIRE, + PROGRESSIVE_HOOKSHOT, + PROGRESSIVE_STRENGTH, + PROGRESSIVE_SCALE, + PROGRESSIVE_WALLET, + PROGRESSIVE_MAGIC_METER, + PROGRESSIVE_STICK_UPGRADE, + PROGRESSIVE_NUT_UPGRADE, + PROGRESSIVE_BOW, + PROGRESSIVE_SLINGSHOT, + PROGRESSIVE_BOMB_BAG, + DOUBLE_DEFENSE, + HEART_CONTAINER, //16 Heart Containers + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + PIECE_OF_HEART, //3 heart pieces + PIECE_OF_HEART, + PIECE_OF_HEART, +}; +const std::array normalItems = { + PIECE_OF_HEART, //35 pieces of heart + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + HEART_CONTAINER, //8 heart containers + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, +}; +const std::array DT_Vanilla = { + RECOVERY_HEART, + RECOVERY_HEART, +}; +const std::array DT_MQ = { + DEKU_SHIELD, + DEKU_SHIELD, + PURPLE_RUPEE, +}; +const std::array DC_Vanilla = { + RED_RUPEE, +}; +const std::array DC_MQ = { + HYLIAN_SHIELD, + BLUE_RUPEE, +}; +const std::array JB_MQ = { + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_NUTS_5, + RECOVERY_HEART, + DEKU_SHIELD, + DEKU_STICK_1, +}; +const std::array FoT_Vanilla = { + RECOVERY_HEART, + ARROWS_10, + ARROWS_30, +}; +const std::array FoT_MQ = { + ARROWS_5, +}; +const std::array FiT_Vanilla = { + HUGE_RUPEE, +}; +const std::array FiT_MQ = { + BOMBS_20, + HYLIAN_SHIELD, +}; +const std::array SpT_Vanilla = { + DEKU_SHIELD, + DEKU_SHIELD, + RECOVERY_HEART, + BOMBS_20, +}; +const std::array SpT_MQ = { + PURPLE_RUPEE, + PURPLE_RUPEE, + ARROWS_30, +}; +const std::array ShT_Vanilla = { + ARROWS_30, +}; +const std::array ShT_MQ = { + ARROWS_5, + ARROWS_5, + RED_RUPEE, +}; +const std::array BW_Vanilla = { + RECOVERY_HEART, + BOMBS_10, + HUGE_RUPEE, + DEKU_NUTS_5, + DEKU_NUTS_10, + DEKU_SHIELD, + HYLIAN_SHIELD, +}; +const std::array GTG_Vanilla = { + ARROWS_30, + ARROWS_30, + ARROWS_30, + HUGE_RUPEE, +}; +const std::array GTG_MQ = { + TREASURE_GAME_GREEN_RUPEE, + TREASURE_GAME_GREEN_RUPEE, + ARROWS_10, + GREEN_RUPEE, + PURPLE_RUPEE, +}; +const std::array GC_Vanilla = { + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + ARROWS_30, +}; +const std::array GC_MQ = { + ARROWS_10, + ARROWS_10, + BOMBS_5, + RED_RUPEE, + RECOVERY_HEART, +}; +const std::array normalBottles = { + EMPTY_BOTTLE, + BOTTLE_WITH_MILK, + BOTTLE_WITH_RED_POTION, + BOTTLE_WITH_GREEN_POTION, + BOTTLE_WITH_BLUE_POTION, + BOTTLE_WITH_FAIRY, + BOTTLE_WITH_FISH, + BOTTLE_WITH_BUGS, + BOTTLE_WITH_POE, + BOTTLE_WITH_BIG_POE, + BOTTLE_WITH_BLUE_FIRE, +}; +const std::array normalRupees = { + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, +}; +const std::array shopsanityRupees = { + BLUE_RUPEE, + BLUE_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, + PROGRESSIVE_WALLET, +}; +const std::array dekuScrubItems = { + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_STICK_1, + BOMBS_5, + BOMBS_5, + BOMBS_5, + BOMBS_5, + BOMBS_5, + RECOVERY_HEART, + RECOVERY_HEART, + RECOVERY_HEART, + RECOVERY_HEART, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, +}; +const std::array songList = { + ZELDAS_LULLABY, + EPONAS_SONG, + SUNS_SONG, + SARIAS_SONG, + SONG_OF_TIME, + SONG_OF_STORMS, + MINUET_OF_FOREST, + PRELUDE_OF_LIGHT, + BOLERO_OF_FIRE, + SERENADE_OF_WATER, + NOCTURNE_OF_SHADOW, + REQUIEM_OF_SPIRIT, +}; +const std::array tradeItems = { + POCKET_EGG, + //POCKET_CUCCO, + COJIRO, + ODD_MUSHROOM, + POACHERS_SAW, + BROKEN_SWORD, + PRESCRIPTION, + EYEBALL_FROG, + EYEDROPS, + CLAIM_CHECK, +}; + +void AddItemToPool(std::vector& pool, uint32_t item, size_t count /*= 1*/) { + pool.insert(pool.end(), count, item); +} + +template +static void AddItemsToPool(std::vector& toPool, const FromPool& fromPool) { + AddElementsToPool(toPool, fromPool); +} + +static void AddItemToMainPool(const uint32_t item, size_t count = 1) { + ItemPool.insert(ItemPool.end(), count, item); +} + +static void AddRandomBottle(std::vector& bottlePool) { + AddItemToMainPool(RandomElement(bottlePool, true)); +} + +uint32_t GetJunkItem() { + if (IceTrapValue.Is(ICETRAPS_MAYHEM) || IceTrapValue.Is(ICETRAPS_ONSLAUGHT)) { + return ICE_TRAP; + } else if (IceTrapValue.Is(ICETRAPS_EXTRA)) { + return RandomElement(JunkPoolItems); + } + //Ice Trap is the last item in JunkPoolItems, so subtract 1 to never hit that index + uint8_t idx = Random(0, JunkPoolItems.size() - 1); + return JunkPoolItems[idx]; +} + +static uint32_t GetPendingJunkItem() { + if (PendingJunkPool.empty()) { + return GetJunkItem(); + } + + return RandomElement(PendingJunkPool, true); +} + +//Replace junk items in the pool with pending junk +static void ReplaceMaxItem(const uint32_t itemToReplace, int max) { + int itemCount = 0; + for (size_t i = 0; i < ItemPool.size(); i++) { + if (ItemPool[i] == itemToReplace) { + if (itemCount >= max) { + ItemPool[i] = GetJunkItem(); + } + itemCount++; + } + } +} + +void PlaceJunkInExcludedLocation(const uint32_t il) { + //place a non-advancement item in this location + for (size_t i = 0; i < ItemPool.size(); i++) { + if (!ItemTable(ItemPool[i]).IsAdvancement()) { + PlaceItemInLocation(il, ItemPool[i]); + ItemPool.erase(ItemPool.begin() + i); + return; + } + } + printf("ERROR: No Junk to Place!!!\n"); +} + +static void PlaceVanillaDekuScrubItems() { + PlaceItemInLocation(ZR_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true); + PlaceItemInLocation(ZR_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true); + PlaceItemInLocation(SFM_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true); + PlaceItemInLocation(SFM_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true); + PlaceItemInLocation(LH_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(LH_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true); + PlaceItemInLocation(LH_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(GV_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true); + PlaceItemInLocation(GV_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true); + PlaceItemInLocation(LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, DEKU_STICK_1, false, true); + PlaceItemInLocation(LW_DEKU_SCRUB_GROTTO_REAR, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(COLOSSUS_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true); + PlaceItemInLocation(COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true); + PlaceItemInLocation(DMC_DEKU_SCRUB, BOMBS_5, false, true); + PlaceItemInLocation(DMC_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(DMC_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true); + PlaceItemInLocation(DMC_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(GC_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(GC_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true); + PlaceItemInLocation(GC_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(LLR_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(LLR_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true); + PlaceItemInLocation(LLR_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true); + + //Dungeon Scrubs + if (DekuTree.IsMQ()) { + PlaceItemInLocation(DEKU_TREE_MQ_DEKU_SCRUB, DEKU_SHIELD, false, true); + } + if (DodongosCavern.IsMQ()) { + PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, DEKU_STICK_1, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, DEKU_SHIELD, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, RED_POTION_REFILL, false, true); + } else { + PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, DEKU_STICK_1, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, DEKU_SHIELD, false, true); + } + if (JabuJabusBelly.IsVanilla()) { + PlaceItemInLocation(JABU_JABUS_BELLY_DEKU_SCRUB, DEKU_NUTS_5); + } + if (GanonsCastle.IsMQ()) { + PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, GREEN_POTION_REFILL, false, true); + PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, BOMBS_5, false, true); + PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, ARROWS_30, false, true); + PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, RED_POTION_REFILL, false, true); + PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, DEKU_NUTS_5, false, true); + } else { + PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, BOMBS_5, false, true); + PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_RIGHT, RED_POTION_REFILL, false, true); + PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_LEFT, GREEN_POTION_REFILL, false, true); + } + + +} + +static void PlaceVanillaMapsAndCompasses() { + for (auto dungeon : dungeonList) { + dungeon->PlaceVanillaMap(); + dungeon->PlaceVanillaCompass(); + } +} + +static void PlaceVanillaSmallKeys() { + for (auto dungeon : dungeonList) { + dungeon->PlaceVanillaSmallKeys(); + } +} + +static void PlaceVanillaBossKeys() { + for (auto dungeon : dungeonList) { + dungeon->PlaceVanillaBossKey(); + } +} + +static void PlaceVanillaCowMilk() { + PlaceItemInLocation(KF_LINKS_HOUSE_COW, MILK, false, true); + PlaceItemInLocation(HF_COW_GROTTO_COW, MILK, false, true); + PlaceItemInLocation(GV_COW, MILK, false, true); + PlaceItemInLocation(KAK_IMPAS_HOUSE_COW, MILK, false, true); + PlaceItemInLocation(DMT_COW_GROTTO_COW, MILK, false, true); + PlaceItemInLocation(LLR_STABLES_LEFT_COW, MILK, false, true); + PlaceItemInLocation(LLR_STABLES_RIGHT_COW, MILK, false, true); + PlaceItemInLocation(LLR_TOWER_LEFT_COW, MILK, false, true); + PlaceItemInLocation(LLR_TOWER_RIGHT_COW, MILK, false, true); + + if (JabuJabusBelly.IsMQ()) { + PlaceItemInLocation(JABU_JABUS_BELLY_MQ_COW, MILK, false, true); + } +} + +static void SetScarceItemPool() { + ReplaceMaxItem(PROGRESSIVE_BOMBCHUS, 3); + ReplaceMaxItem(BOMBCHU_5, 1); + ReplaceMaxItem(BOMBCHU_10, 2); + ReplaceMaxItem(BOMBCHU_20, 0); + ReplaceMaxItem(PROGRESSIVE_MAGIC_METER, 1); + ReplaceMaxItem(DOUBLE_DEFENSE, 0); + ReplaceMaxItem(PROGRESSIVE_STICK_UPGRADE, 1); + ReplaceMaxItem(PROGRESSIVE_NUT_UPGRADE, 1); + ReplaceMaxItem(PROGRESSIVE_BOW, 2); + ReplaceMaxItem(PROGRESSIVE_SLINGSHOT, 2); + ReplaceMaxItem(PROGRESSIVE_BOMB_BAG, 2); + ReplaceMaxItem(HEART_CONTAINER, 0); +} + +static void SetMinimalItemPool() { + ReplaceMaxItem(PROGRESSIVE_BOMBCHUS, 1); + ReplaceMaxItem(BOMBCHU_5, 1); + ReplaceMaxItem(BOMBCHU_10, 0); + ReplaceMaxItem(BOMBCHU_20, 0); + ReplaceMaxItem(NAYRUS_LOVE, 0); + ReplaceMaxItem(PROGRESSIVE_MAGIC_METER, 1); + ReplaceMaxItem(DOUBLE_DEFENSE, 0); + ReplaceMaxItem(PROGRESSIVE_STICK_UPGRADE, 0); + ReplaceMaxItem(PROGRESSIVE_NUT_UPGRADE, 0); + ReplaceMaxItem(PROGRESSIVE_BOW, 1); + ReplaceMaxItem(PROGRESSIVE_SLINGSHOT, 1); + ReplaceMaxItem(PROGRESSIVE_BOMB_BAG, 1); + ReplaceMaxItem(PIECE_OF_HEART, 0); + // Need an extra heart container when starting with 1 heart to be able to reach 3 hearts + ReplaceMaxItem(HEART_CONTAINER, (StartingHearts.Value() == 18)? 1 : 0); +} + +void GenerateItemPool() { + + ItemPool.clear(); + PendingJunkPool.clear(); + + //Initialize ice trap models to always major items + IceTrapModels = { + GI_SHIELD_MIRROR, + GI_BOOMERANG, + GI_LENS, + GI_HAMMER, + GI_BOOTS_IRON, + GI_BOOTS_HOVER, + GI_STONE_OF_AGONY, + GI_DINS_FIRE, + GI_FARORES_WIND, + GI_NAYRUS_LOVE, + GI_ARROW_FIRE, + GI_ARROW_ICE, + GI_ARROW_LIGHT, + 0xB8, //Double defense + GI_CLAIM_CHECK, + 0x80, //Progressive hookshot + 0x81, //Progressive strength + 0x82, //Progressive bomb bag + 0x83, //Progressive bow + 0x84, //Progressive slingshot + 0x85, //Progressive wallet + 0x86, //Progressive scale + 0x8A, //Progressive magic + }; + //Check song shuffle and dungeon reward shuffle just for ice traps + if (ShuffleSongs.Is(SONGSHUFFLE_ANYWHERE)) { + //Push item ids for songs + IceTrapModels.push_back(0xC1); + IceTrapModels.push_back(0xC2); + IceTrapModels.push_back(0xC3); + IceTrapModels.push_back(0xC4); + IceTrapModels.push_back(0xC5); + IceTrapModels.push_back(0xC6); + IceTrapModels.push_back(0xBB); + IceTrapModels.push_back(0xBC); + IceTrapModels.push_back(0xBD); + IceTrapModels.push_back(0xBE); + IceTrapModels.push_back(0xBF); + IceTrapModels.push_back(0xC0); + } + if (ShuffleRewards.Is(REWARDSHUFFLE_ANYWHERE)) { + //Push item ids for dungeon rewards + IceTrapModels.push_back(0xCB); + IceTrapModels.push_back(0xCC); + IceTrapModels.push_back(0xCD); + IceTrapModels.push_back(0xCE); + IceTrapModels.push_back(0xCF); + IceTrapModels.push_back(0xD0); + IceTrapModels.push_back(0xD1); + IceTrapModels.push_back(0xD2); + IceTrapModels.push_back(0xD3); + } + + //Fixed item locations + PlaceItemInLocation(HC_ZELDAS_LETTER, ZELDAS_LETTER); + PlaceItemInLocation(GANON, TRIFORCE); //The Triforce is only used to make sure Ganon is accessible + PlaceItemInLocation(MARKET_BOMBCHU_BOWLING_BOMBCHUS, BOMBCHU_DROP); + + if (ShuffleKokiriSword) { + AddItemToMainPool(KOKIRI_SWORD); + IceTrapModels.push_back(GI_SWORD_KOKIRI); + } else { + PlaceItemInLocation(KF_KOKIRI_SWORD_CHEST, KOKIRI_SWORD, false, true); + } + + if (ShuffleWeirdEgg) { + AddItemToMainPool(WEIRD_EGG); + IceTrapModels.push_back(GI_WEIRD_EGG); + } else { + PlaceItemInLocation(HC_MALON_EGG, WEIRD_EGG, false, true); + } + + if (ShuffleOcarinas) { + AddItemToMainPool(PROGRESSIVE_OCARINA, 2); + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + AddItemToPool(PendingJunkPool, PROGRESSIVE_OCARINA); + } + IceTrapModels.push_back(0x8B); //Progressive ocarina + } else { + PlaceItemInLocation(LW_GIFT_FROM_SARIA, PROGRESSIVE_OCARINA, false, true); + PlaceItemInLocation(HF_OCARINA_OF_TIME_ITEM, PROGRESSIVE_OCARINA, false, true); + } + + if (ShuffleCows) { + //9 total cow locations + for (uint8_t i = 0; i < 9; i++) { + AddItemToMainPool(GetJunkItem()); + } + //extra location for Jabu MQ + if (JabuJabusBelly.IsMQ()) { + AddItemToMainPool(GetJunkItem()); + } + } else { + PlaceVanillaCowMilk(); + } + + if (ShuffleMagicBeans) { + AddItemToMainPool(MAGIC_BEAN_PACK); + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + AddItemToPool(PendingJunkPool, MAGIC_BEAN_PACK); + } + IceTrapModels.push_back(0xC9); //Magic bean pack + } else { + PlaceItemInLocation(ZR_MAGIC_BEAN_SALESMAN, MAGIC_BEAN, false, true); + } + + if (ShuffleMerchants.IsNot(SHUFFLEMERCHANTS_OFF)) { + if (!ProgressiveGoronSword) { + AddItemToMainPool(GIANTS_KNIFE); + } + if (BombchusInLogic) { + AddItemToMainPool(PROGRESSIVE_BOMBCHUS); + } else { + AddItemToMainPool(BOMBCHU_10); + } + } else { + PlaceItemInLocation(GC_MEDIGORON, GIANTS_KNIFE, false, true); + PlaceItemInLocation(WASTELAND_BOMBCHU_SALESMAN, BOMBCHU_10, false, true); + } + + if (ShuffleAdultTradeQuest) { + AddItemToMainPool(POCKET_EGG); + AddItemToMainPool(COJIRO); + AddItemToMainPool(ODD_MUSHROOM); + AddItemToMainPool(ODD_POTION); + AddItemToMainPool(POACHERS_SAW); + AddItemToMainPool(BROKEN_SWORD); + AddItemToMainPool(PRESCRIPTION); + AddItemToMainPool(EYEBALL_FROG); + AddItemToMainPool(EYEDROPS); + } else { + PlaceItemInLocation(KAK_TRADE_POCKET_CUCCO, COJIRO, false, true); + PlaceItemInLocation(LW_TRADE_COJIRO, ODD_MUSHROOM, false, true); + PlaceItemInLocation(KAK_TRADE_ODD_MUSHROOM, ODD_POTION, false, true); + PlaceItemInLocation(LW_TRADE_ODD_POTION, POACHERS_SAW, false, true); + PlaceItemInLocation(GV_TRADE_SAW, BROKEN_SWORD, false, true); + PlaceItemInLocation(DMT_TRADE_BROKEN_SWORD, PRESCRIPTION, false, true); + PlaceItemInLocation(ZD_TRADE_PRESCRIPTION, EYEBALL_FROG, false, true); + PlaceItemInLocation(LH_TRADE_FROG, EYEDROPS, false, true); + PlaceItemInLocation(DMT_TRADE_EYEDROPS, CLAIM_CHECK, false, true); + } + AddItemToMainPool(CLAIM_CHECK); + + if (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS)) { + AddItemToMainPool(TREASURE_GAME_SMALL_KEY, 6); // 6 individual keys + } else if (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK)) { + AddItemToMainPool(TREASURE_GAME_SMALL_KEY); // 1 key which will behave as a pack of 6 + } else { + PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_1, TREASURE_GAME_SMALL_KEY, false, true); + PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_2, TREASURE_GAME_SMALL_KEY, false, true); + PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_3, TREASURE_GAME_SMALL_KEY, false, true); + PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_4, TREASURE_GAME_SMALL_KEY, false, true); + PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_5, TREASURE_GAME_SMALL_KEY, false, true); + }; + + if (Tokensanity.Is(TOKENSANITY_OFF)) { + for (uint32_t loc : GetLocations(allLocations, Category::cSkulltula)) { + PlaceItemInLocation(loc, GOLD_SKULLTULA_TOKEN, false, true); + } + } else if (Tokensanity.Is(TOKENSANITY_DUNGEONS)) { + for (uint32_t loc : GetLocations(allLocations, Category::cSkulltula)) { + if (Location(loc)->IsOverworld()) { + PlaceItemInLocation(loc, GOLD_SKULLTULA_TOKEN, false, true); + } else { + AddItemToMainPool(GOLD_SKULLTULA_TOKEN); + } + } + } else if (Tokensanity.Is(TOKENSANITY_OVERWORLD)) { + for (uint32_t loc : GetLocations(allLocations, Category::cSkulltula)) { + if (Location(loc)->IsDungeon()) { + PlaceItemInLocation(loc, GOLD_SKULLTULA_TOKEN, false, true); + } else { + AddItemToMainPool(GOLD_SKULLTULA_TOKEN); + } + } + } else { + AddItemToMainPool(GOLD_SKULLTULA_TOKEN, 100); + } + + if (BombchusInLogic) { + AddItemToMainPool(PROGRESSIVE_BOMBCHUS, 5); + } else { + AddItemToMainPool(BOMBCHU_5); + AddItemToMainPool(BOMBCHU_10, 3); + AddItemToMainPool(BOMBCHU_20); + } + + //Ice Traps + AddItemToMainPool(ICE_TRAP); + if (GerudoTrainingGrounds.IsVanilla()) { + AddItemToMainPool(ICE_TRAP); + } + if (GanonsCastle.IsVanilla()) { + AddItemToMainPool(ICE_TRAP, 4); + } + + //Gerudo Fortress + if (GerudoFortress.Is(GERUDOFORTRESS_OPEN)) { + PlaceItemInLocation(GF_NORTH_F1_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_NORTH_F2_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, RECOVERY_HEART, false, true); + } else if (GerudoKeys.IsNot(GERUDOKEYS_VANILLA)) { + if (GerudoFortress.Is(GERUDOFORTRESS_FAST)) { + AddItemToMainPool(GERUDO_FORTRESS_SMALL_KEY); + PlaceItemInLocation(GF_NORTH_F2_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, RECOVERY_HEART, false, true); + } else { + //Only add key ring if 4 Fortress keys necessary + if (RingFortress) { + AddItemToMainPool(GERUDO_FORTRESS_KEY_RING); + //Add junk to make up for missing keys + for (uint8_t i = 0; i < 3; i++) { + AddItemToMainPool(GetJunkItem()); + } + } else { + AddItemToMainPool(GERUDO_FORTRESS_SMALL_KEY, 4); + } + } + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + if (RingFortress && GerudoFortress.Is(GERUDOFORTRESS_NORMAL)) { + AddItemToPool(PendingJunkPool, GERUDO_FORTRESS_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, GERUDO_FORTRESS_SMALL_KEY); + } + } + } else { + if (GerudoFortress.Is(GERUDOFORTRESS_FAST)) { + PlaceItemInLocation(GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true); + PlaceItemInLocation(GF_NORTH_F2_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, RECOVERY_HEART, false, true); + } else { + PlaceItemInLocation(GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true); + PlaceItemInLocation(GF_NORTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true); + PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true); + PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true); + } + } + + //Gerudo Membership Card + if (ShuffleGerudoToken && GerudoFortress.IsNot(GERUDOFORTRESS_OPEN)) { + AddItemToMainPool(GERUDO_MEMBERSHIP_CARD); + IceTrapModels.push_back(GI_GERUDO_CARD); + } else if (ShuffleGerudoToken) { + AddItemToPool(PendingJunkPool, GERUDO_MEMBERSHIP_CARD); + PlaceItemInLocation(GF_GERUDO_MEMBERSHIP_CARD, ICE_TRAP, false, true); + } else { + PlaceItemInLocation(GF_GERUDO_MEMBERSHIP_CARD, GERUDO_MEMBERSHIP_CARD, false, true); + } + + //Keys + + //For key rings, need to add as many junk items as "missing" keys + if (KeyRings) { + uint8_t ringJunkAmt = 0; + for (auto dungeon : dungeonList) { + if (dungeon->HasKeyRing()) { + ringJunkAmt += dungeon->GetSmallKeyCount() - 1; + } + } + for (uint8_t i = 0; i < ringJunkAmt; i++) { + AddItemToMainPool(GetJunkItem()); + } + } + + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + if (ShuffleGerudoToken) { + AddItemToPool(PendingJunkPool, GERUDO_MEMBERSHIP_CARD); + } + + //Plentiful small keys + if (Keysanity.Is(KEYSANITY_ANYWHERE) || Keysanity.Is(KEYSANITY_ANY_DUNGEON) || Keysanity.Is(KEYSANITY_OVERWORLD)) { + if (BottomOfTheWell.HasKeyRing()) { + AddItemToPool(PendingJunkPool, BOTTOM_OF_THE_WELL_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, BOTTOM_OF_THE_WELL_SMALL_KEY); + } + if (ForestTemple.HasKeyRing()) { + AddItemToPool(PendingJunkPool, FOREST_TEMPLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, FOREST_TEMPLE_SMALL_KEY); + } + if (FireTemple.HasKeyRing()) { + AddItemToPool(PendingJunkPool, FIRE_TEMPLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, FIRE_TEMPLE_SMALL_KEY); + } + if (WaterTemple.HasKeyRing()) { + AddItemToPool(PendingJunkPool, WATER_TEMPLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, WATER_TEMPLE_SMALL_KEY); + } + if (SpiritTemple.HasKeyRing()) { + AddItemToPool(PendingJunkPool, SPIRIT_TEMPLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, SPIRIT_TEMPLE_SMALL_KEY); + } + if (ShadowTemple.HasKeyRing()) { + AddItemToPool(PendingJunkPool, SHADOW_TEMPLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, SHADOW_TEMPLE_SMALL_KEY); + } + if (GerudoTrainingGrounds.HasKeyRing()) { + AddItemToPool(PendingJunkPool, GERUDO_TRAINING_GROUNDS_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, GERUDO_TRAINING_GROUNDS_SMALL_KEY); + } + if (GanonsCastle.HasKeyRing()) { + AddItemToPool(PendingJunkPool, GANONS_CASTLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, GANONS_CASTLE_SMALL_KEY); + } + } + + if (BossKeysanity.Is(BOSSKEYSANITY_ANYWHERE) || BossKeysanity.Is(BOSSKEYSANITY_ANY_DUNGEON) || BossKeysanity.Is(BOSSKEYSANITY_OVERWORLD)) { + AddItemToPool(PendingJunkPool, FOREST_TEMPLE_BOSS_KEY); + AddItemToPool(PendingJunkPool, FIRE_TEMPLE_BOSS_KEY); + AddItemToPool(PendingJunkPool, WATER_TEMPLE_BOSS_KEY); + AddItemToPool(PendingJunkPool, SPIRIT_TEMPLE_BOSS_KEY); + AddItemToPool(PendingJunkPool, SHADOW_TEMPLE_BOSS_KEY); + } + + if (GanonsBossKey.Is(GANONSBOSSKEY_ANYWHERE) || GanonsBossKey.Is(GANONSBOSSKEY_ANY_DUNGEON) || GanonsBossKey.Is(GANONSBOSSKEY_OVERWORLD)) { + AddItemToPool(PendingJunkPool, GANONS_CASTLE_BOSS_KEY); + } + } + + //Shopsanity + if (Settings::Shopsanity.Is(SHOPSANITY_OFF) || Settings::Shopsanity.Is(SHOPSANITY_ZERO)) { + AddItemsToPool(ItemPool, normalRupees); + } else { //Shopsanity 1-4, random + AddItemsToPool(ItemPool, shopsanityRupees); //Shopsanity gets extra large rupees + } + + //Scrubsanity + if (Settings::Scrubsanity.IsNot(SCRUBSANITY_OFF)) { + //Deku Tree + if (DekuTree.IsMQ()) { + AddItemToMainPool(DEKU_SHIELD); + } + + //Dodongos Cavern + AddItemToMainPool(DEKU_STICK_1); + AddItemToMainPool(DEKU_SHIELD); + if (DodongosCavern.IsMQ()) { + AddItemToMainPool(RECOVERY_HEART); + } else { + AddItemToMainPool(DEKU_NUTS_5); + } + + //Jabu Jabus Belly + if (JabuJabusBelly.IsVanilla()) { + AddItemToMainPool(DEKU_NUTS_5); + } + + //Ganons Castle + AddItemToMainPool(BOMBS_5); + AddItemToMainPool(RECOVERY_HEART); + AddItemToMainPool(BLUE_RUPEE); + if (GanonsCastle.IsMQ()) { + AddItemToMainPool(DEKU_NUTS_5); + } + + //Overworld Scrubs + AddItemsToPool(ItemPool, dekuScrubItems); + + //I'm not sure what this is for, but it was in ootr so I copied it + for (uint8_t i = 0; i < 7; i++) { + if (Random(0, 3)) { + AddItemToMainPool(ARROWS_30); + } else { + AddItemToMainPool(DEKU_SEEDS_30); + } + } + } else { + PlaceVanillaDekuScrubItems(); + } + + AddItemsToPool(ItemPool, alwaysItems); + AddItemsToPool(ItemPool, dungeonRewards); + + //Dungeon pools + if (DekuTree.IsMQ()) { + AddItemsToPool(ItemPool, DT_MQ); + } else { + AddItemsToPool(ItemPool, DT_Vanilla); + } + if (DodongosCavern.IsMQ()) { + AddItemsToPool(ItemPool, DC_MQ); + } else { + AddItemsToPool(ItemPool, DC_Vanilla); + } + if (JabuJabusBelly.IsMQ()) { + AddItemsToPool(ItemPool, JB_MQ); + } + if (ForestTemple.IsMQ()) { + AddItemsToPool(ItemPool, FoT_MQ); + } else { + AddItemsToPool(ItemPool, FoT_Vanilla); + } + if (FireTemple.IsMQ()) { + AddItemsToPool(ItemPool, FiT_MQ); + } else { + AddItemsToPool(ItemPool, FiT_Vanilla); + } + if (SpiritTemple.IsMQ()) { + AddItemsToPool(ItemPool, SpT_MQ); + } else { + AddItemsToPool(ItemPool, SpT_Vanilla); + } + if (ShadowTemple.IsMQ()) { + AddItemsToPool(ItemPool, ShT_MQ); + } else { + AddItemsToPool(ItemPool, ShT_Vanilla); + } + if (BottomOfTheWell.IsVanilla()) { + AddItemsToPool(ItemPool, BW_Vanilla); + } + if (GerudoTrainingGrounds.IsMQ()) { + AddItemsToPool(ItemPool, GTG_MQ); + } else { + AddItemsToPool(ItemPool, GTG_Vanilla); + } + if (GanonsCastle.IsMQ()) { + AddItemsToPool(ItemPool, GC_MQ); + } else { + AddItemsToPool(ItemPool, GC_Vanilla); + } + + uint8_t rutoBottles = 1; + if (ZorasFountain.Is(ZORASFOUNTAIN_OPEN)) { + rutoBottles = 0; + } + + //Add 4 total bottles + uint8_t bottleCount = 4; + std::vector bottles; + bottles.assign(normalBottles.begin(), normalBottles.end()); + IceTrapModels.push_back(ItemTable(RandomElement(bottles)).GetItemID()); //Get one random bottle type for ice traps + for (uint8_t i = 0; i < bottleCount; i++) { + if (i >= rutoBottles) { + AddRandomBottle(bottles); + } else { + AddItemToMainPool(RUTOS_LETTER); + } + } + + //add extra songs only if song shuffle is anywhere + AddItemsToPool(ItemPool, songList); + if (ShuffleSongs.Is(SONGSHUFFLE_ANYWHERE) && ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + AddItemsToPool(PendingJunkPool, songList); + } + + /*For item pool generation, dungeon items are either placed in their vanilla + | location, or added to the pool now and filtered out later depending on when + | they need to get placed or removed in fill.cpp. These items are kept in the + | pool until removal because the filling algorithm needs to know all of the + | advancement items that haven't been placed yet for placing higher priority + | items like stones/medallions.*/ + + if (MapsAndCompasses.Is(MAPSANDCOMPASSES_VANILLA)) { + PlaceVanillaMapsAndCompasses(); + } else { + for (auto dungeon : dungeonList) { + if (dungeon->GetMap() != NONE) { + AddItemToMainPool(dungeon->GetMap()); + } + + if (dungeon->GetCompass() != NONE) { + AddItemToMainPool(dungeon->GetCompass()); + } + } + } + + if (Keysanity.Is(KEYSANITY_VANILLA)) { + PlaceVanillaSmallKeys(); + } else { + for (auto dungeon : dungeonList) { + if (dungeon->HasKeyRing() && Keysanity.IsNot(KEYSANITY_START_WITH)) { + AddItemToMainPool(dungeon->GetKeyRing()); + } else { + if (dungeon->GetSmallKeyCount() > 0) { + AddItemToMainPool(dungeon->GetSmallKey(), dungeon->GetSmallKeyCount()); + } + } + } + } + + if (BossKeysanity.Is(BOSSKEYSANITY_VANILLA)) { + PlaceVanillaBossKeys(); + } else { + AddItemToMainPool(FOREST_TEMPLE_BOSS_KEY); + AddItemToMainPool(FIRE_TEMPLE_BOSS_KEY); + AddItemToMainPool(WATER_TEMPLE_BOSS_KEY); + AddItemToMainPool(SPIRIT_TEMPLE_BOSS_KEY); + AddItemToMainPool(SHADOW_TEMPLE_BOSS_KEY); + } + + if (GanonsBossKey.Value() >= GANONSBOSSKEY_LACS_VANILLA) { + PlaceItemInLocation(TOT_LIGHT_ARROWS_CUTSCENE, GANONS_CASTLE_BOSS_KEY); + } else if (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA)) { + PlaceItemInLocation(GANONS_TOWER_BOSS_KEY_CHEST, GANONS_CASTLE_BOSS_KEY); + } else { + AddItemToMainPool(GANONS_CASTLE_BOSS_KEY); + } + + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + AddItemsToPool(ItemPool, easyItems); + } else { + AddItemsToPool(ItemPool, normalItems); + } + + if (!ShuffleKokiriSword) { + ReplaceMaxItem(KOKIRI_SWORD, 0); + } + + if (ProgressiveGoronSword) { + ReplaceMaxItem(BIGGORON_SWORD, 0); + AddItemToMainPool(PROGRESSIVE_GORONSWORD, 2); + IceTrapModels.push_back(0xD4); // Progressive Goron Sword + } else { + IceTrapModels.push_back(GI_SWORD_BGS); + } + + //Replace ice traps with junk from the pending junk pool if necessary + if (IceTrapValue.Is(ICETRAPS_OFF)) { + ReplaceMaxItem(ICE_TRAP, 0); + } + //Replace all junk items with ice traps for onslaught mode + else if (IceTrapValue.Is(ICETRAPS_ONSLAUGHT)) { + for (uint8_t i = 0; i < JunkPoolItems.size() - 3; i++) { // -3 Omits Huge Rupees and Deku Nuts 10 + ReplaceMaxItem(JunkPoolItems[i], 0); + } + } + + if (ItemPoolValue.Is(ITEMPOOL_SCARCE)) { + SetScarceItemPool(); + } else if (ItemPoolValue.Is(ITEMPOOL_MINIMAL)) { + SetMinimalItemPool(); + } else if (RemoveDoubleDefense) { + ReplaceMaxItem(DOUBLE_DEFENSE, 0); + } + + //this feels ugly and there's probably a better way, but + //it replaces random junk with pending junk. + bool junkSet; + for (uint32_t pendingJunk : PendingJunkPool) { + junkSet = false; + for (uint32_t& item : ItemPool) { + for (uint32_t junk : JunkPoolItems) { + if (item == junk && item != HUGE_RUPEE && item != DEKU_NUTS_10) { + item = pendingJunk; + junkSet = true; + break; + } + } + if (junkSet) break; + } + } + PendingJunkPool.clear(); +} + +void AddJunk() { + SPDLOG_INFO("HAD TO PLACE EXTRA JUNK "); + AddItemToMainPool(GetPendingJunkItem()); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.hpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.hpp new file mode 100644 index 000000000..d71e4cb2f --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "keys.hpp" + +#include +#include +#include + +class ItemLocation; + +void AddItemToPool(std::vector& pool, const uint32_t item, size_t count = 1); +uint32_t GetJunkItem(); +void PlaceJunkInExcludedLocation(const uint32_t il); +void GenerateItemPool(); +void AddJunk(); + +extern std::vector ItemPool; +extern std::vector IceTrapModels; diff --git a/soh/soh/Enhancements/randomizer/3drando/keys.hpp b/soh/soh/Enhancements/randomizer/3drando/keys.hpp new file mode 100644 index 000000000..3e8d8f5cd --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/keys.hpp @@ -0,0 +1,1682 @@ +#pragma once + +#include + +using AreaKey = uint32_t; + +typedef enum { + NONE, + KOKIRI_SWORD, + MASTER_SWORD, + GIANTS_KNIFE, + BIGGORON_SWORD, + DEKU_SHIELD, + HYLIAN_SHIELD, + MIRROR_SHIELD, + GORON_TUNIC, + ZORA_TUNIC, + IRON_BOOTS, + HOVER_BOOTS, + WEIRD_EGG, + ZELDAS_LETTER, + BOOMERANG, + LENS_OF_TRUTH, + MEGATON_HAMMER, + STONE_OF_AGONY, + DINS_FIRE, + FARORES_WIND, + NAYRUS_LOVE, + FIRE_ARROWS, + ICE_ARROWS, + LIGHT_ARROWS, + GERUDO_MEMBERSHIP_CARD, + MAGIC_BEAN, + MAGIC_BEAN_PACK, + DOUBLE_DEFENSE, + GOLD_SKULLTULA_TOKEN, + + POCKET_EGG, + POCKET_CUCCO, + COJIRO, + ODD_MUSHROOM, + ODD_POTION, + POACHERS_SAW, + BROKEN_SWORD, + PRESCRIPTION, + EYEBALL_FROG, + EYEDROPS, + CLAIM_CHECK, + + PROGRESSIVE_HOOKSHOT, + PROGRESSIVE_STRENGTH, + PROGRESSIVE_BOMB_BAG, + PROGRESSIVE_BOW, + PROGRESSIVE_SLINGSHOT, + PROGRESSIVE_WALLET, + PROGRESSIVE_SCALE, + PROGRESSIVE_NUT_UPGRADE, + PROGRESSIVE_STICK_UPGRADE, + PROGRESSIVE_MAGIC_METER, + PROGRESSIVE_OCARINA, + PROGRESSIVE_BOMBCHUS, + PROGRESSIVE_GORONSWORD, + + //Keys just used for logic + BOW, + SLINGSHOT, + HOOKSHOT, + LONGSHOT, + SILVER_GAUNTLETS, + GOLDEN_GAUNTLETS, + SILVER_SCALE, + GOLD_SCALE, + SCARECROW, + DISTANT_SCARECROW, + STICKS, + + EMPTY_BOTTLE, + BOTTLE_WITH_MILK, + BOTTLE_WITH_RED_POTION, + BOTTLE_WITH_GREEN_POTION, + BOTTLE_WITH_BLUE_POTION, + BOTTLE_WITH_FAIRY, + BOTTLE_WITH_FISH, + BOTTLE_WITH_BLUE_FIRE, + BOTTLE_WITH_BUGS, + BOTTLE_WITH_POE, + BOTTLE_WITH_BIG_POE, + RUTOS_LETTER, + + ZELDAS_LULLABY, + EPONAS_SONG, + SARIAS_SONG, + SUNS_SONG, + SONG_OF_TIME, + SONG_OF_STORMS, + MINUET_OF_FOREST, + BOLERO_OF_FIRE, + SERENADE_OF_WATER, + REQUIEM_OF_SPIRIT, + NOCTURNE_OF_SHADOW, + PRELUDE_OF_LIGHT, + + MAP, + DEKU_TREE_MAP, + DODONGOS_CAVERN_MAP, + JABU_JABUS_BELLY_MAP, + FOREST_TEMPLE_MAP, + FIRE_TEMPLE_MAP, + WATER_TEMPLE_MAP, + SPIRIT_TEMPLE_MAP, + SHADOW_TEMPLE_MAP, + BOTTOM_OF_THE_WELL_MAP, + ICE_CAVERN_MAP, + + COMPASS, + DEKU_TREE_COMPASS, + DODONGOS_CAVERN_COMPASS, + JABU_JABUS_BELLY_COMPASS, + FOREST_TEMPLE_COMPASS, + FIRE_TEMPLE_COMPASS, + WATER_TEMPLE_COMPASS, + SPIRIT_TEMPLE_COMPASS, + SHADOW_TEMPLE_COMPASS, + BOTTOM_OF_THE_WELL_COMPASS, + ICE_CAVERN_COMPASS, + + BOSS_KEY, + FOREST_TEMPLE_BOSS_KEY, + FIRE_TEMPLE_BOSS_KEY, + WATER_TEMPLE_BOSS_KEY, + SPIRIT_TEMPLE_BOSS_KEY, + SHADOW_TEMPLE_BOSS_KEY, + GANONS_CASTLE_BOSS_KEY, + + SMALL_KEY, + FOREST_TEMPLE_SMALL_KEY, + FIRE_TEMPLE_SMALL_KEY, + WATER_TEMPLE_SMALL_KEY, + SPIRIT_TEMPLE_SMALL_KEY, + SHADOW_TEMPLE_SMALL_KEY, + BOTTOM_OF_THE_WELL_SMALL_KEY, + GERUDO_TRAINING_GROUNDS_SMALL_KEY, + GERUDO_FORTRESS_SMALL_KEY, + GANONS_CASTLE_SMALL_KEY, + TREASURE_GAME_SMALL_KEY, + + FOREST_TEMPLE_KEY_RING, + FIRE_TEMPLE_KEY_RING, + WATER_TEMPLE_KEY_RING, + SPIRIT_TEMPLE_KEY_RING, + SHADOW_TEMPLE_KEY_RING, + BOTTOM_OF_THE_WELL_KEY_RING, + GERUDO_TRAINING_GROUNDS_KEY_RING, + GERUDO_FORTRESS_KEY_RING, + GANONS_CASTLE_KEY_RING, + + KOKIRI_EMERALD, + GORON_RUBY, + ZORA_SAPPHIRE, + FOREST_MEDALLION, + FIRE_MEDALLION, + WATER_MEDALLION, + SPIRIT_MEDALLION, + SHADOW_MEDALLION, + LIGHT_MEDALLION, + + RECOVERY_HEART, + GREEN_RUPEE, + BLUE_RUPEE, + RED_RUPEE, + PURPLE_RUPEE, + HUGE_RUPEE, + PIECE_OF_HEART, + HEART_CONTAINER, + ICE_TRAP, + MILK, + + BOMBS_5, + BOMBS_10, + BOMBS_20, + BOMBCHU_5, + BOMBCHU_10, + BOMBCHU_20, + BOMBCHU_DROP, + ARROWS_5, + ARROWS_10, + ARROWS_30, + DEKU_NUTS_5, + DEKU_NUTS_10, + DEKU_SEEDS_30, + DEKU_STICK_1, + RED_POTION_REFILL, + GREEN_POTION_REFILL, + BLUE_POTION_REFILL, + + TREASURE_GAME_HEART, + TREASURE_GAME_GREEN_RUPEE, + + TRIFORCE, + TRIFORCE_PIECE, + EPONA, + HINT, + + //SHOP ITEMS + BUY_DEKU_NUT_5, + BUY_ARROWS_30, + BUY_ARROWS_50, + BUY_BOMBS_525, + BUY_DEKU_NUT_10, + BUY_DEKU_STICK_1, + BUY_BOMBS_10, + BUY_FISH, + BUY_RED_POTION_30, + BUY_GREEN_POTION, + BUY_BLUE_POTION, + BUY_HYLIAN_SHIELD, + BUY_DEKU_SHIELD, + BUY_GORON_TUNIC, + BUY_ZORA_TUNIC, + BUY_HEART, + BUY_BOMBCHU_10, + BUY_BOMBCHU_20, + BUY_BOMBCHU_5, + BUY_DEKU_SEEDS_30, + SOLD_OUT, + BUY_BLUE_FIRE, + BUY_BOTTLE_BUG, + BUY_POE, + BUY_FAIRYS_SPIRIT, + BUY_ARROWS_10, + BUY_BOMBS_20, + BUY_BOMBS_30, + BUY_BOMBS_535, + BUY_RED_POTION_40, + BUY_RED_POTION_50, + + //ITEMLOCATIONS + + //DUNGEON REWARDS + LINKS_POCKET, + QUEEN_GOHMA, + KING_DODONGO, + BARINADE, + PHANTOM_GANON, + VOLVAGIA, + MORPHA, + BONGO_BONGO, + TWINROVA, + GANON, + + //SONGS + SONG_FROM_IMPA, + SONG_FROM_MALON, + SONG_FROM_SARIA, + SONG_FROM_COMPOSERS_GRAVE, + SONG_FROM_OCARINA_OF_TIME, + SONG_FROM_WINDMILL, + SHEIK_IN_FOREST, + SHEIK_IN_CRATER, + SHEIK_IN_ICE_CAVERN, + SHEIK_AT_COLOSSUS, + SHEIK_IN_KAKARIKO, + SHEIK_AT_TEMPLE, + +//// Overworld +// Kokiri Forest + KF_MIDOS_TOP_LEFT_CHEST, + KF_MIDOS_TOP_RIGHT_CHEST, + KF_MIDOS_BOTTOM_LEFT_CHEST, + KF_MIDOS_BOTTOM_RIGHT_CHEST, + KF_KOKIRI_SWORD_CHEST, + KF_STORMS_GROTTO_CHEST, + KF_LINKS_HOUSE_COW, + KF_GS_KNOW_IT_ALL_HOUSE, + KF_GS_BEAN_PATCH, + KF_GS_HOUSE_OF_TWINS, + KF_SHOP_ITEM_1, + KF_SHOP_ITEM_2, + KF_SHOP_ITEM_3, + KF_SHOP_ITEM_4, + KF_SHOP_ITEM_5, + KF_SHOP_ITEM_6, + KF_SHOP_ITEM_7, + KF_SHOP_ITEM_8, +//LOST_WOODS + LW_GIFT_FROM_SARIA, + LW_OCARINA_MEMORY_GAME, + LW_TARGET_IN_WOODS, + LW_NEAR_SHORTCUTS_GROTTO_CHEST, + DEKU_THEATER_SKULL_MASK, + DEKU_THEATER_MASK_OF_TRUTH, + LW_SKULL_KID, + LW_TRADE_COJIRO, + LW_TRADE_ODD_POTION, + LW_DEKU_SCRUB_NEAR_BRIDGE, + LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, + LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, + LW_DEKU_SCRUB_GROTTO_FRONT, + LW_DEKU_SCRUB_GROTTO_REAR, + LW_GS_BEAN_PATCH_NEAR_BRIDGE, + LW_GS_BEAN_PATCH_NEAR_THEATER, + LW_GS_ABOVE_THEATER, +//SACRED_FOREST_MEADOW + SFM_WOLFOS_GROTTO_CHEST, + SFM_DEKU_SCRUB_GROTTO_FRONT, + SFM_DEKU_SCRUB_GROTTO_REAR, + SFM_GS, +//HYRULE_FIELD + HF_OCARINA_OF_TIME_ITEM, + HF_NEAR_MARKET_GROTTO_CHEST, + HF_TEKTITE_GROTTO_FREESTANDING_POH, + HF_SOUTHEAST_GROTTO_CHEST, + HF_OPEN_GROTTO_CHEST, + HF_DEKU_SCRUB_GROTTO, + HF_COW_GROTTO_COW, + HF_GS_COW_GROTTO, + HF_GS_NEAR_KAK_GROTTO, +//MARKET + MARKET_SHOOTING_GALLERY_REWARD, + MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, + MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, + MARKET_BOMBCHU_BOWLING_BOMBCHUS, + MARKET_LOST_DOG, + MARKET_TREASURE_CHEST_GAME_REWARD, + MARKET_TREASURE_CHEST_GAME_ITEM_1, + MARKET_TREASURE_CHEST_GAME_ITEM_2, + MARKET_TREASURE_CHEST_GAME_ITEM_3, + MARKET_TREASURE_CHEST_GAME_ITEM_4, + MARKET_TREASURE_CHEST_GAME_ITEM_5, + MARKET_10_BIG_POES, + MARKET_GS_GUARD_HOUSE, + MARKET_BAZAAR_ITEM_1, + MARKET_BAZAAR_ITEM_2, + MARKET_BAZAAR_ITEM_3, + MARKET_BAZAAR_ITEM_4, + MARKET_BAZAAR_ITEM_5, + MARKET_BAZAAR_ITEM_6, + MARKET_BAZAAR_ITEM_7, + MARKET_BAZAAR_ITEM_8, + MARKET_POTION_SHOP_ITEM_1, + MARKET_POTION_SHOP_ITEM_2, + MARKET_POTION_SHOP_ITEM_3, + MARKET_POTION_SHOP_ITEM_4, + MARKET_POTION_SHOP_ITEM_5, + MARKET_POTION_SHOP_ITEM_6, + MARKET_POTION_SHOP_ITEM_7, + MARKET_POTION_SHOP_ITEM_8, + MARKET_BOMBCHU_SHOP_ITEM_1, + MARKET_BOMBCHU_SHOP_ITEM_2, + MARKET_BOMBCHU_SHOP_ITEM_3, + MARKET_BOMBCHU_SHOP_ITEM_4, + MARKET_BOMBCHU_SHOP_ITEM_5, + MARKET_BOMBCHU_SHOP_ITEM_6, + MARKET_BOMBCHU_SHOP_ITEM_7, + MARKET_BOMBCHU_SHOP_ITEM_8, + TOT_LIGHT_ARROWS_CUTSCENE, +//HYRULE_CASTLE + HC_MALON_EGG, + HC_ZELDAS_LETTER, + HC_GREAT_FAIRY_REWARD, + HC_GS_TREE, + HC_GS_STORMS_GROTTO, +//LON_LON_RANCH + LLR_TALONS_CHICKENS, + LLR_FREESTANDING_POH, + LLR_DEKU_SCRUB_GROTTO_LEFT, + LLR_DEKU_SCRUB_GROTTO_CENTER, + LLR_DEKU_SCRUB_GROTTO_RIGHT, + LLR_STABLES_LEFT_COW, + LLR_STABLES_RIGHT_COW, + LLR_TOWER_LEFT_COW, + LLR_TOWER_RIGHT_COW, + LLR_GS_HOUSE_WINDOW, + LLR_GS_TREE, + LLR_GS_RAIN_SHED, + LLR_GS_BACK_WALL, +//KAKARIKO + KAK_ANJU_AS_CHILD, + KAK_ANJU_AS_ADULT, + KAK_TRADE_POCKET_CUCCO, + KAK_IMPAS_HOUSE_FREESTANDING_POH, + KAK_WINDMILL_FREESTANDING_POH, + KAK_MAN_ON_ROOF, + KAK_OPEN_GROTTO_CHEST, + KAK_REDEAD_GROTTO_CHEST, + KAK_SHOOTING_GALLERY_REWARD, + KAK_TRADE_ODD_MUSHROOM, + KAK_10_GOLD_SKULLTULA_REWARD, + KAK_20_GOLD_SKULLTULA_REWARD, + KAK_30_GOLD_SKULLTULA_REWARD, + KAK_40_GOLD_SKULLTULA_REWARD, + KAK_50_GOLD_SKULLTULA_REWARD, + KAK_IMPAS_HOUSE_COW, + KAK_GS_TREE, + KAK_GS_GUARDS_HOUSE, + KAK_GS_WATCHTOWER, + KAK_GS_SKULLTULA_HOUSE, + KAK_GS_HOUSE_UNDER_CONSTRUCTION, + KAK_GS_ABOVE_IMPAS_HOUSE, + KAK_BAZAAR_ITEM_1, + KAK_BAZAAR_ITEM_2, + KAK_BAZAAR_ITEM_3, + KAK_BAZAAR_ITEM_4, + KAK_BAZAAR_ITEM_5, + KAK_BAZAAR_ITEM_6, + KAK_BAZAAR_ITEM_7, + KAK_BAZAAR_ITEM_8, + KAK_POTION_SHOP_ITEM_1, + KAK_POTION_SHOP_ITEM_2, + KAK_POTION_SHOP_ITEM_3, + KAK_POTION_SHOP_ITEM_4, + KAK_POTION_SHOP_ITEM_5, + KAK_POTION_SHOP_ITEM_6, + KAK_POTION_SHOP_ITEM_7, + KAK_POTION_SHOP_ITEM_8, +//GRAVEYARD + GRAVEYARD_SHIELD_GRAVE_CHEST, + GRAVEYARD_HEART_PIECE_GRAVE_CHEST, + GRAVEYARD_COMPOSERS_GRAVE_CHEST, + GRAVEYARD_FREESTANDING_POH, + GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, + GRAVEYARD_HOOKSHOT_CHEST, + GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, + GRAVEYARD_GS_BEAN_PATCH, + GRAVEYARD_GS_WALL, +//DEATH_MOUNTAIN_TRAIL + DMT_FREESTANDING_POH, + DMT_CHEST, + DMT_STORMS_GROTTO_CHEST, + DMT_GREAT_FAIRY_REWARD, + DMT_TRADE_BROKEN_SWORD, + DMT_TRADE_EYEDROPS, + DMT_TRADE_CLAIM_CHECK, + DMT_COW_GROTTO_COW, + DMT_GS_NEAR_KAK, + DMT_GS_BEAN_PATCH, + DMT_GS_ABOVE_DODONGOS_CAVERN, + DMT_GS_FALLING_ROCKS_PATH, +//GORON_CITY + GC_DARUNIAS_JOY, + GC_POT_FREESTANDING_POH, + GC_ROLLING_GORON_AS_CHILD, + GC_ROLLING_GORON_AS_ADULT, + GC_MEDIGORON, + GC_MAZE_LEFT_CHEST, + GC_MAZE_RIGHT_CHEST, + GC_MAZE_CENTER_CHEST, + GC_DEKU_SCRUB_GROTTO_LEFT, + GC_DEKU_SCRUB_GROTTO_CENTER, + GC_DEKU_SCRUB_GROTTO_RIGHT, + GC_GS_CENTER_PLATFORM, + GC_GS_BOULDER_MAZE, + GC_SHOP_ITEM_1, + GC_SHOP_ITEM_2, + GC_SHOP_ITEM_3, + GC_SHOP_ITEM_4, + GC_SHOP_ITEM_5, + GC_SHOP_ITEM_6, + GC_SHOP_ITEM_7, + GC_SHOP_ITEM_8, +//DEATH_MOUNTAIN_CRATER + DMC_VOLCANO_FREESTANDING_POH, + DMC_WALL_FREESTANDING_POH, + DMC_UPPER_GROTTO_CHEST, + DMC_GREAT_FAIRY_REWARD, + DMC_DEKU_SCRUB, + DMC_DEKU_SCRUB_GROTTO_LEFT, + DMC_DEKU_SCRUB_GROTTO_CENTER, + DMC_DEKU_SCRUB_GROTTO_RIGHT, + DMC_GS_CRATE, + DMC_GS_BEAN_PATCH, +//ZORA'S_RIVER + ZR_MAGIC_BEAN_SALESMAN, + ZR_OPEN_GROTTO_CHEST, + ZR_FROGS_IN_THE_RAIN, + ZR_FROGS_OCARINA_GAME, + ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, + ZR_NEAR_DOMAIN_FREESTANDING_POH, + ZR_DEKU_SCRUB_GROTTO_FRONT, + ZR_DEKU_SCRUB_GROTTO_REAR, + ZR_GS_TREE, + ZR_GS_LADDER, + ZR_GS_NEAR_RAISED_GROTTOS, + ZR_GS_ABOVE_BRIDGE, +//ZORA'S_DOMAIN + ZD_DIVING_MINIGAME, + ZD_CHEST, + ZD_KING_ZORA_THAWED, + ZD_TRADE_PRESCRIPTION, + ZD_GS_FROZEN_WATERFALL, + ZD_SHOP_ITEM_1, + ZD_SHOP_ITEM_2, + ZD_SHOP_ITEM_3, + ZD_SHOP_ITEM_4, + ZD_SHOP_ITEM_5, + ZD_SHOP_ITEM_6, + ZD_SHOP_ITEM_7, + ZD_SHOP_ITEM_8, +//ZORA'S_FOUNTAIN + ZF_GREAT_FAIRY_REWARD, + ZF_ICEBERG_FREESTANDING_POH, + ZF_BOTTOM_FREESTANDING_POH, + ZF_GS_ABOVE_THE_LOG, + ZF_GS_TREE, + ZF_GS_HIDDEN_CAVE, +//LAKE_HYLIA + LH_UNDERWATER_ITEM, + LH_CHILD_FISHING, + LH_ADULT_FISHING, + LH_LAB_DIVE, + LH_TRADE_FROG, + LH_FREESTANDING_POH, + LH_SUN, + LH_DEKU_SCRUB_GROTTO_LEFT, + LH_DEKU_SCRUB_GROTTO_CENTER, + LH_DEKU_SCRUB_GROTTO_RIGHT, + LH_GS_BEAN_PATCH, + LH_GS_LAB_WALL, + LH_GS_SMALL_ISLAND, + LH_GS_LAB_CRATE, + LH_GS_TREE, +//GERUDO_VALLEY + GV_CRATE_FREESTANDING_POH, + GV_WATERFALL_FREESTANDING_POH, + GV_CHEST, + GV_TRADE_SAW, + GV_DEKU_SCRUB_GROTTO_FRONT, + GV_DEKU_SCRUB_GROTTO_REAR, + GV_COW, + GV_GS_SMALL_BRIDGE, + GV_GS_BEAN_PATCH, + GV_GS_BEHIND_TENT, + GV_GS_PILLAR, +//GERUDO'S_FORTRESS + GF_NORTH_F1_CARPENTER, + GF_NORTH_F2_CARPENTER, + GF_SOUTH_F1_CARPENTER, + GF_SOUTH_F2_CARPENTER, + GF_GERUDO_MEMBERSHIP_CARD, + GF_CHEST, + GF_HBA_1000_POINTS, + GF_HBA_1500_POINTS, + GF_GS_TOP_FLOOR, + GF_GS_ARCHERY_RANGE, +//WASTELAND + WASTELAND_BOMBCHU_SALESMAN, + WASTELAND_CHEST, + WASTELAND_GS, +//COLOSSUS + COLOSSUS_GREAT_FAIRY_REWARD, + COLOSSUS_FREESTANDING_POH, + COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, + COLOSSUS_DEKU_SCRUB_GROTTO_REAR, + COLOSSUS_GS_BEAN_PATCH, + COLOSSUS_GS_TREE, + COLOSSUS_GS_HILL, +//OUTSIDE_GANON'S_CASTLE + OGC_GREAT_FAIRY_REWARD, + OGC_GS, + +////DUNGEONS +//DEKU_TREE_VANILLA + DEKU_TREE_MAP_CHEST, + DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, + DEKU_TREE_SLINGSHOT_CHEST, + DEKU_TREE_COMPASS_CHEST, + DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, + DEKU_TREE_BASEMENT_CHEST, + DEKU_TREE_GS_COMPASS_ROOM, + DEKU_TREE_GS_BASEMENT_VINES, + DEKU_TREE_GS_BASEMENT_GATE, + DEKU_TREE_GS_BASEMENT_BACK_ROOM, +//DEKU_TREE_MQ + DEKU_TREE_MQ_MAP_CHEST, + DEKU_TREE_MQ_SLINGSHOT_CHEST, + DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, + DEKU_TREE_MQ_COMPASS_CHEST, + DEKU_TREE_MQ_BASEMENT_CHEST, + DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, + DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, + DEKU_TREE_MQ_DEKU_SCRUB, + DEKU_TREE_MQ_GS_LOBBY, + DEKU_TREE_MQ_GS_COMPASS_ROOM, + DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, + DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, +//DEKU_TREE_SHARED + DEKU_TREE_QUEEN_GOHMA_HEART, +//DODONGO'S_CAVERN_VANILLA + DODONGOS_CAVERN_MAP_CHEST, + DODONGOS_CAVERN_COMPASS_CHEST, + DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, + DODONGOS_CAVERN_BOMB_BAG_CHEST, + DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, + DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, + DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, + DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, + DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, + DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + DODONGOS_CAVERN_GS_SCARECROW, + DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, + DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, + DODONGOS_CAVERN_GS_BACK_ROOM, +//DODONGO'S_CAVERN_MQ + DODONGOS_CAVERN_MQ_MAP_CHEST, + DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, + DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, + DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, + DODONGOS_CAVERN_MQ_COMPASS_CHEST, + DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, + DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, + DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, + DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, + DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, + DODONGOS_CAVERN_MQ_GS_BACK_AREA, +//DODONGO'S_CAVERN_SHARED + DODONGOS_CAVERN_BOSS_ROOM_CHEST, + DODONGOS_CAVERN_KING_DODONGO_HEART, +//JABU_JABU'S_BELLY_VANILLA + JABU_JABUS_BELLY_BOOMERANG_CHEST, + JABU_JABUS_BELLY_MAP_CHEST, + JABU_JABUS_BELLY_COMPASS_CHEST, + JABU_JABUS_BELLY_DEKU_SCRUB, + JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, + JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, + JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, + JABU_JABUS_BELLY_GS_NEAR_BOSS, +//JABU_JABU'S_BELLY_MQ + JABU_JABUS_BELLY_MQ_MAP_CHEST, + JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, + JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, + JABU_JABUS_BELLY_MQ_COMPASS_CHEST, + JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, + JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, + JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, + JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, + JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, + JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, + JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, + JABU_JABUS_BELLY_MQ_COW, + JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, + JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, + JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, + JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, +//JABU_JABU'S_BELLY_SHARED + JABU_JABUS_BELLY_BARINADE_HEART, +//BOTTOM_OF_THE_WELL_VANILLA + BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, + BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, + BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, + BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, + BOTTOM_OF_THE_WELL_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_COMPASS_CHEST, + BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, + BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, + BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, + BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, + BOTTOM_OF_THE_WELL_MAP_CHEST, + BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, + BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, + BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, + BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, + BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, + BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, +//BOTTOM_OF_THE_WELL_MQ + BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, + BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, + BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, + BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, + BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, + BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, +//FOREST_TEMPLE_VANILLA + FOREST_TEMPLE_FIRST_ROOM_CHEST, + FOREST_TEMPLE_FIRST_STALFOS_CHEST, + FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, + FOREST_TEMPLE_MAP_CHEST, + FOREST_TEMPLE_WELL_CHEST, + FOREST_TEMPLE_EYE_SWITCH_CHEST, + FOREST_TEMPLE_BOSS_KEY_CHEST, + FOREST_TEMPLE_FLOORMASTER_CHEST, + FOREST_TEMPLE_RED_POE_CHEST, + FOREST_TEMPLE_BOW_CHEST, + FOREST_TEMPLE_BLUE_POE_CHEST, + FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, + FOREST_TEMPLE_BASEMENT_CHEST, + FOREST_TEMPLE_GS_FIRST_ROOM, + FOREST_TEMPLE_GS_LOBBY, + FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, + FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, + FOREST_TEMPLE_GS_BASEMENT, +//FOREST_TEMPLE_MQ + FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, + FOREST_TEMPLE_MQ_WOLFOS_CHEST, + FOREST_TEMPLE_MQ_WELL_CHEST, + FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, + FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, + FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, + FOREST_TEMPLE_MQ_REDEAD_CHEST, + FOREST_TEMPLE_MQ_MAP_CHEST, + FOREST_TEMPLE_MQ_BOW_CHEST, + FOREST_TEMPLE_MQ_COMPASS_CHEST, + FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, + FOREST_TEMPLE_MQ_BASEMENT_CHEST, + FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, + FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, + FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, + FOREST_TEMPLE_MQ_GS_WELL, + FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, +//FOREST_TEMPLE_SHARED + FOREST_TEMPLE_PHANTOM_GANON_HEART, +//FIRE_TEMPLE_VANILLA + FIRE_TEMPLE_NEAR_BOSS_CHEST, + FIRE_TEMPLE_FLARE_DANCER_CHEST, + FIRE_TEMPLE_BOSS_KEY_CHEST, + FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, + FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, + FIRE_TEMPLE_MAP_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, + FIRE_TEMPLE_SCARECROW_CHEST, + FIRE_TEMPLE_COMPASS_CHEST, + FIRE_TEMPLE_MEGATON_HAMMER_CHEST, + FIRE_TEMPLE_HIGHEST_GORON_CHEST, + FIRE_TEMPLE_GS_BOSS_KEY_LOOP, + FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, + FIRE_TEMPLE_GS_BOULDER_MAZE, + FIRE_TEMPLE_GS_SCARECROW_CLIMB, + FIRE_TEMPLE_GS_SCARECROW_TOP, +//FIRE_TEMPLE_MQ + FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, + FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, + FIRE_TEMPLE_MQ_MAP_CHEST, + FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, + FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, + FIRE_TEMPLE_MQ_COMPASS_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, + FIRE_TEMPLE_MQ_FREESTANDING_KEY, + FIRE_TEMPLE_MQ_CHEST_ON_FIRE, + FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, + FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, + FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, + FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, + FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, +//FIRE_TEMPLE_SHARED + FIRE_TEMPLE_VOLVAGIA_HEART, +//WATER_TEMPLE_VANILLA + WATER_TEMPLE_COMPASS_CHEST, + WATER_TEMPLE_MAP_CHEST, + WATER_TEMPLE_CRACKED_WALL_CHEST, + WATER_TEMPLE_TORCHES_CHEST, + WATER_TEMPLE_BOSS_KEY_CHEST, + WATER_TEMPLE_CENTRAL_PILLAR_CHEST, + WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, + WATER_TEMPLE_LONGSHOT_CHEST, + WATER_TEMPLE_RIVER_CHEST, + WATER_TEMPLE_DRAGON_CHEST, + WATER_TEMPLE_GS_BEHIND_GATE, + WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, + WATER_TEMPLE_GS_CENTRAL_PILLAR, + WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, + WATER_TEMPLE_GS_RIVER, +//WATER_TEMPLE_MQ + WATER_TEMPLE_MQ_LONGSHOT_CHEST, + WATER_TEMPLE_MQ_MAP_CHEST, + WATER_TEMPLE_MQ_COMPASS_CHEST, + WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, + WATER_TEMPLE_MQ_BOSS_KEY_CHEST, + WATER_TEMPLE_MQ_FREESTANDING_KEY, + WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, + WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, + WATER_TEMPLE_MQ_GS_RIVER, + WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, + WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, +//WATER_TEMPLE_SHARED + WATER_TEMPLE_MORPHA_HEART, +//SHADOW_TEMPLE_VANILLA + SHADOW_TEMPLE_MAP_CHEST, + SHADOW_TEMPLE_HOVER_BOOTS_CHEST, + SHADOW_TEMPLE_COMPASS_CHEST, + SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, + SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, + SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, + SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, + SHADOW_TEMPLE_FREESTANDING_KEY, + SHADOW_TEMPLE_WIND_HINT_CHEST, + SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, + SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, + SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, + SHADOW_TEMPLE_BOSS_KEY_CHEST, + SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, + SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, + SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, + SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, + SHADOW_TEMPLE_GS_NEAR_SHIP, + SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, +//SHADOW_TEMPLE_MQ + SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, + SHADOW_TEMPLE_MQ_MAP_CHEST, + SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, + SHADOW_TEMPLE_MQ_COMPASS_CHEST, + SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, + SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, + SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, + SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, + SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, + SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, + SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, + SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, + SHADOW_TEMPLE_MQ_FREESTANDING_KEY, + SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, + SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, + SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, + SHADOW_TEMPLE_MQ_GS_AFTER_WIND, + SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, + SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, +//SHADOW_TEMPLE_SHARED + SHADOW_TEMPLE_BONGO_BONGO_HEART, +//SPIRIT_TEMPLE_SHARED +//VANILLA_AND_MQ_LOCATIONS_ARE_MIXED_TO_ENSURE_THE_POSITIONS_OF_S + SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, + SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, + SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, + SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, + SPIRIT_TEMPLE_MAP_CHEST, + SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, + SPIRIT_TEMPLE_MQ_MAP_CHEST, + SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, + SPIRIT_TEMPLE_MQ_COMPASS_CHEST, + SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, + SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, + SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, + SPIRIT_TEMPLE_COMPASS_CHEST, + SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, + SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, + SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, + SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, + SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, + SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, + SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, + SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, + SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, + SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, + SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, + SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, + SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, + SPIRIT_TEMPLE_BOSS_KEY_CHEST, + SPIRIT_TEMPLE_TOPMOST_CHEST, + SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, + SPIRIT_TEMPLE_GS_METAL_FENCE, + SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, + SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, + SPIRIT_TEMPLE_GS_LOBBY, + SPIRIT_TEMPLE_GS_BOULDER_ROOM, + SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, + SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, + SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, + SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, + SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, + SPIRIT_TEMPLE_TWINROVA_HEART, +//ICE_CAVERN_VANILLA + ICE_CAVERN_MAP_CHEST, + ICE_CAVERN_COMPASS_CHEST, + ICE_CAVERN_FREESTANDING_POH, + ICE_CAVERN_IRON_BOOTS_CHEST, + ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, + ICE_CAVERN_GS_HEART_PIECE_ROOM, + ICE_CAVERN_GS_PUSH_BLOCK_ROOM, +//ICE_CAVERN_MQ + ICE_CAVERN_MQ_MAP_CHEST, + ICE_CAVERN_MQ_COMPASS_CHEST, + ICE_CAVERN_MQ_FREESTANDING_POH, + ICE_CAVERN_MQ_IRON_BOOTS_CHEST, + ICE_CAVERN_MQ_GS_RED_ICE, + ICE_CAVERN_MQ_GS_ICE_BLOCK, + ICE_CAVERN_MQ_GS_SCARECROW, +//GERUDO_TRAINING_GROUNDS_VANILLA + GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST, + GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST, + GERUDO_TRAINING_GROUNDS_STALFOS_CHEST, + GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST, + GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST, + GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY, + GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST, + GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST, + GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST, + GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST, +//GERUDO_TRAINING_GROUNDS_MQ + GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST, +//GANON'S_CASTLE_VANILLA + GANONS_CASTLE_FOREST_TRIAL_CHEST, + GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, + GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, + GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, + GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, + GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, + GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, + GANONS_CASTLE_DEKU_SCRUB_LEFT, + GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, + GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, + GANONS_CASTLE_DEKU_SCRUB_RIGHT, +//GANON'S_CASTLE_MQ + GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, + GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, + GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, + GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, + GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, + GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, +//GANON'S_CASTLE_SHARED + GANONS_TOWER_BOSS_KEY_CHEST, + +////EVENTS_AND_DROPS + PIERRE, + DELIVER_RUTOS_LETTER, + MASTER_SWORD_PEDESTAL, + DEKU_BABA_STICKS, + DEKU_BABA_NUTS, + STICK_POT, + NUT_POT, + NUT_CRATE, + BLUE_FIRE, + LONE_FISH, + FISH_GROUP, + BUG_ROCK, + BUG_SHRUB, + WANDERING_BUGS, + FAIRY_POT, + FREE_FAIRIES, + WALL_FAIRY, + BUTTERFLY_FAIRY, + GOSSIP_STONE_FAIRY, + BEAN_PLANT_FAIRY, + FAIRY_POND, + BIG_POE_KILL, + + //HINT LOACTIONS + DMC_GOSSIP_STONE, + DMT_GOSSIP_STONE, + COLOSSUS_GOSSIP_STONE, + DODONGOS_CAVERN_GOSSIP_STONE, + GV_GOSSIP_STONE, + GC_MAZE_GOSSIP_STONE, + GC_MEDIGORON_GOSSIP_STONE, + GRAVEYARD_GOSSIP_STONE, + HC_MALON_GOSSIP_STONE, + HC_ROCK_WALL_GOSSIP_STONE, + HC_STORMS_GROTTO_GOSSIP_STONE, + HF_COW_GROTTO_GOSSIP_STONE, + KF_DEKU_TREE_GOSSIP_STONE_LEFT, + KF_DEKU_TREE_GOSSIP_STONE_RIGHT, + KF_GOSSIP_STONE, + LH_LAB_GOSSIP_STONE, + LH_GOSSIP_STONE_SOUTHEAST, + LH_GOSSIP_STONE_SOUTHWEST, + LW_GOSSIP_STONE, + SFM_MAZE_GOSSIP_STONE_LOWER, + SFM_MAZE_GOSSIP_STONE_UPPER, + SFM_SARIA_GOSSIP_STONE, + TOT_GOSSIP_STONE_LEFT, + TOT_GOSSIP_STONE_LEFT_CENTER, + TOT_GOSSIP_STONE_RIGHT, + TOT_GOSSIP_STONE_RIGHT_CENTER, + ZD_GOSSIP_STONE, + ZF_FAIRY_GOSSIP_STONE, + ZF_JABU_GOSSIP_STONE, + ZR_NEAR_GROTTOS_GOSSIP_STONE, + ZR_NEAR_DOMAIN_GOSSIP_STONE, + HF_NEAR_MARKET_GROTTO_GOSSIP_STONE, + HF_SOUTHEAST_GROTTO_GOSSIP_STONE, + HF_OPEN_GROTTO_GOSSIP_STONE, + KAK_OPEN_GROTTO_GOSSIP_STONE, + ZR_OPEN_GROTTO_GOSSIP_STONE, + KF_STORMS_GROTTO_GOSSIP_STONE, + LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, + DMT_STORMS_GROTTO_GOSSIP_STONE, + DMC_UPPER_GROTTO_GOSSIP_STONE, + GANONDORF_HINT, + + //ENTRANCES + DESERT_COLOSSUS_TO_COLOSSUS_GROTTO, + GV_GROTTO_LEDGE_TO_GV_OCTOROK_GROTTO, + GC_GROTTO_PLATFORM_TO_GC_GROTTO, + GERUDO_FORTRESS_TO_GF_STORMS_GROTTO, + ZORAS_DOMAIN_TO_ZD_STORMS_GROTTO, + HYRULE_CASTLE_GROUNDS_TO_HC_STORMS_GROTTO, + GV_FORTRESS_SIDE_TO_GV_STORMS_GROTTO, + DESERT_COLOSSUS_TO_COLOSSUS_GREAT_FAIRY_FOUNTAIN, + GANONS_CASTLE_GROUNDS_TO_OGC_GREAT_FAIRY_FOUNTAIN, + ZORAS_FOUNTAIN_TO_ZF_GREAT_FAIRY_FOUNTAIN, + GV_FORTRESS_SIDE_TO_GV_CARPENTER_TENT, + GRAVEYARD_WARP_PAD_REGION_TO_SHADOW_TEMPLE_ENTRYWAY, + LAKE_HYLIA_TO_WATER_TEMPLE_LOBBY, + GERUDO_FORTRESS_TO_GERUDO_TRAINING_GROUNDS_LOBBY, + ZORAS_FOUNTAIN_TO_JABU_JABUS_BELLY_BEGINNING, + KAKARIKO_VILLAGE_TO_BOTTOM_OF_THE_WELL, + + //EXITS + HYRULE_CASTLE, + OUTSIDE_GANONS_CASTLE, + DEATH_MOUNTAIN_CRATER, + + //AREAS + ROOT, + ROOT_EXITS, + KOKIRI_FOREST, + KF_LINKS_HOUSE, + KF_MIDOS_HOUSE, + KF_SARIAS_HOUSE, + KF_HOUSE_OF_TWINS, + KF_KNOW_IT_ALL_HOUSE, + KF_KOKIRI_SHOP, + KF_OUTSIDE_DEKU_TREE, + KF_STORMS_GROTTO, + THE_LOST_WOODS, + LW_BRIDGE_FROM_FOREST, + LW_BRIDGE, + LW_FOREST_EXIT, + LW_BEYOND_MIDO, + LW_NEAR_SHORTCUTS_GROTTO, + DEKU_THEATER, + LW_SCRUBS_GROTTO, + SFM_ENTRYWAY, + SACRED_FOREST_MEADOW, + SFM_WOLFOS_GROTTO, + SFM_FAIRY_GROTTO, + SFM_STORMS_GROTTO, + HYRULE_FIELD, + HF_SOUTHEAST_GROTTO, + HF_OPEN_GROTTO, + HF_INSIDE_FENCE_GROTTO, + HF_COW_GROTTO, + HF_NEAR_MARKET_GROTTO, + HF_FAIRY_GROTTO, + HF_NEAR_KAK_GROTTO, + HF_TEKTITE_GROTTO, + LAKE_HYLIA, + LH_FISHING_ISLAND, + LH_OWL_FLIGHT, + LH_LAB, + LH_FISHING_HOLE, + LH_GROTTO, + GERUDO_VALLEY, + GV_UPPER_STREAM, + GV_LOWER_STREAM, + GV_GROTTO_LEDGE, + GV_CRATE_LEDGE, + GV_OCTOROK_GROTTO, + GV_FORTRESS_SIDE, + GV_CARPENTER_TENT, + GV_STORMS_GROTTO, + GERUDO_FORTRESS, + GF_OUTSIDE_GATE, + GF_STORMS_GROTTO, + WASTELAND_NEAR_FORTRESS, + HAUNTED_WASTELAND, + WASTELAND_NEAR_COLOSSUS, + DESERT_COLOSSUS, + COLOSSUS_GREAT_FAIRY_FOUNTAIN, + COLOSSUS_GROTTO, + MARKET_ENTRANCE, + THE_MARKET, + MARKET_GUARD_HOUSE, + MARKET_BAZAAR, + MARKET_MASK_SHOP, + MARKET_SHOOTING_GALLERY, + MARKET_BOMBCHU_BOWLING, + MARKET_TREASURE_CHEST_GAME, + MARKET_POTION_SHOP, + MARKET_BACK_ALLEY, + MARKET_BOMBCHU_SHOP, + MARKET_DOG_LADY_HOUSE, + MARKET_MAN_IN_GREEN_HOUSE, + TOT_ENTRANCE, + TEMPLE_OF_TIME, + TOT_BEYOND_DOOR_OF_TIME, + CASTLE_GROUNDS, + HYRULE_CASTLE_GROUNDS, + HC_GARDEN, + HC_GREAT_FAIRY_FOUNTAIN, + HC_STORMS_GROTTO, + GANONS_CASTLE_GROUNDS, + OGC_GREAT_FAIRY_FOUNTAIN, + KAKARIKO_VILLAGE, + KAK_CARPENTER_BOSS_HOUSE, + KAK_HOUSE_OF_SKULLTULA, + KAK_IMPAS_HOUSE, + KAK_IMPAS_LEDGE, + KAK_IMPAS_HOUSE_BACK, + KAK_IMPAS_HOUSE_NEAR_COW, + KAK_WINDMILL, + KAK_BAZAAR, + KAK_SHOOTING_GALLERY, + KAK_POTION_SHOP_FRONT, + KAK_POTION_SHOP_BACK, + KAK_ROOFTOP, + KAK_BEHIND_GATE, + KAK_BACKYARD, + KAK_ODD_POTION_BUILDING, + KAK_REDEAD_GROTTO, + KAK_OPEN_GROTTO, + THE_GRAVEYARD, + GRAVEYARD_DAMPES_GRAVE, + GRAVEYARD_DAMPES_HOUSE, + GRAVEYARD_SHIELD_GRAVE, + GRAVEYARD_COMPOSERS_GRAVE, + GRAVEYARD_HEART_PIECE_GRAVE, + GRAVEYARD_WARP_PAD_REGION, + DEATH_MOUNTAIN_TRAIL, + DEATH_MOUNTAIN_SUMMIT, + DMT_OWL_FLIGHT, + DMT_GREAT_FAIRY_FOUNTAIN, + DMT_COW_GROTTO, + DMT_STORMS_GROTTO, + GORON_CITY, + GC_WOODS_WARP, + GC_DARUNIAS_CHAMBER, + GC_GROTTO_PLATFORM, + GC_SHOP, + GC_GROTTO, + DMC_UPPER_LOCAL, + DMC_CENTRAL_LOCAL, + DMC_LOWER_LOCAL, + DMC_LOWER_NEARBY, + DMC_UPPER_NEARBY, + DMC_CENTRAL_NEARBY, + DMC_LADDER_AREA_NEARBY, + DMC_UPPER_GROTTO, + DMC_HAMMER_GROTTO, + DMC_GREAT_FAIRY_FOUNTAIN, + ZR_FRONT, + ZORAS_RIVER, + ZR_BEHIND_WATERFALL, + ZR_OPEN_GROTTO, + ZR_FAIRY_GROTTO, + ZR_STORMS_GROTTO, + ZORAS_DOMAIN, + ZD_BEHIND_KING_ZORA, + ZD_SHOP, + ZD_STORMS_GROTTO, + ZORAS_FOUNTAIN, + ZF_GREAT_FAIRY_FOUNTAIN, + LON_LON_RANCH, + LLR_TALONS_HOUSE, + LLR_STABLES, + LLR_TOWER, + LLR_GROTTO, + + DEKU_TREE_ENTRYWAY, + DODONGOS_CAVERN_ENTRYWAY, + JABU_JABUS_BELLY_ENTRYWAY, + FOREST_TEMPLE_ENTRYWAY, + FIRE_TEMPLE_ENTRYWAY, + WATER_TEMPLE_ENTRYWAY, + SPIRIT_TEMPLE_ENTRYWAY, + SHADOW_TEMPLE_ENTRYWAY, + BOTTOM_OF_THE_WELL_ENTRYWAY, + ICE_CAVERN_ENTRYWAY, + GERUDO_TRAINING_GROUNDS_ENTRYWAY, + GANONS_CASTLE_ENTRYWAY, + + DEKU_TREE_LOBBY, + DEKU_TREE_2F_MIDDLE_ROOM, + DEKU_TREE_SLINGSHOT_ROOM, + DEKU_TREE_COMPASS_ROOM, + DEKU_TREE_BASEMENT_LOWER, + DEKU_TREE_BASEMENT_SCRUB_ROOM, + DEKU_TREE_BASEMENT_WATER_ROOM, + DEKU_TREE_BASEMENT_TORCH_ROOM, + DEKU_TREE_BASEMENT_BACK_LOBBY, + DEKU_TREE_BASEMENT_BACK_ROOM, + DEKU_TREE_BASEMENT_UPPER, + DEKU_TREE_OUTSIDE_BOSS_ROOM, + DEKU_TREE_BOSS_ROOM, + + DODONGOS_CAVERN_BEGINNING, + DODONGOS_CAVERN_LOBBY, + DODONGOS_CAVERN_LOBBY_SWITCH, + DODONGOS_CAVERN_SE_CORRIDOR, + DODONGOS_CAVERN_SE_ROOM, + DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, + DODONGOS_CAVERN_LOWER_LIZALFOS, + DODONGOS_CAVERN_DODONGO_ROOM, + DODONGOS_CAVERN_NEAR_DODONGO_ROOM, + DODONGOS_CAVERN_STAIRS_LOWER, + DODONGOS_CAVERN_STAIRS_UPPER, + DODONGOS_CAVERN_COMPASS_ROOM, + DODONGOS_CAVERN_ARMOS_ROOM, + DODONGOS_CAVERN_BOMB_ROOM_LOWER, + DODONGOS_CAVERN_2F_SIDE_ROOM, + DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, + DODONGOS_CAVERN_UPPER_LIZALFOS, + DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, + DODONGOS_CAVERN_BOMB_ROOM_UPPER, + DODONGOS_CAVERN_FAR_BRIDGE, + DODONGOS_CAVERN_BOSS_AREA, + DODONGOS_CAVERN_BACK_ROOM, + DODONGOS_CAVERN_BOSS_ROOM, + + JABU_JABUS_BELLY_BEGINNING, + JABU_JABUS_BELLY_LIFT_MIDDLE, + JABU_JABUS_BELLY_MAIN_UPPER, + JABU_JABUS_BELLY_MAIN_LOWER, + JABU_JABUS_BELLY_SHABOMB_CORRIDOR, + JABU_JABUS_BELLY_LOWER_SIDE_ROOM, + JABU_JABUS_BELLY_LIFT_LOWER, + JABU_JABUS_BELLY_FORKED_CORRIDOR, + JABU_JABUS_BELLY_BOOMERANG_ROOM, + JABU_JABUS_BELLY_MAP_ROOM, + JABU_JABUS_BELLY_COMPASS_ROOM, + JABU_JABUS_BELLY_BLUE_TENTACLE, + JABU_JABUS_BELLY_GREEN_TENTACLE, + JABU_JABUS_BELLY_BIGOCTO_ROOM, + JABU_JABUS_BELLY_ABOVE_BIGOCTO, + JABU_JABUS_BELLY_LIFT_UPPER, + JABU_JABUS_BELLY_NEAR_BOSS_ROOM, + JABU_JABUS_BELLY_BOSS_ROOM, + + FOREST_TEMPLE_FIRST_ROOM, + FOREST_TEMPLE_SOUTH_CORRIDOR, + FOREST_TEMPLE_LOBBY, + FOREST_TEMPLE_NORTH_CORRIDOR, + FOREST_TEMPLE_LOWER_STALFOS, + FOREST_TEMPLE_NW_OUTDOORS_LOWER, + FOREST_TEMPLE_NW_OUTDOORS_UPPER, + FOREST_TEMPLE_NE_OUTDOORS_LOWER, + FOREST_TEMPLE_NE_OUTDOORS_UPPER, + FOREST_TEMPLE_MAP_ROOM, + FOREST_TEMPLE_SEWER, + FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, + FOREST_TEMPLE_FLOORMASTER_ROOM, + FOREST_TEMPLE_WEST_CORRIDOR, + FOREST_TEMPLE_BLOCK_PUSH_ROOM, + FOREST_TEMPLE_NW_CORRIDOR_TWISTED, + FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, + FOREST_TEMPLE_RED_POE_ROOM, + FOREST_TEMPLE_UPPER_STALFOS, + FOREST_TEMPLE_BLUE_POE_ROOM, + FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, + FOREST_TEMPLE_NE_CORRIDOR_TWISTED, + FOREST_TEMPLE_FROZEN_EYE_ROOM, + FOREST_TEMPLE_FALLING_ROOM, + FOREST_TEMPLE_GREEN_POE_ROOM, + FOREST_TEMPLE_EAST_CORRIDOR, + FOREST_TEMPLE_BOSS_REGION, + FOREST_TEMPLE_BOSS_ROOM, + + FIRE_TEMPLE_FIRST_ROOM, + FIRE_TEMPLE_NEAR_BOSS_ROOM, + FIRE_TEMPLE_BOSS_ROOM, + FIRE_TEMPLE_LOOP_ENEMIES, + FIRE_TEMPLE_LOOP_TILES, + FIRE_TEMPLE_LOOP_FLARE_DANCER, + FIRE_TEMPLE_LOOP_HAMMER_SWITCH, + FIRE_TEMPLE_LOOP_GORON_ROOM, + FIRE_TEMPLE_LOOP_EXIT, + FIRE_TEMPLE_BIG_LAVA_ROOM, + FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON, + FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, + FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON, + FIRE_TEMPLE_FIRE_PILLAR_ROOM, + FIRE_TEMPLE_SHORTCUT_ROOM, + FIRE_TEMPLE_SHORTCUT_CLIMB, + FIRE_TEMPLE_BOULDER_MAZE_LOWER, + FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM, + FIRE_TEMPLE_EAST_CENTRAL_ROOM, + FIRE_TEMPLE_FIRE_WALL_CHASE, + FIRE_TEMPLE_MAP_AREA, + FIRE_TEMPLE_BOULDER_MAZE_UPPER, + FIRE_TEMPLE_SCARECROW_ROOM, + FIRE_TEMPLE_EAST_PEAK, + FIRE_TEMPLE_CORRIDOR, + FIRE_TEMPLE_FIRE_MAZE_ROOM, + FIRE_TEMPLE_FIRE_MAZE_UPPER, + FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM, + FIRE_TEMPLE_WEST_CENTRAL_LOWER, + FIRE_TEMPLE_WEST_CENTRAL_UPPER, + FIRE_TEMPLE_LATE_FIRE_MAZE, + FIRE_TEMPLE_UPPER_FLARE_DANCER, + FIRE_TEMPLE_WEST_CLIMB, + FIRE_TEMPLE_WEST_PEAK, + FIRE_TEMPLE_HAMMER_RETURN_PATH, + FIRE_TEMPLE_ABOVE_FIRE_MAZE, + + WATER_TEMPLE_LOBBY, + WATER_TEMPLE_EAST_LOWER, + WATER_TEMPLE_MAP_ROOM, + WATER_TEMPLE_CRACKED_WALL, + WATER_TEMPLE_TORCH_ROOM, + WATER_TEMPLE_NORTH_LOWER, + WATER_TEMPLE_BOULDERS_LOWER, + WATER_TEMPLE_BLOCK_ROOM, + WATER_TEMPLE_JETS_ROOM, + WATER_TEMPLE_BOULDERS_UPPER, + WATER_TEMPLE_BOSS_KEY_ROOM, + WATER_TEMPLE_SOUTH_LOWER, + WATER_TEMPLE_WEST_LOWER, + WATER_TEMPLE_DRAGON_ROOM, + WATER_TEMPLE_CENTRAL_PILLAR_LOWER, + WATER_TEMPLE_CENTRAL_PILLAR_UPPER, + WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT, + WATER_TEMPLE_EAST_MIDDLE, + WATER_TEMPLE_WEST_MIDDLE, + WATER_TEMPLE_HIGH_WATER, + WATER_TEMPLE_BLOCK_CORRIDOR, + WATER_TEMPLE_FALLING_PLATFORM_ROOM, + WATER_TEMPLE_DRAGON_PILLARS_ROOM, + WATER_TEMPLE_DARK_LINK_ROOM, + WATER_TEMPLE_LONGSHOT_ROOM, + WATER_TEMPLE_RIVER, + WATER_TEMPLE_PRE_BOSS_ROOM, + WATER_TEMPLE_BOSS_ROOM, + + SPIRIT_TEMPLE_LOBBY, + SPIRIT_TEMPLE_CHILD, + SPIRIT_TEMPLE_CHILD_CLIMB, + SPIRIT_TEMPLE_EARLY_ADULT, + SPIRIT_TEMPLE_CENTRAL_CHAMBER, + SPIRIT_TEMPLE_OUTDOOR_HANDS, + SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, + SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, + + SHADOW_TEMPLE_BEGINNING, + SHADOW_TEMPLE_FIRST_BEAMOS, + SHADOW_TEMPLE_HUGE_PIT, + SHADOW_TEMPLE_WIND_TUNNEL, + SHADOW_TEMPLE_BEYOND_BOAT, + + BOTTOM_OF_THE_WELL, + BOTTOM_OF_THE_WELL_MAIN_AREA, + + ICE_CAVERN_BEGINNING, + ICE_CAVERN_MAIN, + + GERUDO_TRAINING_GROUNDS_LOBBY, + GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, + GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, + GERUDO_TRAINING_GROUNDS_LAVA_ROOM, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, + GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, + + GANONS_CASTLE_LOBBY, + GANONS_CASTLE_DEKU_SCRUBS, + GANONS_CASTLE_FOREST_TRIAL, + GANONS_CASTLE_FIRE_TRIAL, + GANONS_CASTLE_WATER_TRIAL, + GANONS_CASTLE_SHADOW_TRIAL, + GANONS_CASTLE_SPIRIT_TRIAL, + GANONS_CASTLE_LIGHT_TRIAL, + GANONS_CASTLE_TOWER, + + DEKU_TREE_MQ_LOBBY, + DEKU_TREE_MQ_COMPASS_ROOM, + DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, + DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, + DEKU_TREE_MQ_BASEMENT_BACK_ROOM, + DEKU_TREE_MQ_BASEMENT_LEDGE, + + DODONGOS_CAVERN_MQ_BEGINNING, + DODONGOS_CAVERN_MQ_LOBBY, + DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, + DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, + DODONGOS_CAVERN_MQ_BOSS_AREA, + + JABU_JABUS_BELLY_MQ_BEGINNING, + JABU_JABUS_BELLY_MQ_MAIN, + JABU_JABUS_BELLY_MQ_DEPTHS, + JABU_JABUS_BELLY_MQ_BOSS_AREA, + + FOREST_TEMPLE_MQ_LOBBY, + FOREST_TEMPLE_MQ_CENTRAL_AREA, + FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, + FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, + FOREST_TEMPLE_MQ_NW_OUTDOORS, + FOREST_TEMPLE_MQ_NE_OUTDOORS, + FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, + FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, + FOREST_TEMPLE_MQ_BOW_REGION, + FOREST_TEMPLE_MQ_FALLING_ROOM, + FOREST_TEMPLE_MQ_BOSS_REGION, + + FIRE_TEMPLE_MQ_LOWER, + FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, + FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, + FIRE_TEMPLE_MQ_LOWER_MAZE, + FIRE_TEMPLE_MQ_UPPER_MAZE, + FIRE_TEMPLE_MQ_UPPER, + FIRE_TEMPLE_MQ_BOSS_ROOM, + + WATER_TEMPLE_MQ_LOBBY, + WATER_TEMPLE_MQ_DIVE, + WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS, + WATER_TEMPLE_MQ_DARK_LINK_REGION, + WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS, + + SPIRIT_TEMPLE_MQ_LOBBY, + SPIRIT_TEMPLE_MQ_CHILD, + SPIRIT_TEMPLE_MQ_ADULT, + SPIRIT_TEMPLE_MQ_SHARED, + SPIRIT_TEMPLE_MQ_LOWER_ADULT, + SPIRIT_TEMPLE_MQ_BOSS_AREA, + SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, + SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, + + SHADOW_TEMPLE_MQ_ENTRYWAY, + SHADOW_TEMPLE_MQ_BEGINNING, + SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, + SHADOW_TEMPLE_MQ_FIRST_BEAMOS, + SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, + SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, + SHADOW_TEMPLE_MQ_WIND_TUNNEL, + SHADOW_TEMPLE_MQ_BEYOND_BOAT, + SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, + + BOTTOM_OF_THE_WELL_MQ, + BOTTOM_OF_THE_WELL_MQ_PERIMETER, + BOTTOM_OF_THE_WELL_MQ_MIDDLE, + + ICE_CAVERN_MQ_BEGINNING, + ICE_CAVERN_MQ_MAP_ROOM, + ICE_CAVERN_MQ_IRON_BOOTS_REGION, + ICE_CAVERN_MQ_COMPASS_ROOM, + + GERUDO_TRAINING_GROUNDS_MQ_LOBBY, + GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, + GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, + GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, + GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, + GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, + GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, + + GANONS_CASTLE_MQ_LOBBY, + GANONS_CASTLE_MQ_DEKU_SCRUBS, + GANONS_CASTLE_MQ_FOREST_TRIAL, + GANONS_CASTLE_MQ_FIRE_TRIAL, + GANONS_CASTLE_MQ_WATER_TRIAL, + GANONS_CASTLE_MQ_SHADOW_TRIAL, + GANONS_CASTLE_MQ_SPIRIT_TRIAL, + GANONS_CASTLE_MQ_LIGHT_TRIAL, + + //DUNGEONS + DEKU_TREE, + DODONGOS_CAVERN, + JABU_JABUS_BELLY, + FOREST_TEMPLE, + FIRE_TEMPLE, + WATER_TEMPLE, + SPIRIT_TEMPLE, + SHADOW_TEMPLE, + ICE_CAVERN, + //BOTTOM_OF_THE_WELL, + GERUDO_TRAINING_GROUNDS, + GANONS_CASTLE, + + //HINTS + PREFIX, + WAY_OF_THE_HERO, + PLUNDERING, + FOOLISH, + CAN_BE_FOUND_AT, + HOARDS, + + JUNK01, + JUNK02, + JUNK03, + JUNK04, + JUNK05, + JUNK06, + JUNK07, + JUNK08, + JUNK09, + JUNK10, + JUNK11, + JUNK12, + JUNK13, + JUNK14, + JUNK15, + JUNK16, + JUNK17, + JUNK18, + JUNK19, + JUNK20, + JUNK21, + JUNK22, + JUNK23, + JUNK24, + JUNK25, + JUNK26, + JUNK27, + JUNK28, + JUNK29, + JUNK30, + JUNK31, + JUNK32, + JUNK33, + JUNK34, + JUNK35, + JUNK36, + JUNK37, + JUNK38, + JUNK39, + JUNK40, + JUNK41, + JUNK42, + JUNK43, + JUNK44, + JUNK45, + JUNK46, + JUNK47, + JUNK48, + JUNK49, + JUNK50, + JUNK51, + JUNK52, + JUNK53, + JUNK54, + JUNK55, + JUNK56, + JUNK57, + JUNK58, + JUNK59, + JUNK60, + JUNK61, + JUNK62, + JUNK63, + JUNK64, + JUNK65, + JUNK66, + JUNK67, + JUNK68, + JUNK69, + JUNK70, + JUNK71, + JUNK72, + JUNK73, + JUNK74, + JUNK75, + JUNK76, + JUNK77, + JUNK78, + JUNK79, + JUNK80, + JUNK81, + + BRIDGE_OPEN_HINT, + BRIDGE_VANILLA_HINT, + BRIDGE_STONES_HINT, + BRIDGE_MEDALLIONS_HINT, + BRIDGE_REWARDS_HINT, + BRIDGE_DUNGEONS_HINT, + BRIDGE_TOKENS_HINT, + + GANON_BK_START_WITH_HINT, + GANON_BK_VANILLA_HINT, + GANON_BK_OWN_DUNGEON_HINT, + GANON_BK_OVERWORLD_HINT, + GANON_BK_ANY_DUNGEON_HINT, + GANON_BK_ANYWHERE_HINT, + GANON_BK_TRIFORCE_HINT, + + LACS_VANILLA_HINT, + LACS_MEDALLIONS_HINT, + LACS_STONES_HINT, + LACS_REWARDS_HINT, + LACS_DUNGEONS_HINT, + LACS_TOKENS_HINT, + + SIX_TRIALS, + ZERO_TRIALS, + FOUR_TO_FIVE_TRIALS, + ONE_TO_THREE_TRIALS, + + SPIRITUAL_STONE_TEXT_START, + CHILD_ALTAR_TEXT_END_DOTOPEN, + CHILD_ALTAR_TEXT_END_DOTCLOSED, + CHILD_ALTAR_TEXT_END_DOTINTENDED, + ADULT_ALTAR_TEXT_START, + ADULT_ALTAR_TEXT_END, + + VALIDATION_LINE, + LIGHT_ARROW_LOCATION_HINT, + YOUR_POCKET, + + GANON_LINE01, + GANON_LINE02, + GANON_LINE03, + GANON_LINE04, + GANON_LINE05, + GANON_LINE06, + GANON_LINE07, + GANON_LINE08, + GANON_LINE09, + GANON_LINE10, + GANON_LINE11, + + MEDIGORON_DIALOG_FIRST, + MEDIGORON_DIALOG_SECOND, + CARPET_SALESMAN_DIALOG_FIRST, + CARPET_SALESMAN_DIALOG_SECOND, + CARPET_SALESMAN_DIALOG_THIRD, + CARPET_SALESMAN_DIALOG_FOURTH, + + KEY_ENUM_MAX, +} Key; \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp new file mode 100644 index 000000000..c4506a66d --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp @@ -0,0 +1,898 @@ +#include "location_access.hpp" + +#include "dungeon.hpp" +#include "item_list.hpp" +#include "item_location.hpp" +#include "item_pool.hpp" +#include "logic.hpp" +#include "settings.hpp" +#include "spoiler_log.hpp" +#include "trial.hpp" +#include "entrance.hpp" + +#include +#include + +using namespace Logic; +using namespace Settings; + +//generic grotto event list +std::vector grottoEvents = { + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || (CanUse(STICKS));}}), + EventAccess(&BugShrub, {[]{return CanCutShrubs;}}), + EventAccess(&LoneFish, {[]{return true;}}), +}; + +//set the logic to be a specific age and time of day and see if the condition still holds +bool LocationAccess::CheckConditionAtAgeTime(bool& age, bool& time) const { + + IsChild = false; + IsAdult = false; + AtDay = false; + AtNight = false; + + time = true; + age = true; + + UpdateHelpers(); + return GetConditionsMet(); +} + +bool LocationAccess::ConditionsMet() const { + + Area* parentRegion = AreaTable(Location(location)->GetParentRegionKey()); + bool conditionsMet = false; + + if ((parentRegion->childDay && CheckConditionAtAgeTime(IsChild, AtDay)) || + (parentRegion->childNight && CheckConditionAtAgeTime(IsChild, AtNight)) || + (parentRegion->adultDay && CheckConditionAtAgeTime(IsAdult, AtDay)) || + (parentRegion->adultNight && CheckConditionAtAgeTime(IsAdult, AtNight))) { + conditionsMet = true; + } + + return conditionsMet && CanBuy(); +} + +bool LocationAccess::CanBuy() const { + //Not a shop location, don't need to check if buyable + if (!(Location(location)->IsCategory(Category::cShop))) { + return true; + } + + //Check if wallet is large enough to buy item + bool SufficientWallet = true; + if (Location(location)->GetPrice() > 500) { + SufficientWallet = ProgressiveWallet >= 3; + } else if (Location(location)->GetPrice() > 200) { + SufficientWallet = ProgressiveWallet >= 2; + } else if (Location(location)->GetPrice() > 99) { + SufficientWallet = ProgressiveWallet >= 1; + } + + bool OtherCondition = true; + uint32_t placed = Location(location)->GetPlacedItemKey(); + //Need bottle to buy bottle items, only logically relevant bottle items included here + if (placed == BUY_BLUE_FIRE || placed == BUY_BOTTLE_BUG || placed == BUY_FISH || placed == BUY_FAIRYS_SPIRIT) { + OtherCondition = HasBottle; + } + //If bombchus in logic, need to have found chus to buy; if not just need bomb bag + else if (placed == BUY_BOMBCHU_5 || placed == BUY_BOMBCHU_10 || placed == BUY_BOMBCHU_20) { + OtherCondition = (!BombchusInLogic && Bombs) || (BombchusInLogic && FoundBombchus); + } + + return SufficientWallet && OtherCondition; +} + +Area::Area() = default; +Area::Area(std::string regionName_, std::string scene_, uint32_t hintKey_, + bool timePass_, + std::vector events_, + std::vector locations_, + std::list exits_) + : regionName(std::move(regionName_)), + scene(std::move(scene_)), + hintKey(hintKey_), + timePass(timePass_), + events(std::move(events_)), + locations(std::move(locations_)), + exits(std::move(exits_)) {} + +Area::~Area() = default; + +bool Area::UpdateEvents(SearchMode mode) { + + if (timePass && mode != SearchMode::TimePassAccess) { + if (Child()) { + childDay = true; + childNight = true; + AreaTable(ROOT)->childDay = true; + AreaTable(ROOT)->childNight = true; + } + if (Adult()) { + adultDay = true; + adultNight = true; + AreaTable(ROOT)->adultDay = true; + AreaTable(ROOT)->adultNight = true; + } + } + + bool eventsUpdated = false; + + for (EventAccess& event : events) { + //If the event has already happened, there's no reason to check it + if (event.GetEvent()) { + continue; + } + + if ((childDay && event.CheckConditionAtAgeTime(IsChild, AtDay)) || + (childNight && event.CheckConditionAtAgeTime(IsChild, AtNight)) || + (adultDay && event.CheckConditionAtAgeTime(IsAdult, AtDay)) || + (adultNight && event.CheckConditionAtAgeTime(IsAdult, AtNight))) { + event.EventOccurred(); + eventsUpdated = true; + } + } + return eventsUpdated; +} + +void Area::AddExit(uint32_t parentKey, uint32_t newExitKey, ConditionFn condition) { + Entrance newExit = Entrance(newExitKey, {condition}); + newExit.SetParentRegion(parentKey); + exits.push_front(newExit); +} + +//The exit will be completely removed from this area +void Area::RemoveExit(Entrance* exitToRemove) { + exits.remove_if([exitToRemove](const auto exit){return &exit == exitToRemove;}); +} + +void Area::SetAsPrimary(uint32_t exitToBePrimary) { + for (auto& exit : exits) { + if (exit.Getuint32_t() == exitToBePrimary) { + exit.SetAsPrimary(); + return; + } + } +} + +Entrance* Area::GetExit(uint32_t exitToReturn) { + for (auto& exit : exits) { + if (exit.Getuint32_t() == exitToReturn) { + return &exit; + } + } + auto message = "ERROR: EXIT " + AreaTable(exitToReturn)->regionName + " DOES NOT EXIST IN " + this->regionName; + CitraPrint(message); + return nullptr; +} + +bool Area::CanPlantBeanCheck() const { + return (Logic::MagicBean || Logic::MagicBeanPack) && BothAgesCheck(); +} + +bool Area::AllAccountedFor() const { + for (const EventAccess& event : events) { + if (!event.GetEvent()) { + return false; + } + } + + for (const LocationAccess& loc : locations) { + if (!(Location(loc.GetLocation())->IsAddedToPool())) { + return false; + } + } + + for (const auto& exit : exits) { + if (!exit.GetConnectedRegion()->AllAccess()) { + return false; + } + } + + return AllAccess(); +} + +bool Area::CheckAllAccess(const uint32_t exitKey) { + if (!AllAccess()) { + return false; + } + + for (Entrance& exit : exits) { + if (exit.Getuint32_t() == exitKey) { + return exit.CheckConditionAtAgeTime(Logic::IsChild, Logic::AtDay) && + exit.CheckConditionAtAgeTime(Logic::IsChild, Logic::AtNight) && + exit.CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtDay) && + exit.CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtNight); + } + } + return false; +} + +void Area::ResetVariables() { + childDay = false; + childNight = false; + adultDay = false; + adultNight = false; + addedToPool = false; + for (auto& exit : exits) { + exit.RemoveFromPool(); + } +} + +std::array areaTable; + +bool Here(const uint32_t area, ConditionFn condition) { + return areaTable[area].HereCheck(condition); +} + +bool CanPlantBean(const uint32_t area) { + return areaTable[area].CanPlantBeanCheck(); +} + +bool BothAges(const uint32_t area) { + return areaTable[area].BothAgesCheck(); +} + +bool ChildCanAccess(const uint32_t area) { + return areaTable[area].Child(); +} + +bool AdultCanAccess(const uint32_t area) { + return areaTable[area].Adult(); +} + +bool HasAccessTo(const uint32_t area) { + return areaTable[area].HasAccess(); +} + + + +void AreaTable_Init() { + //Clear the array from any previous playthrough attempts. This is important so that + //locations which appear in both MQ and Vanilla dungeons don't get set in both areas. + areaTable.fill(Area("Invalid Area", "Invalid Area", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {})); + + //name, scene, hint text, events, locations, exits + areaTable[ROOT] = Area("Root", "", LINKS_POCKET, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LINKS_POCKET, {[]{return true;}}) + }, { + //Exits + Entrance(ROOT_EXITS, {[]{return true;}}) + }); + + areaTable[ROOT_EXITS] = Area("Root Exits", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KF_LINKS_HOUSE, {[]{return IsChild;}}), + Entrance(TEMPLE_OF_TIME, {[]{return (CanPlay(PreludeOfLight) && CanLeaveForest) || IsAdult;}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && PreludeOfLight && CanLeaveForest;}}), + Entrance(SACRED_FOREST_MEADOW, {[]{return CanPlay(MinuetOfForest);}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && MinuetOfForest;}}), + Entrance(DMC_CENTRAL_LOCAL, {[]{return CanPlay(BoleroOfFire) && CanLeaveForest;}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && BoleroOfFire && CanLeaveForest;}}), + Entrance(LAKE_HYLIA, {[]{return CanPlay(SerenadeOfWater) && CanLeaveForest;}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && SerenadeOfWater && CanLeaveForest;}}), + Entrance(GRAVEYARD_WARP_PAD_REGION, {[]{return CanPlay(NocturneOfShadow) && CanLeaveForest;}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && NocturneOfShadow && CanLeaveForest;}}), + Entrance(DESERT_COLOSSUS, {[]{return CanPlay(RequiemOfSpirit) && CanLeaveForest;}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && RequiemOfSpirit && CanLeaveForest;}}), + }); + + // Overworld + AreaTable_Init_LostWoods(); + AreaTable_Init_HyruleField(); + AreaTable_Init_CastleTown(); + AreaTable_Init_Kakariko(); + AreaTable_Init_DeathMountain(); + AreaTable_Init_ZorasDomain(); + AreaTable_Init_GerudoValley(); + // Dungeons + AreaTable_Init_DekuTree(); + AreaTable_Init_DodongosCavern(); + AreaTable_Init_JabuJabusBelly(); + AreaTable_Init_ForestTemple(); + AreaTable_Init_FireTemple(); + AreaTable_Init_WaterTemple(); + AreaTable_Init_SpiritTemple(); + AreaTable_Init_ShadowTemple(); + AreaTable_Init_BottomOfTheWell(); + AreaTable_Init_IceCavern(); + AreaTable_Init_GerudoTrainingGrounds(); + AreaTable_Init_GanonsCastle(); + + //Set parent regions + for (uint32_t i = ROOT; i <= GANONS_CASTLE; i++) { + for (LocationAccess& locPair : areaTable[i].locations) { + uint32_t location = locPair.GetLocation(); + Location(location)->SetParentRegion(i); + } + for (Entrance& exit : areaTable[i].exits) { + exit.SetParentRegion(i); + exit.SetName(); + exit.GetConnectedRegion()->entrances.push_front(&exit); + } + } + /* + //Events +}, { + //Locations +}, { + //Exits +*/ +} + +namespace Areas { + + static std::array allAreas = { + ROOT, + ROOT_EXITS, + + KOKIRI_FOREST, + KF_LINKS_HOUSE, + KF_MIDOS_HOUSE, + KF_SARIAS_HOUSE, + KF_HOUSE_OF_TWINS, + KF_KNOW_IT_ALL_HOUSE, + KF_KOKIRI_SHOP, + KF_STORMS_GROTTO, + KF_OUTSIDE_DEKU_TREE, + DEKU_TREE_ENTRYWAY, + + THE_LOST_WOODS, + LW_BRIDGE_FROM_FOREST, + LW_BRIDGE, + LW_FOREST_EXIT, + LW_BEYOND_MIDO, + LW_NEAR_SHORTCUTS_GROTTO, + DEKU_THEATER, + LW_SCRUBS_GROTTO, + SFM_ENTRYWAY, + SACRED_FOREST_MEADOW, + SFM_WOLFOS_GROTTO, + SFM_FAIRY_GROTTO, + SFM_STORMS_GROTTO, + FOREST_TEMPLE_ENTRYWAY, + + KAKARIKO_VILLAGE, + KAK_CARPENTER_BOSS_HOUSE, + KAK_HOUSE_OF_SKULLTULA, + KAK_IMPAS_HOUSE, + KAK_IMPAS_LEDGE, + KAK_IMPAS_HOUSE_BACK, + KAK_IMPAS_HOUSE_NEAR_COW, + KAK_WINDMILL, + KAK_BAZAAR, + KAK_SHOOTING_GALLERY, + KAK_POTION_SHOP_FRONT, + KAK_POTION_SHOP_BACK, + KAK_ROOFTOP, + KAK_BEHIND_GATE, + KAK_BACKYARD, + KAK_ODD_POTION_BUILDING, + KAK_REDEAD_GROTTO, + KAK_OPEN_GROTTO, + BOTTOM_OF_THE_WELL_ENTRYWAY, + + THE_GRAVEYARD, + GRAVEYARD_DAMPES_GRAVE, + GRAVEYARD_DAMPES_HOUSE, + GRAVEYARD_SHIELD_GRAVE, + GRAVEYARD_COMPOSERS_GRAVE, + GRAVEYARD_HEART_PIECE_GRAVE, + GRAVEYARD_WARP_PAD_REGION, + SHADOW_TEMPLE_ENTRYWAY, + + DEATH_MOUNTAIN_TRAIL, + DEATH_MOUNTAIN_SUMMIT, + DMT_OWL_FLIGHT, + DMT_GREAT_FAIRY_FOUNTAIN, + DMT_COW_GROTTO, + DMT_STORMS_GROTTO, + DODONGOS_CAVERN_ENTRYWAY, + + DMC_UPPER_LOCAL, + DMC_CENTRAL_LOCAL, + DMC_LOWER_LOCAL, + DMC_LOWER_NEARBY, + DMC_UPPER_NEARBY, + DMC_CENTRAL_NEARBY, + DMC_LADDER_AREA_NEARBY, + DMC_UPPER_GROTTO, + DMC_HAMMER_GROTTO, + DMC_GREAT_FAIRY_FOUNTAIN, + FIRE_TEMPLE_ENTRYWAY, + + GORON_CITY, + GC_WOODS_WARP, + GC_DARUNIAS_CHAMBER, + GC_GROTTO_PLATFORM, + GC_SHOP, + GC_GROTTO, + + ZR_FRONT, + ZORAS_RIVER, + ZR_BEHIND_WATERFALL, + ZR_OPEN_GROTTO, + ZR_FAIRY_GROTTO, + ZR_STORMS_GROTTO, + ZORAS_DOMAIN, + ZD_BEHIND_KING_ZORA, + ZD_SHOP, + ZD_STORMS_GROTTO, + ZORAS_FOUNTAIN, + ZF_GREAT_FAIRY_FOUNTAIN, + JABU_JABUS_BELLY_ENTRYWAY, + ICE_CAVERN_ENTRYWAY, + + HYRULE_FIELD, + HF_SOUTHEAST_GROTTO, + HF_OPEN_GROTTO, + HF_INSIDE_FENCE_GROTTO, + HF_COW_GROTTO, + HF_NEAR_MARKET_GROTTO, + HF_FAIRY_GROTTO, + HF_NEAR_KAK_GROTTO, + HF_TEKTITE_GROTTO, + + LON_LON_RANCH, + LLR_TALONS_HOUSE, + LLR_STABLES, + LLR_TOWER, + LLR_GROTTO, + + LAKE_HYLIA, + LH_OWL_FLIGHT, + LH_LAB, + LH_FISHING_ISLAND, + LH_FISHING_HOLE, + LH_GROTTO, + WATER_TEMPLE_ENTRYWAY, + + GERUDO_VALLEY, + GV_UPPER_STREAM, + GV_LOWER_STREAM, + GV_GROTTO_LEDGE, + GV_CRATE_LEDGE, + GV_OCTOROK_GROTTO, + GV_FORTRESS_SIDE, + GV_CARPENTER_TENT, + GV_STORMS_GROTTO, + GERUDO_FORTRESS, + GF_OUTSIDE_GATE, + GF_STORMS_GROTTO, + GERUDO_TRAINING_GROUNDS_ENTRYWAY, + + WASTELAND_NEAR_FORTRESS, + HAUNTED_WASTELAND, + WASTELAND_NEAR_COLOSSUS, + DESERT_COLOSSUS, + COLOSSUS_GREAT_FAIRY_FOUNTAIN, + COLOSSUS_GROTTO, + SPIRIT_TEMPLE_ENTRYWAY, + + MARKET_ENTRANCE, + THE_MARKET, + MARKET_GUARD_HOUSE, + MARKET_BAZAAR, + MARKET_MASK_SHOP, + MARKET_SHOOTING_GALLERY, + MARKET_BOMBCHU_BOWLING, + MARKET_TREASURE_CHEST_GAME, + MARKET_POTION_SHOP, + MARKET_BACK_ALLEY, + MARKET_BOMBCHU_SHOP, + MARKET_DOG_LADY_HOUSE, + MARKET_MAN_IN_GREEN_HOUSE, + TOT_ENTRANCE, + TEMPLE_OF_TIME, + TOT_BEYOND_DOOR_OF_TIME, + + CASTLE_GROUNDS, + HYRULE_CASTLE_GROUNDS, + HC_GARDEN, + HC_GREAT_FAIRY_FOUNTAIN, + HC_STORMS_GROTTO, + GANONS_CASTLE_GROUNDS, + OGC_GREAT_FAIRY_FOUNTAIN, + GANONS_CASTLE_ENTRYWAY, + + DEKU_TREE_LOBBY, + DEKU_TREE_2F_MIDDLE_ROOM, + DEKU_TREE_SLINGSHOT_ROOM, + DEKU_TREE_COMPASS_ROOM, + DEKU_TREE_BASEMENT_LOWER, + DEKU_TREE_BASEMENT_SCRUB_ROOM, + DEKU_TREE_BASEMENT_WATER_ROOM, + DEKU_TREE_BASEMENT_TORCH_ROOM, + DEKU_TREE_BASEMENT_BACK_LOBBY, + DEKU_TREE_BASEMENT_BACK_ROOM, + DEKU_TREE_BASEMENT_UPPER, + DEKU_TREE_OUTSIDE_BOSS_ROOM, + DEKU_TREE_BOSS_ROOM, + + DODONGOS_CAVERN_BEGINNING, + DODONGOS_CAVERN_LOBBY, + DODONGOS_CAVERN_LOBBY_SWITCH, + DODONGOS_CAVERN_SE_CORRIDOR, + DODONGOS_CAVERN_SE_ROOM, + DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, + DODONGOS_CAVERN_LOWER_LIZALFOS, + DODONGOS_CAVERN_DODONGO_ROOM, + DODONGOS_CAVERN_NEAR_DODONGO_ROOM, + DODONGOS_CAVERN_STAIRS_LOWER, + DODONGOS_CAVERN_STAIRS_UPPER, + DODONGOS_CAVERN_COMPASS_ROOM, + DODONGOS_CAVERN_ARMOS_ROOM, + DODONGOS_CAVERN_BOMB_ROOM_LOWER, + DODONGOS_CAVERN_2F_SIDE_ROOM, + DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, + DODONGOS_CAVERN_UPPER_LIZALFOS, + DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, + DODONGOS_CAVERN_BOMB_ROOM_UPPER, + DODONGOS_CAVERN_FAR_BRIDGE, + DODONGOS_CAVERN_BOSS_AREA, + DODONGOS_CAVERN_BACK_ROOM, + DODONGOS_CAVERN_BOSS_ROOM, + + JABU_JABUS_BELLY_BEGINNING, + JABU_JABUS_BELLY_LIFT_MIDDLE, + JABU_JABUS_BELLY_MAIN_UPPER, + JABU_JABUS_BELLY_MAIN_LOWER, + JABU_JABUS_BELLY_SHABOMB_CORRIDOR, + JABU_JABUS_BELLY_LOWER_SIDE_ROOM, + JABU_JABUS_BELLY_LIFT_LOWER, + JABU_JABUS_BELLY_FORKED_CORRIDOR, + JABU_JABUS_BELLY_BOOMERANG_ROOM, + JABU_JABUS_BELLY_MAP_ROOM, + JABU_JABUS_BELLY_COMPASS_ROOM, + JABU_JABUS_BELLY_BLUE_TENTACLE, + JABU_JABUS_BELLY_GREEN_TENTACLE, + JABU_JABUS_BELLY_BIGOCTO_ROOM, + JABU_JABUS_BELLY_ABOVE_BIGOCTO, + JABU_JABUS_BELLY_LIFT_UPPER, + JABU_JABUS_BELLY_NEAR_BOSS_ROOM, + JABU_JABUS_BELLY_BOSS_ROOM, + + FOREST_TEMPLE_FIRST_ROOM, + FOREST_TEMPLE_SOUTH_CORRIDOR, + FOREST_TEMPLE_LOBBY, + FOREST_TEMPLE_NORTH_CORRIDOR, + FOREST_TEMPLE_LOWER_STALFOS, + FOREST_TEMPLE_NW_OUTDOORS_LOWER, + FOREST_TEMPLE_NW_OUTDOORS_UPPER, + FOREST_TEMPLE_NE_OUTDOORS_LOWER, + FOREST_TEMPLE_NE_OUTDOORS_UPPER, + FOREST_TEMPLE_MAP_ROOM, + FOREST_TEMPLE_SEWER, + FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, + FOREST_TEMPLE_FLOORMASTER_ROOM, + FOREST_TEMPLE_WEST_CORRIDOR, + FOREST_TEMPLE_BLOCK_PUSH_ROOM, + FOREST_TEMPLE_NW_CORRIDOR_TWISTED, + FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, + FOREST_TEMPLE_RED_POE_ROOM, + FOREST_TEMPLE_UPPER_STALFOS, + FOREST_TEMPLE_BLUE_POE_ROOM, + FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, + FOREST_TEMPLE_NE_CORRIDOR_TWISTED, + FOREST_TEMPLE_FROZEN_EYE_ROOM, + FOREST_TEMPLE_FALLING_ROOM, + FOREST_TEMPLE_GREEN_POE_ROOM, + FOREST_TEMPLE_EAST_CORRIDOR, + FOREST_TEMPLE_BOSS_REGION, + FOREST_TEMPLE_BOSS_ROOM, + + FIRE_TEMPLE_FIRST_ROOM, + FIRE_TEMPLE_NEAR_BOSS_ROOM, + FIRE_TEMPLE_BOSS_ROOM, + FIRE_TEMPLE_LOOP_ENEMIES, + FIRE_TEMPLE_LOOP_TILES, + FIRE_TEMPLE_LOOP_FLARE_DANCER, + FIRE_TEMPLE_LOOP_HAMMER_SWITCH, + FIRE_TEMPLE_LOOP_GORON_ROOM, + FIRE_TEMPLE_LOOP_EXIT, + FIRE_TEMPLE_BIG_LAVA_ROOM, + FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON, + FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, + FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON, + FIRE_TEMPLE_FIRE_PILLAR_ROOM, + FIRE_TEMPLE_SHORTCUT_ROOM, + FIRE_TEMPLE_SHORTCUT_CLIMB, + FIRE_TEMPLE_BOULDER_MAZE_LOWER, + FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM, + FIRE_TEMPLE_EAST_CENTRAL_ROOM, + FIRE_TEMPLE_FIRE_WALL_CHASE, + FIRE_TEMPLE_MAP_AREA, + FIRE_TEMPLE_BOULDER_MAZE_UPPER, + FIRE_TEMPLE_SCARECROW_ROOM, + FIRE_TEMPLE_EAST_PEAK, + FIRE_TEMPLE_CORRIDOR, + FIRE_TEMPLE_FIRE_MAZE_ROOM, + FIRE_TEMPLE_FIRE_MAZE_UPPER, + FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM, + FIRE_TEMPLE_WEST_CENTRAL_LOWER, + FIRE_TEMPLE_WEST_CENTRAL_UPPER, + FIRE_TEMPLE_LATE_FIRE_MAZE, + FIRE_TEMPLE_UPPER_FLARE_DANCER, + FIRE_TEMPLE_WEST_CLIMB, + FIRE_TEMPLE_WEST_PEAK, + FIRE_TEMPLE_HAMMER_RETURN_PATH, + FIRE_TEMPLE_ABOVE_FIRE_MAZE, + + WATER_TEMPLE_LOBBY, + WATER_TEMPLE_EAST_LOWER, + WATER_TEMPLE_MAP_ROOM, + WATER_TEMPLE_CRACKED_WALL, + WATER_TEMPLE_TORCH_ROOM, + WATER_TEMPLE_NORTH_LOWER, + WATER_TEMPLE_BOULDERS_LOWER, + WATER_TEMPLE_BLOCK_ROOM, + WATER_TEMPLE_JETS_ROOM, + WATER_TEMPLE_BOULDERS_UPPER, + WATER_TEMPLE_BOSS_KEY_ROOM, + WATER_TEMPLE_SOUTH_LOWER, + WATER_TEMPLE_WEST_LOWER, + WATER_TEMPLE_DRAGON_ROOM, + WATER_TEMPLE_CENTRAL_PILLAR_LOWER, + WATER_TEMPLE_CENTRAL_PILLAR_UPPER, + WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT, + WATER_TEMPLE_EAST_MIDDLE, + WATER_TEMPLE_WEST_MIDDLE, + WATER_TEMPLE_HIGH_WATER, + WATER_TEMPLE_BLOCK_CORRIDOR, + WATER_TEMPLE_FALLING_PLATFORM_ROOM, + WATER_TEMPLE_DRAGON_PILLARS_ROOM, + WATER_TEMPLE_DARK_LINK_ROOM, + WATER_TEMPLE_LONGSHOT_ROOM, + WATER_TEMPLE_RIVER, + WATER_TEMPLE_PRE_BOSS_ROOM, + WATER_TEMPLE_BOSS_ROOM, + + SPIRIT_TEMPLE_LOBBY, + SPIRIT_TEMPLE_CHILD, + SPIRIT_TEMPLE_CHILD_CLIMB, + SPIRIT_TEMPLE_EARLY_ADULT, + SPIRIT_TEMPLE_CENTRAL_CHAMBER, + SPIRIT_TEMPLE_OUTDOOR_HANDS, + SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, + SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, + SHADOW_TEMPLE_BEGINNING, + SHADOW_TEMPLE_FIRST_BEAMOS, + SHADOW_TEMPLE_HUGE_PIT, + SHADOW_TEMPLE_WIND_TUNNEL, + SHADOW_TEMPLE_BEYOND_BOAT, + BOTTOM_OF_THE_WELL, + BOTTOM_OF_THE_WELL_MAIN_AREA, + ICE_CAVERN_BEGINNING, + ICE_CAVERN_MAIN, + GERUDO_TRAINING_GROUNDS_LOBBY, + GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, + GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, + GERUDO_TRAINING_GROUNDS_LAVA_ROOM, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, + GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, + GANONS_CASTLE_LOBBY, + GANONS_CASTLE_DEKU_SCRUBS, + GANONS_CASTLE_FOREST_TRIAL, + GANONS_CASTLE_FIRE_TRIAL, + GANONS_CASTLE_WATER_TRIAL, + GANONS_CASTLE_SHADOW_TRIAL, + GANONS_CASTLE_SPIRIT_TRIAL, + GANONS_CASTLE_LIGHT_TRIAL, + GANONS_CASTLE_TOWER, + DEKU_TREE_MQ_LOBBY, + DEKU_TREE_MQ_COMPASS_ROOM, + DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, + DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, + DEKU_TREE_MQ_BASEMENT_BACK_ROOM, + DEKU_TREE_MQ_BASEMENT_LEDGE, + DODONGOS_CAVERN_MQ_BEGINNING, + DODONGOS_CAVERN_MQ_LOBBY, + DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, + DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, + DODONGOS_CAVERN_MQ_BOSS_AREA, + JABU_JABUS_BELLY_MQ_BEGINNING, + JABU_JABUS_BELLY_MQ_MAIN, + JABU_JABUS_BELLY_MQ_DEPTHS, + JABU_JABUS_BELLY_MQ_BOSS_AREA, + FOREST_TEMPLE_MQ_LOBBY, + FOREST_TEMPLE_MQ_CENTRAL_AREA, + FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, + FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, + FOREST_TEMPLE_MQ_NW_OUTDOORS, + FOREST_TEMPLE_MQ_NE_OUTDOORS, + FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, + FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, + FOREST_TEMPLE_MQ_BOW_REGION, + FOREST_TEMPLE_MQ_FALLING_ROOM, + FOREST_TEMPLE_MQ_BOSS_REGION, + FIRE_TEMPLE_MQ_LOWER, + FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, + FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, + FIRE_TEMPLE_MQ_LOWER_MAZE, + FIRE_TEMPLE_MQ_UPPER_MAZE, + FIRE_TEMPLE_MQ_UPPER, + FIRE_TEMPLE_MQ_BOSS_ROOM, + WATER_TEMPLE_MQ_LOBBY, + WATER_TEMPLE_MQ_DIVE, + WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS, + WATER_TEMPLE_MQ_DARK_LINK_REGION, + WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS, + SPIRIT_TEMPLE_MQ_LOBBY, + SPIRIT_TEMPLE_MQ_CHILD, + SPIRIT_TEMPLE_MQ_ADULT, + SPIRIT_TEMPLE_MQ_SHARED, + SPIRIT_TEMPLE_MQ_LOWER_ADULT, + SPIRIT_TEMPLE_MQ_BOSS_AREA, + SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, + SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, + SHADOW_TEMPLE_MQ_ENTRYWAY, + SHADOW_TEMPLE_MQ_BEGINNING, + SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, + SHADOW_TEMPLE_MQ_FIRST_BEAMOS, + SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, + SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, + SHADOW_TEMPLE_MQ_WIND_TUNNEL, + SHADOW_TEMPLE_MQ_BEYOND_BOAT, + SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, + BOTTOM_OF_THE_WELL_MQ, + BOTTOM_OF_THE_WELL_MQ_PERIMETER, + BOTTOM_OF_THE_WELL_MQ_MIDDLE, + ICE_CAVERN_MQ_BEGINNING, + ICE_CAVERN_MQ_MAP_ROOM, + ICE_CAVERN_MQ_IRON_BOOTS_REGION, + ICE_CAVERN_MQ_COMPASS_ROOM, + GERUDO_TRAINING_GROUNDS_MQ_LOBBY, + GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, + GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, + GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, + GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, + GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, + GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, + GANONS_CASTLE_MQ_LOBBY, + GANONS_CASTLE_MQ_DEKU_SCRUBS, + GANONS_CASTLE_MQ_FOREST_TRIAL, + GANONS_CASTLE_MQ_FIRE_TRIAL, + GANONS_CASTLE_MQ_WATER_TRIAL, + GANONS_CASTLE_MQ_SHADOW_TRIAL, + GANONS_CASTLE_MQ_SPIRIT_TRIAL, + GANONS_CASTLE_MQ_LIGHT_TRIAL, + }; + + void AccessReset() { + for (const uint32_t area : allAreas) { + AreaTable(area)->ResetVariables(); + } + + if(Settings::HasNightStart) { + if(Settings::ResolvedStartingAge == AGE_CHILD) { + AreaTable(ROOT)->childNight = true; + } else { + AreaTable(ROOT)->adultNight = true; + } + } else { + if(Settings::ResolvedStartingAge == AGE_CHILD) { + AreaTable(ROOT)->childDay = true; + } else { + AreaTable(ROOT)->adultDay = true; + } + } + } + + //Reset exits and clear items from locations + void ResetAllLocations() { + for (const uint32_t area : allAreas) { + AreaTable(area)->ResetVariables(); + //Erase item from every location in this exit + for (LocationAccess& locPair : AreaTable(area)->locations) { + uint32_t location = locPair.GetLocation(); + Location(location)->ResetVariables(); + } + } + + if(Settings::HasNightStart) { + if(Settings::ResolvedStartingAge == AGE_CHILD) { + AreaTable(ROOT)->childNight = true; + } else { + AreaTable(ROOT)->adultNight = true; + } + } else { + if(Settings::ResolvedStartingAge == AGE_CHILD) { + AreaTable(ROOT)->childDay = true; + } else { + AreaTable(ROOT)->adultDay = true; + } + } + } + + bool HasTimePassAccess(uint8_t age) { + for (const uint32_t areaKey : allAreas) { + auto area = AreaTable(areaKey); + if (area->timePass && ((age == AGE_CHILD && area->Child()) || (age == AGE_ADULT && area->Adult()))) { + return true; + } + } + return false; + } + + // Will dump a file which can be turned into a visual graph using graphviz + // https://graphviz.org/download/ + // Use command: dot -Tsvg -o world.svg + // Then open in a browser and CTRL + F to find the area of interest + void DumpWorldGraph(std::string str) { + std::ofstream worldGraph; + worldGraph.open (str + ".dot"); + worldGraph << "digraph {\n\tcenter=true;\n"; + + for (const uint32_t areaKey : allAreas) { + auto area = AreaTable(areaKey); + for (auto exit : area->exits) { + if (exit.GetConnectedRegion()->regionName != "Invalid Area") { + std::string parent = exit.GetParentRegion()->regionName; + if (area->childDay) { + parent += " CD"; + } + if (area->childNight) { + parent += " CN"; + } + if (area->adultDay) { + parent += " AD"; + } + if (area->adultNight) { + parent += " AN"; + } + Area* connected = exit.GetConnectedRegion(); + auto connectedStr = connected->regionName; + if (connected->childDay) { + connectedStr += " CD"; + } + if (connected->childNight) { + connectedStr += " CN"; + } + if (connected->adultDay) { + connectedStr += " AD"; + } + if (connected->adultNight) { + connectedStr += " AN"; + } + worldGraph << "\t\"" + parent + "\"[shape=\"plain\"];\n"; + worldGraph << "\t\"" + connectedStr + "\"[shape=\"plain\"];\n"; + worldGraph << "\t\"" + parent + "\" -> \"" + connectedStr + "\"\n"; + } + } + } + worldGraph << "}"; + worldGraph.close(); + } + +} //namespace Areas + +Area* AreaTable(const uint32_t areaKey) { + if (areaKey > KEY_ENUM_MAX) { + printf("\x1b[1;1HERROR: AREAKEY TOO BIG"); + } + return &(areaTable[areaKey]); +} + +//Retrieve all the shuffable entrances of a specific type +std::vector GetShuffleableEntrances(EntranceType type, bool onlyPrimary /*= true*/) { + std::vector entrancesToShuffle = {}; + for (uint32_t area : Areas::allAreas) { + for (auto& exit: AreaTable(area)->exits) { + if ((exit.GetType() == type || type == EntranceType::All) && (exit.IsPrimary() || !onlyPrimary) && exit.GetType() != EntranceType::None) { + entrancesToShuffle.push_back(&exit); + } + } + } + return entrancesToShuffle; +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.hpp b/soh/soh/Enhancements/randomizer/3drando/location_access.hpp new file mode 100644 index 000000000..7ec696ac1 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access.hpp @@ -0,0 +1,266 @@ +#pragma once + +#include +#include +#include + +#include "logic.hpp" +#include "hint_list.hpp" +#include "keys.hpp" +#include "fill.hpp" + +typedef bool (*ConditionFn)(); + +class EventAccess { +public: + + + explicit EventAccess(bool* event_, std::vector conditions_met_) + : event(event_) { + conditions_met.resize(2); + for (size_t i = 0; i < conditions_met_.size(); i++) { + conditions_met[i] = conditions_met_[i]; + } + } + + bool ConditionsMet() const { + if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) { + return true; + } else if (Settings::Logic.Is(LOGIC_GLITCHLESS)) { + return conditions_met[0](); + } else if (Settings::Logic.Is(LOGIC_GLITCHED)) { + if (conditions_met[0]()) { + return true; + } else if (conditions_met[1] != NULL) { + return conditions_met[1](); + } + } + return false; + } + + bool CheckConditionAtAgeTime(bool& age, bool& time) { + + Logic::IsChild = false; + Logic::IsAdult = false; + Logic::AtDay = false; + Logic::AtNight = false; + + time = true; + age = true; + + Logic::UpdateHelpers(); + return ConditionsMet(); + } + + void EventOccurred() { + *event = true; + } + + bool GetEvent() const { + return *event; + } + +private: + bool* event; + std::vector conditions_met; +}; + +//this class is meant to hold an item location with a boolean function to determine its accessibility from a specific area +class LocationAccess { +public: + + explicit LocationAccess(uint32_t location_, std::vector conditions_met_) + : location(location_) { + conditions_met.resize(2); + for (size_t i = 0; i < conditions_met_.size(); i++) { + conditions_met[i] = conditions_met_[i]; + } + } + + bool GetConditionsMet() const { + if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) { + return true; + } else if (Settings::Logic.Is(LOGIC_GLITCHLESS)) { + return conditions_met[0](); + } else if (Settings::Logic.Is(LOGIC_GLITCHED)) { + if (conditions_met[0]()) { + return true; + } else if (conditions_met[1] != NULL) { + return conditions_met[1](); + } + } + return false; + } + + bool CheckConditionAtAgeTime(bool& age, bool& time) const; + + bool ConditionsMet() const; + + uint32_t GetLocation() const { + return location; + } + +private: + uint32_t location; + std::vector conditions_met; + + //Makes sure shop locations are buyable + bool CanBuy() const; +}; + +class Entrance; +enum class EntranceType; + +class Area { +public: + Area(); + Area(std::string regionName_, std::string scene_, uint32_t hintKey_, + bool timePass_, + std::vector events_, + std::vector locations_, + std::list exits_); + ~Area(); + + std::string regionName; + std::string scene; + uint32_t hintKey; + bool timePass; + std::vector events; + std::vector locations; + std::list exits; + std::list entrances; + //^ The above exits are now stored in a list instead of a vector because + //the entrance randomization algorithm plays around with pointers to these + //entrances a lot. By putting the entrances in a list, we don't have to + //worry about a vector potentially reallocating itself and invalidating all our + //entrance pointers. + + bool childDay = false; + bool childNight = false; + bool adultDay = false; + bool adultNight = false; + bool addedToPool = false; + + bool UpdateEvents(SearchMode mode); + + void AddExit(uint32_t parentKey, uint32_t newExitKey, ConditionFn condition); + + void RemoveExit(Entrance* exitToRemove); + + void SetAsPrimary(uint32_t exitToBePrimary); + + Entrance* GetExit(uint32_t exit); + + bool Child() const { + return childDay || childNight; + } + + bool Adult() const { + return adultDay || adultNight; + } + + bool BothAgesCheck() const { + return Child() && Adult(); + } + + bool HasAccess() const { + return Child() || Adult(); + } + + bool AllAccess() const { + return childDay && childNight && adultDay && adultNight; + } + + //Check to see if an exit can be access as both ages at both times of day + bool CheckAllAccess(uint32_t exitKey); + + const HintText& GetHint() const { + return Hint(hintKey); + } + + //Here checks conditional access based on whether or not both ages have + //access to this area. For example: if there are rocks that block a path + //which both child and adult can access, adult having hammer can give + //both child and adult access to the path. + bool HereCheck(ConditionFn condition) { + + //store current age variables + bool pastAdult = Logic::IsAdult; + bool pastChild = Logic::IsChild; + + //set age access as this areas ages + Logic::IsChild = Child(); + Logic::IsAdult = Adult(); + + //update helpers and check condition as well as having at least child or adult access + Logic::UpdateHelpers(); + bool hereVal = condition() && (Logic::IsAdult || Logic::IsChild); + + //set back age variables + Logic::IsChild = pastChild; + Logic::IsAdult = pastAdult; + Logic::UpdateHelpers(); + + return hereVal; + } + + bool CanPlantBeanCheck() const; + bool AllAccountedFor() const; + + void ResetVariables(); + + void printAgeTimeAccess() const { + auto message = "Child Day: " + std::to_string(childDay) + "\t" + "Child Night: " + std::to_string(childNight) + "\t" + "Adult Day: " + std::to_string(adultDay) + "\t" + "Adult Night: " + std::to_string(adultNight); + CitraPrint(message); + } +}; + +extern std::array areaTable; +extern std::vector grottoEvents; + +bool Here(const AreaKey area, ConditionFn condition); +bool CanPlantBean(const AreaKey area); +bool BothAges(const AreaKey area); +bool ChildCanAccess(const AreaKey area); +bool AdultCanAccess(const AreaKey area); +bool HasAccessTo(const AreaKey area); + +#define DAY_NIGHT_CYCLE true +#define NO_DAY_NIGHT_CYCLE false + +namespace Areas { + + extern void AccessReset(); + extern void ResetAllLocations(); + extern bool HasTimePassAccess(uint8_t age); + extern void DumpWorldGraph(std::string str); +} //namespace Exits + +void AreaTable_Init(); +Area* AreaTable(const uint32_t areaKey); +std::vector GetShuffleableEntrances(EntranceType type, bool onlyPrimary = true); + +// Overworld +void AreaTable_Init_LostWoods(); +void AreaTable_Init_HyruleField(); +void AreaTable_Init_CastleTown(); +void AreaTable_Init_Kakariko(); +void AreaTable_Init_DeathMountain(); +void AreaTable_Init_ZorasDomain(); +void AreaTable_Init_GerudoValley(); +// Dungeons +void AreaTable_Init_DekuTree(); +void AreaTable_Init_DodongosCavern(); +void AreaTable_Init_JabuJabusBelly(); +void AreaTable_Init_ForestTemple(); +void AreaTable_Init_FireTemple(); +void AreaTable_Init_WaterTemple(); +void AreaTable_Init_SpiritTemple(); +void AreaTable_Init_ShadowTemple(); +void AreaTable_Init_BottomOfTheWell(); +void AreaTable_Init_IceCavern(); +void AreaTable_Init_GerudoTrainingGrounds(); +void AreaTable_Init_GanonsCastle(); diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp new file mode 100644 index 000000000..f1532cfaf --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp @@ -0,0 +1,88 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_BottomOfTheWell() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[BOTTOM_OF_THE_WELL_ENTRYWAY] = Area("Bottom of the Well Entryway", "Bottom of the Well", BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(BOTTOM_OF_THE_WELL_MAIN_AREA, {[]{return Dungeon::BottomOfTheWell.IsVanilla() && IsChild && (CanChildAttack || Nuts);}, + /*Glitched*/[]{return Dungeon::BottomOfTheWell.IsVanilla() && IsChild && CanUse(MEGATON_HAMMER);}}), + Entrance(BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return Dungeon::BottomOfTheWell.IsMQ() && IsChild;}, + /*Glitched*/[]{return Dungeon::BottomOfTheWell.IsMQ() && CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE) && Longshot;}}), + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::BottomOfTheWell.IsVanilla()) { + areaTable[BOTTOM_OF_THE_WELL_MAIN_AREA] = Area("Bottom of the Well Main Area", "Bottom of the Well", BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&StickPot, {[]{return true;}}), + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, {[]{return LogicLensBotw || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, {[]{return HasExplosives;}}), + LocationAccess(BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, {[]{return LogicLensBotw || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(BOTTOM_OF_THE_WELL_COMPASS_CHEST, {[]{return LogicLensBotw || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, {[]{return LogicLensBotw || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, {[]{return (LogicLensBotw || CanUse(LENS_OF_TRUTH)) && HasExplosives;}}), + LocationAccess(BOTTOM_OF_THE_WELL_FREESTANDING_KEY, {[]{return Sticks || CanUse(DINS_FIRE);}}), + LocationAccess(BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, {[]{return CanPlay(ZeldasLullaby) && (KokiriSword || (Sticks && LogicChildDeadhand));}}), + LocationAccess(BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, {[]{return CanPlay(ZeldasLullaby) && (LogicLensBotw || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, {[]{return CanPlay(ZeldasLullaby);}}), + LocationAccess(BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, {[]{return CanPlay(ZeldasLullaby);}}), + LocationAccess(BOTTOM_OF_THE_WELL_MAP_CHEST, {[]{return HasExplosives || (((SmallKeys(BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(LENS_OF_TRUTH))) || CanUse(DINS_FIRE)) && GoronBracelet);}}), + LocationAccess(BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, {[]{return SmallKeys(BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, {[]{return SmallKeys(BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, {[]{return Boomerang && (LogicLensBotw || CanUse(LENS_OF_TRUTH)) && SmallKeys(BOTTOM_OF_THE_WELL, 3);}}), + LocationAccess(BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, {[]{return Boomerang && (LogicLensBotw || CanUse(LENS_OF_TRUTH)) && SmallKeys(BOTTOM_OF_THE_WELL, 3);}}), + LocationAccess(BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, {[]{return SmallKeys(BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(LENS_OF_TRUTH)) && Boomerang;}}), + }, { + //Exits + Entrance(BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return true;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::BottomOfTheWell.IsMQ()) { + areaTable[BOTTOM_OF_THE_WELL_MQ_PERIMETER] = Area("Bottom of the Well MQ Perimeter", "Bottom of the Well", BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&WallFairy, {[]{return WallFairy || Slingshot;}}), + }, { + //Locations + LocationAccess(BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, {[]{return KokiriSword || (Sticks && LogicChildDeadhand);}}), + LocationAccess(BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, {[]{return HasExplosives;}}), + //Trick: HasExplosives || (LogicBotWMQDeadHandKey && Boomerang) + LocationAccess(BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, {[]{return CanChildAttack;}}), + LocationAccess(BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, {[]{return CanChildAttack && SmallKeys(BOTTOM_OF_THE_WELL, 2);}}), + }, { + //Exits + Entrance(BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return true;}}), + Entrance(BOTTOM_OF_THE_WELL_MQ_MIDDLE, {[]{return CanPlay(ZeldasLullaby);}}), + //Trick: CanPlay(ZeldasLullaby) || (LogicBotWMQPits && HasExplosives) + }); + + areaTable[BOTTOM_OF_THE_WELL_MQ_MIDDLE] = Area("Bottom of the Well MQ Middle", "Bottom of the Well", BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, {[]{return true;}}), + LocationAccess(BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, {[]{return HasExplosives && SmallKeys(BOTTOM_OF_THE_WELL, 2);}}), + LocationAccess(BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, {[]{return true;}}), + LocationAccess(BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, {[]{return CanChildAttack && HasExplosives;}}), + //Trick: CanChildAttack && (LogicBotWMQPits || HasExplosives) + }, { + //Exits + Entrance(BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return true;}}), + }); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp new file mode 100644 index 000000000..7df38c193 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp @@ -0,0 +1,265 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_CastleTown() { + areaTable[MARKET_ENTRANCE] = Area("Market Entrance", "Market Entrance", THE_MARKET, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(HYRULE_FIELD, {[]{return IsAdult || AtDay;}}), + Entrance(THE_MARKET, {[]{return true;}}), + Entrance(MARKET_GUARD_HOUSE, {[]{return true;}}), + }); + + areaTable[THE_MARKET] = Area("Market", "Market", THE_MARKET, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(MARKET_ENTRANCE, {[]{return true;}}), + Entrance(TOT_ENTRANCE, {[]{return true;}}), + Entrance(CASTLE_GROUNDS, {[]{return true;}}), + Entrance(MARKET_BAZAAR, {[]{return IsChild && AtDay;}}), + Entrance(MARKET_MASK_SHOP, {[]{return IsChild && AtDay;}}), + Entrance(MARKET_SHOOTING_GALLERY, {[]{return IsChild && AtDay;}}), + Entrance(MARKET_BOMBCHU_BOWLING, {[]{return IsChild;}}), + Entrance(MARKET_TREASURE_CHEST_GAME, {[]{return IsChild && AtNight;}}), + Entrance(MARKET_POTION_SHOP, {[]{return IsChild && AtDay;}}), + Entrance(MARKET_BACK_ALLEY, {[]{return IsChild;}}), + }); + + areaTable[MARKET_BACK_ALLEY] = Area("Market Back Alley", "Market", THE_MARKET, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + Entrance(MARKET_BOMBCHU_SHOP, {[]{return AtNight;}}), + Entrance(MARKET_DOG_LADY_HOUSE, {[]{return true;}}), + Entrance(MARKET_MAN_IN_GREEN_HOUSE, {[]{return AtNight;}}), + }); + + areaTable[TOT_ENTRANCE] = Area("ToT Entrance", "ToT Entrance", THE_MARKET, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + }, { + //Locations + LocationAccess(TOT_GOSSIP_STONE_LEFT, {[]{return true;}}), + LocationAccess(TOT_GOSSIP_STONE_LEFT_CENTER, {[]{return true;}}), + LocationAccess(TOT_GOSSIP_STONE_RIGHT_CENTER, {[]{return true;}}), + LocationAccess(TOT_GOSSIP_STONE_RIGHT, {[]{return true;}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + Entrance(TEMPLE_OF_TIME, {[]{return true;}}), + }); + + areaTable[TEMPLE_OF_TIME] = Area("Temple of Time", "", TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(TOT_LIGHT_ARROWS_CUTSCENE, {[]{return IsAdult && CanTriggerLACS;}}), + }, { + //Exits + Entrance(TOT_ENTRANCE, {[]{return true;}}), + Entrance(TOT_BEYOND_DOOR_OF_TIME, {[]{return OpenDoorOfTime.Is(OPENDOOROFTIME_OPEN) || (CanPlay(SongOfTime) && (OpenDoorOfTime.Is(OPENDOOROFTIME_CLOSED) || (HasAllStones && OcarinaOfTime)));}, + /*Glitched*/[]{return SongOfTime && OpenDoorOfTime.Is(OPENDOOROFTIME_CLOSED) && (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::ADVANCED) || + ((Bugs || Fish) && Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)));}}), + }); + + areaTable[TOT_BEYOND_DOOR_OF_TIME] = Area("Beyond Door of Time", "", TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&TimeTravel, {[]{return true;}}), + }, { + //Locations + LocationAccess(SHEIK_AT_TEMPLE, {[]{return ForestMedallion && IsAdult;}}), + }, { + //Exits + Entrance(TEMPLE_OF_TIME, {[]{return true;}}), + }); + + areaTable[CASTLE_GROUNDS] = Area("Castle Grounds", "Castle Grounds", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + Entrance(HYRULE_CASTLE_GROUNDS, {[]{return IsChild;}}), + Entrance(GANONS_CASTLE_GROUNDS, {[]{return IsAdult;}}), + }); + + areaTable[HYRULE_CASTLE_GROUNDS] = Area("Hyrule Castle Grounds", "Castle Grounds", HYRULE_CASTLE, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || CanUse(STICKS);}}), + EventAccess(&BugRock, {[]{return true;}}), + }, { + //Locations + LocationAccess(HC_MALON_EGG, {[]{return true;}}), + LocationAccess(HC_GS_TREE, {[]{return CanChildAttack;}}), + LocationAccess(HC_MALON_GOSSIP_STONE, {[]{return true;}}), + LocationAccess(HC_ROCK_WALL_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(CASTLE_GROUNDS, {[]{return true;}}), + Entrance(HC_GARDEN, {[]{return WeirdEgg || !ShuffleWeirdEgg;}}), + Entrance(HC_GREAT_FAIRY_FOUNTAIN, {[]{return CanBlastOrSmash;}, + /*Glitched*/[]{return Sticks && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + Entrance(HC_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[HC_GARDEN] = Area("HC Garden", "Castle Grounds", HYRULE_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + }, { + //Locations + LocationAccess(HC_ZELDAS_LETTER, {[]{return true;}}), + LocationAccess(SONG_FROM_IMPA, {[]{return true;}}), + }, { + //Exits + Entrance(HYRULE_CASTLE_GROUNDS, {[]{return true;}}), + }); + + areaTable[HC_GREAT_FAIRY_FOUNTAIN] = Area("HC Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(HC_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(CASTLE_GROUNDS, {[]{return true;}}), + }); + + areaTable[HC_STORMS_GROTTO] = Area("HC Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return NutPot || CanBlastOrSmash;}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || (CanBlastOrSmash && CanSummonGossipFairy);}}), + EventAccess(&WanderingBugs, {[]{return WanderingBugs || CanBlastOrSmash;}}), + }, { + //Locations + LocationAccess(HC_GS_STORMS_GROTTO, {[]{return CanBlastOrSmash && HookshotOrBoomerang;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(HC_STORMS_GROTTO_GOSSIP_STONE, {[]{return CanBlastOrSmash;}}), + }, { + //Exits + Entrance(CASTLE_GROUNDS, {[]{return true;}}), + }); + + areaTable[GANONS_CASTLE_GROUNDS] = Area("Ganon's Castle Grounds", "Castle Grounds", OUTSIDE_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations //the terrain was lowered such that you can't get this GS with a simple sword slash + LocationAccess(OGC_GS, {[]{return HasExplosives || (IsAdult && (LogicOutsideGanonsGS || Bow || HookshotOrBoomerang || CanUse(DINS_FIRE)));}}), + }, { + //Exits + Entrance(CASTLE_GROUNDS, {[]{return AtNight;}}), + Entrance(OGC_GREAT_FAIRY_FOUNTAIN, {[]{return CanUse(GOLDEN_GAUNTLETS) && AtNight;}}), + Entrance(GANONS_CASTLE_ENTRYWAY, {[]{return CanBuildRainbowBridge;}, + /*Glitched*/[]{return (HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::ADVANCED) || (HoverBoots && CanShield && Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::EXPERT)) || (HoverBoots && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::ADVANCED));}}), + }); + + areaTable[OGC_GREAT_FAIRY_FOUNTAIN] = Area("OGC Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(OGC_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(CASTLE_GROUNDS, {[]{return true;}}), + }); + + areaTable[MARKET_GUARD_HOUSE] = Area("Market Guard House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_10_BIG_POES, {[]{return IsAdult && BigPoeKill;}}), + LocationAccess(MARKET_GS_GUARD_HOUSE, {[]{return IsChild;}}), + }, { + //Exits + Entrance(MARKET_ENTRANCE, {[]{return true;}}), + }); + + areaTable[MARKET_BAZAAR] = Area("Market Bazaar", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_BAZAAR_ITEM_1, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_2, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_3, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_4, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_5, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_6, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_7, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_MASK_SHOP] = Area("Market Mask Shop", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&SkullMask, {[]{return SkullMask || (ZeldasLetter && (CompleteMaskQuest || ChildCanAccess(KAKARIKO_VILLAGE)));}}), + EventAccess(&MaskOfTruth, {[]{return MaskOfTruth || (SkullMask && (CompleteMaskQuest || (ChildCanAccess(THE_LOST_WOODS) && CanPlay(SariasSong) && AreaTable(THE_GRAVEYARD)->childDay && ChildCanAccess(HYRULE_FIELD) && HasAllStones)));}}), + }, {}, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_SHOOTING_GALLERY] = Area("Market Shooting Gallery", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_SHOOTING_GALLERY_REWARD, {[]{return IsChild;}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_BOMBCHU_BOWLING] = Area("Market Bombchu Bowling", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, {[]{return CanPlayBowling;}}), + LocationAccess(MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, {[]{return CanPlayBowling;}}), + LocationAccess(MARKET_BOMBCHU_BOWLING_BOMBCHUS, {[]{return CanPlayBowling;}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_POTION_SHOP] = Area("Market Potion Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_POTION_SHOP_ITEM_1, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_2, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_3, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_4, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_5, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_6, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_7, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_TREASURE_CHEST_GAME] = Area("Market Treasure Chest Game", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_TREASURE_CHEST_GAME_REWARD, {[]{return (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 6)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1));}, + /*Glitched*/[]{return !ShuffleChestMinigame && (CanUse(FARORES_WIND) && (HasBottle || WeirdEgg) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE));}}), + LocationAccess(MARKET_TREASURE_CHEST_GAME_ITEM_1, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), + LocationAccess(MARKET_TREASURE_CHEST_GAME_ITEM_2, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 2)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), + LocationAccess(MARKET_TREASURE_CHEST_GAME_ITEM_3, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 3)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), + LocationAccess(MARKET_TREASURE_CHEST_GAME_ITEM_4, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 4)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), + LocationAccess(MARKET_TREASURE_CHEST_GAME_ITEM_5, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 5)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_BOMBCHU_SHOP] = Area("Market Bombchu Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_1, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_2, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_3, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_4, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_5, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_6, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_7, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(MARKET_BACK_ALLEY, {[]{return true;}}), + }); + + areaTable[MARKET_DOG_LADY_HOUSE] = Area("Market Dog Lady House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_LOST_DOG, {[]{return IsChild && AtNight;}}), + }, { + //Exits + Entrance(MARKET_BACK_ALLEY, {[]{return true;}}), + }); + + areaTable[MARKET_MAN_IN_GREEN_HOUSE] = Area("Market Man in Green House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(MARKET_BACK_ALLEY, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp new file mode 100644 index 000000000..b7a23c316 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp @@ -0,0 +1,293 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_DeathMountain() { + areaTable[DEATH_MOUNTAIN_TRAIL] = Area("Death Mountain", "Death Mountain", DEATH_MOUNTAIN_TRAIL, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(DEATH_MOUNTAIN_TRAIL) && CanPlay(SongOfStorms) && (HasExplosives || GoronBracelet));}}), + }, { + //Locations + LocationAccess(DMT_CHEST, {[]{return CanBlastOrSmash || (LogicDMTBombable && IsChild && GoronBracelet);}, + /*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + LocationAccess(DMT_FREESTANDING_POH, {[]{return CanTakeDamage || CanUse(HOVER_BOOTS) || (IsAdult && CanPlantBean(DEATH_MOUNTAIN_TRAIL) && (HasExplosives || GoronBracelet));}}), + LocationAccess(DMT_GS_BEAN_PATCH, {[]{return CanPlantBugs && (HasExplosives || GoronBracelet || (LogicDMTSoilGS && (CanTakeDamage || CanUse(HOVER_BOOTS)) && CanUse(BOOMERANG)));}}), + LocationAccess(DMT_GS_NEAR_KAK, {[]{return CanBlastOrSmash;}, + /*Glitched*/[]{return (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}}), + LocationAccess(DMT_GS_ABOVE_DODONGOS_CAVERN, {[]{return IsAdult && AtNight && CanUse(MEGATON_HAMMER) && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsAdult && AtNight && CanGetNightTimeGS && CanUse(STICKS) && ((CanTakeDamageTwice && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}}), + }, { + //Exits + Entrance(KAK_BEHIND_GATE, {[]{return true;}}), + Entrance(GORON_CITY, {[]{return true;}}), + Entrance(DEATH_MOUNTAIN_SUMMIT, {[]{return Here(DEATH_MOUNTAIN_TRAIL, []{return CanBlastOrSmash;}) || (IsAdult && ((CanPlantBean(DEATH_MOUNTAIN_TRAIL) && GoronBracelet) || (HoverBoots && LogicDMTSummitHover)));}, + /*Glitched*/[]{return IsAdult && Here(DEATH_MOUNTAIN_TRAIL, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + Entrance(DODONGOS_CAVERN_ENTRYWAY, {[]{return HasExplosives || GoronBracelet || IsAdult;}}), + Entrance(DMT_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[DEATH_MOUNTAIN_SUMMIT] = Area("Death Mountain Summit", "Death Mountain", DEATH_MOUNTAIN_TRAIL, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&PrescriptionAccess, {[]{return PrescriptionAccess || (IsAdult && (BrokenSwordAccess || BrokenSword));}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&BugRock, {[]{return BugRock || IsChild;}}), + }, { + //Locations + LocationAccess(DMT_TRADE_BROKEN_SWORD, {[]{return IsAdult && BrokenSword;}}), + LocationAccess(DMT_TRADE_EYEDROPS, {[]{return IsAdult && Eyedrops;}}), + LocationAccess(DMT_TRADE_CLAIM_CHECK, {[]{return IsAdult && ClaimCheck;}}), + LocationAccess(DMT_GS_FALLING_ROCKS_PATH, {[]{return IsAdult && AtNight && CanUse(MEGATON_HAMMER) && CanGetNightTimeGS;}}), + LocationAccess(DMT_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), + Entrance(DMC_UPPER_LOCAL, {[]{return true;}}), + Entrance(DMT_OWL_FLIGHT, {[]{return IsChild;}}), + Entrance(DMT_COW_GROTTO, {[]{return Here(DEATH_MOUNTAIN_SUMMIT, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(DEATH_MOUNTAIN_SUMMIT, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + Entrance(DMT_GREAT_FAIRY_FOUNTAIN, {[]{return Here(DEATH_MOUNTAIN_SUMMIT, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return ((KokiriSword || Sticks || IsAdult) && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::ADVANCED)) || (IsChild && CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::EXPERT));}}), + }); + + areaTable[DMT_OWL_FLIGHT] = Area("DMT Owl Flight", "Death Mountain", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAK_IMPAS_LEDGE, {[]{return true;}}), + }); + + areaTable[DMT_COW_GROTTO] = Area("DMT Cow Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMT_COW_GROTTO_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && EponasSong;}}), + }, { + //Exits + Entrance(DEATH_MOUNTAIN_SUMMIT, {[]{return true;}}), + + }); + + areaTable[DMT_STORMS_GROTTO] = Area("DMT Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(DMT_STORMS_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(DMT_STORMS_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), + }); + + areaTable[DMT_GREAT_FAIRY_FOUNTAIN] = Area("DMT Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMT_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(DEATH_MOUNTAIN_SUMMIT, {[]{return true;}}), + }); + + areaTable[GORON_CITY] = Area("Goron City", "Goron City", GORON_CITY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + EventAccess(&StickPot, {[]{return StickPot || IsChild;}}), + EventAccess(&BugRock, {[]{return BugRock || (CanBlastOrSmash || CanUse(SILVER_GAUNTLETS));}}), + EventAccess(&GoronCityChildFire, {[]{return GoronCityChildFire || (IsChild && CanUse(DINS_FIRE));}, + /*Glitched*/[]{return IsChild && CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE);}}), + EventAccess(&GCWoodsWarpOpen, {[]{return GCWoodsWarpOpen || (CanBlastOrSmash || CanUse(DINS_FIRE) || CanUse(BOW) || GoronBracelet || GoronCityChildFire);}, + /*Glitched*/[]{return (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}}), + EventAccess(&GCDaruniasDoorOpenChild, {[]{return GCDaruniasDoorOpenChild || (IsChild && CanPlay(ZeldasLullaby));}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && ZeldasLullaby;}}), + EventAccess(&StopGCRollingGoronAsAdult, {[]{return StopGCRollingGoronAsAdult || (IsAdult && (GoronBracelet || HasExplosives || Bow || (LogicLinkGoronDins && CanUse(DINS_FIRE))));}}), + }, { + //Locations + LocationAccess(GC_MAZE_LEFT_CHEST, {[]{return CanUse(MEGATON_HAMMER) || CanUse(SILVER_GAUNTLETS) || (LogicGoronCityLeftMost && HasExplosives && CanUse(HOVER_BOOTS));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + LocationAccess(GC_MAZE_CENTER_CHEST, {[]{return CanBlastOrSmash || CanUse(SILVER_GAUNTLETS);}}), + LocationAccess(GC_MAZE_RIGHT_CHEST, {[]{return CanBlastOrSmash || CanUse(SILVER_GAUNTLETS);}}), + LocationAccess(GC_POT_FREESTANDING_POH, {[]{return IsChild && GoronCityChildFire && (Bombs || (GoronBracelet && LogicGoronCityPotWithStrength) || (HasBombchus && LogicGoronCityPot));}}), + LocationAccess(GC_ROLLING_GORON_AS_CHILD, {[]{return IsChild && (HasExplosives || (GoronBracelet && LogicChildRollingWithStrength));}}), + LocationAccess(GC_ROLLING_GORON_AS_ADULT, {[]{return StopGCRollingGoronAsAdult;}}), + LocationAccess(GC_GS_BOULDER_MAZE, {[]{return IsChild && CanBlastOrSmash;}}), + LocationAccess(GC_GS_CENTER_PLATFORM, {[]{return IsAdult;}}), + LocationAccess(GC_MEDIGORON, {[]{return IsAdult && AdultsWallet && (CanBlastOrSmash || GoronBracelet);}}), + LocationAccess(GC_MAZE_GOSSIP_STONE, {[]{return CanBlastOrSmash || CanUse(SILVER_GAUNTLETS);}}), + LocationAccess(GC_MEDIGORON_GOSSIP_STONE, {[]{return CanBlastOrSmash || GoronBracelet;}}), + }, { + //Exits + Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), + Entrance(GC_WOODS_WARP, {[]{return GCWoodsWarpOpen;}}), + Entrance(GC_SHOP, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || (IsChild && (CanBlastOrSmash || GoronBracelet || GoronCityChildFire || CanUse(BOW)));}, + /*Glitched*/[]{return IsChild && Sticks && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + Entrance(GC_DARUNIAS_CHAMBER, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || GCDaruniasDoorOpenChild;}}), + Entrance(GC_GROTTO, {[]{return IsAdult && ((CanPlay(SongOfTime) && ((EffectiveHealth > 2) || CanUse(GORON_TUNIC) || CanUse(LONGSHOT) || CanUse(NAYRUS_LOVE))) || (EffectiveHealth > 1 && CanUse(GORON_TUNIC) && CanUse(HOOKSHOT)) || (CanUse(NAYRUS_LOVE) && CanUse(HOOKSHOT)));}, + /*Glitched*/[]{return (HasBombchus && ((IsChild && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE))) || (IsChild && CanUse(LONGSHOT));}}), + }); + + areaTable[GC_WOODS_WARP] = Area("GC Woods Warp", "Goron City", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GCWoodsWarpOpen, {[]{return GCWoodsWarpOpen || (CanBlastOrSmash || CanUse(DINS_FIRE));}}), + }, {}, { + //Exits + Entrance(GORON_CITY, {[]{return CanLeaveForest && GCWoodsWarpOpen;}}), + Entrance(THE_LOST_WOODS, {[]{return true;}}), + }); + + areaTable[GC_DARUNIAS_CHAMBER] = Area("GC Darunias Chamber", "Goron City", GORON_CITY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GoronCityChildFire, {[]{return GoronCityChildFire || (IsChild && CanUse(STICKS));}}), + }, { + //Locations + LocationAccess(GC_DARUNIAS_JOY, {[]{return IsChild && CanPlay(SariasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && ((Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2))) || GCDaruniasDoorOpenChild) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SariasSong;}}), + }, { + //Exits + Entrance(GORON_CITY, {[]{return true;}}), + Entrance(DMC_LOWER_LOCAL, {[]{return IsAdult;}, + /*Glitched*/[]{return IsChild && GCDaruniasDoorOpenChild && (KokiriSword || Sticks) && GlitchOccamsStatue;}}), + }); + + areaTable[GC_GROTTO_PLATFORM] = Area("GC Grotto Platform", "Goron City", GORON_CITY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GC_GROTTO, {[]{return true;}}), + Entrance(GORON_CITY, {[]{return EffectiveHealth > 2 || CanUse(GORON_TUNIC) || CanUse(NAYRUS_LOVE) || ((IsChild || CanPlay(SongOfTime)) && CanUse(LONGSHOT));}}), + }); + + areaTable[GC_SHOP] = Area("GC Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GC_SHOP_ITEM_1, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_2, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_3, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_4, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_5, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_6, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_7, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(GORON_CITY, {[]{return true;}}), + }); + + areaTable[GC_GROTTO] = Area("GC Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GC_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(GC_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(GC_DEKU_SCRUB_GROTTO_CENTER, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(GC_GROTTO_PLATFORM, {[]{return true;}}), + }); + + areaTable[DMC_UPPER_NEARBY] = Area("DMC Upper Nearby", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DMC_UPPER_LOCAL, {[]{return FireTimer >= 48;}}), + Entrance(DEATH_MOUNTAIN_SUMMIT, {[]{return true;}}), + Entrance(DMC_UPPER_GROTTO, {[]{return Here(DMC_UPPER_NEARBY, []{return CanBlastOrSmash && (FireTimer >= 8 || Hearts >= 3);});}, + /*Glitched*/[]{return Here(DMC_UPPER_NEARBY, []{return CanUse(STICKS) && FireTimer >= 48 && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}) + }); + + areaTable[DMC_UPPER_LOCAL] = Area("DMC Upper Local", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || (HasExplosives && CanSummonGossipFairyWithoutSuns && (FireTimer >= 16 || Hearts >= 3));}}), + }, { + //Locations + LocationAccess(DMC_WALL_FREESTANDING_POH, {[]{return FireTimer >= 16 || Hearts >= 3;}}), + LocationAccess(DMC_GS_CRATE, {[]{return (FireTimer >= 8 || Hearts >= 3) && IsChild && CanChildAttack;}}), + LocationAccess(DMC_GOSSIP_STONE, {[]{return HasExplosives && (FireTimer >= 16 || Hearts >= 3);}}), + }, { + //Exits + Entrance(DMC_UPPER_NEARBY, {[]{return true;}}), + Entrance(DMC_LADDER_AREA_NEARBY, {[]{return FireTimer >= 16 || Hearts >= 3;}}), + Entrance(DMC_CENTRAL_NEARBY, {[]{return IsAdult && CanUse(GORON_TUNIC) && CanUse(DISTANT_SCARECROW) && ((EffectiveHealth > 2) || (Fairy && ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) || CanUse(NAYRUS_LOVE));}, + /*Glitched*/[]{return FireTimer >= 24 && CanTakeDamage && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), + Entrance(DMC_LOWER_NEARBY, {[]{return false;}, + /*Glitched*/[]{return FireTimer >= 24 && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[DMC_LADDER_AREA_NEARBY] = Area("DMC Ladder Area Nearby", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMC_DEKU_SCRUB, {[]{return IsChild && CanStunDeku;}}), + }, { + //Exits + Entrance(DMC_UPPER_NEARBY, {[]{return Hearts >= 3;}}), + Entrance(DMC_LOWER_NEARBY, {[]{return Hearts >= 3 && (CanUse(HOVER_BOOTS) || (LogicCraterUpperToLower && IsAdult && CanUse(MEGATON_HAMMER)));}}), + }); + + areaTable[DMC_LOWER_NEARBY] = Area("DMC Lower Nearby", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DMC_LOWER_LOCAL, {[]{return FireTimer >= 48;}}), + Entrance(GC_DARUNIAS_CHAMBER, {[]{return true;}}), + Entrance(DMC_GREAT_FAIRY_FOUNTAIN, {[]{return CanUse(MEGATON_HAMMER);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || (FireTimer >= 48 && CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE) && (CanTakeDamageTwice || CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED))) || + (Bombs && CanShield && FireTimer >= 48 && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::EXPERT)) || Here(DMC_UPPER_LOCAL, []{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::ADVANCED);});}}), + Entrance(DMC_HAMMER_GROTTO, {[]{return IsAdult && CanUse(MEGATON_HAMMER);}, + /*Glitched*/[]{return IsAdult && FireTimer >= 48 && CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE) && (CanTakeDamageTwice || CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}}), + }); + + areaTable[DMC_LOWER_LOCAL] = Area("DMC Lower Local", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DMC_LOWER_NEARBY, {[]{return true;}}), + Entrance(DMC_LADDER_AREA_NEARBY, {[]{return true;}}), + Entrance(DMC_CENTRAL_NEARBY, {[]{return (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT)) && (FireTimer >= 8 || Hearts >= 3);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) && (FireTimer >= 8 || Hearts >= 3);}}), + Entrance(DMC_CENTRAL_LOCAL, {[]{return (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT)) && FireTimer >= 24;}}), + }); + + areaTable[DMC_CENTRAL_NEARBY] = Area("DMC Central Nearby", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMC_VOLCANO_FREESTANDING_POH, {[]{return IsAdult && Hearts >= 3 && (CanPlantBean(DMC_CENTRAL_LOCAL) || (LogicCraterBeanPoHWithHovers && HoverBoots));}, + /*Glitched*/[]{return Here(DMC_LOWER_LOCAL, []{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) && FireTimer >= 24;});}}), + LocationAccess(SHEIK_IN_CRATER, {[]{return IsAdult && (FireTimer >= 8 || Hearts >= 3);}}), + }, { + //Exits + Entrance(DMC_CENTRAL_LOCAL, {[]{return FireTimer >= 48;}}), + }); + + areaTable[DMC_CENTRAL_LOCAL] = Area("DMC Central Local", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(DMC_CENTRAL_LOCAL) && CanPlay(SongOfStorms));}}), + }, { + //Locations + LocationAccess(DMC_GS_BEAN_PATCH, {[]{return (FireTimer >= 8 || Hearts >= 3) && CanPlantBugs && CanChildAttack;}}), + }, { + //Exits + Entrance(DMC_CENTRAL_NEARBY, {[]{return true;}}), + Entrance(DMC_LOWER_NEARBY, {[]{return (IsAdult && CanPlantBean(DMC_CENTRAL_LOCAL)) || CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT);}, + /*Glitched*/[]{return IsChild && Hearts >= 3 && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + Entrance(DMC_UPPER_NEARBY, {[]{return IsAdult && CanPlantBean(DMC_CENTRAL_LOCAL);}}), + Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return (IsChild && Hearts >= 3 && ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) || (IsAdult && FireTimer >= 24);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) && FireTimer >= 48;}}), + }); + + areaTable[DMC_GREAT_FAIRY_FOUNTAIN] = Area("DMC Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMC_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanTakeDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(DMC_LOWER_LOCAL, {[]{return true;}}), + }); + + areaTable[DMC_UPPER_GROTTO] = Area("DMC Upper Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(DMC_UPPER_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(DMC_UPPER_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(DMC_UPPER_LOCAL, {[]{return true;}}), + }); + + areaTable[DMC_HAMMER_GROTTO] = Area("DMC Hammer Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMC_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(DMC_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(DMC_DEKU_SCRUB_GROTTO_CENTER, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(DMC_LOWER_LOCAL, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp new file mode 100644 index 000000000..c67e5d3bd --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp @@ -0,0 +1,266 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_DekuTree() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[DEKU_TREE_ENTRYWAY] = Area("Deku Tree Entryway", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DEKU_TREE_LOBBY, {[]{return Dungeon::DekuTree.IsVanilla();}}), + Entrance(DEKU_TREE_MQ_LOBBY, {[]{return Dungeon::DekuTree.IsMQ();}}), + Entrance(KF_OUTSIDE_DEKU_TREE, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::DekuTree.IsVanilla()) { + areaTable[DEKU_TREE_LOBBY] = Area("Deku Tree Lobby", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Locations + LocationAccess(DEKU_TREE_MAP_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DEKU_TREE_ENTRYWAY, {[]{return true;}}), + Entrance(DEKU_TREE_2F_MIDDLE_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_COMPASS_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_LOWER, {[]{return Here(DEKU_TREE_LOBBY, []{return IsAdult || CanChildAttack || Nuts;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), + Entrance(DEKU_TREE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return IsChild && CanUse(KOKIRI_SWORD) && Nuts && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::EXPERT);}}), + }); + + areaTable[DEKU_TREE_2F_MIDDLE_ROOM] = Area("Deku Tree 2F Middle Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DEKU_TREE_LOBBY, {[]{return Here(DEKU_TREE_2F_MIDDLE_ROOM, []{return HasShield || CanUse(MEGATON_HAMMER);});}}), + Entrance(DEKU_TREE_SLINGSHOT_ROOM,{[]{return Here(DEKU_TREE_2F_MIDDLE_ROOM, []{return HasShield || CanUse(MEGATON_HAMMER);});}}), + }); + + areaTable[DEKU_TREE_SLINGSHOT_ROOM] = Area("Deku Tree Slingshot Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_SLINGSHOT_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DEKU_TREE_2F_MIDDLE_ROOM, {[]{return CanUse(SLINGSHOT) || CanUse(HOVER_BOOTS);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[DEKU_TREE_COMPASS_ROOM] = Area("Deku Tree Compass Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Locations + LocationAccess(DEKU_TREE_COMPASS_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_GS_COMPASS_ROOM, {[]{return IsAdult || CanChildAttack;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(DEKU_TREE_LOBBY, {[]{return HasFireSourceWithTorch || CanUse(BOW);}}), + Entrance(DEKU_TREE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED);}}), + }); + + areaTable[DEKU_TREE_BASEMENT_LOWER] = Area("Deku Tree Basement Lower", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Locations + LocationAccess(DEKU_TREE_BASEMENT_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_GS_BASEMENT_GATE, {[]{return IsAdult || CanChildAttack;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + LocationAccess(DEKU_TREE_GS_BASEMENT_VINES, {[]{return CanUseProjectile || CanUse(DINS_FIRE) || (LogicDekuBasementGS && (IsAdult || Sticks || KokiriSword));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(DEKU_TREE_LOBBY, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_SCRUB_ROOM, {[]{return Here(DEKU_TREE_BASEMENT_LOWER, []{return HasFireSourceWithTorch || CanUse(BOW);});}}), + Entrance(DEKU_TREE_BASEMENT_UPPER, {[]{return IsAdult || LogicDekuB1Skip || HasAccessTo(DEKU_TREE_BASEMENT_UPPER);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[DEKU_TREE_BASEMENT_SCRUB_ROOM] = Area("Deku Tree Basement Scrub Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_LOWER, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_WATER_ROOM, {[]{return Here(DEKU_TREE_BASEMENT_SCRUB_ROOM, []{return CanUse(SLINGSHOT) || CanUse(BOW);});}}), + }); + + areaTable[DEKU_TREE_BASEMENT_WATER_ROOM] = Area("Deku Tree Basement Water Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_SCRUB_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_TORCH_ROOM, {[]{return true;}}), + }); + + areaTable[DEKU_TREE_BASEMENT_TORCH_ROOM] = Area("Deku Tree Basement Torch Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_WATER_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return Here(DEKU_TREE_BASEMENT_TORCH_ROOM, []{return HasFireSourceWithTorch || CanUse(BOW);});}}), + }); + + areaTable[DEKU_TREE_BASEMENT_BACK_LOBBY] = Area("Deku Tree Basement Back Lobby", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return HasFireSourceWithTorch || CanUse(BOW);}) && + (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE)));}, + /*Glitched*/[]{return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return HasFireSourceWithTorch || CanUse(BOW);}) && CanUse(MEGATON_HAMMER);}}), + }, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_TORCH_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_BACK_ROOM, {[]{return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return HasFireSourceWithTorch || CanUse(Bow);}) && + Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return HasFireSourceWithTorch || CanUse(Bow);}) && + Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT));});}}), + Entrance(DEKU_TREE_BASEMENT_UPPER, {[]{return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return HasFireSourceWithTorch || CanUse(Bow);}) && IsChild;}}), + }); + + areaTable[DEKU_TREE_BASEMENT_BACK_ROOM] = Area("Deku Tree Basement Back Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_GS_BASEMENT_BACK_ROOM, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Exits + Entrance(DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return true;}}), + }); + + areaTable[DEKU_TREE_BASEMENT_UPPER] = Area("Deku Tree Basement Upper", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_LOWER, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return IsChild;}}), + Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return Here(DEKU_TREE_BASEMENT_UPPER, []{return HasFireSourceWithTorch || (LogicDekuB1WebsWithBow && IsAdult && CanUse(BOW));});}}), + }); + + areaTable[DEKU_TREE_OUTSIDE_BOSS_ROOM] = Area("Deku Tree Outside Boss Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_UPPER, {[]{return true;}}), + Entrance(DEKU_TREE_BOSS_ROOM, {[]{return Here(DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return HasShield;});}}), + }); + + areaTable[DEKU_TREE_BOSS_ROOM] = Area("Deku Tree Boss Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuTreeClear, {[]{return DekuTreeClear || ((IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + }, { + //Locations + LocationAccess(QUEEN_GOHMA, {[]{return DekuTreeClear;}}), + LocationAccess(DEKU_TREE_QUEEN_GOHMA_HEART, {[]{return DekuTreeClear;}}), + }, { + //Exits + Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_ENTRYWAY, {[]{return DekuTreeClear;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::DekuTree.IsMQ()) { + areaTable[DEKU_TREE_MQ_LOBBY] = Area("Deku Tree MQ Lobby", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}}), + }, { + //Locations + LocationAccess(DEKU_TREE_MQ_MAP_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_MQ_SLINGSHOT_CHEST, {[]{return IsAdult || CanChildAttack;}}), + LocationAccess(DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, {[]{return HasFireSourceWithTorch || (IsAdult && CanUse(BOW));}}), + LocationAccess(DEKU_TREE_MQ_BASEMENT_CHEST, {[]{return HasFireSourceWithTorch || (IsAdult && CanUse(BOW));}}), + LocationAccess(DEKU_TREE_MQ_GS_LOBBY, {[]{return IsAdult || CanChildAttack;}}), + }, { + //Exits + Entrance(DEKU_TREE_ENTRYWAY, {[]{return true;}}), + Entrance(DEKU_TREE_MQ_COMPASS_ROOM, {[]{return Here(DEKU_TREE_MQ_LOBBY, []{return (IsChild && CanUse(SLINGSHOT)) || (IsAdult && CanUse(BOW));}) && + Here(DEKU_TREE_MQ_LOBBY, []{return HasFireSourceWithTorch || (IsAdult && CanUse(BOW));});}}), + Entrance(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return Here(DEKU_TREE_MQ_LOBBY, []{return (IsChild && CanUse(SLINGSHOT)) || (IsAdult && CanUse(BOW));}) && + Here(DEKU_TREE_MQ_LOBBY, []{return HasFireSourceWithTorch;});}}), + Entrance(DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return LogicDekuB1Skip || Here(DEKU_TREE_MQ_LOBBY, []{return IsAdult;});}}), + }); + + areaTable[DEKU_TREE_MQ_COMPASS_ROOM] = Area("Deku Tree MQ Compass Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_MQ_COMPASS_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_MQ_GS_COMPASS_ROOM, {[]{return HookshotOrBoomerang && + Here(DEKU_TREE_MQ_COMPASS_ROOM, []{return HasBombchus || + (Bombs && (CanPlay(SongOfTime) || IsAdult)) || + (IsAdult && CanUse(MEGATON_HAMMER) && (CanPlay(SongOfTime) /*|| LogicDekuMQCompassGS*/));});}}), + }, { + //Exits + Entrance(DEKU_TREE_MQ_LOBBY, {[]{return true;}}), + }); + + areaTable[DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT] = Area("Deku Tree MQ Basement Water Room Front", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return /*LogicDekuMQLog || */ (IsChild && (DekuShield || HylianShield)) || + (IsAdult && (CanUse(LONGSHOT) || (CanUse(HOOKSHOT) && CanUse(IRON_BOOTS))));}}), + Entrance(DEKU_TREE_MQ_LOBBY, {[]{return true;}}), + }); + + areaTable[DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK] = Area("Deku Tree MQ Basement Water Room Front", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, {[]{return CanPlay(SongOfTime);}}), + }, { + //Exits + Entrance(DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return Here(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, []{return (IsChild && CanUse(STICKS)) || CanUse(DINS_FIRE) || + Here(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, []{return IsAdult && CanUse(FIRE_ARROWS);});}) && + Here(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, []{return IsAdult || KokiriSword || CanUseProjectile || (Nuts && Sticks);});}}), + Entrance(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return true;}}), + }); + + areaTable[DEKU_TREE_MQ_BASEMENT_BACK_ROOM] = Area("Deku Tree MQ Basement Back Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, {[]{return (IsAdult && CanUse(LONGSHOT)) || (CanPlay(SongOfTime) && HookshotOrBoomerang);}}), + LocationAccess(DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, {[]{return HasFireSourceWithTorch && HookshotOrBoomerang;}}), + }, { + //Exits + Entrance(DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return IsChild;}}), + Entrance(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return (IsChild && CanUse(KOKIRI_SWORD)) || CanUseProjectile || (Nuts && (IsChild && CanUse(STICKS)));}}), + }); + + areaTable[DEKU_TREE_MQ_BASEMENT_LEDGE] = Area("Deku Tree MQ Basement Ledge", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuTreeClear, {[]{return DekuTreeClear || (Here(DEKU_TREE_MQ_BASEMENT_LEDGE, []{return HasFireSourceWithTorch;}) && + Here(DEKU_TREE_MQ_BASEMENT_LEDGE, []{return HasShield;}) && + (IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang));}}), + }, { + //Locations + LocationAccess(DEKU_TREE_MQ_DEKU_SCRUB, {[]{return CanStunDeku;}}), + LocationAccess(DEKU_TREE_QUEEN_GOHMA_HEART, {[]{return HasFireSourceWithTorch && HasShield && (IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang);}}), + LocationAccess(QUEEN_GOHMA, {[]{return HasFireSourceWithTorch && HasShield && (IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang);}}), + }, { + //Exits + Entrance(DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return IsChild;}}), + Entrance(DEKU_TREE_MQ_LOBBY, {[]{return true;}}), + }); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp new file mode 100644 index 000000000..e46bfff0a --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp @@ -0,0 +1,319 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_DodongosCavern() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[DODONGOS_CAVERN_ENTRYWAY] = Area("Dodongos Cavern Entryway", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_BEGINNING, {[]{return Dungeon::DodongosCavern.IsVanilla();}}), + Entrance(DODONGOS_CAVERN_MQ_BEGINNING, {[]{return Dungeon::DodongosCavern.IsMQ();}}), + Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::DodongosCavern.IsVanilla()) { + areaTable[DODONGOS_CAVERN_BEGINNING] = Area("Dodongos Cavern Beginning", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_ENTRYWAY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return Here(DODONGOS_CAVERN_BEGINNING, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_BEGINNING, []{return GlitchBlueFireWall && BlueFire;});}}), + }); + + areaTable[DODONGOS_CAVERN_LOBBY] = Area("Dodongos Cavern Lobby", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || (CanSummonGossipFairy && Here(DODONGOS_CAVERN_LOBBY, []{return CanBlastOrSmash || GoronBracelet;}));}, + /*Glitched*/[]{return CanSummonGossipFairy && Here(DODONGOS_CAVERN_LOBBY, []{return GlitchBlueFireWall && BlueFire;});}}), + }, { + //Locations + LocationAccess(DODONGOS_CAVERN_MAP_CHEST, {[]{return Here(DODONGOS_CAVERN_LOBBY, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_LOBBY, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}) || CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + LocationAccess(DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, {[]{return CanStunDeku || GoronBracelet;}}), + LocationAccess(DODONGOS_CAVERN_GOSSIP_STONE, {[]{return Here(DODONGOS_CAVERN_LOBBY, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_LOBBY, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_BEGINNING, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_LOBBY_SWITCH, {[]{return IsAdult;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) || (HasExplosives && (CanUse(SLINGSHOT) || CanUse(HOOKSHOT) || CanUse(BOW)) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)) || (CanShield && GoronBracelet && GlitchModernHalfie) || ((KokiriSword || Sticks || CanUse(MEGATON_HAMMER)) && (Bombs || GoronBracelet) && Fairy && GlitchClassicHalfie);}}), + Entrance(DODONGOS_CAVERN_SE_CORRIDOR, {[]{return Here(DODONGOS_CAVERN_LOBBY, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_LOBBY, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), + Entrance(DODONGOS_CAVERN_STAIRS_LOWER, {[]{return HasAccessTo(DODONGOS_CAVERN_LOBBY_SWITCH);}}), + Entrance(DODONGOS_CAVERN_FAR_BRIDGE, {[]{return HasAccessTo(DODONGOS_CAVERN_FAR_BRIDGE);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(DODONGOS_CAVERN_BOSS_AREA, {[]{return Here(DODONGOS_CAVERN_FAR_BRIDGE, []{return HasExplosives;});}}), + Entrance(DODONGOS_CAVERN_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED);}}), + }); + + areaTable[DODONGOS_CAVERN_LOBBY_SWITCH] = Area("Dodongos Cavern Lobby Switch", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_DODONGO_ROOM, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_SE_CORRIDOR] = Area("Dodongos Cavern SE Corridor", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_GS_SCARECROW, {[]{return CanUse(SCARECROW) || (IsAdult && CanUse(LONGSHOT)) || (LogicDCScarecrowGS && (IsAdult || CanChildAttack));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (CanUse(LONGSHOT) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_SE_ROOM, {[]{return Here(DODONGOS_CAVERN_SE_CORRIDOR, []{return CanBlastOrSmash || IsAdult || CanChildAttack || (CanTakeDamage && CanShield);});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_SE_CORRIDOR, []{return (GlitchBlueFireWall && BlueFire);});}}), + Entrance(DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_SE_ROOM] = Area("Dodongos Cavern SE Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, {[]{return IsAdult || CanChildAttack;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_SE_CORRIDOR, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS] = Area("Dodongos Cavern Near Lower Lizalfos", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_SE_CORRIDOR, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_LOWER_LIZALFOS, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_LOWER_LIZALFOS] = Area("Dodongos Cavern Lower Lizalfos", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, {[]{return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, []{return IsAdult || Slingshot || Sticks || KokiriSword || HasExplosives;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(DODONGOS_CAVERN_DODONGO_ROOM, {[]{return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, []{return IsAdult || Slingshot || Sticks || KokiriSword || HasExplosives;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[DODONGOS_CAVERN_DODONGO_ROOM] = Area("Dodongos Cavern Dodongo Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY_SWITCH, {[]{return HasFireSourceWithTorch;}}), + Entrance(DODONGOS_CAVERN_LOWER_LIZALFOS, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_NEAR_DODONGO_ROOM, {[]{return Here(DODONGOS_CAVERN_DODONGO_ROOM, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_DODONGO_ROOM, []{return GlitchBlueFireWall && BlueFire;});}}), + }); + + areaTable[DODONGOS_CAVERN_NEAR_DODONGO_ROOM] = Area("Dodongos Cavern Near Dodongo Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_DODONGO_ROOM, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_STAIRS_LOWER] = Area("Dodongos Cavern Stairs Lower", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_STAIRS_UPPER, {[]{return HasExplosives || GoronBracelet || CanUse(DINS_FIRE) || (LogicDCStaircase && CanUse(BOW));}}), + Entrance(DODONGOS_CAVERN_COMPASS_ROOM, {[]{return Here(DODONGOS_CAVERN_STAIRS_LOWER, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_STAIRS_LOWER, []{return GlitchBlueFireWall && BlueFire;});}}), + }); + + areaTable[DODONGOS_CAVERN_STAIRS_UPPER] = Area("Dodongos Cavern Stairs Upper", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, {[]{return Here(DODONGOS_CAVERN_FAR_BRIDGE, []{return HookshotOrBoomerang;}) || CanUse(LONGSHOT);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE) && HookshotOrBoomerang);}}), + LocationAccess(DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, {[]{return IsAdult || CanChildAttack;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_STAIRS_LOWER, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_ARMOS_ROOM, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_COMPASS_ROOM] = Area("Dodongos Cavern Compass Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_COMPASS_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_STAIRS_LOWER, {[]{return IsAdult || HasExplosives || GoronBracelet;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[DODONGOS_CAVERN_ARMOS_ROOM] = Area("Dodongos Cavern Armos Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_STAIRS_UPPER, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_BOMB_ROOM_LOWER] = Area("Dodongos Cavern Bomb Room Lower", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_2F_SIDE_ROOM, {[]{return Here(DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), + Entrance(DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, {[]{return Here(DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), + Entrance(DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return (IsAdult && LogicDCJump) || CanUse(HOVER_BOOTS) || (IsAdult && CanUse(LONGSHOT));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || + (IsAdult && (CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(SLINGSHOT)) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED));}}), + }); + + areaTable[DODONGOS_CAVERN_2F_SIDE_ROOM] = Area("Dodongos Cavern 2F Side Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM] = Area("Dodongos Cavern First Slingshot Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_UPPER_LIZALFOS, {[]{return CanUse(SLINGSHOT) || CanUse(BOW) || LogicDCSlingshotSkip;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (IsAdult && CanUse(HOOKSHOT) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED));}}), + }); + + areaTable[DODONGOS_CAVERN_UPPER_LIZALFOS] = Area("Dodongos Cavern Upper Lizalfos", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_LOWER_LIZALFOS, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, {[]{return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, []{return IsAdult || Slingshot || Sticks || KokiriSword || HasExplosives;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, {[]{return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, []{return IsAdult || Slingshot || Sticks || KokiriSword || HasExplosives;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM] = Area("Dodongos Cavern Second Slingshot Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_UPPER_LIZALFOS, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return CanUse(SLINGSHOT) || CanUse(BOW) || LogicDCSlingshotSkip;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (IsAdult && CanUse(HOOKSHOT) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED));}}), + }); + + areaTable[DODONGOS_CAVERN_BOMB_ROOM_UPPER] = Area("Dodongos Cavern Bomb Room Upper", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_BOMB_BAG_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_FAR_BRIDGE, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_FAR_BRIDGE] = Area("Dodongos Cavern Far Bridge", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, {[]{return Here(DODONGOS_CAVERN_FAR_BRIDGE, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_FAR_BRIDGE, []{return (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}) || + CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_BOSS_AREA] = Area("Dodongos Cavern Boss Area", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, {}, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_BACK_ROOM, {[]{return Here(DODONGOS_CAVERN_BOSS_AREA, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_BOSS_AREA, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), + Entrance(DODONGOS_CAVERN_BOSS_ROOM, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_BACK_ROOM] = Area("Dodongos Cavern Back Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_GS_BACK_ROOM, {[]{return IsAdult || CanChildAttack;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_BOSS_AREA, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_BOSS_ROOM] = Area("Dodongos Cavern Boss Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DodongosCavernClear, {[]{return DodongosCavernClear || (Here(DODONGOS_CAVERN_BOSS_ROOM, []{return HasExplosives || (CanUse(MEGATON_HAMMER) && CanShield);}) && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword));}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_BOSS_ROOM, []{return HasExplosives || (CanUse(MEGATON_HAMMER) && CanShield) || (GlitchBlueFireWall && BlueFire);}) && (HasExplosives || GoronBracelet) && (IsAdult || Sticks || KokiriSword || CanUse(MEGATON_HAMMER));}}), + }, { + //Locations + LocationAccess(DODONGOS_CAVERN_BOSS_ROOM_CHEST, {[]{return true;}}), + LocationAccess(DODONGOS_CAVERN_KING_DODONGO_HEART, {[]{return DodongosCavernClear;}}), + LocationAccess(KING_DODONGO, {[]{return DodongosCavernClear;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_BOSS_AREA, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_ENTRYWAY, {[]{return DodongosCavernClear;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::DodongosCavern.IsMQ()) { + areaTable[DODONGOS_CAVERN_MQ_BEGINNING] = Area("Dodongos Cavern MQ Beginning", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_ENTRYWAY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_MQ_LOBBY, {[]{return Here(DODONGOS_CAVERN_MQ_BEGINNING, []{return CanBlastOrSmash || GoronBracelet;});}}), + }); + + areaTable[DODONGOS_CAVERN_MQ_LOBBY] = Area("Dodongos Cavern MQ Lobby", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + }, { + //Locations + LocationAccess(DODONGOS_CAVERN_MQ_MAP_CHEST, {[]{return true;}}), + LocationAccess(DODONGOS_CAVERN_MQ_COMPASS_CHEST, {[]{return IsAdult || CanChildAttack || Nuts;}}), + LocationAccess(DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, {[]{return (IsChild && CanUse(STICKS)) || HasFireSource;}}), + LocationAccess(DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, {[]{return CanBlastOrSmash || (IsChild && CanUse(STICKS)) || CanUse(DINS_FIRE) || (IsAdult && (LogicDCJump || HoverBoots || Hookshot));}}), + LocationAccess(DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, {[]{return CanPlay(SongOfTime) && (CanChildAttack || IsAdult);}}), + LocationAccess(DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, {[]{return (IsChild && CanUse(STICKS)) || HasFireSource;}}), + LocationAccess(DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, {[]{return CanBlastOrSmash;}}), + LocationAccess(DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, {[]{return CanStunDeku;}}), + LocationAccess(DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, {[]{return CanStunDeku;}}), + LocationAccess(DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, {[]{return CanStunDeku;}}), + LocationAccess(DODONGOS_CAVERN_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, {[]{return Here(DODONGOS_CAVERN_MQ_LOBBY, []{return CanBlastOrSmash || (((IsChild && CanUse(STICKS)) || CanUse(DINS_FIRE)) && CanTakeDamage);});}}), + Entrance(DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, {[]{return IsAdult || (Here(DODONGOS_CAVERN_MQ_LOBBY, []{return IsAdult;}) && HasExplosives);}}), + //Trick: IsAdult || HasExplosives || (LogicDCMQChildBombs && (KokiriSword || Sticks) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO)) + Entrance(DODONGOS_CAVERN_MQ_BOSS_AREA, {[]{return HasExplosives;}}), + //Trick: HasExplosives || (LogicDCMQEyes && GoronBracelet && (IsAdult || LogicDCMQChildBack) && ((IsChild && CanUse(STICKS)) || CanUse(DINS_FIRE) || (IsAdult && (LogicDCJump || Hammer || HoverBoots || Hookshot)))) + }); + + areaTable[DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE] = Area("Dodongos Cavern MQ Lower Right Side", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, {[]{return (Here(DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, []{return IsAdult && CanUse(BOW);}) || GoronBracelet || + CanUse(DINS_FIRE) || HasExplosives) && + IsChild && CanUse(SLINGSHOT);}}), + }); + + areaTable[DODONGOS_CAVERN_MQ_BOMB_BAG_AREA] = Area("Dodongos Cavern MQ Bomb Bag Area", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, {[]{return true;}}), + LocationAccess(DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, {[]{return (Here(DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, []{return IsAdult && CanUse(BOW);}) || GoronBracelet || CanUse(DINS_FIRE) || HasExplosives) && HookshotOrBoomerang;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_MQ_BOSS_AREA] = Area("Dodongos Cavern MQ BossArea", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + EventAccess(&DodongosCavernClear, {[]{return DodongosCavernClear || (CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword));}}), + }, { + //Locations + LocationAccess(DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, {[]{return true;}}), + LocationAccess(DODONGOS_CAVERN_BOSS_ROOM_CHEST, {[]{return true;}}), + LocationAccess(DODONGOS_CAVERN_KING_DODONGO_HEART, {[]{return CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword);}}), + LocationAccess(KING_DODONGO, {[]{return CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword);}}), + LocationAccess(DODONGOS_CAVERN_MQ_GS_BACK_AREA, {[]{return true;}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp new file mode 100644 index 000000000..ae3c08374 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp @@ -0,0 +1,456 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_FireTemple() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[FIRE_TEMPLE_ENTRYWAY] = Area("Fire Temple Entryway", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return Dungeon::FireTemple.IsVanilla();}}), + Entrance(FIRE_TEMPLE_MQ_LOWER, {[]{return Dungeon::FireTemple.IsMQ();}}), + Entrance(DMC_CENTRAL_LOCAL, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::FireTemple.IsVanilla()) { + areaTable[FIRE_TEMPLE_FIRST_ROOM] = Area("Fire Temple First Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + }, { + //Exits + Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(FIRE_TEMPLE_NEAR_BOSS_ROOM, {[]{return FireTimer >= 24;}}), + Entrance(FIRE_TEMPLE_LOOP_ENEMIES, {[]{return Here(FIRE_TEMPLE_FIRST_ROOM, []{return CanUse(MEGATON_HAMMER);}) && (SmallKeys(FIRE_TEMPLE, 8) || !IsKeysanity);}, + /*Glitched*/[]{return ((IsAdult && CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::EXPERT)) || + (GlitchFireGrunzClip && Bombs && IsAdult && CanUse(HOVER_BOOTS) && CanSurviveDamage)) && (SmallKeys(FIRE_TEMPLE, 8) || !IsKeysanity);}}), + Entrance(FIRE_TEMPLE_LOOP_EXIT, {[]{return true;}}), + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 2) && FireTimer >= 24;}}), + }); + + areaTable[FIRE_TEMPLE_NEAR_BOSS_ROOM] = Area("Fire Temple Near Boss Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return FairyPot || (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT));}}), + }, { + //Locations + LocationAccess(FIRE_TEMPLE_NEAR_BOSS_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_BOSS_ROOM, {[]{return BossKeyFireTemple && ((IsAdult && LogicFireBossDoorJump) || CanUse(HOVER_BOOTS) || Here(FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return CanUse(MEGATON_HAMMER);}));}, + /*Glitched*/[]{return BossKeyFireTemple && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || + (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)));}}), + }); + + areaTable[FIRE_TEMPLE_BOSS_ROOM] = Area("Fire Temple Boss Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FireTempleClear, {[]{return FireTempleClear || (FireTimer >= 64 && CanUse(MEGATON_HAMMER));}, + /*Glitched*/[]{return FireTimer >= 48 && ((CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || + CanUse(MEGATON_HAMMER)) && Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Locations + LocationAccess(FIRE_TEMPLE_VOLVAGIA_HEART, {[]{return FireTempleClear;}}), + LocationAccess(VOLVAGIA, {[]{return FireTempleClear;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return FireTempleClear;}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_ENEMIES] = Area("Fire Temple Loop Enemies", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 8) || !IsKeysanity;}}), + Entrance(FIRE_TEMPLE_LOOP_TILES, {[]{return Here(FIRE_TEMPLE_LOOP_ENEMIES, []{return IsAdult || KokiriSword;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_TILES] = Area("Fire Temple Loop Tiles", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_GS_BOSS_KEY_LOOP, {[]{return IsAdult || CanChildAttack;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_LOOP_ENEMIES, {[]{return true;}}), + Entrance(FIRE_TEMPLE_LOOP_FLARE_DANCER, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_FLARE_DANCER] = Area("Fire Temple Loop Flare Dancer", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_FLARE_DANCER_CHEST, {[]{return (HasExplosives || CanUse(MEGATON_HAMMER)) && IsAdult;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || + (CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED) && HasBombchus && CanShield && (Slingshot || CanUse(BOW) || CanUse(HOOKSHOT)));}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_LOOP_TILES, {[]{return true;}}), + Entrance(FIRE_TEMPLE_LOOP_HAMMER_SWITCH, {[]{return Here(FIRE_TEMPLE_LOOP_FLARE_DANCER, []{return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && (IsAdult || KokiriSword || Slingshot || Boomerang);});}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_HAMMER_SWITCH] = Area("Fire Temple Loop Hammer Switch", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FireLoopSwitch, {[]{return FireLoopSwitch || CanUse(MEGATON_HAMMER);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE) && Bombs && CanTakeDamage && CanUse(STICKS);}}), + }, {}, { + //Exits + Entrance(FIRE_TEMPLE_LOOP_FLARE_DANCER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_LOOP_GORON_ROOM, {[]{return FireLoopSwitch;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_GORON_ROOM] = Area("Fire Temple Loop Goron Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BOSS_KEY_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_LOOP_HAMMER_SWITCH, {[]{return FireLoopSwitch;}}), + Entrance(FIRE_TEMPLE_LOOP_EXIT, {[]{return FireLoopSwitch;}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_EXIT] = Area("Fire Temple Loop Exit", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_LOOP_GORON_ROOM, {[]{return FireLoopSwitch;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[FIRE_TEMPLE_BIG_LAVA_ROOM] = Area("Fire Temple Big Lava Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 2);}}), + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON, {[]{return true;}}), + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, {[]{return IsAdult && (CanPlay(SongOfTime) || LogicFireSongOfTime);}, + /*Glitched*/[]{return FireTimer >= 48 && ((CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || + (IsAdult && (SongOfTime && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && (Bugs || Fish) && CanShield)))));}}), + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON, {[]{return IsAdult && HasExplosives;}, + /*Glitched*/[]{return FireTimer >= 48 && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(FIRE_TEMPLE_FIRE_PILLAR_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 3);}}), + }); + + areaTable[FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON] = Area("Fire Temple Big Lava Room North Goron", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES] = Area("Fire Temple Big Lava Room North Tiles", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, {[]{return IsAdult;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON] = Area("Fire Temple Big Lava Room South Goron", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_FIRE_PILLAR_ROOM] = Area("Fire Temple Fire Pillar Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 3);}}), + Entrance(FIRE_TEMPLE_SHORTCUT_ROOM, {[]{return FireTimer >= 56 && SmallKeys(FIRE_TEMPLE, 4);}}), + }); + + areaTable[FIRE_TEMPLE_SHORTCUT_ROOM] = Area("Fire Temple Shortcut Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, {[]{return Here(FIRE_TEMPLE_SHORTCUT_CLIMB, []{return true;});}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_FIRE_PILLAR_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 4);}}), + Entrance(FIRE_TEMPLE_SHORTCUT_CLIMB, {[]{return Here(FIRE_TEMPLE_SHORTCUT_CLIMB, []{return true;});}, + /*Glitched*/[]{return (GoronBracelet || LogicFireStrength) && Bombs && CanSurviveDamage && CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return (GoronBracelet || (IsAdult && LogicFireStrength)) && (HasExplosives || (IsAdult && (CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(SLINGSHOT))));}, + /*Glitched*/[]{return (GoronBracelet || (IsAdult && LogicFireStrength)) && (CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE) || + (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanUse(STICKS)));}}), + }); + + areaTable[FIRE_TEMPLE_SHORTCUT_CLIMB] = Area("Fire Temple Shortcut Climb", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_SHORTCUT_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_BOULDER_MAZE_LOWER] = Area("Fire Temple Boulder Maze Lower", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, {[]{return true;}}), + LocationAccess(FIRE_TEMPLE_GS_BOULDER_MAZE, {[]{return HasExplosives && (IsAdult || Boomerang || CanUse(HOOKSHOT));}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE) && Bombs) || + Here(FIRE_TEMPLE_BOULDER_MAZE_UPPER, []{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);});}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_SHORTCUT_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 5, 7);}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE) && Bombs;}}), + }); + + areaTable[FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM] = Area("Fire Temple Boulder Maze Lower Side Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_EAST_CENTRAL_ROOM] = Area("Fire Temple East Central Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return CanTakeDamage;}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return SmallKeys(FIRE_TEMPLE, 5, 8);}}), + Entrance(FIRE_TEMPLE_FIRE_WALL_CHASE, {[]{return SmallKeys(FIRE_TEMPLE, 6, 8);}}), + Entrance(FIRE_TEMPLE_MAP_AREA, {[]{return CanUse(SLINGSHOT) || CanUse(BOW);}}), + }); + + areaTable[FIRE_TEMPLE_FIRE_WALL_CHASE] = Area("Fire Temple Fire Wall Chase", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return FireTimer >= 24 && SmallKeys(FIRE_TEMPLE, 6, 8);}}), + Entrance(FIRE_TEMPLE_MAP_AREA, {[]{return IsAdult;}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return FireTimer >= 24 && IsAdult;}, + /*Glitched*/[]{return FireTimer >= 32 && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(FIRE_TEMPLE_CORRIDOR, {[]{return FireTimer >= 24 && IsAdult && SmallKeys(FIRE_TEMPLE, 7);}, + /*Glitched*/[]{return FireTimer >= 32 && SmallKeys(FIRE_TEMPLE, 7) && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && Bombs && HasBombchus && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[FIRE_TEMPLE_MAP_AREA] = Area("Fire Temple Map Area", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_MAP_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_BOULDER_MAZE_UPPER] = Area("Fire Temple Boulder Maze Upper", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_SHORTCUT_CLIMB, {[]{return HasExplosives;}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_FIRE_WALL_CHASE, {[]{return true;}}), + Entrance(FIRE_TEMPLE_SCARECROW_ROOM, {[]{return CanUse(SCARECROW) || (LogicFireScarecrow && IsAdult && CanUse(LONGSHOT));}}), + }); + + areaTable[FIRE_TEMPLE_SCARECROW_ROOM] = Area("Fire Temple Scarecrow Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_GS_SCARECROW_CLIMB, {[]{return IsAdult || CanChildAttack;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_EAST_PEAK, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_EAST_PEAK] = Area("Fire Temple East Peak", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_SCARECROW_CHEST, {[]{return true;}}), + LocationAccess(FIRE_TEMPLE_GS_SCARECROW_TOP, {[]{return CanUseProjectile;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_SCARECROW_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return CanTakeDamage;}}), + }); + + areaTable[FIRE_TEMPLE_CORRIDOR] = Area("Fire Temple Corridor", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRE_WALL_CHASE, {[]{return SmallKeys(FIRE_TEMPLE, 7);}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_FIRE_MAZE_ROOM] = Area("Fire Temple Fire Maze Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_CORRIDOR, {[]{return true;}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return CanUse(HOVER_BOOTS);}, + /*Glitched*/[]{return Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return SmallKeys(FIRE_TEMPLE, 8);}}), + Entrance(FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return LogicFireFlameMaze || false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE) || (CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED) && Bombs && CanShield);}}), + }); + + areaTable[FIRE_TEMPLE_FIRE_MAZE_UPPER] = Area("Fire Temple Fire Maze Upper", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_NEAR_BOSS_ROOM, {[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_WEST_CENTRAL_UPPER, {[]{return CanUse(MEGATON_HAMMER);}, + /*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM] = Area("Fire Temple Fire Maze Side Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_COMPASS_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_WEST_CENTRAL_LOWER] = Area("Fire Temple West Central Lower", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_HIGHEST_GORON_CHEST, {[]{return Here(FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return CanPlay(SongOfTime) && CanUse(MEGATON_HAMMER);});}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE) || Here(FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return (IsAdult || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || + (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE))) && + (((SongOfTime && (((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::NOVICE))) || + CanPlay(SongOfTime)) && ((CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE)) || CanUse(MEGATON_HAMMER)));});}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 8);}}), + Entrance(FIRE_TEMPLE_WEST_CENTRAL_UPPER, {[]{return IsAdult && CanPlay(SongOfTime);}, + /*Glitched*/[]{return (IsAdult && SongOfTime && (((Bugs || Fish) && CanShield && (CanSurviveDamage || (CanTakeDamage && NumBottles >= 2)) && Bombs && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::NOVICE)))) || (Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_WEST_CENTRAL_UPPER] = Area("Fire Temple West Central Upper", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_LATE_FIRE_MAZE] = Area("Fire Temple Late Fire Maze", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || (Bombs && CanShield && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED));}}), + Entrance(FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_UPPER_FLARE_DANCER, {[]{return HasExplosives;}}), + }); + + areaTable[FIRE_TEMPLE_UPPER_FLARE_DANCER] = Area("Fire Temple Upper Flare Dancer", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return Here(FIRE_TEMPLE_UPPER_FLARE_DANCER, []{return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && (IsAdult || KokiriSword || Slingshot || Boomerang);});}}), + Entrance(FIRE_TEMPLE_WEST_CLIMB, {[]{return Here(FIRE_TEMPLE_UPPER_FLARE_DANCER, []{return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && (IsAdult || KokiriSword || Slingshot || Boomerang);});}}), + }); + + areaTable[FIRE_TEMPLE_WEST_CLIMB] = Area("Fire Temple West Climb", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_UPPER_FLARE_DANCER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_WEST_PEAK, {[]{return CanUseProjectile;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[FIRE_TEMPLE_WEST_PEAK] = Area("Fire Temple West Peak", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_MEGATON_HAMMER_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_WEST_CENTRAL_UPPER, {[]{return CanTakeDamage;}}), + Entrance(FIRE_TEMPLE_WEST_CLIMB, {[]{return true;}}), + Entrance(FIRE_TEMPLE_HAMMER_RETURN_PATH, {[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FIRE_TEMPLE_HAMMER_RETURN_PATH] = Area("Fire Temple Hammer Return Path", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_ABOVE_FIRE_MAZE, {[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FIRE_TEMPLE_ABOVE_FIRE_MAZE] = Area("Fire Temple Above Fire Maze", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_HAMMER_RETURN_PATH, {[]{return true;}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return CanUse(MEGATON_HAMMER);}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::FireTemple.IsMQ()) { + areaTable[FIRE_TEMPLE_MQ_LOWER] = Area("Fire Temple MQ Lower", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, {[]{return IsAdult || KokiriSword || Sticks || Slingshot || Bombs || CanUse(DINS_FIRE);}}), + LocationAccess(FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, {[]{return IsAdult && FireTimer >= 24 + && (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT)) + && (CanUse(FIRE_ARROWS) || (CanUse(DINS_FIRE) && + ((DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_QUADRUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OCTUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_SEXDECUPLE)) + || CanUse(GORON_TUNIC) + || CanUse(BOW) + || CanUse(LONGSHOT))));}}), + //Trick: IsAdult && (LogicFewerTunicRequirements || CanUse(GORON_TUNIC)) && (((CanUse(HOVER_BOOTS) || (LogicFireMQNearBoss && CanUse(BOW))) && HasFireSource) || (CanUse(HOOKSHOT) && CanUse(FIRE_ARROWS) || (CanUse(DINS_FIRE) && ((DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_QUADRUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OCTUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_SEXDECUPLE)) || CanUse(GORON_TUNIC) || CanUse(BOW) || CanUse(LONGSHOT))))) + }, { + //Exits + Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(FIRE_TEMPLE_MQ_BOSS_ROOM, {[]{return IsAdult && CanUse(GORON_TUNIC) && CanUse(MEGATON_HAMMER) && BossKeyFireTemple && ((HasFireSource && (LogicFireBossDoorJump || HoverBoots)) || HasAccessTo(FIRE_TEMPLE_MQ_UPPER));}}), + Entrance(FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, {[]{return SmallKeys(FIRE_TEMPLE, 5) && (IsAdult || KokiriSword);}}), + Entrance(FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, {[]{return IsAdult && FireTimer >= 24 && CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR] = Area("Fire Temple MQ Lower Locked Door", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, {[]{return IsAdult && (HasExplosives || Hammer || Hookshot);}}), + LocationAccess(FIRE_TEMPLE_MQ_MAP_CHEST, {[]{return IsAdult && CanUse(MEGATON_HAMMER);}}), + }, {}); + + areaTable[FIRE_TEMPLE_MQ_BIG_LAVA_ROOM] = Area("Fire Temple MQ Big Lava Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return FairyPot || (HasFireSource && Bow && IsAdult && (CanUse(HOOKSHOT) || LogicFireSongOfTime));}}), + //Trick: HasFireSource && (Bow || LogicFireMQBKChest) && IsAdult && (CanUse(HOOKSHOT) || LogicFireSongOfTime) + }, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return HasFireSource && Bow && IsAdult && CanUse(HOOKSHOT);}}), + //Trick: HasFireSource && (Bow || LogicFireMQBKChest) && IsAdult && CanUse(HOOKSHOT) + LocationAccess(FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, {[]{return HasFireSource && HasExplosives && IsAdult && CanUse(HOOKSHOT);}}), + //Trick: HasFireSource && HasExplosives && IsAdult && (CanUse(HOOKSHOT) || LogicFireMQBlockedChest) + LocationAccess(FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_MQ_LOWER_MAZE, {[]{return IsAdult && CanUse(GORON_TUNIC) && SmallKeys(FIRE_TEMPLE, 2) && HasFireSource;}}), + //Trick: IsAdult && CanUse(GORON_TUNIC) && SmallKeys(FIRE_TEMPLE, 2) && (HasFireSource || (LogicFireMQClimb && HoverBoots)) + }); + + areaTable[FIRE_TEMPLE_MQ_LOWER_MAZE] = Area("Fire Temple MQ Lower Maze", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, {[]{return true;}}), + LocationAccess(FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, {[]{return HasExplosives && HasAccessTo(FIRE_TEMPLE_MQ_UPPER_MAZE);}}), + //Trick: HasExplosives && (LogicFireMQMazeSideRoom || FIRE_TEMPLE_MQ_UPPER_MAZE.Adult()) + }, { + //Exits + Entrance(FIRE_TEMPLE_MQ_UPPER_MAZE, {[]{return HasExplosives && IsAdult && CanUse(HOOKSHOT);}}), + //Trick: (IsAdult && ((HasExplosives && CanUse(HOOKSHOT)) || (LogicFireMQMazeHovers && CanUse(HOVER_BOOTS)))) || LogicFireMQMazeJump + }); + + areaTable[FIRE_TEMPLE_MQ_UPPER_MAZE] = Area("Fire Temple MQ Upper Maze", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&WallFairy, {[]{return WallFairy || (IsAdult && (((CanPlay(SongOfTime) && CanUse(HOOKSHOT) && HasExplosives) || CanUse(LONGSHOT))));}}), + EventAccess(&FairyPot, {[]{return SmallKeys(FIRE_TEMPLE, 3);}}), + }, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, {[]{return true;}}), + LocationAccess(FIRE_TEMPLE_MQ_COMPASS_CHEST, {[]{return HasExplosives;}}), + LocationAccess(FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, {[]{return IsAdult && ((CanPlay(SongOfTime) && CanUse(HOOKSHOT) && HasExplosives) || CanUse(LONGSHOT));}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_MQ_UPPER, {[]{return SmallKeys(FIRE_TEMPLE, 3) && IsAdult && ((CanUse(BOW) && CanUse(HOOKSHOT)) || CanUse(FIRE_ARROWS));}}), + }); + + areaTable[FIRE_TEMPLE_MQ_UPPER] = Area("Fire Temple MQ Upper", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_FREESTANDING_KEY, {[]{return IsAdult && CanUse(HOOKSHOT);}}), + //Trick: (IsAdult && CanUse(HOOKSHOT)) || LogicFireMQFlameMaze + LocationAccess(FIRE_TEMPLE_MQ_CHEST_ON_FIRE, {[]{return IsAdult && CanUse(HOOKSHOT) && SmallKeys(FIRE_TEMPLE, 4);}}), + //Trick: ((IsAdult && CanUse(HOOKSHOT)) || LogicFireMQFlameMaze) && SmallKeys(FIRE_TEMPLE, 4) + LocationAccess(FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, {[]{return CanPlay(SongOfTime) || HoverBoots;}}), + //Trick: CanPlay(SongOfTime) || HoverBoots || LogicFireMQFlameMaze + LocationAccess(FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, {[]{return HasExplosives;}}), + LocationAccess(FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, {[]{return IsAdult && CanUse(HOOKSHOT) && SmallKeys(FIRE_TEMPLE, 5);}}), + //Trick: (IsAdult && CanUse(HOOKSHOT) && SmallKeys(FIRE_TEMPLE, 5)) || (LogicFireMQAboveMazeGS && IsAdult && CanUse(LONGSHOT)) + }, {}); + + areaTable[FIRE_TEMPLE_MQ_BOSS_ROOM] = Area("Fire Temple MQ Boss Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FireTempleClear, {[]{return true;}}), + }, { + //Locations + LocationAccess(FIRE_TEMPLE_VOLVAGIA_HEART, {[]{return true;}}), + LocationAccess(VOLVAGIA, {[]{return true;}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp new file mode 100644 index 000000000..138f6672b --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp @@ -0,0 +1,452 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_ForestTemple() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[FOREST_TEMPLE_ENTRYWAY] = Area("Forest Temple Entryway", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_FIRST_ROOM, {[]{return Dungeon::ForestTemple.IsVanilla();}}), + Entrance(FOREST_TEMPLE_MQ_LOBBY, {[]{return Dungeon::ForestTemple.IsMQ();}}), + Entrance(SACRED_FOREST_MEADOW, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::ForestTemple.IsVanilla()) { + areaTable[FOREST_TEMPLE_FIRST_ROOM] = Area("Forest Temple First Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_FIRST_ROOM_CHEST, {[]{return true;}}), + LocationAccess(FOREST_TEMPLE_GS_FIRST_ROOM, {[]{return (IsAdult && Bombs) || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(BOOMERANG) || CanUse(SLINGSHOT) || HasBombchus || CanUse(DINS_FIRE);}, + /*Glitched*/[]{return (Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_SOUTH_CORRIDOR, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_SOUTH_CORRIDOR] = Area("Forest Temple South Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_FIRST_ROOM, {[]{return true;}}), + Entrance(FOREST_TEMPLE_LOBBY, {[]{return IsAdult || CanChildAttack || Nuts;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FOREST_TEMPLE_LOBBY] = Area("Forest Temple Lobby", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleMeg, {[]{return ForestTempleMeg || (ForestTempleJoelle && ForestTempleBeth && ForestTempleAmy && CanUse(BOW));}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_GS_LOBBY, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return IsAdult && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_SOUTH_CORRIDOR, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NORTH_CORRIDOR, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return CanPlay(SongOfTime) || IsChild;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::NOVICE) || (SongOfTime && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))));}}), + Entrance(FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return CanUse(BOW) || CanUse(SLINGSHOT);}}), + Entrance(FOREST_TEMPLE_WEST_CORRIDOR, {[]{return SmallKeys(FOREST_TEMPLE, 1, 5);}}), + Entrance(FOREST_TEMPLE_EAST_CORRIDOR, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + Entrance(FOREST_TEMPLE_BOSS_REGION, {[]{return ForestTempleMeg;}}), + Entrance(FOREST_TEMPLE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return IsAdult && (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT)) && GlitchForestBKSkip;}}), + }); + + areaTable[FOREST_TEMPLE_NORTH_CORRIDOR] = Area("Forest Temple North Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_LOWER_STALFOS, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_LOWER_STALFOS] = Area("Forest Temple Lower Stalfos", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_FIRST_STALFOS_CHEST, {[]{return IsAdult || KokiriSword;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NORTH_CORRIDOR, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_NW_OUTDOORS_LOWER] = Area("Forest Temple NW Outdoors Lower", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, {[]{return CanUse(LONGSHOT) || Here(FOREST_TEMPLE_NW_OUTDOORS_UPPER, []{return HookshotOrBoomerang;});}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return CanPlay(SongOfTime);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::NOVICE) || (SongOfTime && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))));}}), + Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || (IsAdult && CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::NOVICE)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(FOREST_TEMPLE_MAP_ROOM, {[]{return true;}}), + Entrance(FOREST_TEMPLE_SEWER, {[]{return GoldScale || CanUse(IRON_BOOTS) || HasAccessTo(FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}), + Entrance(FOREST_TEMPLE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[FOREST_TEMPLE_NW_OUTDOORS_UPPER] = Area("Forest Temple NW Outdoors Upper", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, {}, { + //Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return true;}}), + Entrance(FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, {[]{return true;}}), + Entrance(FOREST_TEMPLE_FLOORMASTER_ROOM, {[]{return true;}}), + Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_NE_OUTDOORS_LOWER] = Area("Forest Temple NE Outdoors Lower", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, {[]{return CanUse(HOOKSHOT) || HasAccessTo(FOREST_TEMPLE_FALLING_ROOM);}}), + LocationAccess(FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, {[]{return CanUse(HOOKSHOT) || (LogicForestOutdoorEastGS && CanUse(BOOMERANG)) || Here(FOREST_TEMPLE_FALLING_ROOM, []{return CanUse(BOW) || CanUse(SLINGSHOT) || CanUse(DINS_FIRE) || HasExplosives;});}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NE_OUTDOORS_UPPER, {[]{return CanUse(LONGSHOT);}}), + Entrance(FOREST_TEMPLE_SEWER, {[]{return GoldScale || CanUse(IRON_BOOTS) || HasAccessTo(FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}), + Entrance(FOREST_TEMPLE_FALLING_ROOM, {[]{return false;}, + /*Glitched*/[]{return Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[FOREST_TEMPLE_NE_OUTDOORS_UPPER] = Area("Forest Temple NE Outdoors Upper", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, {}, { + //Exits + Entrance(FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return true;}}), + Entrance(FOREST_TEMPLE_MAP_ROOM, {[]{return true;}}), + Entrance(FOREST_TEMPLE_FALLING_ROOM, {[]{return LogicForestDoorFrame && CanUse(HOVER_BOOTS) && CanUse(SCARECROW);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::EXPERT);}}), + }); + + areaTable[FOREST_TEMPLE_MAP_ROOM] = Area("Forest Temple Map Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MAP_CHEST, {[]{return Here(FOREST_TEMPLE_MAP_ROOM, []{return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || ((IsAdult || Sticks || KokiriSword || Slingshot) && (Nuts || HookshotOrBoomerang || CanShield));});}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return Here(FOREST_TEMPLE_MAP_ROOM, []{return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || ((IsAdult || Sticks || KokiriSword || Slingshot) && (Nuts || HookshotOrBoomerang || CanShield));});}}), + Entrance(FOREST_TEMPLE_NE_OUTDOORS_UPPER, {[]{return Here(FOREST_TEMPLE_MAP_ROOM, []{return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || ((IsAdult || Sticks || KokiriSword || Slingshot) && (Nuts || HookshotOrBoomerang || CanShield));});}}), + }); + + areaTable[FOREST_TEMPLE_SEWER] = Area("Forest Temple Sewer", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_WELL_CHEST, {[]{return HasAccessTo(FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST] = Area("Forest Temple Below Boss Key Chest", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return Here(FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, []{return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || ((IsAdult || Sticks || KokiriSword || Slingshot) && (Nuts || HookshotOrBoomerang || CanShield));});}}), + }); + + areaTable[FOREST_TEMPLE_FLOORMASTER_ROOM] = Area("Forest Temple Floormaster Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_FLOORMASTER_CHEST, {[]{return IsAdult || CanChildDamage;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_WEST_CORRIDOR] = Area("Forest Temple West Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return SmallKeys(FOREST_TEMPLE, 1, 5);}}), + Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return IsAdult || CanChildAttack || Nuts;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FOREST_TEMPLE_BLOCK_PUSH_ROOM] = Area("Forest Temple Block Push Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_EYE_SWITCH_CHEST, {[]{return GoronBracelet && (CanUse(BOW) || CanUse(SLINGSHOT));}, + /*Glitched*/[]{return IsAdult && (CanUse(BOW) || CanUse(SLINGSHOT)) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_WEST_CORRIDOR, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return CanUse(HOVER_BOOTS) || (LogicForestOutsideBackdoor && IsAdult && GoronBracelet);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || (Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return IsAdult && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}, + /*Glitched*/[]{return ((IsAdult && (Bow || Hookshot || CanUse(SLINGSHOT)) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)) || + (Bombs && GoronBracelet && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE))) && SmallKeys(FOREST_TEMPLE, 2);}}), + Entrance(FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, {[]{return CanUse(BOW) && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}, + /*Glitched*/[]{return ((IsAdult && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)) || + (IsChild && Bombs && GoronBracelet && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE))) && (CanUse(BOW) || CanUse(SLINGSHOT)) && SmallKeys(FOREST_TEMPLE, 2);}}), + }); + + areaTable[FOREST_TEMPLE_NW_CORRIDOR_TWISTED] = Area("Forest Temple NW Corridor Twisted", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 2);}}), + Entrance(FOREST_TEMPLE_RED_POE_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 3);}}), + }); + + areaTable[FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED] = Area("Forest Temple NW Corridor Straightened", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_BOSS_KEY_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, {[]{return true;}}), + Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 2);}}), + }); + + areaTable[FOREST_TEMPLE_RED_POE_ROOM] = Area("Forest Temple Red Poe Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleJoelle, {[]{return ForestTempleJoelle || CanUse(BOW);}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_RED_POE_CHEST, {[]{return ForestTempleJoelle;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return SmallKeys(FOREST_TEMPLE, 3);}}), + Entrance(FOREST_TEMPLE_UPPER_STALFOS, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_UPPER_STALFOS] = Area("Forest Temple Upper Stalfos", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_BOW_CHEST, {[]{return IsAdult || KokiriSword;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_RED_POE_ROOM, {[]{return IsAdult || KokiriSword;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(FOREST_TEMPLE_BLUE_POE_ROOM, {[]{return IsAdult || KokiriSword;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FOREST_TEMPLE_BLUE_POE_ROOM] = Area("Forest Temple Blue Poe Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleBeth, {[]{return ForestTempleBeth || CanUse(BOW);}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_BLUE_POE_CHEST, {[]{return ForestTempleBeth;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_UPPER_STALFOS, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, {[]{return SmallKeys(FOREST_TEMPLE, 4);}}), + }); + + areaTable[FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED] = Area("Forest Temple NE Corridor Straightened", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_BLUE_POE_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 4);}}), + Entrance(FOREST_TEMPLE_FROZEN_EYE_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 5);}}), + }); + + areaTable[FOREST_TEMPLE_NE_CORRIDOR_TWISTED] = Area("Forest Temple NE Corridor Twisted", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_FROZEN_EYE_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 5);}}), + Entrance(FOREST_TEMPLE_FALLING_ROOM, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_FROZEN_EYE_ROOM] = Area("Forest Temple Frozen Eye Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, {[]{return SmallKeys(FOREST_TEMPLE, 5);}}), + Entrance(FOREST_TEMPLE_NE_CORRIDOR_TWISTED, {[]{return SmallKeys(FOREST_TEMPLE, 5) && (CanUse(BOW) || CanUse(DINS_FIRE));}}), + }); + + areaTable[FOREST_TEMPLE_FALLING_ROOM] = Area("Forest Temple Falling Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return true;}}), + Entrance(FOREST_TEMPLE_GREEN_POE_ROOM, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_GREEN_POE_ROOM] = Area("Forest Temple Green Poe Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleAmy, {[]{return ForestTempleAmy || CanUse(BOW);}}), + }, {}, { + //Exits + Entrance(FOREST_TEMPLE_FALLING_ROOM, {[]{return true;}}), + Entrance(FOREST_TEMPLE_EAST_CORRIDOR, {[]{return ForestTempleAmy;}}), + }); + + areaTable[FOREST_TEMPLE_EAST_CORRIDOR] = Area("Forest Temple East Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return IsAdult || CanChildAttack || Nuts;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(FOREST_TEMPLE_GREEN_POE_ROOM, {[]{return IsAdult || CanChildAttack || Nuts;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FOREST_TEMPLE_BOSS_REGION] = Area("Forest Temple Boss Region", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_BASEMENT_CHEST, {[]{return true;}}), + LocationAccess(FOREST_TEMPLE_GS_BASEMENT, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_BOSS_ROOM, {[]{return BossKeyForestTemple;}}), + }); + + areaTable[FOREST_TEMPLE_BOSS_ROOM] = Area("Forest Temple Boss Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleClear, {[]{return ForestTempleClear || ((IsAdult || KokiriSword) && (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT)));}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_PHANTOM_GANON_HEART, {[]{return ForestTempleClear;}}), + LocationAccess(PHANTOM_GANON, {[]{return ForestTempleClear;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_ENTRYWAY, {[]{return ForestTempleClear;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::ForestTemple.IsMQ()) { + areaTable[FOREST_TEMPLE_MQ_LOBBY] = Area("Forest Temple MQ Lobby", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, {[]{return IsAdult || Bombs || CanUse(STICKS) || Nuts || CanUse(BOOMERANG) || CanUse(DINS_FIRE) || KokiriSword || CanUse(SLINGSHOT);}}), + LocationAccess(FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, {[]{return HookshotOrBoomerang;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return SmallKeys(FOREST_TEMPLE, 1) && (IsAdult || CanChildAttack || Nuts);}}), + }); + + areaTable[FOREST_TEMPLE_MQ_CENTRAL_AREA] = Area("Forest Temple MQ Central Area", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_WOLFOS_CHEST, {[]{return (CanPlay(SongOfTime) || IsChild) && (IsAdult || CanUse(DINS_FIRE) || CanUse(STICKS) || CanUse(SLINGSHOT) || KokiriSword);}}), + LocationAccess(FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, {[]{return IsAdult || KokiriSword;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return (IsAdult && CanUse(BOW)) || (IsChild && CanUse(SLINGSHOT));}}), + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return (IsAdult && CanUse(BOW)) || (IsChild && CanUse(SLINGSHOT));}}), //This is as far as child can get + Entrance(FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, {[]{return IsAdult && GoronBracelet;}}), + //Trick: IsAdult && (GoronBracelet || (LogicForestMQBlockPuzzle && HasBombchus && IsAdult && CanUse(HOOKSHOT))) + Entrance(FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return false;}}), + //Trick: (LogicForestMQHallwaySwitchJumpslash && IsAdult && CanUse(HOVER_BOOTS)) || (LogicForestMQHallwaySwitchHookshot && IsAdult && CanUse(HOOKSHOT)) + Entrance(FOREST_TEMPLE_MQ_BOSS_REGION, {[]{return ForestTempleJoAndBeth && ForestTempleAmyAndMeg;}}), + }); + + areaTable[FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE] = Area("Forest Temple MQ After Block Puzzle", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return SmallKeys(FOREST_TEMPLE, 3);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_BOW_REGION, {[]{return SmallKeys(FOREST_TEMPLE, 4);}}), + Entrance(FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return SmallKeys(FOREST_TEMPLE, 3);}}), + //Trick: SmallKeys(FOREST_TEMPLE, 3) || (LogicForestMQHallwaySwitchJumpslash && ((IsAdult && CanUse(HOOKSHOT)) || LogicForestOutsideBackdoor)) + Entrance(FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return SmallKeys(FOREST_TEMPLE, 2);}}), + }); + + areaTable[FOREST_TEMPLE_MQ_OUTDOOR_LEDGE] = Area("Forest Temple MQ Outdoor Ledge", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_REDEAD_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_MQ_NW_OUTDOORS] = Area("Forest Temple MQ NW Outdoors", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return (IsAdult && (CanUse(IRON_BOOTS) || CanUse(LONGSHOT))) || ProgressiveScale >= 2;}}), + //Trick: (IsAdult && (CanUse(IRON_BOOTS) || CanUse(LONGSHOT) || (LogicForestMQWellSwim && CanUse(HOOKSHOT)))) || ProgressiveScale >= 2 + Entrance(FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return IsAdult && CanUse(FIRE_ARROWS);}}), + }); + + areaTable[FOREST_TEMPLE_MQ_NE_OUTDOORS] = Area("Forest Temple MQ NE Outdoors", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_WELL_CHEST, {[]{return (IsAdult && CanUse(BOW)) || (IsChild && CanUse(SLINGSHOT));}}), + LocationAccess(FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, {[]{return HookshotOrBoomerang || (IsAdult && CanUse(FIRE_ARROWS) && (CanPlay(SongOfTime) || (CanUse(HOVER_BOOTS) && LogicForestDoorFrame)));}}), + LocationAccess(FOREST_TEMPLE_MQ_GS_WELL, {[]{return (IsAdult && ((CanUse(IRON_BOOTS) && CanUse(HOOKSHOT)) || CanUse(BOW))) || (IsChild && CanUse(SLINGSHOT));}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return IsAdult && CanUse(HOOKSHOT) && (CanUse(LONGSHOT) || CanUse(HOVER_BOOTS) || CanPlay(SongOfTime));}}), + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return IsAdult && CanUse(LONGSHOT);}}), + }); + + areaTable[FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES] = Area("Forest Temple MQ Outdoors Top Ledges", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return true;}}), + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return false;}}), + //Trick: LogicForestOutdoorsLedge && IsAdult && CanUse(HOVER_BOOTS) + }); + + areaTable[FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE] = Area("Forest Temple MQ NE Outdoors Ledge", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return true;}}), + Entrance(FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return CanPlay(SongOfTime);}}), + }); + + areaTable[FOREST_TEMPLE_MQ_BOW_REGION] = Area("Forest Temple MQ Bow Region", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleJoAndBeth, {[]{return ForestTempleJoAndBeth || (IsAdult && CanUse(BOW));}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_BOW_CHEST, {[]{return true;}}), + LocationAccess(FOREST_TEMPLE_MQ_MAP_CHEST, {[]{return IsAdult && CanUse(BOW);}}), + LocationAccess(FOREST_TEMPLE_MQ_COMPASS_CHEST, {[]{return IsAdult && CanUse(BOW);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 5) && ((IsAdult && CanUse(BOW)) || CanUse(DINS_FIRE));}}), + }); + + areaTable[FOREST_TEMPLE_MQ_FALLING_ROOM] = Area("Forest Temple MQ Falling Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleAmyAndMeg, {[]{return ForestTempleAmyAndMeg || (IsAdult && CanUse(BOW) && SmallKeys(FOREST_TEMPLE, 6));}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_MQ_BOSS_REGION] = Area("Forest Temple MQ Boss Region", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleClear, {[]{return ForestTempleClear || BossKeyForestTemple;}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_BASEMENT_CHEST, {[]{return true;}}), + LocationAccess(FOREST_TEMPLE_PHANTOM_GANON_HEART, {[]{return BossKeyForestTemple;}}), + LocationAccess(PHANTOM_GANON, {[]{return BossKeyForestTemple;}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp new file mode 100644 index 000000000..383b72b9f --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp @@ -0,0 +1,213 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" +#include "../trial.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_GanonsCastle() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[GANONS_CASTLE_ENTRYWAY] = Area("Ganon's Castle Entryway", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GANONS_CASTLE_LOBBY, {[]{return Dungeon::GanonsCastle.IsVanilla();}}), + Entrance(GANONS_CASTLE_MQ_LOBBY, {[]{return Dungeon::GanonsCastle.IsMQ();}}), + Entrance(GANONS_CASTLE_GROUNDS, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::GanonsCastle.IsVanilla()) { + areaTable[GANONS_CASTLE_LOBBY] = Area("Ganon's Castle Lobby", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GANONS_CASTLE_ENTRYWAY, {[]{return true;}}), + Entrance(GANONS_CASTLE_FOREST_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_FIRE_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_WATER_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_SHADOW_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_SPIRIT_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_LIGHT_TRIAL, {[]{return CanUse(GOLDEN_GAUNTLETS);}}), + Entrance(GANONS_CASTLE_TOWER, {[]{return (ForestTrialClear || Trial::ForestTrial.IsSkipped()) && + (FireTrialClear || Trial::FireTrial.IsSkipped()) && + (WaterTrialClear || Trial::WaterTrial.IsSkipped()) && + (ShadowTrialClear || Trial::ShadowTrial.IsSkipped()) && + (SpiritTrialClear || Trial::SpiritTrial.IsSkipped()) && + (LightTrialClear || Trial::LightTrial.IsSkipped());}}), + Entrance(GANONS_CASTLE_DEKU_SCRUBS, {[]{return LogicLensCastle || CanUse(LENS_OF_TRUTH);}}), + }); + + areaTable[GANONS_CASTLE_DEKU_SCRUBS] = Area("Ganon's Castle Deku Scrubs", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_DEKU_SCRUB_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_DEKU_SCRUB_LEFT, {[]{return CanStunDeku;}}), + }, {}); + + areaTable[GANONS_CASTLE_FOREST_TRIAL] = Area("Ganon's Castle Forest Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTrialClear, {[]{return CanUse(LIGHT_ARROWS) && (FireArrows || DinsFire);}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_FOREST_TRIAL_CHEST, {[]{return IsAdult || CanChildDamage;}}), + }, {}); + + areaTable[GANONS_CASTLE_FIRE_TRIAL] = Area("Ganon's Castle Fire Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FireTrialClear, {[]{return CanUse(GORON_TUNIC) && CanUse(GOLDEN_GAUNTLETS) && CanUse(LIGHT_ARROWS) && CanUse(LONGSHOT);}}), + }, {}, {}); + + areaTable[GANONS_CASTLE_WATER_TRIAL] = Area("Ganon's Castle Water Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BlueFireAccess, {[]{return BlueFireAccess || HasBottle;}}), + EventAccess(&FairyPot, {[]{return FairyPot || BlueFire;}}), + EventAccess(&WaterTrialClear, {[]{return BlueFire && Hammer && CanUse(LIGHT_ARROWS);}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, {[]{return true;}}), + }, {}); + + areaTable[GANONS_CASTLE_SHADOW_TRIAL] = Area("Ganon's Castle Shadow Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ShadowTrialClear, {[]{return CanUse(LIGHT_ARROWS) && Hammer && ((FireArrows && (LogicLensCastle || CanUse(LENS_OF_TRUTH))) || (CanUse(LONGSHOT) && (CanUse(HOVER_BOOTS) || (DinsFire && (LogicLensCastle || CanUse(LENS_OF_TRUTH))))));}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, {[]{return CanUse(FIRE_ARROWS) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || CanPlay(SongOfTime) || IsChild;}}), + LocationAccess(GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, {[]{return CanUse(FIRE_ARROWS) || (CanUse(LONGSHOT) && (CanUse(HOVER_BOOTS) || CanUse(DINS_FIRE)));}}), + }, {}); + + areaTable[GANONS_CASTLE_SPIRIT_TRIAL] = Area("Ganon's Castle Spirit Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return NutPot || ((LogicSpiritTrialHookshot || CanUse(HOOKSHOT)) && HasBombchus && Bow && MirrorShield && IsAdult);}}), + EventAccess(&SpiritTrialClear, {[]{return CanUse(LIGHT_ARROWS) && MirrorShield && HasBombchus && (LogicSpiritTrialHookshot || CanUse(HOOKSHOT));}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, {[]{return LogicSpiritTrialHookshot || CanUse(HOOKSHOT);}}), + LocationAccess(GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, {[]{return (LogicSpiritTrialHookshot || CanUse(HOOKSHOT)) && HasBombchus && (LogicLensCastle || CanUse(LENS_OF_TRUTH));}}), + }, {}); + + areaTable[GANONS_CASTLE_LIGHT_TRIAL] = Area("Ganon's Castle Light Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&LightTrialClear, {[]{return CanUse(LIGHT_ARROWS) && CanUse(HOOKSHOT) && SmallKeys(GANONS_CASTLE, 2) && (LogicLensCastle || CanUse(LENS_OF_TRUTH));}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, {[]{return LogicLensCastle || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, {[]{return CanPlay(ZeldasLullaby) && SmallKeys(GANONS_CASTLE, 1);}}), + }, {}); + } + + areaTable[GANONS_CASTLE_TOWER] = Area("Ganon's Castle Tower", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GANONS_TOWER_BOSS_KEY_CHEST, {[]{return true;}}), + LocationAccess(GANONDORF_HINT, {[]{return BossKeyGanonsCastle;}}), + LocationAccess(GANON, {[]{return BossKeyGanonsCastle && CanUse(LIGHT_ARROWS);}}), + }, {}); + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::GanonsCastle.IsMQ()) { + areaTable[GANONS_CASTLE_MQ_LOBBY] = Area("Ganon's Castle MQ Lobby", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GANONS_CASTLE_ENTRYWAY, {[]{return (IsAdult || (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword))));}}), + Entrance(GANONS_CASTLE_MQ_FOREST_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_MQ_FIRE_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_MQ_WATER_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_MQ_SHADOW_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_MQ_SPIRIT_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_MQ_LIGHT_TRIAL, {[]{return CanUse(GOLDEN_GAUNTLETS);}}), + Entrance(GANONS_CASTLE_TOWER, {[]{return (ForestTrialClear || Trial::ForestTrial.IsSkipped()) && + (FireTrialClear || Trial::FireTrial.IsSkipped()) && + (WaterTrialClear || Trial::WaterTrial.IsSkipped()) && + (ShadowTrialClear || Trial::ShadowTrial.IsSkipped()) && + (SpiritTrialClear || Trial::SpiritTrial.IsSkipped()) && + (LightTrialClear || Trial::LightTrial.IsSkipped());}}), + Entrance(GANONS_CASTLE_MQ_DEKU_SCRUBS, {[]{return LogicLensCastleMQ || CanUse(LENS_OF_TRUTH);}}), + }); + + areaTable[GANONS_CASTLE_MQ_DEKU_SCRUBS] = Area("Ganon's Castle MQ Deku Scrubs", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, {[]{return CanStunDeku;}}), + }, {}); + + areaTable[GANONS_CASTLE_MQ_FOREST_TRIAL] = Area("Ganon's Castle MQ Forest Trial", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTrialClear, {[]{return IsAdult && CanUse(LIGHT_ARROWS) && CanPlay(SongOfTime);}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, {[]{return (IsAdult && CanUse(BOW)) || (IsChild && CanUse(SLINGSHOT));}}), + LocationAccess(GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, {[]{return HasFireSource;}}), + LocationAccess(GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, {[]{return HookshotOrBoomerang;}}), + }, {}); + + areaTable[GANONS_CASTLE_MQ_FIRE_TRIAL] = Area("Ganon's Castle MQ Fire Trial", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FireTrialClear, {[]{return CanUse(GORON_TUNIC) && CanUse(GOLDEN_GAUNTLETS) && CanUse(LIGHT_ARROWS) && (CanUse(LONGSHOT) || CanUse(HOVER_BOOTS));}}), + //Trick: CanUse(GORON_TUNIC) && CanUse(GOLDEN_GAUNTLETS) && CanUse(LIGHT_ARROWS) && (CanUse(LONGSHOT) || HoverBoots || (LogicFireTrialMQ && CanUse(HOOKSHOT))) + }, {}, {}); + + areaTable[GANONS_CASTLE_MQ_WATER_TRIAL] = Area("Ganon's Castle MQ Water Trial", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTrialClear, {[]{return BlueFire && IsAdult && CanUse(LIGHT_ARROWS) && SmallKeys(GANONS_CASTLE, 3);}}), + EventAccess(&BlueFireAccess, {[]{return BlueFireAccess || HasBottle;}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, {[]{return BlueFire && (IsAdult || CanUse(STICKS) || KokiriSword || CanUseProjectile);}}), + }, {}); + + areaTable[GANONS_CASTLE_MQ_SHADOW_TRIAL] = Area("Ganon's Castle MQ Shadow Trial", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ShadowTrialClear, {[]{return IsAdult && CanUse(LIGHT_ARROWS) && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (CanUse(HOVER_BOOTS) || (CanUse(HOOKSHOT) && HasFireSource));}}), + //Trick: IsAdult && CanUse(LIGHT_ARROWS) && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (HoverBoots || (Hookshot && (HasFireSource || LogicShadowTrialMQ))) + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, {[]{return IsAdult && ((Bow && (CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS))) || (CanUse(HOVER_BOOTS) && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (HasExplosives || GoronBracelet || CanUse(DINS_FIRE))));}}), + LocationAccess(GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, {[]{return IsAdult && Bow && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (CanUse(HOVER_BOOTS) || (CanUse(HOOKSHOT) && HasFireSource));}}), + //Trick: IsAdult && Bow && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (HoverBoots || (Hookshot && (HasFireSource || LogicShadowTrialMQ))) + }, {}); + + areaTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL] = Area("Ganon's Castle MQ Spirit Castle", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&SpiritTrialClear, {[]{return IsAdult && CanUse(LIGHT_ARROWS) && Hammer && HasBombchus && FireArrows && MirrorShield;}}), + EventAccess(&NutPot, {[]{return NutPot || (Hammer && HasBombchus && IsAdult && CanUse(FIRE_ARROWS) && MirrorShield);}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, {[]{return IsAdult && Bow && Hammer;}}), + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, {[]{return IsAdult && Bow && Hammer && HasBombchus && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && CanUse(FIRE_ARROWS) && CanUse(MIRROR_SHIELD);}}), + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && CanUse(FIRE_ARROWS) && CanUse(MIRROR_SHIELD);}}), + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, {[]{return IsAdult && Hammer && HasBombchus && CanUse(FIRE_ARROWS) && CanUse(MIRROR_SHIELD);}}), + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && CanUse(FIRE_ARROWS) && CanUse(MIRROR_SHIELD);}}), + }, {}); + + areaTable[GANONS_CASTLE_MQ_LIGHT_TRIAL] = Area("Ganon's Castle MQ Light Trial", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&LightTrialClear, {[]{return IsAdult && CanUse(LIGHT_ARROWS) && SmallKeys(GANONS_CASTLE, 3) && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && CanUse(HOOKSHOT);}}), + //Trick: IsAdult && CanUse(LIGHT_ARROWS) && SmallKeys(GANONS_CASTLE, 3) && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (Hookshot || LogicLightTrialMQ) + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, {[]{return CanPlay(ZeldasLullaby);}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_grounds.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_grounds.cpp new file mode 100644 index 000000000..41eca39a2 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_grounds.cpp @@ -0,0 +1,199 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_GerudoTrainingGrounds() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[GERUDO_TRAINING_GROUNDS_ENTRYWAY] = Area("Gerudo Training Grounds Entryway", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_LOBBY, {[]{return Dungeon::GerudoTrainingGrounds.IsVanilla();}}), + Entrance(GERUDO_TRAINING_GROUNDS_MQ_LOBBY, {[]{return Dungeon::GerudoTrainingGrounds.IsMQ();}}), + Entrance(GERUDO_FORTRESS, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::GerudoTrainingGrounds.IsVanilla()) { + areaTable[GERUDO_TRAINING_GROUNDS_LOBBY] = Area("Gerudo Training Grounds Lobby", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST, {[]{return CanUse(BOW) || CanUse(SLINGSHOT);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST, {[]{return CanUse(BOW) || CanUse(SLINGSHOT);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_STALFOS_CHEST, {[]{return IsAdult || KokiriSword;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST, {[]{return HasExplosives && (IsAdult || KokiriSword);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return true;}}), + Entrance(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, {[]{return (IsAdult || KokiriSword) && (CanUse(HOOKSHOT) || LogicGtgWithoutHookshot);}}), + Entrance(GERUDO_TRAINING_GROUNDS_LAVA_ROOM, {[]{return Here(GERUDO_TRAINING_GROUNDS_LOBBY, []{return (IsAdult || KokiriSword) && HasExplosives;});}}), + Entrance(GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, {[]{return true;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE] = Area("Gerudo Training Grounds Central Maze", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 3) && (LogicLensGtg || CanUse(LENS_OF_TRUTH));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE) && (LogicLensGtg || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 4);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 6);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 7);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 9);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 9);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT] = Area("Gerudo Training Grounds Central Maze Right", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY, {[]{return true;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, {[]{return CanUse(HOOKSHOT);}}), + Entrance(GERUDO_TRAINING_GROUNDS_LAVA_ROOM, {[]{return true;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_LAVA_ROOM] = Area("Gerudo Training Grounds Lava Room", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST, {[]{return CanUse(HOOKSHOT) && CanPlay(SongOfTime) && IronBoots && WaterTimer >= 24;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, {[]{return CanPlay(SongOfTime) || IsChild;}}), + Entrance(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, {[]{return CanUse(LONGSHOT) || (CanUse(HOVER_BOOTS) && CanUse(HOOKSHOT));}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_HAMMER_ROOM] = Area("Gerudo Training Grounds Hammer Room", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST, {[]{return CanUse(MEGATON_HAMMER) || (CanTakeDamage && LogicFlamingChests);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, {[]{return CanUse(MEGATON_HAMMER) && Bow;}}), + Entrance(GERUDO_TRAINING_GROUNDS_LAVA_ROOM, {[]{return true;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER] = Area("Gerudo Training Grounds Eye Statue Lower", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST, {[]{return CanUse(BOW);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, {[]{return true;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER] = Area("Gerudo Training Grounds Eye Statue Upper", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST, {[]{return CanUse(BOW);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, {[]{return true;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM] = Area("Gerudo Training Grounds Heavy Block Room", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, {[]{return (LogicLensGtg || CanUse(LENS_OF_TRUTH)) && (CanUse(HOOKSHOT) || (LogicGtgFakeWall && CanUse(HOVER_BOOTS)));}}), + Entrance(GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, {[]{return (LogicLensGtg || CanUse(LENS_OF_TRUTH)) && (CanUse(HOOKSHOT) || (LogicGtgFakeWall && CanUse(HOVER_BOOTS))) && CanUse(SILVER_GAUNTLETS);}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM] = Area("Gerudo Training Grounds Like Like Room", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST, {[]{return true;}}), + }, {}); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::GerudoTrainingGrounds.IsMQ()) { + areaTable[GERUDO_TRAINING_GROUNDS_MQ_LOBBY] = Area("Gerudo Training Grounds MQ Lobby", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST, {[]{return LogicLensGtgMQ || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 1);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return true;}}), + Entrance(GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, {[]{return Here(GERUDO_TRAINING_GROUNDS_MQ_LOBBY, []{return HasFireSource;});}}), + Entrance(GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, {[]{return Here(GERUDO_TRAINING_GROUNDS_MQ_LOBBY, []{return (IsAdult && CanUse(BOW)) || (IsChild && CanUse(SLINGSHOT));});}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE] = Area("Gerudo Training Grounds MQ Right Side", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&WallFairy, {[]{return WallFairy || (IsAdult && CanUse(BOW));}}), + }, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST, {[]{return IsAdult;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, {[]{return (Bow || CanUse(LONGSHOT)) && CanUse(HOVER_BOOTS) && IsAdult;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER] = Area("Gerudo Training Grounds MQ Underwater", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST, {[]{return HasFireSource && IsAdult && CanUse(IRON_BOOTS) && WaterTimer >= 24 && CanTakeDamage;}}), + }, {}); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE] = Area("Gerudo Training Grounds MQ Left Side", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST, {[]{return IsAdult || KokiriSword || HasExplosives;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, {[]{return IsAdult && CanUse(LONGSHOT);}}), + //Trick: (IsAdult && CanUse(LONGSHOT)) || LogicGtgMQWithoutHookshot || (LogicGtgMQWithHookshot && IsAdult && CanUse(HOOKSHOT)) + }); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM] = Area("Gerudo Training Grounds MQ Stalfos Room", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BlueFireAccess, {[]{return BlueFireAccess || HasBottle;}}), + }, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST, {[]{return IsAdult;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST, {[]{return CanUse(SILVER_GAUNTLETS);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, {[]{return IsAdult && (LogicLensGtgMQ || CanUse(LENS_OF_TRUTH)) && BlueFire && CanPlay(SongOfTime);}}), + //Trick: IsAdult && (LogicLensGtgMQ || CanUse(LENS_OF_TRUTH)) && BlueFire && (CanPlay(SongOfTime) || (LogicGtgFakeWall && IsAdult && CanUse(HOVER_BOOTS))) + }); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS] = Area("Gerudo Training Grounds MQ Back Areas", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST, {[]{return Bow;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST, {[]{return CanUse(HOOKSHOT) || Bow || HasExplosives;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, {[]{return Hammer;}}), + Entrance(GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, {[]{return CanUse(LONGSHOT);}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT] = Area("Gerudo Training Grounds MQ Central Maze Right", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 3);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, {[]{return IsAdult && (CanUse(LONGSHOT) || (CanUse(HOOKSHOT) && Bow));}}), + Entrance(GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, {[]{return IsAdult && CanUse(HOOKSHOT);}}), + }); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp new file mode 100644 index 000000000..7f99b05ff --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp @@ -0,0 +1,234 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_GerudoValley() { + areaTable[GERUDO_VALLEY] = Area("Gerudo Valley", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BugRock, {[]{return BugRock || IsChild;}}), + }, { + //Locations + LocationAccess(GV_GS_SMALL_BRIDGE, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsChild && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && AtNight && CanGetNightTimeGS;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + Entrance(GV_UPPER_STREAM, {[]{return true;}}), + Entrance(GV_CRATE_LEDGE, {[]{return IsChild || CanUse(LONGSHOT);}}), + Entrance(GV_GROTTO_LEDGE, {[]{return true;}}), + Entrance(GV_FORTRESS_SIDE, {[]{return (IsAdult && (CanRideEpona || CanUse(LONGSHOT) || GerudoFortress.Is(GERUDOFORTRESS_OPEN) || CarpenterRescue)) || (IsChild && CanUse(HOOKSHOT));}, + /*Glitched*/[]{return (HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || (IsChild && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::HERO)) || (IsAdult && (CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED) || + (CanUse(HOVER_BOOTS) && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE) || (CanSurviveDamage && (Bombs || HasBombchus) && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::NOVICE)) || (Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED))))));}}), + }); + + areaTable[GV_UPPER_STREAM] = Area("GV Upper Stream", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(GV_UPPER_STREAM) && CanPlay(SongOfStorms));}}), + }, { + //Locations + LocationAccess(GV_WATERFALL_FREESTANDING_POH, {[]{return true;}}), + LocationAccess(GV_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}), + LocationAccess(GV_COW, {[]{return IsChild && CanPlay(EponasSong);}, + /*Glitched*/[]{return IsChild && EponasSong && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)));}}), + LocationAccess(GV_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(GV_LOWER_STREAM, {[]{return true;}}), + }); + + areaTable[GV_LOWER_STREAM] = Area("GV Lower Stream", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(LAKE_HYLIA, {[]{return true;}}), + }); + + areaTable[GV_GROTTO_LEDGE] = Area("GV Grotto Ledge", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GV_LOWER_STREAM, {[]{return true;}}), + Entrance(GV_OCTOROK_GROTTO, {[]{return CanUse(SILVER_GAUNTLETS);}}), + Entrance(GV_CRATE_LEDGE, {[]{return CanUse(LONGSHOT);}}), + }); + + areaTable[GV_CRATE_LEDGE] = Area("GV Crate Ledge", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GV_CRATE_FREESTANDING_POH, {[]{return true;}}), + }, { + //Exits + Entrance(GV_LOWER_STREAM, {[]{return true;}}), + }); + + areaTable[GV_FORTRESS_SIDE] = Area("GV Fortress Side", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BrokenSwordAccess, {[]{return IsAdult && (PoachersSawAccess || PoachersSaw);}}), + }, { + //Locations + LocationAccess(GV_CHEST, {[]{return IsAdult && (CanUse(MEGATON_HAMMER) || LogicGVHammerChest);}, + /*Glitched*/[]{return IsAdult && (CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE) && (CanTakeDamageTwice || CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED))));}}), + LocationAccess(GV_TRADE_SAW, {[]{return IsAdult && PoachersSaw;}}), + LocationAccess(GV_GS_BEHIND_TENT, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && IsAdult && AtNight && CanGetNightTimeGS;}}), + LocationAccess(GV_GS_PILLAR, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + }, { + //Exits + Entrance(GERUDO_FORTRESS, {[]{return true;}}), + Entrance(GV_UPPER_STREAM, {[]{return true;}}), + Entrance(GERUDO_VALLEY, {[]{return IsChild || CanRideEpona || CanUse(LONGSHOT) || GerudoFortress.Is(GERUDOFORTRESS_OPEN) || CarpenterRescue;}, + /*Glitched*/[]{return (HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED) || + (CanUse(HOVER_BOOTS) && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE) || (CanSurviveDamage && (Bombs || HasBombchus) && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::NOVICE)) || (Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED))));}}), + Entrance(GV_CARPENTER_TENT, {[]{return IsAdult;}, + /*Glitched*/[]{return GlitchGVTentAsChild.Value();}}), + Entrance(GV_STORMS_GROTTO, {[]{return IsAdult && CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsAdult && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[GV_CARPENTER_TENT] = Area("GV Carpenter Tent", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GV_FORTRESS_SIDE, {[]{return true;}}), + }); + + areaTable[GV_OCTOROK_GROTTO] = Area("GV Octorok Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GV_GROTTO_LEDGE, {[]{return true;}}), + }); + + areaTable[GV_STORMS_GROTTO] = Area("GV Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GV_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}), + LocationAccess(GV_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(GV_FORTRESS_SIDE, {[]{return true;}}), + }); + + areaTable[GERUDO_FORTRESS] = Area("Gerudo Fortress", "Gerudo Fortress", GERUDO_FORTRESS, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&CarpenterRescue, {[]{return CanFinishGerudoFortress;}}), + EventAccess(&GF_GateOpen, {[]{return IsAdult && GerudoToken;}}), + EventAccess(&GtG_GateOpen, {[]{return GtG_GateOpen || (IsAdult && GerudoToken);}}), + }, { + //Locations + LocationAccess(GF_CHEST, {[]{return CanUse(HOVER_BOOTS) || (IsAdult && CanUse(SCARECROW)) || CanUse(LONGSHOT);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE))) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen);}}), + LocationAccess(GF_HBA_1000_POINTS, {[]{return GerudoToken && CanRideEpona && Bow && AtDay;}}), + LocationAccess(GF_HBA_1500_POINTS, {[]{return GerudoToken && CanRideEpona && Bow && AtDay;}}), + LocationAccess(GF_NORTH_F1_CARPENTER, {[]{return IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + LocationAccess(GF_NORTH_F2_CARPENTER, {[]{return (IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen);}}), + LocationAccess(GF_SOUTH_F1_CARPENTER, {[]{return IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + LocationAccess(GF_SOUTH_F2_CARPENTER, {[]{return IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + LocationAccess(GF_GERUDO_MEMBERSHIP_CARD, {[]{return CanFinishGerudoFortress;}}), + LocationAccess(GF_GS_ARCHERY_RANGE, {[]{return IsAdult && HookshotOrBoomerang && GerudoToken && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsAdult && HookshotOrBoomerang && GlitchGFGuardSneak && AtNight && CanGetNightTimeGS;}}), + LocationAccess(GF_GS_TOP_FLOOR, {[]{return IsAdult && AtNight && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen) && CanGetNightTimeGS;}}), + }, { + //Exits + Entrance(GV_FORTRESS_SIDE, {[]{return true;}}), + Entrance(GF_OUTSIDE_GATE, {[]{return GF_GateOpen;}, + /*Glitched*/[]{return (IsChild && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::ADVANCED)) || ((IsChild || ((CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(BOOMERANG)) && GlitchGFGuardSneak)) && ((CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::NOVICE)) || + CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::INTERMEDIATE)) && (CanUse(STICKS) || (BiggoronSword && IsAdult) || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)));}}), + Entrance(GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return GtG_GateOpen && (IsAdult || ShuffleDungeonEntrances);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE) && (HoverBoots || CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::ADVANCED))) || ((IsChild || ((CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(BOOMERANG)) && GlitchGFGuardSneak)) && ((CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && + CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::INTERMEDIATE)) && (CanUse(STICKS) || (BiggoronSword && IsAdult) || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)));}}), + Entrance(GF_STORMS_GROTTO, {[]{return IsAdult && CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsAdult && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[GF_OUTSIDE_GATE] = Area("GF Outside Gate", "Gerudo Fortress", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GF_GateOpen, {[]{return IsAdult && GerudoToken && (ShuffleGerudoToken || ShuffleOverworldEntrances /*|| ShuffleSpecialIndoorEntrances*/);}}), + }, {}, { + //Exits + Entrance(GERUDO_FORTRESS, {[]{return (IsAdult && (Hookshot || !ShuffleOverworldEntrances)) || GF_GateOpen;}}), + Entrance(WASTELAND_NEAR_FORTRESS, {[]{return true;}}), + }); + + areaTable[GF_STORMS_GROTTO] = Area("GF Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, {}, { + //Exits + Entrance(GERUDO_FORTRESS, {[]{return true;}}), + }); + + areaTable[WASTELAND_NEAR_FORTRESS] = Area("Wasteland Near Fortress", "Haunted Wasteland", HAUNTED_WASTELAND, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GF_OUTSIDE_GATE, {[]{return true;}}), + Entrance(HAUNTED_WASTELAND, {[]{return CanUse(HOVER_BOOTS) || CanUse(LONGSHOT);}, + /*Glitched*/[]{return ((Bombs || HasBombchus) && CanSurviveDamage && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::NOVICE)) || (CanUse(MEGATON_HAMMER) && CanShield && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::INTERMEDIATE)) || + (Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || GlitchItemlessWasteland;}}), + }); + + areaTable[HAUNTED_WASTELAND] = Area("Haunted Wasteland", "Haunted Wasteland", HAUNTED_WASTELAND, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(WASTELAND_CHEST, {[]{return HasFireSource;}, + /*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(WASTELAND_BOMBCHU_SALESMAN, {[]{return AdultsWallet && (IsAdult || Sticks || KokiriSword);}, + /*Glitched*/[]{return AdultsWallet && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), + LocationAccess(WASTELAND_GS, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Exits + Entrance(WASTELAND_NEAR_COLOSSUS, {[]{return LogicLensWasteland || CanUse(LENS_OF_TRUTH);}}), + Entrance(WASTELAND_NEAR_FORTRESS, {[]{return CanUse(HOVER_BOOTS) || CanUse(LONGSHOT);}, + /*Glitched*/[]{return ((Bombs || HasBombchus) && CanSurviveDamage && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::NOVICE)) || (CanUse(MEGATON_HAMMER) && CanShield && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::INTERMEDIATE)) || + (Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED)) || (HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) || GlitchItemlessWasteland;}}), + }); + + areaTable[WASTELAND_NEAR_COLOSSUS] = Area("Wasteland Near Colossus", "Haunted Wasteland", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DESERT_COLOSSUS, {[]{return true;}}), + Entrance(HAUNTED_WASTELAND, {[]{return LogicReverseWasteland || false;}}), + }); + + areaTable[DESERT_COLOSSUS] = Area("Desert Colossus", "Desert Colossus", DESERT_COLOSSUS, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPond, {[]{return FairyPond || CanPlay(SongOfStorms);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms;}}), + EventAccess(&BugRock, {[]{return true;}}), + }, { + //Locations + LocationAccess(COLOSSUS_FREESTANDING_POH, {[]{return IsAdult && CanPlantBean(DESERT_COLOSSUS);}, + /*Glitched*/[]{return (HoverBoots && CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED)) || (((IsChild && (ChildCanAccess(SPIRIT_TEMPLE_OUTDOOR_HANDS) || ChildCanAccess(SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND) || ChildCanAccess(SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND))) || + (IsAdult && (AdultCanAccess(SPIRIT_TEMPLE_OUTDOOR_HANDS) || AdultCanAccess(SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND) || AdultCanAccess(SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND)))) && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::ADVANCED) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE)));}}), + LocationAccess(SHEIK_AT_COLOSSUS, {[]{return true;}}), + LocationAccess(COLOSSUS_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}), + LocationAccess(COLOSSUS_GS_TREE, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + LocationAccess(COLOSSUS_GS_HILL, {[]{return IsAdult && AtNight && (CanPlantBean(DESERT_COLOSSUS) || CanUse(LONGSHOT) || (LogicColossusGS && CanUse(HOOKSHOT))) && CanGetNightTimeGS;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::EXPERT) && CanShield && IsAdult && AtNight && CanGetNightTimeGS;}}), + LocationAccess(COLOSSUS_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(COLOSSUS_GREAT_FAIRY_FOUNTAIN, {[]{return HasExplosives;}}), + Entrance(SPIRIT_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(WASTELAND_NEAR_COLOSSUS, {[]{return true;}}), + Entrance(COLOSSUS_GROTTO, {[]{return CanUse(SILVER_GAUNTLETS);}}), + }); + + areaTable[COLOSSUS_GREAT_FAIRY_FOUNTAIN] = Area("Colossus Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(COLOSSUS_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(DESERT_COLOSSUS, {[]{return true;}}), + }); + + areaTable[COLOSSUS_GROTTO] = Area("Colossus Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(COLOSSUS_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}), + LocationAccess(COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(DESERT_COLOSSUS, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp new file mode 100644 index 000000000..c1ac29d54 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp @@ -0,0 +1,267 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_HyruleField() { + areaTable[HYRULE_FIELD] = Area("Hyrule Field", "Hyrule Field", HYRULE_FIELD, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BigPoeKill, {[]{return CanUse(BOW) && CanRideEpona && HasBottle;}}), + }, { + //Locations + LocationAccess(HF_OCARINA_OF_TIME_ITEM, {[]{return IsChild && HasAllStones;}}), + LocationAccess(SONG_FROM_OCARINA_OF_TIME, {[]{return IsChild && HasAllStones;}}), + }, { + //Exits + Entrance(LW_BRIDGE, {[]{return true;}}), + Entrance(LAKE_HYLIA, {[]{return true;}}), + Entrance(GERUDO_VALLEY, {[]{return true;}}), + Entrance(MARKET_ENTRANCE, {[]{return true;}}), + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + Entrance(ZR_FRONT, {[]{return true;}}), + Entrance(LON_LON_RANCH, {[]{return true;}}), + Entrance(HF_SOUTHEAST_GROTTO, {[]{return Here(HYRULE_FIELD, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(HYRULE_FIELD, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + Entrance(HF_OPEN_GROTTO, {[]{return true;}}), + Entrance(HF_INSIDE_FENCE_GROTTO, {[]{return CanOpenBombGrotto;}, + /*Glitched*/[]{return Sticks && IsChild && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + Entrance(HF_COW_GROTTO, {[]{return (CanUse(MEGATON_HAMMER) || IsChild) && CanOpenBombGrotto;}, + /*Glitched*/[]{return (CanUse(STICKS) && (ShardOfAgony || LogicGrottosWithoutAgony) && (IsChild || (CanOpenBombGrotto && (CanTakeDamageTwice || CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)))) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE));}}), + Entrance(HF_NEAR_MARKET_GROTTO, {[]{return Here(HYRULE_FIELD, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(HYRULE_FIELD, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + Entrance(HF_FAIRY_GROTTO, {[]{return Here(HYRULE_FIELD, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(HYRULE_FIELD, []{return CanUse(STICKS) && ((IsChild && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT)) || (IsAdult && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)));});}}), + Entrance(HF_NEAR_KAK_GROTTO, {[]{return CanOpenBombGrotto;}, + /*Glitched*/[]{return Sticks && IsChild && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + Entrance(HF_TEKTITE_GROTTO, {[]{return CanOpenBombGrotto;}, + /*Glitched*/[]{return Sticks && IsChild && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + }); + + areaTable[HF_SOUTHEAST_GROTTO] = Area("HF Southeast Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(HF_SOUTHEAST_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(HF_SOUTHEAST_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_OPEN_GROTTO] = Area("HF Open Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(HF_OPEN_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(HF_OPEN_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_INSIDE_FENCE_GROTTO] = Area("HF Inside Fence Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(HF_DEKU_SCRUB_GROTTO, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_COW_GROTTO] = Area("HF Cow Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(HF_GS_COW_GROTTO, {[]{return HasFireSource && HookshotOrBoomerang;}, + /*Glitched*/[]{return (CanUse(STICKS) && Bombs && CanSurviveDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) && HookshotOrBoomerang;}}), + LocationAccess(HF_COW_GROTTO_COW, {[]{return HasFireSource && CanPlay(EponasSong);}, + /*Glitched*/[]{return ((CanUse(STICKS) && Bombs && CanSurviveDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || HasFireSource) && + (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && (CanSurviveDamage || (NumBottles >= 2 && Fairy)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)) || Ocarina) && EponasSong;}}), + LocationAccess(HF_COW_GROTTO_GOSSIP_STONE, {[]{return HasFireSource;}, + /*Glitched*/[]{return CanUse(STICKS) && Bombs && CanSurviveDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_NEAR_MARKET_GROTTO] = Area("HF Near Market Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(HF_NEAR_MARKET_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(HF_NEAR_MARKET_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_FAIRY_GROTTO] = Area("HF Fairy Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, {}, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_NEAR_KAK_GROTTO] = Area("HF Near Kak Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(HF_GS_NEAR_KAK_GROTTO, {[]{return HookshotOrBoomerang;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_TEKTITE_GROTTO] = Area("HF Tektite Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(HF_TEKTITE_GROTTO_FREESTANDING_POH, {[]{return ProgressiveScale >= 2 || CanUse(IRON_BOOTS);}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[LAKE_HYLIA] = Area("Lake Hylia", "Lake Hylia", LAKE_HYLIA, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(LAKE_HYLIA) && CanPlay(SongOfStorms));}}), + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || CanUse(STICKS);}}), + EventAccess(&BugShrub, {[]{return BugShrub || (IsChild && CanCutShrubs);}}), + EventAccess(&ChildScarecrow, {[]{return ChildScarecrow || (IsChild && Ocarina);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE))) && IsChild;}}), + EventAccess(&AdultScarecrow, {[]{return AdultScarecrow || (IsAdult && Ocarina);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE))) && IsAdult;}}), + }, { + //Locations + LocationAccess(LH_UNDERWATER_ITEM, {[]{return IsChild && CanDive;}}), + LocationAccess(LH_SUN, {[]{return IsAdult && WaterTempleClear && CanUse(BOW);}}), + LocationAccess(LH_FREESTANDING_POH, {[]{return IsAdult && (CanUse(SCARECROW) || CanPlantBean(LAKE_HYLIA));}, + /*Glitched*/[]{return (IsAdult && CanUse(HOOKSHOT) && ScarecrowSong && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(LH_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}), + LocationAccess(LH_GS_LAB_WALL, {[]{return IsChild && (HookshotOrBoomerang || (LogicLabWallGS && (Sticks || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)))) && AtNight && CanGetNightTimeGS;}}), + LocationAccess(LH_GS_SMALL_ISLAND, {[]{return IsChild && CanChildAttack && AtNight && CanGetNightTimeGS;}}), + LocationAccess(LH_GS_TREE, {[]{return IsAdult && CanUse(LONGSHOT) && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE)) && AtNight && CanGetNightTimeGS;}}), + LocationAccess(LH_LAB_GOSSIP_STONE, {[]{return true;}}), + LocationAccess(LH_GOSSIP_STONE_SOUTHEAST, {[]{return true;}}), + LocationAccess(LH_GOSSIP_STONE_SOUTHWEST, {[]{return true;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + Entrance(ZORAS_DOMAIN, {[]{return IsChild && (CanDive || CanUse(IRON_BOOTS));}, + /*Glitched*/[]{return IsChild && (CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::NaviDive_Stick, GlitchDifficulty::INTERMEDIATE) || + (Bugs && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || (CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || (IsAdult && (HasBoots || ClaimCheck)) || (IsChild && WeirdEgg)))) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED)))));}}), + Entrance(LH_OWL_FLIGHT, {[]{return IsChild;}}), + Entrance(LH_FISHING_ISLAND, {[]{return IsChild || CanUse(SCARECROW) || CanPlantBean(LAKE_HYLIA) || WaterTempleClear;}, + /*Glitched*/[]{return (CanUse(HOOKSHOT) && ScarecrowSong && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + Entrance(LH_LAB, {[]{return true;}}), + Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return CanUse(HOOKSHOT) && (CanUse(IRON_BOOTS) || (IsAdult && CanUse(LONGSHOT) && ProgressiveScale >= 2));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::ADVANCED);}}), + Entrance(LH_GROTTO, {[]{return true;}}), + }); + + areaTable[LH_FISHING_ISLAND] = Area("LH Fishing Island", "Lake Hylia", LAKE_HYLIA, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(LAKE_HYLIA, {[]{return true;}}), + Entrance(LH_FISHING_HOLE, {[]{return true;}}), + }); + + areaTable[LH_OWL_FLIGHT] = Area("LH Owl Flight", "Lake Hylia", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[LH_LAB] = Area("LH Lab", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&EyedropsAccess, {[]{return EyedropsAccess || (IsAdult && (EyeballFrogAccess || (EyeballFrog && DisableTradeRevert)));}}), + }, { + //Locations + LocationAccess(LH_LAB_DIVE, {[]{return ProgressiveScale >= 2 || (LogicLabDiving && CanUse(IRON_BOOTS) && CanUse(HOOKSHOT));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || + (CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || (IsAdult && (HasBoots || ClaimCheck)) || (IsChild && WeirdEgg)))) && CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE));}}), + LocationAccess(LH_TRADE_FROG, {[]{return IsAdult && EyeballFrog;}}), + LocationAccess(LH_GS_LAB_CRATE, {[]{return CanUse(IRON_BOOTS) && CanUse(HOOKSHOT);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && HasBombchus && (HasBottle || (IsAdult && (HasBoots || ClaimCheck)) || (IsChild && WeirdEgg)) && + (CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || + (CanUse(FARORES_WIND) && CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || ProgressiveScale >= 2 || CanUse(IRON_BOOTS))) || + (CanUse(IRON_BOOTS) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE));}}), + }, { + //Exits + Entrance(LAKE_HYLIA, {[]{return true;}}), + }); + + areaTable[LH_FISHING_HOLE] = Area("LH Fishing Hole", "", NONE, DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LH_CHILD_FISHING, {[]{return IsChild;}}), + LocationAccess(LH_ADULT_FISHING, {[]{return IsAdult;}}), + }, { + //Exits + Entrance(LH_FISHING_ISLAND, {[]{return true;}}), + }); + + areaTable[LH_GROTTO] = Area("LH Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LH_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(LH_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(LH_DEKU_SCRUB_GROTTO_CENTER, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(LAKE_HYLIA, {[]{return true;}}), + }); + + areaTable[LON_LON_RANCH] = Area("Lon Lon Ranch", "Lon Lon Ranch", LON_LON_RANCH, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&Epona, {[]{return Epona || (CanPlay(EponasSong) && IsAdult && AtDay);}}), + EventAccess(&LinksCow, {[]{return LinksCow || (CanPlay(EponasSong) && IsAdult && AtDay);}}), + }, { + //Locations + LocationAccess(SONG_FROM_MALON, {[]{return IsChild && ZeldasLetter && Ocarina && AtDay;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && ZeldasLetter && AtDay;}}), + LocationAccess(LLR_GS_TREE, {[]{return IsChild;}}), + LocationAccess(LLR_GS_RAIN_SHED, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}), + LocationAccess(LLR_GS_HOUSE_WINDOW, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + LocationAccess(LLR_GS_BACK_WALL, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && IsChild && AtNight && CanGetNightTimeGS;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + Entrance(LLR_TALONS_HOUSE, {[]{return true;}}), + Entrance(LLR_STABLES, {[]{return true;}}), + Entrance(LLR_TOWER, {[]{return true;}}), + Entrance(LLR_GROTTO, {[]{return IsChild;}}), + }); + + areaTable[LLR_TALONS_HOUSE] = Area("LLR Talons House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LLR_TALONS_CHICKENS, {[]{return IsChild && AtDay && ZeldasLetter;}}), + }, { + //Exits + Entrance(LON_LON_RANCH, {[]{return true;}}), + }); + + areaTable[LLR_STABLES] = Area("LLR Stables", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LLR_STABLES_LEFT_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE))) && EponasSong;}}), + LocationAccess(LLR_STABLES_RIGHT_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE))) && EponasSong;}}), + }, { + //Exits + Entrance(LON_LON_RANCH, {[]{return true;}}), + }); + + areaTable[LLR_TOWER] = Area("LLR Tower", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LLR_FREESTANDING_POH, {[]{return IsChild;}}), + LocationAccess(LLR_TOWER_LEFT_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE))) && EponasSong;}}), + LocationAccess(LLR_TOWER_RIGHT_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE))) && EponasSong;}}), + }, { + //Exits + Entrance(LON_LON_RANCH, {[]{return true;}}), + }); + + areaTable[LLR_GROTTO] = Area("LLR Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LLR_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(LLR_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(LLR_DEKU_SCRUB_GROTTO_CENTER, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(LON_LON_RANCH, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ice_cavern.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ice_cavern.cpp new file mode 100644 index 000000000..0431e5ca3 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ice_cavern.cpp @@ -0,0 +1,86 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_IceCavern() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[ICE_CAVERN_ENTRYWAY] = Area("Ice Cavern Entryway", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(ICE_CAVERN_BEGINNING, {[]{return Dungeon::IceCavern.IsVanilla();}}), + Entrance(ICE_CAVERN_MQ_BEGINNING, {[]{return Dungeon::IceCavern.IsMQ();}}), + Entrance(ZORAS_FOUNTAIN, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::IceCavern.IsVanilla()) { + areaTable[ICE_CAVERN_BEGINNING] = Area("Ice Cavern Beginning", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(ICE_CAVERN_ENTRYWAY, {[]{return true;}}), + Entrance(ICE_CAVERN_MAIN, {[]{return Here(ICE_CAVERN_BEGINNING, []{return IsAdult || HasExplosives || CanUse(DINS_FIRE);});}}), + }); + + areaTable[ICE_CAVERN_MAIN] = Area("Ice Cavern", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BlueFireAccess, {[]{return BlueFireAccess || (IsAdult && HasBottle);}}), + }, { + //Locations + LocationAccess(ICE_CAVERN_MAP_CHEST, {[]{return BlueFire && IsAdult;}}), + LocationAccess(ICE_CAVERN_COMPASS_CHEST, {[]{return BlueFire;}}), + LocationAccess(ICE_CAVERN_IRON_BOOTS_CHEST, {[]{return BlueFire && (IsAdult || Slingshot || Sticks || KokiriSword || CanUse(DINS_FIRE));}}), + LocationAccess(SHEIK_IN_ICE_CAVERN, {[]{return BlueFire && IsAdult;}}), + LocationAccess(ICE_CAVERN_FREESTANDING_POH, {[]{return BlueFire;}}), + LocationAccess(ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, {[]{return HookshotOrBoomerang;}}), + LocationAccess(ICE_CAVERN_GS_HEART_PIECE_ROOM, {[]{return BlueFire && HookshotOrBoomerang;}}), + LocationAccess(ICE_CAVERN_GS_PUSH_BLOCK_ROOM, {[]{return BlueFire && HookshotOrBoomerang;}}), + }, {}); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::IceCavern.IsMQ()) { + areaTable[ICE_CAVERN_MQ_BEGINNING] = Area("Ice Cavern MQ Beginning", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, {}, { + //Exits + Entrance(ICE_CAVERN_ENTRYWAY, {[]{return true;}}), + Entrance(ICE_CAVERN_MQ_MAP_ROOM, {[]{return IsAdult || CanUse(DINS_FIRE) || (HasExplosives && (CanUse(STICKS) || CanUse(SLINGSHOT) || KokiriSword));}}), + Entrance(ICE_CAVERN_MQ_COMPASS_ROOM, {[]{return IsAdult && BlueFire;}}), + Entrance(ICE_CAVERN_MQ_IRON_BOOTS_REGION, {[]{return BlueFire;}}), + }); + + areaTable[ICE_CAVERN_MQ_MAP_ROOM] = Area("Ice Cavern MQ Map Room", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BlueFireAccess, {[]{return BlueFireAccess || HasBottle;}}), + }, { + //Locations + LocationAccess(ICE_CAVERN_MQ_MAP_CHEST, {[]{return BlueFire && (IsAdult || CanUse(STICKS) || KokiriSword || CanUseProjectile);}}), + }, {}); + + areaTable[ICE_CAVERN_MQ_IRON_BOOTS_REGION] = Area("Ice Cavern MQ Iron Boots Region", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ICE_CAVERN_MQ_IRON_BOOTS_CHEST, {[]{return IsAdult;}}), + LocationAccess(SHEIK_IN_ICE_CAVERN, {[]{return IsAdult;}}), + LocationAccess(ICE_CAVERN_MQ_GS_ICE_BLOCK, {[]{return IsAdult || CanUseProjectile;}}), + LocationAccess(ICE_CAVERN_MQ_GS_SCARECROW, {[]{return IsAdult && (CanUse(SCARECROW) || (CanUse(HOVER_BOOTS) && CanUse(LONGSHOT)));}}), + //Tricks: (CanUse(SCARECROW) || (HoverBoots && CanUse(LONGSHOT)) || LogicIceMQScarecrow) && IsAdult + }, {}); + + areaTable[ICE_CAVERN_MQ_COMPASS_ROOM] = Area("Ice Cavern MQ Compass Room", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ICE_CAVERN_MQ_COMPASS_CHEST, {[]{return true;}}), + LocationAccess(ICE_CAVERN_MQ_FREESTANDING_POH, {[]{return HasExplosives;}}), + LocationAccess(ICE_CAVERN_MQ_GS_RED_ICE, {[]{return CanPlay(SongOfTime);}}), + //Trick: CanPlay(SongOfTime) || LogicIceMQRedIceGS + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp new file mode 100644 index 000000000..9d24ab031 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp @@ -0,0 +1,245 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_JabuJabusBelly() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[JABU_JABUS_BELLY_ENTRYWAY] = Area("Jabu Jabus Belly Entryway", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_BEGINNING, {[]{return Dungeon::JabuJabusBelly.IsVanilla();}}), + Entrance(JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return Dungeon::JabuJabusBelly.IsMQ();}}), + Entrance(ZORAS_FOUNTAIN, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::JabuJabusBelly.IsVanilla()) { + areaTable[JABU_JABUS_BELLY_BEGINNING] = Area("Jabu Jabus Belly Beginning", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_ENTRYWAY, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return CanUseProjectile;}, + /*Glitched*/[]{return CanUse(BOOMERANG) || CanUse(BOW) || CanUse(HOOKSHOT) || (CanUse(STICKS) && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT)) || CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[JABU_JABUS_BELLY_LIFT_MIDDLE] = Area("Jabu Jabus Belly Lift Middle", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_BEGINNING, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MAIN_UPPER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LIFT_LOWER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_NEAR_BOSS_ROOM, {[]{return HasAccessTo(JABU_JABUS_BELLY_LIFT_UPPER) || (LogicJabuBossGSAdult && IsAdult && CanUse(HOVER_BOOTS));}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)) && + GlitchJabuSwitch && (Fish || Bugs || CanUse(FARORES_WIND) || (IsAdult && ClaimCheck));}}), + }); + + areaTable[JABU_JABUS_BELLY_MAIN_UPPER] = Area("Jabu Jabus Belly Main Upper", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_BIGOCTO_ROOM, {[]{return Here(JABU_JABUS_BELLY_GREEN_TENTACLE, []{return CanUse(BOOMERANG);});}}), + }); + + areaTable[JABU_JABUS_BELLY_MAIN_LOWER] = Area("Jabu Jabus Belly Main Lower", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_MAIN_UPPER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_SHABOMB_CORRIDOR, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LOWER_SIDE_ROOM, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_SHABOMB_CORRIDOR] = Area("Jabu Jabus Belly Shabomb Corridor", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, {[]{return true;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LIFT_LOWER, {[]{return CanUseProjectile;}, + /*Glitched*/[]{return CanUse(BOOMERANG) || CanUse(BOW) || CanUse(HOOKSHOT) || (CanUse(STICKS) && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT));}}), + }); + + areaTable[JABU_JABUS_BELLY_LOWER_SIDE_ROOM] = Area("Jabu Jabus Belly Lower Side Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return FairyPot || (CanUse(BOOMERANG) || CanUse(HOVER_BOOTS));}, + /*Glitched*/[]{return (Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE);}}), + }, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_LIFT_LOWER] = Area("Jabu Jabus Belly Lift Lower", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_DEKU_SCRUB, {[]{return (IsChild || CanDive || LogicJabuScrubJumpDive || CanUse(IRON_BOOTS)) && CanStunDeku;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_SHABOMB_CORRIDOR, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_FORKED_CORRIDOR] = Area("Jabu Jabus Belly Forked Corridor", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_MAIN_UPPER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_BOOMERANG_ROOM, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MAP_ROOM, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_COMPASS_ROOM, {[]{return Here(JABU_JABUS_BELLY_MAP_ROOM, []{return CanUse(BOOMERANG);});}}), + Entrance(JABU_JABUS_BELLY_BLUE_TENTACLE, {[]{return Here(JABU_JABUS_BELLY_MAP_ROOM, []{return CanUse(BOOMERANG);});}}), + Entrance(JABU_JABUS_BELLY_GREEN_TENTACLE, {[]{return Here(JABU_JABUS_BELLY_BLUE_TENTACLE, []{return CanUse(BOOMERANG);});}}), + }); + + areaTable[JABU_JABUS_BELLY_BOOMERANG_ROOM] = Area("Jabu Jabus Belly Boomerang Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_BOOMERANG_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_MAP_ROOM] = Area("Jabu Jabus Belly Map Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_MAP_CHEST, {[]{return CanUse(BOOMERANG);}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_COMPASS_ROOM] = Area("Jabu Jabus Belly Compass Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_COMPASS_CHEST, {[]{return IsAdult || CanChildAttack;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_BLUE_TENTACLE] = Area("Jabu Jabus Belly Blue Tentacle", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return Here(JABU_JABUS_BELLY_BLUE_TENTACLE, []{return CanUse(BOOMERANG);});}}), + }); + + areaTable[JABU_JABUS_BELLY_GREEN_TENTACLE] = Area("Jabu Jabus Belly Green Tentacle", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return Here(JABU_JABUS_BELLY_GREEN_TENTACLE, []{return CanUse(BOOMERANG);});}}), + }); + + areaTable[JABU_JABUS_BELLY_BIGOCTO_ROOM] = Area("Jabu Jabus Belly Bigocto Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_ABOVE_BIGOCTO, {[]{return Here(JABU_JABUS_BELLY_BIGOCTO_ROOM, []{return (CanUse(BOOMERANG) || Nuts) && (CanUse(KOKIRI_SWORD) || CanUse(STICKS));});}}), + }); + + areaTable[JABU_JABUS_BELLY_ABOVE_BIGOCTO] = Area("Jabu Jabus Belly Above Bigocto", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + EventAccess(&NutPot, {[]{return true;}}), + }, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_LIFT_UPPER, {[]{return CanUse(BOOMERANG);}, + /*Glitched*/[]{return HasBombchus && CanShield && IsAdult && (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT)) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED);}}), + }); + + areaTable[JABU_JABUS_BELLY_LIFT_UPPER] = Area("Jabu Jabus Belly Lift Upper", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LIFT_LOWER, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_NEAR_BOSS_ROOM] = Area("Jabu Jabus Belly Near Boss Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_GS_NEAR_BOSS, {[]{return IsAdult || CanChildAttack;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_BOSS_ROOM, {[]{return CanUse(BOOMERANG);}, + /*Glitched*/[]{return (CanUse(HOVER_BOOTS) && (CanUse(BOW) || CanUse(SLINGSHOT))) || CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE) || + (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || (Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[JABU_JABUS_BELLY_BOSS_ROOM] = Area("Jabu Jabus Belly Boss Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&JabuJabusBellyClear, {[]{return JabuJabusBellyClear || CanUse(BOOMERANG);}}), + }, { + //Locations + LocationAccess(JABU_JABUS_BELLY_BARINADE_HEART, {[]{return JabuJabusBellyClear;}}), + LocationAccess(BARINADE, {[]{return JabuJabusBellyClear;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_NEAR_BOSS_ROOM, {[]{return JabuJabusBellyClear;}}), + Entrance(JABU_JABUS_BELLY_ENTRYWAY, {[]{return JabuJabusBellyClear;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::JabuJabusBelly.IsMQ()) { + areaTable[JABU_JABUS_BELLY_MQ_BEGINNING] = Area("Jabu Jabus Belly MQ Beginning", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(JABU_JABUS_BELLY_MQ_MAP_CHEST, {[]{return CanBlastOrSmash;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, {[]{return IsChild && CanUse(SLINGSHOT);}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_ENTRYWAY, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MQ_MAIN, {[]{return Here(JABU_JABUS_BELLY_MQ_BEGINNING, []{return IsChild && CanUse(SLINGSHOT);});}}), + }); + + areaTable[JABU_JABUS_BELLY_MQ_MAIN] = Area("Jabu Jabus Belly MQ Main", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, {[]{return (IsAdult && (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT))) || ChildCanAccess(JABU_JABUS_BELLY_MQ_BOSS_AREA);}}), + LocationAccess(JABU_JABUS_BELLY_MQ_COMPASS_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, {[]{return CanPlay(SongOfTime);}}), + //Trick: CanPlay(SongOfTime) || (LogicJabuMQSoTGS && IsChild && CanUse(BOOMERANG)) + }, { + //Exits + Entrance(JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MQ_DEPTHS, {[]{return HasExplosives && IsChild && CanUse(BOOMERANG);}}), + }); + + areaTable[JABU_JABUS_BELLY_MQ_DEPTHS] = Area("Jabu Jabus Belly MQ Depths", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, {[]{return Sticks || CanUse(DINS_FIRE);}}), + LocationAccess(JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, {[]{return (LogicLensJabuMQ || CanUse(LENS_OF_TRUTH)) || Here(JABU_JABUS_BELLY_MQ_MAIN, []{return IsAdult && CanUse(HOVER_BOOTS) && CanUse(HOOKSHOT);});}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_MQ_MAIN, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MQ_BOSS_AREA, {[]{return Sticks || (CanUse(DINS_FIRE) && KokiriSword);}}), + }); + + areaTable[JABU_JABUS_BELLY_MQ_BOSS_AREA] = Area("Jabu Jabus Belly MQ Boss Area", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + EventAccess(&JabuJabusBellyClear, {[]{return true;}}), + }, { + //Locations + LocationAccess(JABU_JABUS_BELLY_MQ_COW, {[]{return CanPlay(EponasSong);}}), + LocationAccess(JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_BARINADE_HEART, {[]{return true;}}), + LocationAccess(BARINADE, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, {[]{return true;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_MQ_MAIN, {[]{return true;}}), + }); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp new file mode 100644 index 000000000..87523ef3b --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp @@ -0,0 +1,303 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_Kakariko() { + areaTable[KAKARIKO_VILLAGE] = Area("Kakariko Village", "Kakariko Village", KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&CojiroAccess, {[]{return CojiroAccess || (IsAdult && WakeUpAdultTalon);}}), + EventAccess(&BugRock, {[]{return true;}}), + EventAccess(&KakarikoVillageGateOpen, {[]{return KakarikoVillageGateOpen || (IsChild && (ZeldasLetter || OpenKakariko.Is(OPENKAKARIKO_OPEN)));}}), + }, { + //Locations + LocationAccess(SHEIK_IN_KAKARIKO, {[]{return IsAdult && ForestMedallion && FireMedallion && WaterMedallion;}}), + LocationAccess(KAK_ANJU_AS_CHILD, {[]{return IsChild && AtDay;}}), + LocationAccess(KAK_ANJU_AS_ADULT, {[]{return IsAdult && AtDay;}}), + LocationAccess(KAK_TRADE_POCKET_CUCCO, {[]{return IsAdult && AtDay && PocketEgg && WakeUpAdultTalon;}}), + LocationAccess(KAK_GS_HOUSE_UNDER_CONSTRUCTION, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}), + LocationAccess(KAK_GS_SKULLTULA_HOUSE, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}), + LocationAccess(KAK_GS_GUARDS_HOUSE, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}), + LocationAccess(KAK_GS_TREE, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}), + LocationAccess(KAK_GS_WATCHTOWER, {[]{return IsChild && (Slingshot || HasBombchus || CanUse(BOW) || CanUse(LONGSHOT)) && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsChild && AtNight && CanGetNightTimeGS && (CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE) || (Sticks && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE)));}}), + LocationAccess(KAK_GS_ABOVE_IMPAS_HOUSE, {[]{return IsAdult && CanUse(HOOKSHOT) && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsAdult && AtNight && CanGetNightTimeGS && ((HoverBoots && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE));}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + Entrance(KAK_CARPENTER_BOSS_HOUSE, {[]{return true;}}), + Entrance(KAK_HOUSE_OF_SKULLTULA, {[]{return true;}}), + Entrance(KAK_IMPAS_HOUSE, {[]{return true;}}), + Entrance(KAK_WINDMILL, {[]{return true;}}), + Entrance(KAK_BAZAAR, {[]{return IsAdult && AtDay;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE);}}), + Entrance(KAK_SHOOTING_GALLERY, {[]{return IsAdult && AtDay;}}), + Entrance(BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return DrainWell && (IsChild || ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF));}, + /*Glitched*/[]{return (IsChild && (CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE) || (AtNight && (CanDoGlitch(GlitchType::NaviDive_Stick, GlitchDifficulty::NOVICE) || ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || + (CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || WeirdEgg))) && ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || + (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED)))))))) || (IsAdult && CanUse(LONGSHOT) && AtDay && CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE));}}), + Entrance(KAK_POTION_SHOP_FRONT, {[]{return AtDay || IsChild;}}), + Entrance(KAK_REDEAD_GROTTO, {[]{return CanOpenBombGrotto;}}), + Entrance(KAK_IMPAS_LEDGE, {[]{return (IsChild && AtDay) || CanUse(HOOKSHOT);}, + /*Glitched*/[]{return IsAdult && ((HoverBoots && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(KAK_ROOFTOP, {[]{return CanUse(HOOKSHOT) || (LogicManOnRoof && (IsAdult || AtDay || Slingshot || HasBombchus || CanUse(BOW) || CanUse(LONGSHOT)));}, + /*Glitched*/[]{return LogicManOnRoof && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + Entrance(THE_GRAVEYARD, {[]{return true;}}), + Entrance(KAK_BEHIND_GATE, {[]{return IsAdult || (KakarikoVillageGateOpen);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[KAK_IMPAS_LEDGE] = Area("Kak Impas Ledge", "Kakariko Village", KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAK_IMPAS_HOUSE_BACK, {[]{return true;}}), + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_ROOFTOP] = Area("Kak Rooftop", "Kakariko Village", KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_MAN_ON_ROOF, {[]{return true;}}), + }, { + //Exits + Entrance(KAK_BACKYARD, {[]{return true;}}), + }); + + areaTable[KAK_BACKYARD] = Area("Kak Backyard", "Kakariko Village", KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + Entrance(KAK_OPEN_GROTTO, {[]{return true;}}), + Entrance(KAK_ODD_POTION_BUILDING, {[]{return IsAdult;}}), + Entrance(KAK_POTION_SHOP_BACK, {[]{return IsAdult && AtDay;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[KAK_CARPENTER_BOSS_HOUSE] = Area("Kak Carpenter Boss House", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WakeUpAdultTalon, {[]{return WakeUpAdultTalon || (IsAdult && PocketEgg);}}), + }, {}, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_HOUSE_OF_SKULLTULA] = Area("Kak House of Skulltula", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_10_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 10;}}), + LocationAccess(KAK_20_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 20;}}), + LocationAccess(KAK_30_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 30;}}), + LocationAccess(KAK_40_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 40;}}), + LocationAccess(KAK_50_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 50;}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_IMPAS_HOUSE] = Area("Kak Impas House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAK_IMPAS_HOUSE_NEAR_COW, {[]{return true;}}), + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_IMPAS_HOUSE_BACK] = Area("Kak Impas House Back", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_IMPAS_HOUSE_FREESTANDING_POH, {[]{return true;}}), + }, { + //Exits + Entrance(KAK_IMPAS_LEDGE, {[]{return true;}}), + Entrance(KAK_IMPAS_HOUSE_NEAR_COW, {[]{return true;}}), + }); + + areaTable[KAK_IMPAS_HOUSE_NEAR_COW] = Area("Kak Impas House Near Cow", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_IMPAS_HOUSE_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED))) && EponasSong;}}), + }, {}); + + areaTable[KAK_WINDMILL] = Area("Kak Windmill", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DrainWell, {[]{return DrainWell || (IsChild && CanPlay(SongOfStorms));}, + /*Glitched*/[]{return IsChild && SongOfStorms && (CanDoGlitch(GlitchType::WindmillBombOI, GlitchDifficulty::ADVANCED) || ((Fish || Bugs) && CanShield && ((Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2))) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) && + CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Fish || Bugs) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)));}}), + }, { + //Locations + LocationAccess(KAK_WINDMILL_FREESTANDING_POH, {[]{return CanUse(BOOMERANG) || DampesWindmillAccess || (IsAdult && CanUse(HOOKSHOT) && LogicWindmillPoHHookshot);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(SONG_FROM_WINDMILL, {[]{return IsAdult && Ocarina;}, + /*Glitched*/[]{return IsAdult && (CanDoGlitch(GlitchType::WindmillBombOI, GlitchDifficulty::EXPERT) || ((Fish || Bugs) && CanShield && ((Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2))) || (DampesWindmillAccess || (IsAdult && CanUse(HOOKSHOT) && LogicWindmillPoHHookshot) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE))) && + CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Fish || Bugs) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)));}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_BAZAAR] = Area("Kak Bazaar", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_BAZAAR_ITEM_1, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_2, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_3, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_4, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_5, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_6, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_7, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_SHOOTING_GALLERY] = Area("Kak Shooting Gallery", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_SHOOTING_GALLERY_REWARD, {[]{return IsAdult && Bow;}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_POTION_SHOP_FRONT] = Area("Kak Potion Shop Front", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_POTION_SHOP_ITEM_1, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_2, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_3, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_4, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_5, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_6, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_7, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_8, {[]{return IsAdult;}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + Entrance(KAK_POTION_SHOP_BACK, {[]{return IsAdult;}}), + }); + + areaTable[KAK_POTION_SHOP_BACK] = Area("Kak Potion Shop Back", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAK_BACKYARD, {[]{return IsAdult;}}), + Entrance(KAK_POTION_SHOP_FRONT, {[]{return true;}}), + }); + + areaTable[KAK_ODD_POTION_BUILDING] = Area("Kak Granny's Potion Shop", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&OddPoulticeAccess, {[]{return OddPoulticeAccess || (IsAdult && (OddMushroomAccess || (OddMushroom && DisableTradeRevert)));}}), + }, { + LocationAccess(KAK_TRADE_ODD_MUSHROOM, {[]{return IsAdult && OddMushroom;}}), + }, { + //Exits + Entrance(KAK_BACKYARD, {[]{return true;}}), + }); + + areaTable[KAK_REDEAD_GROTTO] = Area("Kak Redead Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_REDEAD_GROTTO_CHEST, {[]{return IsAdult || (Sticks || KokiriSword || CanUse(DINS_FIRE) || CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD));}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_OPEN_GROTTO] = Area("Kak Open Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(KAK_OPEN_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(KAK_OPEN_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(KAK_BACKYARD, {[]{return true;}}), + }); + + areaTable[THE_GRAVEYARD] = Area("The Graveyard", "The Graveyard", THE_GRAVEYARD, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || (CanUse(STICKS) && AtDay);}}), + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(THE_GRAVEYARD) && CanPlay(SongOfStorms));}}), + EventAccess(&BugRock, {[]{return true;}}), + }, { + //Locations + LocationAccess(GRAVEYARD_FREESTANDING_POH, {[]{return (IsAdult && CanPlantBean(THE_GRAVEYARD)) || CanUse(LONGSHOT) || (LogicGraveyardPoH && CanUse(BOOMERANG));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::NOVICE);}}), + LocationAccess(GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, {[]{return IsChild && AtNight;}}), //TODO: This needs to change + LocationAccess(GRAVEYARD_GS_WALL, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsChild && AtNight && CanGetNightTimeGS && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(GRAVEYARD_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}), + }, { + //Exits + Entrance(GRAVEYARD_SHIELD_GRAVE, {[]{return IsAdult || AtNight;}}), + Entrance(GRAVEYARD_COMPOSERS_GRAVE, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || ((Bugs || Fish) && CanShield && (IsChild || AdultCanAccess(GRAVEYARD_WARP_PAD_REGION) || (IsAdult && (CanPlantBean(THE_GRAVEYARD) || CanUse(LONGSHOT))) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)))) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + Entrance(GRAVEYARD_HEART_PIECE_GRAVE, {[]{return IsAdult || AtNight;}}), + Entrance(GRAVEYARD_DAMPES_GRAVE, {[]{return IsAdult;}}), + Entrance(GRAVEYARD_DAMPES_HOUSE, {[]{return IsAdult || AtDampeTime;}}), //TODO: This needs to be handled + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + Entrance(GRAVEYARD_WARP_PAD_REGION, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[GRAVEYARD_SHIELD_GRAVE] = Area("Graveyard Shield Grave", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GRAVEYARD_SHIELD_GRAVE_CHEST, {[]{return true;}}), + //Free Fairies + }, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + }); + + areaTable[GRAVEYARD_HEART_PIECE_GRAVE] = Area("Graveyard Heart Piece Grave", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GRAVEYARD_HEART_PIECE_GRAVE_CHEST, {[]{return CanPlay(SunsSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || ((Bugs || Fish) && CanShield && (Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2))) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SunsSong;}}), + }, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + }); + + areaTable[GRAVEYARD_COMPOSERS_GRAVE] = Area("Graveyard Composers Grave", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GRAVEYARD_COMPOSERS_GRAVE_CHEST, {[]{return HasFireSource;}, + /*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(SONG_FROM_COMPOSERS_GRAVE, {[]{return IsAdult || (Slingshot || Boomerang || Sticks || HasExplosives || KokiriSword || CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(BOW) || CanUse(HOOKSHOT));}}), + }, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + }); + + areaTable[GRAVEYARD_DAMPES_GRAVE] = Area("Graveyard Dampes Grave", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return true;}}), + EventAccess(&DampesWindmillAccess, {[]{return DampesWindmillAccess || (IsAdult && CanPlay(SongOfTime));}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::WindmillBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsAdult && SongOfTime;}}), + }, { + //Locations + LocationAccess(GRAVEYARD_HOOKSHOT_CHEST, {[]{return true;}}), + LocationAccess(GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, {[]{return IsAdult || LogicChildDampeRacePoH;}}), + }, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + Entrance(KAK_WINDMILL, {[]{return IsAdult && CanPlay(SongOfTime);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::WindmillBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsAdult && SongOfTime;}}), + }); + + areaTable[GRAVEYARD_DAMPES_HOUSE] = Area("Graveyard Dampes House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + }); + + areaTable[GRAVEYARD_WARP_PAD_REGION] = Area("Graveyard Warp Pad Region", "Graveyard", THE_GRAVEYARD, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + }, { + //Locations + LocationAccess(GRAVEYARD_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + Entrance(SHADOW_TEMPLE_ENTRYWAY, {[]{return CanUse(DINS_FIRE) || (LogicShadowFireArrowEntry && IsAdult && CanUse(FIRE_ARROWS));}, + /*Glitched*/[]{return (CanUse(STICKS) && (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE) || CanUse(FIRE_ARROWS))) || (CanTakeDamage && ( + CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE)));}}), + }); + + areaTable[KAK_BEHIND_GATE] = Area("Kak Behind Gate", "Kakariko Village", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return IsAdult || LogicVisibleCollision || KakarikoVillageGateOpen || OpenKakariko.Is(OPENKAKARIKO_OPEN);}}), + Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_lost_woods.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_lost_woods.cpp new file mode 100644 index 000000000..fa68b8012 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_lost_woods.cpp @@ -0,0 +1,275 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_LostWoods() { + areaTable[KOKIRI_FOREST] = Area("Kokiri Forest", "Kokiri Forest", KOKIRI_FOREST, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(KOKIRI_FOREST) && CanPlay(SongOfStorms));}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + EventAccess(&ShowedMidoSwordAndShield, {[]{return ShowedMidoSwordAndShield || (IsChild && KokiriSword && DekuShield);}}), + }, { + //Locations + LocationAccess(KF_KOKIRI_SWORD_CHEST, {[]{return IsChild;}}), + LocationAccess(KF_GS_KNOW_IT_ALL_HOUSE, {[]{return IsChild && CanChildAttack && AtNight && (HasNightStart || CanLeaveForest || CanPlay(SunsSong)) && CanGetNightTimeGS;}}), + LocationAccess(KF_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}), + LocationAccess(KF_GS_HOUSE_OF_TWINS, {[]{return IsAdult && AtNight && HookshotOrBoomerang && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsAdult && AtNight && CanGetNightTimeGS && (CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE));}}), + LocationAccess(KF_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(KF_LINKS_HOUSE, {[]{return true;}}), + Entrance(KF_MIDOS_HOUSE, {[]{return true;}}), + Entrance(KF_SARIAS_HOUSE, {[]{return true;}}), + Entrance(KF_HOUSE_OF_TWINS, {[]{return true;}}), + Entrance(KF_KNOW_IT_ALL_HOUSE, {[]{return true;}}), + Entrance(KF_KOKIRI_SHOP, {[]{return true;}}), + Entrance(KF_OUTSIDE_DEKU_TREE, {[]{return IsAdult || OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(THE_LOST_WOODS, {[]{return true;}}), + Entrance(LW_BRIDGE_FROM_FOREST, {[]{return IsAdult || OpenForest.IsNot(OPENFOREST_CLOSED) || DekuTreeClear;}, + /*Glitched*/[]{return CanLeaveForest && (CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || GlitchWWTEscape);}}), + Entrance(KF_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[KF_OUTSIDE_DEKU_TREE] = Area("KF Outside Deku Tree", "Kokiri Forest", KOKIRI_FOREST, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || ((IsAdult && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF)) || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || ((IsAdult && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF)) || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}}), + EventAccess(&ShowedMidoSwordAndShield, {[]{return ShowedMidoSwordAndShield || (IsChild && KokiriSword && DekuShield);}}), + }, { + //Locations + LocationAccess(KF_DEKU_TREE_GOSSIP_STONE_LEFT, {[]{return true;}}), + LocationAccess(KF_DEKU_TREE_GOSSIP_STONE_RIGHT, {[]{return true;}}), + }, { + //Exits + Entrance(DEKU_TREE_ENTRYWAY, {[]{return IsChild || (ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF) && (OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(KOKIRI_FOREST, {[]{return IsAdult || OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[KF_LINKS_HOUSE] = Area("KF Link's House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KF_LINKS_HOUSE_COW, {[]{return IsAdult && CanPlay(EponasSong) && LinksCow;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (NumBottles >= 2 && Fairy)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT))) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && Bombs && IsAdult && EponasSong && LinksCow;}}), + }, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}) + }); + + areaTable[KF_MIDOS_HOUSE] = Area("KF Mido's House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KF_MIDOS_TOP_LEFT_CHEST, {[]{return true;}}), + LocationAccess(KF_MIDOS_TOP_RIGHT_CHEST, {[]{return true;}}), + LocationAccess(KF_MIDOS_BOTTOM_LEFT_CHEST, {[]{return true;}}), + LocationAccess(KF_MIDOS_BOTTOM_RIGHT_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + }); + + areaTable[KF_SARIAS_HOUSE] = Area("KF Saria's House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + }); + + areaTable[KF_HOUSE_OF_TWINS] = Area("KF House of Twins", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + }); + + areaTable[KF_KNOW_IT_ALL_HOUSE] = Area("KF Know It All House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + }); + + areaTable[KF_KOKIRI_SHOP] = Area("KF Kokiri Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KF_SHOP_ITEM_1, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_2, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_3, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_4, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_5, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_6, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_7, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + }); + + areaTable[KF_STORMS_GROTTO] = Area("KF Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(KF_STORMS_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(KF_STORMS_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}) + }); + + areaTable[LW_FOREST_EXIT] = Area("LW Forest Exit", "Lost Woods", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}) + }); + + areaTable[THE_LOST_WOODS] = Area("Lost Woods", "Lost Woods", THE_LOST_WOODS, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&OddMushroomAccess, {[]{return OddMushroomAccess || (IsAdult && (CojiroAccess || Cojiro));}}), + EventAccess(&PoachersSawAccess, {[]{return PoachersSawAccess || (IsAdult && OddPoulticeAccess);}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || CanPlay(SongOfStorms);}}), + EventAccess(&BugShrub, {[]{return IsChild && CanCutShrubs;}, + /*Glitched*/[]{return IsChild && Sticks && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + }, { + //Locations + LocationAccess(LW_SKULL_KID, {[]{return IsChild && CanPlay(SariasSong);}, + /*Glitched*/[]{return IsChild && (Fish || Bugs) && SariasSong && CanShield && (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) || (HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)));}}), + LocationAccess(LW_TRADE_COJIRO, {[]{return IsAdult && Cojiro;}}), + LocationAccess(LW_TRADE_ODD_POTION, {[]{return IsAdult && OddPoultice && Cojiro;}}), + LocationAccess(LW_OCARINA_MEMORY_GAME, {[]{return IsChild && Ocarina;}, + /*Glitched*/[]{return IsChild && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Fish || Bugs) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)));}}), + LocationAccess(LW_TARGET_IN_WOODS, {[]{return IsChild && CanUse(SLINGSHOT);}}), + LocationAccess(LW_DEKU_SCRUB_NEAR_BRIDGE, {[]{return IsChild && CanStunDeku;}}), + LocationAccess(LW_GS_BEAN_PATCH_NEAR_BRIDGE, {[]{return CanPlantBugs && CanChildAttack;}}), + LocationAccess(LW_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(LW_FOREST_EXIT, {[]{return true;}}), + Entrance(GC_WOODS_WARP, {[]{return true;}}), + Entrance(LW_BRIDGE, {[]{return CanLeaveForest && ((IsAdult && CanPlantBean(THE_LOST_WOODS)) || CanUse(HOVER_BOOTS) || CanUse(LONGSHOT));}, + /*Glitched*/[]{return CanLeaveForest && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && HasBombchus) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(ZORAS_RIVER, {[]{return CanLeaveForest && (CanDive || CanUse(IRON_BOOTS));}, + /*Glitched*/[]{return CanLeaveForest && (CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::NaviDive_Stick, GlitchDifficulty::ADVANCED) || + ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || (CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || (IsAdult && (HasBoots || ClaimCheck)) || (IsChild && WeirdEgg)))) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED)))));}}), + Entrance(LW_BEYOND_MIDO, {[]{return IsChild || CanPlay(SariasSong);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::NOVICE) || + CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || (CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::ADVANCED) && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE) || HoverBoots)) || + ((CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SariasSong);}}), + Entrance(LW_NEAR_SHORTCUTS_GROTTO, {[]{return Here(THE_LOST_WOODS, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(THE_LOST_WOODS, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + }); + + areaTable[LW_BEYOND_MIDO] = Area("LW Beyond Mido", "Lost Woods", THE_LOST_WOODS, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || CanUse(STICKS);}}), + }, { + //Locations + LocationAccess(LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, {[]{return IsChild && CanStunDeku;}}), + LocationAccess(LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, {[]{return IsChild && CanStunDeku;}}), + LocationAccess(LW_GS_ABOVE_THEATER, {[]{return IsAdult && AtNight && (CanPlantBean(LW_BEYOND_MIDO) || (LogicLostWoodsGSBean && CanUse(HOOKSHOT) && (CanUse(LONGSHOT) || CanUse(BOW) || CanUse(SLINGSHOT) || HasBombchus || CanUse(DINS_FIRE)))) && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsAdult && AtNight && CanGetNightTimeGS && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(LW_GS_BEAN_PATCH_NEAR_THEATER, {[]{return CanPlantBugs && (CanChildAttack || (Scrubsanity.Is(SCRUBSANITY_OFF) && DekuShield));}}), + }, { + //Exits + Entrance(LW_FOREST_EXIT, {[]{return true;}}), + Entrance(THE_LOST_WOODS, {[]{return IsChild || CanPlay(SariasSong);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || ((CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || + ((Bugs || Fish) && CanShield && Bombs && (CanSurviveDamage || (NumBottles >= 2 && Fairy)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SariasSong);}}), + Entrance(SFM_ENTRYWAY, {[]{return true;}}), + Entrance(DEKU_THEATER, {[]{return true;}}), + Entrance(LW_SCRUBS_GROTTO, {[]{return Here(LW_BEYOND_MIDO, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(LW_BEYOND_MIDO, []{return IsChild && CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + }); + + areaTable[LW_NEAR_SHORTCUTS_GROTTO] = Area("LW Near Shortcuts Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(LW_NEAR_SHORTCUTS_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(THE_LOST_WOODS, {[]{return true;}}), + }); + + areaTable[DEKU_THEATER] = Area("Deku Theater", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_THEATER_SKULL_MASK, {[]{return IsChild && SkullMask;}}), + LocationAccess(DEKU_THEATER_MASK_OF_TRUTH, {[]{return IsChild && MaskOfTruth;}}), + }, { + //Exits + Entrance(LW_BEYOND_MIDO, {[]{return true;}}), + }); + + areaTable[LW_SCRUBS_GROTTO] = Area("LW Scrubs Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LW_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}), + LocationAccess(LW_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(LW_BEYOND_MIDO, {[]{return true;}}), + }); + + areaTable[SFM_ENTRYWAY] = Area("SFM Entryway", "Sacred Forest Meadow", SACRED_FOREST_MEADOW, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(LW_BEYOND_MIDO, {[]{return true;}}), + Entrance(SACRED_FOREST_MEADOW, {[]{return IsAdult || Slingshot || Sticks || KokiriSword || CanUse(DINS_FIRE) || CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}}), + Entrance(SFM_WOLFOS_GROTTO, {[]{return CanOpenBombGrotto;}}), + }); + + areaTable[SACRED_FOREST_MEADOW] = Area("Sacred Forest Meadow", "Sacred Forest Meadow", SACRED_FOREST_MEADOW, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + }, { + //Locations + LocationAccess(SONG_FROM_SARIA, {[]{return IsChild && ZeldasLetter;}}), + LocationAccess(SHEIK_IN_FOREST, {[]{return IsAdult;}}), + LocationAccess(SFM_GS, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + LocationAccess(SFM_MAZE_GOSSIP_STONE_LOWER, {[]{return true;}}), + LocationAccess(SFM_MAZE_GOSSIP_STONE_UPPER, {[]{return true;}}), + LocationAccess(SFM_SARIA_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(SFM_ENTRYWAY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_ENTRYWAY, {[]{return CanUse(HOOKSHOT);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(SFM_FAIRY_GROTTO, {[]{return true;}}), + Entrance(SFM_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[SFM_FAIRY_GROTTO] = Area("SFM Fairy Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, {}, { + //Exits + Entrance(SACRED_FOREST_MEADOW, {[]{return true;}}), + }); + + areaTable[SFM_WOLFOS_GROTTO] = Area("SFM Wolfos Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SFM_WOLFOS_GROTTO_CHEST, {[]{return IsAdult || Slingshot || Sticks || KokiriSword || CanUse(DINS_FIRE) || CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}}), + }, { + //Exits + Entrance(SFM_ENTRYWAY, {[]{return true;}}), + }); + + areaTable[SFM_STORMS_GROTTO] = Area("SFM Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SFM_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}), + LocationAccess(SFM_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(SACRED_FOREST_MEADOW, {[]{return true;}}), + }); + + areaTable[LW_BRIDGE_FROM_FOREST] = Area("LW Bridge From Forest", "Lost Woods", THE_LOST_WOODS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LW_GIFT_FROM_SARIA, {[]{return true;}}), + }, { + //Exits + Entrance(LW_BRIDGE, {[]{return true;}}), + }); + + areaTable[LW_BRIDGE] = Area("LW Bridge", "Lost Woods", THE_LOST_WOODS, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + Entrance(HYRULE_FIELD, {[]{return true;}}), + Entrance(THE_LOST_WOODS, {[]{return CanUse(LONGSHOT);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::NOVICE);}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp new file mode 100644 index 000000000..e9216f743 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp @@ -0,0 +1,189 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_ShadowTemple() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[SHADOW_TEMPLE_ENTRYWAY] = Area("Shadow Temple Entryway", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(SHADOW_TEMPLE_BEGINNING, {[]{return Dungeon::ShadowTemple.IsVanilla() && (LogicLensShadow || CanUse(LENS_OF_TRUTH)) && (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT));}, + /*Glitched*/[]{return Dungeon::ShadowTemple.IsVanilla() && (LogicLensShadow || CanUse(LENS_OF_TRUTH)) && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(SHADOW_TEMPLE_MQ_BEGINNING, {[]{return Dungeon::ShadowTemple.IsMQ() && (LogicLensShadowMQ || CanUse(LENS_OF_TRUTH)) && (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT));}, + /*Glitched*/[]{return Dungeon::ShadowTemple.IsMQ() && (LogicLensShadowMQ || CanUse(LENS_OF_TRUTH)) && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(GRAVEYARD_WARP_PAD_REGION, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::ShadowTemple.IsVanilla()) { + areaTable[SHADOW_TEMPLE_BEGINNING] = Area("Shadow Temple Beginning", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(SHADOW_TEMPLE_MAP_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_HOVER_BOOTS_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(SHADOW_TEMPLE_FIRST_BEAMOS, {[]{return HoverBoots;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[SHADOW_TEMPLE_FIRST_BEAMOS] = Area("Shadow Temple First Beamos", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), //This fairy pot is only on 3DS + }, { + //Locations + LocationAccess(SHADOW_TEMPLE_COMPASS_CHEST, {[]{return IsAdult || KokiriSword || Sticks;}}), + LocationAccess(SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, {[]{return CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT);}}), + LocationAccess(SHADOW_TEMPLE_GS_NEAR_SHIP, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE) && Longshot;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_HUGE_PIT, {[]{return HasExplosives && IsAdult && SmallKeys(SHADOW_TEMPLE, 1, 2);}}), + Entrance(SHADOW_TEMPLE_BEYOND_BOAT, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE) && Longshot && CanPlay(ZeldasLullaby);}}), + }); + + areaTable[SHADOW_TEMPLE_HUGE_PIT] = Area("Shadow Temple Huge Pit", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, {[]{return LogicShadowUmbrella || GoronBracelet;}}), + LocationAccess(SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, {[]{return LogicShadowUmbrella || GoronBracelet;}}), + LocationAccess(SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, {[]{return SmallKeys(SHADOW_TEMPLE, 2, 3) && (LogicLensShadowBack || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(SHADOW_TEMPLE_FREESTANDING_KEY, {[]{return SmallKeys(SHADOW_TEMPLE, 2, 3) && (LogicLensShadowBack || CanUse(LENS_OF_TRUTH)) && Hookshot && (Bombs || GoronBracelet || (LogicShadowFreestandingKey && HasBombchus));}}), + LocationAccess(SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, {[]{return Hookshot;}}), + LocationAccess(SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, {[]{return SmallKeys(SHADOW_TEMPLE, 2, 3) && (LogicLensShadowBack || CanUse(LENS_OF_TRUTH)) && Hookshot;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_WIND_TUNNEL, {[]{return (LogicLensShadowBack || CanUse(LENS_OF_TRUTH)) && Hookshot && SmallKeys(SHADOW_TEMPLE, 3, 4);}}), + }); + + areaTable[SHADOW_TEMPLE_WIND_TUNNEL] = Area("Shadow Temple Wind Tunnel", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_WIND_HINT_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_GS_NEAR_SHIP, {[]{return CanUse(LONGSHOT) && SmallKeys(SHADOW_TEMPLE, 4, 5);}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_BEYOND_BOAT, {[]{return CanPlay(ZeldasLullaby) && SmallKeys(SHADOW_TEMPLE, 4, 5);}}), + }); + + areaTable[SHADOW_TEMPLE_BEYOND_BOAT] = Area("Shadow Temple Beyond Boat", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ShadowTempleClear, {[]{return ShadowTempleClear || (SmallKeys(SHADOW_TEMPLE, 5) && BossKeyShadowTemple && (Bow || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus)));}}), + }, { + //Locations + LocationAccess(SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, {[]{return CanUse(DINS_FIRE);}}), + LocationAccess(SHADOW_TEMPLE_BOSS_KEY_CHEST, {[]{return CanUse(DINS_FIRE);}}), + LocationAccess(SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_BONGO_BONGO_HEART, {[]{return SmallKeys(SHADOW_TEMPLE, 5) && BossKeyShadowTemple && (Bow || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus));}}), + LocationAccess(BONGO_BONGO, {[]{return SmallKeys(SHADOW_TEMPLE, 5) && BossKeyShadowTemple && (Bow || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus));}}), + LocationAccess(SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, {[]{return true;}}), + }, {}); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::ShadowTemple.IsMQ()) { + areaTable[SHADOW_TEMPLE_MQ_BEGINNING] = Area("Shadow Temple MQ Beginning", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(SHADOW_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(SHADOW_TEMPLE_MQ_FIRST_BEAMOS, {[]{return IsAdult && (CanUse(FIRE_ARROWS) || CanUse(HOVER_BOOTS));}}), + //Trick: IsAdult && (CanUse(FIRE_ARROWS) || HoverBoots || (LogicShadowMQGap && CanUse(LONGSHOT))) + Entrance(SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, {[]{return HasExplosives && SmallKeys(SHADOW_TEMPLE, 6);}}), + }); + + areaTable[SHADOW_TEMPLE_MQ_DEAD_HAND_AREA] = Area("Shadow Temple MQ Dead Hand Area", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_COMPASS_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, {[]{return CanPlay(SongOfTime) && IsAdult && CanUse(BOW);}}), + }, {}); + + areaTable[SHADOW_TEMPLE_MQ_FIRST_BEAMOS] = Area("Shadow Temple MQ First Beamos", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_MAP_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, {[]{return HasExplosives && SmallKeys(SHADOW_TEMPLE, 2);}}), + }); + + areaTable[SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT] = Area("Shadow Temple MQ Upper Huge Pit", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, {[]{return CanPlay(SongOfTime);}}), + //Trick: CanPlay(SongOfTime) || (LogicShadowMQInvisibleBlades && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO)) + LocationAccess(SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, {[]{return CanPlay(SongOfTime);}}), + //Trick: CanPlay(SongOfTime) || (LogicShadowMQInvisibleBlades && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO)) + }, { + //Exits + Entrance(SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, {[]{return HasFireSource;}}), + //Trick: HasFireSource || LogicShadowMQHugePit + }); + + areaTable[SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT] = Area("Shadow Temple MQ Lower Huge Pit", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, {[]{return IsAdult && CanUse(LONGSHOT);}}), + LocationAccess(SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, {[]{return (LogicShadowUmbrella && HoverBoots) || GoronBracelet;}}), + LocationAccess(SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, {[]{return (LogicShadowUmbrella && HoverBoots) || GoronBracelet;}}), + LocationAccess(SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, {[]{return HoverBoots && SmallKeys(SHADOW_TEMPLE, 3) && (LogicLensShadowMQBack || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, {[]{return HoverBoots && SmallKeys(SHADOW_TEMPLE, 3) && Hookshot && (LogicLensShadowMQBack || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, {[]{return Hookshot;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_MQ_WIND_TUNNEL, {[]{return HoverBoots && (LogicLensShadowMQBack || CanUse(LENS_OF_TRUTH)) && Hookshot && SmallKeys(SHADOW_TEMPLE, 4);}}), + }); + + areaTable[SHADOW_TEMPLE_MQ_WIND_TUNNEL] = Area("Shadow Temple MQ Wind Tunnel", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_GS_AFTER_WIND, {[]{return true;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_MQ_BEYOND_BOAT, {[]{return CanPlay(ZeldasLullaby) && SmallKeys(SHADOW_TEMPLE, 5);}}), + }); + + areaTable[SHADOW_TEMPLE_MQ_BEYOND_BOAT] = Area("Shadow Temple MQ Beyond Boat", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ShadowTempleClear, {[]{return ShadowTempleClear || ((Bow || (LogicShadowStatue && HasBombchus)) && BossKeyShadowTemple);}}), + }, { + //Locations + LocationAccess(SHADOW_TEMPLE_BONGO_BONGO_HEART, {[]{return (Bow || (LogicShadowStatue && HasBombchus)) && BossKeyShadowTemple;}}), + LocationAccess(BONGO_BONGO, {[]{return (Bow || (LogicShadowStatue && HasBombchus)) && BossKeyShadowTemple;}}), + LocationAccess(SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, {[]{return Bow || (LogicShadowStatue && HasBombchus);}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, {[]{return Bow && CanPlay(SongOfTime) && IsAdult && CanUse(LONGSHOT);}}), + }); + + areaTable[SHADOW_TEMPLE_MQ_INVISIBLE_MAZE] = Area("Shadow Temple MQ Invisible Maze", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, {[]{return CanUse(DINS_FIRE) && SmallKeys(SHADOW_TEMPLE, 6);}}), + LocationAccess(SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return CanUse(DINS_FIRE) && SmallKeys(SHADOW_TEMPLE, 6);}}), + LocationAccess(SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_FREESTANDING_KEY, {[]{return true;}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp new file mode 100644 index 000000000..4bfd7c269 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp @@ -0,0 +1,232 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_SpiritTemple() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[SPIRIT_TEMPLE_ENTRYWAY] = Area("Spirit Temple Entryway", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(SPIRIT_TEMPLE_LOBBY, {[]{return Dungeon::SpiritTemple.IsVanilla();}}), + Entrance(SPIRIT_TEMPLE_MQ_LOBBY, {[]{return Dungeon::SpiritTemple.IsMQ();}}), + Entrance(DESERT_COLOSSUS, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::SpiritTemple.IsVanilla()) { + areaTable[SPIRIT_TEMPLE_LOBBY] = Area("Spirit Temple Lobby", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(SPIRIT_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(SPIRIT_TEMPLE_CHILD, {[]{return IsChild;}}), + Entrance(SPIRIT_TEMPLE_EARLY_ADULT, {[]{return CanUse(SILVER_GAUNTLETS);}}), + }); + + areaTable[SPIRIT_TEMPLE_CHILD] = Area("Child Spirit Temple", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutCrate, {[]{return true;}}), + }, { + //Locations + LocationAccess(SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, {[]{return (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot)));}}), + LocationAccess(SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, {[]{return (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot))) && (Sticks || CanUse(DINS_FIRE));}}), + LocationAccess(SPIRIT_TEMPLE_GS_METAL_FENCE, {[]{return (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot)));}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_CHILD_CLIMB, {[]{return SmallKeys(SPIRIT_TEMPLE, 1);}}), + }); + + areaTable[SPIRIT_TEMPLE_CHILD_CLIMB] = Area("Child Spirit Temple Climb", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, {[]{return HasProjectile(HasProjectileAge::Both) || ((SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && CanUse(SILVER_GAUNTLETS) && HasProjectile(HasProjectileAge::Adult)) || (SmallKeys(SPIRIT_TEMPLE, 5) && IsChild && HasProjectile(HasProjectileAge::Child));}}), + LocationAccess(SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, {[]{return HasProjectile(HasProjectileAge::Both) || ((SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && CanUse(SILVER_GAUNTLETS) && HasProjectile(HasProjectileAge::Adult)) || (SmallKeys(SPIRIT_TEMPLE, 5) && IsChild && HasProjectile(HasProjectileAge::Child));}}), + LocationAccess(SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, {[]{return HasProjectile(HasProjectileAge::Both) || CanUse(DINS_FIRE) || + (CanTakeDamage && (Sticks || KokiriSword || HasProjectile(HasProjectileAge::Child))) || + (IsChild && SmallKeys(SPIRIT_TEMPLE, 5) && HasProjectile(HasProjectileAge::Child)) || + ((SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && CanUse(SILVER_GAUNTLETS) && (HasProjectile(HasProjectileAge::Adult) || CanTakeDamage));}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_CENTRAL_CHAMBER, {[]{return HasExplosives;}}), + }); + + areaTable[SPIRIT_TEMPLE_EARLY_ADULT] = Area("Early Adult Spirit Temple", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_COMPASS_CHEST, {[]{return CanUse(HOOKSHOT) && CanPlay(ZeldasLullaby);}}), + LocationAccess(SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, {[]{return Bow || Hookshot || HasBombchus || (Bombs && LogicSpiritLowerAdultSwitch);}}), + LocationAccess(SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 3);}}), + LocationAccess(SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 3);}}), + LocationAccess(SPIRIT_TEMPLE_GS_BOULDER_ROOM, {[]{return CanPlay(SongOfTime) && (Bow || Hookshot || HasBombchus || (Bombs && LogicSpiritLowerAdultSwitch));}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_CENTRAL_CHAMBER, {[]{return SmallKeys(SPIRIT_TEMPLE, 1);}}), + }); + + areaTable[SPIRIT_TEMPLE_CENTRAL_CHAMBER] = Area("Spirit Temple Central Chamber", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MAP_CHEST, {[]{return ((HasExplosives || SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && + + (CanUse(DINS_FIRE) || + (((MagicMeter && FireArrows) || LogicSpiritMapChest) && Bow && Sticks))) || + (SmallKeys(SPIRIT_TEMPLE, 5) && HasExplosives && + CanUse(STICKS)) || + (SmallKeys(SPIRIT_TEMPLE, 3) && + (CanUse(FIRE_ARROWS) || (LogicSpiritMapChest && Bow)) && + CanUse(SILVER_GAUNTLETS));}}), + LocationAccess(SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, {[]{return ((HasExplosives || SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && + (CanUse(DINS_FIRE) || + (((MagicMeter && FireArrows) || LogicSpiritSunChest) && Bow && Sticks))) || + (SmallKeys(SPIRIT_TEMPLE, 5) && HasExplosives && + CanUse(STICKS)) || + (SmallKeys(SPIRIT_TEMPLE, 3) && + (CanUse(FIRE_ARROWS) || (LogicSpiritSunChest && Bow)) && + CanUse(SILVER_GAUNTLETS));}}), + LocationAccess(SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 3) && CanUse(SILVER_GAUNTLETS) && CanPlay(ZeldasLullaby);}}), + LocationAccess(SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 3) && CanUse(SILVER_GAUNTLETS) && CanPlay(ZeldasLullaby) && (Hookshot || HoverBoots);}}), + LocationAccess(SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, {[]{return (HasExplosives && Boomerang && Hookshot) || + (CanUse(BOOMERANG) && SmallKeys(SPIRIT_TEMPLE, 5) && HasExplosives) || + (Hookshot && CanUse(SILVER_GAUNTLETS) && + (SmallKeys(SPIRIT_TEMPLE, 3) || + (SmallKeys(SPIRIT_TEMPLE, 2) && Boomerang && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))));}}), + LocationAccess(SPIRIT_TEMPLE_GS_LOBBY, {[]{return ((HasExplosives || SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && + LogicSpiritLobbyGS && Boomerang && (Hookshot || HoverBoots)) || + (LogicSpiritLobbyGS && SmallKeys(SPIRIT_TEMPLE, 5) && HasExplosives && CanUse(BOOMERANG)) || + (SmallKeys(SPIRIT_TEMPLE, 3) && CanUse(SILVER_GAUNTLETS) && (Hookshot || HoverBoots));}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_OUTDOOR_HANDS, {[]{return true;}}), + Entrance(SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, {[]{return SmallKeys(SPIRIT_TEMPLE, 4) && CanUse(SILVER_GAUNTLETS);}}), + Entrance(SPIRIT_TEMPLE_CHILD_CLIMB, {[]{return true;}}), + }); + + areaTable[SPIRIT_TEMPLE_OUTDOOR_HANDS] = Area("Spirit Temple Outdoor Hands", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, {[]{return (SmallKeys(SPIRIT_TEMPLE, 3) && Longshot && HasExplosives) || SmallKeys(SPIRIT_TEMPLE, 5);}}), + LocationAccess(SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 4) && CanUse(SILVER_GAUNTLETS) && HasExplosives;}}), + }, { + //Exits + Entrance(DESERT_COLOSSUS, {[]{return (IsChild && SmallKeys(SPIRIT_TEMPLE, 5)) || (CanUse(SILVER_GAUNTLETS) && ((SmallKeys(SPIRIT_TEMPLE, 3) && HasExplosives) || SmallKeys(SPIRIT_TEMPLE, 5)));}}), + }); + + areaTable[SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR] = Area("Spirit Temple Beyond Central Locked Door", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, {[]{return MirrorShield && HasExplosives;}}), + LocationAccess(SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, {[]{return (LogicLensSpirit || CanUse(LENS_OF_TRUTH)) && HasExplosives;}}), + LocationAccess(SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, {[]{return (LogicLensSpirit || CanUse(LENS_OF_TRUTH)) && HasExplosives;}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, {[]{return SmallKeys(SPIRIT_TEMPLE, 5) && (LogicSpiritWall || CanUse(LONGSHOT) || HasBombchus || ((Bombs || Nuts || CanUse(DINS_FIRE)) && (Bow || CanUse(HOOKSHOT) || Hammer)));}}), + }); + + areaTable[SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR] = Area("Spirit Temple Beyond Final Locked Door", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&SpiritTempleClear, {[]{return SpiritTempleClear || (MirrorShield && HasExplosives && Hookshot && BossKeySpiritTemple);}}), + }, { + //Locations + LocationAccess(SPIRIT_TEMPLE_BOSS_KEY_CHEST, {[]{return CanPlay(ZeldasLullaby) && ((CanTakeDamage && LogicFlamingChests) || (Bow && Hookshot));}}), + LocationAccess(SPIRIT_TEMPLE_TOPMOST_CHEST, {[]{return MirrorShield;}}), + LocationAccess(SPIRIT_TEMPLE_TWINROVA_HEART, {[]{return MirrorShield && HasExplosives && Hookshot && BossKeySpiritTemple;}}), + LocationAccess(TWINROVA, {[]{return MirrorShield && HasExplosives && Hookshot && BossKeySpiritTemple;}}), + }, {}); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::SpiritTemple.IsMQ()) { + areaTable[SPIRIT_TEMPLE_MQ_LOBBY] = Area("Spirit Temple MQ Lobby", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, {[]{return true;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, {[]{return Here(SPIRIT_TEMPLE_MQ_LOBBY, []{return CanBlastOrSmash;}) && ((IsChild && CanUse(SLINGSHOT)) || (IsAdult && CanUse(BOW)));}}), + LocationAccess(SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, {[]{return HasBombchus || (IsAdult && (CanUse(BOW) || CanUse(HOOKSHOT))) || (IsChild && (CanUse(SLINGSHOT) || CanUse(BOOMERANG)));}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(SPIRIT_TEMPLE_MQ_CHILD, {[]{return IsChild;}}), + Entrance(SPIRIT_TEMPLE_MQ_ADULT, {[]{return HasBombchus && IsAdult && CanUse(LONGSHOT) && CanUse(SILVER_GAUNTLETS);}}), + }); + + areaTable[SPIRIT_TEMPLE_MQ_CHILD] = Area("Spirit Temple MQ Child", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return FairyPot || (KokiriSword && HasBombchus && Slingshot);}}), + }, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, {[]{return Here(SPIRIT_TEMPLE_MQ_ADULT, []{return SmallKeys(SPIRIT_TEMPLE, 7) && Hammer;});}}), + LocationAccess(SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, {[]{return KokiriSword && HasBombchus && Slingshot && CanUse(DINS_FIRE);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_MAP_CHEST, {[]{return KokiriSword || Bombs;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, {[]{return HasBombchus && SmallKeys(SPIRIT_TEMPLE, 7) && Slingshot && (CanUse(DINS_FIRE) || (Here(SPIRIT_TEMPLE_MQ_ADULT, []{return IsAdult && CanUse(FIRE_ARROWS);})));}}), + //Trick: HasBombchus && SmallKeys(SPIRIT_TEMPLE, 7) && Slingshot && (CanUse(DINS_FIRE) || (SPIRIT_TEMPLE_MQ_ADULT.Adult() && IsAdult && (CanUse(FIRE_ARROWS) || (LogicSpiritMQFrozenEye && CanUse(BOW) && CanPlay(SongOfTime))))) + }, { + //Exits + Entrance(SPIRIT_TEMPLE_MQ_SHARED, {[]{return HasBombchus && SmallKeys(SPIRIT_TEMPLE, 2);}}), + }); + + areaTable[SPIRIT_TEMPLE_MQ_ADULT] = Area("Spirit Temple MQ Adult", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 7);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, {[]{return CanPlay(ZeldasLullaby);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, {[]{return (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 5);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime) && MirrorShield;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 7);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, {[]{return SmallKeys(SPIRIT_TEMPLE, 7);}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_MQ_LOWER_ADULT, {[]{return MirrorShield && IsAdult && CanUse(FIRE_ARROWS);}}), + //Trick: MirrorShield && IsAdult && (CanUse(FIRE_ARROWS) || (LogicSpiritMQLowerAdult && CanUse(DINS_FIRE) && Bow)) + Entrance(SPIRIT_TEMPLE_MQ_SHARED, {[]{return true;}}), + Entrance(SPIRIT_TEMPLE_MQ_BOSS_AREA, {[]{return SmallKeys(SPIRIT_TEMPLE, 6) && CanPlay(ZeldasLullaby) && Hammer;}}), + Entrance(SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, {[]{return SmallKeys(SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH));}}), + }); + + areaTable[SPIRIT_TEMPLE_MQ_SHARED] = Area("Spirit Temple MQ Shared", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 6);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_COMPASS_CHEST, {[]{return (IsChild && CanUse(SLINGSHOT) && SmallKeys(SPIRIT_TEMPLE, 7)) || (IsAdult && CanUse(BOW)) || (Bow && Slingshot);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, {[]{return CanPlay(SongOfTime) || IsAdult;}}), + //Trick: CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult + LocationAccess(SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, {[]{return IsAdult;}}), + //Trick: (LogicSpiritMQSunBlockGS && Boomerange && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT)) || IsAdult + }, { + //Exits + Entrance(SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, {[]{return (SmallKeys(SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || IsAdult)) || (SmallKeys(SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH)));}}), + //Trick: (SmallKeys(SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult)) || (SmallKeys(SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH))) + Entrance(DESERT_COLOSSUS, {[]{return (SmallKeys(SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || IsAdult)) || (SmallKeys(SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH)) && IsAdult);}}), + //Trick: (SmallKeys(SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult)) || (SmallKeys(SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH)) && IsAdult) + }); + + areaTable[SPIRIT_TEMPLE_MQ_LOWER_ADULT] = Area("Spirit Temple MQ Lower Adult", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, {[]{return true;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 7) && Hammer && Ocarina && SongOfTime && EponasSong && SunsSong && SongOfStorms && ZeldasLullaby;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, {[]{return Hammer;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, {[]{return true;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, {[]{return SmallKeys(SPIRIT_TEMPLE, 7) && Hammer && Ocarina && SongOfTime && EponasSong && SunsSong && SongOfStorms && ZeldasLullaby;}}), + }, {}); + + areaTable[SPIRIT_TEMPLE_MQ_BOSS_AREA] = Area("Spirit Temple MQ Boss Area", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&SpiritTempleClear, {[]{return SpiritTempleClear || (MirrorShield && BossKeySpiritTemple);}}), + }, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, {[]{return LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(SPIRIT_TEMPLE_TWINROVA_HEART, {[]{return MirrorShield && BossKeySpiritTemple;}}), + LocationAccess(TWINROVA, {[]{return MirrorShield && BossKeySpiritTemple;}}), + }, {}); + + areaTable[SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND] = Area("Spirit Temple MQ Mirror Shield Hand", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, {[]{return true;}}), + }, {}); + + areaTable[SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND] = Area("Spirit Temple MQ Silver Gauntlets Hand", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, {[]{return true;}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp new file mode 100644 index 000000000..d2f566b2c --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp @@ -0,0 +1,351 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_WaterTemple() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[WATER_TEMPLE_ENTRYWAY] = Area("Water Temple Entryway", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return Dungeon::WaterTemple.IsVanilla();}}), + Entrance(WATER_TEMPLE_MQ_LOBBY, {[]{return Dungeon::WaterTemple.IsMQ();}}), + Entrance(LAKE_HYLIA, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::WaterTemple.IsVanilla()) { + //Water Temple logic currently assumes that the locked door leading to the upper water raising location is unlocked from the start + areaTable[WATER_TEMPLE_LOBBY] = Area("Water Temple Lobby", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(WATER_TEMPLE_EAST_LOWER, {[]{return WaterTempleLow || ((LogicFewerTunicRequirements || CanUse(ZORA_TUNIC)) && (CanUse(IRON_BOOTS) || (CanUse(LONGSHOT) && LogicWaterTempleTorchLongshot)));}, + /*Glitched*/[]{return ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || (CanUse(FARORES_WIND) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED))));}}), + Entrance(WATER_TEMPLE_NORTH_LOWER, {[]{return WaterTempleLow || ((LogicFewerTunicRequirements || CanUse(ZORA_TUNIC)) && CanUse(IRON_BOOTS));}}), + Entrance(WATER_TEMPLE_SOUTH_LOWER, {[]{return WaterTempleLow && HasExplosives && (CanDive || CanUse(IRON_BOOTS)) && (LogicFewerTunicRequirements || CanUse(ZORA_TUNIC));}, + /*Glitched*/[]{return CanUse(IRON_BOOTS) && (WaterTempleMiddle || WaterTempleHigh) && (LogicFewerTunicRequirements || CanUse(ZORA_TUNIC)) && AdultCanAccess(WATER_TEMPLE_WEST_LOWER) && CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(WATER_TEMPLE_WEST_LOWER, {[]{return WaterTempleLow && GoronBracelet && (IsChild || CanDive || CanUse(IRON_BOOTS)) && (LogicFewerTunicRequirements || CanUse(ZORA_TUNIC));}}), + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_LOWER, {[]{return WaterTempleLow && SmallKeys(WATER_TEMPLE, 5);}}), + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_UPPER, {[]{return (WaterTempleLow || WaterTempleMiddle) && (HasFireSourceWithTorch || CanUse(BOW));}}), + Entrance(WATER_TEMPLE_EAST_MIDDLE, {[]{return (WaterTempleLow || WaterTempleMiddle || (CanUse(IRON_BOOTS) && WaterTimer >= 16)) && CanUse(HOOKSHOT);}}), + Entrance(WATER_TEMPLE_WEST_MIDDLE, {[]{return WaterTempleMiddle;}, + /*Glitched*/[]{return WaterTempleLow && (CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(WATER_TEMPLE_HIGH_WATER, {[]{return IsAdult && (CanUse(HOVER_BOOTS) || (LogicWaterTempleUpperBoost && Bombs && CanTakeDamage));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(WATER_TEMPLE_BLOCK_CORRIDOR, {[]{return (WaterTempleLow || WaterTempleMiddle) && (CanUse(SLINGSHOT) || CanUse(BOW)) && (CanUse(LONGSHOT) || CanUse(HOVER_BOOTS) || (LogicWaterCentralBow && (IsAdult || WaterTempleMiddle)));}, + /*Glitched*/[]{return (WaterTempleLow || WaterTempleMiddle) && IsAdult && CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(WATER_TEMPLE_FALLING_PLATFORM_ROOM, {[]{return WaterTempleHigh && SmallKeys(WATER_TEMPLE, 4);}, + /*Glitched*/[]{return SmallKeys(WATER_TEMPLE, 4) && (CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE));}}), + Entrance(WATER_TEMPLE_PRE_BOSS_ROOM, {[]{return WaterTempleHigh && CanUse(LONGSHOT);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE) || + (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + }); + + areaTable[WATER_TEMPLE_EAST_LOWER] = Area("Water Temple East Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTempleLow, {[]{return WaterTempleLow || CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return ZeldasLullaby && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && + ((Bombs && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || (HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)))));}}), + }, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return WaterTempleLow || ((LogicFewerTunicRequirements || CanUse(ZORA_TUNIC)) && CanUse(IRON_BOOTS));}, + /*Glitched*/[]{return ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || (CanUse(FARORES_WIND) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED))));}}), + Entrance(WATER_TEMPLE_MAP_ROOM, {[]{return WaterTempleHigh;}}), + Entrance(WATER_TEMPLE_CRACKED_WALL, {[]{return WaterTempleMiddle || (WaterTempleHigh && WaterTempleLow && ((CanUse(HOVER_BOOTS) && LogicWaterCrackedWallHovers) || LogicWaterCrackedWallNothing));}, + /*Glitched*/[]{return WaterTempleHigh && WaterTempleLow && CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + Entrance(WATER_TEMPLE_TORCH_ROOM, {[]{return WaterTempleLow && (HasFireSourceWithTorch || CanUse(BOW));}}), + }); + + areaTable[WATER_TEMPLE_MAP_ROOM] = Area("Water Temple Map Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_MAP_CHEST, {[]{return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_EAST_LOWER, {[]{return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT);}}), + }); + + areaTable[WATER_TEMPLE_CRACKED_WALL] = Area("Water Temple Cracked Wall", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_CRACKED_WALL_CHEST, {[]{return HasExplosives;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_EAST_LOWER, {[]{return true;}}), + }); + + areaTable[WATER_TEMPLE_TORCH_ROOM] = Area("Water Temple Torch Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_TORCHES_CHEST, {[]{return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_EAST_LOWER, {[]{return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT);}}), + }); + + areaTable[WATER_TEMPLE_NORTH_LOWER] = Area("Water Temple North Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(WATER_TEMPLE_BOULDERS_LOWER, {[]{return (CanUse(LONGSHOT) || (LogicWaterBossKeyRegion && CanUse(HOVER_BOOTS))) && SmallKeys(WATER_TEMPLE, 4);}, + /*Glitched*/[]{return ((Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || + CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE)) && SmallKeys(WATER_TEMPLE, 4);}}), + }); + + areaTable[WATER_TEMPLE_BOULDERS_LOWER] = Area("Water Temple Boulders Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, {[]{return CanUse(LONGSHOT) || Here(WATER_TEMPLE_BOULDERS_UPPER, []{return (IsAdult && HookshotOrBoomerang) || (CanUse(IRON_BOOTS) && CanUse(HOOKSHOT));});}}), + }, { + //Exits + Entrance(WATER_TEMPLE_NORTH_LOWER, {[]{return SmallKeys(WATER_TEMPLE, 4);}}), + Entrance(WATER_TEMPLE_BLOCK_ROOM, {[]{return true;}}), + Entrance(WATER_TEMPLE_BOULDERS_UPPER, {[]{return (IsAdult && (CanUse(HOVER_BOOTS) || LogicWaterNorthBasementLedgeJump)) || (CanUse(HOVER_BOOTS) && CanUse(IRON_BOOTS));}}), + }); + + areaTable[WATER_TEMPLE_BLOCK_ROOM] = Area("Water Temple Block Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_BOULDERS_LOWER, {[]{return (GoronBracelet && HasExplosives) || CanUse(HOOKSHOT);}}), + Entrance(WATER_TEMPLE_JETS_ROOM, {[]{return (GoronBracelet && HasExplosives) || (CanUse(HOOKSHOT) && CanUse(HOVER_BOOTS));}, + /*Glitched*/[]{return CanUse(HOOKSHOT) && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[WATER_TEMPLE_JETS_ROOM] = Area("Water Temple Jets Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_BLOCK_ROOM, {[]{return CanUse(HOOKSHOT);}}), + Entrance(WATER_TEMPLE_BOULDERS_UPPER, {[]{return true;}}), + }); + + areaTable[WATER_TEMPLE_BOULDERS_UPPER] = Area("Water Temple Boulders Upper", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_BOULDERS_LOWER, {[]{return true;}}), + Entrance(WATER_TEMPLE_JETS_ROOM, {[]{return IsAdult;}}), + Entrance(WATER_TEMPLE_BOSS_KEY_ROOM, {[]{return (CanUse(IRON_BOOTS) || (IsAdult && LogicWaterBKJumpDive)) && SmallKeys(WATER_TEMPLE, 5);}}), + }); + + areaTable[WATER_TEMPLE_BOSS_KEY_ROOM] = Area("Water Temple Boss Key Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(WATER_TEMPLE_BOSS_KEY_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_BOULDERS_UPPER, {[]{return (CanUse(IRON_BOOTS) || (IsAdult && LogicWaterBKJumpDive) || IsChild || CanDive) && SmallKeys(WATER_TEMPLE, 5);}}), + }); + + areaTable[WATER_TEMPLE_SOUTH_LOWER] = Area("Water Temple South Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_GS_BEHIND_GATE, {[]{return CanUse(HOOKSHOT) || (IsAdult && CanUse(HOVER_BOOTS));}, + /*Glitched*/[]{return (CanUse(BOOMERANG) && CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE)) || + (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + }, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return CanUse(IRON_BOOTS);}}), + }); + + areaTable[WATER_TEMPLE_WEST_LOWER] = Area("Water Temple West Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return CanUse(HOOKSHOT) && CanUse(IRON_BOOTS) && GoronBracelet;}, + /*Glitched*/[]{return CanUse(IRON_BOOTS) && (LogicFewerTunicRequirements || CanUse(ZORA_TUNIC)) && CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(WATER_TEMPLE_DRAGON_ROOM, {[]{return IsAdult || CanChildAttack;}}), + }); + + areaTable[WATER_TEMPLE_DRAGON_ROOM] = Area("Water Temple Dragon Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_DRAGON_CHEST, {[]{return (CanUse(HOOKSHOT) && CanUse(IRON_BOOTS)) || (IsAdult && LogicWaterDragonAdult && HasBombchus && (CanDive || CanUse(IRON_BOOTS))) || + Here(WATER_TEMPLE_RIVER, []{return IsAdult && CanUse(BOW) && ((LogicWaterDragonAdult && (CanDive || CanUse(IRON_BOOTS))) || LogicWaterDragonJumpDive);});}, + /*Glitched*/[]{return Bombs && ((IsAdult && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::ADVANCED)) || (CanUse(IRON_BOOTS) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)));}}), + }, { + //Exits + Entrance(WATER_TEMPLE_WEST_LOWER, {[]{return true;}}), + }); + + areaTable[WATER_TEMPLE_CENTRAL_PILLAR_LOWER] = Area("Water Temple Central Pillar Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return SmallKeys(WATER_TEMPLE, 5);}}), + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_UPPER, {[]{return CanUse(HOOKSHOT);}}), + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT, {[]{return WaterTempleMiddle && CanUse(IRON_BOOTS) && WaterTimer >= 40;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::NOVICE) && CanUse(IRON_BOOTS) && WaterTimer >= 40;}}), + }); + + areaTable[WATER_TEMPLE_CENTRAL_PILLAR_UPPER] = Area("Water Temple Central Pillar Upper", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTempleMiddle, {[]{return WaterTempleMiddle || CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return ZeldasLullaby && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && + (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) || (HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)))));}}), + }, { + //Locations + LocationAccess(WATER_TEMPLE_GS_CENTRAL_PILLAR, {[]{return CanUse(LONGSHOT) || (LogicWaterCentralGSFW && WaterTempleHigh && CanUse(FARORES_WIND) && HookshotOrBoomerang);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_LOWER, {[]{return true;}}), + }); + + areaTable[WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT] = Area("Water Temple Central Pillar Basement", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_CENTRAL_PILLAR_CHEST, {[]{return CanUse(HOOKSHOT) && CanUse(IRON_BOOTS) && WaterTimer >= 40;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_LOWER, {[]{return CanUse(IRON_BOOTS) && WaterTimer >= 16;}}), + }); + + areaTable[WATER_TEMPLE_EAST_MIDDLE] = Area("Water Temple East Middle", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_COMPASS_CHEST, {[]{return CanUseProjectile;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return CanUse(IRON_BOOTS);}}), + }); + + areaTable[WATER_TEMPLE_WEST_MIDDLE] = Area("Water Temple West Middle", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(WATER_TEMPLE_HIGH_WATER, {[]{return CanUseProjectile;}}), + }); + + areaTable[WATER_TEMPLE_HIGH_WATER] = Area("Water Temple High Water", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTempleHigh, {[]{return WaterTempleHigh || CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return ZeldasLullaby && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && + (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) || (HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)))));}}), + }, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), + }); + + areaTable[WATER_TEMPLE_BLOCK_CORRIDOR] = Area("Water Temple Block Corridor", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, {[]{return GoronBracelet && (WaterTempleLow || WaterTempleMiddle);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE) && (WaterTempleLow || WaterTempleMiddle);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return CanUse(HOOKSHOT);}}), + }); + + areaTable[WATER_TEMPLE_FALLING_PLATFORM_ROOM] = Area("Water Temple Falling Platform Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, {[]{return CanUse(LONGSHOT) || (LogicWaterFallingPlatformGS && IsAdult && HookshotOrBoomerang);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return CanUse(HOOKSHOT) && SmallKeys(WATER_TEMPLE, 4);}}), + Entrance(WATER_TEMPLE_DRAGON_PILLARS_ROOM, {[]{return CanUse(HOOKSHOT) && SmallKeys(WATER_TEMPLE, 5);}}), + }); + + areaTable[WATER_TEMPLE_DRAGON_PILLARS_ROOM] = Area("Water Temple Dragon Pillars Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_FALLING_PLATFORM_ROOM, {[]{return CanUseProjectile;}}), + Entrance(WATER_TEMPLE_DARK_LINK_ROOM, {[]{return CanUse(HOOKSHOT);}}), + }); + + areaTable[WATER_TEMPLE_DARK_LINK_ROOM] = Area("Water Temple Dark Link Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_DRAGON_PILLARS_ROOM, {[]{return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}}), + Entrance(WATER_TEMPLE_LONGSHOT_ROOM, {[]{return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}}), + }); + + areaTable[WATER_TEMPLE_LONGSHOT_ROOM] = Area("Water Temple Longshot Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_LONGSHOT_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_DARK_LINK_ROOM, {[]{return true;}}), + Entrance(WATER_TEMPLE_RIVER, {[]{return IsChild || CanPlay(SongOfTime);}, + /*Glitched*/[]{return SongOfTime && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && + (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) || (HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)))));}}), + }); + + areaTable[WATER_TEMPLE_RIVER] = Area("Water Temple River", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_RIVER_CHEST, {[]{return (CanUse(SLINGSHOT) || CanUse(BOW)) && (IsAdult || CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT));}}), + LocationAccess(WATER_TEMPLE_GS_RIVER, {[]{return (CanUse(IRON_BOOTS) && CanUse(HOOKSHOT)) || (LogicWaterRiverGS && CanUse(LONGSHOT));}}), + }, { + //Exits + Entrance(WATER_TEMPLE_DRAGON_ROOM, {[]{return (CanUse(SLINGSHOT) || CanUse(BOW)) && (IsAdult || CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT));}}), + }); + + areaTable[WATER_TEMPLE_PRE_BOSS_ROOM] = Area("Water Temple Pre Boss Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(WATER_TEMPLE_BOSS_ROOM, {[]{return BossKeyWaterTemple;}}), + }); + + areaTable[WATER_TEMPLE_BOSS_ROOM] = Area("Water Temple Boss Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTempleClear, {[]{return WaterTempleClear || (CanUse(HOOKSHOT) && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)));}}), + }, { + //Locations + LocationAccess(WATER_TEMPLE_MORPHA_HEART, {[]{return WaterTempleClear;}}), + LocationAccess(MORPHA, {[]{return WaterTempleClear;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return WaterTempleClear;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::WaterTemple.IsMQ()) { + areaTable[WATER_TEMPLE_MQ_LOBBY] = Area("Water Temple MQ Lobby", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTempleClear, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}), + }, { + //Locations + LocationAccess(WATER_TEMPLE_MORPHA_HEART, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}), + LocationAccess(MORPHA, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(WATER_TEMPLE_MQ_DIVE, {[]{return IsAdult && WaterTimer >= 24 && CanUse(IRON_BOOTS);}}), + Entrance(WATER_TEMPLE_MQ_DARK_LINK_REGION, {[]{return SmallKeys(WATER_TEMPLE, 1) && IsAdult && CanUse(LONGSHOT);}}), + }); + + areaTable[WATER_TEMPLE_MQ_DIVE] = Area("Water Temple MQ Dive", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_MQ_MAP_CHEST, {[]{return HasFireSource && IsAdult && CanUse(HOOKSHOT);}}), + LocationAccess(WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, {[]{return IsAdult && CanUse(ZORA_TUNIC) && CanUse(HOOKSHOT) && (CanUse(DINS_FIRE) && CanPlay(SongOfTime));}}), + //Trick: IsAdult && CanUse(ZORA_TUNIC) && CanUse(HOOKSHOT) && ((LogicWaterMQCentralPillar && CanUse(FIRE_ARROWS)) || (CanUse(DINS_FIRE) && CanPlay(SongOfTime))) + }, { + //Exits + Entrance(WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS, {[]{return CanPlay(ZeldasLullaby);}}), + }); + + areaTable[WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS] = Area("Water Temple MQ Lowered Water Levels", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_MQ_COMPASS_CHEST, {[]{return (IsAdult && CanUse(BOW)) || CanUse(DINS_FIRE) || Here(WATER_TEMPLE_MQ_LOBBY, []{return IsChild && CanUse(STICKS) && HasExplosives;});}}), + LocationAccess(WATER_TEMPLE_MQ_LONGSHOT_CHEST, {[]{return IsAdult && CanUse(HOOKSHOT);}}), + LocationAccess(WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, {[]{return CanUse(DINS_FIRE);}}), + LocationAccess(WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, {[]{return IsAdult && CanUse(LONGSHOT);}}), + }, {}); + + areaTable[WATER_TEMPLE_MQ_DARK_LINK_REGION] = Area("Water Temple MQ Dark Link Region", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(WATER_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return IsAdult && WaterTimer >= 24 && CanUse(DINS_FIRE) && (LogicWaterDragonJumpDive || CanDive || CanUse(IRON_BOOTS));}}), + LocationAccess(WATER_TEMPLE_MQ_GS_RIVER, {[]{return true;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS, {[]{return IsAdult && WaterTimer >= 24 && CanUse(DINS_FIRE) && CanUse(IRON_BOOTS);}}), + }); + + areaTable[WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS] = Area("Water Temple MQ Basement Gated Areas", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_MQ_FREESTANDING_KEY, {[]{return HoverBoots || CanUse(SCARECROW) || LogicWaterNorthBasementLedgeJump;}}), + LocationAccess(WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, {[]{return CanUse(FIRE_ARROWS) && (HoverBoots || CanUse(SCARECROW));}}), + LocationAccess(WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, {[]{return SmallKeys(WATER_TEMPLE, 2) && (HoverBoots || CanUse(SCARECROW) || LogicWaterNorthBasementLedgeJump);}}), + //Trick: LogicWaterMQLockedGS || (SmallKeys(WATER_TEMPLE, 2) && (HoverBoots || CanUse(SCARECROW) || LogicWaterNorthBasementLedgeJump)) + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp new file mode 100644 index 000000000..bff5d7563 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp @@ -0,0 +1,188 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_ZorasDomain() { + areaTable[ZR_FRONT] = Area("ZR Front", "Zora River", ZORAS_RIVER, DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ZR_GS_TREE, {[]{return IsChild && CanChildAttack;}}), + }, { + //Exits + Entrance(ZORAS_RIVER, {[]{return IsAdult || CanBlastOrSmash;}, + /*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[ZORAS_RIVER] = Area("Zora River", "Zora River", ZORAS_RIVER, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(ZORAS_RIVER) && CanPlay(SongOfStorms));}}), + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || CanUse(STICKS);}}), + EventAccess(&BugShrub, {[]{return BugShrub || CanCutShrubs;}}), + }, { + //Locations + LocationAccess(ZR_MAGIC_BEAN_SALESMAN, {[]{return IsChild;}}), + LocationAccess(ZR_FROGS_OCARINA_GAME, {[]{return IsChild && CanPlay(ZeldasLullaby) && CanPlay(SariasSong) && CanPlay(SunsSong) && CanPlay(EponasSong) && CanPlay(SongOfTime) && CanPlay(SongOfStorms);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && ZeldasLullaby && SariasSong && SunsSong && EponasSong && SongOfTime && SongOfStorms;}}), + LocationAccess(ZR_FROGS_IN_THE_RAIN, {[]{return IsChild && CanPlay(SongOfStorms);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SongOfStorms;}}), + LocationAccess(ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, {[]{return IsChild || CanUse(HOVER_BOOTS) || (IsAdult && LogicZoraRiverLower);}}), + LocationAccess(ZR_NEAR_DOMAIN_FREESTANDING_POH, {[]{return IsChild || CanUse(HOVER_BOOTS) || (IsAdult && LogicZoraRiverUpper);}}), + LocationAccess(ZR_GS_LADDER, {[]{return IsChild && AtNight && CanChildAttack && CanGetNightTimeGS;}}), + LocationAccess(ZR_GS_NEAR_RAISED_GROTTOS, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + LocationAccess(ZR_GS_ABOVE_BRIDGE, {[]{return IsAdult && CanUse(HOOKSHOT) && AtNight && CanGetNightTimeGS;}}), + LocationAccess(ZR_NEAR_GROTTOS_GOSSIP_STONE, {[]{return true;}}), + LocationAccess(ZR_NEAR_DOMAIN_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(ZR_FRONT, {[]{return true;}}), + Entrance(ZR_OPEN_GROTTO, {[]{return true;}}), + Entrance(ZR_FAIRY_GROTTO, {[]{return Here(ZORAS_RIVER, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(ZORAS_RIVER, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + Entrance(THE_LOST_WOODS, {[]{return CanDive || CanUse(IRON_BOOTS);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || (CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || (IsAdult && (HasBoots || ClaimCheck)) || (IsChild && WeirdEgg)))) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED))));}}), + Entrance(ZR_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + Entrance(ZR_BEHIND_WATERFALL, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED) || ((CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby);}}), + }); + + areaTable[ZR_BEHIND_WATERFALL] = Area("ZR Behind Waterfall", "Zora River", NONE, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(ZORAS_RIVER, {[]{return true;}}), + Entrance(ZORAS_DOMAIN, {[]{return true;}}), + }); + + areaTable[ZR_OPEN_GROTTO] = Area("ZR Open Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(ZR_OPEN_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(ZR_OPEN_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(ZORAS_RIVER, {[]{return true;}}), + }); + + areaTable[ZR_FAIRY_GROTTO] = Area("ZR Fairy Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Event + EventAccess(&FreeFairies, {[]{return true;}}), + }, {}, { + //Exits + Entrance(ZORAS_RIVER, {[]{return true;}}), + }); + + areaTable[ZR_STORMS_GROTTO] = Area("ZR Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ZR_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}), + LocationAccess(ZR_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(ZORAS_RIVER, {[]{return true;}}), + }); + + areaTable[ZORAS_DOMAIN] = Area("Zoras Domain", "Zoras Domain", ZORAS_DOMAIN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&EyeballFrogAccess, {[]{return EyeballFrogAccess || (IsAdult && KingZoraThawed && (Eyedrops || EyeballFrog || Prescription || PrescriptionAccess));}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + EventAccess(&NutPot, {[]{return true;}}), + EventAccess(&StickPot, {[]{return StickPot || IsChild;}}), + EventAccess(&FishGroup, {[]{return FishGroup || IsChild;}}), + EventAccess(&KingZoraThawed, {[]{return KingZoraThawed || (IsAdult && BlueFire);}}), + EventAccess(&DeliverLetter, {[]{return DeliverLetter || (RutosLetter && IsChild && ZorasFountain.IsNot(ZORASFOUNTAIN_OPEN));}}), + }, { + //Locations + LocationAccess(ZD_DIVING_MINIGAME, {[]{return IsChild;}}), + LocationAccess(ZD_CHEST, {[]{return IsChild && CanUse(STICKS);}}), + LocationAccess(ZD_KING_ZORA_THAWED, {[]{return KingZoraThawed;}}), + LocationAccess(ZD_TRADE_PRESCRIPTION, {[]{return KingZoraThawed && Prescription;}}), + LocationAccess(ZD_GS_FROZEN_WATERFALL, {[]{return IsAdult && AtNight && (HookshotOrBoomerang || CanUse(SLINGSHOT) || Bow || MagicMeter) && CanGetNightTimeGS;}}), + LocationAccess(ZD_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(ZR_BEHIND_WATERFALL, {[]{return true;}}), + Entrance(LAKE_HYLIA, {[]{return IsChild && (CanDive || CanUse(IRON_BOOTS));}, + /*Glitched*/[]{return (IsAdult && GlitchZDOoBJumpSlash) || (IsChild && CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || WeirdEgg))) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED))));}}), + Entrance(ZD_BEHIND_KING_ZORA, {[]{return DeliverLetter || ZorasFountain.Is(ZORASFOUNTAIN_OPEN) || (ZorasFountain.Is(ZORASFOUNTAIN_ADULT) && IsAdult);}, + /*Glitched*/[]{return ((IsChild || CanUse(IRON_BOOTS)) && CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::NOVICE) || + CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(ZD_SHOP, {[]{return IsChild || BlueFire;}, + /*Glitched*/[]{return GlitchZDOoBJumpSlash.Value();}}), + Entrance(ZD_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[ZD_BEHIND_KING_ZORA] = Area("ZD Behind King Zora", "Zoras Domain", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(ZORAS_DOMAIN, {[]{return DeliverLetter || ZorasFountain.Is(ZORASFOUNTAIN_OPEN) || (ZorasFountain.Is(ZORASFOUNTAIN_ADULT) && IsAdult);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::NOVICE) || (CanUse(LONGSHOT) && CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE)) || (Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(ZORAS_FOUNTAIN, {[]{return true;}}), + }); + + areaTable[ZD_SHOP] = Area("ZD Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ZD_SHOP_ITEM_1, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_2, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_3, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_4, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_5, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_6, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_7, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(ZORAS_DOMAIN, {[]{return true;}}), + }); + + areaTable[ZD_STORMS_GROTTO] = Area("ZD Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, {}, { + //Exits + Entrance(ZORAS_DOMAIN, {[]{return true;}}), + }); + + areaTable[ZORAS_FOUNTAIN] = Area("Zoras Fountain", "Zoras Fountain", ZORAS_FOUNTAIN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || (CanUse(STICKS) && AtDay);}}), + }, { + //Locations + LocationAccess(ZF_ICEBERG_FREESTANDING_POH, {[]{return IsAdult;}}), + LocationAccess(ZF_BOTTOM_FREESTANDING_POH, {[]{return IsAdult && IronBoots && WaterTimer >= 24;}}), + LocationAccess(ZF_GS_TREE, {[]{return IsChild;}}), + LocationAccess(ZF_GS_ABOVE_THE_LOG, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsChild && AtNight && CanGetNightTimeGS && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + LocationAccess(ZF_GS_HIDDEN_CAVE, {[]{return CanUse(SILVER_GAUNTLETS) && CanBlastOrSmash && HookshotOrBoomerang && IsAdult && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::INTERMEDIATE) && IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + LocationAccess(ZF_FAIRY_GOSSIP_STONE, {[]{return true;}}), + LocationAccess(ZF_JABU_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(ZD_BEHIND_KING_ZORA, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_ENTRYWAY, {[]{return (IsChild && Fish);}, + /*Glitched*/[]{return (IsChild && CanUse(STICKS) && GlitchJabuStickRecoil) || (IsAdult && GlitchJabuAdult);}}), + Entrance(ICE_CAVERN_ENTRYWAY, {[]{return IsAdult;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(ZF_GREAT_FAIRY_FOUNTAIN, {[]{return HasExplosives || (CanUse(SILVER_GAUNTLETS) && Hammer && LogicZFGreatFairy);}, + /*Glitched*/[]{return IsChild && (KokiriSword || Sticks) && CanShield && (CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::ADVANCED) || (CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::INTERMEDIATE)));}}), + }); + + areaTable[ZF_GREAT_FAIRY_FOUNTAIN] = Area("ZF Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ZF_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(ZORAS_FOUNTAIN, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/logic.cpp b/soh/soh/Enhancements/randomizer/3drando/logic.cpp new file mode 100644 index 000000000..f85e4ed2a --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/logic.cpp @@ -0,0 +1,1218 @@ +#include "logic.hpp" + +#include +#include +#include +#include +#include + +#include "settings.hpp" +#include "dungeon.hpp" +#include "setting_descriptions.hpp" + +using namespace Settings; + +namespace Logic { + + bool noVariable = false; + + //Child item logic + bool KokiriSword = false; + bool ZeldasLetter = false; + bool WeirdEgg = false; + bool HasBottle = false; + bool Bombchus = false; + bool Bombchus5 = false; + bool Bombchus10 = false; + bool Bombchus20 = false; + bool MagicBean = false; + bool MagicBeanPack = false; + bool RutosLetter = false; + bool Boomerang = false; + bool DinsFire = false; + bool FaroresWind = false; + bool NayrusLove = false; + bool LensOfTruth = false; + bool ShardOfAgony = false; + bool SkullMask = false; + bool MaskOfTruth = false; + + //Adult logic + bool Hammer = false; + bool IronBoots = false; + bool HoverBoots = false; + bool MirrorShield = false; + bool GoronTunic = false; + bool ZoraTunic = false; + bool Epona = false; + bool BigPoe = false; + bool GerudoToken = false; + bool FireArrows = false; + bool IceArrows = false; + bool LightArrows = false; + bool MasterSword = false; + bool BiggoronSword = false; + + //Trade Quest + bool PocketEgg = false; + bool Cojiro = false; + bool OddMushroom = false; + bool OddPoultice = false; + bool PoachersSaw = false; + bool BrokenSword = false; + bool Prescription = false; + bool EyeballFrog = false; + bool Eyedrops = false; + bool ClaimCheck = false; + + //Trade Quest Events + bool WakeUpAdultTalon = false; + bool CojiroAccess = false; + bool OddMushroomAccess = false; + bool OddPoulticeAccess = false; + bool PoachersSawAccess = false; + bool BrokenSwordAccess = false; + bool PrescriptionAccess = false; + bool EyeballFrogAccess = false; + bool EyedropsAccess = false; + bool DisableTradeRevert = false; + + //Songs + bool ZeldasLullaby = false; + bool SariasSong = false; + bool SunsSong = false; + bool SongOfStorms = false; + bool EponasSong = false; + bool SongOfTime = false; + bool MinuetOfForest = false; + bool BoleroOfFire = false; + bool SerenadeOfWater = false; + bool RequiemOfSpirit = false; + bool NocturneOfShadow = false; + bool PreludeOfLight = false; + + //Stones and Meddallions + bool ForestMedallion = false; + bool FireMedallion = false; + bool WaterMedallion = false; + bool SpiritMedallion = false; + bool ShadowMedallion = false; + bool LightMedallion = false; + bool KokiriEmerald = false; + bool GoronRuby = false; + bool ZoraSapphire = false; + + //Dungeon Clears + bool DekuTreeClear = false; + bool DodongosCavernClear = false; + bool JabuJabusBellyClear = false; + bool ForestTempleClear = false; + bool FireTempleClear = false; + bool WaterTempleClear = false; + bool SpiritTempleClear = false; + bool ShadowTempleClear = false; + + //Trial Clears + bool ForestTrialClear = false; + bool FireTrialClear = false; + bool WaterTrialClear = false; + bool SpiritTrialClear = false; + bool ShadowTrialClear = false; + bool LightTrialClear = false; + + //Progressive Items + uint8_t ProgressiveBulletBag = 0; + uint8_t ProgressiveBombBag = 0; + uint8_t ProgressiveMagic = 0; + uint8_t ProgressiveScale = 0; + uint8_t ProgressiveHookshot = 0; + uint8_t ProgressiveBow = 0; + uint8_t ProgressiveWallet = 0; + uint8_t ProgressiveStrength = 0; + uint8_t ProgressiveOcarina = 0; + uint8_t ProgressiveGiantKnife = 0; + + //Logical keysanity + bool IsKeysanity = false; + + //Keys + uint8_t ForestTempleKeys = 0; + uint8_t FireTempleKeys = 0; + uint8_t WaterTempleKeys = 0; + uint8_t SpiritTempleKeys = 0; + uint8_t ShadowTempleKeys = 0; + uint8_t GanonsCastleKeys = 0; + uint8_t GerudoFortressKeys = 0; + uint8_t GerudoTrainingGroundsKeys = 0; + uint8_t BottomOfTheWellKeys = 0; + uint8_t TreasureGameKeys = 0; + + //Boss Keys + bool BossKeyForestTemple = false; + bool BossKeyFireTemple = false; + bool BossKeyWaterTemple = false; + bool BossKeySpiritTemple = false; + bool BossKeyShadowTemple = false; + bool BossKeyGanonsCastle = false; + + //Gold Skulltula Count + uint8_t GoldSkulltulaTokens = 0; + + //Bottle Count + uint8_t Bottles = 0; + uint8_t NumBottles = 0; + bool NoBottles = false; + + //Drops and Bottle Contents Access + bool DekuNutDrop = false; + bool NutPot = false; + bool NutCrate = false; + bool DekuBabaNuts = false; + bool DekuStickDrop = false; + bool StickPot = false; + bool DekuBabaSticks = false; + bool BugsAccess = false; + bool BugShrub = false; + bool WanderingBugs = false; + bool BugRock = false; + bool BlueFireAccess = false; + bool FishAccess = false; + bool FishGroup = false; + bool LoneFish = false; + bool FairyAccess = false; + bool GossipStoneFairy = false; + bool BeanPlantFairy = false; + bool ButterflyFairy = false; + bool FairyPot = false; + bool FreeFairies = false; + bool FairyPond = false; + bool BombchuDrop = false; + bool AmmoCanDrop = false; + + bool BuyBombchus5 = false; + bool BuyBombchus10 = false; + bool BuyBombchus20 = false; + bool BuySeed = false; + bool BuyArrow = false; + bool BuyBomb = false; + bool BuyGPotion = false; + bool BuyBPotion = false; + bool MagicRefill = false; + + uint8_t PieceOfHeart = 0; + uint8_t HeartContainer = 0; + bool DoubleDefense = false; + + /* --- HELPERS, EVENTS, AND LOCATION ACCESS --- */ + /* These are used to simplify reading the logic, but need to be updated + / every time a base value is updated. */ + + bool Slingshot = false; + bool Ocarina = false; + bool OcarinaOfTime = false; + bool BombBag = false; + bool MagicMeter = false; + bool Hookshot = false; + bool Longshot = false; + bool Bow = false; + bool GoronBracelet = false; + bool SilverGauntlets = false; + bool GoldenGauntlets = false; + bool SilverScale = false; + bool GoldScale = false; + bool AdultsWallet = false; + + bool ChildScarecrow = false; + bool AdultScarecrow = false; + bool ScarecrowSong = false; + bool Scarecrow = false; + bool DistantScarecrow = false; + + bool Bombs = false; + bool DekuShield = false; + bool HylianShield = false; + bool Nuts = false; + bool Sticks = false; + bool Bugs = false; + bool BlueFire = false; + bool Fish = false; + bool Fairy = false; + bool BottleWithBigPoe = false; + + bool FoundBombchus = false; + bool CanPlayBowling = false; + bool HasBombchus = false; + bool HasExplosives = false; + bool HasBoots = false; + bool IsChild = false; + bool IsAdult = false; + bool IsGlitched = false; + bool CanBlastOrSmash = false; + bool CanChildAttack = false; + bool CanChildDamage = false; + bool CanCutShrubs = false; + bool CanDive = false; + bool CanLeaveForest = false; + bool CanPlantBugs = false; + bool CanRideEpona = false; + bool CanStunDeku = false; + bool CanSummonGossipFairy = false; + bool CanSummonGossipFairyWithoutSuns = false; + bool NeedNayrusLove = false; + bool CanSurviveDamage = false; + bool CanTakeDamage = false; + bool CanTakeDamageTwice = false; + //bool CanPlantBean = false; + bool CanOpenBombGrotto = false; + bool CanOpenStormGrotto = false; + bool BigPoeKill = false; + bool HookshotOrBoomerang = false; + bool CanGetNightTimeGS = false; + + uint8_t BaseHearts = 0; + uint8_t Hearts = 0; + uint8_t Multiplier = 0; + uint8_t EffectiveHealth = 0; + uint8_t FireTimer = 0; + uint8_t WaterTimer = 0; + + bool GuaranteeTradePath = false; + bool GuaranteeHint = false; + bool HasFireSource = false; + bool HasFireSourceWithTorch = false; + + bool CanFinishGerudoFortress = false; + + bool HasShield = false; + bool CanShield = false; + bool CanJumpslash = false; + bool CanUseProjectile = false; + bool CanUseMagicArrow = false; + + //Bridge and LACS Requirements + uint8_t MedallionCount = 0; + uint8_t StoneCount = 0; + uint8_t DungeonCount = 0; + bool HasAllStones = false; + bool HasAllMedallions = false; + bool CanBuildRainbowBridge = false; + bool CanTriggerLACS = false; + + //Other + bool AtDay = false; + bool AtNight = false; + uint8_t Age = 0; + + //Events + bool ShowedMidoSwordAndShield = false; + bool CarpenterRescue = false; + bool GF_GateOpen = false; + bool GtG_GateOpen = false; + bool DampesWindmillAccess = false; + bool DrainWell = false; + bool GoronCityChildFire = false; + bool GCWoodsWarpOpen = false; + bool GCDaruniasDoorOpenChild = false; + bool StopGCRollingGoronAsAdult = false; + bool WaterTempleLow = false; + bool WaterTempleMiddle = false; + bool WaterTempleHigh = false; + bool KakarikoVillageGateOpen = false; + bool KingZoraThawed = false; + bool ForestTempleJoelle = false; + bool ForestTempleBeth = false; + bool ForestTempleJoAndBeth = false; + bool ForestTempleAmy = false; + bool ForestTempleMeg = false; + bool ForestTempleAmyAndMeg = false; + bool FireLoopSwitch = false; + bool LinksCow = false; + bool AtDampeTime = false; + bool DeliverLetter = false; + bool TimeTravel = false; + + /* --- END OF HELPERS AND LOCATION ACCESS --- */ + + //Placement Tracking + uint8_t AddedProgressiveBulletBags = 0; + uint8_t AddedProgressiveBombBags = 0; + uint8_t AddedProgressiveMagics = 0; + uint8_t AddedProgressiveScales = 0; + uint8_t AddedProgressiveHookshots = 0; + uint8_t AddedProgressiveBows = 0; + uint8_t AddedProgressiveWallets = 0; + uint8_t AddedProgressiveStrengths = 0; + uint8_t AddedProgressiveOcarinas = 0; + uint8_t TokensInPool = 0; + + //Event checking past + bool DrainWellPast = false; + bool DampesWindmillAccessPast = false; + bool DekuTreeClearPast = false; + bool GoronRubyPast = false; + bool ZoraSapphirePast = false; + bool ForestTrialClearPast = false; + bool FireTrialClearPast = false; + bool WaterTrialClearPast = false; + bool SpiritTrialClearPast = false; + bool ShadowTrialClearPast = false; + bool LightTrialClearPast = false; + bool BuyDekuShieldPast = false; + bool TimeTravelPast = false; + + bool CanPlay(bool song) { + return Ocarina && song; + } + + static bool IsMagicItem(uint32_t item) { + return item == DINS_FIRE || + item == FARORES_WIND || + item == NAYRUS_LOVE || + item == LENS_OF_TRUTH; + } + + static bool IsMagicArrow(uint32_t item) { + return item == FIRE_ARROWS || + item == ICE_ARROWS || + item == LIGHT_ARROWS; + } + + bool HasItem(uint32_t itemName) { + return (itemName == DINS_FIRE && DinsFire) || + (itemName == FARORES_WIND && FaroresWind) || + (itemName == NAYRUS_LOVE && NayrusLove) || + (itemName == LENS_OF_TRUTH && LensOfTruth) || + (itemName == BOW && Bow) || + (itemName == MEGATON_HAMMER && Hammer) || + (itemName == IRON_BOOTS && IronBoots) || + (itemName == HOVER_BOOTS && HoverBoots) || + (itemName == HOOKSHOT && Hookshot) || + (itemName == LONGSHOT && Longshot) || + (itemName == SILVER_GAUNTLETS && SilverGauntlets) || + (itemName == GOLDEN_GAUNTLETS && GoldenGauntlets) || + (itemName == GORON_TUNIC && GoronTunic) || + (itemName == ZORA_TUNIC && ZoraTunic) || + (itemName == SCARECROW && Scarecrow) || + (itemName == DISTANT_SCARECROW && DistantScarecrow)|| + (itemName == HYLIAN_SHIELD && HylianShield) || + (itemName == MIRROR_SHIELD && MirrorShield) || + (itemName == MASTER_SWORD && MasterSword) || + (itemName == BIGGORON_SWORD && BiggoronSword) || + (itemName == SLINGSHOT && Slingshot) || + (itemName == BOOMERANG && Boomerang) || + (itemName == KOKIRI_SWORD && KokiriSword) || + (itemName == STICKS && Sticks) || + (itemName == DEKU_SHIELD && DekuShield) || + (itemName == FIRE_ARROWS && FireArrows) || + (itemName == ICE_ARROWS && IceArrows) || + (itemName == LIGHT_ARROWS && LightArrows); + + } + + //Can the passed in item be used? + bool CanUse(uint32_t itemName) { + if (!HasItem(itemName)) + return false; + + switch (itemName) { + // Adult items + case BOW: return IsAdult || BowAsChild; + case MEGATON_HAMMER: return IsAdult || HammerAsChild; + case IRON_BOOTS: return IsAdult || IronBootsAsChild; + case HOVER_BOOTS: return IsAdult || HoverBootsAsChild; + case HOOKSHOT: return IsAdult || HookshotAsChild; + case LONGSHOT: return IsAdult || HookshotAsChild; + case SILVER_GAUNTLETS: return IsAdult; + case GOLDEN_GAUNTLETS: return IsAdult; + case GORON_TUNIC: return IsAdult || GoronTunicAsChild; + case ZORA_TUNIC: return IsAdult || ZoraTunicAsChild; + case SCARECROW: return IsAdult || HookshotAsChild; + case DISTANT_SCARECROW: return IsAdult || HookshotAsChild; + case HYLIAN_SHIELD: return IsAdult; + case MIRROR_SHIELD: return IsAdult || MirrorShieldAsChild; + case MASTER_SWORD: return IsAdult || MasterSwordAsChild; + case BIGGORON_SWORD: return IsAdult || BiggoronSwordAsChild; + + // Child items + case SLINGSHOT: return IsChild || SlingshotAsAdult; + case BOOMERANG: return IsChild || BoomerangAsAdult; + case KOKIRI_SWORD: return IsChild || KokiriSwordAsAdult; + case STICKS: return IsChild || StickAsAdult; + case DEKU_SHIELD: return IsChild || DekuShieldAsAdult; + + // Magic items + default: return MagicMeter && (IsMagicItem(itemName) || (IsMagicArrow(itemName) && CanUse(BOW))); + } + } + + bool HasProjectile(HasProjectileAge age) { + return HasExplosives || + (age == HasProjectileAge::Child && (Slingshot || Boomerang)) || + (age == HasProjectileAge::Adult && (Hookshot || Bow )) || + (age == HasProjectileAge::Both && (Slingshot || Boomerang) && (Hookshot || Bow)) || + (age == HasProjectileAge::Either && (Slingshot || Boomerang || Hookshot || Bow)); + } + + uint8_t GetDifficultyValueFromString(Option& glitchOption) { + for (size_t i = 0; i < GlitchDifficulties.size(); i++) { + if (glitchOption.GetSelectedOptionText() == GlitchDifficulties[i]) { + return i + 1; + } + } + return 0; + } + + bool CanDoGlitch(GlitchType glitch, GlitchDifficulty difficulty) { + uint8_t setDifficulty; + switch (glitch) { + //Restricted Items + case GlitchType::RestrictedItems: + setDifficulty = GetDifficultyValueFromString(GlitchRestrictedItems); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return true; + + //Super Stab + case GlitchType::SuperStab: + setDifficulty = GetDifficultyValueFromString(GlitchSuperStab); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return CanShield && CanUse(STICKS); + + //Infinite Sword Glitch + case GlitchType::ISG: + setDifficulty = GetDifficultyValueFromString(GlitchISG); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return CanShield && (IsAdult || KokiriSword || Sticks); + + //Bomb Hover + case GlitchType::BombHover: + setDifficulty = GetDifficultyValueFromString(GlitchHover); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && (HasBombchus || (Bombs && setDifficulty >= static_cast(GlitchDifficulty::ADVANCED))); + + //Bomb Ocarina Items + case GlitchType::BombOI: + setDifficulty = GetDifficultyValueFromString(GlitchBombOI); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return Bombs && CanSurviveDamage; + case GlitchType::OutdoorBombOI: + return ((CanUse(FARORES_WIND) && (DinsFire || NayrusLove || LensOfTruth || HasBottle || HasBombchus || Nuts || StartingConsumables || + (IsChild && (Sticks || ProgressiveBulletBag || (MagicBean || MagicBeanPack) || Boomerang || WeirdEgg || (Hammer && HammerAsChild))) || + (IsAdult && (ProgressiveBow || Hookshot || HasBoots || Hammer || (Sticks && StickAsAdult) || (Boomerang && BoomerangAsAdult)))) && + CanDoGlitch(GlitchType::BombOI, (static_cast(difficulty) >= 3) ? difficulty : GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)) || + (((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || + (CanUse(FARORES_WIND) && FaroresWindAnywhere)) && CanDoGlitch(GlitchType::BombOI, difficulty))); + case GlitchType::WindmillBombOI: + return (((CanUse(FARORES_WIND) || (!NeedNayrusLove && (NayrusLove || DinsFire))) && (LensOfTruth || HasBottle || HasBombchus || Nuts || StartingConsumables || + (IsChild && (Sticks || ProgressiveBulletBag || (MagicBean || MagicBeanPack) || Boomerang || WeirdEgg || (Hammer && HammerAsChild))) || + (IsAdult && (ProgressiveBow || Hookshot || HasBoots || Hammer || (Sticks && StickAsAdult) || (Boomerang && BoomerangAsAdult)))) && + CanDoGlitch(GlitchType::BombOI, (static_cast(difficulty) >= 3) ? difficulty : GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)) || + (((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (CanUse(FARORES_WIND) && FaroresWindAnywhere)) && CanDoGlitch(GlitchType::BombOI, difficulty))); + case GlitchType::IndoorBombOI: + return (((IsAdult && ClaimCheck) && (HasBottle || HasBoots || (CanUse(FARORES_WIND) && FaroresWindAnywhere))) || + ((Bugs || Fish || Fairy) && (NumBottles >= 2 || (IsAdult && (ClaimCheck || HasBoots)) || (IsChild && WeirdEgg) || (CanUse(FARORES_WIND) && FaroresWindAnywhere))) || + ((CanUse(FARORES_WIND) && FaroresWindAnywhere) && (HasBottle || (IsAdult && (ClaimCheck || HasBoots)) || (IsChild && WeirdEgg))) || + (((!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || CanUse(FARORES_WIND)) && + (NumBottles + ((IsChild) ? ((WeirdEgg) ? 1 : 0) : (((IronBoots) ? 1 : 0) + ((HoverBoots) ? 1 : 0) + ((ClaimCheck) ? 1 : 0))) >= 2))) && + CanDoGlitch(GlitchType::BombOI, difficulty) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE); + case GlitchType::DungeonBombOI: + return ((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || (CanUse(FARORES_WIND))) && CanDoGlitch(GlitchType::BombOI, difficulty); + + //Hover Boost + case GlitchType::HoverBoost: + setDifficulty = GetDifficultyValueFromString(GlitchHoverBoost); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return Bombs && CanUse(HOVER_BOOTS) && CanSurviveDamage; + + //Super Slide + case GlitchType::SuperSlide: + setDifficulty = GetDifficultyValueFromString(GlitchSuperSlide); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return true; + + //Megaflip + case GlitchType::Megaflip: + setDifficulty = GetDifficultyValueFromString(GlitchMegaflip); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + // Bombchu megaflips should be considered 2 difficulty levels higher + return CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast(difficulty) + 2)); + + //A-Slide + case GlitchType::ASlide: + setDifficulty = GetDifficultyValueFromString(GlitchASlide); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + // Same deal as bombchu megaflips + return IsChild && CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast(difficulty) + 2)); + + //Hammer Slide + case GlitchType::HammerSlide: + setDifficulty = GetDifficultyValueFromString(GlitchHammerSlide); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return CanUse(MEGATON_HAMMER) && CanUse(HOVER_BOOTS) && CanShield; + + //Ledge Cancel + case GlitchType::LedgeCancel: + setDifficulty = GetDifficultyValueFromString(GlitchLedgeCancel); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + // Similar to bombchu megaflips / A-slides but doesn't scale beyond advanced + return CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast(GlitchDifficulty::ADVANCED))); + + //Action Swap + case GlitchType::ActionSwap: + setDifficulty = GetDifficultyValueFromString(GlitchActionSwap); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return true; + + //Quick Put Away + case GlitchType::QPA: + setDifficulty = GetDifficultyValueFromString(GlitchQPA); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + // Boot Put Away Delay Method Frame Perfect Method Ledge Grab Method + return (CanTakeDamage && Bombs && ((CanUse(HOVER_BOOTS) || CanUse(IRON_BOOTS)) || setDifficulty >= static_cast(GlitchDifficulty::INTERMEDIATE))) || setDifficulty >= static_cast(GlitchDifficulty::ADVANCED); + + //Hookshot Clip + case GlitchType::HookshotClip: + setDifficulty = GetDifficultyValueFromString(GlitchHookshotClip); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return CanUse(HOOKSHOT); + + //Hookshot Jump: Bonk + case GlitchType::HookshotJump_Bonk: + setDifficulty = GetDifficultyValueFromString(GlitchHookshotJump_Bonk); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return IsAdult && Hookshot; // Child hookshot jumps are tiny so these stay as adult only until I check + + //Hookshot Jump: Boots + case GlitchType::HookshotJump_Boots: + setDifficulty = GetDifficultyValueFromString(GlitchHookshotJump_Boots); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return IsAdult && Hookshot && HasBoots; // Child hookshot jumps are tiny so these stay as adult only until I check + + //Cutscene Dives + case GlitchType::CutsceneDive: + setDifficulty = GetDifficultyValueFromString(GlitchCutsceneDive); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return true; + + //Navi Dives without TSC + case GlitchType::NaviDive_Stick: + setDifficulty = GetDifficultyValueFromString(GlitchNaviDive_Stick); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return IsChild && Sticks; + + //Triple Slash Clip + case GlitchType::TripleSlashClip: + setDifficulty = GetDifficultyValueFromString(GlitchTripleSlashClip); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return IsAdult || KokiriSword; + + //Ledge Clip + case GlitchType::LedgeClip: + setDifficulty = GetDifficultyValueFromString(GlitchLedgeClip); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return IsAdult; + + //Seam Walks + case GlitchType::SeamWalk: + setDifficulty = GetDifficultyValueFromString(GlitchSeamWalk); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return true; + } + + //Shouldn't be reached + return false; + } + + //Updates all logic helpers. Should be called whenever a non-helper is changed + void UpdateHelpers() { + NumBottles = ((NoBottles) ? 0 : (Bottles + ((DeliverLetter) ? 1 : 0))); + HasBottle = NumBottles >= 1; + Slingshot = (ProgressiveBulletBag >= 1) && (BuySeed || AmmoCanDrop); + Ocarina = ProgressiveOcarina >= 1; + OcarinaOfTime = ProgressiveOcarina >= 2; + MagicMeter = (ProgressiveMagic >= 1) && (AmmoCanDrop || (HasBottle && (BuyGPotion || BuyBPotion))); + BombBag = (ProgressiveBombBag >= 1) && (BuyBomb || AmmoCanDrop); + Hookshot = ProgressiveHookshot >= 1; + Longshot = ProgressiveHookshot >= 2; + Bow = (ProgressiveBow >= 1) && (BuyArrow || AmmoCanDrop); + GoronBracelet = ProgressiveStrength >= 1; + SilverGauntlets = ProgressiveStrength >= 2; + GoldenGauntlets = ProgressiveStrength >= 3; + SilverScale = ProgressiveScale >= 1; + GoldScale = ProgressiveScale >= 2; + AdultsWallet = ProgressiveWallet >= 1; + MasterSword = MasterSword || IsAdult; + BiggoronSword = BiggoronSword || ProgressiveGiantKnife >= 2; + + ScarecrowSong = ScarecrowSong || (ChildScarecrow && AdultScarecrow); + Scarecrow = Hookshot && CanPlay(ScarecrowSong); + DistantScarecrow = Longshot && CanPlay(ScarecrowSong); + + //Drop Access + DekuStickDrop = StickPot || DekuBabaSticks; + DekuNutDrop = (NutPot || NutCrate || DekuBabaNuts) && AmmoCanDrop; + BugsAccess = BugShrub || WanderingBugs || BugRock; + FishAccess = LoneFish || FishGroup; + FairyAccess = FairyPot || GossipStoneFairy || BeanPlantFairy || ButterflyFairy || FreeFairies || FairyPond; + + + //refills + Bombs = BombBag; + Nuts = DekuNutDrop || Nuts; + Sticks = DekuStickDrop || Sticks; + Bugs = HasBottle && BugsAccess; + BlueFire = HasBottle && BlueFireAccess; + Fish = HasBottle && FishAccess; + Fairy = HasBottle && FairyAccess; + + FoundBombchus = (BombchuDrop || Bombchus || Bombchus5 || Bombchus10 || Bombchus20); + CanPlayBowling = (BombchusInLogic && FoundBombchus) || (!BombchusInLogic && BombBag); + HasBombchus = (BuyBombchus5 || BuyBombchus10 || BuyBombchus20 || (AmmoDrops.Is(AMMODROPS_BOMBCHU) && FoundBombchus)); + + HasExplosives = Bombs || (BombchusInLogic && HasBombchus); + + HasBoots = IronBoots || HoverBoots; + + //Unshuffled adult trade quest + Eyedrops = Eyedrops || (!ShuffleAdultTradeQuest && ClaimCheck); + EyeballFrog = EyeballFrog || (!ShuffleAdultTradeQuest && Eyedrops); + Prescription = Prescription || (!ShuffleAdultTradeQuest && EyeballFrog); + BrokenSword = BrokenSword || (!ShuffleAdultTradeQuest && Prescription); + PoachersSaw = PoachersSaw || (!ShuffleAdultTradeQuest && BrokenSword); + OddPoultice = OddPoultice || (!ShuffleAdultTradeQuest && PoachersSaw); + OddMushroom = OddMushroom || (!ShuffleAdultTradeQuest && OddPoultice); + Cojiro = Cojiro || (!ShuffleAdultTradeQuest && OddMushroom); + PocketEgg = PocketEgg || (!ShuffleAdultTradeQuest && Cojiro); + + // IsChild = Age == AGE_CHILD; + // IsAdult = Age == AGE_ADULT; + + CanBlastOrSmash = HasExplosives || CanUse(MEGATON_HAMMER); + CanChildAttack = IsChild && (Slingshot || Boomerang || Sticks || KokiriSword || HasExplosives || CanUse(DINS_FIRE) || CanUse(MASTER_SWORD) || CanUse(MEGATON_HAMMER) || CanUse(BIGGORON_SWORD)); + CanChildDamage = IsChild && (Slingshot || Sticks || KokiriSword || HasExplosives || CanUse(DINS_FIRE) || CanUse(MASTER_SWORD) || CanUse(MEGATON_HAMMER) || CanUse(BIGGORON_SWORD)); + CanStunDeku = IsAdult || CanChildAttack || Nuts || HasShield; + CanCutShrubs = IsAdult /*|| Sticks*/ || KokiriSword || Boomerang || HasExplosives || CanUse(MASTER_SWORD) || CanUse(MEGATON_HAMMER) || CanUse(BIGGORON_SWORD); + CanDive = ProgressiveScale >= 1; + CanLeaveForest = OpenForest.IsNot(OPENFOREST_CLOSED) || IsAdult || DekuTreeClear || ShuffleInteriorEntrances || ShuffleOverworldEntrances; + CanPlantBugs = IsChild && Bugs; + CanRideEpona = IsAdult && Epona && CanPlay(EponasSong); + CanSummonGossipFairy = Ocarina && (ZeldasLullaby || EponasSong || SongOfTime || SunsSong); + CanSummonGossipFairyWithoutSuns = Ocarina && (ZeldasLullaby || EponasSong || SongOfTime); + Hearts = BaseHearts + HeartContainer + (PieceOfHeart >> 2); + EffectiveHealth = ((Hearts << (2 + DoubleDefense)) >> Multiplier) + ((Hearts << (2 + DoubleDefense)) % (1 << Multiplier) > 0); //Number of half heart hits to die, ranges from 1 to 160 + FireTimer = CanUse(GORON_TUNIC) ? 255 : (LogicFewerTunicRequirements) ? (Hearts * 8) : 0; + WaterTimer = CanUse( ZORA_TUNIC) ? 255 : (LogicFewerTunicRequirements) ? (Hearts * 8) : 0; + NeedNayrusLove = (EffectiveHealth == 1); + CanSurviveDamage = !NeedNayrusLove || CanUse(NAYRUS_LOVE); + CanTakeDamage = Fairy || CanSurviveDamage; + CanTakeDamageTwice = (Fairy && NumBottles >= 2) || ((EffectiveHealth == 2) && (CanUse(NAYRUS_LOVE) || Fairy)) || (EffectiveHealth > 2); + //CanPlantBean = IsChild && (MagicBean || MagicBeanPack); + CanOpenBombGrotto = CanBlastOrSmash && (ShardOfAgony || LogicGrottosWithoutAgony); + CanOpenStormGrotto = CanPlay(SongOfStorms) && (ShardOfAgony || LogicGrottosWithoutAgony); + HookshotOrBoomerang = CanUse(HOOKSHOT) || CanUse(BOOMERANG); + CanGetNightTimeGS = (CanPlay(SunsSong) || !NightGSExpectSuns); + + GuaranteeTradePath = ShuffleInteriorEntrances || ShuffleOverworldEntrances || LogicBiggoronBolero || CanBlastOrSmash || StopGCRollingGoronAsAdult; + //GuaranteeHint = (hints == "Mask" && MaskofTruth) || (hints == "Agony") || (hints != "Mask" && hints != "Agony"); + HasFireSource = CanUse(DINS_FIRE) || CanUse(FIRE_ARROWS); + HasFireSourceWithTorch = HasFireSource || CanUse(STICKS); + + //Gerudo Fortress + CanFinishGerudoFortress = (GerudoFortress.Is(GERUDOFORTRESS_NORMAL) && GerudoFortressKeys >= 4 && (IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen)) || + (GerudoFortress.Is(GERUDOFORTRESS_FAST) && GerudoFortressKeys >= 1 && (IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))) || + (GerudoFortress.IsNot(GERUDOFORTRESS_NORMAL) && GerudoFortress.IsNot(GERUDOFORTRESS_FAST)); + + HasShield = CanUse(HYLIAN_SHIELD) || CanUse(DEKU_SHIELD); //Mirror shield can't reflect attacks + CanShield = CanUse(MIRROR_SHIELD) || HasShield; + CanJumpslash = IsAdult || Sticks || KokiriSword; + CanUseProjectile = HasExplosives || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(SLINGSHOT) || CanUse(BOOMERANG); + CanUseMagicArrow = CanUse(FIRE_ARROWS) || CanUse(ICE_ARROWS) || CanUse(LIGHT_ARROWS); + + //Bridge and LACS Requirements + MedallionCount = (ForestMedallion ? 1:0) + (FireMedallion ? 1:0) + (WaterMedallion ? 1:0) + (SpiritMedallion ? 1:0) + (ShadowMedallion ? 1:0) + (LightMedallion ? 1:0); + StoneCount = (KokiriEmerald ? 1:0) + (GoronRuby ? 1:0) + (ZoraSapphire ? 1:0); + DungeonCount = (DekuTreeClear ? 1:0) + (DodongosCavernClear ? 1:0) + (JabuJabusBellyClear ? 1:0) + (ForestTempleClear ? 1:0) + (FireTempleClear ? 1:0) + (WaterTempleClear ? 1:0) + (SpiritTempleClear ? 1:0) + (ShadowTempleClear ? 1:0); + HasAllStones = StoneCount == 3; + HasAllMedallions = MedallionCount == 6; + + CanBuildRainbowBridge = Bridge.Is(RAINBOWBRIDGE_OPEN) || + (Bridge.Is(RAINBOWBRIDGE_VANILLA) && ShadowMedallion && SpiritMedallion && LightArrows) || + (Bridge.Is(RAINBOWBRIDGE_STONES) && StoneCount >= BridgeStoneCount.Value()) || + (Bridge.Is(RAINBOWBRIDGE_MEDALLIONS) && MedallionCount >= BridgeMedallionCount.Value()) || + (Bridge.Is(RAINBOWBRIDGE_REWARDS) && StoneCount + MedallionCount >= BridgeRewardCount.Value()) || + (Bridge.Is(RAINBOWBRIDGE_DUNGEONS) && DungeonCount >= BridgeDungeonCount.Value()) || + (Bridge.Is(RAINBOWBRIDGE_TOKENS) && GoldSkulltulaTokens >= BridgeTokenCount.Value()); + + CanTriggerLACS = (LACSCondition == LACSCONDITION_VANILLA && ShadowMedallion && SpiritMedallion) || + (LACSCondition == LACSCONDITION_STONES && StoneCount >= LACSStoneCount.Value()) || + (LACSCondition == LACSCONDITION_MEDALLIONS && MedallionCount >= LACSMedallionCount.Value()) || + (LACSCondition == LACSCONDITION_REWARDS && StoneCount + MedallionCount >= LACSRewardCount.Value()) || + (LACSCondition == LACSCONDITION_DUNGEONS && DungeonCount >= LACSDungeonCount.Value()) || + (LACSCondition == LACSCONDITION_TOKENS && GoldSkulltulaTokens >= LACSTokenCount.Value()); + + } + + bool SmallKeys(Key dungeon, uint8_t requiredAmount) { + return SmallKeys(dungeon, requiredAmount, requiredAmount); + } + + bool SmallKeys(Key dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched) { + switch (dungeon) { + case FOREST_TEMPLE: + if (IsGlitched && (GetDifficultyValueFromString(GlitchHookshotJump_Boots) >= static_cast(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHoverBoost) >= static_cast(GlitchDifficulty::NOVICE) || + (GetDifficultyValueFromString(GlitchHover) >= static_cast(GlitchDifficulty::NOVICE) && GetDifficultyValueFromString(GlitchISG) >= static_cast(GlitchDifficulty::INTERMEDIATE)))) { + return ForestTempleKeys >= requiredAmountGlitched; + } + return ForestTempleKeys >= requiredAmountGlitchless; + + case FIRE_TEMPLE: + if (IsGlitched && (GetDifficultyValueFromString(GlitchLedgeClip) >= static_cast(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHover) >= static_cast(GlitchDifficulty::INTERMEDIATE))) { + return FireTempleKeys >= requiredAmountGlitched; + } + return FireTempleKeys >= requiredAmountGlitchless; + + case WATER_TEMPLE: + if (IsGlitched && (false)) { + return WaterTempleKeys >= requiredAmountGlitched; + } + return WaterTempleKeys >= requiredAmountGlitchless; + + case SPIRIT_TEMPLE: + if (IsGlitched && (false)) { + return SpiritTempleKeys >= requiredAmountGlitched; + } + return SpiritTempleKeys >= requiredAmountGlitchless; + + case SHADOW_TEMPLE: + if (IsGlitched && (GetDifficultyValueFromString(GlitchHookshotClip) >= static_cast(GlitchDifficulty::NOVICE))) { + return ShadowTempleKeys >= requiredAmountGlitched; + } + return ShadowTempleKeys >= requiredAmountGlitchless; + + case BOTTOM_OF_THE_WELL: + if (IsGlitched && (false)) { + return BottomOfTheWellKeys >= requiredAmountGlitched; + } + return BottomOfTheWellKeys >= requiredAmountGlitchless; + + case GERUDO_TRAINING_GROUNDS: + if (IsGlitched && (false)) { + return GerudoTrainingGroundsKeys >= requiredAmountGlitched; + } + return GerudoTrainingGroundsKeys >= requiredAmountGlitchless; + + case GANONS_CASTLE: + if (IsGlitched && (false)) { + return GanonsCastleKeys >= requiredAmountGlitched; + } + return GanonsCastleKeys >= requiredAmountGlitchless; + + case MARKET_TREASURE_CHEST_GAME: + if (IsGlitched && (false)) { + return TreasureGameKeys >= requiredAmountGlitched; + } + return TreasureGameKeys >= requiredAmountGlitchless; + + default: + return false; + } + } + + bool EventsUpdated() { + + if (DekuTreeClearPast != DekuTreeClear || + GoronRubyPast != GoronRuby || + ZoraSapphirePast != ZoraSapphire || + ForestTrialClearPast != ForestTrialClear || + FireTrialClearPast != FireTrialClear || + WaterTrialClearPast != WaterTrialClear || + ShadowTrialClearPast != ShadowTrialClear || + SpiritTrialClearPast != SpiritTrialClear || + LightTrialClearPast != LightTrialClear || + DrainWellPast != DrainWell || + DampesWindmillAccessPast != DampesWindmillAccess || + TimeTravelPast != TimeTravel) { + DekuTreeClearPast = DekuTreeClear; + GoronRubyPast = GoronRuby; + ZoraSapphirePast = ZoraSapphire; + ForestTrialClearPast = ForestTrialClear; + FireTrialClearPast = FireTrialClear; + WaterTrialClearPast = WaterTrialClear; + ShadowTrialClearPast = ShadowTrialClear; + SpiritTrialClearPast = SpiritTrialClear; + LightTrialClearPast = LightTrialClear; + DrainWellPast = DrainWell; + DampesWindmillAccessPast = DampesWindmillAccess; + return true; + } + return false; + } + + //Reset All Logic to false + void LogicReset() { + //Settings-dependent variables + IsKeysanity = Keysanity.Is(KEYSANITY_ANYWHERE) || Keysanity.Is(KEYSANITY_OVERWORLD) || Keysanity.Is(KEYSANITY_ANY_DUNGEON); + AmmoCanDrop = AmmoDrops.IsNot(AMMODROPS_NONE); + + //Child item logic + KokiriSword = false; + ZeldasLetter = false; + WeirdEgg = false; + HasBottle = false; + Bombchus = false; + Bombchus5 = false; + Bombchus10 = false; + Bombchus20 = false; + MagicBean = false; + MagicBeanPack = false; + RutosLetter = false; + Boomerang = false; + DinsFire = false; + FaroresWind = false; + NayrusLove = false; + LensOfTruth = false; + ShardOfAgony = false; + SkullMask = false; + MaskOfTruth = false; + + //Adult logic + Hammer = false; + IronBoots = false; + HoverBoots = false; + MirrorShield = false; + GoronTunic = false; + ZoraTunic = false; + Epona = false; + BigPoe = false; + GerudoToken = false; + FireArrows = false; + IceArrows = false; + LightArrows = false; + MasterSword = false; + BiggoronSword = false; + + //Trade Quest + PocketEgg = false; + Cojiro = false; + OddMushroom = false; + OddPoultice = false; + PoachersSaw = false; + BrokenSword = false; + Prescription = false; + EyeballFrog = false; + Eyedrops = false; + ClaimCheck = false; + + //Trade Quest Events + WakeUpAdultTalon = false; + CojiroAccess = false; + OddMushroomAccess = false; + OddPoulticeAccess = false; + PoachersSawAccess = false; + BrokenSwordAccess = false; + PrescriptionAccess = false; + EyeballFrogAccess = false; + EyedropsAccess = false; + DisableTradeRevert = false; + + //Songs + ZeldasLullaby = false; + SariasSong = false; + SunsSong = false; + SongOfStorms = false; + EponasSong = false; + SongOfTime = false; + MinuetOfForest = false; + BoleroOfFire = false; + SerenadeOfWater = false; + RequiemOfSpirit = false; + NocturneOfShadow = false; + PreludeOfLight = false; + + //Stones and Meddallions + ForestMedallion = false; + FireMedallion = false; + WaterMedallion = false; + SpiritMedallion = false; + ShadowMedallion = false; + LightMedallion = false; + KokiriEmerald = false; + GoronRuby = false; + ZoraSapphire = false; + + //Dungeon Clears + DekuTreeClear = false; + DodongosCavernClear = false; + JabuJabusBellyClear = false; + ForestTempleClear = false; + FireTempleClear = false; + WaterTempleClear = false; + SpiritTempleClear = false; + ShadowTempleClear = false; + + //Trial Clears + ForestTrialClear = false; + FireTrialClear = false; + WaterTrialClear = false; + SpiritTrialClear = false; + ShadowTrialClear = false; + LightTrialClear = false; + + //Progressive Items + ProgressiveBulletBag = 0; + ProgressiveBombBag = 0; + ProgressiveMagic = 0; + ProgressiveScale = 0; + ProgressiveHookshot = 0; + ProgressiveBow = 0; + ProgressiveWallet = 0; + ProgressiveStrength = 0; + ProgressiveOcarina = 0; + ProgressiveGiantKnife = 0; + + //Keys + ForestTempleKeys = 0; + //If not keysanity, start with 1 logical key to account for automatically unlocking the basement door in vanilla FiT + FireTempleKeys = IsKeysanity || Dungeon::FireTemple.IsMQ() ? 0 : 1; + WaterTempleKeys = 0; + SpiritTempleKeys = 0; + ShadowTempleKeys = 0; + GanonsCastleKeys = 0; + GerudoFortressKeys = 0; + GerudoTrainingGroundsKeys = 0; + BottomOfTheWellKeys = 0; + TreasureGameKeys = 0; + + //Boss Keys + BossKeyForestTemple = 0; + BossKeyFireTemple = 0; + BossKeyWaterTemple = 0; + BossKeySpiritTemple = 0; + BossKeyShadowTemple = 0; + BossKeyGanonsCastle = 0; + + //Gold Skulltula Count + GoldSkulltulaTokens = 0; + + //Bottle Count + Bottles = 0; + NumBottles = 0; + NoBottles = false; + + + + //Drops and Bottle Contents Access + DekuNutDrop = false; + NutPot = false; + NutCrate = false; + DekuBabaNuts = false; + DekuStickDrop = false; + StickPot = false; + DekuBabaSticks = false; + BugsAccess = false; + BugShrub = false; + WanderingBugs = false; + BugRock = false; + BlueFireAccess = false; + FishAccess = false; + FishGroup = false; + LoneFish = false; + FairyAccess = false; + GossipStoneFairy = false; + BeanPlantFairy = false; + ButterflyFairy = false; + FairyPot = false; + FreeFairies = false; + FairyPond = false; + BombchuDrop = false; + + BuyBombchus5 = false; + BuyBombchus10 = false; + BuyBombchus20 = false; + BuySeed = false; + BuyArrow = false; + BuyBomb = false; + BuyGPotion = false; + BuyBPotion = false; + MagicRefill = false; + + PieceOfHeart = 0; + HeartContainer = 0; + DoubleDefense = false; + + /* --- HELPERS, EVENTS, AND LOCATION ACCESS --- */ + /* These are used to simplify reading the logic, but need to be updated + / every time a base value is updated. */ + + Slingshot = false; + Ocarina = false; + OcarinaOfTime = false; + BombBag = false; + MagicMeter = false; + Hookshot = false; + Longshot = false; + Bow = false; + GoronBracelet = false; + SilverGauntlets = false; + GoldenGauntlets = false; + SilverScale = false; + GoldScale = false; + AdultsWallet = false; + + ChildScarecrow = false; + AdultScarecrow = false; + ScarecrowSong = false; + Scarecrow = false; + DistantScarecrow = false; + + Bombs = false; + DekuShield = false; + HylianShield = false; + Nuts = false; + Sticks = false; + Bugs = false; + BlueFire = false; + Fish = false; + Fairy = false; + BottleWithBigPoe = false; + + FoundBombchus = false; + CanPlayBowling = false; + HasBombchus = false; + HasExplosives = false; + HasBoots = false; + IsChild = false; + IsAdult = false; + IsGlitched = Settings::Logic.Is(LOGIC_GLITCHED); + CanBlastOrSmash = false; + CanChildAttack = false; + CanChildDamage = false; + CanCutShrubs = false; + CanDive = false; + CanLeaveForest = false; + CanPlantBugs = false; + CanRideEpona = false; + CanStunDeku = false; + CanSummonGossipFairy = false; + CanSummonGossipFairyWithoutSuns = false; + //CanPlantBean = false; + CanOpenBombGrotto = false; + CanOpenStormGrotto = false; + BigPoeKill = false; + HookshotOrBoomerang = false; + + BaseHearts = StartingHearts.Value() + 1; + Hearts = 0; + Multiplier = (DamageMultiplier.Value() < 6) ? DamageMultiplier.Value() : 10; + EffectiveHealth = 0; + FireTimer = 0; + WaterTimer = 0; + + GuaranteeTradePath = false; + GuaranteeHint = false; + HasFireSource = false; + HasFireSourceWithTorch = false; + + CanFinishGerudoFortress = false; + + HasShield = false; + CanShield = false; + CanJumpslash = false; + CanUseProjectile = false; + CanUseMagicArrow = false; + + //Bridge Requirements + HasAllStones = false; + HasAllMedallions = false; + CanBuildRainbowBridge = false; + CanTriggerLACS = false; + + //Other + AtDay = false; + AtNight = false; + Age = Settings::ResolvedStartingAge; + + //Events + ShowedMidoSwordAndShield = false; + CarpenterRescue = false; + GF_GateOpen = false; + GtG_GateOpen = false; + DampesWindmillAccess = false; + DrainWell = false; + GoronCityChildFire = false; + GCWoodsWarpOpen = false; + GCDaruniasDoorOpenChild = false; + StopGCRollingGoronAsAdult = false; + WaterTempleLow = false; + WaterTempleMiddle = false; + WaterTempleHigh = false; + KakarikoVillageGateOpen = false; + KingZoraThawed = false; + ForestTempleJoelle = false; + ForestTempleBeth = false; + ForestTempleJoAndBeth = false; + ForestTempleAmy = false; + ForestTempleMeg = false; + ForestTempleAmyAndMeg = false; + FireLoopSwitch = false; + LinksCow = false; + AtDampeTime = false; + DeliverLetter = false; + TimeTravel = false; + + DrainWellPast = false; + DampesWindmillAccessPast = false; + DekuTreeClearPast = false; + GoronRubyPast = false; + ZoraSapphirePast = false; + ForestTrialClearPast = false; + FireTrialClearPast = false; + WaterTrialClearPast = false; + SpiritTrialClearPast = false; + ShadowTrialClearPast = false; + LightTrialClearPast = false; + BuyDekuShieldPast = false; + TimeTravelPast = false; + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/logic.hpp b/soh/soh/Enhancements/randomizer/3drando/logic.hpp new file mode 100644 index 000000000..9863878d1 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/logic.hpp @@ -0,0 +1,387 @@ +#pragma once + +#include "keys.hpp" +#include + +namespace Logic { +extern bool noVariable; + +// Child item logic +extern bool KokiriSword; +extern bool Slingshot; +extern bool ZeldasLetter; +extern bool WeirdEgg; +extern bool HasBottle; +extern bool BombBag; +extern bool Bombchus; +extern bool Bombchus5; +extern bool Bombchus10; +extern bool Bombchus20; +extern bool MagicBean; +extern bool MagicBeanPack; +extern bool RutosLetter; +extern bool Boomerang; +extern bool DinsFire; +extern bool FaroresWind; +extern bool NayrusLove; +extern bool LensOfTruth; +extern bool ShardOfAgony; +extern bool SkullMask; +extern bool MaskOfTruth; + +// Adult logic +extern bool Bow; +extern bool Hammer; +extern bool IronBoots; +extern bool HoverBoots; +extern bool MirrorShield; +extern bool GoronTunic; +extern bool ZoraTunic; +extern bool Epona; +extern bool BigPoe; +extern bool GerudoToken; +extern bool FireArrows; +extern bool IceArrows; +extern bool LightArrows; +extern bool MasterSword; +extern bool BiggoronSword; + +// Trade Quest +extern bool PocketEgg; +extern bool Cojiro; +extern bool OddMushroom; +extern bool OddPoultice; +extern bool PoachersSaw; +extern bool BrokenSword; +extern bool Prescription; +extern bool EyeballFrog; +extern bool Eyedrops; +extern bool ClaimCheck; + +// Trade Quest Events +extern bool WakeUpAdultTalon; +extern bool CojiroAccess; +extern bool OddMushroomAccess; +extern bool OddPoulticeAccess; +extern bool PoachersSawAccess; +extern bool BrokenSwordAccess; +extern bool PrescriptionAccess; +extern bool EyeballFrogAccess; +extern bool EyedropsAccess; +extern bool DisableTradeRevert; + +// Songs +extern bool ZeldasLullaby; +extern bool SariasSong; +extern bool SunsSong; +extern bool SongOfStorms; +extern bool EponasSong; +extern bool SongOfTime; +extern bool MinuetOfForest; +extern bool BoleroOfFire; +extern bool SerenadeOfWater; +extern bool RequiemOfSpirit; +extern bool NocturneOfShadow; +extern bool PreludeOfLight; + +// Stones and Meddallions +extern bool ForestMedallion; +extern bool FireMedallion; +extern bool WaterMedallion; +extern bool SpiritMedallion; +extern bool ShadowMedallion; +extern bool LightMedallion; +extern bool KokiriEmerald; +extern bool GoronRuby; +extern bool ZoraSapphire; + +// Dungeon Clears +extern bool DekuTreeClear; +extern bool DodongosCavernClear; +extern bool JabuJabusBellyClear; +extern bool ForestTempleClear; +extern bool FireTempleClear; +extern bool WaterTempleClear; +extern bool SpiritTempleClear; +extern bool ShadowTempleClear; + +// Trial Clears +extern bool ForestTrialClear; +extern bool FireTrialClear; +extern bool WaterTrialClear; +extern bool SpiritTrialClear; +extern bool ShadowTrialClear; +extern bool LightTrialClear; + +// Progression Items +extern uint8_t ProgressiveBulletBag; +extern uint8_t ProgressiveBombBag; +extern uint8_t ProgressiveScale; +extern uint8_t ProgressiveHookshot; +extern uint8_t ProgressiveBow; +extern uint8_t ProgressiveStrength; +extern uint8_t ProgressiveWallet; +extern uint8_t ProgressiveMagic; +extern uint8_t ProgressiveOcarina; +extern uint8_t ProgressiveGiantKnife; + +// Keysanity +extern bool IsKeysanity; + +// Keys +extern uint8_t ForestTempleKeys; +extern uint8_t FireTempleKeys; +extern uint8_t WaterTempleKeys; +extern uint8_t SpiritTempleKeys; +extern uint8_t ShadowTempleKeys; +extern uint8_t BottomOfTheWellKeys; +extern uint8_t GerudoTrainingGroundsKeys; +extern uint8_t GerudoFortressKeys; +extern uint8_t GanonsCastleKeys; +extern uint8_t TreasureGameKeys; + +// Boss Keys +extern bool BossKeyForestTemple; +extern bool BossKeyFireTemple; +extern bool BossKeyWaterTemple; +extern bool BossKeySpiritTemple; +extern bool BossKeyShadowTemple; +extern bool BossKeyGanonsCastle; + +// Gold Skulltula Count +extern uint8_t GoldSkulltulaTokens; + +// Bottle Count, with and without Ruto's Letter +extern uint8_t Bottles; +extern uint8_t NumBottles; +extern bool NoBottles; + +// item and bottle drops +extern bool DekuNutDrop; +extern bool NutPot; +extern bool NutCrate; +extern bool DekuBabaNuts; +extern bool DekuStickDrop; +extern bool StickPot; +extern bool DekuBabaSticks; +extern bool BugsAccess; +extern bool BugShrub; +extern bool WanderingBugs; +extern bool BugRock; +extern bool BlueFireAccess; +extern bool FishAccess; +extern bool FishGroup; +extern bool LoneFish; +extern bool FairyAccess; +extern bool GossipStoneFairy; +extern bool BeanPlantFairy; +extern bool ButterflyFairy; +extern bool FairyPot; +extern bool FreeFairies; +extern bool FairyPond; +extern bool BombchuDrop; + +extern bool BuyBombchus5; +extern bool BuyBombchus10; +extern bool BuyBombchus20; +extern bool BuyArrow; +extern bool BuyBomb; +extern bool BuyGPotion; +extern bool BuyBPotion; +extern bool BuySeed; +extern bool MagicRefill; + +extern uint8_t PieceOfHeart; +extern uint8_t HeartContainer; +extern bool DoubleDefense; + +/* --- HELPERS --- */ +/* These are used to simplify reading the logic, but need to be updated +/ every time a base value is updated. */ + +extern bool Ocarina; +extern bool OcarinaOfTime; +extern bool MagicMeter; +extern bool Hookshot; +extern bool Longshot; +extern bool GoronBracelet; +extern bool SilverGauntlets; +extern bool GoldenGauntlets; +extern bool SilverScale; +extern bool GoldScale; +extern bool AdultsWallet; + +extern bool ChildScarecrow; +extern bool AdultScarecrow; +extern bool ScarecrowSong; +extern bool Scarecrow; +extern bool DistantScarecrow; + +extern bool Bombs; +extern bool DekuShield; +extern bool HylianShield; +extern bool Nuts; +extern bool Sticks; +extern bool Bugs; +extern bool BlueFire; +extern bool Fish; +extern bool Fairy; +extern bool BottleWithBigPoe; + +extern bool Bombs; +extern bool FoundBombchus; +extern bool CanPlayBowling; +extern bool HasBombchus; +extern bool HasExplosives; +extern bool HasBoots; +extern bool IsChild; +extern bool IsAdult; +extern bool IsGlitched; +extern bool CanBlastOrSmash; +extern bool CanChildAttack; +extern bool CanChildDamage; +extern bool CanCutShrubs; +extern bool CanDive; +extern bool CanLeaveForest; +extern bool CanPlantBugs; +extern bool CanRideEpona; +extern bool CanStunDeku; +extern bool CanSummonGossipFairy; +extern bool CanSummonGossipFairyWithoutSuns; +extern bool NeedNayrusLove; +extern bool CanSurviveDamage; +extern bool CanTakeDamage; +extern bool CanTakeDamageTwice; +// extern bool CanPlantBean; +extern bool CanOpenBombGrotto; +extern bool CanOpenStormGrotto; +extern bool HookshotOrBoomerang; +extern bool CanGetNightTimeGS; +extern bool BigPoeKill; + +extern uint8_t BaseHearts; +extern uint8_t Hearts; +extern uint8_t Multiplier; +extern uint8_t EffectiveHealth; +extern uint8_t FireTimer; +extern uint8_t WaterTimer; + +extern bool GuaranteeTradePath; +extern bool GuaranteeHint; +extern bool HasFireSource; +extern bool HasFireSourceWithTorch; + +// Gerudo Fortress +extern bool CanFinishGerudoFortress; + +extern bool HasShield; +extern bool CanShield; +extern bool CanJumpslash; +extern bool CanUseProjectile; +extern bool CanUseMagicArrow; + +// Bridge Requirements +extern bool HasAllStones; +extern bool HasAllMedallions; +extern bool CanBuildRainbowBridge; +extern bool CanTriggerLACS; + +// Other +extern bool AtDay; +extern bool AtNight; +extern bool LinksCow; +extern uint8_t Age; + +// Events +extern bool ShowedMidoSwordAndShield; +extern bool CarpenterRescue; +extern bool DampesWindmillAccess; +extern bool GF_GateOpen; +extern bool GtG_GateOpen; +extern bool DrainWell; +extern bool GoronCityChildFire; +extern bool GCWoodsWarpOpen; +extern bool GCDaruniasDoorOpenChild; +extern bool StopGCRollingGoronAsAdult; +extern bool WaterTempleLow; +extern bool WaterTempleMiddle; +extern bool WaterTempleHigh; +extern bool KingZoraThawed; +extern bool AtDampeTime; +extern bool DeliverLetter; +extern bool KakarikoVillageGateOpen; +extern bool ForestTempleJoelle; +extern bool ForestTempleBeth; +extern bool ForestTempleJoAndBeth; +extern bool ForestTempleAmy; +extern bool ForestTempleMeg; +extern bool ForestTempleAmyAndMeg; +extern bool FireLoopSwitch; +extern bool TimeTravel; + +/* --- END OF HELPERS --- */ + +extern uint8_t AddedProgressiveBulletBags; +extern uint8_t AddedProgressiveBombBags; +extern uint8_t AddedProgressiveMagics; +extern uint8_t AddedProgressiveScales; +extern uint8_t AddedProgressiveHookshots; +extern uint8_t AddedProgressiveBows; +extern uint8_t AddedProgressiveWallets; +extern uint8_t AddedProgressiveStrengths; +extern uint8_t AddedProgressiveOcarinas; +extern uint8_t TokensInPool; + +enum class HasProjectileAge { + Adult, + Child, + Both, + Either, +}; + +enum class GlitchType { + RestrictedItems, + SuperStab, + ISG, + BombHover, + BombOI, + OutdoorBombOI, + WindmillBombOI, + IndoorBombOI, + DungeonBombOI, + HoverBoost, + SuperSlide, + Megaflip, + ASlide, + HammerSlide, + LedgeCancel, + ActionSwap, + QPA, + HookshotClip, + HookshotJump_Bonk, + HookshotJump_Boots, + CutsceneDive, + NaviDive_Stick, + TripleSlashClip, + LedgeClip, + SeamWalk, +}; + +enum class GlitchDifficulty { + NOVICE = 1, + INTERMEDIATE, + ADVANCED, + EXPERT, + HERO, +}; + +void UpdateHelpers(); +bool CanPlay(bool song); +bool CanUse(uint32_t itemName); +bool HasProjectile(HasProjectileAge age); +bool SmallKeys(Key dungeon, uint8_t requiredAmount); +bool SmallKeys(Key dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched); +bool CanDoGlitch(GlitchType glitch, GlitchDifficulty difficulty); +bool EventsUpdated(); +void LogicReset(); +} // namespace Logic \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/menu.cpp b/soh/soh/Enhancements/randomizer/3drando/menu.cpp new file mode 100644 index 000000000..80e5d63b2 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/menu.cpp @@ -0,0 +1,550 @@ +#include +#include +#include +#include +#include + +#include "cosmetics.hpp" +#include "menu.hpp" +#include "patch.hpp" +#include "preset.hpp" +#include "randomizer.hpp" +#include "settings.hpp" +#include "spoiler_log.hpp" +#include "location_access.hpp" +#include "debug.hpp" +#include +#include "randomizerTypes.h" + +namespace { +bool seedChanged; +uint16_t pastSeedLength; +std::vector presetEntries; +std::vector menuList; +Option* currentSetting; +Menu* currentMenu; +} // namespace + +void PrintTopScreen() { + SPDLOG_INFO("\x1b[2;11H%sOcarina of Time 3D Randomizer%s", CYAN, RESET); + SPDLOG_INFO("\x1b[3;18H%s%s-%s%s", CYAN, RANDOMIZER_VERSION, COMMIT_NUMBER, RESET); + SPDLOG_INFO("\x1b[4;10HA/B/D-pad: Navigate Menu\n"); + SPDLOG_INFO(" Select: Exit to Homebrew Menu\n"); + SPDLOG_INFO(" Y: New Random Seed\n"); + SPDLOG_INFO(" X: Input Custom Seed\n"); + SPDLOG_INFO("\x1b[11;7HCurrent Seed: %s", Settings::seed.c_str()); +} + +void MenuInit() { + Settings::InitSettings(); + + seedChanged = false; + pastSeedLength = Settings::seed.length(); + + Menu* main = new Menu("Main", MenuType::MainMenu, &Settings::mainMenu, MAIN_MENU); + menuList.push_back(main); + currentMenu = main; + + srand(time(NULL)); + + if (!CreatePresetDirectories()) { + printf("\x1b[20;5Failed to create preset directories."); + printf("\x1b[21;5Loading presets might crash."); + } + + // If cached presets exist, load them + LoadCachedSettings(); + LoadCachedCosmetics(); + // If Randomize all settings in a category is selected + // Re-randomize them + Settings::RandomizeAllSettings(); + + PrintTopScreen(); + + PrintMainMenu(); +} + +#define KEY_DUP 0 +#define KEY_DDOWN 1 +#define KEY_DLEFT 2 +#define KEY_DRIGHT 3 +#define KEY_A 4 +#define KEY_B 5 +#define KEY_Y 6 +#define KEY_X 7 + +void MoveCursor(uint32_t kDown, bool updatedByHeld) { + // Option sub menus need special checking for locked options + if (currentMenu->mode == OPTION_SUB_MENU) { + // Cancel if holding and reached first/last selectable option + if (updatedByHeld) { + bool noSelectableOption = true; + if (kDown & KEY_DUP) { + for (int i = currentMenu->menuIdx - 1; i >= 0; i--) { + if (!currentMenu->settingsList->at(i)->IsHidden() && + !currentMenu->settingsList->at(i)->IsLocked()) { + noSelectableOption = false; + break; + } + } + } + if (kDown & KEY_DDOWN) { + for (size_t i = currentMenu->menuIdx + 1; i < currentMenu->settingsList->size(); i++) { + if (!currentMenu->settingsList->at(i)->IsHidden() && + !currentMenu->settingsList->at(i)->IsLocked()) { + noSelectableOption = false; + break; + } + } + } + if (noSelectableOption) { + return; + } + } + // Loop through settings until an unlocked one is reached + do { + if ((kDown & KEY_DUP) != 0) { + currentMenu->menuIdx--; + } + if ((kDown & KEY_DDOWN) != 0) { + currentMenu->menuIdx++; + } + + // Bounds checking + if (currentMenu->menuIdx == currentMenu->settingsList->size()) { + currentMenu->menuIdx = 0; + } else if (currentMenu->menuIdx == 0xFFFF) { + currentMenu->menuIdx = static_cast(currentMenu->settingsList->size() - 1); + } + + currentSetting = currentMenu->settingsList->at(currentMenu->menuIdx); + } while (currentSetting->IsLocked() || currentSetting->IsHidden()); + } + // All other menus except reset-to-defaults confirmation + else if (currentMenu->mode != RESET_TO_DEFAULTS) { + // Cancel if holding and reached first/last menu + if (updatedByHeld) { + if ((kDown & KEY_DUP && currentMenu->menuIdx == 0) || + (kDown & KEY_DDOWN && currentMenu->menuIdx == currentMenu->itemsList->size() - 1)) { + return; + } + } + + if (kDown & KEY_DUP) { + currentMenu->menuIdx--; + } + if (kDown & KEY_DDOWN) { + currentMenu->menuIdx++; + } + + // Bounds checking + uint16_t max = -1; + if (currentMenu->mode == LOAD_PRESET || currentMenu->mode == DELETE_PRESET) { // Number of presets if applicable + max = presetEntries.size(); + } else if (currentMenu->mode == GENERATE_MODE) { // Generate menu: 2 options + max = 2; + } else if (currentMenu->itemsList != nullptr) { + max = currentMenu->itemsList->size(); // Default max: Number of items in menu + } + if (currentMenu->menuIdx == max) { + currentMenu->menuIdx = 0; + } else if (currentMenu->menuIdx == 0xFFFF) { + currentMenu->menuIdx = max - 1; + } + + // Scroll Check + if (currentMenu->menuIdx > currentMenu->settingBound + (MAX_SUBMENUS_ON_SCREEN - 1)) { + currentMenu->settingBound = currentMenu->menuIdx - (MAX_SUBMENUS_ON_SCREEN - 1); + } else if (currentMenu->menuIdx < currentMenu->settingBound) { + currentMenu->settingBound = currentMenu->menuIdx; + } + } +} + +void MenuUpdate(uint32_t kDown, bool updatedByHeld) { + // Check for menu change + // If user pressed A on a non-option, non-action menu, they're navigating to a new menu + if (kDown & KEY_A && currentMenu->mode != OPTION_SUB_MENU && currentMenu->type != MenuType::Action) { + if (currentMenu->itemsList->size() > currentMenu->menuIdx) { + Menu* newMenu; + newMenu = currentMenu->itemsList->at(currentMenu->menuIdx); + menuList.push_back(newMenu); + currentMenu = menuList.back(); + ModeChangeInit(); + kDown = 0; + } + // If they pressed B on any menu other than main, go backwards to the previous menu + } else if (kDown & KEY_B && currentMenu->mode != MAIN_MENU) { + // Want to reset generate menu when leaving + if (currentMenu->mode == POST_GENERATE) { + currentMenu->mode = GENERATE_MODE; + } + PrintTopScreen(); + menuList.pop_back(); + currentMenu = menuList.back(); + ModeChangeInit(); + kDown = 0; + } + + if (currentMenu->mode != GENERATE_MODE) { + + // New Random Seed + if (kDown & KEY_Y) { + pastSeedLength = Settings::seed.length(); + Settings::seed = std::to_string(rand()); + seedChanged = true; + } + + // Input Custom Seed + if (kDown & KEY_X) { + pastSeedLength = Settings::seed.length(); + Settings::seed = GetInput("Enter Seed"); + seedChanged = true; + } + + // Reprint seed if it changed + if (seedChanged) { + std::string spaces = ""; + spaces.append(pastSeedLength, ' '); + printf("\x1b[11;21H%s", spaces.c_str()); + printf("\x1b[11;21H%s", Settings::seed.c_str()); + seedChanged = false; + } + } + + // Print current menu (if applicable) + MoveCursor(kDown, updatedByHeld); // Move cursor, if applicable + if (currentMenu->mode == MAIN_MENU) { + PrintMainMenu(); + ClearDescription(); + } else if (currentMenu->mode == OPTION_SUB_MENU) { + UpdateOptionSubMenu(kDown); + PrintOptionSubMenu(); + } else if (currentMenu->mode == LOAD_PRESET) { + UpdatePresetsMenu(kDown); + PrintPresetsMenu(); + } else if (currentMenu->mode == DELETE_PRESET) { + UpdatePresetsMenu(kDown); + PrintPresetsMenu(); + } else if (currentMenu->mode == RESET_TO_DEFAULTS) { + UpdateResetToDefaultsMenu(kDown); + PrintResetToDefaultsMenu(); + } else if (currentMenu->mode == GENERATE_MODE) { + UpdateGenerateMenu(kDown); + if (currentMenu->mode != POST_GENERATE) { + PrintGenerateMenu(); + } + } else if (currentMenu->mode == SUB_MENU) { + PrintSubMenu(); + } +} + +void ModeChangeInit() { + if (currentMenu->mode == OPTION_SUB_MENU) { + // loop through until we reach an unlocked setting + while (currentMenu->settingsList->at(currentMenu->menuIdx)->IsLocked() || + currentMenu->settingsList->at(currentMenu->menuIdx)->IsHidden()) { + currentMenu->menuIdx++; + } + currentSetting = currentMenu->settingsList->at(currentMenu->menuIdx); + + } else if (currentMenu->mode == SAVE_PRESET) { + ClearDescription(); + if (SaveSpecifiedPreset(GetInput("Preset Name").substr(0, 19), OptionCategory::Setting)) { + printf("\x1b[24;5HPreset Saved!"); + printf("\x1b[26;5HPress B to return to the preset menu."); + } else { + printf("\x1b[24;5HFailed to save preset."); + printf("\x1b[26;5HPress B to return to the preset menu."); + } + + } else if (currentMenu->mode == LOAD_PRESET || currentMenu->mode == DELETE_PRESET) { + presetEntries = GetSettingsPresets(); + + } else if (currentMenu->mode == GENERATE_MODE) { + } +} + +void UpdateCustomCosmeticColors(uint32_t kDown) { + if (kDown & KEY_A) { + if (currentSetting->GetSelectedOptionText().compare(0, 8, Cosmetics::CUSTOM_COLOR_PREFIX) == 0) { + std::string newColor = GetInput("Enter a 6 digit hex color").substr(0, 6); + if (Cosmetics::ValidHexString(newColor)) { + currentSetting->SetSelectedOptionText(Cosmetics::CustomColorOptionText(newColor)); + } + } + } +} + +void UpdateOptionSubMenu(uint32_t kDown) { + if ((kDown & KEY_DRIGHT) != 0) { + currentSetting->NextOptionIndex(); + } + if ((kDown & KEY_DLEFT) != 0) { + currentSetting->PrevOptionIndex(); + } + + // Bounds checking + currentSetting->SanitizeSelectedOptionIndex(); + + currentSetting->SetVariable(); + Settings::ForceChange(kDown, currentSetting); + UpdateCustomCosmeticColors(kDown); +} + +void UpdatePresetsMenu(uint32_t kDown) { + // clear any potential message + ClearDescription(); + if (kDown & KEY_A && currentMenu->mode == LOAD_PRESET && !presetEntries.empty()) { + if (LoadPreset(presetEntries[currentMenu->menuIdx], OptionCategory::Setting)) { + Settings::ResolveExcludedLocationConflicts(); + for (Menu* menu : Settings::GetAllOptionMenus()) { + menu->ResetMenuIndex(); + } + printf("\x1b[24;5HPreset Loaded!"); + } else { + printf("\x1b[24;5HFailed to load preset."); + } + } else if (kDown & KEY_A && currentMenu->mode == DELETE_PRESET && !presetEntries.empty()) { + if (DeletePreset(presetEntries[currentMenu->menuIdx], OptionCategory::Setting)) { + presetEntries.erase(presetEntries.begin() + currentMenu->menuIdx); + if (currentMenu->menuIdx == presetEntries.size()) { // Catch when last preset is deleted + currentMenu->menuIdx--; + } + printf("\x1b[24;5HPreset Deleted."); + } else { + printf("\x1b[24;5HFailed to delete preset."); + } + } +} + +void UpdateResetToDefaultsMenu(uint32_t kDown) { + // clear any potential message + ClearDescription(); + if (kDown & KEY_A) { + Settings::SetDefaultSettings(); + printf("\x1b[24;5HSettings have been reset to defaults."); + } +} + +void UpdateGenerateMenu(uint32_t kDown) { + if ((kDown & KEY_A) != 0) { + Settings::PlayOption = currentMenu->menuIdx; + // GenerateRandomizer(); + // This is just a dummy mode to stop the prompt from appearing again + currentMenu->mode = POST_GENERATE; + } +} + +void PrintMainMenu() { + printf("\x1b[0;%dHMain Settings", 1 + (BOTTOM_WIDTH - 13) / 2); + + for (uint8_t i = 0; i < MAX_SUBMENUS_ON_SCREEN; i++) { + if (i >= Settings::mainMenu.size()) + break; + + Menu* menu = Settings::mainMenu[i]; + + uint8_t row = 3 + i; + // make the current menu green + if (currentMenu->menuIdx == i) { + printf("\x1b[%d;%dH%s>", row, 2, GREEN); + printf("\x1b[%d;%dH%s%s", row, 3, menu->name.c_str(), RESET); + } else { + printf("\x1b[%d;%dH%s", row, 3, menu->name.c_str()); + } + } +} + +void PrintOptionSubMenu() { + // bounds checking incase settings go off screen + // this is complicated to account for hidden settings and there's probably a better way to do it + uint16_t hiddenSettings = 0; + uint16_t visibleSettings = 0; + for (uint16_t i = currentMenu->settingBound; visibleSettings < MAX_SUBMENU_SETTINGS_ON_SCREEN; i++) { + if (i >= currentMenu->settingsList->size()) { + break; + } + if (currentMenu->settingsList->at(i)->IsHidden()) { + hiddenSettings++; + } else { + visibleSettings++; + } + } + bool isLastVisibleSetting = true; + for (size_t i = currentMenu->menuIdx + 1; i < currentMenu->settingsList->size(); i++) { + if (!currentMenu->settingsList->at(i)->IsHidden()) { + isLastVisibleSetting = false; + break; + } + } + if (currentMenu->menuIdx >= + currentMenu->settingBound - (isLastVisibleSetting ? 0 : 1) + MAX_SUBMENU_SETTINGS_ON_SCREEN + hiddenSettings) { + currentMenu->settingBound = currentMenu->menuIdx; + uint8_t offset = 0; + // skip over hidden settings + while (offset < MAX_SUBMENU_SETTINGS_ON_SCREEN - (isLastVisibleSetting ? 1 : 2)) { + currentMenu->settingBound--; + if (currentMenu->settingBound == 0) { + break; + } + offset += currentMenu->settingsList->at(currentMenu->settingBound)->IsHidden() ? 0 : 1; + } + } else if (currentMenu->menuIdx < currentMenu->settingBound + 1) { + currentMenu->settingBound = std::max(currentMenu->menuIdx - 1, 0); + } + + // print menu name + printf("\x1b[0;%dH%s", 1 + (BOTTOM_WIDTH - currentMenu->name.length()) / 2, currentMenu->name.c_str()); + + // keep count of hidden settings to not make blank spaces appear in the list + hiddenSettings = 0; + + for (uint8_t i = 0; i - hiddenSettings < MAX_SUBMENU_SETTINGS_ON_SCREEN; i++) { + // break if there are no more settings to print + if (i + currentMenu->settingBound >= currentMenu->settingsList->size()) + break; + + Option* setting = currentMenu->settingsList->at(i + currentMenu->settingBound); + + uint8_t row = 3 + ((i - hiddenSettings) * 2); + // make the current setting green + if (currentMenu->menuIdx == i + currentMenu->settingBound) { + printf("\x1b[%d;%dH%s>", row, 1, GREEN); + printf("\x1b[%d;%dH%s:", row, 2, setting->GetName().data()); + printf("\x1b[%d;%dH%s%s", row, 26, setting->GetSelectedOptionText().data(), RESET); + // dim to make a locked setting grey + } else if (setting->IsLocked()) { + printf("\x1b[%d;%dH%s%s:", row, 2, DIM, setting->GetName().data()); + printf("\x1b[%d;%dH%s%s", row, 26, setting->GetSelectedOptionText().data(), RESET); + // don't display hidden settings + } else if (setting->IsHidden()) { + hiddenSettings++; + continue; + } else { + printf("\x1b[%d;%dH%s:", row, 2, setting->GetName().data()); + printf("\x1b[%d;%dH%s", row, 26, setting->GetSelectedOptionText().data()); + } + } + + PrintOptionDescription(); +} + +void PrintSubMenu() { + printf("\x1b[0;%dH%s", 1 + (BOTTOM_WIDTH - currentMenu->name.length()) / 2, currentMenu->name.c_str()); + + for (uint8_t i = 0; i < MAX_SUBMENUS_ON_SCREEN; i++) { + if (i >= currentMenu->itemsList->size()) + break; + + uint8_t row = 3 + i; + // make the current menu green + if (currentMenu->menuIdx == currentMenu->settingBound + i) { + printf("\x1b[%d;%dH%s>", row, 2, GREEN); + printf("\x1b[%d;%dH%s%s", row, 3, currentMenu->itemsList->at(currentMenu->settingBound + i)->name.c_str(), + RESET); + } else { + printf("\x1b[%d;%dH%s", row, 3, currentMenu->itemsList->at(currentMenu->settingBound + i)->name.c_str()); + } + } +} + +void PrintPresetsMenu() { + if (presetEntries.empty()) { + printf("\x1b[10;4HNo Presets Detected!"); + printf("\x1b[12;4HPress B to return to the preset menu."); + return; + } + + if (currentMenu->mode == LOAD_PRESET) { + printf("\x1b[0;%dHSelect a Preset to Load", 1 + (BOTTOM_WIDTH - 23) / 2); + } else if (currentMenu->mode == DELETE_PRESET) { + printf("\x1b[0;%dHSelect a Preset to Delete", 1 + (BOTTOM_WIDTH - 25) / 2); + } + + for (uint8_t i = 0; i < MAX_SUBMENU_SETTINGS_ON_SCREEN; i++) { + if (i >= presetEntries.size()) + break; + + std::string preset = presetEntries[i]; + + uint8_t row = 3 + (i * 2); + // make the current preset green + if (currentMenu->menuIdx == i) { + printf("\x1b[%d;%dH%s>", row, 14, GREEN); + printf("\x1b[%d;%dH%s%s", row, 15, preset.c_str(), RESET); + } else { + printf("\x1b[%d;%dH%s", row, 15, preset.c_str()); + } + } +} + +void PrintResetToDefaultsMenu() { + printf("\x1b[10;4HPress A to reset to default settings."); + printf("\x1b[12;4HPress B to return to the preset menu."); +} + +void PrintGenerateMenu() { + printf("\x1b[3;%dHHow will you play?", 1+(BOTTOM_WIDTH-18)/2); + std::vector playOptions = {"3ds Console", "Citra Emulator"}; + + for (uint8_t i = 0; i < playOptions.size(); i++) { + + std::string option = playOptions[i]; + uint8_t row = 6 + (i * 2); + //make the current selection green + if (currentMenu->menuIdx == i) { + printf("\x1b[%d;%dH%s>", row, 14, GREEN); + printf("\x1b[%d;%dH%s%s", row, 15, option.c_str(), RESET); + } else { + printf("\x1b[%d;%dH%s", row, 15, option.c_str()); + } + } +} + +void ClearDescription() { + //clear the previous description + std::string spaces = ""; + spaces.append(9 * TOP_WIDTH, ' '); + printf("\x1b[22;0H%s", spaces.c_str()); +} + +void PrintOptionDescription() { + ClearDescription(); + std::string_view description = currentSetting->GetSelectedOptionDescription(); + + printf("\x1b[22;0H%s", description.data()); +} + +std::string GenerateRandomizer(std::unordered_map cvarSettings) { + // if a blank seed was entered, make a random one + srand(time(NULL)); + Settings::seed = std::to_string(rand()); + + int ret = Playthrough::Playthrough_Init(std::hash{}(Settings::seed), cvarSettings); + if (ret < 0) { + if (ret == -1) { // Failed to generate after 5 tries + printf("\n\nFailed to generate after 5 tries.\nPress B to go back to the menu.\nA different seed might be " + "successful."); + SPDLOG_INFO("\nRANDOMIZATION FAILED COMPLETELY. PLZ FIX\n"); + return ""; + } else { + printf("\n\nError %d with fill.\nPress Select to exit or B to go back to the menu.\n", ret); + return ""; + } + } + + // Restore settings that were set to a specific value for vanilla logic + if (Settings::Logic.Is(LOGIC_VANILLA)) { + for (Option* setting : Settings::vanillaLogicDefaults) { + setting->RestoreDelayedOption(); + } + Settings::Keysanity.RestoreDelayedOption(); + } + + return "./Randomizer/" + Settings::seed + ".json"; +} + +std::string GetInput(const char* hintText) { + return std::string(); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/menu.hpp b/soh/soh/Enhancements/randomizer/3drando/menu.hpp new file mode 100644 index 000000000..2f3933135 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/menu.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include "randomizerTypes.h" + +#define MAIN_MENU 0 +#define OPTION_SUB_MENU 1 +#define SUB_MENU 2 +#define GENERATE_MODE 3 +#define LOAD_PRESET 4 +#define SAVE_PRESET 5 +#define DELETE_PRESET 6 +#define POST_GENERATE 7 +#define RESET_TO_DEFAULTS 8 + +#define MAX_SUBMENUS_ON_SCREEN 27 +#define MAX_SUBMENU_SETTINGS_ON_SCREEN 13 +#define TOP_WIDTH 50 +#define BOTTOM_WIDTH 40 +#define SCREEN_HEIGHT 30 + +#define RESET "\x1b[0m" +#define DIM "\x1b[2m" + +#define BLACK "\x1b[30m" +#define RED "\x1b[31m" +#define GREEN "\x1b[32m" +#define YELLOW "\x1b[33m" +#define BLUE "\x1b[34m" +#define MEGANTA "\x1b[35m" +#define CYAN "\x1b[36m" +#define WHITE "\x1b[37m" + +void ModeChangeInit(); +void UpdateOptionSubMenu(uint32_t kDown); +void UpdatePresetsMenu(uint32_t kdown); +void UpdateResetToDefaultsMenu(uint32_t kdown); +void UpdateGenerateMenu(uint32_t kDown); +void PrintMainMenu(); +void PrintOptionSubMenu(); +void PrintSubMenu(); +void PrintPresetsMenu(); +void PrintResetToDefaultsMenu(); +void PrintGenerateMenu(); +void ClearDescription(); +void PrintOptionDescription(); +std::string GenerateRandomizer(std::unordered_map cvarSettings); +std::string GetInput(const char* hintText); + +extern void MenuInit(); +extern void MenuUpdate(uint32_t kDown, bool updatedByHeld); diff --git a/soh/soh/Enhancements/randomizer/3drando/music.cpp b/soh/soh/Enhancements/randomizer/3drando/music.cpp new file mode 100644 index 000000000..6171d2a0e --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/music.cpp @@ -0,0 +1,128 @@ +#include "music.hpp" +#include + +namespace Music { + const std::array seqTypesMusic = { + /* NA_BGM_FIELD */ SEQ_BGM_WORLD, + /* NA_BGM_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_KAKARIKO_ADULT */ SEQ_BGM_WORLD, + /* NA_BGM_ENEMY */ SEQ_NOSHUFFLE, // Temporarily unshuffled: Override plays incorrect in some areas, like Lake Hylia, by continuously repeating the start + /* NA_BGM_BOSS00 */ SEQ_BGM_BATTLE, + /* NA_BGM_FAIRY_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_MARKET */ SEQ_BGM_WORLD, + /* NA_BGM_TITLE */ SEQ_BGM_WORLD, + /* NA_BGM_LINK_HOUSE */ SEQ_BGM_WORLD, + /* NA_BGM_GAME_OVER */ SEQ_FANFARE, + /* NA_BGM_BOSS_CLEAR */ SEQ_FANFARE, + /* NA_BGM_ITEM_GET */ SEQ_FANFARE, + /* NA_BGM_OPENING_GANON */ SEQ_FANFARE, + /* NA_BGM_HEART_GET */ SEQ_FANFARE, + /* NA_BGM_OCA_LIGHT */ SEQ_OCARINA, + /* NA_BGM_BUYO_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_KAKARIKO_KID */ SEQ_BGM_WORLD, + /* NA_BGM_GODESS */ SEQ_BGM_EVENT, + /* NA_BGM_HIME */ SEQ_BGM_EVENT, + /* NA_BGM_FIRE_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_OPEN_TRE_BOX */ SEQ_FANFARE, + /* NA_BGM_FORST_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_HIRAL_GARDEN */ SEQ_BGM_WORLD, + /* NA_BGM_GANON_TOWER */ SEQ_BGM_WORLD, + /* NA_BGM_RONRON */ SEQ_BGM_WORLD, + /* NA_BGM_GORON */ SEQ_BGM_WORLD, + /* NA_BGM_SPIRIT_STONE */ SEQ_FANFARE, + /* NA_BGM_OCA_FLAME */ SEQ_OCARINA, + /* NA_BGM_OCA_WIND */ SEQ_OCARINA, + /* NA_BGM_OCA_WATER */ SEQ_OCARINA, + /* NA_BGM_OCA_SOUL */ SEQ_OCARINA, + /* NA_BGM_OCA_DARKNESS */ SEQ_OCARINA, + /* NA_BGM_MIDDLE_BOSS */ SEQ_BGM_ERROR, + /* NA_BGM_S_ITEM_GET */ SEQ_FANFARE, + /* NA_BGM_SHRINE_OF_TIME */ SEQ_BGM_WORLD, + /* NA_BGM_EVENT_CLEAR */ SEQ_FANFARE, + /* NA_BGM_KOKIRI */ SEQ_BGM_WORLD, + /* NA_BGM_OCA_YOUSEI */ SEQ_FANFARE, + /* NA_BGM_MAYOIMORI */ SEQ_BGM_WORLD, + /* NA_BGM_SOUL_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_HORSE */ SEQ_BGM_EVENT, + /* NA_BGM_HORSE_GOAL */ SEQ_FANFARE, + /* NA_BGM_INGO */ SEQ_BGM_WORLD, + /* NA_BGM_MEDAL_GET */ SEQ_FANFARE, + /* NA_BGM_OCA_SARIA */ SEQ_OCARINA, + /* NA_BGM_OCA_EPONA */ SEQ_OCARINA, + /* NA_BGM_OCA_ZELDA */ SEQ_OCARINA, + /* NA_BGM_OCA_SUNMOON */ SEQ_NOSHUFFLE, /* Remove Sun's Song from the Ocarina pool for now due to bugs */ + /* NA_BGM_OCA_TIME */ SEQ_OCARINA, + /* NA_BGM_OCA_STORM */ SEQ_OCARINA, + /* NA_BGM_NAVI */ SEQ_BGM_EVENT, + /* NA_BGM_DEKUNOKI */ SEQ_BGM_EVENT, + /* NA_BGM_FUSHA */ SEQ_BGM_WORLD, + /* NA_BGM_HIRAL_DEMO */ SEQ_NOSHUFFLE, + /* NA_BGM_MINI_GAME */ SEQ_BGM_EVENT, + /* NA_BGM_SEAK */ SEQ_BGM_EVENT, + /* NA_BGM_ZORA */ SEQ_BGM_WORLD, + /* NA_BGM_APPEAR */ SEQ_FANFARE, + /* NA_BGM_ADULT_LINK */ SEQ_BGM_EVENT, + /* NA_BGM_MASTER_SWORD */ SEQ_FANFARE, + /* NA_BGM_INTRO_GANON */ SEQ_BGM_EVENT, + /* NA_BGM_SHOP */ SEQ_BGM_WORLD, + /* NA_BGM_KENJA */ SEQ_BGM_EVENT, + /* NA_BGM_FILE_SELECT */ SEQ_NOSHUFFLE, + /* NA_BGM_ICE_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_GATE_OPEN */ SEQ_NOSHUFFLE, + /* NA_BGM_OWL */ SEQ_BGM_EVENT, + /* NA_BGM_DARKNESS_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_AQUA_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_BRIDGE */ SEQ_NOSHUFFLE, + /* NA_BGM_SARIA */ SEQ_NOSHUFFLE, + /* NA_BGM_GERUDO */ SEQ_BGM_WORLD, + /* NA_BGM_DRUGSTORE */ SEQ_BGM_WORLD, + /* NA_BGM_KOTAKE_KOUME */ SEQ_BGM_EVENT, + /* NA_BGM_ESCAPE */ SEQ_BGM_EVENT, + /* NA_BGM_UNDERGROUND */ SEQ_BGM_WORLD, + /* NA_BGM_GANON_BATTLE_1 */ SEQ_BGM_BATTLE, + /* NA_BGM_GANON_BATTLE_2 */ SEQ_BGM_BATTLE, + /* NA_BGM_END_DEMO */ SEQ_NOSHUFFLE, + /* NA_BGM_STAFF_1 */ SEQ_NOSHUFFLE, + /* NA_BGM_STAFF_2 */ SEQ_NOSHUFFLE, + /* NA_BGM_STAFF_3 */ SEQ_NOSHUFFLE, + /* NA_BGM_STAFF_4 */ SEQ_NOSHUFFLE, + /* NA_BGM_BOSS01 */ SEQ_BGM_BATTLE, + /* NA_BGM_MINI_GAME_2 */ SEQ_BGM_ERROR, + }; + + std::array seqOverridesMusic; + + /* Initializes the list of music overrides to unshuffled */ + void InitMusicRandomizer() { + for(int i = 0; i < SEQ_COUNT; i++) + seqOverridesMusic[i] = BGM_BASE + i; + } + + /* Shuffles the sequences grouping them by type */ + /* type is a bitmask of SeqType */ + void ShuffleSequences(int type) { + std::vector seqs; + + // Get all sequences of the desired type(s) into a vector + for (int i = 0; i < SEQ_COUNT; i++) { + if (seqTypesMusic[i] & type) { + seqs.push_back(seqOverridesMusic[i]); + } + } + + // Shuffle the vector... + for (std::size_t i = 0; i < seqs.size(); i++) + { + std::swap(seqs[i], seqs[rand() % seqs.size()]); + } + + // ...and feed it back into the overrides array + for (int i = 0; i < SEQ_COUNT; i++) { + if (seqTypesMusic[i] & type) + { + seqOverridesMusic[i] = seqs.back(); + seqs.pop_back(); + } + } + } +} // namespace Music diff --git a/soh/soh/Enhancements/randomizer/3drando/music.hpp b/soh/soh/Enhancements/randomizer/3drando/music.hpp new file mode 100644 index 000000000..90f7fc9dd --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/music.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +namespace Music { + const uint32_t BGM_BASE = 0x1000585; + const int SEQ_COUNT = 85; + + enum SeqType { + SEQ_NOSHUFFLE = 0, + SEQ_BGM_WORLD = 1 << 0, + SEQ_BGM_EVENT = 1 << 1, + SEQ_BGM_BATTLE = 1 << 2, + SEQ_OCARINA = 1 << 3, + SEQ_FANFARE = 1 << 4, + // A soundtrack in this category has the issue where if another soundtrack that isn't + // in this category overrides it, it will keep playing when it should be stopped. + // For example when beating a mini-boss or finishing the zora diving game. + SEQ_BGM_ERROR = 1 << 5, + }; + + extern const std::array seqTypesMusic; + extern std::array seqOverridesMusic; + + void InitMusicRandomizer(); + void ShuffleSequences(int type); +} // namespace Music diff --git a/soh/soh/Enhancements/randomizer/3drando/patch.cpp b/soh/soh/Enhancements/randomizer/3drando/patch.cpp new file mode 100644 index 000000000..59ba85e1f --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/patch.cpp @@ -0,0 +1,25 @@ +#include "patch.hpp" + +#include "cosmetics.hpp" +#include "custom_messages.hpp" +#include "music.hpp" +#include "sound_effects.hpp" +#include "shops.hpp" +#include "spoiler_log.hpp" +#include "entrance.hpp" +#include "hints.hpp" + +#include +#include +#include +#include +#include +#include + +// For specification on the IPS file format, visit: https://zerosoft.zophar.net/ips.php + +using FILEPtr = std::unique_ptr; + +void WriteFloatToBuffer(std::vector& buffer, float f, size_t offset) { + memcpy(buffer.data() + offset, &f, sizeof(float)); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/patch.hpp b/soh/soh/Enhancements/randomizer/3drando/patch.hpp new file mode 100644 index 000000000..3dd95d8d4 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/patch.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "playthrough.hpp" +#include "settings.hpp" + +#define V_TO_P(addr) (addr - 0x100000) +#define P_TO_V(offset) (offset + 0x100000) +#define PATCH_CONSOLE 0 +#define PATCH_CITRA 1 +#define PATCH_SIZE_MAX 65535 + +bool WriteAllPatches(); diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp new file mode 100644 index 000000000..772cd4a5f --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp @@ -0,0 +1,97 @@ +#include "playthrough.hpp" + +#include "custom_messages.hpp" +#include "fill.hpp" +#include "location_access.hpp" +#include "logic.hpp" +#include "random.hpp" +#include "spoiler_log.hpp" +#include "randomizerTypes.h" + +namespace Playthrough { + +int Playthrough_Init(uint32_t seed, std::unordered_map cvarSettings) { + // initialize the RNG with just the seed incase any settings need to be + // resolved to something random + Random_Init(seed); + + overrides.clear(); + CustomMessages::ClearMessages(); + ItemReset(); + HintReset(); + Areas::AccessReset(); + + Settings::UpdateSettings(cvarSettings); + // once the settings have been finalized turn them into a string for hashing + std::string settingsStr; + for (Menu* menu : Settings::GetAllOptionMenus()) { + // don't go through non-menus + if (menu->mode != OPTION_SUB_MENU) { + continue; + } + + for (size_t i = 0; i < menu->settingsList->size(); i++) { + Option* setting = menu->settingsList->at(i); + if (setting->IsCategory(OptionCategory::Setting)) { + settingsStr += setting->GetSelectedOptionText(); + } + } + } + unsigned int finalHash = std::hash{}(Settings::seed + settingsStr); + Random_Init(finalHash); + + Logic::UpdateHelpers(); + + if (Settings::Logic.Is(LOGIC_VANILLA)) { + VanillaFill(); // Just place items in their vanilla locations + } else { // Fill locations with logic + int ret = Fill(); + if (ret < 0) { + return ret; + } + } + + GenerateHash(); + WriteIngameSpoilerLog(); + + if (Settings::GenerateSpoilerLog) { + // write logs + printf("\x1b[11;10HWriting Spoiler Log..."); + if (SpoilerLog_Write(cvarSettings[RSK_LANGUAGE])) { + printf("Done"); + } else { + printf("Failed"); + } +#ifdef ENABLE_DEBUG + printf("\x1b[11;10HWriting Placement Log..."); + if (PlacementLog_Write()) { + printf("Done\n"); + } else { + printf("Failed\n"); + } +#endif + } + + playthroughLocations.clear(); + wothLocations.clear(); + playthroughBeatable = false; + + return 1; +} + +// used for generating a lot of seeds at once +int Playthrough_Repeat(int count /*= 1*/) { + printf("\x1b[0;0HGENERATING %d SEEDS", count); + uint32_t repeatedSeed = 0; + for (int i = 0; i < count; i++) { + repeatedSeed = rand() % 0xFFFFFFFF; + Settings::seed = std::to_string(repeatedSeed); + CitraPrint("testing seed: " + Settings::seed); + ClearProgress(); + // Playthrough_Init(std::hash{}(Settings::seed)); + printf("\x1b[15;15HSeeds Generated: %d\n", i + 1); + } + + return 1; +} +} // namespace Playthrough \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.hpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.hpp new file mode 100644 index 000000000..5fd0e19ff --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.hpp @@ -0,0 +1,9 @@ +#pragma once +#include +#include +#include "item_location.hpp" + +namespace Playthrough { +int Playthrough_Init(uint32_t seed, std::unordered_map cvarSettings); + int Playthrough_Repeat(int count = 1); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/pool_functions.hpp b/soh/soh/Enhancements/randomizer/3drando/pool_functions.hpp new file mode 100644 index 000000000..1cb96c746 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/pool_functions.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include + +template +static void erase_if(std::vector& vector, Predicate pred) { + vector.erase(std::remove_if(begin(vector), end(vector), pred), end(vector)); +} + +template +std::vector FilterFromPool(std::vector& vector, Predicate pred, bool eraseAfterFilter = false) { + std::vector filteredPool = {}; + std::copy_if(vector.begin(), vector.end(), std::back_inserter(filteredPool), pred); + + if (eraseAfterFilter) { + erase_if(vector, pred); + } + + return filteredPool; +} + +template +std::vector FilterAndEraseFromPool(std::vector& vector, Predicate pred) { + return FilterFromPool(vector, pred, true); +} + +template +void AddElementsToPool(std::vector& toPool, const FromPool& fromPool) { + toPool.insert(toPool.end(), std::cbegin(fromPool), std::cend(fromPool)); +} + +template +bool ElementInContainer(T& element, const Container& container) { + return std::find(container.begin(), container.end(), element) != container.end(); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/preset.cpp b/soh/soh/Enhancements/randomizer/3drando/preset.cpp new file mode 100644 index 000000000..ab036ab14 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/preset.cpp @@ -0,0 +1,202 @@ +#include "preset.hpp" + +#include +#include +#include +#include +#include +#include + +#include "category.hpp" +#include "settings.hpp" +#include "tinyxml2.h" +#include "utils.hpp" + +namespace fs = std::filesystem; + +static const std::string CACHED_SETTINGS_FILENAME = "CACHED_SETTINGS"; +static const std::string CACHED_COSMETICS_FILENAME = "CACHED_COSMETICS"; + +static std::string_view GetBasePath(OptionCategory category) { + static constexpr std::array paths{ + "/3ds/presets/oot3dr/settings/", + "/3ds/presets/oot3dr/cosmetics/", + }; + + switch(category) { + case OptionCategory::Setting : + case OptionCategory::Cosmetic : + return paths[static_cast(category)]; + case OptionCategory::Toggle : + break; + } + return ""; +} + +//Creates preset directories if they don't exist +bool CreatePresetDirectories() { + //Create the 3ds directory if it doesn't exist + std::filesystem::create_directory("./3ds"); + //Create the presets directory if it doesn't exist + std::filesystem::create_directory("./3ds/presets"); + //Create the oot3d directory if it doesn't exist + std::filesystem::create_directory("./3ds/presets/oot3dr"); + //Create the cosmetics directory if it doesn't exist + std::filesystem::create_directory("./3ds/presets/oot3dr/cosmetics"); + //Create the settings directory if it doesn't exist + std::filesystem::create_directory("./3ds/presets/oot3dr/settings"); + + return true; +} + +//Gets the preset filenames +std::vector GetSettingsPresets() { + std::vector presetEntries = {}; + for (const auto& entry : fs::directory_iterator(GetBasePath(OptionCategory::Setting))) { + if(entry.path().stem().string() != CACHED_SETTINGS_FILENAME) { + presetEntries.push_back(entry.path().stem().string()); + } + } + return presetEntries; +} + +static std::string PresetPath(std::string_view presetName, OptionCategory category) { + return std::string(GetBasePath(category)).append(presetName).append(".xml"); +} + +// Presets are now saved as XML files using the tinyxml2 library. +// Documentation: https://leethomason.github.io/tinyxml2/index.html +bool SavePreset(std::string_view presetName, OptionCategory category) { + using namespace tinyxml2; + + XMLDocument preset = XMLDocument(false); + + // Create and insert the XML declaration + preset.InsertEndChild(preset.NewDeclaration()); + + // Create the root node + XMLElement* rootNode = preset.NewElement("settings"); + preset.InsertEndChild(rootNode); + + for (Menu* menu : Settings::GetAllOptionMenus()) { + if (menu->mode != OPTION_SUB_MENU) { + continue; + } + for (const Option* setting : *menu->settingsList) { + if (!setting->IsCategory(category)) { + continue; + } + + XMLElement* newSetting = rootNode->InsertNewChildElement("setting"); + newSetting->SetAttribute("name", RemoveLineBreaks(setting->GetName()).c_str()); + newSetting->SetText(setting->GetSelectedOptionText().c_str()); + } + } + + XMLError e = preset.SaveFile(PresetPath(presetName, category).c_str()); + return e == XML_SUCCESS; +} + +//Read the preset XML file +bool LoadPreset(std::string_view presetName, OptionCategory category) { + using namespace tinyxml2; + + XMLDocument preset; + XMLError e = preset.LoadFile(PresetPath(presetName, category).c_str()); + if (e != XML_SUCCESS) { + return false; + } + + XMLElement* rootNode = preset.RootElement(); + if (strcmp(rootNode->Name(), "settings") != 0) { + // We do not have our root node, so it may be the old structure. We don't support that one anymore. + return false; + } + + XMLElement* curNode = rootNode->FirstChildElement(); + + for (Menu* menu : Settings::GetAllOptionMenus()) { + if (menu->mode != OPTION_SUB_MENU) { + continue; + } + + for (Option* setting : *menu->settingsList) { + if (!setting->IsCategory(category)) { + continue; + } + + // Since presets are saved linearly, we can simply loop through the nodes as + // we loop through the settings to find most of the matching elements. + const std::string& settingToFind = RemoveLineBreaks(setting->GetName()); + if (settingToFind == RemoveLineBreaks(curNode->Attribute("name"))) { + setting->SetSelectedIndexByString(curNode->GetText()); + curNode = curNode->NextSiblingElement(); + } else { + // If the current setting and element don't match, then search + // linearly from the beginning. This will get us back on track if the + // next setting and element line up with each other. + curNode = rootNode->FirstChildElement(); + while (curNode != nullptr) { + if (settingToFind == RemoveLineBreaks(curNode->Attribute("name"))) { + setting->SetSelectedIndexByString(curNode->GetText()); + curNode = curNode->NextSiblingElement(); + break; + } + curNode = curNode->NextSiblingElement(); + } + } + + // Reset to the beginning if we reached the end. + if (curNode == nullptr) { + curNode = rootNode->FirstChildElement(); + } + } + } + return true; +} + +//Delete the selected preset +bool DeletePreset(std::string_view presetName, OptionCategory category) { + const std::string filepath = PresetPath(presetName, category); + + std::filesystem::remove(filepath); + + return true; +} + +//Saves the new preset to a file +bool SaveSpecifiedPreset(std::string_view presetName, OptionCategory category) { + //don't save if the user cancelled + if (presetName.empty()) { + return false; + } + return SavePreset(presetName, category); +} + +void SaveCachedSettings() { + SavePreset(CACHED_SETTINGS_FILENAME, OptionCategory::Setting); +} + +void LoadCachedSettings() { + //If cache file exists, load it + for (const auto& entry : fs::directory_iterator(GetBasePath(OptionCategory::Setting))) { + if(entry.path().stem().string() == CACHED_SETTINGS_FILENAME) { + //File exists, open + LoadPreset(CACHED_SETTINGS_FILENAME, OptionCategory::Setting); + } + } +} + +bool SaveCachedCosmetics() { + return SavePreset(CACHED_COSMETICS_FILENAME, OptionCategory::Cosmetic); +} + +void LoadCachedCosmetics() { + //If cache file exists, load it + for (const auto& entry : fs::directory_iterator(GetBasePath(OptionCategory::Cosmetic))) { + if(entry.path().stem().string() == CACHED_COSMETICS_FILENAME) { + //File exists, open + LoadPreset(CACHED_COSMETICS_FILENAME, OptionCategory::Cosmetic); + } + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/preset.hpp b/soh/soh/Enhancements/randomizer/3drando/preset.hpp new file mode 100644 index 000000000..64536757c --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/preset.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +enum class OptionCategory; + +bool CreatePresetDirectories(); +std::vector GetSettingsPresets(); +bool SavePreset(std::string_view presetName, OptionCategory category); +bool LoadPreset(std::string_view presetName, OptionCategory category); +bool DeletePreset(std::string_view presetName, OptionCategory category); +bool SaveSpecifiedPreset(std::string_view presetName, OptionCategory category); +void SaveCachedSettings(); +void LoadCachedSettings(); +bool SaveCachedCosmetics(); +void LoadCachedCosmetics(); diff --git a/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp b/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp new file mode 100644 index 000000000..a936b6567 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp @@ -0,0 +1,27 @@ +#include "menu.hpp" +#include "hint_list.hpp" +#include "item_list.hpp" +#include "item_location.hpp" +#include "location_access.hpp" +#include "rando_main.hpp" +// #include +#include +#include + +#define TICKS_PER_SEC 268123480.0 + +void RandoMain::GenerateRando(std::unordered_map cvarSettings) { + HintTable_Init(); + ItemTable_Init(); + LocationTable_Init(); + + // std::string settingsFileName = "./randomizer/latest_settings.json"; + // CVar_SetString("gLoadedPreset", settingsFileName.c_str()); + + std::string fileName = GenerateRandomizer(cvarSettings); + CVar_SetString("gSpoilerLog", fileName.c_str()); + + Game::SaveSettings(); + Game::LoadSettings(); + CVar_SetS32("gNewSeedGenerated", 1); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/rando_main.hpp b/soh/soh/Enhancements/randomizer/3drando/rando_main.hpp new file mode 100644 index 000000000..523620d1e --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/rando_main.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace RandoMain { +void GenerateRando(std::unordered_map cvarSettings); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/random.cpp b/soh/soh/Enhancements/randomizer/3drando/random.cpp new file mode 100644 index 000000000..4cd5c85f1 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/random.cpp @@ -0,0 +1,29 @@ +#include "random.hpp" + +#include + +static bool init = false; +static std::mt19937_64 generator; + +//Initialize with seed specified +void Random_Init(uint32_t seed) { + init = true; + generator = std::mt19937_64{seed}; +} + +//Returns a random integer in range [min, max-1] +uint32_t Random(int min, int max) { + if (!init) { + //No seed given, get a random number from device to seed + const auto seed = static_cast(std::random_device{}()); + Random_Init(seed); + } + std::uniform_int_distribution distribution(min, max-1); + return distribution(generator); +} + +//Returns a random floating point number in [0.0, 1.0] +double RandomDouble() { + std::uniform_real_distribution distribution(0.0, 1.0); + return distribution(generator); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/random.hpp b/soh/soh/Enhancements/randomizer/3drando/random.hpp new file mode 100644 index 000000000..c8ccf0f50 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/random.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include +#include + +void Random_Init(uint32_t seed); +uint32_t Random(int min, int max); +double RandomDouble(); + +//Get a random element from a vector or array +template +T RandomElement(std::vector& vector, bool erase) { + const auto idx = Random(0, vector.size()); + const T selected = vector[idx]; + if (erase) { + vector.erase(vector.begin() + idx); + } + return selected; +} +template +auto& RandomElement(Container& container) { + return container[Random(0, std::size(container))]; +} +template +const auto& RandomElement(const Container& container) { + return container[Random(0, std::size(container))]; +} + +//Shuffle items within a vector or array +template +void Shuffle(std::vector& vector) { + for (std::size_t i = 0; i + 1 < vector.size(); i++) + { + std::swap(vector[i], vector[Random(i, vector.size())]); + } +} +template +void Shuffle(std::array& arr) { + for (std::size_t i = 0; i + 1 < arr.size(); i++) + { + std::swap(arr[i], arr[Random(i, arr.size())]); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/randomizer.hpp b/soh/soh/Enhancements/randomizer/3drando/randomizer.hpp new file mode 100644 index 000000000..1b02c9037 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/randomizer.hpp @@ -0,0 +1,4 @@ +#pragma once + +#define RANDOMIZER_VERSION "v3.1" +#define COMMIT_NUMBER "develop" diff --git a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp new file mode 100644 index 000000000..edca583e5 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp @@ -0,0 +1,1696 @@ +#include "setting_descriptions.hpp" + +//Setting descriptions are mostly copied from OoT Randomizer tooltips with minor edits + +/*------------------------------ +| RANDOMIZE SETTINGS | *SCREEN WIDTH* +------------------------------*/ /*--------------------------------------------------*/ +string_view openRandomize = "Randomize all Open Settings."; // +string_view worldRandomize = "Randomize all World Settings except for MQ\n" // + "dungeons."; // +string_view shuffleRandomize = "Randomize all Shuffle Settings."; // +string_view dungeonRandomize = "Randomize all Dungeon Shuffle Settings."; // + // +/*------------------------------ // +| LOGIC | // +------------------------------*/ // +string_view logicGlitchless = "No glitches are required, but may require some\n" // + "minor tricks. Add minor tricks to consider for\n" // + "logic in Logical Tricks."; // +string_view logicGlitched = "The glitches you enable at the set difficulty\n" // + "or below may be required.\n" // + "\n" // + "In development, but still usable."; // +string_view logicNoLogic = "Maximize randomization, All locations are\n" // + "considered available. MAY BE IMPOSSIBLE TO BEAT.";// +string_view logicVanilla = "For those who want to play the game normally but\n" + "with the improvements of the randomizer. All\n" // + "locations will contain their vanilla items. This\n" + "supercedes all item shuffle, logic, hint, and\n" // + "item pool settings. You can still use non-vanilla\n" + "world settings such as adult start or entrance\n" // + "shuffle, but the game may require glitches to\n" // + "complete if you do."; // +/*------------------------------ // +| FOREST | // +------------------------------*/ // +string_view forestOpen = "Mido no longer blocks the path to the Deku Tree,\n" + "and the Kokiri boy no longer blocks the path out\n" + "of the forest."; // +string_view forestClosed = "Beating Deku Tree is logically required to leave\n" + "the forest area (Kokiri Forest/Lost Woods/Sacred\n" + "Forest Meadow/Deku Tree), while the Kokiri Sword\n" + "and a Deku Shield are required to access the Deku\n" + "Tree. Items needed for this will be guaranteed\n" // + "inside the forest area. This setting is\n" // + "incompatible with starting as adult."; // +string_view forestClosedDeku = "The Kokiri boy no longer blocks the path out of\n"// + "the forest, but Mido still blocks the path to the\n" + "Deku Tree, requiring Kokiri Sword and Deku Shield\n" + "to access the Deku Tree."; // +/*------------------------------ // +| KAKARIKO GATE | // +------------------------------*/ // +string_view kakGateOpen = "The gate is always open instead of needing\n" // + "Zelda's Letter. The Happy Mask Shop opens upon\n" // + "obtaining Zelda's Letter without needing to show\n" + "it to the guard."; // +string_view kakGateClosed = "The gate and the Happy Mask Shop both remain\n" // + "closed until showing Zelda's Letter to the guard\n" + "in Kakariko."; // +/*------------------------------ // +| DOOR OF TIME | // +------------------------------*/ // +string_view doorOfTimeOpen = "The Door of Time starts opened instead of needing\n" + "to play the Song of Time."; // +string_view doorOfTimeClosed = "Only an Ocarina and the Song of Time need to be\n"// + "found to open the Door of Time."; // +string_view doorOfTimeIntended = "The Ocarina of Time, the Song of Time, and\n" // + "all Spiritual Stones need to be found to\n" // + "open the Door of Time."; // +/*------------------------------ // +| ZORA'S FOUNTAIN | // +------------------------------*/ // +string_view fountainNormal = "King Zora obstructs the way to Zora's Fountain.\n"// + "Ruto's Letter must be shown as child in order to\n" + "move him for both eras."; // +string_view fountainAdult = "King Zora is always moved in the adult era. This\n" + "means Ruto's Letter is only required to access\n" // + "Zora's Fountain as child."; // +string_view fountainOpen = "King Zora starts as moved in both the child and\n"// + "adult eras. This also removes Ruto's Letter from\n" + "the pool since it can't be used."; // +/*------------------------------ // +| GERUDO FORTRESS | // +------------------------------*/ // +string_view gerudoNormal = "All 4 carpenters can be rescued."; // +string_view gerudoFast = "Only the bottom left carpenter must be rescued."; // +string_view gerudoOpen = "The carpenters are rescued from the start of the\n" + "game, and if Shuffle Gerudo Card is disabled,\n" // + "the player starts with the Gerudo Card in the\n" // + "inventory allowing access to Gerudo Training\n" // + "Grounds."; // +/*------------------------------ // +| RAINBOW BRIDGE | // +------------------------------*/ // +string_view bridgeOpen = "The Rainbow Bridge is always present."; // +string_view bridgeVanilla = "The Rainbow Bridge requires Shadow and Spirit\n" // + "Medallions as well as Light Arrows."; // +string_view bridgeStones = "The Rainbow Bridge requires collecting a\n" // + "configurable number of Spiritual Stones."; // +string_view bridgeMedallions = "The Rainbow Bridge requires collecting a\n" // + "configurable number of Medallions."; // +string_view bridgeRewards = "The Rainbow Bridge requires collecting a\n" // + "configurable number of Dungeon Rewards."; // +string_view bridgeDungeons = "The Rainbow Bridge requires completing a\n" // + "configurable number of Dungeons.\n" // + "\n" // + "Dungeons are considered complete when Link steps\n" + "into the blue warp at the end of them."; // +string_view bridgeTokens = "The Rainbow Bridge requires collecting a\n" // + "configurable number of Gold Skulltula Tokens."; // +/*------------------------------ // +| BRIDGE CONDITIONS | // +------------------------------*/ // +string_view bridgeStoneCountDesc = "Set the number of Spiritual Stones required to\n" // + "spawn the Rainbow Bridge."; // +string_view bridgeMedallionCountDesc = "Set the number of Medallions required to spawn the" + "Rainbow Bridge."; // +string_view bridgeRewardCountDesc = "Set the number of Dungeon Rewards (Spiritual\n" // + "Stones and Medallions) required to spawn the\n" // + "Rainbow Bridge."; // +string_view bridgeDungeonCountDesc = "Set the number of completed dungeons required to\n" + "spawn the Rainbow Bridge."; // +string_view bridgeTokenCountDesc = "Set the number of Gold Skulltula Tokens required\n" + "to spawn the Rainbow Bridge."; // +/*------------------------------ // +| RANDOM GANONS TRIALS | // +------------------------------*/ // +string_view randomGanonsTrialsDesc = "Sets a random number of required trials to enter\n" + "Ganon's Tower."; // +/*------------------------------ // +| GANON'S TRIAL COUNT | // +------------------------------*/ // +string_view ganonsTrialCountDesc = "Set the number of trials required to enter\n" // + "Ganon's Tower. Trials will be randomly selected.";// +/*------------------------------ // +| STARTING AGE | // +------------------------------*/ // +string_view ageDesc = "Choose which age Link will start as.\n" // + "\n" // + "Starting as adult means you start with the Master\n" + "Sword in your inventory.\n" // + "\n" // + "Only the child option is compatible with Closed\n"// + "Forest."; // +/*------------------------------ // +| SHUFFLE ENTRANCES | // +------------------------------*/ // +string_view shuffleEntrancesDesc = "Shuffle where the entrances between areas lead to." + "If turned on, select which kinds of entrances you\n" + "want shuffled in the options below. Note that some" + "types of entrances can have wildly varying\n" // + "generation times."; // + // +/*------------------------------ // +| DUNGEON ENTRANCES | // +------------------------------*/ // +string_view dungeonEntrancesDesc = "Shuffle the pool of dungeon entrances, including\n" + "Bottom of the Well, Ice Cavern, and Gerudo\n" // + "Training Grounds. Shuffling Ganon's Castle can\n" // + "be enabled separately.\n" // + "\n" // + "Additionally, the entrances of Deku Tree, Fire\n" // + "Temple, Bottom of the Well and Gerudo Training\n" // + "Ground are opened for both adult and child."; // +/*------------------------------ // +| OVERWORLD ENTRANCES | // +------------------------------*/ // +string_view overworldEntrancesDesc = "Shuffle the pool of Overworld entrances, which\n" // + "corresponds to almost all loading zones between\n"// + "Overworld areas.\n" // + "\n" // + "Some entrances are unshuffled to avoid issues:\n" // + "- Hyrule Castle Courtyard and Garden entrance\n" // + "- Both Market Back Alley entrances\n" // + "- Gerudo Valley to Lake Hylia (unless entrances\n"// + " are decoupled)"; // +/*------------------------------ // +| INTERIOR ENTRANCES | // +------------------------------*/ // +string_view interiorEntrancesOff = "Interior entrances will not be shuffled."; // +string_view interiorEntrancesSimple = "Shuffle the pool of interior entrances which\n" // + "contains most Houses and all Great Fairies."; // +string_view interiorEntrancesAll = "An extended version of 'Simple' with some extra\n"// + "places:\n" // + "- Windmill\n" // + "- Link's House\n" // + "- Temple of Time\n" // + "- Kakariko Potion Shop."; // +/*------------------------------ // +| GROTTO ENTRANCES | // +------------------------------*/ // +string_view grottoEntrancesDesc = "Shuffle the pool of grotto entrances, including\n"// + "all graves, small Fairy Fountains and the Lost\n" // + "Woods Stage."; // +/*------------------------------ // +| BOMBCHUS IN LOGIC | // +------------------------------*/ // +string_view bombchuLogicDesc = "Bombchus are properly considered in logic.\n" // + "They can be replenished in shops, or through\n" // + "bombchu drops, if those are enabled.\n" // + "\n" // + "Bombchu Bowling is opened by bombchus."; // +/*------------------------------ // +| AMMO DROPS | // +------------------------------*/ // +string_view defaultAmmoDropsDesc = "Bombs, arrows, seeds, nuts, sticks and\n" // + "magic jars appear as normal.\n"; // +string_view bombchuDropsDesc = "Bombs, arrows, seeds, nuts, sticks and\n" // + "magic jars appear as normal.\n" // + "Bombchus can sometimes replace bomb drops."; // +string_view noAmmoDropsDesc = "All ammo drops will be replaced by blue rupees,\n"// + "except for Deku Sticks.\n" // + "Ammo upgrades will only refill ammo by 10 units.";// +/*------------------------------ // +| HEART DROPS AND REFILLS | // +------------------------------*/ // +string_view defaultHeartDropsDesc = "Heart drops will appear as normal.\n" // + "Health upgrades fully heal Link when picked up.\n"// + "Fairies heal Link as normal."; // +string_view noHeartDropsDesc = "Heart drops will be replaced by green rupees.\n" // + "Health upgrades fully heal Link when picked up.\n"// + "Fairies heal Link as normal."; // +string_view noHeartRefillDesc = "Heart drops will appear as normal.\n" // + "Health upgrades don't heal Link when picked up.\n"// + "Fairies heal Link by only 3 hearts."; // +string_view scarceHeartsDesc = "Heart drops will be replaced by green rupees.\n" // + "Health upgrades don't heal Link when picked up.\n"// + "Fairies heal Link by only 3 hearts."; // +/*------------------------------ // +| MQ DUNGEON COUNT | // +------------------------------*/ // +string_view mqDungeonCountDesc = "Specify the number of Master Quest dungeons to\n" // + "appear in the game. Which dungeons become Master\n" + "Quest will be chosen at random."; // +/*------------------------------ // +| SET MQ DUNGEONS | // +------------------------------*/ // +string_view setDungeonTypesDesc = "If set, you can choose specific dungeons to be\n" // + "vanilla, MQ, or random"; // +/*------------------------------ // +| SHUFFLE DUNGEON REWARDS | // +------------------------------*/ // +string_view shuffleRewardsEndOfDungeon= "Medallions and Spiritual Stones will be given as\n" + "rewards for beating dungeons.\n" // + "\n" // + "This setting will force Link's Pocket to be a\n" // + "Medallion or Spiritual Stone."; // +string_view shuffleRewardsAnyDungeon = "Medallions and Spiritual Stones can only appear\n"// + "inside of dungeons."; // +string_view shuffleRewardsOverworld = "Medallions and Spiritual Stones can only appear\n"// + "outside of dungeons."; // +string_view shuffleRewardsAnywhere = "Medallions and Spiritual Stones can appear\n" // + "anywhere."; // +/*------------------------------ // +| LINK'S POCKET | // +------------------------------*/ // +string_view linksPocketDungeonReward = "Link will start with a Dungeon Reward in his\n" // + "inventory."; // +string_view linksPocketAdvancement = "Link will receive a random advancement item at the" + "beginning of the playthrough."; // +string_view linksPocketAnything = "Link will receive a random item from the item pool" + "at the beginning of the playthrough."; // +string_view linksPocketNothing = "Link will start with a very useful green rupee."; // +/*------------------------------ // +| SONG SHUFFLE | // +------------------------------*/ // +string_view songsSongLocations = "Songs will only appear at locations that normally\n" + "teach songs."; // +string_view songsDungeonRewards = "Songs appear at the end of dungeons. For major\n" // + "dungeons, they will be at the boss heart container" + "location. The remaining 4 songs are placed at:\n" // + "- Zelda's Lullaby Location\n" // + "- Ice Cavern's Serenade of Water Location\n" // + "- Bottom of the Well's Lens of Truth Location\n" // + "- Gerudo Training Ground's Ice Arrow Location"; // +string_view songsAllLocations = "Songs can appear in any location."; // + // +/*------------------------------ // +| SHOPSANITY | // +------------------------------*/ // +string_view shopsOff = "All shop items will be the same as vanilla."; // +string_view shopsZero = "Vanilla shop items will be shuffled among\n" // + "different shops."; // +string_view shopsOne = "Vanilla shop items will be shuffled among\n" // + "different shops, and each shop will contain\n" // + "one non-vanilla shop item."; // +string_view shopsTwo = "Vanilla shop items will be shuffled among\n" // + "different shops, and each shop will contain\n" // + "two non-vanilla shop items."; // +string_view shopsThree = "Vanilla shop items will be shuffled among\n" // + "different shops, and each shop will contain\n" // + "three non-vanilla shop items."; // +string_view shopsFour = "Vanilla shop items will be shuffled among\n" // + "different shops, and each shop will contain\n" // + "four non-vanilla shop items."; // +string_view shopsRandom = "Vanilla shop items will be shuffled among\n" // + "different shops, and each shop will contain\n" // + "1-4 non-vanilla shop items."; // +/*------------------------------ // +| TOKENSANITY | // +------------------------------*/ // +string_view tokensOff = "GS locations will not be shuffled."; // +string_view tokensDungeon = "This only shuffles the GS locations that are\n" // + "within dungeons, increasing the value of most\n" // + "dungeons and making internal dungeon exploration\n" + "more diverse."; // +string_view tokensOverworld = "This only shuffles the GS locations that are\n" // + "outside of dungeons."; // +string_view tokensAllTokens = "Effectively adds 100 new locations for items to\n"// + "appear."; // + // +/*------------------------------ // +| SCRUB SHUFFLE | // +------------------------------*/ // +string_view scrubsOff = "Only the 3 Scrubs that give one-time items in the\n" + "vanilla game (PoH, Deku Nut capacity, and Deku\n" // + "Stick capacity) will have random items."; // +string_view scrubsAffordable = "All Scrub prices will be reduced to 10 rupees each"; +string_view scrubsExpensive = "All Scrub prices will be their vanilla prices.\n" // + "This will require spending over 1000 rupees on\n" // + "Scrubs."; // +string_view scrubsRandomPrices = "All Scrub prices will be between 0-95 rupees. This" + "will on average be very, very expensive overall.";// +/*------------------------------ // +| SHUFFLE COWS | // +------------------------------*/ // +string_view shuffleCowsDesc = "Enabling this will let cows give you items upon\n"// + "performing Epona's song in front of them. There\n"// + "are 9 cows, and an extra in MQ Jabu."; // + // +/*------------------------------ // +| SHUFFLE KOKIRI SWORD | // +------------------------------*/ // +string_view kokiriSwordDesc = "Enabling this shuffles the Kokiri Sword into the\n" + "item pool.\n" // + "\n" // + "This will require extensive use of sticks until\n"// + "the sword is found."; // +/*------------------------------ // +| SHUFFLE OCARINAS | // +------------------------------*/ // +string_view ocarinasDesc = "Enabling this shuffles the Fairy Ocarina and the\n" + "Ocarina of Time into the item pool.\n" // + "\n" // + "This will require finding an Ocarina before being\n" + "able to play songs."; // +/*------------------------------ // +| SHUFFLE WEIRD EGG | // +------------------------------*/ // +string_view weirdEggDesc = "Enabling this shuffles the Weird Egg from Malon\n"// + "into the item pool.\n" // + "This will require finding the Weird Egg to talk to" + "Zelda in Hyrule Castle, which in turn locks\n" // + "rewards from Impa, Saria, Malon, and Talon, as\n" // + "well as the Happy Mask Sidequest. The Weird Egg is" + "also required for Zelda's Letter to unlock the\n" // + "Kakariko Gate as child which can lock some\n" // + "progression"; // +/*------------------------------ // +| SHUFFLE Gerudo Membership Card | // +------------------------------*/ // +string_view gerudoTokenDesc = "Enabling this shuffles the Gerudo Membership Card into the\n" + "item pool.\n" // + "\n" // + "The Gerudo Membership Card is required to enter the Gerudo\n" + "Training Ground."; // +/*------------------------------ // +| SHUFFLE MAGIC BEANS | // +------------------------------*/ // +string_view magicBeansDesc = "Enabling this adds a pack of 10 beans to the item\n" + "pool and changes the Magic Bean Salesman to sell a" + "random item at a price of 60 rupees."; // +/*------------------------------ // +| SHUFFLE MERCHANTS | // +------------------------------*/ // +string_view merchantsDesc = "Enabling this adds a Giant's Knife and a pack\n" // + "of Bombchus to the item pool and changes both\n" // + "Medigoron and the Haunted Wasteland Carpet\n" // + "Salesman to sell a random item once at the price\n" + "of 200 rupees."; // +string_view merchantsHintsDesc = "These hints will make Medigoron and the Carpet\n" // + "Salesman tell you which item they're selling.\n" // + "\n" // + "The Clearer Hints setting will affect how they\n" // + "refer to the item."; // +/*------------------------------ // +| SHUFFLE ADULT TRADE | // +------------------------------*/ // +string_view adultTradeDesc = "Enabling this adds all of the adult trade quest\n"// + "items to the pool, each of which can be traded\n" // + "for a unique reward. You will be able to choose\n"// + "which of your owned adult trade items is visible\n" + "in the inventory by selecting the item and using\n" + "the L and R buttons. If disabled, only the Claim\n" + "Check will be found in the pool."; // +/*------------------------------ // +| SHUFFLE CHEST MINIGAME | // +------------------------------*/ // +string_view chestMinigameDesc = "The 5 key chests in the Treasure Chest Shop will\n" + "be randomized, and the 6 keys will be added to the"// + "pool. The rupee chests will be replaced by traps.\n" + "Also, the shop owner is on vacation, so he can't\n" + "close any chests or doors once you leave.\n" // + "\n" // + "If you choose the \"pack\" option, you will get\n"// + "all the keys at once, in a single item."; // +/*------------------------------ // +| MAPS AND COMPASSES | // +------------------------------*/ // +string_view mapCompassStartWith = "Maps and Compasses are given to you from the\n" // + "start. This will add a small amount of money and\n" + "refill items to the pool."; // +string_view mapCompassVanilla = "Maps and Compasses will appear in their vanilla\n"// + "locations."; // +string_view mapCompassOwnDungeon = "Maps and Compasses can only appear in their\n" // + "respective dungeon."; // +string_view mapCompassAnyDungeon = "Maps and Compasses can only appear in a dungeon,\n" + "but not necessarily the dungeon they are for."; // +string_view mapCompassOverworld = "Maps and Compasses can only appear outside of\n" // + "dungeons."; // +string_view mapCompassAnywhere = "Maps and Compasses can appear anywhere in the\n" // + "world."; // +/*------------------------------ // +| SMALL KEYS | // +------------------------------*/ // +string_view smallKeyStartWith = "Small Keys are given to you from the start so you\n" + "won't have to worry about locked doors. An easier\n" + "mode."; // +string_view smallKeyVanilla = "Small Keys will appear in their vanilla locations." + "You start with 3 keys in Spirit Temple MQ because\n" + "the vanilla key layout is not beatable in logic.";// +string_view smallKeyOwnDungeon = "Small Keys can only appear in their respective\n" // + "dungeon. If Fire Temple is not a Master Quest\n" // + "dungeon, the door to the Boss Key chest will be\n"// + "unlocked."; // +string_view smallKeyAnyDungeon = "Small Keys can only appear inside of any dungeon,\n" + "but won't necessarily be in the dungeon that the\n" + "key is for. A difficult mode since it is more\n" // + "likely to need to enter a dungeon multiple times."; +string_view smallKeyOverworld = "Small Keys can only appear outside of dungeons.\n"// + "You may need to enter a dungeon multiple times to\n" + "gain items to access the overworld locations with\n" + "the keys required to finish a dungeon."; // +string_view smallKeyAnywhere = "Small Keys can appear anywhere in the world. A\n" // + "difficult mode since it is more likely to need to\n" + "enter a dungeon multiple times."; // +/*------------------------------ // +| GERUDO FORTRESS KEYS | // +------------------------------*/ // +string_view gerudoKeysVanilla = "Gerudo Fortress Keys will appear in their vanilla\n" + "location, dropping from fighting Gerudo guards\n" // + "that attack when trying to free the jailed\n" // + "carpenters."; // +string_view gerudoKeysAnyDungeon = "Gerudo Fortress Keys can only appear inside of\n" // + "dungeons."; // +string_view gerudoKeysOverworld = "Gerudo Fortress Keys can only appear outside of\n"// + "dungeons."; // +string_view gerudoKeysAnywhere = "Gerudo Fortress Keys can appear anywhere in the\n"// + "world."; // +/*------------------------------ // +| Key Rings | // +------------------------------*/ // +string_view keyRingDesc = "Selected key ring dungeons will have all of their\n" + "keys found at once in a ring rather than\n" // + "individually.\n\n" // + "For example, instead of shuffling 5 Forest Temple\n" + "small keys into the pool, you will find a single\n" + "key ring which will give you all 5 keys at once.\n"; +/*------------------------------ // +| BOSS KEYS | // +------------------------------*/ // +string_view bossKeyStartWith = "Boss Keys are given to you from the start so you\n" + "won't have to worry about boss doors. An easier\n"// + "mode."; // +string_view bossKeyVanilla = "Boss Keys will appear in their vanilla locations."; +string_view bossKeyOwnDungeon = "Boss Keys can only appear in their respective\n" // + "dungeon."; // +string_view bossKeyAnyDungeon = "Boss Keys can only appear inside of any dungeon,\n" + "but won't necessarily be in the dungeon that the\n" + "key is for. A difficult mode since it is more\n" // + "likely to need to enter a dungeon multiple times."; +string_view bossKeyOverworld = "Boss Keys can only appear outside of dungeons.\n" // + "You may need to enter a dungeon without the boss\n" + "key to get items required to find the key in the\n" + "overworld."; // +string_view bossKeyAnywhere = "Boss Keys can appear anywhere in the world. A\n" // + "difficult mode since it is more likely to need to\n" + "enter a dungeon multiple times."; // +/*------------------------------ // +| GANON'S CASTLE BOSS KEY | // +------------------------------*/ // +string_view ganonKeyStartWith = "Ganon's Castle Boss Key is given to you from the\n" + "start and you don't have to worry about finding it"; +string_view ganonKeyVanilla = "Ganon's Castle Boss Key will appear in the vanilla" + "location."; // +string_view ganonKeyOwnDungeon = "Ganon's Castle Boss Key can only appear inside\n" // + "Ganon's Castle."; // +string_view ganonKeyAnyDungeon = "Ganon's Castle Boss Key can only appear inside of\n" + "a dungeon, but not necessarily Ganon's Castle."; // +string_view ganonKeyOverworld = "Ganon's Castle Boss Key can only appear outside of" + "dungeons."; // +string_view ganonKeyAnywhere = "Ganon's Castle Boss Key can appear anywhere in the" + "world."; // +string_view ganonKeyLACS = "These settings put the boss key on the Light Arrow" + "Cutscene location, from Zelda in Temple of Time as" + "adult, with differing requirements."; // +/*------------------------------ // +| LACS CONDITIONS | // +------------------------------*/ // +string_view lacsMedallionCountDesc = "Set the number of Medallions required to trigger\n" + "the Light Arrow Cutscene."; // +string_view lacsStoneCountDesc = "Set the number of Spiritual Stones required to\n" // + "trigger the Light Arrow Cutscene."; // +string_view lacsRewardCountDesc = "Set the number of Dungeon Rewards (Spiritual\n" // + "Stones and Medallions) required to trigger the\n" // + "Light Arrow Cutscene."; // +string_view lacsDungeonCountDesc = "Set the number of completed dungeons required to\n" + "trigger the Light Arrow Cutscene.\n" // + "\n" // + "Dungeons are considered complete when Link steps\n" + "into the blue warp at the end of them."; // +string_view lacsTokenCountDesc = "Set the number of Gold Skulltula Tokens required\n" + "to trigger the Light Arrow Cutscene."; // +/*------------------------------ // +| SKIP CHILD STEALTH | // +------------------------------*/ // +string_view childStealthDesc = "The crawlspace into Hyrule Castle goes straight to" + "Zelda, skipping the guards."; // +/*------------------------------ // +| SKIP TOWER ESCAPE | // +------------------------------*/ // +string_view skipTowerEscapeDesc = "The tower escape sequence between Ganondorf and\n"// + "Ganon will be skipped."; // +/*------------------------------ // +| SKIP EPONA RACE | // +------------------------------*/ // +string_view skipEponaRaceDesc = "Epona can be summoned with Epona's Song without\n"// + "needing to race Ingo."; // +/*------------------------------ // +| SKIP MINIGAME PHASES | // +------------------------------*/ // +string_view skipMinigamePhasesDesc = "Completing the second objective in the Dampe Race\n" + "and Gerudo Archery on the first attempt will give\n" + "both rewards at once for that minigame."; // +/*------------------------------ // +| FREE SCARECROW | // +------------------------------*/ // +string_view freeScarecrowDesc = "Pulling out the Ocarina near a spot at which\n" // + "Pierre can spawn will do so, without needing\n" // + "the song."; // +/*------------------------------ // +| FOUR POES CUTSCENE | // +------------------------------*/ // +string_view fourPoesDesc = "The cutscene with the 4 poes in Forest Temple will" + "be skipped. If the cutscene is not skipped, it can" + "be exploited to reach the basement early."; // +/*------------------------------ // +| LAKE HYLIA OWL | // +------------------------------*/ // +string_view lakeHyliaOwlDesc = "The owl flight cutscene in Lake Hylia will be\n" // + "skipped. This cutscene lets you see what item\n" // + "is on top of the laboratory roof."; // +/*------------------------------ // +| BIG POE TARGET COUNT | // +------------------------------*/ // +string_view bigPoeTargetCountDesc = "The Poe buyer will give a reward for turning in\n"// + "the chosen number of Big Poes."; // +/*------------------------------ // +| NUM REQUIRED CUCCOS | // +------------------------------*/ // +string_view numRequiredCuccosDesc = "The cucco lady will give a reward for returning\n"// + "this many of her cuccos to the pen."; // +/*------------------------------ // +| KING ZORA SPEED | // +-------------------------------*/ // +string_view kingZoraSpeedFast = "King Zora will move out of the way in 1 shuffle"; // + // +string_view kingZoraSpeedVanilla = "King Zora will move out of the way in 26 shuffles"; + // +string_view kingZoraSpeedRandom = "King Zora will move out of the way in 1 to 128\n" // + "shuffles, with lower numbers being more common"; // +/*------------------------------ // +| COMPLETE MASK QUEST | // +------------------------------*/ // +string_view completeMaskDesc = "Once the happy mask shop is opened, all masks\n" // + "will be available to be borrowed."; // +/*------------------------------ // +| QUICK TEXT | // +------------------------------*/ // +string_view quickTextDesc0 = "Quick text will be unchanged, requiring\n" // + "frame-perfect inputs like in the vanilla game."; // +string_view quickTextDesc1 = "Every text box will be completable by pressing B\n" + "at any point while it's scrolling."; // +string_view quickTextDesc2 = "Every text box will auto-complete instantly.\n" // + "No scrolling allowed!"; // +string_view quickTextDesc3 = "Holding B will advance and close text boxes\n" // + "automatically, except for choice selections."; // +/*------------------------------ // +| SKIP SONG REPLAYS | // +------------------------------*/ // +string_view skipSongReplaysDesc = "The automatic replay after you play a song will\n"// + "be skipped.\n" // + "You can choose to keep the sfx anyway, but you\n" // + "will have control of Link during it."; // +/*------------------------------ // +| KEEP FW WARP POINT | // +------------------------------*/ // +string_view keepFWWarpPointDesc = "The Farore's Wind warp point will stay active\n" // + "after having been warped to. The old point will\n"// + "need to be dispelled before setting a new one."; // +/*------------------------------ // +| FAST BUNNY HOOD | // +------------------------------*/ // +string_view fastBunnyHoodDesc = "The Bunny Hood mask behaves like it does in\n" // + "Majora's Mask and makes you run 50% faster."; // +/*------------------------------ // +| GOSSIP STONE HINTS | // +------------------------------*/ // +string_view gossipStonesHintsDesc = "Gossip Stones can be made to give hints about\n" // + "where items can be found.\n" // + "Different settings can be chosen to decide which\n" + "item is needed to speak to Gossip Stones. Choosing" + "to stick with the Mask of Truth will make the\n" // + "hints very difficult to obtain.\n" // + "Hints for 'on the way of the hero' are locations\n" + "that contain items that are required to beat the\n" + "game."; // + // +/*------------------------------ // +| HINT CLARITY | // +------------------------------*/ // +string_view obscureHintsDesc = "Sets the difficulty of hints.\n" // + "Obscure: Hints are unique for each thing, but\n" // + "the writing may be confusing.\n" // + "E.g. Kokiri Sword > a butter knife"; // +string_view ambiguousHintsDesc = "Sets the difficulty of hints.\n" // + "Ambiguous: Hints are clearly written, but may\n" // + "refer to more than one thing.\n" // + "E.g. Kokiri Sword > a sword"; // +string_view clearHintsDesc = "Sets the difficulty of hints.\n" // + "Clear: Hints are clearly written and are unique\n"// + "for each thing.\n" // + "E.g. Kokiri Sword > the Kokiri Sword"; // +/*------------------------------ // +| HINT DISTRIBUTION | // +------------------------------*/ // +string_view uselessHintsDesc = "Only junk hints."; // +string_view balancedHintsDesc = "Recommended hint spread."; // +string_view strongHintsDesc = "More useful hints."; // +string_view veryStrongHintsDesc = "Many powerful hints."; // + // +/*------------------------------ // +| MAP AND COMPASS GIVES INFO | // +------------------------------*/ // +string_view compassesShowRewardsDesc = "If dungeon rewards are set to be shuffled at the\n" + "end of dungeons, the in-game menu will reveal\n" // + "which reward is in each dungeon, if the compass\n"// + "for that dungeon has been collected."; // +string_view compassesShowWotHDesc = "The in-game menu will reveal whether each\n" // + "dungeon is on the Way of the Hero, a barren\n" // + "location, or neither, if the compass for that\n" // + "dungeon has been collected."; // +string_view mapsShowDungeonModesDesc = "If any Master Quest dungeons will be randomly\n" // + "shuffled, the in-game menu will reveal whether\n" // + "it is in its Vanilla or Master Quest form, if\n" // + "the map for the dungeon has been collected.\n" // + "Ganon's Castle and Gerudo Training Grounds are\n" // + "always revealed, as they do not have maps."; // +/*------------------------------ // +| DAMAGE MULTIPLIER | // +------------------------------*/ // +string_view damageMultiDesc = "Changes the amount of damage taken.\n" // + "\n" // + "If set to OHKO, Link will die in one hit."; // +/*------------------------------ // +| STARTING TIME | // +------------------------------*/ // +string_view startingTimeDesc = "Change up Link's sleep routine."; // + // +/*------------------------------ // +| ALL LOCATIONS REACHABLE | // +------------------------------*/ // +string_view locationsReachableDesc = "When this options is enabled, the randomizer will\n" + "guarantee that every item is obtainable and every\n" + "location is reachable. When disabled, only\n" // + "required items and locations to beat the game\n" // + "will be guaranteed reachable."; // +/*------------------------------ // +| NIGHT GS EXPECT SUNS | // +------------------------------*/ // +string_view nightGSDesc = "GS Tokens that can only be obtained during the\n" // + "night expect you to have Sun's Song to collect\n" // + "them. This prevents needing to wait until night\n"// + "for some locations."; // + // +/*------------------------------ // +| CHEST ANIMATIONS | // +------------------------------*/ // +string_view chestAnimDesc = "Choose if you want the slow animation to play\n" // + "if a chest contains a major item.\n"; // + // +/*------------------------------ // +| CHEST SIZE AND COLOR | // +------------------------------*/ // +string_view chestSizeDesc = "This option will change the appearance of all\n" // + "regular chests depending on their contents:\n" // + "Major Items = Big Wooden Chests\n" // + "Lesser Items = Small Wooden Chests\n" // + "Boss Keys = Big Fancy Chests\n" // + "Small Keys = Small Fancy Chests"; // + // +/*------------------------------ // +| INGAME SPOILERS | // +------------------------------*/ // +string_view ingameSpoilersShowDesc = "Every spoiler is shown."; // +string_view ingameSpoilersHideDesc = "Hides the spheres page and only shows a\n" // + "location's item after it has been found."; // + // +/*------------------------------ // +| MENU OPENING BUTTON | // +------------------------------*/ // +string_view menuButtonDesc = "Choose which button will bring up the Dungeon\n" // + "Information Menu. You can also use the menu to\n" // + "buffer frame perfect inputs if you choose D-Pad"; // + // +/*------------------------------ // +| START WITH CONSUMABLES | // +------------------------------*/ // +string_view startWithConsumablesDesc = "Start the game with maxed out Deku Sticks and Deku" + "Nuts."; // + // +/*------------------------------ // +| START WITH MAX RUPEES | // +------------------------------*/ // +string_view startWithMaxRupeesDesc = "Start the game with a full wallet.\n" // + "Wallet upgrades will also fill the wallet."; // + // +/*------------------------------ // +| ITEM POOL | // +------------------------------*/ // +string_view itemPoolPlentiful = "Extra major items are added to the pool."; // +string_view itemPoolBalanced = "Original item pool."; // +string_view itemPoolScarce = "Some excess items are removed, including health\n"// + "upgrades."; // +string_view itemPoolMinimal = "Most excess items are removed."; // + // +/*------------------------------ // +| ICE TRAPS | // +------------------------------*/ // +string_view iceTrapsOff = "All Ice Traps are removed."; // +string_view iceTrapsNormal = "Only Ice Traps from the base item pool are placed."; +string_view iceTrapsExtra = "Chance to add extra Ice Traps when junk items are\n" + "added to the itempool."; // +string_view iceTrapsMayhem = "All added junk items will be Ice Traps."; // +string_view iceTrapsOnslaught = "All junk items will be replaced by Ice Traps, even" + "those in the base pool."; // +/*------------------------------ // +| REMOVE DOUBLE DEFENSE | // +------------------------------*/ // +string_view removeDDDesc = "If set the double defense item will be removed\n" // + "from the item pool for balanced and plentiful."; // +/*------------------------------ // +| PROGRESSSIVE GORON SOWRD | // +------------------------------*/ // +string_view progGoronSword = "Giant's Knife will always be found\n" // + "before Biggoron's Sword. Medigoron only starts\n" // + "selling new knives once the Giant's Knife\n" // + "has been found and broken."; // +/*------------------------------ // +| USE FARORE'S WIND ANYWHERE | // +------------------------------*/ // +string_view faroresWindAnywhereDesc = "Farore's Wind can be used outside of dungeons."; // + // +/*------------------------------ // +| LIFT AGE RESTRICTIONS | // +------------------------------*/ // +string_view ageRestrictionsDesc = "Remove age restrictions for inventory items.\n" // + "Select \"Choose\" to open the list of individual\n" + "options.\n\n" // + "Most of the items won't appear correctly when\n" // + "used as the wrong version of Link, but they'll be\n" + "fully functional otherwise."; // + // +/*------------------------------ // +| ENABLE ADULT DEKU STICK | // +------------------------------*/ // +string_view adultStickDesc = "Adult Link can wield a deku stick. In game Adult\n" + "Link will look like he's holding a Hylian Shield,\n" + "but rest assured it is a deku stick."; // + // +/*------------------------------ // +| ENABLE ADULT BOOMERANG | // +------------------------------*/ // +string_view adultBoomerangDesc = "Adult Link can throw the boomerang."; // + // +/*------------------------------ // +| ENABLE CHILD HAMMER | // +------------------------------*/ // +string_view childHammerDesc = "Child Link can swing the Megaton Hammer."; // +/*------------------------------ // +| ENABLE ADULT SLINGSHOT | // +------------------------------*/ // +string_view adultSlingshotDesc = "Adult Link can use the Slingshot (but it looks\n" // + "like the Bow)."; // + // +/*------------------------------ // +| ENABLE CHILD BOW | // +------------------------------*/ // +string_view childBowDesc = "Child Link can use the Bow. It will look like the\n" + "Slingshot, but will shoot arrows."; // + // +/*------------------------------ // +| ENABLE CHILD HOOKSHOT | // +------------------------------*/ // +string_view childHookshotDesc = "Child Link can use the Hookshot/Longshot.\n" // + "It will be difficult to aim, the red dot and\n" // + "laser won't appear and the hook will look like\n" // + "a small bomb."; // +/*------------------------------ // +| ENABLE CHILD IRON BOOTS | // +------------------------------*/ // +string_view childIronBootsDesc = "Child Link can equip the Iron Boots."; // + // +/*------------------------------ // +| ENABLE CHILD HOVER BOOTS | // +------------------------------*/ // +string_view childHoverBootsDesc = "Child Link can equip the Hover Boots. The yellow\n" + "circle beneath Link's feet won't appear."; // + // +/*------------------------------ // +| ENABLE ADULT MASKS | // +------------------------------*/ // +string_view adultMasksDesc = "Adult Link can equip masks.\n" // + "\n" // + "This setting will not change the logic."; // + // +/*------------------------------ // +| ENABLE ADULT KOKIRI SWORD | // +------------------------------*/ // +string_view adultKokiriSwordDesc = "Adult Link can equip the Kokiri Sword."; // + // +/*------------------------------ // +| ENABLE CHILD MASTER SWORD | // +------------------------------*/ // +string_view childMasterSwordDesc = "Child Link can equip the Master Sword."; // + // +/*------------------------------ // +| ENABLE CHILD BIGGORON SWORD | // +------------------------------*/ // +string_view childBiggoronSwordDesc = "Child Link can equip the Biggoron Sword and the\n"// + "Giant's Knife."; // + // +/*------------------------------ // +| ENABLE ADULT DEKU SHIELD | // +------------------------------*/ // +string_view adultDekuShieldDesc = "Adult Link can equip the Deku Shield."; // + // +/*------------------------------ // +| ENABLE CHILD MIRROR SHIELD | // +------------------------------*/ // +string_view childMirrorShieldDesc = "Child Link can equip the Mirror Shield."; // + // +/*------------------------------ // +| ENABLE CHILD GORON TUNIC | // +------------------------------*/ // +string_view childGoronTunicDesc = "Child Link can equip the Goron Tunic."; // + // +/*------------------------------ // +| ENABLE CHILD ZORA TUNIC | // +------------------------------*/ // +string_view childZoraTunicDesc = "Child Link can equip the Zora Tunic."; // + // +/*------------------------------ // +| GK DURABILITY | // +------------------------------*/ // +string_view gkDurabilityVanilla = "The durability will always be set to 8."; // +string_view gkDurabilityRandomRisk = "Each Giant's Knife will get a random durability\n"// + "between 1 and 128, with low being more common,\n" // + "and with an average of 15."; // +string_view gkDurabilityRandomSafe = "Each Giant's Knife will get a random durability\n"// + "between 10 and 50, with an average of 30."; // + // +/*------------------------------ // +| MULTIPLAYER | // +------------------------------*/ // +string_view mp_EnabledDesc = "Enables multiplayer.\n" // + "Other players will always be seen and heard\n" // + "regardless of the other settings."; // +string_view mp_SharedProgressDesc = "Progress and certain actors will be synced between" + "everyone in the network that has this option on,\n" + "the same seed hash, and the same sync id."; // +string_view mp_SyncIdDesc = "Limits shared progress to only sync with other\n" // + "players that have the same sync ID. This is only\n" + "necessary to set if multiple groups of players\n" // + "play on the same seed hash, but only want to share" + "their progress with certan people.\n" // + "For example, when doing a 2v2 race."; // +string_view mp_SharedHealthDesc = "Syncs health when shared progress is on,\n" // + "otherwise just shares the damage and recovery."; // +string_view mp_SharedRupeesDesc = "Syncs rupees when shared progress is on,\n" // + "otherwise just shares the gain and loss."; // +string_view mp_SharedAmmoDesc = "Syncs ammo when shared progress is on,\n" // + "otherwise just shares the gain and loss."; // + // +/*------------------------------ // +| INGAME DEFAULTS | // +------------------------------*/ // +string_view zTargetingDesc = "Sets L-Targeting to start as switch or hold."; // +string_view cameraControlDesc = "Sets the camera controls to start as normal or\n" // + "with the y-axis inverted."; // +string_view motionControlDesc = "Sets the motion controls to start on or off."; // +string_view togglePlayMusicDesc = "Starts the game with the music on or off."; // +string_view togglePlaySFXDesc = "Starts the game with the sound effects on or off."; +string_view silenceNaviDesc = "Sets whether Navi should start silenced or not."; // +string_view ignoreMaskReactionDesc = "Sets whether NPCs ignore the worn mask or not.\n" // + "Does not apply when trading masks."; // + // +/*------------------------------ // +| NAVI & TRAIL COLORS | // +------------------------------*/ // +string_view naviColorsDesc = "Inner color is for the main light orb, outer color" + "is for the aura.\n\n" // + "The Rainbow option will make the color change\n" // + "continuously in a 3 seconds loop."; // +string_view necessarySimpleModeDesc = "For boomerang and sword trails, OoT3D uses a\n" // + "special texture that doesn't support every color.\n\n" + "Unsupported colors will always use the plain\n" // + "texture from OoT instead:\n" // + "- Black and Purple sword trails\n" // + "- White, Black and Purple boomerang trails\n" // + "- Random or Custom colors without at least one\n" // + " maxed out RGB component."; // +string_view alwaysSimpleModeDesc = "All boomerang and sword trails will use the plain\n" + "texture from OoT, regardless of what color is\n" // + "chosen."; // + // +/*------------------------------ // +| COLORED KEYS | // +------------------------------*/ // +string_view coloredKeysDesc = "If set, small key models will be colored\n" // + "differently depending on which dungeon they can be" + "used in. Forest Temple keys are green. Fire Temple" + "keys are red. etc."; // +string_view coloredBossKeysDesc = "If set, boss key models will be colored\n" // + "differently depending on which dungeon they can be" + "used in. The Forest Temple boss key is green. The " + "Fire Temple boss key is red. etc."; // +/*------------------------------ // +| MIRROR WORLD | // +------------------------------*/ // +string_view mirrorWorldDesc = "If set, the world will be mirrored."; // + // +/*------------------------------ // +| SHUFFLE MUSIC | // +------------------------------*/ // +string_view musicRandoDesc = "Randomize the music in the game."; // +string_view shuffleBGMDesc = "Randomize area background music, either\n" // + "grouped into categories or all mixed together."; // +string_view fanfaresOffDesc = "Fanfares are not shuffled."; // +string_view onlyFanfaresDesc = "Fanfares and ocarina songs are shuffled in\n" // + "separate pools."; // +string_view fanfaresOcarinaDesc = "Fanfares and ocarina songs are shuffled together\n" + "in the same pool."; // +string_view shuffleOcaMusicDesc = "The music that plays back after you play an" // + "ocarina song is randomized."; // +/*------------------------------ // +| SHUFFLE SFX | // +------------------------------*/ // +string_view shuffleSFXOff = "Sound effects will stay vanilla."; // +string_view shuffleSFXAll = "All sound effects will be shuffled."; // +string_view shuffleSFXSceneSpecific = "All sound effects will be shuffled, but will also\n" + "be different in each scene."; // +string_view shuffleSFXChaos = "Each sound effect will become random about\n" // + "every second."; // +string_view shuffleSFXCategorically = "Sound effects will be shuffled in categories.\n" // + "\n" // + "The sound may get annoying fast when disabled."; // +/*------------------------------ // +| RANDOM TRAP DAMAGE TYPE | // +------------------------------*/ // +string_view randomTrapDmgDesc = "All traps will be the base game ice trap"; // + // +string_view basicTrapDmgDesc = "All alternative traps will cause a small damage\n"// + "and no other negative effects"; // + // +string_view advancedTrapDmgDesc = "Some chest traps will burn your Deku Shield or\n" // + "cause a lot of damage (with one-hit protection)"; // + //--------------// +/*------------------------------ // +| DETAILED LOGIC EXPLANATIONS | // +------------------------------*/ +string_view ToggleLogicNoneDesc = "Disables all the Detailed Logic tricks."; // +string_view ToggleLogicNoviceDesc = "Enables only the easier Detailed Logic tricks"; // +string_view ToggleLogicIntermediateDesc = "Enables all but the harder Detailed Logic tricks."; +string_view ToggleLogicExpertDesc = "Enables all the Detailed Logic tricks."; // + // +string_view LogicGrottosWithoutAgonyDesc = "Difficulty: Novice\n" // + "Grottos can be accessed without Stone of Agony,\n"// + "simply by knowing where they are located."; // +string_view LogicVisibleCollisionDesc = "Difficulty: Novice\n" // + "The closed Kakariko Village Gate can be crossed\n"// + "when coming from Death Mountain Trail.\n" // + "Useful for Entrance Randomiser."; // +string_view LogicFewerTunicRequirementsDesc = "Difficulty: Novice\n" // + "Allows the following possible without Tunics:\n" // + "- Enter Water Temple.\n" // + "- Enter Fire Temple. Only the first floor\n" // + " is accessible, and not Volvagia.\n" // + "- Zora's Fountain Bottom Freestanding PoH.\n" // + "- Gerudo Training Grounds Underwater Silver Rupee\n" + "Chest. May need to make multiple trips."; // +string_view LogicLostWoodsGSBeanDesc = "Difficulty: Novice\n" // + "You can collect the token with a precise Hookshot\n" + "use, as long as you can kill the Skulltula first.\n" + "It can be killed using Longshot, Bow, Bombchus\n" // + "or Din's Fire."; // +string_view LogicLabDivingDesc = "Difficulty: Novice\n" // + "Remove the Iron Boots in the midst of Hookshotting" + "the underwater crate"; // +string_view LogicLabWallGSDesc = "Difficulty: Intermediate\n" // + "The jump slash to actually collect the token is\n"// + "somewhat precise"; // +string_view LogicGraveyardPoHDesc = "Difficulty: Novice\n" // + "Using a precise moving setup you can obtain the\n"// + "Piece of Heart by having the Boomerang interact\n"// + "with it along the return path."; // +string_view LogicChildDampeRacePoHDesc = "Difficulty: Intermediate\n" // + "It is possible to complete the second dampe race\n" + "as child in under a minute, but it is a strict\n" // + "time limit."; // +string_view LogicGVHammerChestDesc = "Difficulty: Novice\n" // + "The chest can be reached by sidehopping between\n"// + "the wall and the east most hammer rock."; // +string_view LogicGerudoKitchenDesc = "Difficulty: Intermediate\n" // + "The logic normally guarantees one of Bow,\n" // + "Hookshot, or Hover Boots."; // +string_view LogicLensWastelandDesc = "Difficulty: Expert\n" // + "By memorizing the path, you can travel through the" + "Wasteland without using the Lens of Truth to see\n" + "the Poe. The equivalent trick for going in reverse" + "through the Wasteland is \"Reverse Wasteland\"."; // +string_view LogicReverseWastelandDesc = "Difficulty: Expert\n" // + "By memorizing the path, you can travel through the" + "Wasteland in reverse."; // +string_view LogicColossusGSDesc = "Difficulty: Expert\n" // + "Somewhat precise. If you kill enough Leevers you\n" + "can get enough of a break to take some time to aim" + "more carefully."; // +string_view LogicOutsideGanonsGSDesc = "Difficulty: Intermediate\n" // + "Can be killed with a precise sidehop jumpslash\n" // + "from the top of the broken arch."; // +string_view LogicManOnRoofDesc = "Difficulty: Novice\n" // + "Can be reached by side-hopping off the watchtower."; +string_view LogicWindmillPoHHookshotDesc = "Difficulty: Novice\n" // + "Adult Link can reach the upper area of the windmill" + "using the hookshot and a midair jump slash."; // +string_view LogicDMTBombableDesc = "Difficulty: Expert\n" // + "Child Link can blow up the wall using a nearby\n" // + "bomb flower. You must backwalk with the flower and" + "then quickly throw it toward the wall."; // +string_view LogicDMTSoilGSDesc = "Difficulty: Intermediate\n" // + "Bugs will go into the soft soil even while the\n" // + "boulder is still blocking the entrance if dropped\n" + "from above. Then, using a precise moving setup you" + "can kill the Gold Skulltula and obtain the token by" + "having the Boomerang collect it while returning.";// +string_view LogicDMTSummitHoverDesc = "Difficulty: Intermediate\n" // + "By rolling around the lower boulder with hover\n" // + "boots and grabbing the ledge with the higher\n" // + "boulder near the wall, you'll be able to grab the\n" + "ledge above it to reach the summit."; // +string_view LogicLinkGoronDinsDesc = "Difficulty: Intermediate\n" // + "The timing is quite awkward."; // +string_view LogicGoronCityLeftMostDesc = "Difficulty: Novice\n" // + "A precise backwalk starting from on top of the\n" // + "crate and ending with a precisely-timed backflip\n" + "can reach this chest without needing either the\n"// + "Hammer or Silver Gauntlets."; // +string_view LogicGoronCityPotDesc = "Difficulty: Expert\n" // + "A Bombchu can be used to stop the spinning pot,\n"// + "but it can be quite finicky to get it to work."; // +string_view LogicGoronCityPotWithStrengthDesc = "Difficulty: Intermediate\n" // + "Allows for stopping the Goron City Spinning Pot\n"// + "using a bomb flower alone, requiring strength in\n" + "lieu of inventory explosives."; // +string_view LogicChildRollingWithStrengthDesc = "Difficulty: Expert\n" // + "Use the bombflower on the stairs or near\n" // + "Medigoron. Timing is tight, especially without\n" // + "backwalking."; // +string_view LogicCraterUpperToLowerDesc = "Difficulty: Intermediate\n" // + "With the Hammer, you can jump slash the rock twice" + "in the same jump in order to destroy it before you" + "fall into the lava."; // +string_view LogicCraterBeanPoHWithHoversDesc = "Difficulty: Expert\n" // + "Hover from the base of the bridge near Goron City\n" + "and walk up the very steep slope."; // +string_view LogicBiggoronBoleroDesc = "Difficulty: Intermediate\n" // + "Playing a warp song normally causes a trade item\n" + "to spoil immediately, however, it is possible use\n" + "Bolero to reach Biggoron and still deliver the Eye" + "Drops before they spoil. If you do not wear the\n" + "Goron Tunic, the heat timer inside the crater will" + "override the trade item's timer. When you exit to\n" + "Death Mountain Trail you will have one second to\n" + "show the Eye Drops before they expire."; // +string_view LogicZoraRiverLowerDesc = "Difficulty: Novice\n" // + "Adult can reach this PoH with a precise jump, no\n" + "Hover Boots required."; // +string_view LogicZoraRiverUpperDesc = "Difficulty: Novice\n" // + "Adult can reach this PoH with a precise jump, no\n" + "Hover Boots required."; // +string_view LogicZFGreatFairyDesc = "Difficulty: Novice\n" // + "Destroying the boulders blocking the hidden area\n" + "with silver gauntlets and hammer lets you pass\n" // + "under the wall to the great fairy fountain."; // +string_view LogicDekuB1WebsWithBowDesc = "Difficulty: Novice\n" // + "All spider web walls in the Deku Tree basement can" + "be burnt as adult with just a bow by shooting\n" // + "through torches. This trick only applies to the\n"// + "circular web leading to Gohma; the two vertical\n"// + "webs are always in logic. Backflip onto the chest\n" + "near the torch at the bottom of the vine wall.\n" // + "With precise positioning you can shoot through the" + "torch to the right edge of the circular web."; // +string_view LogicDekuB1SkipDesc = "Difficulty: Intermediate\n" // + "A precise jump can be used to skip needing to use\n" + "the Slingshot to go around B1 of the Deku Tree. If" + "used with the \"Closed Forest\" setting, a\n" // + "Slingshot will not be guaranteed to exist\n" // + "somewhere inside the Forest. This trick applies to" + "both Vanilla and Master Quest."; // +string_view LogicDekuBasementGSDesc = "Difficulty: Intermediate\n" // + "Can be defeated by doing a precise jump slash."; // +string_view LogicDCStaircaseDesc = "Difficulty: Intermediate\n" // + "The Bow can be used to knock down the stairs with\n" + "two well-timed shots."; // +string_view LogicDCJumpDesc = "Difficulty: Novice\n" // + "Jump is adult only."; // +string_view LogicDCSlingshotSkipDesc = "Difficulty: Expert\n" // + "With precise platforming, child can cross the\n" // + "platforms while the flame circles are there. When\n" + "enabling this trick, it's recommended that you\n" // + "also enable the Adult variant: \"Dodongo's Cavern\n" + "Spike Trap Room Jump without Hover Boots\"."; // +string_view LogicDCScarecrowGSDesc = "Difficulty: Intermediate\n" // + "You can jump off an Armos Statue to reach the\n" // + "alcove with the Gold Skulltula. It takes quite a\n" + "long time to pull the statue the entire way. The\n" + "jump to the alcove can be a bit picky when done\n"// + "as child."; // +string_view LogicJabuBossGSAdultDesc = "Difficulty: Intermediate\n" // + "You can easily get over to the door to the near\n"// + "boss area early with Hover Boots. The tricky part\n" + "is getting through the door without being able to\n" + "use a box to keep the switch pressed. One way is\n" + "to quickly roll from the switch and open the door\n" + "before it closes."; // +string_view LogicJabuScrubJumpDiveDesc = "Difficulty: Novice\n" // + "Standing above the underwater tunnel leading to\n"// + "the scrub, jump down and swim through the tunnel.\n" + "This allows adult to access the scrub with no\n" // + "Scale or Iron Boots."; // +string_view LogicForestOutsideBackdoorDesc = "Difficulty: Intermediate\n" // + "With a precise jump slash from above, you can\n" // + "reach the backdoor to the west courtyard without\n" + "Hover Boots. Applies to both Vanilla and Master\n"// + "Quest."; // +string_view LogicForestDoorFrameDesc = "Difficulty: Intermediate\n" // + "A precise Hover Boots movement from the upper\n" // + "balconies in this courtyard can be used to get on\n" + "top of the door frame. Applies to both Vanilla and" + "Master Quest. In Vanilla, from on top the door\n" // + "frame you can summon Pierre, allowing you to\n" // + "access the falling ceiling room early. In Master\n" + "Quest, this allows you to obtain the GS on the\n" // + "door frame as adult without Hookshot or Song of\n"// + "Time."; // +string_view LogicForestOutdoorEastGSDesc = "Difficulty: Novice\n" // + "Precise Boomerang throws can allow child to kill\n" + "the Skulltula and collect the token."; // +string_view LogicFireBossDoorJumpDesc = "Difficulty: Intermediate\n" // + "The Fire Temple Boss Door can be reached with a\n"// + "precise jump. You must be touching the side wall\n" + "of the room so that Link will grab the ledge from\n" + "farther away than is normally possible."; // +string_view LogicFireStrengthDesc = "Difficulty: Expert\n" // + "A precise jump can be used to skip pushing the\n" // + "block."; // +string_view LogicFireScarecrowDesc = "Difficulty: Novice\n" // + "Also known as \"Pixelshot\". The Longshot can\n" // + "reach the target on the elevator itself, allowing\n" + "you to skip needing to spawn the scarecrow."; // +string_view LogicFireFlameMazeDesc = "Difficulty: Expert\n" // + "If you move quickly you can sneak past the edge of" + "a flame wall before it can rise up to block you.\n" + "To do it without taking damage is more precise.\n"// + "Allows you to progress without needing either a\n"// + "Small Key or Hover Boots."; // +string_view LogicFireSongOfTimeDesc = "Difficulty: Intermediate\n" // + "A precise jump can be used to reach this room."; // +string_view LogicWaterTempleTorchLongshotDesc = "Difficulty: Novice\n" // + "Stand on the eastern side of the central pillar\n"// + "and longshot the torches on the bottom level.\n" // + "Swim through the corridor and float up to the top\n" + "level. This allows access to this area and lower\n" + "water levels without Iron Boots. The majority of\n" + "the tricks that allow you to skip Iron Boots in\n"// + "the Water Temple are not going to be relevant\n" // + "unless this trick is first enabled."; // +string_view LogicWaterTempleUpperBoostDesc = "Difficulty: Expert\n" // + "Stand on the corner closest to the upper ledge\n" // + "where you play Zelda's Lullaby to raise the water\n" + "and put a bomb down behind you. Hold forward when\n" + "the bomb explodes and Link should jump just far\n"// + "enough to grab the ledge."; // +string_view LogicWaterCentralBowDesc = "Difficulty: Intermediate\n" // + "A very precise Bow shot can hit the eye switch\n" // + "from the floor above. Then, you can jump down into" + "the hallway and make through it before the gate\n"// + "closes. It can also be done as child, using the\n"// + "Slingshot instead of the Bow."; // +string_view LogicWaterCentralGSFWDesc = "Difficulty: Novice\n" // + "If you set Farore's Wind inside the central pillar" + "and then return to that warp point after raising\n" + "the water to the highest level, you can obtain\n" // + "this Skulltula Token with Hookshot or Boomerang.";// +string_view LogicWaterCrackedWallNothingDesc = "Difficulty: Expert\n" // + "A precise jump slash (among other methods) will\n"// + "get you to the cracked wall without needing the\n"// + "Hover Boots or to raise the water to the middle\n"// + "level. This trick supersedes \"Water Temple\n" // + "Cracked Wall with Hover Boots\"."; // +string_view LogicWaterCrackedWallHoversDesc = "Difficulty: Expert\n" // + "With a midair side-hop while wearing the Hover\n" // + "Boots, you can reach the cracked wall without\n" // + "needing to raise the water up to the middle level."; +string_view LogicWaterBossKeyRegionDesc = "Difficulty: Intermediate\n" // + "With precise Hover Boots movement it is possible\n" + "to reach the boss key chest's region without\n" // + "needing the Longshot. It is not necessary to take\n" + "damage from the spikes. The Gold Skulltula Token\n" + "in the following room can also be obtained with\n"// + "just the Hover Boots."; // +string_view LogicWaterBKJumpDiveDesc = "Difficulty: Intermediate\n" // + "Stand on the very edge of the raised corridor\n" // + "leading from the push block room to the rolling\n"// + "boulder corridor. Face the gold skulltula on the\n" + "waterfall and jump over the boulder corridor floor" + "into the pool of water, swimming right once\n" // + "underwater. This allows access to the boss key\n" // + "room without Iron boots."; // +string_view LogicWaterNorthBasementLedgeJumpDesc = "Difficulty: Novice\n" // + "In the northern basement there's a ledge from\n" // + "where, in vanilla Water Temple, boulders roll out\n" + "into the room. Normally to jump directly to this\n" + "ledge logically requires the Hover Boots, but with" + "precise jump, it can be done without them. This\n"// + "trick applies to both Vanilla and Master Quest."; // +string_view LogicWaterDragonAdultDesc = "Difficulty: Expert\n" // + "Normally you need both Hookshot and Iron Boots to\n" + "hit the switch and swim through the tunnel to get\n" + "to the chest. But by hitting the switch from dry\n" + "land, using one of Bombchus, Hookshot, or Bow, it\n" + "is possible to skip one or both of those\n" // + "requirements. After the gate has been opened, a\n"// + "well-timed dive with at least the Silver Scale\n" // + "could be used to swim through the tunnel."; // +string_view LogicWaterDragonJumpDiveDesc = "Difficulty: Expert\n" // + "If you come into the dragon statue room from the\n" + "serpent river, you can jump down from above and\n"// + "get into the tunnel without needing either Iron\n"// + "Boots or a Scale. This trick applies to both\n" // + "Vanilla and Master Quest. In Vanilla, you must\n" // + "shoot the switch from above with the Bow, and then" + "quickly get through the tunnel before the gate\n" // + "closes."; // +string_view LogicWaterRiverGSDesc = "Difficulty: Novice\n" // + "Standing on the exposed ground toward the end of\n" + "the river, a precise Longshot use can obtain the\n" + "token."; // +string_view LogicWaterFallingPlatformGSDesc = "Difficulty: Intermediate\n" // + "If you stand on the very edge of the platform,\n" // + "this Gold Skulltula can be obtained with only the\n" + "Hookshot."; // +string_view LogicSpiritLowerAdultSwitchDesc = "Difficulty: Novice\n" // + "A bomb can be used to hit the switch on the\n" // + "ceiling, but it must be thrown from a particular\n" + "distance away and with precise timing."; // +string_view LogicSpiritChildBombchuDesc = "Difficulty: Intermediate\n" // + "A carefully-timed Bombchu can hit the switch."; // +string_view LogicSpiritWallDesc = "Difficulty: Expert\n" // + "The logic normally guarantees a way of dealing\n" // + "with both the Beamos and the Walltula before\n" // + "climbing the wall."; // +string_view LogicSpiritLobbyGSDesc = "Difficulty: Intermediate\n" // + "Standing on the highest part of the arm of the\n" // + "statue, a precise Boomerang throw can kill and\n" // + "obtain this Gold Skulltula. You must throw the\n" // + "Boomerang slightly off to the side so that it\n" // + "curves into the Skulltula, as aiming directly at\n" + "it will clank off of the wall in front."; // +string_view LogicSpiritMapChestDesc = "Difficulty: Intermediate\n" // + "To get a line of sight from the upper torch to the" + "map chest torches, you must pull an Armos statue\n" + "all the way up the stairs."; // +string_view LogicSpiritSunChestDesc = "Difficulty: Expert\n" // + "Using the blocks in the room as platforms you can\n" + "get lines of sight to all three torches. The timer" + "on the torches is quite short so you must move\n" // + "quickly in order to light all three."; // +string_view LogicShadowFireArrowEntryDesc = "Difficulty: Expert\n" // + "It is possible to light all of the torches to open" + "the Shadow Temple entrance with just Fire Arrows,\n" + "but you must be very quick, precise, and strategic" + "with how you take your shots."; // +string_view LogicShadowUmbrellaDesc = "Difficulty: Expert\n" // + "A very precise Hover Boots movement from off of\n"// + "the lower chest can get you on top of the crushing\n" + "spikes without needing to pull the block. Applies\n" + "to both Vanilla and Master Quest."; // +string_view LogicShadowFreestandingKeyDesc = "Difficulty: Intermediate\n" // + "Release the Bombchu with good timing so that it\n"// + "explodes near the bottom of the pot."; // +string_view LogicShadowStatueDesc = "Difficulty: Novice\n" // + "By sending a Bombchu around the edge of the gorge," + "you can knock down the statue without needing a\n"// + "Bow. Applies in both vanilla and MQ Shadow."; // +string_view LogicChildDeadhandDesc = "Difficulty: Novice\n" // + "Requires 9 sticks or 5 jump slashes."; // +string_view LogicGtgWithoutHookshotDesc = "Difficulty: Expert\n" // + "The final silver rupee on the ceiling can be\n" // + "reached by being pulled up into it by the\n" // + "Wallmaster.\n" // + "Then, you must also reach the exit of the room\n" // + "without the use of the Hookshot. If you move\n" // + "quickly, you can sneak past the edge of a\n" // + "flame wall before it can rise up to block you.\n" // + "To do so without taking damage is more precise"; // +string_view LogicGtgFakeWallDesc = "Difficulty: Novice\n" // + "A precise Hover Boots use from the top of the\n" // + "chest can allow you to grab the ledge without\n" // + "needing the usual requirements."; // +string_view LogicLensSpiritDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Spirit Temple."; // +string_view LogicLensShadowDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Shadow Temple before the invisible moving platform"; +string_view LogicLensShadowBackDesc = "Difficulty: Intermediate\n" // + "Removes the requirements for the Lens of Truth in\n" + "Shadow Temple beyond the invisible moving platform"; +string_view LogicLensBotwDesc = "Difficulty: Intermediate\n" // + "Removes the requirements for the Lens of Truth in\n" + "Bottom of the Well."; // +string_view LogicLensGtgDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Gerudo Training Grounds."; // +string_view LogicLensCastleDesc = "Difficulty: Intermediate\n" // + "Removes the requirements for the Lens of Truth in\n" + "Ganon's Castle."; // +string_view LogicLensJabuMQDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Jabu Jabu's Belly MQ."; // +string_view LogicLensSpiritMQDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Spirit Temple MQ."; // +string_view LogicLensShadowMQDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Shadow Temple MQ before the invisible moving \n" // + "platform"; // +string_view LogicLensShadowMQBackDesc = "Difficulty: Intermediate\n" // + "Removes the requirements for the Lens of Truth in\n" + "Shadow Temple MQ beyond the invisible moving \n" // + "platform"; // +string_view LogicLensBotwMQDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Bottom of the Well MQ."; // +string_view LogicLensGtgMQDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Gerudo Training Grounds MQ."; // +string_view LogicLensCastleMQDesc = "Difficulty: Intermediate\n" // + "Removes the requirements for the Lens of Truth in\n" + "Ganon's Castle MQ."; // +string_view LogicSpiritTrialHookshotDesc = "Difficulty: Intermediate\n" // + "A precise jump off of an Armos can collect the\n" // + "highest rupee."; // + // +string_view LogicFlamingChestsDesc = "Difficulty: Novice\n" // + "The chests encircled in flames in Gerudo Training\n" + "Grounds and in Spirit Temple can be opened by\n" // + "running into the flames while Link is invincible\n" + "after taking damage."; // + // +/*------------------------------ // +| GLITCHES | // +------------------------------*/ // +const std::vector GlitchDifficulties{"Novice", "Intermediate", "Advanced", "Expert", "Hero"}; // +/* Restricted Items */ // +string_view GlitchRestrictedItemsDescDisabled = "Swapping an item that can normally be used in an\n" + "area with one that would be dimmed will let you\n" + "use that item for 1 frame after closing your\n" // + "inventory. This can be useful on its own or in\n" // + "combination with other glitches."; // +string_view GlitchRestrictedItemsDescNovice = "You may be required to use restricted items."; // +/* Super Stab */ // +string_view GlitchSuperStabDescDisabled = "Forcing sticks to unequip during a crouch stab by\n" + "breaking it and moving them in your inventory has\n" + "the effect of hitting all spherical collision."; // +string_view GlitchSuperStabDescNovice = "You may be expected to hit switches or kill gold\n" + "skulltulas with a super stab."; // +/* ISG */ // +string_view GlitchISGDescDisabled = "Shortened to ISG, allows Link's melee weapon to\n"// + "be in a constant swinging state. Simply touching\n" + "objects with this causes them to get hit.\n" // + "Putting away the weapon while ISG is on hits\n" // + "any object with a spherical hitbox,\n" // + "such as small skulltulas. It is initiated by\n" // + "interrupting a crouch stab."; // +string_view GlitchISGDescNovice = "ISG may be required to kill certain enemies,\n" // + "or to Bomb Hover when enabled."; // +string_view GlitchISGDescIntermediate = "You may be required to use a bomb to activate ISG."; +string_view GlitchISGDescAdvanced = "You may be required to use a bomb to activate ISG\n" + "repeatedly or while under attack."; // +/* Hover */ // +string_view GlitchHoverDescDisabled = "Hovering allows Link to consecutively backflip\n" // + "in the air without falling. By shielding\n" // + "damage with ISG on, Link will stay in midair.\n" // + "While bombs aren't always required, this option\n"// + "will always expect them to be used.\n" // + "\n" // + "Requires ISG to be enabled."; // +string_view GlitchHoverDescNovice = "Only bombchus are required for hovering."; // +string_view GlitchHoverDescIntermediate = "Some hovers may require that you start from flat\n" + "terrain, which requires somewhat precise timing.";// +string_view GlitchHoverDescAdvanced = "Usage of regular bombs will now also be expected,\n" + "which may require consecutive precise timings."; // +/* Bomb OI */ // +string_view GlitchBombOIDescDisabled = "Allowing a bomb to explode in Link's hands while\n" + "moving and then attempting to pull out a cutscene\n" + "item on a specific frame will cause Link to play\n" + "an invisible ocarina instead.\n" // + "This will only work if bombs are not dimmed on the" + "frame you use the cutscene item."; // +string_view GlitchBombOIDescNovice = "You may be expected to use ocarina items with a\n"// + "bomb to play warp songs."; // +string_view GlitchBombOIDescIntermediate = "You may be expected to use ocarina items with a\n"// + "bomb to play the ocarina where Link's position\n" // + "matters."; // +string_view GlitchBombOIDescAdvanced = "You may be expected to use restricted items to use" + "the cutscene item or to make the bombs usable on\n" + "the correct frame."; // +string_view GlitchBombOIDescExpert = "You may be expected to use restricted items to\n" // + "perform ocarina items where Link's position isn't\n" + "particularly lenient"; // +/* Hover Boost */ // +string_view GlitchHoverBoostDescDisabled = "Equipping hover boots when Link takes damage will\n" + "cause him to keep the high knockback speed and\n" // + "lets him traverse large gaps.\n" // + "If performed at the edge of a platform Link will\n" + "instead perform a mega jump which has less range\n" + "but more height than a hover boost."; // +string_view GlitchHoverBoostDescNovice = "Hover boosts that do not need the maximum speed\n"// + "may be required."; // +string_view GlitchHoverBoostDescIntermediate = "Hover boosts that do need the maximum speed may be" + "required."; // +string_view GlitchHoverBoostDescAdvanced = "Hover boosts that use more complex movement during" + "the hover may be required."; // +/* Super Slide */ // +string_view GlitchSuperSlideDescDisabled = "Holding the circle pad just outside the dead zone\n" + "will cause Link to turn on the spot which locks\n"// + "his speed. This can be used to preserve high\n" // + "speeds indefinitely."; // +string_view GlitchSuperSlideDescNovice = "Forward extended super slides (FESSes) where Link\n" + "is damaged by an explosion may be required."; // +string_view GlitchSuperSlideDescIntermediate = "Hammer extended super slides where the recoil from" + "a hammer crouch stab is used may be required."; // +string_view GlitchSuperSlideDescAdvanced = "Hyper Extended Super Slides (HESSes) and\n" // + "damageless FESSes where Link rolls into a bomb may" + "be required."; // +string_view GlitchSuperSlideDescExpert = "HESSes with more precise movement may be required."; +/* Megaflip */ // +string_view GlitchMegaflipDescDisabled = "A backflip or sidehop with high speed from an\n" // + "attack hitting your shield during i-frames. This\n" + "is normally achieved by rolling into an explosion.\n" + "Equipping hover boots to preserve the high speed\n" + "when landing is known as a hoverflip."; // +string_view GlitchMegaflipDescNovice = "You may be expected to perform megaflips on flat\n" + "ground with bombs."; // +string_view GlitchMegaflipDescIntermediate = "You may be expected to perform megaflips in small\n" + "areas, distance megaflips, or hoverflips with a\n"// + "bomb."; // +string_view GlitchMegaflipDescAdvanced = "You may be expected to perform hoverflips with\n" // + "difficult midair movement, or distance megaflips\n" + "under time pressure with a bomb.\n\n" // + "Additionally, you may be expected to perform\n" // + "novice megaflips with a bombchu"; // +string_view GlitchMegaflipDescExpert = "You may be expected to perform intermediate\n" // + "megaflips with a bombchu."; // +string_view GlitchMegaflipDescHero = "You may be expected to perform any megaflip with a" + "bombchu."; // +/* A-Slide */ // +string_view GlitchASlideDescDisabled = "An A-slide is performed the same as a megaflip\n" // + "except without pressing the A button at the end.\n" + "This causes child Link's collision to glitch below" + "the ground and lets him bypass certain actors."; // +string_view GlitchASlideDescNovice = "You may be expected to perform A-slides to pass\n"// + "actors you can't press A to interact with."; // +string_view GlitchASlideDescIntermediate = "You may be expected to perform A-slides quickly or" + "around actors that can be interacted with."; // +string_view GlitchASlideDescAdvanced = "You may be expected to perform novice A-slides\n" // + "with a bombchu."; // +string_view GlitchASlideDescExpert = "You may be expected to perform intermediate\n" // + "A-slides with a bombchu."; +/* Hammer Slide */ // +string_view GlitchHammerSlideDescDisabled = "Equipping hover boots after a hammer crouch stab\n" + "against a wall preserves the recoil speed which\n"// + "allows Link to cross larger gaps than usual."; // +string_view GlitchHammerSlideDescNovice = "Simple hammer slides may be required"; // +string_view GlitchHammerSlideDescIntermediate = "Hammer slides which require good movement and high" + "speed may be required."; // +/* Ledge Cancel */ // +string_view GlitchLedgeCancelDescDisabled = "Climbing a short ledge and shielding damage will\n" + "prevent the ledge climbing state from ending.\n" // + "This state allows Link to walk through some actors" + "such as boulders and NPCs."; // +string_view GlitchLedgeCancelDescNovice = "You may be expected to perform ledge cancels using" + "bombs as a damage source."; // +string_view GlitchLedgeCancelDescIntermediate = "You may be expected to perform ledge cancels in\n"// + "places with little room."; // +string_view GlitchLedgeCancelDescAdvanced = "You may be expected to perform ledge cancels using" + "bombchus as a damage source."; // +/* Action Swap */ // +string_view GlitchActionSwapDescDisabled = "Action swap allows Link to switch between 2 held\n" + "items without the put away/equip animations.\n" // + "This can be exploited to produce various effects."; +string_view GlitchActionSwapDescNovice = "You may be expected to use shallow water to set up" + "action swap."; // +string_view GlitchActionSwapDescAdvanced = "You may be expected to use bombchus to set up\n" // + "action swap."; // +/* QPA */ // +string_view GlitchQPADescDisabled = "Certain events can cancel putting away an item\n" // + "which later lets Link put it away without an\n" // + "animation. This can be used with sticks to access\n" + "a glitched damage value with the properties of\n" // + "hammer and fire arrows, or with a bottle to store\n" + "a cutscene for ocarina items."; // +string_view GlitchQPADescNovice = "You may be expected to get QPA using the boots\n" // + "animation to delay putting away the item and a\n" // + "bomb."; // +string_view GlitchQPADescIntermediate = "You may be expected to get QPA using only a bomb."; +string_view GlitchQPADescAdvanced = "You may be expected to get QPA using a ledge grab\n" + "to interrupt putting away the item."; // +string_view GlitchQPADescExpert = "You may be expected to get QPA from enemy attacks."; +/* Hookshot Clip */ // +string_view GlitchHookshotClipDescDisabled = "Hookshot Clipping allows Link to hookshot through\n" + "certain walls, which is useful if a valid\n" // + "target is on the other side."; // +string_view GlitchHookshotClipDescNovice = "Basic Hookshot Clipping may be required."; // +string_view GlitchHookshotClipDescIntermediate = "Hookshot clips with precise angles and poor\n" // + "visibility may be required."; // +/* Hookshot Jump: Bonk */ // +string_view GlitchHookshotJump_BonkDescDisabled = "A Hookshot Jump is an umbrella term for techniques" + "that launch Link into the sky using the Hookshot\n" + "in various ways, sometimes together with\n" // + "other items. The bonk method only requires the\n" // + "Hookshot itself."; // +string_view GlitchHookshotJump_BonkDescNovice = "Simple hookshot jumps against large flat walls of\n" + "hookshottable surfaces may be required."; // +string_view GlitchHookshotJump_BonkDescIntermediate = "Less lenient hookshot jumps may be required."; // +string_view GlitchHookshotJump_BonkDescAdvanced = "Hookshot jumps with precise midair movement may be" + "required."; // +/* Hookshot Jump: Boots */ // +string_view GlitchHookshotJump_BootsDescDisabled = "This Hookshot Jump technique is one of the easier\n" + "ones, and require any pair of boots."; // +string_view GlitchHookshotJump_BootsDescNovice = "Only relatively short Hookshot Jumps with boots\n"// + "may be required."; // +string_view GlitchHookshotJump_BootsDescIntermediate = "Higher Hookshot Jumps with boots, where you look\n" + "further up or downwards may be required."; // +string_view GlitchHookshotJump_BootsDescAdvanced = "Hookshot jumps that require a lot of height and\n"// + "precise midair movement may be required."; // +/* Cutscene Dives */ // +string_view GlitchCutsceneDiveDescDisabled = "Water physics won't effect Link if he enters the\n" + "water while a cutscene is playing, allowing him\n"// + "to sink to the bottom."; // +string_view GlitchCutsceneDiveDescNovice = "Attempting to use Farore's Wind (when it's already" + "set) with another magic item active prevents the\n" + "water from clearing the FW cutscene until the\n" // + "other effect ends.\n" // + "You may be expected to use Nayru's Love as the\n" // + "other magic effect."; // +string_view GlitchCutsceneDiveDescIntermediate = "You can catch something in a bottle while standing" + "over water using the hover boots to fall through\n" + "the water during the catching cutscene."; // +string_view GlitchCutsceneDiveDescAdvanced = "You may be expected to use magic arrows to perform" + "Farore's Wind cutscene dives."; // +/* Navi Dive: Stick */ // +string_view GlitchNaviDive_StickDescDisabled = "A Navi dive is a type of cutscene dive achieved by" + "falling off a ledge while talking to Navi. While\n" + "the usual method for achieving this is a TSC, it\n" + "is also possible to perform using a jump attack\n"// + "with deku sticks."; // +string_view GlitchNaviDive_StickDescNovice = "You may be expected to enter BotW with a stick\n" // + "Navi dive."; // +string_view GlitchNaviDive_StickDescIntermediate = "You may be expected to use the LH to ZD shortcut\n" + "with a stick Navi dive."; // +string_view GlitchNaviDive_StickDescAdvanced = "You may be expected to use the LW to ZR shortcut\n" + "with a stick Navi dive."; // +/* TSC */ // +string_view GlitchTripleSlashClipDescDisabled = "When doing a three-slash-combo with either the\n" // + "Kokiri Sword or the Master Sword and put it away,\n" + "Link will be placed back a small distance.\n" // + "If, while slashing, you use the recoil of hitting\n" + "a wall and then put away the sword, Link may clip\n" + "into a wall behind him if angled correctly."; // +string_view GlitchTripleSlashClipDescNovice = "Basic Triple Slash Clipping may be required."; // +string_view GlitchTripleSlashClipDescIntermediate = "Some more complex OoB movement may be required."; // +string_view GlitchTripleSlashClipDescAdvanced = "Very precise OoB movement may be required."; // +string_view GlitchTripleSlashClipDescExpert = "Very precise TSCs may be required."; // +/* Ledge Clip */ // +string_view GlitchLedgeClipDescDisabled = "A Ledge Clip allows Link to fall through a floor\n" + "or pass through an object by facing a wall\n" // + "and dropping down to the left in various ways.\n" // + "These only work as an adult."; // +string_view GlitchLedgeClipDescNovice = "Basic Ledge Clips may be required.\n" // + "Some require that you let go of the ledge with\n" // + "a specific timing."; // +string_view GlitchLedgeClipDescIntermediate = "Certain harder clips may also be required."; // +string_view GlitchLedgeClipDescAdvanced = "Ledge clips with complex OoB movement may be\n" // + "required."; // +/* Seam Walk */ // +string_view GlitchSeamWalkDescDisabled = "Where 2 walls come together they form a seam that\n" + "Link can stand on. It is possible to use these to\n" + "gain height and reach normally inaccessible areas.\n" + "Additionally these seams can reach far above the\n" + "walls that form them, creating invisible seams."; // +string_view GlitchSeamWalkDescNovice = "Short seam walks up visible walls with ISG may be\n" + "required."; // +string_view GlitchSeamWalkDescIntermediate = "Short seam walks up visible walls without ISG or\n" + "longer seam walks with ISG may be required."; // +string_view GlitchSeamWalkDescAdvanced = "Longer seam walks without ISG may be required."; // +string_view GlitchSeamWalkDescExpert = "Very precise seam walks may be required."; // +string_view GlitchSeamWalkDescHero = "Crossing Gerudo Valley as child by walking up a\n"// + "wall with the cucco may be required."; // +/* Misc Glitches */ // +string_view GlitchWWTEscapeDesc = "Using deku nuts and the crawlspace to let you\n" // + "move while reading the nearby sign, you can walk\n" + "through the Kokiri guarding the exit. This only\n"// + "affects logic with shuffled entrances."; // +string_view GlitchGVTentAsChildDesc = "The loading zone for the carpenters' tent exists\n" + "in the child map despite the tent being removed.\n\n" + "With this setting enabled you may be expected to\n" + "use that loading zone."; // +string_view GlitchGFGuardSneakDesc = "By using the bow, hookshot, or boomerang while\n" // + "looking up and targeting the Fortress wall, you\n"// + "can walk\n past the guard on the slope without\n" // + "being caught."; // +string_view GlitchItemlessWastelandDesc = "By starting a backwalk and then targeting every\n"// + "other frame Link will maintain backwalk speed\n" // + "over the quicksand in the haunted wasteland which\n" + "lets him cross with no items."; // +string_view GlitchOccamsStatueDesc = "With some precise movement through loading zones\n" + "in Darunia's room, it is possible to unload the\n"// + "collision of the statue blocking the way to DMC.";// +string_view GlitchZDOoBJumpSlashDesc = "Jump slashing the wall next to the pillar above\n"// + "the ZD to LH shortcut as adult will let you clip\n" + "through. From here you can either jump to the shop" + "loading zone or fall OoB a little bit and swim\n" // + "into the shortcut loading zone."; // +string_view GlitchJabuStickRecoilDesc = "Child can enter Jabu without a fish in a bottle\n"// + "using the recoil from breaking a deku stick while\n" + "sidehopping next to the loading zone."; // +string_view GlitchJabuAdultDesc = "Adult can enter Jabu by walking over a specific\n"// + "section of ice on the side near ice cavern."; // +string_view GlitchBlueFireWallDesc = "Pouring blue fire on certain destructable walls\n"// + "will cause them to break."; // +string_view GlitchClassicHalfieDesc = "Dying during a jump attack towards a ledge just\n"// + "too high to climb will put Link on top of the\n" // + "ledge. Combined with a fairy this lets Link climb\n" + "ledges such as the one to the switch in DC."; // +string_view GlitchModernHalfieDesc = "Using a bomb flower and a twisted backflip, it is\n" + "possible to access the switch in DC with only a\n"// + "deku shield and the goron bracelet."; // +string_view GlitchJabuSwitchDesc = "Using a cutscene item the frame you land on the\n"// + "blue switches in Jabu Jabu's Belly will make them\n" + "stay held for a while after you step off them."; // +string_view GlitchForestBKSkipDesc = "Using the hookshot or bow to shorten a backflip\n"// + "it is possible to land on the other side of the\n"// + "railing in the north of the lobby and get clipped\n" + "out of bounds. From here it is possible to jump\n"// + "into the boss loading zone."; // +string_view GlitchFireGrunzClipDesc = "Grabbing a ledge in a corner partially clips Link\n" + "through the wall. A bomb can be used to push Link\n" + "fully through the wall to get out of bounds. This\n" + "can be used in the fire temple along with hover\n"// + "boots to skip hammer in the first room."; // diff --git a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp new file mode 100644 index 000000000..396fdd24c --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp @@ -0,0 +1,541 @@ +#pragma once +#include +#include + +using string_view = std::string_view; + +extern string_view openRandomize; +extern string_view worldRandomize; +extern string_view shuffleRandomize; +extern string_view dungeonRandomize; + +extern string_view logicGlitchless; +extern string_view logicGlitched; +extern string_view logicNoLogic; +extern string_view logicVanilla; + +extern string_view forestOpen; +extern string_view forestClosed; +extern string_view forestClosedDeku; + +extern string_view kakGateOpen; +extern string_view kakGateClosed; + +extern string_view doorOfTimeOpen; +extern string_view doorOfTimeClosed; +extern string_view doorOfTimeIntended; + +extern string_view fountainNormal; +extern string_view fountainAdult; +extern string_view fountainOpen; + +extern string_view gerudoNormal; +extern string_view gerudoFast; +extern string_view gerudoOpen; + +extern string_view bridgeOpen; +extern string_view bridgeVanilla; +extern string_view bridgeStones; +extern string_view bridgeMedallions; +extern string_view bridgeRewards; +extern string_view bridgeDungeons; +extern string_view bridgeTokens; + +extern string_view bridgeStoneCountDesc; +extern string_view bridgeMedallionCountDesc; +extern string_view bridgeRewardCountDesc; +extern string_view bridgeDungeonCountDesc; +extern string_view bridgeTokenCountDesc; + +extern string_view randomGanonsTrialsDesc; + +extern string_view ganonsTrialCountDesc; + +extern string_view ageDesc; + +extern string_view shuffleEntrancesDesc; + +extern string_view dungeonEntrancesDesc; + +extern string_view overworldEntrancesDesc; + +extern string_view grottoEntrancesDesc; + +extern string_view interiorEntrancesOff; +extern string_view interiorEntrancesSimple; +extern string_view interiorEntrancesAll; + +extern string_view bombchuLogicDesc; + +extern string_view defaultAmmoDropsDesc; +extern string_view bombchuDropsDesc; +extern string_view noAmmoDropsDesc; + +extern string_view defaultHeartDropsDesc; +extern string_view noHeartDropsDesc; +extern string_view noHeartRefillDesc; +extern string_view scarceHeartsDesc; + +extern string_view mqDungeonCountDesc; +extern string_view setDungeonTypesDesc; + +extern string_view shuffleRewardsEndOfDungeon; +extern string_view shuffleRewardsAnyDungeon; +extern string_view shuffleRewardsOverworld; +extern string_view shuffleRewardsAnywhere; + +extern string_view linksPocketDungeonReward; +extern string_view linksPocketAdvancement; +extern string_view linksPocketAnything; +extern string_view linksPocketNothing; + +extern string_view songsSongLocations; +extern string_view songsDungeonRewards; +extern string_view songsAllLocations; + +extern string_view shopsOff; +extern string_view shopsZero; +extern string_view shopsOne; +extern string_view shopsTwo; +extern string_view shopsThree; +extern string_view shopsFour; +extern string_view shopsRandom; + +extern string_view tokensOff; +extern string_view tokensDungeon; +extern string_view tokensOverworld; +extern string_view tokensAllTokens; + +extern string_view scrubsOff; +extern string_view scrubsAffordable; +extern string_view scrubsExpensive; +extern string_view scrubsRandomPrices; + +extern string_view shuffleCowsDesc; + +extern string_view kokiriSwordDesc; + +extern string_view ocarinasDesc; + +extern string_view weirdEggDesc; + +extern string_view gerudoTokenDesc; + +extern string_view magicBeansDesc; + +extern string_view merchantsDesc; +extern string_view merchantsHintsDesc; + +extern string_view adultTradeDesc; + +extern string_view chestMinigameDesc; + +extern string_view mapCompassStartWith; +extern string_view mapCompassVanilla; +extern string_view mapCompassOwnDungeon; +extern string_view mapCompassAnyDungeon; +extern string_view mapCompassOverworld; +extern string_view mapCompassAnywhere; + +extern string_view smallKeyStartWith; +extern string_view smallKeyVanilla; +extern string_view smallKeyOwnDungeon; +extern string_view smallKeyAnyDungeon; +extern string_view smallKeyOverworld; +extern string_view smallKeyAnywhere; + +extern string_view gerudoKeysVanilla; +extern string_view gerudoKeysAnyDungeon; +extern string_view gerudoKeysOverworld; +extern string_view gerudoKeysAnywhere; + +extern string_view keyRingDesc; + +extern string_view bossKeyStartWith; +extern string_view bossKeyVanilla; +extern string_view bossKeyOwnDungeon; +extern string_view bossKeyAnyDungeon; +extern string_view bossKeyOverworld; +extern string_view bossKeyAnywhere; + +extern string_view ganonKeyStartWith; +extern string_view ganonKeyVanilla; +extern string_view ganonKeyOwnDungeon; +extern string_view ganonKeyAnyDungeon; +extern string_view ganonKeyOverworld; +extern string_view ganonKeyAnywhere; +extern string_view ganonKeyLACS; + +extern string_view lacsMedallionCountDesc; +extern string_view lacsStoneCountDesc; +extern string_view lacsRewardCountDesc; +extern string_view lacsDungeonCountDesc; +extern string_view lacsTokenCountDesc; + +extern string_view childStealthDesc; + +extern string_view skipTowerEscapeDesc; + +extern string_view skipEponaRaceDesc; + +extern string_view skipMinigamePhasesDesc; + +extern string_view freeScarecrowDesc; + +extern string_view fourPoesDesc; + +extern string_view lakeHyliaOwlDesc; + +extern string_view bigPoeTargetCountDesc; + +extern string_view numRequiredCuccosDesc; + +extern string_view kingZoraSpeedFast; +extern string_view kingZoraSpeedVanilla; +extern string_view kingZoraSpeedRandom; + +extern string_view completeMaskDesc; + +extern string_view quickTextDesc0; +extern string_view quickTextDesc1; +extern string_view quickTextDesc2; +extern string_view quickTextDesc3; +extern string_view skipSongReplaysDesc; + +extern string_view keepFWWarpPointDesc; + +extern string_view fastBunnyHoodDesc; + +extern string_view gossipStonesHintsDesc; + +extern string_view obscureHintsDesc; +extern string_view ambiguousHintsDesc; +extern string_view clearHintsDesc; + +extern string_view uselessHintsDesc; +extern string_view balancedHintsDesc; +extern string_view strongHintsDesc; +extern string_view veryStrongHintsDesc; + +extern string_view compassesShowRewardsDesc; +extern string_view compassesShowWotHDesc; +extern string_view mapsShowDungeonModesDesc; + +extern string_view damageMultiDesc; + +extern string_view startingTimeDesc; + +extern string_view locationsReachableDesc; +extern string_view nightGSDesc; + +extern string_view chestAnimDesc; + +extern string_view chestSizeDesc; + +extern string_view ingameSpoilersShowDesc; +extern string_view ingameSpoilersHideDesc; + +extern string_view menuButtonDesc; + +extern string_view startWithConsumablesDesc; + +extern string_view startWithMaxRupeesDesc; + +extern string_view itemPoolPlentiful; +extern string_view itemPoolBalanced; +extern string_view itemPoolScarce; +extern string_view itemPoolMinimal; + +extern string_view iceTrapsOff; +extern string_view iceTrapsNormal; +extern string_view iceTrapsExtra; +extern string_view iceTrapsMayhem; +extern string_view iceTrapsOnslaught; + +extern string_view removeDDDesc; + +extern string_view progGoronSword; + +extern string_view faroresWindAnywhereDesc; + +extern string_view ageRestrictionsDesc; +extern string_view adultStickDesc; +extern string_view adultBoomerangDesc; +extern string_view childHammerDesc; +extern string_view adultSlingshotDesc; +extern string_view childBowDesc; +extern string_view childHookshotDesc; +extern string_view childIronBootsDesc; +extern string_view childHoverBootsDesc; +extern string_view adultMasksDesc; +extern string_view adultKokiriSwordDesc; +extern string_view childMasterSwordDesc; +extern string_view childBiggoronSwordDesc; +extern string_view adultDekuShieldDesc; +extern string_view childMirrorShieldDesc; +extern string_view childGoronTunicDesc; +extern string_view childZoraTunicDesc; + +extern string_view gkDurabilityVanilla; +extern string_view gkDurabilityRandomRisk; +extern string_view gkDurabilityRandomSafe; + +extern string_view mp_EnabledDesc; +extern string_view mp_SharedProgressDesc; +extern string_view mp_SyncIdDesc; +extern string_view mp_SharedHealthDesc; +extern string_view mp_SharedRupeesDesc; +extern string_view mp_SharedAmmoDesc; + +extern string_view zTargetingDesc; +extern string_view cameraControlDesc; +extern string_view motionControlDesc; +extern string_view togglePlayMusicDesc; +extern string_view togglePlaySFXDesc; +extern string_view silenceNaviDesc; +extern string_view ignoreMaskReactionDesc; + +extern string_view naviColorsDesc; +extern string_view necessarySimpleModeDesc; +extern string_view alwaysSimpleModeDesc; + +extern string_view coloredKeysDesc; +extern string_view coloredBossKeysDesc; + +extern string_view mirrorWorldDesc; + +extern string_view musicRandoDesc; +extern string_view shuffleBGMDesc; +extern string_view fanfaresOffDesc; +extern string_view onlyFanfaresDesc; +extern string_view fanfaresOcarinaDesc; +extern string_view shuffleOcaMusicDesc; + +extern string_view shuffleSFXOff; +extern string_view shuffleSFXAll; +extern string_view shuffleSFXSceneSpecific; +extern string_view shuffleSFXChaos; +extern string_view shuffleSFXCategorically; + +extern string_view randomTrapDmgDesc; +extern string_view basicTrapDmgDesc; +extern string_view advancedTrapDmgDesc; + +extern string_view ToggleAllTricksDesc; + +extern string_view ToggleLogicNoneDesc; +extern string_view ToggleLogicNoviceDesc; +extern string_view ToggleLogicIntermediateDesc; +extern string_view ToggleLogicExpertDesc; +extern string_view LogicGrottosWithoutAgonyDesc; +extern string_view LogicVisibleCollisionDesc; +extern string_view LogicFewerTunicRequirementsDesc; +extern string_view LogicLostWoodsGSBeanDesc; +extern string_view LogicLabDivingDesc; +extern string_view LogicLabWallGSDesc; +extern string_view LogicGraveyardPoHDesc; +extern string_view LogicChildDampeRacePoHDesc; +extern string_view LogicGVHammerChestDesc; +extern string_view LogicGerudoKitchenDesc; +extern string_view LogicLensWastelandDesc; +extern string_view LogicReverseWastelandDesc; +extern string_view LogicColossusGSDesc; +extern string_view LogicOutsideGanonsGSDesc; +extern string_view LogicManOnRoofDesc; +extern string_view LogicWindmillPoHHookshotDesc; +extern string_view LogicDMTBombableDesc; +extern string_view LogicDMTSoilGSDesc; +extern string_view LogicDMTSummitHoverDesc; +extern string_view LogicLinkGoronDinsDesc; +extern string_view LogicGoronCityLeftMostDesc; +extern string_view LogicGoronCityPotDesc; +extern string_view LogicGoronCityPotWithStrengthDesc; +extern string_view LogicChildRollingWithStrengthDesc; +extern string_view LogicCraterUpperToLowerDesc; +extern string_view LogicCraterBeanPoHWithHoversDesc; +extern string_view LogicBiggoronBoleroDesc; +extern string_view LogicZoraRiverLowerDesc; +extern string_view LogicZoraRiverUpperDesc; +extern string_view LogicZFGreatFairyDesc; +extern string_view LogicDekuB1WebsWithBowDesc; +extern string_view LogicDekuB1SkipDesc; +extern string_view LogicDekuBasementGSDesc; +extern string_view LogicDCStaircaseDesc; +extern string_view LogicDCJumpDesc; +extern string_view LogicDCSlingshotSkipDesc; +extern string_view LogicDCScarecrowGSDesc; +extern string_view LogicJabuBossGSAdultDesc; +extern string_view LogicJabuScrubJumpDiveDesc; +extern string_view LogicForestOutsideBackdoorDesc; +extern string_view LogicForestDoorFrameDesc; +extern string_view LogicForestOutdoorEastGSDesc; +extern string_view LogicFireBossDoorJumpDesc; +extern string_view LogicFireStrengthDesc; +extern string_view LogicFireScarecrowDesc; +extern string_view LogicFireFlameMazeDesc; +extern string_view LogicFireSongOfTimeDesc; +extern string_view LogicWaterTempleTorchLongshotDesc; +extern string_view LogicWaterTempleUpperBoostDesc; +extern string_view LogicWaterCentralBowDesc; +extern string_view LogicWaterCentralGSFWDesc; +extern string_view LogicWaterCrackedWallNothingDesc; +extern string_view LogicWaterCrackedWallHoversDesc; +extern string_view LogicWaterBossKeyRegionDesc; +extern string_view LogicWaterBKJumpDiveDesc; +extern string_view LogicWaterNorthBasementLedgeJumpDesc; +extern string_view LogicWaterDragonAdultDesc; +extern string_view LogicWaterDragonJumpDiveDesc; +extern string_view LogicWaterRiverGSDesc; +extern string_view LogicWaterFallingPlatformGSDesc; +extern string_view LogicSpiritLowerAdultSwitchDesc; +extern string_view LogicSpiritChildBombchuDesc; +extern string_view LogicSpiritWallDesc; +extern string_view LogicSpiritLobbyGSDesc; +extern string_view LogicSpiritMapChestDesc; +extern string_view LogicSpiritSunChestDesc; +extern string_view LogicShadowFireArrowEntryDesc; +extern string_view LogicShadowUmbrellaDesc; +extern string_view LogicShadowFreestandingKeyDesc; +extern string_view LogicShadowStatueDesc; +extern string_view LogicChildDeadhandDesc; +extern string_view LogicGtgWithoutHookshotDesc; +extern string_view LogicGtgFakeWallDesc; +extern string_view LogicLensSpiritDesc; +extern string_view LogicLensShadowDesc; +extern string_view LogicLensShadowBackDesc; +extern string_view LogicLensBotwDesc; +extern string_view LogicLensGtgDesc; +extern string_view LogicLensCastleDesc; +extern string_view LogicLensJabuMQDesc; +extern string_view LogicLensSpiritMQDesc; +extern string_view LogicLensShadowMQDesc; +extern string_view LogicLensShadowMQBackDesc; +extern string_view LogicLensBotwMQDesc; +extern string_view LogicLensGtgMQDesc; +extern string_view LogicLensCastleMQDesc; +extern string_view LogicSpiritTrialHookshotDesc; +extern string_view LogicFlamingChestsDesc; + +extern const std::vector GlitchDifficulties; + +extern string_view GlitchRestrictedItemsDescDisabled; +extern string_view GlitchRestrictedItemsDescNovice; + +extern string_view GlitchSuperStabDescDisabled; +extern string_view GlitchSuperStabDescNovice; + +extern string_view GlitchISGDescDisabled; +extern string_view GlitchISGDescNovice; +extern string_view GlitchISGDescIntermediate; +extern string_view GlitchISGDescAdvanced; + +extern string_view GlitchHoverDescDisabled; +extern string_view GlitchHoverDescNovice; +extern string_view GlitchHoverDescIntermediate; +extern string_view GlitchHoverDescAdvanced; + +extern string_view GlitchBombOIDescDisabled; +extern string_view GlitchBombOIDescNovice; +extern string_view GlitchBombOIDescIntermediate; +extern string_view GlitchBombOIDescAdvanced; +extern string_view GlitchBombOIDescExpert; + +extern string_view GlitchHoverBoostDescDisabled; +extern string_view GlitchHoverBoostDescNovice; +extern string_view GlitchHoverBoostDescIntermediate; +extern string_view GlitchHoverBoostDescAdvanced; + +extern string_view GlitchSuperSlideDescDisabled; +extern string_view GlitchSuperSlideDescNovice; +extern string_view GlitchSuperSlideDescIntermediate; +extern string_view GlitchSuperSlideDescAdvanced; +extern string_view GlitchSuperSlideDescExpert; + +extern string_view GlitchMegaflipDescDisabled; +extern string_view GlitchMegaflipDescNovice; +extern string_view GlitchMegaflipDescIntermediate; +extern string_view GlitchMegaflipDescAdvanced; +extern string_view GlitchMegaflipDescExpert; +extern string_view GlitchMegaflipDescHero; + +extern string_view GlitchASlideDescDisabled; +extern string_view GlitchASlideDescNovice; +extern string_view GlitchASlideDescIntermediate; +extern string_view GlitchASlideDescAdvanced; +extern string_view GlitchASlideDescExpert; + +extern string_view GlitchHammerSlideDescDisabled; +extern string_view GlitchHammerSlideDescNovice; +extern string_view GlitchHammerSlideDescIntermediate; + +extern string_view GlitchLedgeCancelDescDisabled; +extern string_view GlitchLedgeCancelDescNovice; +extern string_view GlitchLedgeCancelDescIntermediate; +extern string_view GlitchLedgeCancelDescAdvanced; + +extern string_view GlitchActionSwapDescDisabled; +extern string_view GlitchActionSwapDescNovice; +extern string_view GlitchActionSwapDescAdvanced; + +extern string_view GlitchQPADescDisabled; +extern string_view GlitchQPADescNovice; +extern string_view GlitchQPADescIntermediate; +extern string_view GlitchQPADescAdvanced; +extern string_view GlitchQPADescExpert; + +extern string_view GlitchHookshotClipDescDisabled; +extern string_view GlitchHookshotClipDescNovice; +extern string_view GlitchHookshotClipDescIntermediate; + +extern string_view GlitchHookshotJump_BonkDescDisabled; +extern string_view GlitchHookshotJump_BonkDescNovice; +extern string_view GlitchHookshotJump_BonkDescIntermediate; +extern string_view GlitchHookshotJump_BonkDescAdvanced; + +extern string_view GlitchHookshotJump_BootsDescDisabled; +extern string_view GlitchHookshotJump_BootsDescNovice; +extern string_view GlitchHookshotJump_BootsDescIntermediate; +extern string_view GlitchHookshotJump_BootsDescAdvanced; + +extern string_view GlitchCutsceneDiveDescDisabled; +extern string_view GlitchCutsceneDiveDescNovice; +extern string_view GlitchCutsceneDiveDescIntermediate; +extern string_view GlitchCutsceneDiveDescAdvanced; + +extern string_view GlitchNaviDive_StickDescDisabled; +extern string_view GlitchNaviDive_StickDescNovice; +extern string_view GlitchNaviDive_StickDescIntermediate; +extern string_view GlitchNaviDive_StickDescAdvanced; + +extern string_view GlitchTripleSlashClipDescDisabled; +extern string_view GlitchTripleSlashClipDescNovice; +extern string_view GlitchTripleSlashClipDescIntermediate; +extern string_view GlitchTripleSlashClipDescAdvanced; +extern string_view GlitchTripleSlashClipDescExpert; + +extern string_view GlitchLedgeClipDescDisabled; +extern string_view GlitchLedgeClipDescNovice; +extern string_view GlitchLedgeClipDescIntermediate; +extern string_view GlitchLedgeClipDescAdvanced; + +extern string_view GlitchSeamWalkDescDisabled; +extern string_view GlitchSeamWalkDescNovice; +extern string_view GlitchSeamWalkDescIntermediate; +extern string_view GlitchSeamWalkDescAdvanced; +extern string_view GlitchSeamWalkDescExpert; +extern string_view GlitchSeamWalkDescHero; + +extern string_view GlitchWWTEscapeDesc; +extern string_view GlitchGVTentAsChildDesc; +extern string_view GlitchGFGuardSneakDesc; +extern string_view GlitchItemlessWastelandDesc; +extern string_view GlitchOccamsStatueDesc; +extern string_view GlitchZDOoBJumpSlashDesc; +extern string_view GlitchJabuStickRecoilDesc; +extern string_view GlitchJabuAdultDesc; +extern string_view GlitchBlueFireWallDesc; +extern string_view GlitchClassicHalfieDesc; +extern string_view GlitchModernHalfieDesc; +extern string_view GlitchJabuSwitchDesc; +extern string_view GlitchForestBKSkipDesc; +extern string_view GlitchFireGrunzClipDesc; diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp new file mode 100644 index 000000000..05fc10c4b --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -0,0 +1,2779 @@ +#include "settings.hpp" + +#include "cosmetics.hpp" +#include "dungeon.hpp" +#include "fill.hpp" +#include "item_location.hpp" +#include "music.hpp" +#include "sound_effects.hpp" +#include "random.hpp" +#include "randomizer.hpp" +#include "setting_descriptions.hpp" +#include "trial.hpp" +#include "keys.hpp" + +using namespace Cosmetics; +using namespace Dungeon; +using namespace Trial; +using namespace Music; +using namespace SFX; + +namespace Settings { + std::string seed; + std::string version = RANDOMIZER_VERSION "-" COMMIT_NUMBER; + std::array hashIconIndexes; + + bool skipChildZelda = false; + + std::vector NumOpts(int min, int max, int step = 1, std::string textBefore = {}, std::string textAfter = {}) { + std::vector options; + options.reserve((max - min) / step + 1); + for (int i = min; i <= max; i += step) { + options.push_back(textBefore + std::to_string(i) + textAfter); + } + return options; + } + + std::vector MultiVecOpts(std::vector> optionsVector) { + uint32_t totalSize = 0; + for (auto vector : optionsVector) { + totalSize += vector.size(); + } + std::vector options; + options.reserve(totalSize); + for (auto vector : optionsVector) { + for (auto op : vector) { + options.push_back(op); + } + } + return options; + } + + // Setting name, Options, Setting Descriptions (assigned in setting_descriptions.cpp) Category (default: Setting),Default index (default: 0), Default hidden (default: false) + //Open Settings Any option index past the last description will use the last description + Option RandomizeOpen = Option::Bool("Randomize Settings", {"No","Yes"}, {openRandomize}, OptionCategory::Toggle); + Option OpenForest = Option::U8 ("Forest", {"Closed", "Open", "Closed Deku"}, {forestClosed, forestOpen, forestClosedDeku}, OptionCategory::Setting, OPENFOREST_OPEN); + Option OpenKakariko = Option::U8 ("Kakariko Gate", {"Closed", "Open"}, {kakGateClosed, kakGateOpen}); + Option OpenDoorOfTime = Option::U8 ("Door of Time", {"Open", "Closed", "Intended"}, {doorOfTimeOpen, doorOfTimeClosed, doorOfTimeIntended}); + Option ZorasFountain = Option::U8 ("Zora's Fountain", {"Normal", "Adult", "Open"}, {fountainNormal, fountainAdult, fountainOpen}); + Option GerudoFortress = Option::U8 ("Gerudo Fortress", {"Normal", "Fast", "Open"}, {gerudoNormal, gerudoFast, gerudoOpen}); + Option Bridge = Option::U8 ("Rainbow Bridge", {"Open", "Vanilla", "Stones", "Medallions", "Rewards", "Dungeons", "Tokens"}, {bridgeOpen, bridgeVanilla, bridgeStones, bridgeMedallions, bridgeRewards, bridgeDungeons, bridgeTokens}, OptionCategory::Setting, RAINBOWBRIDGE_VANILLA); + Option BridgeStoneCount = Option::U8 (" Stone Count", {NumOpts(0, 3)}, {bridgeStoneCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeMedallionCount= Option::U8 (" Medallion Count", {NumOpts(0, 6)}, {bridgeMedallionCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeRewardCount = Option::U8 (" Reward Count", {NumOpts(0, 9)}, {bridgeRewardCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeDungeonCount = Option::U8 (" Dungeon Count", {NumOpts(0, 8)}, {bridgeDungeonCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeTokenCount = Option::U8 (" Token Count", {NumOpts(0, 100)}, {bridgeTokenCountDesc}, OptionCategory::Setting, 1, true); + Option RandomGanonsTrials = Option::Bool("Random Ganon's Trials", {"Off", "On"}, {randomGanonsTrialsDesc}, OptionCategory::Setting, ON); + Option GanonsTrialsCount = Option::U8 (" Trial Count", {NumOpts(0, 6)}, {ganonsTrialCountDesc}, OptionCategory::Setting, 1, true); + std::vector