testing out item replacement (#416)

* skip learning song of storms

* don't set flag when getting goron tunic as child

* Initiates prelude check when master sword unloads.

Not quite how N64 rando does it but so far it's the only way I've found to make it trigger without also triggering the time travel again.

* Stops Shadow Temple lore prompts from appearing in rando.

* Skips cutscene of royal tomb explosion in rando.

Explosion sound doesn't play correctly and I think the debris appears in the wrong place, but the functionality is here.

* Improves visual of exploding gravestone.

* Adds some comments explaining the rando differences

* Skip ruto text box in jabu blue warp

For rando

* skip intro cutscene in dodongo's cavern

* load spoiler files on boot, fix spoilerfile existing check when making new saves

* name entry dropped spoiler logic

* make sure to actually init the cvar

* no chime on load

* uncomment

* Skip ganondrof cutscene

Skip to scream part of the death animation, skipping the text boxes etc. For rando

* Update z_boss_ganondrof.c

* skip owl flight cutscenes in rando

* Fixes skipped text so it only applies to shadow temple.

Earlier fix inadvertently applied to some other text as well, changed logic so that only specified sceneNums and textIds can have this enabled, and text skipped by sceneNum can have the skip overriden by textId if needed. Currently there are no overrides so the textId section of the logic is commented out to avoid compilation errors.

* Adds a default to the switch case statements that leaves the randoSkipText variable unchanged, just in case.

* TEST: Text for item

* Adding ganon flavor text

* ADD: AMMO Count

* format ganon text/hint text

* Autoskip the tower cutscene if settings call for tower collapse.

* ganon hint text logic

* Improved prelude after time travel fix

* swapped the sizes between ganon hint text and ganon text, as they were set to the wrong things.

* this is all i did

* not the cleanest code ever but it's working

* ADD: GS Count

* ADD: Wallter (crash for now)

* TWEAK: Wallet check

* FIX: Use DrawItem instread of DrawUpgrade... b-baka!

* Fixes some vanilla bugs introduced by rando code.

* Added cutscene skip for zelda escaping

Using the debug cutscene skipping function. Also added a conditional so the bridge doesn't spawn closed when cutscene is ready to trigger

* ADD: X Spacing + Placeholders for song

* ADD: default case for items

* TWEAK: Spacing

* FIX: Light Arrow

* ADD: Ammo Option

* use groups instead

* ADD: More spacing logic

* songs and names

* TWEAK: Color on wallet

* colors

* Added flags cutscene before nabooru fight

* ADD: ChromaKey text

* First attempt skip cs after nabooru defeat

* Better implementation for specific rando cutscene skips

* use pulseaudio defaults

* spaces/tabs

* move color push/pop to stop crash

* make the colors work again

* the real bottle fix

* pulseaudio values tuned for n64 audio at 44.1khz

* update tlength

* remove one hardcoded samplerate

* Cleaned up and fixed zelda escape skip

The if statement is a freaking monster, but unless we want to skip more cutscenes in the same way later, this is the most compact way of doing it that I know of.

* Revert one line to match original

nothing functional

* another hint line that breaks autonewline logic

* don't autospawn epona if we don't have the song/ocarina

* Trying to use iron knuckle death effects

not working yet

* Streamlined OoT cutscene skip for future additions

Also cleaned up if statement in general

* Made if statement more readable

Also added clarity for what cutscene was skipped

* Fixed typo in comment

* Janky nabooru defeat cs skip

* altar text formatting (gonna need help shortening some of the french ones)

* more altar text formatting

* english altar text formatting complete

* make gtg blocking guard check for card not bridge

* FIX: Typo!

* FIX: Uppercases

* FIX: Typo

* TWEAK: Alter + some names

* TWEAK: More caps!

* ADD: Missing string

TWEAK more uppercases and namefixe
s

* Hide nabooru death by covering her in flames

* bandaid fix for death crash issue

* Twinrova defeat cs skip

Skips the animation and manually calls the function to show the "beam" around the sisters

* fix crash

* fix caps to match

* fix great fairy reward mashing/shielding issue

* TWEAK : Typo clé to Clé

* TWEAK: Some Altar hints

TWEAK: Some capitals

* TWEAK: Unmatching text + some cap again

* TWEAK: More tweaks

* fix build

* remove extra json.hpp, add hint

* Update randomizer_item_tracker.cpp

* TWEAK: Double Defense with RedParticles instead of white

* make sure we don't optimize out the check to ensure a spoilerfile exists

* vanilla ganon boss key hint formatting

* TWEAK: FR- better way of the hero text

* fix

* and again

* Initializes dungeonsDone items in gSaveContext to 0.

* Replaces sizeof calculation with a NUM_DUNGEONS constant.

* Fixes Saria's Gift on the LW Bridge from getting killed when holding shield.

* More airtight fix for Saria's Gift on the Bridge.

* Lifts one of the conditions in the if statement a little higher to prevent unnecessary lookups of getItemId.

* Invalidate text box icon before drawing

* Fixes the case where Saria's gift is an Ice Trap.

We still get the Ice Trap once, but never again. This does mean you can now hold R while walking in to avoid the ice trap, but everything else seems to work fine.

* Initial commit

Might need changing when we change the settings in the future

* Fixes Door of Time opening cutscene after warping with prelude.

* Initial waterfall skip

Very rudimentary way of doing things but it seems to work so 🤷

* inital rework

* fixed default rotation for 2D sprites

* fix tab/space issues

* 3d drops rando merge fix again

* Allows Impa to appear in the Lullaby check post drawbridge escape.

* Changes Ganon's Trials Count setting to a checkbox

The checkbox is whether or not to skip all of them. Leaving the box unchecked will mean doing all of them. Eventually this will be switched back to a slider once we implement the logic for which trials start out completed.

* Sets all Ganon's Trials to incomplete in new saves.

Fixes https://github.com/briaguya-ai/rando-issue-tracker/issues/131

* fix castle guards when oot throw cutscene has already played in rando

* Properly removes the beams when trials are cleared.

* Removes Question Mark from Skip Ganon's Trials UI.

* Adds a todo comment about when to change back to slider.

* make deku seeds check for bullet bag

* Various tweaks

TWEAK: Altar Text
TWEAK: Hint names
TWEAK: Replace more problematic œ to oe

* upgrade ocarina on both child and adult equips

* FIX: Jabu Item

* update equipped hookshot/longshot when obtained as other age

* add hint

* don't give the bgs check without the claim check

* Skips Darunia Cutscene in Fire Temple

* Added a TODO note about not skipping the cutscene.

There is a setting we will want to have eventually that will require this cutscene to not be skipped since it is used during a glitch.

* remove todo

* restore fast ocarina option in imgui that was lost in merge

* Fixes grey screen issue + tooltip for 2 handed shield

* update to use dg instead of g for textures in item tracker

* TWEAK: Default color for cosmetic RAND button was not the corect one

* fix texture crash, remove unused item tracker code

* don't open mask shop until we get zelda's letter

* Update README.md

* Prevents "correct" chime under incorrect conditions.

* Fixes typo in conditional and adds "bonk" sound effect.

"Bonk" sound is NA_SE_SY_OCARINA_ERROR and it plays when conditions for the Door of Time have not been met after playing Song of Time. This is only possible in rando's "Intended" Door of Time option, in which the Ocarina of Time and all 3 spritual stones are required to open the door, instead of the vanilla requirements of just having the song of time.

* remove modify dpad equips toggle, replace with checks for dpad menu

* remove extra check

* add ability to hold c-up to assign to dpad when dpad menuing is enabled

* disable d-pad navigation on item menu when holding c-up to equip

* dpad+c-up stuff for equipment menu

* ADD: Checbox for songs colors

* TWEAK: RandoColors for normal songs

* kind of quick and dirty but it works

* TWEAK: Clarity of the tooltip

Co-authored-by: briaguya <briaguya@alice>
Co-authored-by: Christopher Leggett <chris@leggett.dev>
Co-authored-by: aMannus <mannusmenting@gmail.com>
Co-authored-by: PurpleHato <linkvssangoku.jr@gmail.com>
Co-authored-by: Dog <5172592+Dog@users.noreply.github.com>
Co-authored-by: Vague Rant <vaguerant@users.noreply.github.com>
Co-authored-by: Baoulettes <perlouzerie@hotmail.fr>
Co-authored-by: Ada <60364512+GreatArgorath@users.noreply.github.com>
This commit is contained in:
briaguya 2022-07-11 20:11:07 -04:00 committed by GitHub
parent 0fd779f002
commit c25089b98f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
206 changed files with 53442 additions and 525 deletions

View File

@ -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

View File

@ -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<CVar>();

View File

@ -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::string, std::unique_ptr<CVar>, std::less<>> cvars;
void CVar_SetFloat(const char* name, float value);
void CVar_SetString(const char* name, const char* value);
#endif
#endif

View File

@ -56,7 +56,7 @@ namespace Game {
void InitSettings() {
ModInternal::RegisterHook<ModInternal::AudioInit>(UpdateAudio);
ModInternal::RegisterHook<ModInternal::GfxInit>([] {
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();
});

View File

@ -402,6 +402,12 @@ namespace SohImGui {
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,6 +935,8 @@ 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();
}
@ -1008,6 +1014,18 @@ 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();

View File

@ -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);

View File

@ -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<ID3DBlob> vs, ps;
ComPtr<ID3DBlob> 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;

View File

@ -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"
@ -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<int>(message), static_cast<int>(w_param), static_cast<int>(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)) {

View File

@ -81,7 +81,7 @@ static uint32_t frame_count;
static vector<Framebuffer> 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);

View File

@ -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<float, float>

View File

@ -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 <WTypesbase.h>
#endif
#include <time.h>
#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);

View File

@ -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);

View File

@ -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;

View File

@ -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.

View File

@ -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 {

View File

@ -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;

View File

@ -3,6 +3,7 @@
#include "ultra64.h"
#include "z64math.h"
#include <randomizerTypes.h>
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 {

1000
soh/randomizerTypes.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
#include <Lib/spdlog/include/spdlog/spdlog.h>
void GenerateRandomizer() {
int ret = Playthrough::Playthrough_Init(std::hash<std::string>{}(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();
}

View File

@ -181,6 +181,61 @@
<ItemGroup>
<ClCompile Include="soh\Enhancements\cosmetics\CosmeticsEditor.cpp" />
<ClCompile Include="soh\Enhancements\debugger\actorViewer.cpp" />
<ClCompile Include="soh\Enhancements\gfx.c" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\hint_list\hint_list_exclude_dungeon.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\hint_list\hint_list_exclude_overworld.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\hint_list\hint_list_item.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_castle_town.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_kakariko.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_shadow_temple.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_spirit_temple.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_forest_temple.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_gerudo_training_grounds.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_deku_tree.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_ice_cavern.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_fire_temple.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_lost_woods.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_bottom_of_the_well.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_hyrule_field.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_gerudo_valley.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_ganons_castle.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_water_temple.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_zoras_domain.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_jabujabus_belly.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_dodongos_cavern.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_death_mountain.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\cosmetics.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\custom_messages.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\debug.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\dungeon.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\entrance.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\fill.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\hints.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\hint_list.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\item.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\item_list.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\item_location.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\item_pool.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\logic.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\menu.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\music.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\patch.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\playthrough.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\preset.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\random.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\rando_main.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\settings.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\setting_descriptions.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\shops.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\sound_effects.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\spoiler_log.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\starting_inventory.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\tinyxml2.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\trial.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\3drando\utils.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\randomizer.cpp" />
<ClCompile Include="soh\Enhancements\randomizer\randomizer_item_tracker.cpp" />
<ClCompile Include="soh\frame_interpolation.cpp" />
<ClCompile Include="soh\Enhancements\bootcommands.c" />
<ClCompile Include="soh\Enhancements\debugconsole.cpp" />
@ -890,6 +945,45 @@
<ItemGroup>
<ClInclude Include="soh\Enhancements\cosmetics\CosmeticsEditor.h" />
<ClInclude Include="soh\Enhancements\debugger\actorViewer.h" />
<ClCompile Include="soh\Enhancements\randomizer\randomizer.h" />
<ClInclude Include="soh\Enhancements\gfx.h" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\category.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\cosmetics.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\custom_messages.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\debug.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\dungeon.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\entrance.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\fill.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\hints.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\hint_list.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\item.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\item_list.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\item_location.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\item_pool.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\keys.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\location_access.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\logic.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\menu.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\music.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\patch.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\playthrough.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\pool_functions.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\preset.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\random.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\randomizer.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\rando_main.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\settings.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\setting_descriptions.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\shops.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\sound_effects.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\spoiler_log.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\starting_inventory.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\text.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\tinyxml2.h" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\trial.hpp" />
<ClInclude Include="soh\Enhancements\randomizer\3drando\utils.hpp" />
<ClInclude Include="randomizerTypes.h" />
<ClInclude Include="soh\Enhancements\randomizer\randomizer_item_tracker.h" />
<ClInclude Include="soh\frame_interpolation.h" />
<ClInclude Include="include\alloca.h" />
<ClInclude Include="include\bgm.h" />

View File

@ -2211,6 +2211,174 @@
<ClCompile Include="soh\Enhancements\cosmetics\CosmeticsEditor.cpp">
<Filter>Header Files\include</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\hint_list\hint_list_exclude_dungeon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\hint_list\hint_list_exclude_overworld.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\hint_list\hint_list_item.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_bottom_of_the_well.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_castle_town.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_death_mountain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_deku_tree.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_dodongos_cavern.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_fire_temple.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_forest_temple.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_ganons_castle.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_gerudo_training_grounds.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_gerudo_valley.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_hyrule_field.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_ice_cavern.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_jabujabus_belly.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_kakariko.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_lost_woods.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_shadow_temple.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_spirit_temple.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_water_temple.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access\locacc_zoras_domain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\cosmetics.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\custom_messages.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\debug.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\dungeon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\entrance.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\fill.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\hints.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\hint_list.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\item.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\item_list.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\item_location.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\item_pool.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\location_access.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\logic.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\menu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\music.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\patch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\playthrough.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\preset.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\random.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\rando_main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\settings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\setting_descriptions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\shops.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\sound_effects.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\spoiler_log.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\starting_inventory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\tinyxml2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\trial.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\3drando\utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\randomizer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\randomizer.h">
<Filter>Header Files</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\gfx.c">
<Filter>Header Files\soh\Enhancements</Filter>
</ClCompile>
<ClCompile Include="soh\Enhancements\randomizer\randomizer_item_tracker.cpp">
<Filter>Source Files\src</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\overlays\actors\ovl_kaleido_scope\z_kaleido_scope.h">
@ -3788,6 +3956,120 @@
<ClInclude Include="soh\Enhancements\cosmetics\CosmeticsEditor.h">
<Filter>Header Files\include</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\category.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\cosmetics.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\custom_messages.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\debug.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\dungeon.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\entrance.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\fill.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\hints.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\hint_list.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\item.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\item_list.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\item_location.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\item_pool.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\keys.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\location_access.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\logic.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\menu.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\music.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\patch.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\playthrough.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\pool_functions.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\preset.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\random.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\randomizer.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\rando_main.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\settings.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\setting_descriptions.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\shops.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\sound_effects.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\spoiler_log.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\starting_inventory.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\text.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\tinyxml2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\trial.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\3drando\utils.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="randomizerTypes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\gfx.h">
<Filter>Header Files\soh\Enhancements</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\randomizer\randomizer_item_tracker.h">
<Filter>Source Files\src</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="SHIPOFHARKINIAN.ico" />

View File

@ -130,6 +130,9 @@ std::map<uint32_t, ItemMapEntry> 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<uint32_t, QuestMapEntry> 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<SongMapEntry, 12> 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<SongMapEntry, 12> 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<SongMapEntry, 12> 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<typename T>
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);
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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,
};

View File

@ -0,0 +1,152 @@
#include "cosmetics.hpp"
#include "random.hpp"
#include <sstream>
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<std::string_view, 13> 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<std::string_view, 28> 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<std::string_view, 20> 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<std::string_view, 20> 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<std::string_view, 13> 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

View File

@ -0,0 +1,50 @@
#pragma once
#include <array>
#include <string>
#include <vector>
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<std::string_view, 13> gauntletColors;
extern const std::array<std::string_view, 28> tunicColors;
extern const std::array<std::string_view, 20> naviInnerColors;
extern const std::array<std::string_view, 20> naviOuterColors;
extern const std::array<std::string_view, 13> 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

View File

@ -0,0 +1,495 @@
#include "custom_messages.hpp"
#include "debug.hpp"
#include "shops.hpp"
#include "z64item.h"
#include <array>
#include <set>
#include <sstream>
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<MessageEntry, MessageEntryComp> messageEntries;
std::vector<MessageEntry> 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<const char*, uint32_t> 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<const char*, uint32_t> 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<uint8_t>& 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; }
}

View File

@ -0,0 +1,93 @@
#pragma once
#include <string>
#include <utility>
#include <vector>
#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<const char*, uint32_t> RawMessageEntryData();
std::pair<const char*, uint32_t> RawMessageData();
void CreateAlwaysIncludedMessages();
Text AddColorsAndFormat(Text text, const std::vector<uint8_t>& 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();
}

View File

@ -0,0 +1,5 @@
#include "debug.hpp"
void CitraPrint (std::string_view str) {
}

View File

@ -0,0 +1,5 @@
#pragma once
#include <string_view>
void CitraPrint(std::string_view str);

View File

@ -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<uint32_t> vanillaLocations_,
std::vector<uint32_t> mqLocations_,
std::vector<uint32_t> 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<uint32_t> DungeonInfo::GetDungeonLocations() const {
auto locations = masterQuest ? mqLocations : vanillaLocations;
AddElementsToPool(locations, sharedLocations);
return locations;
}
//Gets all dungeon locations (MQ + Vanilla)
std::vector<uint32_t> 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

View File

@ -0,0 +1,104 @@
#pragma once
#include <array>
#include <string>
#include <vector>
#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<uint32_t> vanillaLocations_,
std::vector<uint32_t> mqLocations_,
std::vector<uint32_t> 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<uint32_t> GetDungeonLocations() const;
// Gets all dungeon locations (MQ + Vanilla)
std::vector<uint32_t> 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<uint32_t> vanillaLocations;
std::vector<uint32_t> mqLocations;
std::vector<uint32_t> 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<DungeonInfo*, 12>;
extern const DungeonArray dungeonList;
} // namespace Dungeon

View File

@ -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 <vector>
#include <utility>
#include <set>
#include <map>
#include <Lib/spdlog/include/spdlog/spdlog.h>
std::list<EntranceOverride> 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<EntranceLinkInfo, EntranceLinkInfo>;
using EntrancePair = std::pair<Entrance*, Entrance*>;
//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<EntranceInfoPair>& 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<Entrance*> AssumeEntrancePool(std::vector<Entrance*>& entrancePool) {
std::vector<Entrance*> 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<std::vector<Entrance*>, 2> SplitEntrancesByRequirements(std::vector<Entrance*>& entrancesToSplit, std::vector<Entrance*>& assumedEntrances) {
//First, disconnect all root assumed entrances and save which regions they were originally connected to, so we can reconnect them later
std::map<Entrance*, uint32_t> originalConnectedRegions = {};
std::set<Entrance*> 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<Entrance*> restrictiveEntrances = {};
std::vector<Entrance*> softEntrances = {};
Logic::LogicReset();
// //Apply the effects of all advancement items to search for entrance accessibility
std::vector<uint32_t> 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<EntrancePair>& 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<Entrance*>& 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<std::string, 2> childForbidden = {"OGC Great Fairy Fountain -> Castle Grounds", "GV Carpenter Tent -> GV Fortress Side"};
std::array<std::string, 2> adultForbidden = {"HC Great Fairy Fountain -> Castle Grounds", "HC Storms Grotto -> Castle Grounds"};
auto allShuffleableEntrances = GetShuffleableEntrances(EntranceType::All, false);
for (auto& entrance: allShuffleableEntrances) {
std::vector<Entrance*> 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<EntrancePair>& 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<Entrance*>& entrances, std::vector<Entrance*>& targetEntrances, std::vector<EntrancePair>& 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<Entrance*>& entrancePool, std::vector<Entrance*>& 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<EntrancePair> 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<EntranceInfoPair> 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<EntranceType, std::vector<Entrance*>> 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<EntranceType, std::vector<Entrance*>> 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<std::list<Entrance*>> playthroughEntrances;

View File

@ -0,0 +1,320 @@
#pragma once
#include "keys.hpp"
#include "location_access.hpp"
#include "debug.hpp"
#include <string>
#include <list>
#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<EntranceOverride> 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<ConditionFn> 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<ConditionFn> 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<std::list<Entrance*>> playthroughEntrances;
extern bool noRandomEntrances;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
#pragma once
#include "keys.hpp"
#include <vector>
#include <string>
enum class SearchMode {
ReachabilitySearch,
GeneratePlaythrough,
CheckBeatable,
AllLocationsReachable,
ValidateWorld,
TimePassAccess,
TempleOfTimeAccess,
ValidStartingRegion,
PoeCollectorAccess,
};
void ClearProgress();
void VanillaFill();
int Fill();
std::vector<uint32_t> GetAccessibleLocations(const std::vector<uint32_t>& allowedLocations,
SearchMode mode = SearchMode::ReachabilitySearch, std::string ignore = "",
bool checkPoeCollectorAccess = false,
bool checkOtherEntranceAccess = false);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
#pragma once
#include "hints.hpp"
#include "keys.hpp"
#include <vector>
extern std::array<HintText, KEY_ENUM_MAX> hintTable;
void HintTable_Init();
const HintText& Hint(uint32_t hintKey);
std::vector<HintText> GetHintCategory(HintCategory category);
void HintTable_Init_Item();
void HintTable_Init_Exclude_Overworld();
void HintTable_Init_Exclude_Dungeon();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 <Lib/spdlog/include/spdlog/spdlog.h>
using namespace CustomMessages;
using namespace Logic;
using namespace Settings;
using namespace Trial;
constexpr std::array<HintSetting, 4> 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<DungeonInfo, 10> 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<uint32_t> alreadyChecked = {};
std::vector<uint32_t> 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<uint32_t> 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<uint8_t>& 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<uint32_t>& 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<uint32_t> 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<uint32_t> possibleHintLocations = {};
// iterate through playthrough locations by sphere
std::vector<uint32_t> 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<uint32_t> 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<uint32_t>& 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<uint32_t> 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<uint32_t> 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<uint32_t> 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<uint32_t> 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<uint32_t> CalculateBarrenRegions() {
std::vector<uint32_t> barrenLocations = {};
std::vector<uint32_t> 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<TrialInfo*> 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<uint8_t>() >= 1 && GanonsTrialsCount.Value<uint8_t>() <= 3) {
//get requried trials
std::vector<TrialInfo*> 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<uint8_t>() == 1) {
requirement.SetForm(SINGULAR);
} else {
requirement.SetForm(PLURAL);
}
requirement.Replace("%d", std::to_string(count.Value<uint8_t>()));
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<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(KOKIRI_EMERALD)) +
(StartingGoronRuby.Value<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(GORON_RUBY)) +
(StartingZoraSapphire.Value<uint8_t>() ? 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<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(LIGHT_MEDALLION)) +
(StartingForestMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(FOREST_MEDALLION)) +
(StartingFireMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(FIRE_MEDALLION)) +
(StartingWaterMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(WATER_MEDALLION)) +
(StartingSpiritMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(SPIRIT_MEDALLION)) +
(StartingShadowMedallion.Value<uint8_t>() ? 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>()];
uint8_t remainingDungeonWothHints = hintSetting.dungeonsWothLimit;
uint8_t remainingDungeonBarrenHints = hintSetting.dungeonsBarrenLimit;
// Add 'always' location hints
if (hintSetting.distTable[static_cast<int>(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<int>(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<HintType> 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<std::string> 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<std::string> 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<std::string> 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<std::string, 13> 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<int>(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<uint32_t> 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<uint32_t> 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<uint32_t> 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<uint32_t> 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({});
}

View File

@ -0,0 +1,227 @@
#pragma once
#include <array>
#include <string>
#include <vector>
#include "keys.hpp"
#include "text.hpp"
#include "random.hpp"
#include "settings.hpp"
#include <functional>
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<HintDistributionSetting, static_cast<int>(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<Text> obscureText_, std::vector<Text> ambiguousText_, Text clearText_, HintCategory type_)
: obscureText(std::move(obscureText_)),
ambiguousText(std::move(ambiguousText_)),
clearText(std::move(clearText_)),
type(type_) {}
static auto Item(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Item};
}
static auto Always(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Always};
}
static auto Sometimes(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Sometimes};
}
static auto Exclude(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Exclude};
}
static auto Entrance(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Entrance};
}
static auto Region(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Region};
}
static auto Junk(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Junk};
}
static auto DungeonName(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::DungeonName};
}
static auto Boss(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Boss};
}
static auto Bridge(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Bridge};
}
static auto GanonsBossKey(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::GanonsBossKey};
}
static auto LACS(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::LACS};
}
static auto Altar(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Altar};
}
static auto Validation(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Validation};
}
static auto LightArrow(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::LightArrow};
}
static auto GanonLine(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::GanonLine};
}
static auto MerchantsDialogs(std::vector<Text>&& obscureText, std::vector<Text>&& 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<Text> obscureText = {};
std::vector<Text> ambiguousText = {};
Text clearText;
HintCategory type;
};
using ConditionalAlwaysHint = std::pair<uint32_t, std::function<bool()>>;
//10 dungeons as GTG and GC are excluded
extern std::array<DungeonInfo, 10> dungeonInfoData;
extern std::array<ConditionalAlwaysHint, 9> conditionalAlwaysHints;
extern uint32_t GetHintRegionHintKey(const uint32_t area);
extern void CreateAllHints();
extern void CreateMerchantsHints();
Text& GetChildAltarText();
Text& GetAdultAltarText();
Text& GetGanonText();
Text& GetGanonHintText();

View File

@ -0,0 +1,84 @@
#include "item.hpp"
#include <array>
#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<uint8_t*>(logicVar) += 10;
}
else {
if (std::holds_alternative<bool*>(logicVar)) {
*std::get<bool*>(logicVar) = true;
} else {
*std::get<uint8_t*>(logicVar) += 1;
}
}
Logic::UpdateHelpers();
}
void Item::UndoEffect() {
if (FOREST_TEMPLE_KEY_RING <= hintKey && hintKey <= GANONS_CASTLE_KEY_RING) {
*std::get<uint8_t*>(logicVar) -= 10;
}
else {
if (std::holds_alternative<bool*>(logicVar)) {
*std::get<bool*>(logicVar) = false;
} else {
*std::get<uint8_t*>(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;
}

View File

@ -0,0 +1,142 @@
#pragma once
#include <string>
#include <variant>
#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<bool*, uint8_t*> logicVar;
uint32_t hintKey;
uint16_t price;
bool playthrough = false;
};

View File

@ -0,0 +1,290 @@
#include "item_list.hpp"
#include "logic.hpp"
#include <array>
#include "z64item.h"
using namespace Logic;
static std::array<Item, KEY_ENUM_MAX> 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;
}

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,490 @@
#pragma once
#include <algorithm>
#include <array>
#include <cstdio>
#include <functional>
#include <set>
#include <string>
#include <vector>
#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<Category> 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<uint8_t>(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>();
}
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<Category>&& 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<Category>&& 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<Category>&& 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<Category>&& 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<Category>&& 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<Category>&& 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<Category>&& 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<Category>&& 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<Category>&& 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<Category>&& 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<Category>&& 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<Category> 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<std::vector<uint32_t>> ShopLocationLists;
extern std::vector<uint32_t> gossipStoneLocations;
extern std::vector<uint32_t> dungeonRewardLocations;
extern std::vector<uint32_t> overworldLocations;
extern std::vector<uint32_t> allLocations;
extern std::vector<uint32_t> everyPossibleLocation;
//set of overrides to write to the patch
extern std::set<ItemOverride, ItemOverride_Compare> overrides;
extern std::vector<std::vector<uint32_t>> playthroughLocations;
extern std::vector<uint32_t> 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<uint32_t> GetLocations(const std::vector<uint32_t>& locationPool, Category categoryInclude,
Category categoryExclude = Category::cNull);
void LocationReset();
void ItemReset();
void HintReset();
void AddExcludedOptions();
void CreateItemOverrides();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
#pragma once
#include "keys.hpp"
#include <cstddef>
#include <vector>
#include <stdint.h>
class ItemLocation;
void AddItemToPool(std::vector<uint32_t>& 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<uint32_t> ItemPool;
extern std::vector<uint8_t> IceTrapModels;

File diff suppressed because it is too large Load Diff

View File

@ -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 <fstream>
#include <iostream>
using namespace Logic;
using namespace Settings;
//generic grotto event list
std::vector<EventAccess> 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<EventAccess> events_,
std::vector<LocationAccess> locations_,
std::list<Entrance> 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<Area, KEY_ENUM_MAX> 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<const uint32_t, 414> 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 <filename> -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<Entrance*> GetShuffleableEntrances(EntranceType type, bool onlyPrimary /*= true*/) {
std::vector<Entrance*> 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;
}

View File

@ -0,0 +1,266 @@
#pragma once
#include <string>
#include <vector>
#include <list>
#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<ConditionFn> 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<ConditionFn> 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<ConditionFn> 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<ConditionFn> 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<EventAccess> events_,
std::vector<LocationAccess> locations_,
std::list<Entrance> exits_);
~Area();
std::string regionName;
std::string scene;
uint32_t hintKey;
bool timePass;
std::vector<EventAccess> events;
std::vector<LocationAccess> locations;
std::list<Entrance> exits;
std::list<Entrance*> 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<Area, KEY_ENUM_MAX> areaTable;
extern std::vector<EventAccess> 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<Entrance*> 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();

View File

@ -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;}}),
});
}
}

View File

@ -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;}}),
});
}

View File

@ -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;}}),
});
}

View File

@ -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;}}),
});
}
}

View File

@ -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;}}),
}, {});
}
}

View File

@ -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;}}),
}, {});
}
}

View File

@ -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;}}),
}, {});
}
}

View File

@ -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);}}),
}, {});
}
}

View File

@ -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);}}),
});
}
}

View File

@ -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<bool>();}}),
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;}}),
});
}

View File

@ -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;}}),
});
}

View File

@ -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
}, {});
}
}

View File

@ -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;}}),
});
}
}

View File

@ -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;}}),
});
}

View File

@ -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);}}),
});
}

View File

@ -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;}}),
}, {});
}
}

View File

@ -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;}}),
}, {});
}
}

View File

@ -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))
}, {});
}
}

View File

@ -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<bool>();}}),
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;}}),
});
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,387 @@
#pragma once
#include "keys.hpp"
#include <cstdint>
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

View File

@ -0,0 +1,550 @@
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <ctime>
#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 <Lib/spdlog/include/spdlog/spdlog.h>
#include "randomizerTypes.h"
namespace {
bool seedChanged;
uint16_t pastSeedLength;
std::vector<std::string> presetEntries;
std::vector<Menu*> 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<uint16_t>(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<std::string> 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<RandomizerSettingKey, uint8_t> 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<std::string>{}(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();
}

View File

@ -0,0 +1,52 @@
#pragma once
#include <string>
#include <unordered_map>
#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<RandomizerSettingKey, uint8_t> cvarSettings);
std::string GetInput(const char* hintText);
extern void MenuInit();
extern void MenuUpdate(uint32_t kDown, bool updatedByHeld);

View File

@ -0,0 +1,128 @@
#include "music.hpp"
#include <cstdlib>
namespace Music {
const std::array<SeqType, SEQ_COUNT> 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<uint32_t, SEQ_COUNT> 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<uint32_t> 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

View File

@ -0,0 +1,29 @@
#pragma once
#include <array>
#include <vector>
#include <stdint.h>
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<SeqType, SEQ_COUNT> seqTypesMusic;
extern std::array<uint32_t, SEQ_COUNT> seqOverridesMusic;
void InitMusicRandomizer();
void ShuffleSequences(int type);
} // namespace Music

View File

@ -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 <array>
#include <cstring>
#include <fstream>
#include <memory>
#include <string>
#include <vector>
// For specification on the IPS file format, visit: https://zerosoft.zophar.net/ips.php
using FILEPtr = std::unique_ptr<FILE, decltype(&std::fclose)>;
void WriteFloatToBuffer(std::vector<char>& buffer, float f, size_t offset) {
memcpy(buffer.data() + offset, &f, sizeof(float));
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <set>
#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();

View File

@ -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<RandomizerSettingKey, uint8_t> 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<std::string>{}(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<std::string>{}(Settings::seed));
printf("\x1b[15;15HSeeds Generated: %d\n", i + 1);
}
return 1;
}
} // namespace Playthrough

View File

@ -0,0 +1,9 @@
#pragma once
#include <string>
#include <set>
#include "item_location.hpp"
namespace Playthrough {
int Playthrough_Init(uint32_t seed, std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettings);
int Playthrough_Repeat(int count = 1);
}

View File

@ -0,0 +1,38 @@
#pragma once
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>
template <typename T, typename Predicate>
static void erase_if(std::vector<T>& vector, Predicate pred) {
vector.erase(std::remove_if(begin(vector), end(vector), pred), end(vector));
}
template <typename T, typename Predicate>
std::vector<T> FilterFromPool(std::vector<T>& vector, Predicate pred, bool eraseAfterFilter = false) {
std::vector<T> filteredPool = {};
std::copy_if(vector.begin(), vector.end(), std::back_inserter(filteredPool), pred);
if (eraseAfterFilter) {
erase_if(vector, pred);
}
return filteredPool;
}
template <typename T, typename Predicate>
std::vector<T> FilterAndEraseFromPool(std::vector<T>& vector, Predicate pred) {
return FilterFromPool(vector, pred, true);
}
template <typename T, typename FromPool>
void AddElementsToPool(std::vector<T>& toPool, const FromPool& fromPool) {
toPool.insert(toPool.end(), std::cbegin(fromPool), std::cend(fromPool));
}
template <typename T, typename Container>
bool ElementInContainer(T& element, const Container& container) {
return std::find(container.begin(), container.end(), element) != container.end();
}

View File

@ -0,0 +1,202 @@
#include "preset.hpp"
#include <array>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <vector>
#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<std::string_view, 2> paths{
"/3ds/presets/oot3dr/settings/",
"/3ds/presets/oot3dr/cosmetics/",
};
switch(category) {
case OptionCategory::Setting :
case OptionCategory::Cosmetic :
return paths[static_cast<size_t>(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<std::string> GetSettingsPresets() {
std::vector<std::string> 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 <settings> 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);
}
}
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <string>
#include <vector>
enum class OptionCategory;
bool CreatePresetDirectories();
std::vector<std::string> 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();

View File

@ -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 <soh/Enhancements/randomizer.h>
#include <Cvar.h>
#include <GameSettings.h>
#define TICKS_PER_SEC 268123480.0
void RandoMain::GenerateRando(std::unordered_map<RandomizerSettingKey, u8> 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);
}

View File

@ -0,0 +1,5 @@
#pragma once
namespace RandoMain {
void GenerateRando(std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettings);
}

View File

@ -0,0 +1,29 @@
#include "random.hpp"
#include <random>
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<uint32_t>(std::random_device{}());
Random_Init(seed);
}
std::uniform_int_distribution<uint32_t> distribution(min, max-1);
return distribution(generator);
}
//Returns a random floating point number in [0.0, 1.0]
double RandomDouble() {
std::uniform_real_distribution<double> distribution(0.0, 1.0);
return distribution(generator);
}

View File

@ -0,0 +1,46 @@
#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <vector>
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 <typename T>
T RandomElement(std::vector<T>& 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 <typename Container>
auto& RandomElement(Container& container) {
return container[Random(0, std::size(container))];
}
template <typename Container>
const auto& RandomElement(const Container& container) {
return container[Random(0, std::size(container))];
}
//Shuffle items within a vector or array
template <typename T>
void Shuffle(std::vector<T>& vector) {
for (std::size_t i = 0; i + 1 < vector.size(); i++)
{
std::swap(vector[i], vector[Random(i, vector.size())]);
}
}
template <typename T, std::size_t size>
void Shuffle(std::array<T, size>& arr) {
for (std::size_t i = 0; i + 1 < arr.size(); i++)
{
std::swap(arr[i], arr[Random(i, arr.size())]);
}
}

View File

@ -0,0 +1,4 @@
#pragma once
#define RANDOMIZER_VERSION "v3.1"
#define COMMIT_NUMBER "develop"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,541 @@
#pragma once
#include <string_view>
#include <vector>
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<string_view> 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;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,735 @@
#include "item_location.hpp"
#include "item_pool.hpp"
#include "location_access.hpp"
#include "random.hpp"
#include "item.hpp"
#include "shops.hpp"
#include "debug.hpp"
#include <math.h>
#include <map>
#include "z64item.h"
using namespace Settings;
std::vector<ItemAndPrice> NonShopItems = {};
static std::array<std::array<Text, 3>, 0xD5> trickNameTable; //Table of trick names for ice traps
bool initTrickNames = false; //Indicates if trick ice trap names have been initialized yet
//Set vanilla shop item locations before potentially shuffling
void PlaceVanillaShopItems() {
//Loop to place vanilla items in each location
for (size_t i = 0; i < ShopLocationLists.size(); i++) {
for (size_t j = 0; j < ShopLocationLists[i].size(); j++) {
Location(ShopLocationLists[i][j])->PlaceVanillaItem();
}
}
}
//These are the vanilla shop items, but in a priority order of importance
//However many shop item slots were cleared, this will return 64 minus that number of vanilla shop items to be placed with assumed fill
//The first 32 items here will always be present in shops
//Shopsanity 4 will only have the first 32, shopsanity 1 will have the first 56, etc.
//Shopsanity random will have anywhere from the first 32 to the first 56, so the order of items after 32 is relevant
std::vector<uint32_t> GetMinVanillaShopItems(int total_replaced) {
std::vector<uint32_t> minShopItems = {
BUY_DEKU_SHIELD,
BUY_HYLIAN_SHIELD,
BUY_GORON_TUNIC,
BUY_ZORA_TUNIC,
BUY_DEKU_NUT_5,
BUY_DEKU_NUT_5,
BUY_DEKU_NUT_10,
BUY_DEKU_STICK_1,
BUY_DEKU_STICK_1,
BUY_DEKU_SEEDS_30,
BUY_ARROWS_10,
BUY_ARROWS_10,
BUY_ARROWS_30,
BUY_ARROWS_50,
BUY_BOMBCHU_5,
BUY_BOMBCHU_10,
BUY_BOMBCHU_10,
BUY_BOMBCHU_20,
BUY_BOMBS_525,
BUY_BOMBS_535,
BUY_BOMBS_10,
BUY_BOMBS_20,
BUY_GREEN_POTION,
BUY_RED_POTION_30,
BUY_BLUE_FIRE,
BUY_FAIRYS_SPIRIT,
BUY_BOTTLE_BUG,
BUY_FISH,
//^First 28 items from OoTR
BUY_HYLIAN_SHIELD,
BUY_BOTTLE_BUG,
BUY_DEKU_STICK_1,
BUY_FAIRYS_SPIRIT,
//^First 32 items: Always guaranteed
BUY_BLUE_FIRE,
BUY_FISH,
BUY_BOMBCHU_10,
BUY_DEKU_NUT_5,
BUY_ARROWS_10,
BUY_BOMBCHU_20,
BUY_BOMBS_535,
BUY_RED_POTION_30,
//^First 40 items: Exist on shopsanity 3 or less
BUY_BOMBS_30,
BUY_BOMBCHU_20,
BUY_DEKU_NUT_5,
BUY_ARROWS_10,
BUY_DEKU_NUT_5,
BUY_ARROWS_30,
BUY_RED_POTION_40,
BUY_FISH,
//^First 48 items: Exist on shopsanity 2 or less
BUY_BOMBCHU_20,
BUY_ARROWS_30,
BUY_RED_POTION_50,
BUY_ARROWS_30,
BUY_DEKU_NUT_5,
BUY_ARROWS_50,
BUY_ARROWS_50,
BUY_GREEN_POTION,
//^First 56 items: Exist on shopsanity 1 or less
BUY_POE,
BUY_POE,
BUY_HEART,
BUY_HEART,
BUY_HEART,
BUY_HEART,
BUY_HEART,
BUY_HEART,
//^All 64 items: Only exist with shopsanity 0
};
//Now delete however many items there are to replace
for (int i = 0; i < total_replaced; i++) {
minShopItems.pop_back();
}
return minShopItems;
}
//This table contains a cumulative probability for each possible shop price based on
// a beta distribution with alpha = 1.5, beta = 2, and the result of the distribution, a float in [0.0, 1.0),
// being mutliplied by 60, casted to an integer, then multiplied by 5 to give a value in range [0, 295] in increments of 5.
// Meaning the first value is the probability of 0, the next value is the probability of 0 plus the probability of 5, etc.
//Probabilities generated using a python script with 1 billion trials, so should hopefully be pretty good
//Average price ~126
//~38% chance of needing no wallet, ~45% chance of needing 1, ~17% chance of needing 2
static constexpr std::array<double, 60> ShopPriceProbability= {
0.005326994, 0.014908518, 0.027114719, 0.041315285, 0.057136304, 0.074325887, 0.092667151, 0.112002061, 0.132198214, 0.153125390,
0.174696150, 0.196810540, 0.219388148, 0.242361379, 0.265657012, 0.289205134, 0.312970402, 0.336877590, 0.360881110, 0.384932772,
0.408976198, 0.432982176, 0.456902494, 0.480686053, 0.504313389, 0.527746488, 0.550938554, 0.573856910, 0.596465330, 0.618736235,
0.640646600, 0.662162782, 0.683240432, 0.703859801, 0.724001242, 0.743631336, 0.762722631, 0.781259986, 0.799198449, 0.816521905,
0.833208595, 0.849243398, 0.864579161, 0.879211177, 0.893112051, 0.906263928, 0.918639420, 0.930222611, 0.940985829, 0.950914731,
0.959992180, 0.968187000, 0.975495390, 0.981884488, 0.987344345, 0.991851853, 0.995389113, 0.997937921, 0.999481947, 1.000000000,
};
int GetRandomShopPrice() {
double random = RandomDouble(); //Randomly generated probability value
for (size_t i = 0; i < ShopPriceProbability.size(); i++) {
if (random < ShopPriceProbability[i]) {
//The randomly generated value has surpassed the total probability up to this point, so this is the generated price
return i * 5; //i in range [0, 59], output in range [0, 295] in increments of 5
}
}
return -1; //Shouldn't happen
}
//Similar to above, beta distribution with alpha = 1, beta = 2,
// multiplied by 20 instead of 60 to give values in rage [0, 95] in increments of 5
//Average price ~31
static constexpr std::array<double, 20> ScrubPriceProbability = {
0.097500187, 0.190002748, 0.277509301, 0.360018376, 0.437522571, 0.510021715, 0.577520272, 0.640029304, 0.697527584, 0.750024535,
0.797518749, 0.840011707, 0.877508776, 0.910010904, 0.937504342, 0.960004661, 0.977502132, 0.989998967, 0.997500116, 1.000000000,
};
int16_t GetRandomScrubPrice() {
double random = RandomDouble();
for (size_t i = 0; i < ScrubPriceProbability.size(); i++) {
if (random < ScrubPriceProbability[i]) {
return i * 5; // i in range [0, 19], output in range [0, 95] in increments of 5
}
}
return -1;
}
//Get 1 to 4, or a random number from 1-4 depending on shopsanity setting
int GetShopsanityReplaceAmount() {
if (Settings::Shopsanity.Is(SHOPSANITY_ONE)) {
return 1;
} else if (Settings::Shopsanity.Is(SHOPSANITY_TWO)) {
return 2;
} else if (Settings::Shopsanity.Is(SHOPSANITY_THREE)) {
return 3;
} else if (Settings::Shopsanity.Is(SHOPSANITY_FOUR)) {
return 4;
} else { //Random, get number in [1, 4]
return Random(1, 5);
}
}
//Initialize the table of trick names with an easy, medium, and hard name for each language
void InitTrickNames() {
trickNameTable[GI_SWORD_KOKIRI] = {
Text{"Korok Sword", "Épée Korok", "Espada Korok"},
Text{"Hero's Sword", "Épée du Héros", "Espada del héroe"},
Text{"Razor Sword", "Lame Rasoir", "Espada de esmeril"}};
/* trickNameTable[GI_SWORD_MASTER] = {
Text{"Goddess Sword", "Épée de la déesse", "Espada Divina"},
Text{"Gilded Sword", "Excalibur", "Espada de los Sabios"},
Text{"Magical Sword", "Lame dorée", "Fay"}};*/
trickNameTable[GI_SWORD_KNIFE] = {
Text{"Big Goron's Sword", "Épée de Gros Goron", "Espada de Big Goron"},
Text{"Fierce Deity's Sword", "Épée du Dieu Démon", "Espada de la Fiera Deidad"},
Text{"Biggoron's Knife", "Lame de Grogoron", "Daga de Biggoron"}};
trickNameTable[GI_SWORD_BGS] = {
Text{"Big Goron's Sword", "Épée de Biggoron", "Espada de Big Goron"},
Text{"Fierce Deity's Sword", "Épée du dieu démon", "Espada de la Fiera Deidad"},
Text{"Biggoron's Knife", "Lame de Grogoron", "Daga de Biggoron"}};
trickNameTable[GI_SHIELD_DEKU] = {
Text{"Boko Shield", "Bouclier Boko", "Escudo Boko"},
Text{"Ordon Shield", "Bouclier de Toal", "Escudo de Ordon"},
Text{"Wooden Shield", "Bouclier de Bois", "Escudo de madera"}};
trickNameTable[GI_SHIELD_HYLIAN] = {
Text{"Hyrule Shield", "Bouclier d'Hyrule", "Escudo Hylian"},
Text{"Goddess Shield", "Bouclier Sacré", "Escudo Divino"},
Text{"Hero's Shield", "Bouclier du Héros", "Escudo del héroe"}};
trickNameTable[GI_SHIELD_MIRROR] = {
Text{"Magic Mirror", "Miroir Magique", "Escudo mágico"},
Text{"Magical Shield", "Bouclier Magique", "Escudo arcano"},
Text{"Mirror of Twilight", "Miroir des Ombres", "Espejo del Crepúsculo"}};
trickNameTable[GI_TUNIC_GORON] = {
Text{"Gerudo Tunic", "Tunique Gerudo", "Sayo gerudo"},
Text{"Magic Armor", "Armure Magique", "Túnica Goron"},
Text{"Red Mail", "Habits Rouges", "Ropas rojas"}};
trickNameTable[GI_TUNIC_ZORA] = {
Text{"Rito Tunic", "Tunique Rito", "Sayo rito"},
Text{"Zora Armor", "Armure Zora", "Túnica Zora"},
Text{"Blue Mail", "Habits Bleus", "Ropas azules"}};
trickNameTable[GI_BOOTS_IRON] = {
Text{"Iron Hoofs", "Patins de Plomb", "Botas férreas"},
Text{"Snow Boots", "Bottes de Neige", "Botas de nieve"},
Text{"Boots of Power", "Bottes de Puissance", "Botas de plomo"}};
trickNameTable[GI_BOOTS_HOVER] = {
Text{"Hover Hoofs", "Patins des airs", "Botas flotadoras"},
Text{"Pegasus Boots", "Bottes pégase", "Botas de Pegaso"},
Text{"Boots of Speed", "Bottes de vitesse", "Botas del desierto"}};
trickNameTable[GI_WEIRD_EGG] = {
Text{"Poached Egg", "Oeuf à la coque", "Huevo pasado"},
Text{"Lon Lon Egg", "Oeuf Lon Lon", "Huevo Lon Lon"},
Text{"Zora Egg", "Oeuf Zora", "Huevo Zora"}};
trickNameTable[GI_LETTER_ZELDA] = {
Text{"Ruto's Letter", "Lettre de Ruto", "Carta de Ruto"},
Text{"Royal Letter", "Lettre Eoyale", "Carta para Kafei"},
Text{"Zelda's Business Card", "Carte d'affaires de Zelda", "Carta"}};
trickNameTable[GI_BOOMERANG] = {
Text{"Prank Fetch Toy", "Inséparable Bâtonnet", "Bumerang"},
Text{"Gale Boomerang", "Boomerang Tornade", "Bumerán tornado"},
Text{"Magic Boomerang", "Boomerang Magique", "Bumerán mágico"}};
trickNameTable[GI_LENS] = {
Text{"Sheikah-leidoscope", "Sheikah-léidoscope", "Monóculo de la Verdad"},
Text{"Sheikah Sensor", "Sonar Sheikah", "Sensor Sheikah"},
Text{"Magnifying Lens", "Loupe", "Lente Aumentadora"}};
trickNameTable[GI_HAMMER] = {
Text{"Goron Gavel", "Masse Perforatrice", "Mazo Goron"},
Text{"Magic Hammer", "Marteau Magique", "Martillo mágico"},
Text{"Skull Hammer", "Maillet Ressort", "Martillo de hierro"}};
trickNameTable[GI_STONE_OF_AGONY] = {
Text{"Shard of Agahnim", "Fragment d'Agahnim", "Piedra de Agahnim"},
Text{"Stone of Agony", "Pierre de Souffrance", "Fragmento de la Agonía"},
Text{"Pirate's Charm", "Pierre de Pirate", "Amuleto Pirata"}};
trickNameTable[GI_DINS_FIRE] = {
Text{"Eldin's Fire", "Feu d'Eldin", "Fuego de Eldin"},
Text{"Din's Blaze", "Flamme de Din", "Poder de Din"},
Text{"Din's Pearl", "Perle de Din", "Orbe de Din"}};
trickNameTable[GI_FARORES_WIND] = {
Text{"Faron's Wind", "Vent de Firone", "Viento de Farone"},
Text{"Farore's Windfall", "Zéphyr de Farore", "Valor de Farore"},
Text{"Farore's Pearl", "Perle de Farore", "Orbe de Farore"}};
trickNameTable[GI_NAYRUS_LOVE] = {
Text{"Lanayru's Love", "Amour de Lanelle", "Amor de Lanayru"},
Text{"Nayru's Passion", "Passion de Nayru", "Sabiduría de Nayru"},
Text{"Nayru's Pearl", "Perle de Nayru", "Orbe de Nayru"}};
trickNameTable[GI_ARROW_FIRE] = {
Text{"Soul Arrow", "Flèche des Esprits", "Flecha del Espíritu"},
Text{"Bomb Arrow", "Flèche-Bombe", "Flecha bomba"},
Text{"Fire Candy", "Bonbon deFfeu", "Cetro de fuego"}};
trickNameTable[GI_ARROW_ICE] = {
Text{"Shadow Arrow", "Flèche d'Ombre", "Flecha de las Sombras"},
Text{"Ancient Arrow", "Flèche Archéonique", "Flecha ancestral"},
Text{"Ice Trap Arrow", "Flèche de Piège de Glace", "Cetro de hielo"}};
trickNameTable[GI_ARROW_LIGHT] = {
Text{"Wind Arrow", "Flèche de Vent", "Flecha del Viento"},
Text{"Shock Arrow", "Flèches Électriques", "Flecha eléctrica"},
Text{"Silver Arrow", "Flèches d'Argent", "Flecha de plata"}};
trickNameTable[GI_GERUDO_CARD] = {
Text{"Desert Title Deed", "Abonnement Gerudo", "Escritura del desierto"},
Text{"Gerudo's Card", "Carte Goron", "Tóken Gerudo"},
Text{"Gerudo's Membership Card", "Autographe de Nabooru", "Tarjeta Gerudo"}};
trickNameTable[0xC9] = {
Text{"Funky Bean Pack", "Paquet de Fèves Magiques", "Lote de frijoles mágicos"},
Text{"Crenel Bean Pack", "Paquet de Haricots Gonggle", "Lote de alubias mágicas"},
Text{"Mystic Bean Pack", "Paquet de Haricots Mystiques", "Lote de porotos mágicos"}};
trickNameTable[0xB8] = {
Text{"Diamond Hearts", "Coeurs de Diamant", "Contenedor de diamante"},
Text{"Double Damage", "Double Souffrance", "Doble daño receptivo"},
Text{"Quadruple Defence", "Quadruple Défence", "Defensa cuádruple"}};
trickNameTable[GI_POCKET_EGG] = {
Text{"Poached Egg", "oeuf à la coque", "Huevo pasado"},
Text{"Lon Lon Egg", "oeuf Lon Lon", "Huevo Lon Lon"},
Text{"Zora Egg", "oeuf Zora", "Huevo del Pez Viento"}};
trickNameTable[GI_POCKET_CUCCO] = {
Text{"D.I.Y. Alarm Clock", "Réveille-matin improvisé", "Alarma emplumada portátil"},
Text{"Kakariko Cucco", "Cocotte Cocorico", "Cuco de Kakariko"},
Text{"Hatched Cucco", "Cocotte éclose", "Pollo de bolsillo"}};
trickNameTable[GI_COJIRO] = {
Text{"Blucco", "Chair-Qui-Poule", "Cucazul"},
Text{"Grog's Cucco", "Cocotte de Grog", "Cuco de Grog"},
Text{"Corijo", "Cojiro", "Corijo"}};
trickNameTable[GI_ODD_MUSHROOM] = {
Text{"Magic Mushroom", "Champignon magique", "Champiñón mágico"},
Text{"Endura Shroom", "Champi Vigueur", "Champiñón del bosque"},
Text{"Mushroom", "Champignon", "Seta"}};
trickNameTable[GI_ODD_POTION] = {
Text{"Odd Medicine", "Élixir suspect", "Poción rara"},
Text{"Granny's Poultice", "Mixture de Granny", "Medicina de la abuela"},
Text{"Mushroom Poultice", "Mixture de champignon", "Medicina de champiñones"}};
trickNameTable[GI_SAW] = {
Text{"Carpenter's Saw", "Scie du charpentier", "Sierra del carpintero"},
Text{"Poacher's Sword", "Hache du chasseur", "Espada del capataz"},
Text{"Grog's Saw", "Scie de Grog", "Sierra del Cazador Furtivo"}};
trickNameTable[GI_SWORD_BROKEN] = {
Text{"Broken Biggoron's Sword", "Épée brisée de Grogoron", "Espada de Biggoron rota"},
Text{"Broken Giant's Knife", "Lame des Géants brisée", "Daga gigante rota"},
Text{"Biggoron's Sword", "Épée de Biggoron", "Espada de Biggoron"}};
trickNameTable[GI_PRESCRIPTION] = {
Text{"Biggoron's Prescription", "Ordonnance de Grogoron", "Receta de Biggoron"},
Text{"Eyedrop Prescription", "Ordonnance de gouttes", "Receta ocular"},
Text{"Urgent Prescription", "Ordonnance urgente", "Prescripción"}};
trickNameTable[GI_FROG] = {
Text{"Don Gero", "Don Gero", "Don Gero"},
Text{"Eyedrop Frog", "Grenouille-qui-louche", "Globo Ocular de Rana"},
Text{"Frog", "Crapaud", "Rana"}};
trickNameTable[GI_EYEDROPS] = {
Text{"Biggoron's Eyedrops", "Gouttes de Grogoron", "Gotas de Biggoron"},
Text{"Hyrule's Finest Eyedrops", "Eau du Lac Hylia", "Gotas oculares"},
Text{"Zora Perfume", "Parfum Zora", "Perfume Zora"}};
trickNameTable[GI_CLAIM_CHECK] = {
Text{"Clay Check", "Certificat Grogoron", "Comprobante de Reclamación"},
Text{"Sheikah Slate", "Tablette Sheikah", "Piedra Sheikah"},
Text{"Cyclone Slate", "Ardoise des tornades", "Pizarra de los Torbellinos"}};
trickNameTable[GI_SKULL_TOKEN] = {
Text{"Skulltula Token", "Bon de Skulltula dorée", "Símbolo de Skulltula"},
Text{"Golden Skulltula Spirit", "Pièce de Skulltula dorée", "Tóken de Skulltula Dorada"},
Text{"Gold Walltula Token", "Jeton de Walltula dorée", "Skulltula dorada"}};
trickNameTable[0x80] = {
Text{"Progressive Grappling Hook", "Lance-chaîne (prog.)", "Garra progresiva"},
Text{"Progressive Clawshot", "Grappin-griffe (prog.)", "Zarpa progresiva"},
Text{"Progressive Gripshot", "Grappince (prog.)", "Enganchador progresivo"}};
trickNameTable[0x81] = {
Text{"Progressive Glove", "Gant de puissance (prog.)", "Guanteletes progresivos"},
Text{"Progressive Power Bracelet", "Bracelet de force (prog.)", "Brasaletes progresivos"},
Text{"Progressive Magic Bracelet", "Bracelet magique (prog.)", "Manoplas progresivas"}};
trickNameTable[0x82] = {
Text{"Progressive Bomb Capacity", "Capacité de bombes (prog.)", "Mayor capacidad de bombas"},
Text{"Progressive Bomb Pack", "Paquet de bombes (prog.)", "Zurrón de bombas progresivo"},
Text{"Progressive Bomb Box", "Boîte à bombes (prog.)", "Bolsa de bombas progresiva"}};
trickNameTable[0x83] = {
Text{"Progressive Arrow Capacity", "Capacité de flèches (prog.)", "Mayor capacidad de flechas"},
Text{"Progressive Hero's Bow", "Arc du héros (prog.)", "Arco del héroe progresivo"},
Text{"Progressive Arrow Holder", "Arbalète (prog.)", "Ballesta progresiva"}};
trickNameTable[0x84] = {
Text{"Progressive Seed Capacity", "Capacité de graines (prog.)", "Mayor capacidad de semillas"},
Text{"Progressive Scattershot", "Lance-Pierre rafale (prog.)", "Resortera múltiple progresiva"},
Text{"Progressive Seed Satchel", "Sac de graines (prog.)", "Bolsa de semillas progresiva"}};
trickNameTable[0x85] = {
Text{"Progressive Rupee Capacity", "Capacité de rubis (prog.)", "Mayor capacidad de rupias"},
Text{"Progressive Purse", "Sacoche (prog.)", "Cartera de rupias progresiva"},
Text{"Progressive Rupee Bag", "Sac à rubis (prog.)", "Zurrón de rupias progresivo"}};
trickNameTable[0x86] = {
Text{"Progressive Diving Ability", "Plongée (prog.)", "Buceo progresivo"},
Text{"Progressive Pearl", "Perle (prog.)", "Perla progresiva"},
Text{"Progressive Scute", "Bulle (prog.)", "Fragmento Zora progresivo"}};
trickNameTable[0x87] = {
Text{"Progressive Nut Pack", "Paquet de noix (prog.)", "Mayor capacidad de semillas"},
Text{"Progressive Nut Bag", "Sac de noix (prog.)", "Bolsa de nueces progresiva"},
Text{"Progressive Husk Capacity", "Capacité de noisettes (prog.)", "Mayor capacidad de castañas"}};
trickNameTable[0x88] = {
Text{"Progressive Stick Pack", "Paquet de bâtons Mojo (prog.)", "Mayor capacidad de bastones"},
Text{"Progressive Stick Bag", "Sac de bâtons (prog.)", "Mayor capacidad de ramas deku"},
Text{"Progressive Rod Capacity", "Capacité de tiges (prog.)", "Mayor capacidad de cetros deku"}};
trickNameTable[0x89] = {
Text{"Progressive Bomblings", "Bombinsectes (prog.)", "Bombinsectos progresivos"},
Text{"Progressive Missiles", "Missiles (prog.)", "Misiles progresivos"},
Text{"Progressive Bombchu Bag", "Sac à Bombchu (prog.)", "Bombachus progresivos"}};
trickNameTable[0x8A] = {
Text{"Progressive Stamina Meter", "Jauge d'endurance (prog.)", "Medidor de vigor progresivo"},
Text{"Progressive Energy Meter", "Jauge d'énergie (prog.)", "Medidor de energía progresivo"},
Text{"Progressive Magic Powder", "Poudre magique (prog.)", "Medidor de carga progresivo"}};
trickNameTable[0x8B] = {
Text{"Progressive Memento", "Souvenir (prog.)", "Silbato progresivo"},
Text{"Progressive Flute", "Flûte (prog.)", "Flauta progresiva"},
Text{"Progressive Recorder", "Harmonica (prog.)", "Armónica progresiva"}};
trickNameTable[0xD4] = {
Text{"Progressive Titan Blade", "Lame des Titans (prog.)", "Hoja del Titán progresiva"},
Text{"Progressive Goron Knife", "Lame Goron (prog.)", "Daga Goron progresiva"},
Text{"Progressive Giant Sword", "Épée géante (prog.)", "Espada gigante progresiva"}};
trickNameTable[0x0F] = {
Text{"Magic Bottle", "Flacon magique", "Frasco feérico"},
Text{"Glass Bottle", "Flacon de verre", "Botella de cristal"},
Text{"Bottle with Water", "Flacon d'eau", "Botella Tingle"}};
trickNameTable[0x14] = {
Text{"Bottle with Chateau Romani", "Flacon de cuvée Romani", "Botella de Reserva Romani"},
Text{"Bottle with Fresh Milk", "Flacon de lait frais", "Botella de leche fresca"},
Text{"Bottle with Mystery Milk", "Flacon de lait grand cru", "Botella de leche extra"}};
trickNameTable[0x8C] = {
Text{"Bottle with Red Chu Jelly", "Flacon de gelée Chuchu rouge", "Jugo de Chuchu Rojo"},
Text{"Bottle with Medicine of Life", "Flacon d'élixir rouge", "Botella de medicina de la vida"},
Text{"Bottle with Heart Potion", "Flacon de potion de soin", "Botella de poción de salud"}};
trickNameTable[0x8D] = {
Text{"Bottle with Green Chu Jelly", "Flacon de gelée Chuchu verte", "Jugo de Chuchu Verde"},
Text{"Bottle with Medicine of Magic", "Flacon d'élixir vert", "Botella de medicina mágica"},
Text{"Bottle with Stamina Potion", "Flacon d'Endurol", "Botella de elixir vigorizante"}};
trickNameTable[0x8E] = {
Text{"Bottle with Blue Chu Jelly", "Flacon de gelée Chuchu bleue", "Jugo de Chuchu Azul"},
Text{"Bottle with Water of Life", "Flacon d'élixir bleu", "Botella de agua de la vida"},
Text{"Bottle with Air Potion", "Flacon de potion d'oxygène", "Botella de oxígeno"}};
trickNameTable[0x8F] = {
Text{"Bottle with Forest Firefly", "Flacon avec une luciole", "Luciérnaga del bosque"},
Text{"Bottle with Faerie", "Flacon de poudre féérique", "Gran Hada embotellada"},
Text{"Bottle with Stray Fairy", "Flacon avec une fée perdue", "Hada perdida en una botella"}};
trickNameTable[0x90] = {
Text{"Bottle with Small Jabu-Jabu", "Flacon avec mini Jabu-Jabu", "Lord Chapu-Chapu embotellado"},
Text{"Bottle with Hyrule Bass", "Flacon avec perche d'Hyrule", "Locha de Hyrule embotellada"},
Text{"Bottle with Hyrule Loach", "Flacon avec loche d'Hyrule", "Perca de Términa embotellada"}};
trickNameTable[0x91] = {
Text{"Bottle with Will-O-Wisp", "Flacon avec feu follet", "Botella de llama azul"},
Text{"Bottle with Ancient Flame", "Flacon de flamme ancienne", "Botella de fuego ancestral"},
Text{"Bottle with Nayru's Flame", "Flacon de flamme de Nayru", "Botella de llamas de Nayru"}};
trickNameTable[0x92] = {
Text{"Bottle with Baby Tektites", "Flacon de bébé Araknon", "Tektites en una botella"},
Text{"Bottle with Lanayru Ants", "Flacon de fourmis de Lanelle", "Celestarabajo embotellado"},
Text{"Bottle with Insects", "Flacon de bibittes", "Saltabosques embotellados"}};
trickNameTable[0x94] = {
Text{"Bottle with Ghini", "Flacon avec Ghini", "Ghini en una botella"},
Text{"Bottle with Imp Poe", "Flacon avec Spectre", "Espectro en una botella"},
Text{"Bottle with Anti-Fairy", "Flacon avec Tetdoss", "Whisp en una botella"}};
trickNameTable[0x15] = {
Text{"Bottle with Maggie's Letter", "Flacon avec lettre de Maggy", "Carta de Dolores"},
Text{"Bottle with Letter to Kafei", "Flacon avec lettre pour Kafei", "Carta para Kafei"},
Text{"Bottle with Zelda's Letter", "Flacon avec Lettre de Zelda", "Carta náutica"}};
trickNameTable[0x93] = {
Text{"Bottle with Composer Brother", "Flacon avec un compositeur", "Hermana Poe embotellada"},
Text{"Bottle with Jalhalla", "Flacon avec Jalhalla", "Yaihalla embotellado"},
Text{"Bottle with Grim Repoe", "Flacon avec le Faucheur", "Bubble en una botella"}};
trickNameTable[0xC1] = {
Text{"Ballad of the Goddess", "Chant de la déesse", "Cántico de la Diosa"},
Text{"Song of Healing", "Chant de l'apaisement", "Canción de curación"},
Text{"Bolero of Fire", "Boléro du feu", "Bolero del fuego"}};
trickNameTable[0xC2] = {
Text{"Earth God's Lyric", "Hymne du dieu de la terre", "Melodía del Espíritu de la Tierra"},
Text{"Song of Soaring", "Chant de l'envol", "Canción del viento"},
Text{"Requiem of Spirit", "Requiem des esprits", "Réquiem del espíritu"}};
trickNameTable[0xC3] = {
Text{"Wind God's Aria", "Hymne du dieu du vent", "Melodía del Espíritu del Viento"},
Text{"Wind's Requiem", "Mélodie du vent", "Melodía del Viento"},
Text{"Minuet of Forest", "Menuet de la forêt", "Minueto del bosque"}};
trickNameTable[0xC4] = {
Text{"Song of Passing", "Mambo de Manbo", "Melodía del transcurrir"},
Text{"Command Melody", "Air du marionnettiste", "Cara al Sol"},
Text{"Prelude of Light", "Prélude de la lumière", "Preludio de la luz"}};
trickNameTable[0xC5] = {
Text{"Song of Double Time", "Chant accéléré", "Canción del doble tiempo"},
Text{"Inverted Song of Time", "Chant du temps inversé", "Canción del tiempo invertida"},
Text{"Serenade of Water", "Sérénade de l'eau", "Serenata del agua"}};
trickNameTable[0xC6] = {
Text{"Ballad of Gales", "Requiem de la tornade", "Melodía del Tornado"},
Text{"Frog's Song of Soul", "Rap des grenouilles", "Canción del alma de la rana"},
Text{"Nocturne of Shadow", "Nocturne de l'ombre", "Nocturno de la sombra"}};
trickNameTable[0xBB] = {
Text{"Saria's Karaoke", "Karaoké de Saria", "Dueto del bosque"},
Text{"Sonata of Awakening", "Sonate de l'éveil", "Sonata del despertar"},
Text{"Saria's Song", "Chant de Saria", "Canción de Saria"}};
trickNameTable[0xBC] = {
Text{"Darunia's Tango", "Tango de Darunia", "Coro del fuego"},
Text{"Goron Lullaby", "Berceuse des Gorons", "Nana goron"},
Text{"Zelda's Lullaby", "Berceuse de Zelda", "Nana de Zelda"}};
trickNameTable[0xBD] = {
Text{"Ruto's Blues", "Blues de Ruto", "Sonata del agua"},
Text{"New Wave Bossa Nova", "Bossa-nova des flots", "Bossanova de las olas"},
Text{"Song of Time", "Chant du temps", "Canción del tiempo"}};
trickNameTable[0xBE] = {
Text{"Nabooru's Reggae", "Reggae de Nabooru", "Reggae del espíritu"},
Text{"Elegy of Emptiness", "Hymne du vide", "Elegía al vacío"},
Text{"Epona's Song", "Chant d'Épona", "Canción de Epona"}};
trickNameTable[0xBF] = {
Text{"Impa's Death Metal", "Death métal d'Impa", "Diurno de la sombra"},
Text{"Oath to Order", "Ode de l'appel", "Oda al orden"},
Text{"Song of Storms", "Chant des tempêtes", "Canción de la tormenta"}};
trickNameTable[0xC0] = {
Text{"Rauru's Sing-Along", "Chansonnette de Rauru", "Predulio de luz"},
Text{"Ballad of the Wind Fish", "Ballade sur Poisson-Rêve", "Balada del Piez Viento"},
Text{"Sun's Song", "Chant du soleil", "Canción del Sol"}};
trickNameTable[0xCB] = {
Text{"Pendant of Courage", "Pendentif du courage", "Colgante del valor"},
Text{"Farore's Emerald", "Émeraude de Farore", "Esmeralda de Farore"},
Text{"Kokiri's Peridot", "Péridot Kokiri", "Ágata de los Kokiri"}};
trickNameTable[0xCC] = {
Text{"Pendant of Power", "Pendentif de la force", "Colgante del poder"},
Text{"Din's Ruby", "Rubis de Din", "Rubí de Din"},
Text{"Goron's Garnet", "Grenat Goron", "Topacio de los Goron"}};
trickNameTable[0xCD] = {
Text{"Pendant of Wisdom", "Pendentif de la sagesse", "Colgante de la sabiduría"},
Text{"Nayru's Sapphire", "Saphir de Nayru", "Zafiro de Nayru"},
Text{"Zora's Aquamarine", "Aquamarine Zora", "Lapislázuli de los Zora"}};
trickNameTable[0xCE] = {
Text{"Wind Medallion", "Médaillon du vent", "Medallón del Viento"},
Text{"Saria's Medallion", "Médaillon de Saria", "Medallón de Saria"},
Text{"Medallion of Forest", "Médaillon du Temple de la Forêt", "Medalla del Bosque"}};
trickNameTable[0xCF] = {
Text{"Bombos Medallion", "Médaillon des flammes", "Medallón del Temblor"},
Text{"Darunia's Medallion", "Médaillon de Darunia", "Medallón de Darunia"},
Text{"Medallion of Fire", "Médaillon du Temple du Feu", "Medalla del Fuego"}};
trickNameTable[0xD0] = {
Text{"Ice Medallion", "Médaillon de glace", "Medallón Helado"},
Text{"Ruto's Medallion", "Médaillon de Ruto", "Medallón de Ruto"},
Text{"Medallion of Water", "Médaillon du Temple de l'Eau", "Medalla del Agua"}};
trickNameTable[0xD1] = {
Text{"Quake Medallion", "Médaillon des secousses", "Medallón Llamarada"},
Text{"Nabooru's Medallion", "Médaillon de Nabooru", "Medallón de Nabooru"},
Text{"Medallion of Spirit", "Médaillon du Temple de l'Esprit", "Medalla del Espíritu"}};
trickNameTable[0xD2] = {
Text{"Travel Medallion", "Amulette de téléportation", "Medallón Maligno"},
Text{"Impa's Medallion", "Médaillon d'Impa", "Medallón de Impa"},
Text{"Medallion of Shadow", "Médaillon du Temple de l'Ombre", "Medalla de la Sombra"}};
trickNameTable[0xD3] = {
Text{"Ether Medallion", "Médaillon d'éther", "Medallón de Tesoro"},
Text{"Rauru's Medallion", "Médaillon de Rauru", "Medallón de Rauru"},
Text{"Medallion of Light", "Médaillon du temple de lumière", "Medalla de la Luz"}};
trickNameTable[GI_HEART] = {
Text{"Love", "Bisou", "Te amo"},
Text{"Heart Container", "Réceptacle de coeur", "Contenedor de corazón"},
Text{"Piece of Heart", "Quart de coeur", "Pieza de corazón"}};
trickNameTable[GI_RUPEE_GREEN] = {
Text{"Green Rupy", "Rupee vert", "Rubia verde"},
Text{"One Rupee", "Un rubis", "Guaraní hyliano"},
Text{"Rupee (1)", "Rubis (1)", "Peso hyliano"}};
trickNameTable[GI_RUPEE_BLUE] = {
Text{"Blue Rupy", "Rupee bleu", "Rubia azul"},
Text{"Five Rupees", "Cinq rubis", "Bolívar hyliano"},
Text{"Rupee (5)", "Rubis (5)", "Peso hyliano"}};
trickNameTable[GI_RUPEE_RED] = {
Text{"Red Rupy", "Rupee rouge", "Rubia roja"},
Text{"Twenty Rupees", "Vingt rubis", "Colon hyliano"},
Text{"Rupee (20)", "Rubis (20)", "Peso hyliano"}};
trickNameTable[GI_RUPEE_PURPLE] = {
Text{"Purple Rupy", "Rupee pourpre", "Rubia morada"},
Text{"Fifty Rupees", "Cinquante rubis", "Balboa hyliano"},
Text{"Rupee (50)", "Rubis (50)", "Peso hyliano"}};
trickNameTable[GI_RUPEE_GOLD] = {
Text{"Huge Rupy", "Énorme Rupee", "Rubia gigante"},
Text{"Two Hundred Rupees", "Deux cent rubis", "Euro hyliano"},
Text{"Rupee (200)", "Rubis (200)", "Dólar hyliano"}};
trickNameTable[GI_HEART_PIECE] = {
Text{"Piece of Health", "Quart d'énergie", "Pieza de amor"},
Text{"Recovery Heart", "Coeur d'énergie", "Corazón"},
Text{"Heart Container", "Réceptacle de coeur", "Contenedor de corazón"}};
trickNameTable[GI_HEART_CONTAINER_2] = {
Text{"Health Container", "Réceptacle d'énergie", "Contenedor de amor"},
Text{"Recovery Heart", "Quart de coeur", "Corazón"},
Text{"Piece of Heart", "Coeur d'énergie", "Pieza de corazón"}};
/*
//Names for individual upgrades, in case progressive names are replaced
trickNameTable[GI_HOOKSHOT] = {
Text{"Grappling Hook", "Grappin-griffe", "Gancho lanzable"},
Text{"Clawshot", "Lance-chaîne", "Zarpa"},
Text{"Gripshot", "Grappince", "Enganchador"}};
trickNameTable[GI_LONGSHOT] = {
Text{"Longshot, no strings attached", "Grappin sans attrape", "Gancho lanzable más largo"},
Text{"Double Clawshot", "Double-grappin", "Superzarpa"},
Text{"Switch Hook", "Great grappin", "Gancho chulo"}};
trickNameTable[GI_BOMB_BAG_1] = {
Text{"Bomb Capacity (20)", "Capacité de bombes (20)", "Bolsa de bombas (contiene 20)"},
Text{"Bronze Bomb Bag", "Sac de Bombes de bronze", "Saco de bronce de bombas"},
Text{"Small Bomb Bag", "Petit Sac de Bombes", "Zurrón de bombas pequeño"}};
trickNameTable[GI_BOMB_BAG_2] = {
Text{"Bomb Capacity (30)", "Capacité de bombes (30)", "Bolsa de bombas (contiene 30)"},
Text{"Silver Bomb Bag", "Sac de Bombes d'argent", "Saco plateado de bombas"},
Text{"Medium Bomb Bag", "Sac de Bombes moyen", "Zurrón de bombas mediano"}};
trickNameTable[GI_BOMB_BAG_3] = {
Text{"Bomb Capacity (40)", "Capacité de bombes (40)", "Bolsa de bombas (contiene 40)"},
Text{"Golden Bomb Bag", "Sac de Bombes d'or", "Saco dorado de bombas"},
Text{"Large Bomb Bag", "Gros Sac de Bombes", "Zurrón de bombas grande"}};
trickNameTable[GI_BOW_1] = {
Text{"Bow", "Arc", "Arco del Hada"},
Text{"Hero's Bow", "Arc du héros", "Arco del héroe"},
Text{"Small Quiver", "Petit carquois", "Saco de flechas pequeño"}};
trickNameTable[GI_BOW_2] = {
Text{"Arrow Capacity (40)", "Capacité de flèches (40)", "Capacidad de flechas (40)"},
Text{"Silver Quiver", "Carquois d'argent", "Carcaj plateado"},
Text{"Medium Quiver", "Carquois moyen", "Saco de flechas mediano"}};
trickNameTable[GI_BOW_3] = {
Text{"Arrow Capacity (50)", "Capacité de flèches (50)", "Capacidad de flechas (50)"},
Text{"Golden Quiver", "Carquois d'or", "Carcaj dorado"},
Text{"Large Quiver", "Gros carquois", "Saco de flechas grande"}};
trickNameTable[GI_SLINGSHOT_1] = {
Text{"Slingshot", "Lance-Pierre", "Tirachinas del Hada"},
Text{"Scattershot", "Lance-Pierre rafale", "Tirachinas múltiple"},
Text{"Small Seed Satchel", "Petit sac de graines", "Bolsa de semillas pequeña"}};
trickNameTable[GI_SLINGSHOT_2] = {
Text{"Deku Seed Capacity (40)", "Capacité de graines (40)", "Capacidad de semillas (40)"},
Text{"Silver Deku Seed Bullet Bag", "Sac de graines d'argent", "Bolsa de balas (contiene 40)"},
Text{"Medium Seed Satchel", "Sac de graines moyen", "Bolsa de semillas mediana"}};
trickNameTable[GI_SLINGSHOT_3] = {
Text{"Deku Seed Capacity (50)", "Capacité de graines (50)", "Capacidad de semillas (50)"},
Text{"Golden Deku Seed Bullet Bag", "Sac de graines d'or", "Bolsa de balas (contiene 50)"},
Text{"Large Seed Satchel", "Gros sac de graines", "Bolsa de semillas grande"}};
trickNameTable[GI_STRENGTH_1] = {
Text{"Goron's Gauntlet", "Gantelet Goron", "Brazalete amarillo"},
Text{"Power Bracelet", "Bracelet de force", "Brazalete de fuerza"},
Text{"Magic Bracelet", "Bracelet de Lavio", "Brazalete de Ravio"}};
trickNameTable[GI_STRENGTH_2] = {
Text{"Silver Bracelets", "Bracelets d'argent", "Guantes Moguma"},
Text{"Power Gloves", "Gant de puissance", "Guante del Poder"},
Text{"Magic Gauntlets", "Gantelet magique", "Guante mágico"}};
trickNameTable[GI_STRENGTH_3] = {
Text{"Golden Bracelets", "Bracelets d'or", "Guantelete de Thanos"},
Text{"Titan's Mitts", "Moufle de titan", "Guantes de Titán"},
Text{"Magnetic Gloves", "Magnéto-gants", "Guantes de fuego"}};
trickNameTable[GI_SCALE_1] = {
Text{"Silver Pearl", "Perle d'argent", "Perla de Plata progresiva"},
Text{"Adult Scale", "Écaille d'adulte", "Bola de bolos zora"},
Text{"Zora Scale", "Écaille Zora", "Escama de Zora"}};
trickNameTable[GI_SCALE_2] = {
Text{"Golden Pearl", "Perle d'or", "Perla de Oro progresiva"},
Text{"Giant Scale", "Écaille de géant", "Escama de Faren"},
Text{"Water Dragon Scale", "Écaille du dragon de l'eau", "Escama de dragón acuático"}};
trickNameTable[GI_WALLET_1] = {
Text{"Rupee Capacity (200)", "Capacité de rubis (200)", "Capacidad de rupias (200)"},
Text{"Silver Wallet", "Bourse d'argent", "Cartera de rupias de adulto"},
Text{"Medium Wallet", "Bourse moyenne", "Zurrón de rupias mediano"}};
trickNameTable[GI_WALLET_2] = {
Text{"Rupee Capacity (500)", "Capacité de rubis (500)", "Capacidad de rupias (500)"},
Text{"Golden Wallet", "Bourse d'or", "Cartera de rupias gigante"},
Text{"Large Wallet", "Grosse Bourse", "Zurrón de rupias grande"}};
trickNameTable[GI_WALLET_3] = {
Text{"Rupee Capacity (999)", "Capacité de rubis (999)", "Capacidad de rupias (999)"},
Text{"Golden Wallet", "Bourse d'or", "Cartera de ricachón"},
Text{"Large Wallet", "Grosse Bourse", "Zurrón de rupias gigante"}};
trickNameTable[GI_DEKU_NUT_UPGRADE_1] = {
Text{"Deku Bomb Capacity (30)", "Capacité de bombes Mojo (30)", "Capacidad de semillas deku (40)"},
Text{"Baba Nut Capacity (30)", "Capacité de noix Baba (30)", "Capacidad de nueces baba (40)"},
Text{"Deku Nut Pack (30)", "Paquet de noix Mojo (30)", "Capacidad de nueces mojo (40)"}};
trickNameTable[GI_DEKU_NUT_UPGRADE_2] = {
Text{"Deku Bomb Capacity (40)", "Capacité de bombes Mojo (40)", "Capacidad de semillas deku (50)"},
Text{"Baba Nut Capacity (40)", "Capacité de noix Baba (40)", "Capacidad de nueces baba (50)"},
Text{"Deku Nut Pack (40)", "Paquet de noix Mojo (40)", "Capacidad de nueces mojo (50)"}};
trickNameTable[GI_DEKU_STICK_UPGRADE_1] = {
Text{"Deku Rod Capacity (20)", "Capacité de tiges Mojo (20)", "Capacidad de palos mojo (20)"},
Text{"Boko Stick Capacity (20)", "Capacité de Bâtons Boko (20)", "Capacidad de palos boko (20)"},
Text{"Deku Stick Pack (20)", "Paquet de bâtons Mojo (20)", "Capacidad de bastones deku (20)"}};
trickNameTable[GI_DEKU_STICK_UPGRADE_2] = {
Text{"Deku Rod Capacity (30)", "Capacité de tiges Mojo (30)", "Capacidad de palos mojo (30)"},
Text{"Boko Stick Capacity (30)", "Capacité de Bâtons Boko (30)", "Capacidad de palos boko (30)"},
Text{"Deku Stick Pack (30)", "Paquet de bâtons Mojo (30)", "Capacidad de bastones deku (30)"}};
trickNameTable[GI_MAGIC_1] = {
Text{"Stamina Meter", "Jauge d'endurance", "Medidor de vigor"},
Text{"Energy Meter", "Jauge d'énergie", "Medidor de energía"},
Text{"Magic Powder", "Poudre magique", "Medidor de carga"}};
trickNameTable[GI_MAGIC_2] = {
Text{"Enhanced Stamina Meter", "Jauge d'endurance améliorée", "Medidor de vigor mejorado"},
Text{"Enhanced Energy Meter", "Jauge d'énergie améliorée", "Medidor de energía mejorado"},
Text{"Enhanced Magic Powder", "Poudre magique améliorée", "Medidor de carga mejorado"}};
trickNameTable[GI_OCARINA_1] = {
Text{"Ocarina", "Ocarina", "Ocarina"},
Text{"Saria's Ocarina", "Ocarina de Saria", "Ocarina de Saria"},
Text{"Wood Ocarina", "Ocarina de bois", "Ocarina del Hada"}};
trickNameTable[GI_OCARINA_2] = {
Text{"Flute", "Flûte", "Flauta"},
Text{"Zelda's Ocarina", "Ocarina de Zelda", "Ocarina de Zelda"},
Text{"Ocarina of Winds", "Ocarina des vents", "Ocarina del Viento"}};
trickNameTable[GI_CUCCO] = {
Text{"D.I.Y. Alarm Clock", "Réveille-matin improvisé", "Alarma emplumada"},
Text{"Kakariko Cucco", "Cocotte Cocorico", "Cuco de Kakariko"},
Text{"Hatched Cucco", "Cocotte éclose", "Pollo"}};
trickNameTable[GI_MASK_KEATON] = {
Text{"Kee... Something Mask", "Masque de Quiche", "Máscara Kealgo"},
Text{"Kitsune Mask", "Masque de Kitsune", "Máscara Kitsune"},
Text{"Kafei's Mask", "Masque de Kafei", "Máscara de Kafei"}};
trickNameTable[GI_MASK_SKULL] = {
Text{"Skull Kid's Mask", "Masque de Skull Kid", "Máscara de Skull Kid"},
Text{"Stalfos Mask", "Masque de squelette", "Máscara de Stalfos"},
Text{"Captain's Hat", "Heaume du capitaine", "Casco del capitán"}};
trickNameTable[GI_MASK_SPOOKY] = {
Text{"Skrik Mask", "Masque Skrik", "Máscara Escalofriante"},
Text{"ReDead Mask", "Masque de Remort", "Máscara de ReDead"},
Text{"Gibdo Mask", "Masque de Gibdo", "Careta de Gibdo"}};
trickNameTable[GI_MASK_BUNNY] = {
Text{"Peppy Mask", "Masque de Peppy", "Capucha de Pascua"},
Text{"Bunny Ears", "Oreilles de lapin", "Orejas de conejo"},
Text{"Postman's Hat", "Casquette du facteur", "Gorra de cartero"}};
trickNameTable[GI_MASK_GORON] = {
Text{"Goro Mask", "Masque Goro", "Máscara Goro"},
Text{"Mask of Goron", "Masque des Gorons", "Máscara de los Goron"},
Text{"Darunia Mask", "Masque de Darunia", "Máscara de Darmani"}};
trickNameTable[GI_MASK_ZORA] = {
Text{"Zola Mask", "Masque Zola", "Máscara Zola"},
Text{"Mask of Zora", "Masque des Zoras", "Máscara de los Zora"},
Text{"Ruto Mask", "Masque de Ruto", "Máscara de Mikau"}};
trickNameTable[GI_MASK_GERUDO] = {
Text{"Ganguro Mask", "Masque de Ganguro", "Máscara Canguro"},
Text{"Mask of Gerudo", "Masque des Gerudos", "Máscara de las Gerudo"},
Text{"Nabooru Mask", "Masque de Nabooru", "Máscara de Nabooru"}};
trickNameTable[GI_MASK_TRUTH] = {
Text{"Sheikah Mask", "Masque Sheikah", "Máscara Sheikah"},
Text{"Mask of Gossip", "Masque de potins", "Máscara chismosa"},
Text{"Eye of Truth", "oeil de vérité", "Ojo de la Verdad"}};*/
}
//Generate a fake name for the ice trap based on the item it's displayed as
Text GetIceTrapName(uint8_t id) {
//If the trick names table has not been initialized, do so
if (!initTrickNames) {
InitTrickNames();
initTrickNames = true;
}
//Randomly get the easy, medium, or hard name for the given item id
return RandomElement(trickNameTable[id]);
}
//Get shop index based on a given location
static std::map<std::string_view, int> ShopNameToNum = {{"KF Shop", 0}, {"Kak Potion Shop", 1}, {"MK Bombchu Shop", 2}, {"MK Potion Shop", 3},
{"MK Bazaar", 4}, {"Kak Bazaar", 5}, {"ZD Shop", 6}, {"GC Shop", 7}};
int GetShopIndex(uint32_t loc) {
//Kind of hacky, but extract the shop and item position from the name
const std::string& name(Location(loc)->GetName());
int split = name.find(" Item ");
std::string_view shop(name.c_str(), split);
int pos = std::stoi(name.substr(split+6, 1)) - 1;
int shopnum = ShopNameToNum[shop];
return shopnum*8 + pos;
}
//Without this transformed index, shop-related tables and arrays would need 64 entries- But only half of that is needed for shopsanity
//So we use this transformation to map only important indices to an array with 32 entries in the following manner:
//Shop index: 4 5 6 7 12 13 14 15 20 21 22 23...
//Transformed: 0 1 2 3 4 5 6 7 8 9 10 11...
//So we first divide the shop index by 4, then by 2 which basically tells us the index of the shop it's in,
//then multiply by 4 since there are 4 items per shop
//And finally we use a modulo by 4 to get the index within the "shop" of 4 items, and add
int TransformShopIndex(int index) {
return 4*((index / 4) / 2) + index % 4;
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "item.hpp"
#include "item_location.hpp"
#include <vector>
#include <array>
struct ItemAndPrice {
Text Name;
int Price;
bool Repurchaseable;
};
extern void PlaceVanillaShopItems();
extern std::vector<uint32_t> GetMinVanillaShopItems(int total_replaced);
extern int GetRandomShopPrice();
extern int16_t GetRandomScrubPrice();
extern int GetShopsanityReplaceAmount();
extern Text GetIceTrapName(uint8_t id);
extern int GetShopIndex(uint32_t loc);
extern int TransformShopIndex(int index);
extern std::vector<ItemAndPrice> NonShopItems;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
#pragma once
#include <array>
#include <vector>
#include <stdint.h>
#define SFX_BASE 0x1000001
#define SFX_COUNT 1388
#define SFX_COUNT_TRIMMED (1388 - 233)
namespace SFX {
typedef enum {
// Movement
SEQ_WALK,
SEQ_WALK_LOUD,
SEQ_JUMP,
SEQ_LAND,
SEQ_SLIP,
SEQ_SLIP_LOOP,
SEQ_BOUND,
SEQ_CRAWL,
SEQ_MOVE_LOOP,
// Combat
SEQ_WEAPON_SWING,
SEQ_WEAPON_HIT,
SEQ_THROW_LOOP,
SEQ_PROJECTILE_SHOT,
SEQ_MAGIC_CHARGE_LOOP,
SEQ_EXPLOSION,
// Monsters
SEQ_MONSTER_CRY_SHORT,
SEQ_MONSTER_CRY_MEDIUM,
SEQ_MONSTER_CRY_LONG,
SEQ_MONSTER_DAMAGED,
SEQ_MONSTER_DEAD,
SEQ_MONSTER_ATTACK,
// Voice
SEQ_VOICE_SHORT,
SEQ_VOICE_MEDIUM,
SEQ_VOICE_LONG,
// Etc
SEQ_DOOR_OPEN,
SEQ_DOOR_CLOSE,
SEQ_AMBIENCE,
// Meta
SEQTYPE_COUNT,
SEQ_NOCAT = 0xFE, // For sound effects that doesn't fit into any category
SEQ_NOSHUFFLE = 0xFF, // For DUMMYs and YOBIs that are either blank or duplicates, and for system sound effects
} SeqType;
typedef struct {
/// Contains the amount of sound effects in each group, excluding SEQ_NOCAT and SEQ_NOSHUFFLE.
uint16_t rSeqMaxes[SEQTYPE_COUNT];
/// Contains the original list of SeqTypes.
/// Can be used to check which type a sound effect is.
SeqType rSeqTypesSFX[SFX_COUNT];
/// Contains all sound effects.
uint32_t rSFXOverrides_All[SFX_COUNT];
/// Contains all sound effects excluding SEQ_NOSHUFFLE.
uint32_t rSFXOverrides_AllTrimmed[SFX_COUNT_TRIMMED];
/// Contains all sound effects grouped into their SeqTypes.
/// The size of the second dimension should be at least the amount in the largest group.
uint32_t rSFXOverrides_Types[SEQTYPE_COUNT][100];
} SFXData;
extern const std::array<SeqType, SFX_COUNT> seqTypesSFX;
const SFXData& GetSFXData();
void InitSFXRandomizer();
void ShuffleSequences(bool shuffleCategorically);
} // namespace SFX

Some files were not shown because too many files have changed in this diff Show More