From e86f75bfc86fb6599d9d19bee64dc3ae9d3efad9 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Wed, 5 Feb 2025 21:14:17 +0100 Subject: [PATCH 01/11] Added the ability to connect to the server and download the item locations --- README.md | 9 + soh/CMakeLists.txt | 11 + .../Enhancements/randomizer/archipelago.cpp | 268 +++ soh/soh/Enhancements/randomizer/archipelago.h | 67 + .../randomizer/archipelago_mappings.h | 1781 +++++++++++++++++ .../randomizer/archipelago_settings_window.h | 36 + soh/soh/Enhancements/randomizer/context.cpp | 33 + soh/soh/Enhancements/randomizer/context.h | 6 + .../Enhancements/randomizer/fixed_string.hpp | 682 +++++++ soh/soh/Enhancements/randomizer/item_list.cpp | 3 + .../Enhancements/randomizer/randomizerTypes.h | 1 + .../Enhancements/randomizer/static_data.cpp | 31 + soh/soh/Enhancements/randomizer/static_data.h | 4 + soh/soh/OTRGlobals.cpp | 4 + soh/soh/OTRGlobals.h | 1 + soh/soh/SohGui.cpp | 4 + soh/soh/SohGui.hpp | 1 + soh/soh/SohMenuBar.cpp | 10 + .../ovl_file_choose/z_file_choose.c | 9 + 19 files changed, 2961 insertions(+) create mode 100644 soh/soh/Enhancements/randomizer/archipelago.cpp create mode 100644 soh/soh/Enhancements/randomizer/archipelago.h create mode 100644 soh/soh/Enhancements/randomizer/archipelago_mappings.h create mode 100644 soh/soh/Enhancements/randomizer/archipelago_settings_window.h create mode 100644 soh/soh/Enhancements/randomizer/fixed_string.hpp diff --git a/README.md b/README.md index e7f929bad..128af0a73 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,15 @@ ![Ship of Harkinian](docs/shiptitle.darkmode.png#gh-dark-mode-only) ![Ship of Harkinian](docs/shiptitle.lightmode.png#gh-light-mode-only) +## Fork Overview + +Currently playing around trying to see if we're able to hook the existing Archipelago Ocarina of time randomizer into Ship of Harkinian. +You can currently connect to the multiworld server, scout the items. +If you have no randomizer genereted (the `Randomizer` folder is empty) and press the `Link up` button, you'll be able to start a randomizer save file +with the items populated with the location from the server. + +Sending and recieving is not implemented yet, Multiworld items are currently just recovery hearts + ## Website Official Website: https://www.shipofharkinian.com/ diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 8218588e4..9169df2c2 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -96,6 +96,10 @@ if (NOT TARGET ZAPDLib) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD ${CMAKE_BINARY_DIR}/ZAPD) endif() +if (NOT TARGET APCpp) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../APCpp ${CMAKE_BINARY_DIR}/APCpp) +endif() + set(PROJECT_NAME soh) ################################################################################ @@ -350,6 +354,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE assets ${SDL2-NET-INCLUDE} ${BOOST-INCLUDE} ${CMAKE_CURRENT_SOURCE_DIR}/assets/ + ${CMAKE_CURRENT_SOURCE_DIR}/../APCpp . ) @@ -631,6 +636,9 @@ endif() add_dependencies(${PROJECT_NAME} libultraship ) +add_dependencies(${PROJECT_NAME} + APCpp +) if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") add_dependencies(${PROJECT_NAME} ZAPDLib @@ -643,6 +651,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") set(ADDITIONAL_LIBRARY_DEPENDENCIES "libultraship;" "ZAPDLib;" + "APCpp;" "glu32;" "SDL2::SDL2;" "SDL2::SDL2main;" @@ -657,6 +666,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") set(ADDITIONAL_LIBRARY_DEPENDENCIES "libultraship;" "ZAPDLib;" + "APCpp;" "glu32;" "SDL2::SDL2;" "SDL2::SDL2main;" @@ -695,6 +705,7 @@ else() set(ADDITIONAL_LIBRARY_DEPENDENCIES "libultraship;" "ZAPDLib;" + "APCpp" SDL2::SDL2 "$<$:SDL2_net::SDL2_net>" ${CMAKE_DL_LIBS} diff --git a/soh/soh/Enhancements/randomizer/archipelago.cpp b/soh/soh/Enhancements/randomizer/archipelago.cpp new file mode 100644 index 000000000..07d763fc4 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/archipelago.cpp @@ -0,0 +1,268 @@ +#include "archipelago.h" +#include "soh/UIWidgets.hpp" +#include "soh/util.h" + +#include +#include +#include +#include + +#include "fixed_string.hpp" + +//extern "C" { +// #include "include/z64item.h" +// #include "objects/gameplay_keep/gameplay_keep.h" +// extern SaveContext gSaveContext; +// extern PlayState* gPlayState; +//} + +//constexpr const char* requestedSlotData(int i) + +using namespace fixstr; //https://github.com/unterumarmung/fixed_string +template +struct CallbackWrapper { + static void SlotCallbackFunc(int id) { + ArchipelagoClient::getInstance().add_slot_data(key, id); + SPDLOG_TRACE("Recieved Slot data ({}, {})", key, id); + } +}; + +template +auto SubscribeToSlotData() { + AP_RegisterSlotDataIntCallback(std::string(key), CallbackWrapper::SlotCallbackFunc); +} + +ArchipelagoClient::ArchipelagoClient() { + namespace apc = AP_Client_consts; + CVarSetInteger("archipelago_connected", 0); + strncpy(server_address, CVarGetString(apc::SETTING_ADDRESS, apc::DEFAULT_SERVER_NAME), apc::MAX_ADDRESS_LENGTH); + strncpy(slot_name, CVarGetString(apc::SETTING_NAME, ""), apc::MAX_PLAYER_NAME_LENGHT); +} + +ArchipelagoClient& ArchipelagoClient::getInstance() { + static ArchipelagoClient Client; + return Client; +} + + +void ArchipelagoClient::add_slot_data(std::string_view key, int id) { + slot_data.insert(std::pair(key, id)); +} + +void registerSlotCallbacks() { + SubscribeToSlotData<"open_forest">(); + SubscribeToSlotData<"open_kakoriko">(); + SubscribeToSlotData<"open_door_of_time">(); + SubscribeToSlotData<"zora_fountain">(); + SubscribeToSlotData<"gerudo_fortress">(); + SubscribeToSlotData<"bridge">(); + SubscribeToSlotData<"bridge_stones">(); + SubscribeToSlotData<"bridge_medallions">(); + SubscribeToSlotData<"bridge_rewards">(); + SubscribeToSlotData<"bridge_tokens">(); + SubscribeToSlotData<"bridge_hearts">(); + SubscribeToSlotData<"shuffle_ganon_bosskey">(); + SubscribeToSlotData<"ganon_bosskey_medallions">(); + SubscribeToSlotData<"ganon_bosskey_stones">(); + SubscribeToSlotData<"ganon_bosskey_rewards">(); + SubscribeToSlotData<"ganon_bosskey_tokens">(); + SubscribeToSlotData<"ganon_bosskey_hearts">(); + SubscribeToSlotData<"trials">(); + SubscribeToSlotData<"triforce_hunt">(); + SubscribeToSlotData<"triforce_goal">(); + SubscribeToSlotData<"extra_triforce_percentage">(); + SubscribeToSlotData<"shopsanity">(); + SubscribeToSlotData<"shop_slots">(); + SubscribeToSlotData<"shopsanity_prices">(); + SubscribeToSlotData<"tokensanity">(); + SubscribeToSlotData<"dungeon_shortcuts">(); + SubscribeToSlotData<"mq_dungeons_mode">(); + SubscribeToSlotData<"mq_dungeons_count">(); + SubscribeToSlotData<"shuffle_interior_entrances">(); + SubscribeToSlotData<"shuffle_grotto_entrances">(); + SubscribeToSlotData<"shuffle_dungeon_entrances">(); + SubscribeToSlotData<"shuffle_overworld_entrances">(); + SubscribeToSlotData<"shuffle_bosses">(); + SubscribeToSlotData<"key_rings">(); + SubscribeToSlotData<"enhance_map_compass">(); + SubscribeToSlotData<"shuffle_mapcompass">(); + SubscribeToSlotData<"shuffle_smallkeys">(); + SubscribeToSlotData<"shuffle_hideoutkeys">(); + SubscribeToSlotData<"shuffle_bosskeys">(); + SubscribeToSlotData<"logic_rules">(); + SubscribeToSlotData<"logic_no_night_tokens_without_suns_song">(); + SubscribeToSlotData<"warp_songs">(); + SubscribeToSlotData<"shuffle_song_items">(); + SubscribeToSlotData<"shuffle_medigoron_carpet_salesman">(); + SubscribeToSlotData<"shuffle_frog_song_rupees">(); + SubscribeToSlotData<"shuffle_scrubs">(); + SubscribeToSlotData<"shuffle_child_trade">(); + SubscribeToSlotData<"shuffle_freestanding_items">(); + SubscribeToSlotData<"shuffle_pots">(); + SubscribeToSlotData<"shuffle_crates">(); + SubscribeToSlotData<"shuffle_cows">(); + SubscribeToSlotData<"shuffle_beehives">(); + SubscribeToSlotData<"shuffle_kokiri_sword">(); + SubscribeToSlotData<"shuffle_ocarinas">(); + SubscribeToSlotData<"shuffle_gerudo_card">(); + SubscribeToSlotData<"shuffle_beans">(); + SubscribeToSlotData<"starting_age">(); + SubscribeToSlotData<"bombchus_in_logic">(); + SubscribeToSlotData<"spawn_positions">(); + SubscribeToSlotData<"owl_drops">(); + SubscribeToSlotData<"no_epona_race">(); + SubscribeToSlotData<"skip_some_minigame_phases">(); + SubscribeToSlotData<"complete_mask_quest">(); + SubscribeToSlotData<"free_scarecrow">(); + SubscribeToSlotData<"plant_beans">(); + SubscribeToSlotData<"chicken_count">(); + SubscribeToSlotData<"big_poe_count">(); + SubscribeToSlotData<"fae_torch_count">(); + SubscribeToSlotData<"blue_fire_arrows">(); + SubscribeToSlotData<"damage_multiplier">(); + SubscribeToSlotData<"deadly_bonks">(); + SubscribeToSlotData<"starting_tod">(); + SubscribeToSlotData<"junk_ice_traps">(); + SubscribeToSlotData<"start_with_consumables">(); + SubscribeToSlotData<"adult_trade_start">(); +} + +bool ArchipelagoClient::start_client() { + switch(AP_GetConnectionStatus()) { + case AP_ConnectionStatus::ConnectionRefused: + SPDLOG_TRACE("refused"); + break; + case AP_ConnectionStatus::Authenticated: + SPDLOG_TRACE("Authenticated"); + break; + case AP_ConnectionStatus::Connected: + SPDLOG_TRACE("Connected"); + break; + case AP_ConnectionStatus::Disconnected: + SPDLOG_TRACE("Disconnected"); + break; + } + + if(AP_GetConnectionStatus() != AP_ConnectionStatus::Disconnected) { + SPDLOG_TRACE("AP already connected, shutting it down"); + AP_Shutdown(); + } + + AP_Init(server_address, "Ocarina of Time", slot_name, password); + //AP_SetClientConnectedCallback(&ArchipelagoClient::on_connected); // currently broken :( + //AP_SetClientCouldntConnectCallback(5, &ArchipelagoClient::on_couldntConnect); + AP_SetItemClearCallback(&ArchipelagoClient::on_clear_items); + AP_SetItemRecvCallback(&ArchipelagoClient::on_item_recieved); + AP_SetLocationCheckedCallback(&ArchipelagoClient::on_location_checked); + AP_SetLocationInfoCallback(&ArchipelagoClient::on_location_scouted); + registerSlotCallbacks(); + AP_Start(); + AP_ConnectionStatus conn_status = AP_GetConnectionStatus(); + + //switch(conn_status) { + // case AP_ConnectionStatus::Authenticated: + // SPDLOG_TRACE("Authenticated"); + // break; + // case AP_ConnectionStatus::Connected: + // SPDLOG_TRACE("Connected"); + // break; + // case AP_ConnectionStatus::Disconnected: + // SPDLOG_TRACE("Disconnected"); + // break; + //} + save_data(); + return conn_status == AP_ConnectionStatus::Connected; +} + +void ArchipelagoClient::start_location_scouts() { + AP_SendLocationScouts(AP_GetAllLocations(), false); +} + +void ArchipelagoClient::save_data() { + CVarSetString(AP_Client_consts::SETTING_ADDRESS, server_address); + CVarSetString(AP_Client_consts::SETTING_NAME, slot_name); +} + +void ArchipelagoClient::on_connected() { + // todo implement me + SPDLOG_TRACE("AP Connected!!"); +} +void ArchipelagoClient::on_couldntConnect(AP_ConnectionStatus connection_status) { + // todo implement me +} + + +void ArchipelagoClient::on_clear_items() { + // todo implement me +} + +void ArchipelagoClient::on_item_recieved(int64_t recieved_item_id, bool notify_player) { + // todo implement me +} + +void ArchipelagoClient::on_location_checked(int64_t location_id) { + // todo implement me +} + +void ArchipelagoClient::on_location_scouted(std::vector network_items) { + for(const AP_NetworkItem& item: network_items) { + SPDLOG_TRACE("Location scouted: {} for {} in location {}", item.itemName, item.playerName, item.locationName); + } + getInstance().scouted_items = network_items; +} + +char* ArchipelagoClient::get_server_address_buff() { + return server_address; +} +char* ArchipelagoClient::get_slot_name_buff() { + return slot_name; +} +char* ArchipelagoClient::get_password_buff() { + return password; +} + +const std::map& ArchipelagoClient::get_slot_data() { + return slot_data; +} + +const std::vector& ArchipelagoClient::get_scouted_items() { + return scouted_items; +} + + +void ArchipelagoWindow::ArchipelagoDrawConnectPage() { + ArchipelagoClient& AP_client = ArchipelagoClient::getInstance(); + ImGui::SeparatorText("Connection info"); + ImGui::InputText("Server Address", AP_client.get_server_address_buff(), AP_Client_consts::MAX_ADDRESS_LENGTH); + ImGui::InputText("Slot Name", AP_client.get_slot_name_buff(), AP_Client_consts::MAX_PLAYER_NAME_LENGHT); + ImGui::InputText("Password (leave blank for no password)", AP_client.get_password_buff(), AP_Client_consts::MAX_PASSWORD_LENGTH, ImGuiInputTextFlags_Password); + + char connected_text[25] = "Disconnected"; + if(ImGui::Button("Connect")) { + bool success = AP_client.start_client(); + if(success) { + strncpy(connected_text, "Connected!", 25); + SPDLOG_TRACE("Connected!!"); + } + else { + strncpy(connected_text, "Connection failed!", 25); + SPDLOG_TRACE("Connection failed :("); + } + } + + ImGui::SameLine(); + ImGui::Text(connected_text); + if(ImGui::Button("scout")) { + AP_client.start_location_scouts(); + } + ImGui::SameLine(); + if(ImGui::Button("link up")) { + CVarSetInteger("archipelago_connected", 1); + } + +}; + +void ArchipelagoWindow::DrawElement() { + ArchipelagoDrawConnectPage(); + UIWidgets::PaddedSeparator(); +}; \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/archipelago.h b/soh/soh/Enhancements/randomizer/archipelago.h new file mode 100644 index 000000000..cbaad2348 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/archipelago.h @@ -0,0 +1,67 @@ +#include "archipelago_settings_window.h" +#include "../../../../APCpp/Archipelago.h" + +#include "fixed_string.hpp" + +namespace AP_Client_consts { + static constexpr int MAX_ADDRESS_LENGTH = 64; + static constexpr int MAX_PLAYER_NAME_LENGHT = 17; + static constexpr int MAX_PASSWORD_LENGTH = 32; + static constexpr char const* DEFAULT_SERVER_NAME = "archipelago.gg:"; + + static constexpr char const* SETTING_ADDRESS = "AP_server_address"; + static constexpr char const* SETTING_NAME = "AP_slot_name"; +}; + +class ArchipelagoClient { + public: + static ArchipelagoClient& getInstance(); + + bool start_client(); + bool stop_client(); + + void start_location_scouts(); + + // getters + char* get_server_address_buff(); + char* get_slot_name_buff(); + char* get_password_buff(); + const std::map& get_slot_data(); + const std::vector& get_scouted_items(); + + void add_slot_data(std::string_view key, int id); + + protected: + ArchipelagoClient(); + + private: + ArchipelagoClient(ArchipelagoClient &) = delete; + void operator=(const ArchipelagoClient &) = delete; + static std::shared_ptr instance; + static bool initialized; + + char server_address[AP_Client_consts::MAX_ADDRESS_LENGTH]; + char slot_name[AP_Client_consts::MAX_PLAYER_NAME_LENGHT]; + char password[AP_Client_consts::MAX_PLAYER_NAME_LENGHT]; + + std::map slot_data; + std::set locations; + std::vector scouted_items; + + //void registerSlotCallbacks(); + + void save_data(); + + // callback functions + static void on_connected(); + static void on_couldntConnect(AP_ConnectionStatus connection_status); + static void on_clear_items(); + static void on_item_recieved(int64_t recieved_item_id, bool notify_player); + static void on_location_checked(int64_t location_id); + static void on_deathlink_recieved() { }; // TODO: implement me + static void on_location_scouted(std::vector network_items); + + // callbacks + +}; + diff --git a/soh/soh/Enhancements/randomizer/archipelago_mappings.h b/soh/soh/Enhancements/randomizer/archipelago_mappings.h new file mode 100644 index 000000000..cb0c84484 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/archipelago_mappings.h @@ -0,0 +1,1781 @@ +#pragma once + +#include +#include + +#include "randomizerTypes.h" + +constexpr std::pair ap_item_mapping_pairs[] = { + { "Bombs (5)", RG_BOMBS_5 }, + { "Deku Nuts (5)", RG_DEKU_NUTS_5 }, + { "Bombchus (10)", RG_BOMBCHU_10 }, + { "Boomerang", RG_BOOMERANG }, + { "Deku Stick (1)", RG_DEKU_STICK_1 }, + { "Lens of Truth", RG_LENS_OF_TRUTH }, + { "Megaton Hammer", RG_MEGATON_HAMMER }, + { "Cojiro", RG_COJIRO }, + { "Bottle", RG_EMPTY_BOTTLE }, + { "Bottle with Milk", RG_BOTTLE_WITH_MILK }, + { "Rutos Letter", RG_RUTOS_LETTER }, + { "Magic Bean", RG_MAGIC_BEAN }, + { "Pocket Egg", RG_POCKET_EGG }, + { "Pocket Cucco", RG_COJIRO }, /* SoH doesn't have pocket cucco as loose item in its RandomizerGet table, skip chicken step for now */ + { "Odd Mushroom", RG_ODD_MUSHROOM }, + { "Odd Potion", RG_ODD_POTION }, + { "Poachers Saw", RG_POACHERS_SAW }, + { "Broken Sword", RG_BROKEN_SWORD }, + { "Prescription", RG_PRESCRIPTION }, + { "Eyeball Frog", RG_EYEBALL_FROG }, + { "Eyedrops", RG_EYEDROPS }, + { "Claim Check", RG_CLAIM_CHECK }, + { "Kokiri Sword", RG_KOKIRI_SWORD }, + { "Giants Knife", RG_GIANTS_KNIFE }, + { "Deku Shield", RG_DEKU_SHIELD }, + { "Hylian Shield", RG_HYLIAN_SHIELD }, + { "Mirror Shield", RG_MIRROR_SHIELD }, + { "Goron Tunic", RG_GORON_TUNIC }, + { "Zora Tunic", RG_ZORA_TUNIC }, + { "Iron Boots", RG_IRON_BOOTS }, + { "Hover Boots", RG_HOVER_BOOTS }, + { "Stone of Agony", RG_STONE_OF_AGONY }, + { "Gerudo Membership Card", RG_GERUDO_MEMBERSHIP_CARD }, + { "Heart Container", RG_HEART_CONTAINER }, + { "Piece of Heart", RG_PIECE_OF_HEART }, + { "Weird Egg", RG_WEIRD_EGG }, + { "Recovery Heart", RG_RECOVERY_HEART }, + { "Arrows (5)", RG_ARROWS_5 }, + { "Arrows (10)", RG_ARROWS_10 }, + { "Arrows (30)", RG_ARROWS_30 }, + { "Rupee (1)", RG_GREEN_RUPEE }, + { "Rupees (5)", RG_BLUE_RUPEE }, + { "Rupees (20)", RG_RED_RUPEE }, + { "Rupees (50)", RG_PURPLE_RUPEE }, + { "Rupees (200)", RG_HUGE_RUPEE }, + { "Biggoron Sword", RG_BIGGORON_SWORD }, + { "Fire Arrows", RG_FIRE_ARROWS }, + { "Ice Arrows", RG_ICE_ARROWS }, + { "Light Arrows", RG_LIGHT_ARROWS }, + { "Gold Skulltula Token", RG_GOLD_SKULLTULA_TOKEN }, + { "Dins Fire", RG_DINS_FIRE }, + { "Nayrus Love", RG_NAYRUS_LOVE }, + { "Farores Wind", RG_FARORES_WIND }, + { "Deku Nuts (10)", RG_DEKU_NUTS_10 }, + { "Bombs (10)", RG_BOMBS_10 }, + { "Bombs (20)", RG_BOMBS_20 }, + { "Deku Seeds (30)", RG_DEKU_SEEDS_30}, + { "Bombchus (5)", RG_BOMBCHU_5 }, + { "Bombchus (20)", RG_BOMBCHU_20 }, + { "Rupee (Treasure Chest Game)", RG_TREASURE_GAME_GREEN_RUPEE }, + { "Piece of Heart (Treasure Chest Game)", RG_TREASURE_GAME_HEART }, + { "Ice Trap", RG_ICE_TRAP }, + { "Progressive Hookshot", RG_PROGRESSIVE_HOOKSHOT }, + { "Progressive Strength Upgrade", RG_PROGRESSIVE_STRENGTH }, + { "Bomb Bag", RG_BOMB_BAG }, + { "Bow", RG_FAIRY_BOW}, + { "Slingshot", RG_FAIRY_SLINGSHOT}, + { "Progressive Wallet", RG_PROGRESSIVE_WALLET }, + { "Progressive Scale", RG_PROGRESSIVE_SCALE}, + { "Deku Nut Capacity", RG_PROGRESSIVE_NUT_UPGRADE }, + { "Deku Stick Capacity", RG_PROGRESSIVE_STICK_UPGRADE }, + { "Bombchus", RG_BOMBCHU_20 }, /* used when bombchus are included in logic */ + { "Magic Meter", RG_PROGRESSIVE_MAGIC_METER }, + { "Ocarina", RG_PROGRESSIVE_OCARINA }, + { "Bottle with Red Potion", RG_BOTTLE_WITH_RED_POTION }, + { "Bottle with Green Potion", RG_BOTTLE_WITH_GREEN_POTION }, + { "Bottle with Blue Potion", RG_BOTTLE_WITH_BLUE_POTION }, + { "Bottle with Fairy", RG_BOTTLE_WITH_FAIRY }, + { "Bottle with Fish", RG_BOTTLE_WITH_FISH}, + { "Bottle with Blue Fire", RG_BOTTLE_WITH_BLUE_FIRE }, + { "Bottle with Bugs", RG_BOTTLE_WITH_BUGS }, + { "Bottle with Big Poe", RG_BOTTLE_WITH_BIG_POE }, + { "Bottle with Poe", RG_BOTTLE_WITH_POE }, + { "Boss Key (Forest Temple)", RG_FOREST_TEMPLE_BOSS_KEY }, + { "Boss Key (Fire Temple)", RG_FIRE_TEMPLE_BOSS_KEY }, + { "Boss Key (Water Temple)", RG_WATER_TEMPLE_BOSS_KEY }, + { "Boss Key (Spirit Temple)", RG_SPIRIT_TEMPLE_BOSS_KEY }, + { "Boss Key (Shadow Temple)", RG_SHADOW_TEMPLE_BOSS_KEY }, + { "Boss Key (Ganons Castle)", RG_GANONS_CASTLE_BOSS_KEY }, + { "Compass (Deku Tree)", RG_DEKU_TREE_COMPASS }, + { "Compass (Dodongos Cavern)", RG_DODONGOS_CAVERN_COMPASS }, + { "Compass (Jabu Jabus Belly)", RG_JABU_JABUS_BELLY_COMPASS }, + { "Compass (Forest Temple)", RG_FOREST_TEMPLE_COMPASS }, + { "Compass (Fire Temple)", RG_FIRE_TEMPLE_COMPASS }, + { "Compass (Water Temple)", RG_WATER_TEMPLE_COMPASS }, + { "Compass (Spirit Temple)", RG_SPIRIT_TEMPLE_COMPASS }, + { "Compass (Shadow Temple)", RG_SHADOW_TEMPLE_COMPASS }, + { "Compass (Bottom of the Well)", RG_BOTTOM_OF_THE_WELL_COMPASS }, + { "Compass (Ice Cavern)", RG_ICE_CAVERN_COMPASS }, + { "Map (Deku Tree)", RG_DEKU_TREE_MAP }, + { "Map (Dodongos Cavern)", RG_DODONGOS_CAVERN_MAP }, + { "Map (Jabu Jabus Belly)", RG_JABU_JABUS_BELLY_MAP }, + { "Map (Forest Temple)", RG_FOREST_TEMPLE_MAP }, + { "Map (Fire Temple)", RG_FIRE_TEMPLE_MAP }, + { "Map (Water Temple)", RG_WATER_TEMPLE_MAP }, + { "Map (Spirit Temple)", RG_SPIRIT_TEMPLE_MAP }, + { "Map (Shadow Temple)", RG_SHADOW_TEMPLE_MAP }, + { "Map (Bottom of the Well)", RG_BOTTOM_OF_THE_WELL_MAP }, + { "Map (Ice Cavern)", RG_ICE_CAVERN_MAP }, + { "Small Key (Forest Temple)", RG_FOREST_TEMPLE_SMALL_KEY }, + { "Small Key (Fire Temple)", RG_FIRE_TEMPLE_SMALL_KEY }, + { "Small Key (Water Temple)", RG_WATER_TEMPLE_SMALL_KEY }, + { "Small Key (Spirit Temple)", RG_SPIRIT_TEMPLE_SMALL_KEY }, + { "Small Key (Shadow Temple)", RG_SHADOW_TEMPLE_SMALL_KEY }, + { "Small Key (Bottom of the Well)", RG_BOTTOM_OF_THE_WELL_SMALL_KEY }, + { "Small Key (Gerudo Training Ground)", RG_GERUDO_TRAINING_GROUND_SMALL_KEY }, + { "Small Key (Thieves Hideout)", RG_GERUDO_FORTRESS_SMALL_KEY }, + { "Small Key (Ganons Castle)", RG_GANONS_CASTLE_SMALL_KEY }, + { "Double Defense", RG_DOUBLE_DEFENSE }, + { "Magic Bean Pack", RG_MAGIC_BEAN_PACK }, + { "Triforce Piece", RG_TRIFORCE_PIECE }, + { "Zeldas Letter", RG_ZELDAS_LETTER }, + { "Minuet of Forest", RG_MINUET_OF_FOREST }, + { "Bolero of Fire", RG_BOLERO_OF_FIRE }, + { "Serenade of Water", RG_SERENADE_OF_WATER }, + { "Requiem of Spirit", RG_REQUIEM_OF_SPIRIT }, + { "Nocturne of Shadow", RG_NOCTURNE_OF_SHADOW }, + { "Prelude of Light", RG_PRELUDE_OF_LIGHT }, + { "Zeldas Lullaby", RG_ZELDAS_LULLABY }, + { "Eponas Song", RG_EPONAS_SONG }, + { "Sarias Song", RG_SARIAS_SONG }, + { "Suns Song", RG_SUNS_SONG }, + { "Song of Time", RG_SONG_OF_STORMS }, + { "Song of Storms", RG_SONG_OF_STORMS}, + { "Small Key Ring (Forest Temple)", RG_FOREST_TEMPLE_KEY_RING }, + { "Small Key Ring (Fire Temple)", RG_FOREST_TEMPLE_KEY_RING }, + { "Small Key Ring (Water Temple)", RG_WATER_TEMPLE_KEY_RING }, + { "Small Key Ring (Spirit Temple)", RG_SPIRIT_TEMPLE_KEY_RING }, + { "Small Key Ring (Shadow Temple)", RG_SHADOW_TEMPLE_KEY_RING }, + { "Small Key Ring (Bottom of the Well)", RG_BOTTOM_OF_THE_WELL_KEY_RING }, + { "Small Key Ring (Gerudo Training Ground)", RG_GERUDO_TRAINING_GROUND_KEY_RING }, + { "Small Key Ring (Thieves Hideout)", RG_GERUDO_FORTRESS_KEY_RING }, + { "Small Key Ring (Ganons Castle)", RG_GANONS_CASTLE_KEY_RING } + +} ; + +// todo rupies, pots, hearts random items i may have missed, all containing RC_UNKNOWN_CHECK as their current enum; + +constexpr std::pair ap_check_mapping_pairs[] = { + { "Song from Impa" , RC_SONG_FROM_IMPA }, + { "Song from Malon" , RC_SONG_FROM_MALON }, + { "Song from Saria" , RC_SONG_FROM_SARIA }, + { "Song from Royal Familys Tomb" , RC_SONG_FROM_ROYAL_FAMILYS_TOMB }, + { "Song from Ocarina of Time" , RC_SONG_FROM_OCARINA_OF_TIME }, + { "Song from Windmill" , RC_SONG_FROM_WINDMILL }, + { "Sheik in Forest" , RC_SHEIK_IN_FOREST }, + { "Sheik in Crater" , RC_SHEIK_IN_CRATER }, + { "Sheik in Ice Cavern" , RC_SHEIK_IN_ICE_CAVERN }, + { "Sheik at Colossus" , RC_SHEIK_AT_COLOSSUS }, + { "Sheik in Kakariko" , RC_SHEIK_IN_KAKARIKO }, + { "Sheik at Temple" , RC_SHEIK_AT_TEMPLE }, + { "KF Midos Top Left Chest" , RC_KF_MIDOS_TOP_LEFT_CHEST }, + { "KF Midos Top Right Chest" , RC_KF_MIDOS_TOP_RIGHT_CHEST }, + { "KF Midos Bottom Left Chest" , RC_KF_MIDOS_BOTTOM_LEFT_CHEST }, + { "KF Midos Bottom Right Chest" , RC_KF_MIDOS_BOTTOM_RIGHT_CHEST }, + { "KF Kokiri Sword Chest" , RC_KF_KOKIRI_SWORD_CHEST }, + { "KF Storms Grotto Chest" , RC_KF_STORMS_GROTTO_CHEST }, + { "KF Links House Cow" , RC_KF_LINKS_HOUSE_COW }, + { "KF GS Know It All House" , RC_KF_GS_KNOW_IT_ALL_HOUSE }, + { "KF GS Bean Patch" , RC_KF_GS_BEAN_PATCH }, + { "KF GS House of Twins" , RC_KF_GS_HOUSE_OF_TWINS }, + { "KF Shop Item 1" , RC_KF_SHOP_ITEM_1 }, + { "KF Shop Item 2" , RC_KF_SHOP_ITEM_2 }, + { "KF Shop Item 3" , RC_KF_SHOP_ITEM_3 }, + { "KF Shop Item 4" , RC_KF_SHOP_ITEM_4 }, + { "KF Shop Item 5" , RC_KF_SHOP_ITEM_5 }, + { "KF Shop Item 6" , RC_KF_SHOP_ITEM_6 }, + { "KF Shop Item 7" , RC_KF_SHOP_ITEM_7 }, + { "KF Shop Item 8" , RC_KF_SHOP_ITEM_8 }, + { "LW Gift from Saria" , RC_LW_GIFT_FROM_SARIA }, + { "LW Ocarina Memory Game" , RC_LW_OCARINA_MEMORY_GAME }, + { "LW Target in Woods" , RC_LW_TARGET_IN_WOODS }, + { "LW Near Shortcuts Grotto Chest" , RC_LW_NEAR_SHORTCUTS_GROTTO_CHEST }, + { "Deku Theater Skull Mask" , RC_DEKU_THEATER_SKULL_MASK }, + { "Deku Theater Mask of Truth" , RC_DEKU_THEATER_MASK_OF_TRUTH }, + { "LW Skull Kid" , RC_LW_SKULL_KID }, + { "LW Deku Scrub Near Bridge" , RC_LW_DEKU_SCRUB_NEAR_BRIDGE }, + { "LW Deku Scrub Near Deku Theater Left" , RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT }, + { "LW Deku Scrub Near Deku Theater Right" , RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT }, + { "LW Deku Scrub Grotto Front" , RC_LW_DEKU_SCRUB_GROTTO_FRONT }, + { "LW Deku Scrub Grotto Rear" , RC_LW_DEKU_SCRUB_GROTTO_REAR }, + { "LW GS Bean Patch Near Bridge" , RC_LW_GS_BEAN_PATCH_NEAR_BRIDGE }, + { "LW GS Bean Patch Near Theater" , RC_LW_GS_BEAN_PATCH_NEAR_THEATER }, + { "LW GS Above Theater" , RC_LW_GS_ABOVE_THEATER }, + { "SFM Wolfos Grotto Chest" , RC_SFM_WOLFOS_GROTTO_CHEST }, + { "SFM Deku Scrub Grotto Front" , RC_SFM_DEKU_SCRUB_GROTTO_FRONT }, + { "SFM Deku Scrub Grotto Rear" , RC_SFM_DEKU_SCRUB_GROTTO_REAR }, + { "SFM GS" , RC_SFM_GS }, + { "HF Ocarina of Time Item" , RC_HF_OCARINA_OF_TIME_ITEM }, + { "HF Near Market Grotto Chest" , RC_HF_NEAR_MARKET_GROTTO_CHEST }, + { "HF Tektite Grotto Freestanding PoH" , RC_HF_TEKTITE_GROTTO_FREESTANDING_POH }, + { "HF Southeast Grotto Chest" , RC_HF_SOUTHEAST_GROTTO_CHEST }, + { "HF Open Grotto Chest" , RC_HF_OPEN_GROTTO_CHEST }, + { "HF Deku Scrub Grotto" , RC_HF_DEKU_SCRUB_GROTTO }, + { "HF Cow Grotto Cow" , RC_HF_COW_GROTTO_COW }, + { "HF GS Cow Grotto" , RC_HF_GS_COW_GROTTO }, + { "HF GS Near Kak Grotto" , RC_HF_GS_NEAR_KAK_GROTTO }, + { "Market Shooting Gallery Reward" , RC_MARKET_SHOOTING_GALLERY_REWARD }, + { "Market Bombchu Bowling First Prize" , RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE }, + { "Market Bombchu Bowling Second Prize" , RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE }, + { "Market Lost Dog" , RC_MARKET_LOST_DOG }, + { "Market Treasure Chest Game Reward" , RC_MARKET_TREASURE_CHEST_GAME_REWARD }, + { "Market 10 Big Poes" , RC_MARKET_10_BIG_POES }, + { "Market GS Guard House" , RC_MARKET_GS_GUARD_HOUSE }, + { "Market Bazaar Item 1" , RC_MARKET_BAZAAR_ITEM_1 }, + { "Market Bazaar Item 2" , RC_MARKET_BAZAAR_ITEM_2 }, + { "Market Bazaar Item 3" , RC_MARKET_BAZAAR_ITEM_3 }, + { "Market Bazaar Item 4" , RC_MARKET_BAZAAR_ITEM_4 }, + { "Market Bazaar Item 5" , RC_MARKET_BAZAAR_ITEM_5 }, + { "Market Bazaar Item 6" , RC_MARKET_BAZAAR_ITEM_6 }, + { "Market Bazaar Item 7" , RC_MARKET_BAZAAR_ITEM_7 }, + { "Market Bazaar Item 8" , RC_MARKET_BAZAAR_ITEM_8 }, + { "Market Potion Shop Item 1" , RC_MARKET_POTION_SHOP_ITEM_1 }, + { "Market Potion Shop Item 2" , RC_MARKET_POTION_SHOP_ITEM_2 }, + { "Market Potion Shop Item 3" , RC_MARKET_POTION_SHOP_ITEM_3 }, + { "Market Potion Shop Item 4" , RC_MARKET_POTION_SHOP_ITEM_4 }, + { "Market Potion Shop Item 5" , RC_MARKET_POTION_SHOP_ITEM_5 }, + { "Market Potion Shop Item 6" , RC_MARKET_POTION_SHOP_ITEM_6 }, + { "Market Potion Shop Item 7" , RC_MARKET_POTION_SHOP_ITEM_7 }, + { "Market Potion Shop Item 8" , RC_MARKET_POTION_SHOP_ITEM_8 }, + { "Market Bombchu Shop Item 1" , RC_MARKET_BOMBCHU_SHOP_ITEM_1 }, + { "Market Bombchu Shop Item 2" , RC_MARKET_BOMBCHU_SHOP_ITEM_2 }, + { "Market Bombchu Shop Item 3" , RC_MARKET_BOMBCHU_SHOP_ITEM_3 }, + { "Market Bombchu Shop Item 4" , RC_MARKET_BOMBCHU_SHOP_ITEM_4 }, + { "Market Bombchu Shop Item 5" , RC_MARKET_BOMBCHU_SHOP_ITEM_5 }, + { "Market Bombchu Shop Item 6" , RC_MARKET_BOMBCHU_SHOP_ITEM_6 }, + { "Market Bombchu Shop Item 7" , RC_MARKET_BOMBCHU_SHOP_ITEM_7 }, + { "Market Bombchu Shop Item 8" , RC_MARKET_BOMBCHU_SHOP_ITEM_8 }, + { "ToT Light Arrows Cutscene" , RC_TOT_LIGHT_ARROWS_CUTSCENE }, + { "HC Malon Egg" , RC_HC_MALON_EGG }, + { "HC Zeldas Letter" , RC_HC_ZELDAS_LETTER }, + { "HC Great Fairy Reward" , RC_HC_GREAT_FAIRY_REWARD }, + { "HC GS Tree" , RC_HC_GS_TREE }, + { "HC GS Storms Grotto" , RC_HC_GS_STORMS_GROTTO }, + { "LLR Talons Chickens" , RC_LLR_TALONS_CHICKENS }, + { "LLR Freestanding PoH" , RC_LLR_FREESTANDING_POH }, + { "LLR Deku Scrub Grotto Left" , RC_LLR_DEKU_SCRUB_GROTTO_LEFT }, + { "LLR Deku Scrub Grotto Center" , RC_LLR_DEKU_SCRUB_GROTTO_CENTER }, + { "LLR Deku Scrub Grotto Right" , RC_LLR_DEKU_SCRUB_GROTTO_RIGHT }, + { "LLR Stables Left Cow" , RC_LLR_STABLES_LEFT_COW }, + { "LLR Stables Right Cow" , RC_LLR_STABLES_RIGHT_COW }, + { "LLR Tower Left Cow" , RC_LLR_TOWER_LEFT_COW }, + { "LLR Tower Right Cow" , RC_LLR_TOWER_RIGHT_COW }, + { "LLR GS House Window" , RC_LLR_GS_HOUSE_WINDOW }, + { "LLR GS Tree" , RC_LLR_GS_TREE }, + { "LLR GS Rain Shed" , RC_LLR_GS_RAIN_SHED }, + { "LLR GS Back Wall" , RC_LLR_GS_BACK_WALL }, + { "Kak Anju as Child" , RC_KAK_ANJU_AS_CHILD }, + { "Kak Anju as Adult" , RC_KAK_ANJU_AS_ADULT }, + { "Kak Impas House Freestanding PoH" , RC_KAK_IMPAS_HOUSE_FREESTANDING_POH }, + { "Kak Windmill Freestanding PoH" , RC_KAK_WINDMILL_FREESTANDING_POH }, + { "Kak Man on Roof" , RC_KAK_MAN_ON_ROOF }, + { "Kak Open Grotto Chest" , RC_KAK_OPEN_GROTTO_CHEST }, + { "Kak Redead Grotto Chest" , RC_KAK_REDEAD_GROTTO_CHEST }, + { "Kak Shooting Gallery Reward" , RC_KAK_SHOOTING_GALLERY_REWARD }, + { "Kak 10 Gold Skulltula Reward" , RC_KAK_10_GOLD_SKULLTULA_REWARD }, + { "Kak 20 Gold Skulltula Reward" , RC_KAK_20_GOLD_SKULLTULA_REWARD }, + { "Kak 30 Gold Skulltula Reward" , RC_KAK_30_GOLD_SKULLTULA_REWARD }, + { "Kak 40 Gold Skulltula Reward" , RC_KAK_40_GOLD_SKULLTULA_REWARD }, + { "Kak 50 Gold Skulltula Reward" , RC_KAK_50_GOLD_SKULLTULA_REWARD }, + { "Kak Impas House Cow" , RC_KAK_IMPAS_HOUSE_COW }, + { "Kak GS Tree" , RC_KAK_GS_TREE }, + { "Kak GS Near Gate Guard" , RC_KAK_GS_GUARDS_HOUSE }, + { "Kak GS Watchtower" , RC_KAK_GS_WATCHTOWER }, + { "Kak GS Skulltula House" , RC_KAK_GS_SKULLTULA_HOUSE }, + { "Kak GS House Under Construction" , RC_KAK_GS_HOUSE_UNDER_CONSTRUCTION }, + { "Kak GS Above Impas House" , RC_KAK_GS_ABOVE_IMPAS_HOUSE }, + { "Kak Bazaar Item 1" , RC_KAK_BAZAAR_ITEM_1 }, + { "Kak Bazaar Item 2" , RC_KAK_BAZAAR_ITEM_2 }, + { "Kak Bazaar Item 3" , RC_KAK_BAZAAR_ITEM_3 }, + { "Kak Bazaar Item 4" , RC_KAK_BAZAAR_ITEM_4 }, + { "Kak Bazaar Item 5" , RC_KAK_BAZAAR_ITEM_5 }, + { "Kak Bazaar Item 6" , RC_KAK_BAZAAR_ITEM_6 }, + { "Kak Bazaar Item 7" , RC_KAK_BAZAAR_ITEM_7 }, + { "Kak Bazaar Item 8" , RC_KAK_BAZAAR_ITEM_8 }, + { "Kak Potion Shop Item 1" , RC_KAK_POTION_SHOP_ITEM_1 }, + { "Kak Potion Shop Item 2" , RC_KAK_POTION_SHOP_ITEM_2 }, + { "Kak Potion Shop Item 3" , RC_KAK_POTION_SHOP_ITEM_3 }, + { "Kak Potion Shop Item 4" , RC_KAK_POTION_SHOP_ITEM_4 }, + { "Kak Potion Shop Item 5" , RC_KAK_POTION_SHOP_ITEM_5 }, + { "Kak Potion Shop Item 6" , RC_KAK_POTION_SHOP_ITEM_6 }, + { "Kak Potion Shop Item 7" , RC_KAK_POTION_SHOP_ITEM_7 }, + { "Kak Potion Shop Item 8" , RC_KAK_POTION_SHOP_ITEM_8 }, + { "Graveyard Shield Grave Chest" , RC_GRAVEYARD_SHIELD_GRAVE_CHEST }, + { "Graveyard Heart Piece Grave Chest" , RC_GRAVEYARD_HEART_PIECE_GRAVE_CHEST }, + { "Graveyard Royal Familys Tomb Chest" , RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_CHEST }, + { "Graveyard Freestanding PoH" , RC_GRAVEYARD_FREESTANDING_POH }, + { "Graveyard Dampe Gravedigging Tour" , RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR }, + { "Graveyard Dampe Race Hookshot Chest" , RC_GRAVEYARD_HOOKSHOT_CHEST }, + { "Graveyard Dampe Race Freestanding PoH" , RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH }, + { "Graveyard GS Bean Patch" , RC_GRAVEYARD_GS_BEAN_PATCH }, + { "Graveyard GS Wall" , RC_GRAVEYARD_GS_WALL }, + { "DMT Freestanding PoH" , RC_DMT_FREESTANDING_POH }, + { "DMT Chest" , RC_DMT_CHEST }, + { "DMT Storms Grotto Chest" , RC_DMT_STORMS_GROTTO_CHEST }, + { "DMT Great Fairy Reward" , RC_DMT_GREAT_FAIRY_REWARD }, + { "DMT Biggoron" , RC_DMT_TRADE_CLAIM_CHECK }, // semi sure + { "DMT Cow Grotto Cow" , RC_DMT_COW_GROTTO_COW }, + { "DMT GS Near Kak" , RC_DMT_GS_NEAR_KAK }, + { "DMT GS Bean Patch" , RC_DMT_GS_BEAN_PATCH }, + { "DMT GS Above Dodongos Cavern" , RC_DMT_GS_ABOVE_DODONGOS_CAVERN }, + { "DMT GS Falling Rocks Path" , RC_DMT_GS_FALLING_ROCKS_PATH }, + { "GC Darunias Joy" , RC_GC_DARUNIAS_JOY }, + { "GC Pot Freestanding PoH" , RC_GC_POT_FREESTANDING_POH }, + { "GC Rolling Goron as Child" , RC_GC_ROLLING_GORON_AS_CHILD }, + { "GC Rolling Goron as Adult" , RC_GC_ROLLING_GORON_AS_ADULT }, + { "GC Medigoron" , RC_GC_MEDIGORON }, + { "GC Maze Left Chest" , RC_GC_MAZE_LEFT_CHEST }, + { "GC Maze Right Chest" , RC_GC_MAZE_RIGHT_CHEST }, + { "GC Maze Center Chest" , RC_GC_MAZE_CENTER_CHEST }, + { "GC Deku Scrub Grotto Left" , RC_GC_DEKU_SCRUB_GROTTO_LEFT }, + { "GC Deku Scrub Grotto Center" , RC_GC_DEKU_SCRUB_GROTTO_CENTER }, + { "GC Deku Scrub Grotto Right" , RC_GC_DEKU_SCRUB_GROTTO_RIGHT }, + { "GC GS Center Platform" , RC_GC_GS_CENTER_PLATFORM }, + { "GC GS Boulder Maze" , RC_GC_GS_BOULDER_MAZE }, + { "GC Shop Item 1" , RC_GC_SHOP_ITEM_1 }, + { "GC Shop Item 2" , RC_GC_SHOP_ITEM_2 }, + { "GC Shop Item 3" , RC_GC_SHOP_ITEM_3 }, + { "GC Shop Item 4" , RC_GC_SHOP_ITEM_4 }, + { "GC Shop Item 5" , RC_GC_SHOP_ITEM_5 }, + { "GC Shop Item 6" , RC_GC_SHOP_ITEM_6 }, + { "GC Shop Item 7" , RC_GC_SHOP_ITEM_7 }, + { "GC Shop Item 8" , RC_GC_SHOP_ITEM_8 }, + { "DMC Volcano Freestanding PoH" , RC_DMC_VOLCANO_FREESTANDING_POH }, + { "DMC Wall Freestanding PoH" , RC_DMC_WALL_FREESTANDING_POH }, + { "DMC Upper Grotto Chest" , RC_DMC_UPPER_GROTTO_CHEST }, + { "DMC Great Fairy Reward" , RC_DMC_GREAT_FAIRY_REWARD }, + { "DMC Deku Scrub" , RC_DMC_DEKU_SCRUB }, + { "DMC Deku Scrub Grotto Left" , RC_DMC_DEKU_SCRUB_GROTTO_LEFT }, + { "DMC Deku Scrub Grotto Center" , RC_DMC_DEKU_SCRUB_GROTTO_CENTER }, + { "DMC Deku Scrub Grotto Right" , RC_DMC_DEKU_SCRUB_GROTTO_RIGHT }, + { "DMC GS Crate" , RC_DMC_GS_CRATE }, + { "DMC GS Bean Patch" , RC_DMC_GS_BEAN_PATCH }, + { "ZR Magic Bean Salesman" , RC_ZR_MAGIC_BEAN_SALESMAN }, + { "ZR Open Grotto Chest" , RC_ZR_OPEN_GROTTO_CHEST }, + { "ZR Frogs in the Rain" , RC_ZR_FROGS_IN_THE_RAIN }, + { "ZR Frogs Ocarina Game" , RC_ZR_FROGS_OCARINA_GAME }, + { "ZR Near Open Grotto Freestanding PoH" , RC_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH }, + { "ZR Near Domain Freestanding PoH" , RC_ZR_NEAR_DOMAIN_FREESTANDING_POH }, + { "ZR Deku Scrub Grotto Front" , RC_ZR_DEKU_SCRUB_GROTTO_FRONT }, + { "ZR Deku Scrub Grotto Rear" , RC_ZR_DEKU_SCRUB_GROTTO_REAR }, + { "ZR GS Tree" , RC_ZR_GS_TREE }, + { "ZR GS Ladder" , RC_ZR_GS_LADDER }, + { "ZR GS Near Raised Grottos" , RC_ZR_GS_NEAR_RAISED_GROTTOS }, + { "ZR GS Above Bridge" , RC_ZR_GS_ABOVE_BRIDGE }, + { "ZD Diving Minigame" , RC_ZD_DIVING_MINIGAME }, + { "ZD Chest" , RC_ZD_CHEST }, + { "ZD King Zora Thawed" , RC_ZD_KING_ZORA_THAWED }, + { "ZD GS Frozen Waterfall" , RC_ZD_GS_FROZEN_WATERFALL }, + { "ZD Shop Item 1" , RC_ZD_SHOP_ITEM_1 }, + { "ZD Shop Item 2" , RC_ZD_SHOP_ITEM_2 }, + { "ZD Shop Item 3" , RC_ZD_SHOP_ITEM_3 }, + { "ZD Shop Item 4" , RC_ZD_SHOP_ITEM_4 }, + { "ZD Shop Item 5" , RC_ZD_SHOP_ITEM_5 }, + { "ZD Shop Item 6" , RC_ZD_SHOP_ITEM_6 }, + { "ZD Shop Item 7" , RC_ZD_SHOP_ITEM_7 }, + { "ZD Shop Item 8" , RC_ZD_SHOP_ITEM_8 }, + { "ZF Great Fairy Reward" , RC_ZF_GREAT_FAIRY_REWARD }, + { "ZF Iceberg Freestanding PoH" , RC_ZF_ICEBERG_FREESTANDING_POH }, + { "ZF Bottom Freestanding PoH" , RC_ZF_BOTTOM_FREESTANDING_POH }, + { "ZF GS Above the Log" , RC_ZF_GS_ABOVE_THE_LOG }, + { "ZF GS Tree" , RC_ZF_GS_TREE }, + { "ZF GS Hidden Cave" , RC_ZF_GS_HIDDEN_CAVE }, + { "LH Underwater Item" , RC_LH_UNDERWATER_ITEM }, + { "LH Child Fishing" , RC_LH_CHILD_FISHING }, + { "LH Adult Fishing" , RC_LH_ADULT_FISHING }, + { "LH Lab Dive" , RC_LH_LAB_DIVE }, + { "LH Freestanding PoH" , RC_LH_FREESTANDING_POH }, + { "LH Sun" , RC_LH_SUN }, + { "LH Deku Scrub Grotto Left" , RC_LH_DEKU_SCRUB_GROTTO_LEFT }, + { "LH Deku Scrub Grotto Center" , RC_LH_DEKU_SCRUB_GROTTO_CENTER }, + { "LH Deku Scrub Grotto Right" , RC_LH_DEKU_SCRUB_GROTTO_RIGHT }, + { "LH GS Bean Patch" , RC_LH_GS_BEAN_PATCH }, + { "LH GS Lab Wall" , RC_LH_GS_LAB_WALL }, + { "LH GS Small Island" , RC_LH_GS_SMALL_ISLAND }, + { "LH GS Lab Crate" , RC_LH_GS_LAB_CRATE }, + { "LH GS Tree" , RC_LH_GS_TREE }, + { "GV Crate Freestanding PoH" , RC_GV_CRATE_FREESTANDING_POH }, + { "GV Waterfall Freestanding PoH" , RC_GV_WATERFALL_FREESTANDING_POH }, + { "GV Chest" , RC_GV_CHEST }, + { "GV Deku Scrub Grotto Front" , RC_GV_DEKU_SCRUB_GROTTO_FRONT }, + { "GV Deku Scrub Grotto Rear" , RC_GV_DEKU_SCRUB_GROTTO_REAR }, + { "GV Cow" , RC_GV_COW }, + { "GV GS Small Bridge" , RC_GV_GS_SMALL_BRIDGE }, + { "GV GS Bean Patch" , RC_GV_GS_BEAN_PATCH }, + { "GV GS Behind Tent" , RC_GV_GS_BEHIND_TENT }, + { "GV GS Pillar" , RC_GV_GS_PILLAR }, + { "GF Chest" , RC_GF_CHEST }, + { "GF HBA 1000 Points" , RC_GF_HBA_1000_POINTS }, + { "GF HBA 1500 Points" , RC_GF_HBA_1500_POINTS }, + { "GF GS Top Floor" , RC_GF_GS_TOP_FLOOR }, + { "GF GS Archery Range" , RC_GF_GS_ARCHERY_RANGE }, + { "Hideout 1 Torch Jail Gerudo Key" , RC_HIDEOUT_JAIL_GUARD_1_TORCH }, + { "Hideout 2 Torches Jail Gerudo Key" , RC_HIDEOUT_JAIL_GUARD_1_TORCH }, + { "Hideout 3 Torches Jail Gerudo Key" , RC_HIDEOUT_JAIL_GUARD_1_TORCH }, + { "Hideout 4 Torches Jail Gerudo Key" , RC_HIDEOUT_JAIL_GUARD_1_TORCH }, + { "Hideout Gerudo Membership Card" , RC_HIDEOUT_GERUDO_MEMBERSHIP_CARD }, + { "Wasteland Bombchu Salesman" , RC_WASTELAND_BOMBCHU_SALESMAN }, + { "Wasteland Chest" , RC_WASTELAND_CHEST }, + { "Wasteland GS" , RC_WASTELAND_GS }, + { "Colossus Great Fairy Reward" , RC_COLOSSUS_GREAT_FAIRY_REWARD }, + { "Colossus Freestanding PoH" , RC_COLOSSUS_FREESTANDING_POH }, + { "Colossus Deku Scrub Grotto Front" , RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT }, + { "Colossus Deku Scrub Grotto Rear" , RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR }, + { "Colossus GS Bean Patch" , RC_COLOSSUS_GS_BEAN_PATCH }, + { "Colossus GS Tree" , RC_COLOSSUS_GS_TREE }, + { "Colossus GS Hill" , RC_COLOSSUS_GS_HILL }, + { "OGC Great Fairy Reward" , RC_OGC_GREAT_FAIRY_REWARD }, + { "OGC GS" , RC_OGC_GS }, + { "Deku Tree Map Chest" , RC_DEKU_TREE_MAP_CHEST }, + { "Deku Tree Slingshot Room Side Chest" , RC_DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST }, + { "Deku Tree Slingshot Chest" , RC_DEKU_TREE_SLINGSHOT_CHEST }, + { "Deku Tree Compass Chest" , RC_DEKU_TREE_COMPASS_CHEST }, + { "Deku Tree Compass Room Side Chest" , RC_DEKU_TREE_COMPASS_ROOM_SIDE_CHEST }, + { "Deku Tree Basement Chest" , RC_DEKU_TREE_BASEMENT_CHEST }, + { "Deku Tree GS Compass Room" , RC_DEKU_TREE_GS_COMPASS_ROOM }, + { "Deku Tree GS Basement Vines" , RC_DEKU_TREE_GS_BASEMENT_VINES }, + { "Deku Tree GS Basement Gate" , RC_DEKU_TREE_GS_BASEMENT_GATE }, + { "Deku Tree GS Basement Back Room" , RC_DEKU_TREE_GS_BASEMENT_BACK_ROOM }, + { "Deku Tree MQ Map Chest" , RC_DEKU_TREE_MQ_MAP_CHEST }, + { "Deku Tree MQ Slingshot Chest" , RC_DEKU_TREE_MQ_SLINGSHOT_CHEST }, + { "Deku Tree MQ Slingshot Room Back Chest" , RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST }, + { "Deku Tree MQ Compass Chest" , RC_DEKU_TREE_MQ_COMPASS_CHEST }, + { "Deku Tree MQ Basement Chest" , RC_DEKU_TREE_MQ_BASEMENT_CHEST }, + { "Deku Tree MQ Before Spinning Log Chest" , RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST }, + { "Deku Tree MQ After Spinning Log Chest" , RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST }, + { "Deku Tree MQ Deku Scrub" , RC_DEKU_TREE_MQ_DEKU_SCRUB }, + { "Deku Tree MQ GS Lobby" , RC_DEKU_TREE_MQ_GS_LOBBY }, + { "Deku Tree MQ GS Compass Room" , RC_DEKU_TREE_MQ_COMPASS_CHEST }, + { "Deku Tree MQ GS Basement Graves Room" , RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM }, + { "Deku Tree MQ GS Basement Back Room" , RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM }, + { "Deku Tree Queen Gohma Heart" , RC_DEKU_TREE_QUEEN_GOHMA_HEART }, + { "Dodongos Cavern Map Chest" , RC_DODONGOS_CAVERN_MAP_CHEST }, + { "Dodongos Cavern Compass Chest" , RC_DODONGOS_CAVERN_COMPASS_CHEST }, + { "Dodongos Cavern Bomb Flower Platform Chest" , RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST }, + { "Dodongos Cavern Bomb Bag Chest" , RC_DODONGOS_CAVERN_BOMB_BAG_CHEST }, + { "Dodongos Cavern End of Bridge Chest" , RC_DODONGOS_CAVERN_END_OF_BRIDGE_CHEST }, + { "Dodongos Cavern Deku Scrub Side Room Near Dodongos" , RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS }, + { "Dodongos Cavern Deku Scrub Lobby" , RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY }, + { "Dodongos Cavern Deku Scrub Near Bomb Bag Left" , RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT }, + { "Dodongos Cavern Deku Scrub Near Bomb Bag Right" , RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT }, + { "Dodongos Cavern GS Side Room Near Lower Lizalfos" , RC_DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS }, + { "Dodongos Cavern GS Scarecrow" , RC_DODONGOS_CAVERN_GS_SCARECROW }, + { "Dodongos Cavern GS Alcove Above Stairs" , RC_DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS }, + { "Dodongos Cavern GS Vines Above Stairs" , RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS }, + { "Dodongos Cavern GS Back Room" , RC_DODONGOS_CAVERN_GS_BACK_ROOM }, + { "Dodongos Cavern MQ Map Chest" , RC_DODONGOS_CAVERN_MQ_MAP_CHEST }, + { "Dodongos Cavern MQ Bomb Bag Chest" , RC_DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST }, + { "Dodongos Cavern MQ Torch Puzzle Room Chest" , RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST }, + { "Dodongos Cavern MQ Larvae Room Chest" , RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST }, + { "Dodongos Cavern MQ Compass Chest" , RC_DODONGOS_CAVERN_MQ_COMPASS_CHEST }, + { "Dodongos Cavern MQ Under Grave Chest" , RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST }, + { "Dodongos Cavern MQ Deku Scrub Lobby Front" , RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT }, + { "Dodongos Cavern MQ Deku Scrub Lobby Rear" , RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR }, + { "Dodongos Cavern MQ Deku Scrub Side Room Near Lower Lizalfos" , RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS }, + { "Dodongos Cavern MQ Deku Scrub Staircase" , RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE }, + { "Dodongos Cavern MQ GS Scrub Room" , RC_DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM }, + { "Dodongos Cavern MQ GS Larvae Room" , RC_DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM }, + { "Dodongos Cavern MQ GS Lizalfos Room" , RC_DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM }, + { "Dodongos Cavern MQ GS Song of Time Block Room" , RC_DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM }, + { "Dodongos Cavern MQ GS Back Area" , RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA }, + { "Dodongos Cavern Boss Room Chest" , RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST }, + { "Dodongos Cavern King Dodongo Heart" , RC_DODONGOS_CAVERN_KING_DODONGO_HEART }, + { "Jabu Jabus Belly Boomerang Chest" , RC_JABU_JABUS_BELLY_BOOMERANG_CHEST }, + { "Jabu Jabus Belly Map Chest" , RC_JABU_JABUS_BELLY_MAP_CHEST }, + { "Jabu Jabus Belly Compass Chest" , RC_JABU_JABUS_BELLY_COMPASS_CHEST }, + { "Jabu Jabus Belly Deku Scrub" , RC_JABU_JABUS_BELLY_DEKU_SCRUB }, + { "Jabu Jabus Belly GS Water Switch Room" , RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM }, + { "Jabu Jabus Belly GS Lobby Basement Lower" , RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER }, + { "Jabu Jabus Belly GS Lobby Basement Upper" , RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER }, + { "Jabu Jabus Belly GS Near Boss" , RC_JABU_JABUS_BELLY_GS_NEAR_BOSS }, + { "Jabu Jabus Belly MQ Map Chest" , RC_JABU_JABUS_BELLY_MQ_MAP_CHEST }, + { "Jabu Jabus Belly MQ First Room Side Chest" , RC_JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST }, + { "Jabu Jabus Belly MQ Second Room Lower Chest" , RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST }, + { "Jabu Jabus Belly MQ Compass Chest" , RC_JABU_JABUS_BELLY_MQ_COMPASS_CHEST }, + { "Jabu Jabus Belly MQ Basement Near Switches Chest" , RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST }, + { "Jabu Jabus Belly MQ Basement Near Vines Chest" , RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST }, + { "Jabu Jabus Belly MQ Boomerang Room Small Chest" , RC_JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST }, + { "Jabu Jabus Belly MQ Boomerang Chest" , RC_JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST }, + { "Jabu Jabus Belly MQ Falling Like Like Room Chest" , RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST }, + { "Jabu Jabus Belly MQ Second Room Upper Chest" , RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST }, + { "Jabu Jabus Belly MQ Near Boss Chest" , RC_JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST }, + { "Jabu Jabus Belly MQ Cow" , RC_JABU_JABUS_BELLY_MQ_COW }, + { "Jabu Jabus Belly MQ GS Boomerang Chest Room" , RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM }, + { "Jabu Jabus Belly MQ GS Tailpasaran Room" , RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM }, + { "Jabu Jabus Belly MQ GS Invisible Enemies Room" , RC_JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM }, + { "Jabu Jabus Belly MQ GS Near Boss" , RC_JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS }, + { "Jabu Jabus Belly Barinade Heart" , RC_JABU_JABUS_BELLY_BARINADE_HEART }, + { "Bottom of the Well Front Left Fake Wall Chest" , RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST }, + { "Bottom of the Well Front Center Bombable Chest" , RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST }, + { "Bottom of the Well Back Left Bombable Chest" , RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST }, + { "Bottom of the Well Underwater Left Chest" , RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST }, + { "Bottom of the Well Freestanding Key" , RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY }, + { "Bottom of the Well Compass Chest" , RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST }, + { "Bottom of the Well Center Skulltula Chest" , RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST }, + { "Bottom of the Well Right Bottom Fake Wall Chest" , RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST }, + { "Bottom of the Well Fire Keese Chest" , RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST }, + { "Bottom of the Well Like Like Chest" , RC_BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST }, + { "Bottom of the Well Map Chest" , RC_BOTTOM_OF_THE_WELL_MAP_CHEST }, + { "Bottom of the Well Underwater Front Chest" , RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST }, + { "Bottom of the Well Invisible Chest" , RC_BOTTOM_OF_THE_WELL_INVISIBLE_CHEST }, + { "Bottom of the Well Lens of Truth Chest" , RC_BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST }, + { "Bottom of the Well GS West Inner Room" , RC_BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM }, + { "Bottom of the Well GS East Inner Room" , RC_BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM }, + { "Bottom of the Well GS Like Like Cage" , RC_BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE }, + { "Bottom of the Well MQ Map Chest" , RC_BOTTOM_OF_THE_WELL_MQ_MAP_CHEST }, + { "Bottom of the Well MQ East Inner Room Freestanding Key" , RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY }, + { "Bottom of the Well MQ Compass Chest" , RC_BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST }, + { "Bottom of the Well MQ Dead Hand Freestanding Key" , RC_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY }, + { "Bottom of the Well MQ Lens of Truth Chest" , RC_BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST }, + { "Bottom of the Well MQ GS Coffin Room" , RC_BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM }, + { "Bottom of the Well MQ GS West Inner Room" , RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM }, + { "Bottom of the Well MQ GS Basement" , RC_BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT }, + { "Forest Temple First Room Chest" , RC_FOREST_TEMPLE_FIRST_ROOM_CHEST }, + { "Forest Temple First Stalfos Chest" , RC_FOREST_TEMPLE_FIRST_STALFOS_CHEST }, + { "Forest Temple Raised Island Courtyard Chest" , RC_FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST }, + { "Forest Temple Map Chest" , RC_FOREST_TEMPLE_MAP_CHEST }, + { "Forest Temple Well Chest" , RC_FOREST_TEMPLE_WELL_CHEST }, + { "Forest Temple Eye Switch Chest" , RC_FOREST_TEMPLE_EYE_SWITCH_CHEST }, + { "Forest Temple Boss Key Chest" , RC_FOREST_TEMPLE_BOSS_KEY_CHEST }, + { "Forest Temple Floormaster Chest" , RC_FOREST_TEMPLE_FLOORMASTER_CHEST }, + { "Forest Temple Red Poe Chest" , RC_FOREST_TEMPLE_RED_POE_CHEST }, + { "Forest Temple Bow Chest" , RC_FOREST_TEMPLE_BOW_CHEST }, + { "Forest Temple Blue Poe Chest" , RC_FOREST_TEMPLE_BLUE_POE_CHEST }, + { "Forest Temple Falling Ceiling Room Chest" , RC_FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST }, + { "Forest Temple Basement Chest" , RC_FOREST_TEMPLE_BASEMENT_CHEST }, + { "Forest Temple GS First Room" , RC_FOREST_TEMPLE_GS_FIRST_ROOM }, + { "Forest Temple GS Lobby" , RC_FOREST_TEMPLE_GS_LOBBY }, + { "Forest Temple GS Raised Island Courtyard" , RC_FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD }, + { "Forest Temple GS Level Island Courtyard" , RC_FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD }, + { "Forest Temple GS Basement" , RC_FOREST_TEMPLE_GS_BASEMENT }, + { "Forest Temple MQ First Room Chest" , RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST }, + { "Forest Temple MQ Wolfos Chest" , RC_FOREST_TEMPLE_MQ_WOLFOS_CHEST }, + { "Forest Temple MQ Well Chest" , RC_FOREST_TEMPLE_MQ_WELL_CHEST }, + { "Forest Temple MQ Raised Island Courtyard Lower Chest" , RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST }, + { "Forest Temple MQ Raised Island Courtyard Upper Chest" , RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST }, + { "Forest Temple MQ Boss Key Chest" , RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST }, + { "Forest Temple MQ Redead Chest" , RC_FOREST_TEMPLE_MQ_REDEAD_CHEST }, + { "Forest Temple MQ Map Chest" , RC_FOREST_TEMPLE_MQ_MAP_CHEST }, + { "Forest Temple MQ Bow Chest" , RC_FOREST_TEMPLE_MQ_BOW_CHEST }, + { "Forest Temple MQ Compass Chest" , RC_FOREST_TEMPLE_MQ_COMPASS_CHEST }, + { "Forest Temple MQ Falling Ceiling Room Chest" , RC_FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST }, + { "Forest Temple MQ Basement Chest" , RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST }, + { "Forest Temple MQ GS First Hallway" , RC_FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY }, + { "Forest Temple MQ GS Raised Island Courtyard" , RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD }, + { "Forest Temple MQ GS Level Island Courtyard" , RC_FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD }, + { "Forest Temple MQ GS Well" , RC_FOREST_TEMPLE_MQ_GS_WELL }, + { "Forest Temple MQ GS Block Push Room" , RC_FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM }, + { "Forest Temple Phantom Ganon Heart" , RC_FOREST_TEMPLE_PHANTOM_GANON_HEART }, + { "Fire Temple Near Boss Chest" , RC_FIRE_TEMPLE_NEAR_BOSS_CHEST }, + { "Fire Temple Flare Dancer Chest" , RC_FIRE_TEMPLE_FLARE_DANCER_CHEST }, + { "Fire Temple Boss Key Chest" , RC_FIRE_TEMPLE_BOSS_KEY_CHEST }, + { "Fire Temple Big Lava Room Lower Open Door Chest" , RC_FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST }, + { "Fire Temple Big Lava Room Blocked Door Chest" , RC_FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST }, + { "Fire Temple Boulder Maze Lower Chest" , RC_FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST }, + { "Fire Temple Boulder Maze Side Room Chest" , RC_FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST }, + { "Fire Temple Map Chest" , RC_FIRE_TEMPLE_MAP_CHEST }, + { "Fire Temple Boulder Maze Shortcut Chest" , RC_FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST }, + { "Fire Temple Boulder Maze Upper Chest" , RC_FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST }, + { "Fire Temple Scarecrow Chest" , RC_FIRE_TEMPLE_SCARECROW_CHEST }, + { "Fire Temple Compass Chest" , RC_FIRE_TEMPLE_COMPASS_CHEST }, + { "Fire Temple Megaton Hammer Chest" , RC_FIRE_TEMPLE_MEGATON_HAMMER_CHEST }, + { "Fire Temple Highest Goron Chest" , RC_FIRE_TEMPLE_HIGHEST_GORON_CHEST }, + { "Fire Temple GS Boss Key Loop" , RC_FIRE_TEMPLE_GS_BOSS_KEY_LOOP }, + { "Fire Temple GS Song of Time Room" , RC_FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM }, + { "Fire Temple GS Boulder Maze" , RC_FIRE_TEMPLE_GS_BOULDER_MAZE }, + { "Fire Temple GS Scarecrow Climb" , RC_FIRE_TEMPLE_GS_SCARECROW_CLIMB }, + { "Fire Temple GS Scarecrow Top" , RC_FIRE_TEMPLE_GS_SCARECROW_TOP }, + { "Fire Temple MQ Map Room Side Chest" , RC_FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST }, + { "Fire Temple MQ Megaton Hammer Chest" , RC_FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST }, + { "Fire Temple MQ Map Chest" , RC_FIRE_TEMPLE_MQ_MAP_CHEST }, + { "Fire Temple MQ Near Boss Chest" , RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST }, + { "Fire Temple MQ Big Lava Room Blocked Door Chest" , RC_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST }, + { "Fire Temple MQ Boss Key Chest" , RC_FIRE_TEMPLE_MQ_BOSS_KEY_CHEST }, + { "Fire Temple MQ Lizalfos Maze Side Room Chest" , RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST }, + { "Fire Temple MQ Compass Chest" , RC_FIRE_TEMPLE_MQ_COMPASS_CHEST }, + { "Fire Temple MQ Lizalfos Maze Upper Chest" , RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST }, + { "Fire Temple MQ Lizalfos Maze Lower Chest" , RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST }, + { "Fire Temple MQ Freestanding Key" , RC_FIRE_TEMPLE_MQ_FREESTANDING_KEY }, + { "Fire Temple MQ Chest On Fire" , RC_FIRE_TEMPLE_MQ_CHEST_ON_FIRE }, + { "Fire Temple MQ GS Big Lava Room Open Door" , RC_FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR }, + { "Fire Temple MQ GS Skull On Fire" , RC_FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE }, + { "Fire Temple MQ GS Flame Maze Center" , RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER }, + { "Fire Temple MQ GS Flame Maze Side Room" , RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM }, + { "Fire Temple MQ GS Above Flame Maze" , RC_FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_MAZE }, + { "Fire Temple Volvagia Heart" , RC_FIRE_TEMPLE_VOLVAGIA_HEART }, + { "Water Temple Compass Chest" , RC_WATER_TEMPLE_COMPASS_CHEST }, + { "Water Temple Map Chest" , RC_WATER_TEMPLE_MAP_CHEST }, + { "Water Temple Cracked Wall Chest" , RC_WATER_TEMPLE_CRACKED_WALL_CHEST }, + { "Water Temple Torches Chest" , RC_WATER_TEMPLE_TORCHES_CHEST }, + { "Water Temple Boss Key Chest" , RC_WATER_TEMPLE_BOSS_KEY_CHEST }, + { "Water Temple Central Pillar Chest" , RC_WATER_TEMPLE_CENTRAL_PILLAR_CHEST }, + { "Water Temple Central Bow Target Chest" , RC_WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST }, + { "Water Temple Longshot Chest" , RC_WATER_TEMPLE_LONGSHOT_CHEST }, + { "Water Temple River Chest" , RC_WATER_TEMPLE_RIVER_CHEST }, + { "Water Temple Dragon Chest" , RC_WATER_TEMPLE_DRAGON_CHEST }, + { "Water Temple GS Behind Gate" , RC_WATER_TEMPLE_GS_BEHIND_GATE }, + { "Water Temple GS Near Boss Key Chest" , RC_WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST }, + { "Water Temple GS Central Pillar" , RC_WATER_TEMPLE_GS_CENTRAL_PILLAR }, + { "Water Temple GS Falling Platform Room" , RC_WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM }, + { "Water Temple GS River" , RC_WATER_TEMPLE_GS_RIVER }, + { "Water Temple MQ Longshot Chest" , RC_WATER_TEMPLE_MQ_LONGSHOT_CHEST }, + { "Water Temple MQ Map Chest" , RC_WATER_TEMPLE_MQ_MAP_CHEST }, + { "Water Temple MQ Compass Chest" , RC_WATER_TEMPLE_MQ_COMPASS_CHEST }, + { "Water Temple MQ Central Pillar Chest" , RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST }, + { "Water Temple MQ Boss Key Chest" , RC_WATER_TEMPLE_MQ_BOSS_KEY_CHEST }, + { "Water Temple MQ Freestanding Key" , RC_WATER_TEMPLE_MQ_FREESTANDING_KEY }, + { "Water Temple MQ GS Lizalfos Hallway" , RC_WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY }, + { "Water Temple MQ GS Before Upper Water Switch" , RC_WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH }, + { "Water Temple MQ GS River" , RC_WATER_TEMPLE_MQ_GS_RIVER }, + { "Water Temple MQ GS Freestanding Key Area" , RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA }, + { "Water Temple MQ GS Triple Wall Torch" , RC_WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH }, + { "Water Temple Morpha Heart" , RC_WATER_TEMPLE_MORPHA_HEART }, + { "Shadow Temple Map Chest" , RC_SHADOW_TEMPLE_MAP_CHEST }, + { "Shadow Temple Hover Boots Chest" , RC_SHADOW_TEMPLE_HOVER_BOOTS_CHEST }, + { "Shadow Temple Compass Chest" , RC_SHADOW_TEMPLE_COMPASS_CHEST }, + { "Shadow Temple Early Silver Rupee Chest" , RC_SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST }, + { "Shadow Temple Invisible Blades Visible Chest" , RC_SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST }, + { "Shadow Temple Invisible Blades Invisible Chest" , RC_SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST }, + { "Shadow Temple Falling Spikes Lower Chest" , RC_SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST }, + { "Shadow Temple Falling Spikes Upper Chest" , RC_SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST }, + { "Shadow Temple Falling Spikes Switch Chest" , RC_SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST }, + { "Shadow Temple Invisible Spikes Chest" , RC_SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST }, + { "Shadow Temple Freestanding Key" , RC_SHADOW_TEMPLE_FREESTANDING_KEY }, + { "Shadow Temple Wind Hint Chest" , RC_SHADOW_TEMPLE_WIND_HINT_CHEST }, + { "Shadow Temple After Wind Enemy Chest" , RC_SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST }, + { "Shadow Temple After Wind Hidden Chest" , RC_SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST }, + { "Shadow Temple Spike Walls Left Chest" , RC_SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST }, + { "Shadow Temple Boss Key Chest" , RC_SHADOW_TEMPLE_BOSS_KEY_CHEST }, + { "Shadow Temple Invisible Floormaster Chest" , RC_SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST }, + { "Shadow Temple GS Invisible Blades Room" , RC_SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM }, // semi sure + { "Shadow Temple GS Falling Spikes Room" , RC_SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM }, + { "Shadow Temple GS Single Giant Pot" , RC_SHADOW_TEMPLE_GS_SINGLE_GIANT_POT }, + { "Shadow Temple GS Near Ship" , RC_SHADOW_TEMPLE_GS_NEAR_SHIP }, + { "Shadow Temple GS Triple Giant Pot" , RC_SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT }, + { "Shadow Temple MQ Early Gibdos Chest" , RC_SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST }, + { "Shadow Temple MQ Map Chest" , RC_SHADOW_TEMPLE_MQ_MAP_CHEST }, + { "Shadow Temple MQ Near Ship Invisible Chest" , RC_SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST }, + { "Shadow Temple MQ Compass Chest" , RC_SHADOW_TEMPLE_MQ_COMPASS_CHEST }, + { "Shadow Temple MQ Hover Boots Chest" , RC_SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST }, + { "Shadow Temple MQ Invisible Blades Invisible Chest" , RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST }, + { "Shadow Temple MQ Invisible Blades Visible Chest" , RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST }, + { "Shadow Temple MQ Beamos Silver Rupees Chest" , RC_SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST }, + { "Shadow Temple MQ Falling Spikes Lower Chest" , RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST }, + { "Shadow Temple MQ Falling Spikes Upper Chest" , RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST }, + { "Shadow Temple MQ Falling Spikes Switch Chest" , RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST }, + { "Shadow Temple MQ Invisible Spikes Chest" , RC_SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST }, + { "Shadow Temple MQ Stalfos Room Chest" , RC_SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST }, + { "Shadow Temple MQ Wind Hint Chest" , RC_SHADOW_TEMPLE_MQ_WIND_HINT_CHEST }, + { "Shadow Temple MQ After Wind Hidden Chest" , RC_SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST }, + { "Shadow Temple MQ After Wind Enemy Chest" , RC_SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST }, + { "Shadow Temple MQ Boss Key Chest" , RC_SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST }, + { "Shadow Temple MQ Spike Walls Left Chest" , RC_SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST }, + { "Shadow Temple MQ Freestanding Key" , RC_SHADOW_TEMPLE_MQ_FREESTANDING_KEY }, + { "Shadow Temple MQ Bomb Flower Chest" , RC_SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST }, + { "Shadow Temple MQ GS Falling Spikes Room" , RC_SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM }, + { "Shadow Temple MQ GS Wind Hint Room" , RC_SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM }, + { "Shadow Temple MQ GS After Wind" , RC_SHADOW_TEMPLE_MQ_GS_AFTER_WIND }, + { "Shadow Temple MQ GS After Ship" , RC_SHADOW_TEMPLE_MQ_GS_AFTER_SHIP }, + { "Shadow Temple MQ GS Near Boss" , RC_SHADOW_TEMPLE_MQ_GS_NEAR_BOSS }, + { "Shadow Temple Bongo Bongo Heart" , RC_SHADOW_TEMPLE_BONGO_BONGO_HEART }, + { "Spirit Temple Child Bridge Chest" , RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST }, + { "Spirit Temple Child Early Torches Chest" , RC_SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST }, + { "Spirit Temple Child Climb North Chest" , RC_SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST }, + { "Spirit Temple Child Climb East Chest" , RC_SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST }, + { "Spirit Temple Map Chest" , RC_SPIRIT_TEMPLE_MAP_CHEST }, + { "Spirit Temple Sun Block Room Chest" , RC_SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST }, + { "Spirit Temple MQ Entrance Front Left Chest" , RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST }, + { "Spirit Temple MQ Entrance Back Right Chest" , RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST }, + { "Spirit Temple MQ Entrance Front Right Chest" , RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST }, + { "Spirit Temple MQ Entrance Back Left Chest" , RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST }, + { "Spirit Temple MQ Map Chest" , RC_SPIRIT_TEMPLE_MQ_MAP_CHEST }, + { "Spirit Temple MQ Map Room Enemy Chest" , RC_SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST }, + { "Spirit Temple MQ Child Climb North Chest" , RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST }, + { "Spirit Temple MQ Child Climb South Chest" , RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST }, + { "Spirit Temple MQ Compass Chest" , RC_SPIRIT_TEMPLE_MQ_COMPASS_CHEST }, + { "Spirit Temple MQ Silver Block Hallway Chest" , RC_SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST }, + { "Spirit Temple MQ Sun Block Room Chest" , RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST }, + { "Spirit Temple Silver Gauntlets Chest" , RC_SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST }, + { "Spirit Temple Compass Chest" , RC_SPIRIT_TEMPLE_COMPASS_CHEST }, + { "Spirit Temple Early Adult Right Chest" , RC_SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST }, + { "Spirit Temple First Mirror Left Chest" , RC_SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST }, + { "Spirit Temple First Mirror Right Chest" , RC_SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST }, + { "Spirit Temple Statue Room Northeast Chest" , RC_SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST }, + { "Spirit Temple Statue Room Hand Chest" , RC_SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST }, + { "Spirit Temple Near Four Armos Chest" , RC_SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST }, + { "Spirit Temple Hallway Right Invisible Chest" , RC_SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST }, + { "Spirit Temple Hallway Left Invisible Chest" , RC_SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST }, + { "Spirit Temple MQ Child Hammer Switch Chest" , RC_SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST }, + { "Spirit Temple MQ Statue Room Lullaby Chest" , RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST }, + { "Spirit Temple MQ Statue Room Invisible Chest" , RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST }, + { "Spirit Temple MQ Leever Room Chest" , RC_SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST }, + { "Spirit Temple MQ Symphony Room Chest" , RC_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST }, + { "Spirit Temple MQ Beamos Room Chest" , RC_SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST }, + { "Spirit Temple MQ Chest Switch Chest" , RC_SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST }, + { "Spirit Temple MQ Boss Key Chest" , RC_SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST }, + { "Spirit Temple Mirror Shield Chest" , RC_SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST }, + { "Spirit Temple Boss Key Chest" , RC_SPIRIT_TEMPLE_BOSS_KEY_CHEST }, + { "Spirit Temple Topmost Chest" , RC_SPIRIT_TEMPLE_TOPMOST_CHEST }, + { "Spirit Temple MQ Mirror Puzzle Invisible Chest" , RC_SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST }, + { "Spirit Temple GS Metal Fence" , RC_SPIRIT_TEMPLE_GS_METAL_FENCE }, + { "Spirit Temple GS Sun on Floor Room" , RC_SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM }, + { "Spirit Temple GS Hall After Sun Block Room" , RC_SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM }, + { "Spirit Temple GS Lobby" , RC_SPIRIT_TEMPLE_GS_LOBBY }, + { "Spirit Temple GS Boulder Room" , RC_SPIRIT_TEMPLE_GS_BOULDER_ROOM }, + { "Spirit Temple MQ GS Sun Block Room" , RC_SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM }, + { "Spirit Temple MQ GS Leever Room" , RC_SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM }, + { "Spirit Temple MQ GS Symphony Room" , RC_SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM }, + { "Spirit Temple MQ GS Nine Thrones Room West" , RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST }, + { "Spirit Temple MQ GS Nine Thrones Room North" , RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH }, + { "Spirit Temple Twinrova Heart" , RC_SPIRIT_TEMPLE_TWINROVA_HEART }, + { "Ice Cavern Map Chest" , RC_ICE_CAVERN_MAP_CHEST }, + { "Ice Cavern Compass Chest" , RC_ICE_CAVERN_COMPASS_CHEST }, + { "Ice Cavern Iron Boots Chest" , RC_ICE_CAVERN_IRON_BOOTS_CHEST }, + { "Ice Cavern GS Spinning Scythe Room" , RC_ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM }, + { "Ice Cavern GS Heart Piece Room" , RC_ICE_CAVERN_GS_HEART_PIECE_ROOM }, + { "Ice Cavern GS Push Block Room" , RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM }, + { "Ice Cavern Freestanding PoH" , RC_ICE_CAVERN_FREESTANDING_POH }, + { "Ice Cavern MQ Map Chest" , RC_ICE_CAVERN_MQ_MAP_CHEST }, + { "Ice Cavern MQ Compass Chest" , RC_ICE_CAVERN_MQ_COMPASS_CHEST }, + { "Ice Cavern MQ Freestanding PoH" , RC_ICE_CAVERN_MQ_FREESTANDING_POH }, + { "Ice Cavern MQ Iron Boots Chest" , RC_ICE_CAVERN_MQ_IRON_BOOTS_CHEST }, + { "Ice Cavern MQ GS Red Ice" , RC_ICE_CAVERN_MQ_GS_RED_ICE }, + { "Ice Cavern MQ GS Ice Block" , RC_ICE_CAVERN_MQ_GS_ICE_BLOCK }, + { "Ice Cavern MQ GS Scarecrow" , RC_ICE_CAVERN_MQ_GS_SCARECROW }, + { "Gerudo Training Ground Lobby Left Chest" , RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST }, + { "Gerudo Training Ground Lobby Right Chest" , RC_GERUDO_TRAINING_GROUND_LOBBY_RIGHT_CHEST }, + { "Gerudo Training Ground Stalfos Chest" , RC_GERUDO_TRAINING_GROUND_STALFOS_CHEST }, + { "Gerudo Training Ground Before Heavy Block Chest" , RC_GERUDO_TRAINING_GROUND_BEFORE_HEAVY_BLOCK_CHEST }, + { "Gerudo Training Ground Heavy Block First Chest" , RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FIRST_CHEST }, + { "Gerudo Training Ground Heavy Block Second Chest" , RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_SECOND_CHEST }, + { "Gerudo Training Ground Heavy Block Third Chest" , RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_THIRD_CHEST }, + { "Gerudo Training Ground Heavy Block Fourth Chest" , RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FOURTH_CHEST }, + { "Gerudo Training Ground Eye Statue Chest" , RC_GERUDO_TRAINING_GROUND_EYE_STATUE_CHEST }, + { "Gerudo Training Ground Near Scarecrow Chest" , RC_GERUDO_TRAINING_GROUND_NEAR_SCARECROW_CHEST }, + { "Gerudo Training Ground Hammer Room Clear Chest" , RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_CLEAR_CHEST }, + { "Gerudo Training Ground Hammer Room Switch Chest" , RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_SWITCH_CHEST }, + { "Gerudo Training Ground Freestanding Key" , RC_GERUDO_TRAINING_GROUND_FREESTANDING_KEY }, + { "Gerudo Training Ground Maze Right Central Chest" , RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_CENTRAL_CHEST }, + { "Gerudo Training Ground Maze Right Side Chest" , RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_SIDE_CHEST }, + { "Gerudo Training Ground Underwater Silver Rupee Chest" , RC_GERUDO_TRAINING_GROUND_UNDERWATER_SILVER_RUPEE_CHEST }, + { "Gerudo Training Ground Beamos Chest" , RC_GERUDO_TRAINING_GROUND_BEAMOS_CHEST }, + { "Gerudo Training Ground Hidden Ceiling Chest" , RC_GERUDO_TRAINING_GROUND_HIDDEN_CEILING_CHEST }, + { "Gerudo Training Ground Maze Path First Chest" , RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FIRST_CHEST }, + { "Gerudo Training Ground Maze Path Second Chest" , RC_GERUDO_TRAINING_GROUND_MAZE_PATH_SECOND_CHEST }, + { "Gerudo Training Ground Maze Path Third Chest" , RC_GERUDO_TRAINING_GROUND_MAZE_PATH_THIRD_CHEST }, + { "Gerudo Training Ground Maze Path Final Chest" , RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FINAL_CHEST }, + { "Gerudo Training Ground MQ Lobby Left Chest" , RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST }, + { "Gerudo Training Ground MQ Lobby Right Chest" , RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST }, + { "Gerudo Training Ground MQ First Iron Knuckle Chest" , RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST }, + { "Gerudo Training Ground MQ Before Heavy Block Chest" , RC_GERUDO_TRAINING_GROUND_MQ_BEFORE_HEAVY_BLOCK_CHEST }, + { "Gerudo Training Ground MQ Heavy Block Chest" , RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST }, + { "Gerudo Training Ground MQ Eye Statue Chest" , RC_GERUDO_TRAINING_GROUND_MQ_EYE_STATUE_CHEST }, + { "Gerudo Training Ground MQ Ice Arrows Chest" , RC_GERUDO_TRAINING_GROUND_MQ_ICE_ARROWS_CHEST }, + { "Gerudo Training Ground MQ Second Iron Knuckle Chest" , RC_GERUDO_TRAINING_GROUND_MQ_SECOND_IRON_KNUCKLE_CHEST }, + { "Gerudo Training Ground MQ Flame Circle Chest" , RC_GERUDO_TRAINING_GROUND_MQ_FLAME_CIRCLE_CHEST }, + { "Gerudo Training Ground MQ Maze Right Central Chest" , RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_CENTRAL_CHEST }, + { "Gerudo Training Ground MQ Maze Right Side Chest" , RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_SIDE_CHEST }, + { "Gerudo Training Ground MQ Underwater Silver Rupee Chest" , RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST }, + { "Gerudo Training Ground MQ Dinolfos Chest" , RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST }, + { "Gerudo Training Ground MQ Hidden Ceiling Chest" , RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST }, + { "Gerudo Training Ground MQ Maze Path First Chest" , RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST }, + { "Gerudo Training Ground MQ Maze Path Third Chest" , RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_THIRD_CHEST }, + { "Gerudo Training Ground MQ Maze Path Second Chest" , RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST }, + { "Ganons Castle Forest Trial Chest" , RC_GANONS_CASTLE_FOREST_TRIAL_CHEST }, + { "Ganons Castle Water Trial Left Chest" , RC_GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST }, + { "Ganons Castle Water Trial Right Chest" , RC_GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST }, + { "Ganons Castle Shadow Trial Front Chest" , RC_GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST }, + { "Ganons Castle Shadow Trial Golden Gauntlets Chest" , RC_GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST }, + { "Ganons Castle Light Trial First Left Chest" , RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST }, + { "Ganons Castle Light Trial Second Left Chest" , RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST }, + { "Ganons Castle Light Trial Third Left Chest" , RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST }, + { "Ganons Castle Light Trial First Right Chest" , RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST }, + { "Ganons Castle Light Trial Second Right Chest" , RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST }, + { "Ganons Castle Light Trial Third Right Chest" , RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST }, + { "Ganons Castle Light Trial Invisible Enemies Chest" , RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST }, + { "Ganons Castle Light Trial Lullaby Chest" , RC_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST }, + { "Ganons Castle Spirit Trial Crystal Switch Chest" , RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST }, + { "Ganons Castle Spirit Trial Invisible Chest" , RC_GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST }, + { "Ganons Castle Deku Scrub Left" , RC_GANONS_CASTLE_DEKU_SCRUB_LEFT }, + { "Ganons Castle Deku Scrub Center-Left" , RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT }, + { "Ganons Castle Deku Scrub Center-Right" , RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT}, + { "Ganons Castle Deku Scrub Right" , RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT }, + { "Ganons Castle MQ Forest Trial Freestanding Key" , RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY }, + { "Ganons Castle MQ Forest Trial Eye Switch Chest" , RC_GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST }, + { "Ganons Castle MQ Forest Trial Frozen Eye Switch Chest" , RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST }, + { "Ganons Castle MQ Water Trial Chest" , RC_GANONS_CASTLE_MQ_WATER_TRIAL_CHEST }, + { "Ganons Castle MQ Shadow Trial Bomb Flower Chest" , RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST }, + { "Ganons Castle MQ Shadow Trial Eye Switch Chest" , RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST }, + { "Ganons Castle MQ Light Trial Lullaby Chest" , RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST }, + { "Ganons Castle MQ Spirit Trial First Chest" , RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST }, + { "Ganons Castle MQ Spirit Trial Invisible Chest" , RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST }, + { "Ganons Castle MQ Spirit Trial Sun Front Left Chest" , RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST }, + { "Ganons Castle MQ Spirit Trial Sun Back Left Chest" , RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST }, + { "Ganons Castle MQ Spirit Trial Sun Back Right Chest" , RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST }, + { "Ganons Castle MQ Spirit Trial Golden Gauntlets Chest" , RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST }, + { "Ganons Castle MQ Deku Scrub Left" , RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT }, + { "Ganons Castle MQ Deku Scrub Center-Left" , RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT }, + { "Ganons Castle MQ Deku Scrub Center" , RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER }, + { "Ganons Castle MQ Deku Scrub Center-Right" , RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT }, + { "Ganons Castle MQ Deku Scrub Right" , RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT }, + { "Ganons Tower Boss Key Chest" , RC_GANONS_TOWER_BOSS_KEY_CHEST }, + { "Gift from Sages" , RC_GIFT_FROM_RAURU }, + { "ZR Frogs Zeldas Lullaby" , RC_ZR_FROGS_ZELDAS_LULLABY }, + { "ZR Frogs Eponas Song" , RC_ZR_FROGS_EPONAS_SONG }, + { "ZR Frogs Sarias Song" , RC_ZR_FROGS_SARIAS_SONG }, + { "ZR Frogs Suns Song" , RC_ZR_FROGS_SUNS_SONG }, + { "ZR Frogs Song of Time" , RC_ZR_FROGS_SONG_OF_TIME }, + { "KF Behind Midos Blue Rupee" , RC_UNKNOWN_CHECK }, + { "KF Boulder Maze Blue Rupee 1" , RC_UNKNOWN_CHECK }, + { "KF Boulder Maze Blue Rupee 2" , RC_UNKNOWN_CHECK }, + { "KF End of Bridge Blue Rupee" , RC_UNKNOWN_CHECK }, + { "KF Top of Sarias Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "KF Top of Sarias Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "KF Top of Sarias Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "KF Bean Platform Green Rupee 1" , RC_UNKNOWN_CHECK }, + { "KF Bean Platform Green Rupee 2" , RC_UNKNOWN_CHECK }, + { "KF Bean Platform Green Rupee 3" , RC_UNKNOWN_CHECK }, + { "KF Bean Platform Green Rupee 4" , RC_UNKNOWN_CHECK }, + { "KF Bean Platform Green Rupee 5" , RC_UNKNOWN_CHECK }, + { "KF Bean Platform Green Rupee 6" , RC_UNKNOWN_CHECK }, + { "KF Bean Platform Red Rupee" , RC_UNKNOWN_CHECK }, + { "KF Grass Near Ramp Green Rupee 1" , RC_UNKNOWN_CHECK }, + { "KF Grass Near Ramp Green Rupee 2" , RC_UNKNOWN_CHECK }, + { "KF Grass Near Midos Green Rupee 1" , RC_UNKNOWN_CHECK }, + { "KF Grass Near Midos Green Rupee 2" , RC_UNKNOWN_CHECK }, + { "KF Sarias House Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "KF Sarias House Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "KF Sarias House Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "KF Sarias House Recovery Heart 4" , RC_UNKNOWN_CHECK }, + { "KF Shop Blue Rupee" , RC_UNKNOWN_CHECK }, + { "KF Links House Pot" , RC_KF_LINKS_HOUSE_POT }, + { "KF Know it All House Pot 1" , RC_UNKNOWN_CHECK }, + { "KF Know it All House Pot 2" , RC_UNKNOWN_CHECK }, + { "KF House of Twins Pot 1" , RC_UNKNOWN_CHECK }, + { "KF House of Twins Pot 2" , RC_UNKNOWN_CHECK }, + { "KF Storms Grotto Beehive 1" , RC_UNKNOWN_CHECK }, + { "KF Storms Grotto Beehive 2" , RC_UNKNOWN_CHECK }, + { "LW Under Boulder Blue Rupee" , RC_UNKNOWN_CHECK }, + { "LW Underwater Green Rupee 1" , RC_UNKNOWN_CHECK }, + { "LW Underwater Green Rupee 2" , RC_UNKNOWN_CHECK }, + { "LW Underwater Shortcut Green Rupee" , RC_UNKNOWN_CHECK }, + { "LW Underwater Green Rupee 3" , RC_UNKNOWN_CHECK }, + { "LW Underwater Green Rupee 4" , RC_UNKNOWN_CHECK }, + { "LW Underwater Green Rupee 5" , RC_UNKNOWN_CHECK }, + { "LW Underwater Green Rupee 6" , RC_UNKNOWN_CHECK }, + { "LW Underwater Green Rupee 7" , RC_UNKNOWN_CHECK }, + { "LW Near Shortcuts Grotto Beehive 1" , RC_UNKNOWN_CHECK }, + { "LW Near Shortcuts Grotto Beehive 2" , RC_UNKNOWN_CHECK }, + { "LW Scrubs Grotto Beehive" , RC_UNKNOWN_CHECK }, + { "SFM Storms Grotto Beehive" , RC_SFM_STORMS_GROTTO_BEEHIVE }, + { "HF Cow Grotto Pot 1" , RC_HF_COW_GROTTO_POT_1 }, + { "HF Cow Grotto Pot 2" , RC_HF_COW_GROTTO_POT_2 }, + { "HF Near Market Grotto Beehive 1" , RC_UNKNOWN_CHECK }, + { "HF Near Market Grotto Beehive 2" , RC_UNKNOWN_CHECK }, + { "HF Open Grotto Beehive 1" , RC_UNKNOWN_CHECK }, + { "HF Open Grotto Beehive 2" , RC_UNKNOWN_CHECK }, + { "HF Southeast Grotto Beehive 1" , RC_UNKNOWN_CHECK }, + { "HF Southeast Grotto Beehive 2" , RC_UNKNOWN_CHECK }, + { "HF Inside Fence Grotto Beehive" , RC_HF_INSIDE_FENCE_GROTTO_BEEHIVE }, + { "Market Night Red Rupee Crate" , RC_UNKNOWN_CHECK }, + { "Market Night Green Rupee Crate 1" , RC_UNKNOWN_CHECK }, + { "Market Night Green Rupee Crate 2" , RC_UNKNOWN_CHECK }, + { "Market Night Green Rupee Crate 3" , RC_UNKNOWN_CHECK }, + { "Market Dog Lady House Crate" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Crate" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 1" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 2" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 3" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 4" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 5" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 6" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 7" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 8" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 9" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 10" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 11" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 12" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 13" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 14" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 15" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 16" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 17" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 18" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 19" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 20" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 21" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 22" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 23" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 24" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 25" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 26" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 27" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 28" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 29" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 30" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 31" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 32" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 33" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 34" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 35" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 36" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 37" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 38" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 39" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 40" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 41" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 42" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 43" , RC_UNKNOWN_CHECK }, + { "Market Guard House Child Pot 44" , RC_UNKNOWN_CHECK }, + { "Market Guard House Adult Pot 1" , RC_UNKNOWN_CHECK }, + { "Market Guard House Adult Pot 2" , RC_UNKNOWN_CHECK }, + { "Market Guard House Adult Pot 3" , RC_UNKNOWN_CHECK }, + { "Market Guard House Adult Pot 4" , RC_UNKNOWN_CHECK }, + { "Market Guard House Adult Pot 5" , RC_UNKNOWN_CHECK }, + { "Market Guard House Adult Pot 6" , RC_UNKNOWN_CHECK }, + { "Market Guard House Adult Pot 7" , RC_UNKNOWN_CHECK }, + { "Market Man in Green House Pot 1" , RC_UNKNOWN_CHECK }, + { "Market Man in Green House Pot 2" , RC_UNKNOWN_CHECK }, + { "Market Man in Green House Pot 3" , RC_UNKNOWN_CHECK }, + { "HC Storms Grotto Pot 1" , RC_HC_STORMS_GROTTO_POT_1 }, + { "HC Storms Grotto Pot 2" , RC_HC_STORMS_GROTTO_POT_2 }, + { "HC Storms Grotto Pot 3" , RC_HC_STORMS_GROTTO_POT_3 }, + { "HC Storms Grotto Pot 4" , RC_HC_STORMS_GROTTO_POT_4 }, + { "LLR Front Pot 1" , RC_LLR_FRONT_POT_1 }, + { "LLR Front Pot 2" , RC_LLR_FRONT_POT_2 }, + { "LLR Front Pot 3" , RC_LLR_FRONT_POT_3 }, + { "LLR Front Pot 4" , RC_LLR_FRONT_POT_4 }, + { "LLR Rain Shed Pot 1" , RC_LLR_RAIN_SHED_POT_1 }, + { "LLR Rain Shed Pot 2" , RC_LLR_RAIN_SHED_POT_2 }, + { "LLR Rain Shed Pot 3" , RC_LLR_RAIN_SHED_POT_3 }, + { "LLR Talons House Pot 1" , RC_LLR_TALONS_HOUSE_POT_1 }, + { "LLR Talons House Pot 2" , RC_LLR_TALONS_HOUSE_POT_2 }, + { "LLR Talons House Pot 3" , RC_LLR_TALONS_HOUSE_POT_3 }, + { "LLR Child Crate" , RC_UNKNOWN_CHECK }, + { "LLR Grotto Beehive" , RC_LLR_GROTTO_BEEHIVE }, + { "Kak Near Potion Shop Pot 1" , RC_KAK_NEAR_POTION_SHOP_POT_1 }, + { "Kak Near Potion Shop Pot 2" , RC_KAK_NEAR_POTION_SHOP_POT_2 }, + { "Kak Near Potion Shop Pot 3" , RC_KAK_NEAR_POTION_SHOP_POT_3 }, + { "Kak Near Impas House Pot 1" , RC_KAK_NEAR_IMPAS_HOUSE_POT_1 }, + { "Kak Near Impas House Pot 2" , RC_KAK_NEAR_IMPAS_HOUSE_POT_2 }, + { "Kak Near Impas House Pot 3" , RC_KAK_NEAR_IMPAS_HOUSE_POT_3 }, + { "Kak Near Guards House Pot 1" , RC_KAK_NEAR_GUARDS_HOUSE_POT_1 }, + { "Kak Near Guards House Pot 2" , RC_KAK_NEAR_GUARDS_HOUSE_POT_2 }, + { "Kak Near Guards House Pot 3" , RC_KAK_NEAR_GUARDS_HOUSE_POT_3 }, + { "Kak Near Odd Medicine Building Pot 1" , RC_UNKNOWN_CHECK }, + { "Kak Near Odd Medicine Building Pot 2" , RC_UNKNOWN_CHECK }, + { "Kak Adult Red Rupee Crate" , RC_UNKNOWN_CHECK }, + { "Kak Adult Arrows Crate" , RC_UNKNOWN_CHECK }, + { "Kak Open Grotto Beehive 1" , RC_UNKNOWN_CHECK }, + { "Kak Open Grotto Beehive 2" , RC_UNKNOWN_CHECK }, + { "Graveyard Dampe Race Rupee 1" , RC_GRAVEYARD_DAMPE_RACE_RUPEE_1 }, + { "Graveyard Dampe Race Rupee 2" , RC_GRAVEYARD_DAMPE_RACE_RUPEE_2 }, + { "Graveyard Dampe Race Rupee 3" , RC_GRAVEYARD_DAMPE_RACE_RUPEE_3 }, + { "Graveyard Dampe Race Rupee 4" , RC_GRAVEYARD_DAMPE_RACE_RUPEE_4 }, + { "Graveyard Dampe Race Rupee 5" , RC_GRAVEYARD_DAMPE_RACE_RUPEE_5 }, + { "Graveyard Dampe Race Rupee 6" , RC_GRAVEYARD_DAMPE_RACE_RUPEE_6 }, + { "Graveyard Dampe Race Rupee 7" , RC_GRAVEYARD_DAMPE_RACE_RUPEE_7 }, + { "Graveyard Dampe Race Rupee 8" , RC_GRAVEYARD_DAMPE_RACE_RUPEE_8 }, + { "Graveyard Dampe Pot 1" , RC_UNKNOWN_CHECK }, + { "Graveyard Dampe Pot 2" , RC_UNKNOWN_CHECK }, + { "Graveyard Dampe Pot 3" , RC_UNKNOWN_CHECK }, + { "Graveyard Dampe Pot 4" , RC_UNKNOWN_CHECK }, + { "Graveyard Dampe Pot 5" , RC_UNKNOWN_CHECK }, + { "Graveyard Dampe Pot 6" , RC_UNKNOWN_CHECK }, + { "DMT Rock Red Rupee" , RC_UNKNOWN_CHECK }, + { "DMT Rock Blue Rupee" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Green Rupee 1" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Green Rupee 2" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Green Rupee 3" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Green Rupee 4" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Green Rupee 5" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Green Rupee 6" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Red Rupee" , RC_DMT_COW_GROTTO_RED_RUPEE }, + { "DMT Cow Grotto Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Recovery Heart 4" , RC_UNKNOWN_CHECK }, + { "DMT Cow Grotto Beehive" , RC_DMT_COW_GROTTO_BEEHIVE }, + { "DMT Storms Grotto Beehive 1" , RC_UNKNOWN_CHECK }, + { "DMT Storms Grotto Beehive 2" , RC_UNKNOWN_CHECK }, + { "GC Spinning Pot Bomb Drop 1" , RC_UNKNOWN_CHECK }, + { "GC Spinning Pot Bomb Drop 2" , RC_UNKNOWN_CHECK }, + { "GC Spinning Pot Bomb Drop 3" , RC_UNKNOWN_CHECK }, + { "GC Spinning Pot Rupee Drop 1" , RC_UNKNOWN_CHECK }, + { "GC Spinning Pot Rupee Drop 2" , RC_UNKNOWN_CHECK }, + { "GC Spinning Pot Rupee Drop 3" , RC_UNKNOWN_CHECK }, + { "GC Spinning Pot PoH Drop Rupee 1" , RC_UNKNOWN_CHECK }, + { "GC Spinning Pot PoH Drop Rupee 2" , RC_UNKNOWN_CHECK }, + { "GC Darunia Pot 1" , RC_GC_DARUNIA_POT_1 }, + { "GC Darunia Pot 2" , RC_GC_DARUNIA_POT_2 }, + { "GC Darunia Pot 3" , RC_GC_DARUNIA_POT_3 }, + { "GC Medigoron Pot" , RC_UNKNOWN_CHECK }, + { "GC Lower Staircase Pot 1" , RC_GC_LOWER_STAIRCASE_POT_1 }, + { "GC Lower Staircase Pot 2" , RC_GC_LOWER_STAIRCASE_POT_2 }, + { "GC Upper Staircase Pot 1" , RC_GC_UPPER_STAIRCASE_POT_1 }, + { "GC Upper Staircase Pot 2" , RC_GC_UPPER_STAIRCASE_POT_2 }, + { "GC Upper Staircase Pot 3" , RC_GC_UPPER_STAIRCASE_POT_3 }, + { "GC Boulder Maze Crate" , RC_UNKNOWN_CHECK }, + { "GC Grotto Beehive" , RC_GC_GROTTO_BEEHIVE }, + { "DMC Adult Green Rupee 1" , RC_UNKNOWN_CHECK }, + { "DMC Adult Green Rupee 2" , RC_UNKNOWN_CHECK }, + { "DMC Adult Green Rupee 3" , RC_UNKNOWN_CHECK }, + { "DMC Adult Green Rupee 4" , RC_UNKNOWN_CHECK }, + { "DMC Adult Green Rupee 5" , RC_UNKNOWN_CHECK }, + { "DMC Adult Green Rupee 6" , RC_UNKNOWN_CHECK }, + { "DMC Adult Red Rupee" , RC_UNKNOWN_CHECK }, + { "DMC Child Red Rupee 1" , RC_UNKNOWN_CHECK }, + { "DMC Child Red Rupee 2" , RC_UNKNOWN_CHECK }, + { "DMC Child Blue Rupee 1" , RC_UNKNOWN_CHECK }, + { "DMC Child Blue Rupee 2" , RC_UNKNOWN_CHECK }, + { "DMC Child Blue Rupee 3" , RC_UNKNOWN_CHECK }, + { "DMC Child Blue Rupee 4" , RC_UNKNOWN_CHECK }, + { "DMC Child Blue Rupee 5" , RC_UNKNOWN_CHECK }, + { "DMC Child Blue Rupee 6" , RC_UNKNOWN_CHECK }, + { "DMC Near GC Pot 1" , RC_DMC_NEAR_GC_POT_1 }, + { "DMC Near GC Pot 2" , RC_DMC_NEAR_GC_POT_2 }, + { "DMC Near GC Pot 3" , RC_DMC_NEAR_GC_POT_3 }, + { "DMC Near GC Pot 4" , RC_DMC_NEAR_GC_POT_4 }, + { "DMC Upper Grotto Beehive 1" , RC_UNKNOWN_CHECK }, + { "DMC Upper Grotto Beehive 2" , RC_UNKNOWN_CHECK }, + { "DMC Hammer Grotto Beehive" , RC_DMC_HAMMER_GROTTO_BEEHIVE }, + { "ZR Waterfall Red Rupee 1" , RC_UNKNOWN_CHECK }, + { "ZR Waterfall Red Rupee 2" , RC_UNKNOWN_CHECK }, + { "ZR Waterfall Red Rupee 3" , RC_UNKNOWN_CHECK }, + { "ZR Waterfall Red Rupee 4" , RC_UNKNOWN_CHECK }, + { "ZR Open Grotto Beehive 1" , RC_UNKNOWN_CHECK }, + { "ZR Open Grotto Beehive 2" , RC_UNKNOWN_CHECK }, + { "ZR Storms Grotto Beehive" , RC_ZR_STORMS_GROTTO_BEEHIVE }, + { "ZD Pot 1" , RC_UNKNOWN_CHECK }, + { "ZD Pot 2" , RC_UNKNOWN_CHECK }, + { "ZD Pot 3" , RC_UNKNOWN_CHECK }, + { "ZD Pot 4" , RC_UNKNOWN_CHECK }, + { "ZD Pot 5" , RC_UNKNOWN_CHECK }, + { "ZD In Front of King Zora Beehive 1" , RC_UNKNOWN_CHECK }, + { "ZD In Front of King Zora Beehive 2" , RC_UNKNOWN_CHECK }, + { "ZD Behind King Zora Beehive" , RC_ZD_BEHIND_KING_ZORA_BEEHIVE }, + { "ZF Bottom Green Rupee 1" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 2" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 3" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 4" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 5" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 6" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 7" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 8" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 9" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 10" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 11" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 12" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 13" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 14" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 15" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 16" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 17" , RC_UNKNOWN_CHECK }, + { "ZF Bottom Green Rupee 18" , RC_UNKNOWN_CHECK }, + { "ZF Hidden Cave Pot 1" , RC_ZF_HIDDEN_CAVE_POT_1 }, + { "ZF Hidden Cave Pot 2" , RC_ZF_HIDDEN_CAVE_POT_2 }, + { "ZF Hidden Cave Pot 3" , RC_ZF_HIDDEN_CAVE_POT_3 }, + { "ZF Near Jabu Pot 1" , RC_ZF_NEAR_JABU_POT_1 }, + { "ZF Near Jabu Pot 2" , RC_ZF_NEAR_JABU_POT_2 }, + { "ZF Near Jabu Pot 3" , RC_ZF_NEAR_JABU_POT_3 }, + { "ZF Near Jabu Pot 4" , RC_ZF_NEAR_JABU_POT_4 }, + { "LH Underwater Near Shore Green Rupee" , RC_UNKNOWN_CHECK }, + { "LH Underwater Green Rupee 1" , RC_UNKNOWN_CHECK }, + { "LH Underwater Green Rupee 2" , RC_UNKNOWN_CHECK }, + { "LH Lab Dive Red Rupee 1" , RC_UNKNOWN_CHECK }, + { "LH Lab Dive Red Rupee 2" , RC_UNKNOWN_CHECK }, + { "LH Lab Dive Red Rupee 3" , RC_UNKNOWN_CHECK }, + { "LH Grotto Beehive" , RC_LH_GROTTO_BEEHIVE }, + { "GV Octorok Grotto Red Rupee" , RC_GV_OCTOROK_GROTTO_RED_RUPEE }, + { "GV Octorok Grotto Blue Rupee 1" , RC_UNKNOWN_CHECK }, + { "GV Octorok Grotto Blue Rupee 2" , RC_UNKNOWN_CHECK }, + { "GV Octorok Grotto Blue Rupee 3" , RC_UNKNOWN_CHECK }, + { "GV Octorok Grotto Green Rupee 1" , RC_UNKNOWN_CHECK }, + { "GV Octorok Grotto Green Rupee 2" , RC_UNKNOWN_CHECK }, + { "GV Octorok Grotto Green Rupee 3" , RC_UNKNOWN_CHECK }, + { "GV Octorok Grotto Green Rupee 4" , RC_UNKNOWN_CHECK }, + { "GV Crate Near Cow" , RC_UNKNOWN_CHECK }, + { "GV Freestanding PoH Crate" , RC_UNKNOWN_CHECK }, + { "GV Storms Grotto Beehive" , RC_UNKNOWN_CHECK }, + { "GF Above Jail Crate" , RC_UNKNOWN_CHECK }, + { "Hideout Break Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Hideout Break Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Hideout 1 Torch Jail Pot 1" , RC_UNKNOWN_CHECK }, + { "Hideout 1 Torch Jail Pot 2" , RC_UNKNOWN_CHECK }, + { "Hideout 1 Torch Jail Pot 3" , RC_UNKNOWN_CHECK }, + { "Hideout Kitchen Pot 1" , RC_UNKNOWN_CHECK }, + { "Hideout Kitchen Pot 2" , RC_UNKNOWN_CHECK }, + { "Hideout 4 Torch Jail Pot 1" , RC_UNKNOWN_CHECK }, + { "Hideout 4 Torch Jail Pot 2" , RC_UNKNOWN_CHECK }, + { "Hideout 2 Torch Jail Pot 1" , RC_UNKNOWN_CHECK }, + { "Hideout 2 Torch Jail Pot 2" , RC_UNKNOWN_CHECK }, + { "Hideout 2 Torch Jail Pot 3" , RC_UNKNOWN_CHECK }, + { "Hideout 2 Torch Jail In Cell Pot 1" , RC_UNKNOWN_CHECK }, + { "Hideout 2 Torch Jail In Cell Pot 2" , RC_UNKNOWN_CHECK }, + { "Hideout 2 Torch Jail In Cell Pot 3" , RC_UNKNOWN_CHECK }, + { "Hideout 2 Torch Jail In Cell Pot 4" , RC_UNKNOWN_CHECK }, + { "Hideout Break Room Crate 1" , RC_UNKNOWN_CHECK }, + { "Hideout Break Room Crate 2" , RC_UNKNOWN_CHECK }, + { "Hideout Break Room Hallway Crate 1" , RC_UNKNOWN_CHECK }, + { "Hideout Break Room Hallway Crate 2" , RC_UNKNOWN_CHECK }, + { "Hideout 3 Torch Jail Crate" , RC_UNKNOWN_CHECK }, + { "Hideout 1 Torch Jail Crate" , RC_UNKNOWN_CHECK }, + { "Hideout Near Kitchen Crate 1" , RC_UNKNOWN_CHECK }, + { "Hideout Near Kitchen Crate 2" , RC_UNKNOWN_CHECK }, + { "Hideout Near Kitchen Crate 3" , RC_UNKNOWN_CHECK }, + { "Hideout Near Kitchen Crate 4" , RC_UNKNOWN_CHECK }, + { "Hideout Near Kitchen Crate 5" , RC_UNKNOWN_CHECK }, + { "Hideout 2 Torch Jail Crate 1" , RC_UNKNOWN_CHECK }, + { "Hideout 2 Torch Jail Crate 2" , RC_UNKNOWN_CHECK }, + { "Wasteland Near GS Pot 1" , RC_WASTELAND_NEAR_GS_POT_1 }, + { "Wasteland Near GS Pot 2" , RC_WASTELAND_NEAR_GS_POT_2 }, + { "Wasteland Near GS Pot 3" , RC_WASTELAND_NEAR_GS_POT_3 }, + { "Wasteland Crate Before Quicksand" , RC_UNKNOWN_CHECK }, + { "Wasteland Crate After Quicksand 1" , RC_UNKNOWN_CHECK }, + { "Wasteland Crate After Quicksand 2" , RC_UNKNOWN_CHECK }, + { "Wasteland Crate After Quicksand 3" , RC_UNKNOWN_CHECK }, + { "Wasteland Crate Near Colossus" , RC_UNKNOWN_CHECK }, + { "Colossus Grotto Beehive" , RC_COLOSSUS_GROTTO_BEEHIVE }, + { "Deku Tree Lower Lobby Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Deku Tree Upper Lobby Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Deku Tree Basement Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Deku Tree Basement Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Deku Tree Basement Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Deku Tree MQ Lower Lobby Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Deku Tree MQ Near Compass Room Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Deku Tree MQ Compass Room Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Deku Tree MQ Basement Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Deku Tree MQ Basement Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Deku Tree MQ Basement Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Deku Tree MQ Slingshot Room Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Deku Tree MQ Lobby Crate" , RC_UNKNOWN_CHECK }, + { "Deku Tree MQ Slingshot Room Crate 1" , RC_UNKNOWN_CHECK }, + { "Deku Tree MQ Slingshot Room Crate 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Lizalfos Upper Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Lizalfos Upper Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Blade Room Behind Block Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Right Side Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Right Side Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Right Side Pot 3" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Right Side Pot 4" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Right Side Pot 5" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Right Side Pot 6" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Lower Lizalfos Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Lower Lizalfos Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Lower Lizalfos Pot 3" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Lower Lizalfos Pot 4" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Torch Room Pot 1" , RC_DODONGOS_CAVERN_TORCH_ROOM_POT_1 }, + { "Dodongos Cavern Torch Room Pot 2" , RC_DODONGOS_CAVERN_TORCH_ROOM_POT_2 }, + { "Dodongos Cavern Torch Room Pot 3" , RC_DODONGOS_CAVERN_TORCH_ROOM_POT_3 }, + { "Dodongos Cavern Torch Room Pot 4" , RC_DODONGOS_CAVERN_TORCH_ROOM_POT_4 }, + { "Dodongos Cavern Staircase Pot 1" , RC_DODONGOS_CAVERN_STAIRCASE_POT_1 }, + { "Dodongos Cavern Staircase Pot 2" , RC_DODONGOS_CAVERN_STAIRCASE_POT_2 }, + { "Dodongos Cavern Staircase Pot 3" , RC_DODONGOS_CAVERN_STAIRCASE_POT_3 }, + { "Dodongos Cavern Staircase Pot 4" , RC_DODONGOS_CAVERN_STAIRCASE_POT_4 }, + { "Dodongos Cavern Last Block Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Last Block Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Last Block Pot 3" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Blade Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Blade Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Single Eye Switch Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Single Eye Switch Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Double Eye Switch Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Double Eye Switch Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Torch Puzzle Room Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Right Side Pot 1" , RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_1 }, + { "Dodongos Cavern MQ Right Side Pot 2" , RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_2 }, + { "Dodongos Cavern MQ Right Side Pot 3" , RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_3 }, + { "Dodongos Cavern MQ Right Side Pot 4" , RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_4 }, + { "Dodongos Cavern MQ Staircase Pot 1" , RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_1 }, + { "Dodongos Cavern MQ Staircase Pot 2" , RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_2 }, + { "Dodongos Cavern MQ Staircase Pot 3" , RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_3 }, + { "Dodongos Cavern MQ Staircase Pot 4" , RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_4 }, + { "Dodongos Cavern MQ Upper Lizalfos Pot 1" , RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_1 }, + { "Dodongos Cavern MQ Upper Lizalfos Pot 2" , RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_2 }, + { "Dodongos Cavern MQ Upper Lizalfos Pot 3" , RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_3 }, + { "Dodongos Cavern MQ Upper Lizalfos Pot 4" , RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_4 }, + { "Dodongos Cavern MQ Poes Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Pot 3" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Pot 4" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Room Before Boss Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Room Before Boss Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Armos Army Room Upper Pot" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Armos Army Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Armos Army Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Torch Puzzle Room Pot Pillar" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Torch Puzzle Room Pot Corner" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Before Upper Lizalfos Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Before Upper Lizalfos Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ After Upper Lizalfos Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ After Upper Lizalfos Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Back Poe Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Back Poe Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Staircase Crate Bottom Left" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Staircase Crate Bottom Right" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Staircase Crate Mid Left" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Staircase Crate Top Left" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Staircase Crate Mid Right" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Staircase Crate Top Right" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Crate 5" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Crate 6" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Crate 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Crate 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Crate 3" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Crate 4" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Crate Near Bomb Flower" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Poes Room Crate 7" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Larvae Room Crate 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Larvae Room Crate 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Larvae Room Crate 3" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Larvae Room Crate 4" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Larvae Room Crate 5" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ Larvae Room Crate 6" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ After Upper Lizalfos Crate 1" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern MQ After Upper Lizalfos Crate 2" , RC_UNKNOWN_CHECK }, + { "Dodongos Cavern Lower Lizalfos Hidden Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly Above Big Octo Pot 1" , RC_JABU_JABUS_BELLY_ABOVE_BIG_OCTO_POT_1 }, + { "Jabu Jabus Belly Above Big Octo Pot 2" , RC_JABU_JABUS_BELLY_ABOVE_BIG_OCTO_POT_2 }, + { "Jabu Jabus Belly Basement 2 Octoroks Pot 1" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly Basement 2 Octoroks Pot 2" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly Basement 2 Octoroks Pot 3" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly Basement 2 Octoroks Pot 4" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly Basement Switch Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly Basement Switch Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly Small Wooden Crate" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Underwater Green Rupee 1" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Underwater Green Rupee 2" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Underwater Green Rupee 3" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ First Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ First Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Elevator Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Elevator Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Falling Like Like Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Falling Like Like Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Boomerang Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly MQ Boomerang Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Jabu Jabus Belly Barinade Pot 1" , RC_JABU_JABUS_BELLY_BARINADE_POT_1 }, + { "Jabu Jabus Belly Barinade Pot 2" , RC_JABU_JABUS_BELLY_BARINADE_POT_2 }, + { "Jabu Jabus Belly Barinade Pot 3" , RC_JABU_JABUS_BELLY_BARINADE_POT_3 }, + { "Jabu Jabus Belly Barinade Pot 4" , RC_JABU_JABUS_BELLY_BARINADE_POT_4 }, + { "Jabu Jabus Belly Barinade Pot 5" , RC_JABU_JABUS_BELLY_BARINADE_POT_5 }, + { "Jabu Jabus Belly Barinade Pot 6" , RC_JABU_JABUS_BELLY_BARINADE_POT_6 }, + { "Bottom of the Well Center Room Pit Fall Blue Rupee 1" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well Center Room Pit Fall Blue Rupee 2" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well Center Room Pit Fall Blue Rupee 3" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well Center Room Pit Fall Blue Rupee 4" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well Center Room Pit Fall Blue Rupee 5" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well Coffin Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well Coffin Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well Left Side Pot 1" , RC_BOTTOM_OF_THE_WELL_LEFT_SIDE_POT_1 }, + { "Bottom of the Well Left Side Pot 2" , RC_BOTTOM_OF_THE_WELL_LEFT_SIDE_POT_2 }, + { "Bottom of the Well Left Side Pot 3" , RC_BOTTOM_OF_THE_WELL_LEFT_SIDE_POT_3 }, + { "Bottom of the Well Near Entrance Pot 1" , RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_1 }, + { "Bottom of the Well Near Entrance Pot 2" , RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_2 }, + { "Bottom of the Well Underwater Pot" , RC_BOTTOM_OF_THE_WELL_UNDERWATER_POT }, + { "Bottom of the Well Basement Pot 1" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_1 }, + { "Bottom of the Well Basement Pot 2" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_2 }, + { "Bottom of the Well Basement Pot 3" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_3 }, + { "Bottom of the Well Basement Pot 4" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_4 }, + { "Bottom of the Well Basement Pot 5" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_5 }, + { "Bottom of the Well Basement Pot 6" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_6 }, + { "Bottom of the Well Basement Pot 7" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_7 }, + { "Bottom of the Well Basement Pot 8" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_8 }, + { "Bottom of the Well Basement Pot 9" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_9 }, + { "Bottom of the Well Basement Pot 10" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_10 }, + { "Bottom of the Well Basement Pot 11" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_11 }, + { "Bottom of the Well Basement Pot 12" , RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_12 }, + { "Bottom of the Well Fire Keese Pot" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well West Inner Room Flying Pot 1" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well West Inner Room Flying Pot 2" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well West Inner Room Flying Pot 3" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ Bombable Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ Bombable Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ Basement Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ Basement Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ Basement Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ Coffin Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ Coffin Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ Center Room Right Pot 1" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ Center Room Right Pot 2" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ Center Room Right Pot 3" , RC_UNKNOWN_CHECK }, + { "Bottom of the Well MQ East Inner Room Pot 1" , RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_POT_1 }, + { "Bottom of the Well MQ East Inner Room Pot 2" , RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_POT_2 }, + { "Bottom of the Well MQ East Inner Room Pot 3" , RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_POT_3 }, + { "Forest Temple Courtyard Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple Courtyard Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple Well Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple Well Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple Center Room Right Pot 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple Center Room Right Pot 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple Center Room Right Pot 3" , RC_UNKNOWN_CHECK }, + { "Forest Temple Center Room Left Pot 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple Center Room Left Pot 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple Center Room Left Pot 3" , RC_UNKNOWN_CHECK }, + { "Forest Temple Lower Stalfos Pot" , RC_UNKNOWN_CHECK }, + { "Forest Temple Upper Stalfos Pot 1" , RC_FOREST_TEMPLE_UPPER_STALFOS_POT_1 }, + { "Forest Temple Upper Stalfos Pot 2" , RC_FOREST_TEMPLE_UPPER_STALFOS_POT_2 }, + { "Forest Temple Upper Stalfos Pot 3" , RC_FOREST_TEMPLE_UPPER_STALFOS_POT_3 }, + { "Forest Temple Upper Stalfos Pot 4" , RC_FOREST_TEMPLE_UPPER_STALFOS_POT_4 }, + { "Forest Temple Blue Poe Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple Blue Poe Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple Blue Poe Room Pot 3" , RC_UNKNOWN_CHECK }, + { "Forest Temple Frozen Eye Switch Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple Frozen Eye Switch Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple Green Poe Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple Green Poe Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Courtyard Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Courtyard Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Courtyard Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Well Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Well Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Well Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Center Room Right Pot 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Center Room Right Pot 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Center Room Right Pot 3" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Center Room Left Pot 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Center Room Left Pot 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Center Room Left Pot 3" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Wolfos Room Pot" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Upper Stalfos Pot 1" , RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_1 }, + { "Forest Temple MQ Upper Stalfos Pot 2" , RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_2 }, + { "Forest Temple MQ Upper Stalfos Pot 3" , RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_3 }, + { "Forest Temple MQ Upper Stalfos Pot 4" , RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_4 }, + { "Forest Temple MQ Blue Poe Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Blue Poe Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Blue Poe Room Pot 3" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Green Poe Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Green Poe Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Basement Pot 1" , RC_FOREST_TEMPLE_MQ_BASEMENT_POT_1 }, + { "Forest Temple MQ Basement Pot 2" , RC_FOREST_TEMPLE_MQ_BASEMENT_POT_2 }, + { "Forest Temple MQ Basement Pot 3" , RC_FOREST_TEMPLE_MQ_BASEMENT_POT_3 }, + { "Forest Temple MQ Basement Pot 4" , RC_FOREST_TEMPLE_MQ_BASEMENT_POT_4 }, + { "Forest Temple MQ Frozen Eye Switch Room Small Wooden Crate 1" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Frozen Eye Switch Room Small Wooden Crate 2" , RC_UNKNOWN_CHECK }, + { "Forest Temple MQ Frozen Eye Switch Room Small Wooden Crate 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple Elevator Room Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple Elevator Room Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple Elevator Room Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple Narrow Path Room Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple Narrow Path Room Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple Narrow Path Room Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple Moving Fire Room Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple Moving Fire Room Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple Moving Fire Room Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple Big Lava Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple Big Lava Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple Big Lava Room Pot 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple Near Boss Pot 1" , RC_FIRE_TEMPLE_NEAR_BOSS_POT_1 }, + { "Fire Temple Near Boss Pot 2" , RC_FIRE_TEMPLE_NEAR_BOSS_POT_2 }, + { "Fire Temple Flame Maze Right Side Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple Flame Maze Right Side Pot 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple Flame Maze Right Side Pot 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple Flame Maze Right Side Pot 4" , RC_UNKNOWN_CHECK }, + { "Fire Temple Flame Maze Left Side Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple Flame Maze Left Side Pot 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple Flame Maze Left Side Pot 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple Flame Maze Left Side Pot 4" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Elevator Room Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Elevator Room Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Elevator Room Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ First Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ First Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Big Lava Room Left Pot" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Big Lava Room Right Pot" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Big Lava Room Alcove Pot" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Near Boss Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Near Boss Pot 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Narrow Path Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Narrow Path Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Flame Maze Right Upper Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Flame Maze Right Upper Pot 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Flame Maze Right Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Flame Maze Right Pot 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Flame Maze Left Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shoot Torch On Wall Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shoot Torch On Wall Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Iron Knuckle Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Iron Knuckle Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Iron Knuckle Room Pot 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Iron Knuckle Room Pot 4" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Boss Key Chest Room Pot" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Near Boss Left Crate 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Near Boss Left Crate 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Near Boss Right Lower Crate 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Near Boss Right Lower Crate 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Near Boss Right Mid Crate" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Near Boss Right Upper Crate" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shortcut Crate 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shortcut Crate 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shortcut Crate 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shortcut Crate 4" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shortcut Crate 5" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shortcut Crate 6" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Lower Lizalfos Maze Crate 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Lower Lizalfos Maze Crate 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Lower Lizalfos Maze Crate 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Upper Lizalfos Maze Crate 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Upper Lizalfos Maze Crate 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Upper Lizalfos Maze Crate 3" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shoot Torch On Wall Room Right Crate 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shoot Torch On Wall Room Right Crate 2" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shoot Torch On Wall Room Center Crate" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shoot Torch On Wall Room Left Crate 1" , RC_UNKNOWN_CHECK }, + { "Fire Temple MQ Shoot Torch On Wall Room Left Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple River Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Water Temple River Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Water Temple River Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Water Temple River Recovery Heart 4" , RC_UNKNOWN_CHECK }, + { "Water Temple Main Room L2 Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple Main Room L2 Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple Behind Gate Pot 1" , RC_WATER_TEMPLE_BEHIND_GATE_POT_1 }, + { "Water Temple Behind Gate Pot 2" , RC_WATER_TEMPLE_BEHIND_GATE_POT_2 }, + { "Water Temple Behind Gate Pot 3" , RC_WATER_TEMPLE_BEHIND_GATE_POT_3 }, + { "Water Temple Behind Gate Pot 4" , RC_WATER_TEMPLE_BEHIND_GATE_POT_4 }, + { "Water Temple Near Compass Pot 1" , RC_WATER_TEMPLE_NEAR_COMPASS_POT_1 }, + { "Water Temple Near Compass Pot 2" , RC_WATER_TEMPLE_NEAR_COMPASS_POT_2 }, + { "Water Temple Near Compass Pot 3" , RC_WATER_TEMPLE_NEAR_COMPASS_POT_3 }, + { "Water Temple Like Like Pot 1" , RC_WATER_TEMPLE_LIKE_LIKE_POT_1 }, + { "Water Temple Like Like Pot 2" , RC_WATER_TEMPLE_LIKE_LIKE_POT_2 }, + { "Water Temple North Basement Block Puzzle Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple North Basement Block Puzzle Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple L1 Torch Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple L1 Torch Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple River Pot 1" , RC_WATER_TEMPLE_RIVER_POT_1 }, + { "Water Temple Central Bow Target Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple Central Bow Target Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Pot 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Pot 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Storage Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Storage Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Storage Room Pot 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Dark Link Top Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Dark Link Top Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Dark Link Lower Pot" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Room After Dark Link Pot" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Boss Key Chest Room Pot" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Pot 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dodongo Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dodongo Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Room Pot" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ L1 Torch Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ L1 Torch Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Pot 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Gate Pot 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Gate Pot 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ River Pot" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Upper Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Upper Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 5" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 6" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 7" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 8" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 9" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 10" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 11" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 12" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 13" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Central Pillar Lower Crate 14" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Submerged Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Submerged Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Submerged Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Submerged Crate 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Submerged Crate 5" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Submerged Crate 6" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Behind Gate Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Behind Gate Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Triple Wall Torch Behind Gate Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Storage Room Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Storage Room Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Storage Room Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Storage Room Crate 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Storage Room Crate 5" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Storage Room Crate 6" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Storage Room Crate 7" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dragon Statue By Torches Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dragon Statue By Torches Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dragon Statue Submerged Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dragon Statue Submerged Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dragon Statue Submerged Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dragon Statue Submerged Crate 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dragon Statue Near Door Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dragon Statue Near Door Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Boss Key Chest Room Upper Crate" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Boss Key Chest Room Lower Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Boss Key Chest Room Lower Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Boss Key Chest Room Lower Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Boss Key Chest Room Lower Crate 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Lower Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Lower Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Lower Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Lower Crate 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Lower Crate 5" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Lower Crate 6" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Upper Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Before Upper Water Switch Upper Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Behind Gate Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Behind Gate Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Behind Gate Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Behind Gate Crate 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Front Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Front Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Submerged Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Submerged Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Submerged Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Submerged Crate 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Submerged Crate 5" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Area Submerged Crate 6" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dodongo Room Lower Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dodongo Room Lower Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dodongo Room Lower Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dodongo Room Upper Crate" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Dodongo Room Hall Crate" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Room Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Room Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Room Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Room Crate 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Freestanding Key Room Crate 5" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Gate Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Gate Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Room Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Room Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Room Crate 3" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Room Crate 4" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Room Crate 5" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Hall Crate 1" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Hall Crate 2" , RC_UNKNOWN_CHECK }, + { "Water Temple MQ Lizalfos Hallway Hall Crate 3" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Invisible Blades Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Invisible Blades Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Before Boat Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Before Boat Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple After Boat Upper Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple After Boat Upper Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple After Boat Lower Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Shadow Temple 3 Spinning Pots Rupee 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple 3 Spinning Pots Rupee 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple 3 Spinning Pots Rupee 3" , RC_UNKNOWN_CHECK }, + { "Shadow Temple 3 Spinning Pots Rupee 4" , RC_UNKNOWN_CHECK }, + { "Shadow Temple 3 Spinning Pots Rupee 5" , RC_UNKNOWN_CHECK }, + { "Shadow Temple 3 Spinning Pots Rupee 6" , RC_UNKNOWN_CHECK }, + { "Shadow Temple 3 Spinning Pots Rupee 7" , RC_UNKNOWN_CHECK }, + { "Shadow Temple 3 Spinning Pots Rupee 8" , RC_UNKNOWN_CHECK }, + { "Shadow Temple 3 Spinning Pots Rupee 9" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Whispering Walls Near Dead Hand Pot" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Whispering Walls Left Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Whispering Walls Left Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Whispering Walls Left Pot 3" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Whispering Walls Front Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Whispering Walls Front Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Whispering Walls Flying Pot" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Map Chest Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Map Chest Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Falling Spikes Lower Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Falling Spikes Lower Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Falling Spikes Upper Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Falling Spikes Upper Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Spike Walls Pot" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Invisible Floormaster Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Invisible Floormaster Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple After Wind Pot 1" , RC_SHADOW_TEMPLE_AFTER_WIND_POT_1 }, + { "Shadow Temple After Wind Pot 2" , RC_SHADOW_TEMPLE_AFTER_WIND_POT_2 }, + { "Shadow Temple After Wind Flying Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple After Wind Flying Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple After Boat Pot" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Near Boss Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple Near Boss Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Invisible Blades Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Invisible Blades Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Before Boat Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Before Boat Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ After Boat Upper Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ After Boat Upper Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ After Boat Lower Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ 3 Spinning Pots Rupee 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ 3 Spinning Pots Rupee 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ 3 Spinning Pots Rupee 3" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ 3 Spinning Pots Rupee 4" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ 3 Spinning Pots Rupee 5" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ 3 Spinning Pots Rupee 6" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ 3 Spinning Pots Rupee 7" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ 3 Spinning Pots Rupee 8" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ 3 Spinning Pots Rupee 9" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Whispering Walls Pot 1" , RC_SHADOW_TEMPLE_MQ_WHISPERING_WALLS_POT_1 }, + { "Shadow Temple MQ Whispering Walls Pot 2" , RC_SHADOW_TEMPLE_MQ_WHISPERING_WALLS_POT_2 }, + { "Shadow Temple MQ Whispering Walls After Time Block Flying Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Whispering Walls After Time Block Flying Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Whispering Walls Before Time Block Flying Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Whispering Walls Before Time Block Flying Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Compass Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Compass Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Falling Spikes Lower Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Falling Spikes Lower Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Falling Spikes Upper Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Falling Spikes Upper Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ After Wind Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ After Wind Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ After Wind Flying Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ After Wind Flying Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ After Boat Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ After Boat Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Near Boss Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Near Boss Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Bomb Flower Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Bomb Flower Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Spike Walls Pot" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Truth Spinner Small Wooden Crate 1" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Truth Spinner Small Wooden Crate 2" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Truth Spinner Small Wooden Crate 3" , RC_UNKNOWN_CHECK }, + { "Shadow Temple MQ Truth Spinner Small Wooden Crate 4" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Shifting Wall Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Shifting Wall Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Child Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Child Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Lobby Pot 1" , RC_SPIRIT_TEMPLE_LOBBY_POT_1 }, + { "Spirit Temple Lobby Pot 2" , RC_SPIRIT_TEMPLE_LOBBY_POT_2 }, + { "Spirit Temple Lobby Flying Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Lobby Flying Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Child Climb Pot" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Hall After Sun Block Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Hall After Sun Block Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Beamos Hall Pot" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Child Anubis Pot" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Child Bridge Flying Pot" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Before Child Climb Small Wooden Crate 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Before Child Climb Small Wooden Crate 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Central Chamber Flying Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Central Chamber Flying Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Adult Climb Flying Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Adult Climb Flying Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Big Mirror Flying Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Big Mirror Flying Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Big Mirror Flying Pot 3" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Big Mirror Flying Pot 4" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Big Mirror Flying Pot 5" , RC_UNKNOWN_CHECK }, + { "Spirit Temple Big Mirror Flying Pot 6" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Lobby Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Lobby Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Lobby Pot 3" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Lobby Pot 4" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Child Torch Slugs Room Pot" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Child 3 Gibdo Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Child 3 Gibdo Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Child Stalfos Fight Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Child Stalfos Fight Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Child Stalfos Fight Pot 3" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Child Climb Pot" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Central Chamber Floor Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Central Chamber Floor Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Central Chamber Floor Pot 3" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Central Chamber Top Left Pot (Left)" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Central Chamber Top Left Pot (Right)" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Sun Block Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Sun Block Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Below 4 Wallmasters Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Below 4 Wallmasters Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Shifting Wall Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Shifting Wall Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ After Shifting Wall Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ After Shifting Wall Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Big Mirror Pot 1" , RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_1 }, + { "Spirit Temple MQ Big Mirror Pot 2" , RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_2 }, + { "Spirit Temple MQ Big Mirror Pot 3" , RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_3 }, + { "Spirit Temple MQ Big Mirror Pot 4" , RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_4 }, + { "Spirit Temple MQ Central Chamber Crate 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Central Chamber Crate 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Big Mirror Crate 1" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Big Mirror Crate 2" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Big Mirror Crate 3" , RC_UNKNOWN_CHECK }, + { "Spirit Temple MQ Big Mirror Crate 4" , RC_UNKNOWN_CHECK }, + { "Ice Cavern Frozen Blue Rupee" , RC_UNKNOWN_CHECK }, + { "Ice Cavern Map Room Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Ice Cavern Map Room Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Ice Cavern Map Room Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Ice Cavern Block Room Red Rupee 1" , RC_UNKNOWN_CHECK }, + { "Ice Cavern Block Room Red Rupee 2" , RC_UNKNOWN_CHECK }, + { "Ice Cavern Block Room Red Rupee 3" , RC_UNKNOWN_CHECK }, + { "Ice Cavern Hall Pot 1" , RC_ICE_CAVERN_HALL_POT_1 }, + { "Ice Cavern Hall Pot 2" , RC_ICE_CAVERN_HALL_POT_2 }, + { "Ice Cavern Spinning Blade Pot 1" , RC_ICE_CAVERN_SPINNING_BLADE_POT_1 }, + { "Ice Cavern Spinning Blade Pot 2" , RC_ICE_CAVERN_SPINNING_BLADE_POT_2 }, + { "Ice Cavern Spinning Blade Pot 3" , RC_ICE_CAVERN_SPINNING_BLADE_POT_3 }, + { "Ice Cavern Spinning Blade Flying Pot" , RC_UNKNOWN_CHECK }, + { "Ice Cavern Near End Pot 1" , RC_ICE_CAVERN_NEAR_END_POT_1 }, + { "Ice Cavern Near End Pot 2" , RC_ICE_CAVERN_NEAR_END_POT_2 }, + { "Ice Cavern Frozen Pot" , RC_UNKNOWN_CHECK }, + { "Ice Cavern MQ First Hall Pot" , RC_UNKNOWN_CHECK }, + { "Ice Cavern MQ Tektite Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Ice Cavern MQ Tektite Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Ice Cavern MQ Center Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Ice Cavern MQ Center Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Ice Cavern MQ Near End Pot" , RC_UNKNOWN_CHECK }, + { "Ice Cavern MQ Compass Room Pot 1" , RC_UNKNOWN_CHECK }, + { "Ice Cavern MQ Compass Room Pot 2" , RC_UNKNOWN_CHECK }, + { "Gerudo Training Ground Beamos Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Gerudo Training Ground Beamos Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Gerudo Training Ground MQ Lobby Left Pot 1" , RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_POT_1 }, + { "Gerudo Training Ground MQ Lobby Left Pot 2" , RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_POT_2 }, + { "Gerudo Training Ground MQ Lobby Right Pot 1" , RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_POT_1 }, + { "Gerudo Training Ground MQ Lobby Right Pot 2" , RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_POT_2 }, + { "Gerudo Training Ground MQ Maze Crate" , RC_UNKNOWN_CHECK }, + { "Ganons Castle Shadow Trial Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Ganons Castle Shadow Trial Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Ganons Castle Shadow Trial Recovery Heart 3" , RC_UNKNOWN_CHECK }, + { "Ganons Castle Fire Trial Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Ganons Castle Spirit Trial Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Ganons Castle Water Trial Pot 1" , RC_GANONS_CASTLE_WATER_TRIAL_POT_1 }, + { "Ganons Castle Water Trial Pot 2" , RC_GANONS_CASTLE_WATER_TRIAL_POT_2 }, + { "Ganons Castle Forest Trial Pot 1" , RC_GANONS_CASTLE_FOREST_TRIAL_POT_1 }, + { "Ganons Castle Forest Trial Pot 2" , RC_GANONS_CASTLE_FOREST_TRIAL_POT_2 }, + { "Ganons Castle Light Trial Boulder Pot" , RC_UNKNOWN_CHECK }, + { "Ganons Castle Light Trial Pot 1" , RC_GANONS_CASTLE_LIGHT_TRIAL_POT_1 }, + { "Ganons Castle Light Trial Pot 2" , RC_GANONS_CASTLE_LIGHT_TRIAL_POT_2 }, + { "Ganons Castle Shadow Trial Like Like Pot 1" , RC_UNKNOWN_CHECK }, + { "Ganons Castle Shadow Trial Like Like Pot 2" , RC_UNKNOWN_CHECK }, + { "Ganons Castle Shadow Trial Pot 1" , RC_GANONS_CASTLE_SHADOW_TRIAL_POT_1 }, + { "Ganons Castle Shadow Trial Pot 2" , RC_GANONS_CASTLE_SHADOW_TRIAL_POT_2 }, + { "Ganons Castle Fire Trial Pot 1" , RC_GANONS_CASTLE_FIRE_TRIAL_POT_1 }, + { "Ganons Castle Fire Trial Pot 2" , RC_GANONS_CASTLE_FIRE_TRIAL_POT_2 }, + { "Ganons Castle Spirit Trial Pot 1" , RC_GANONS_CASTLE_SPIRIT_TRIAL_POT_1 }, + { "Ganons Castle Spirit Trial Pot 2" , RC_GANONS_CASTLE_SPIRIT_TRIAL_POT_2 }, + { "Ganons Castle MQ Water Trial Recovery Heart" , RC_UNKNOWN_CHECK }, + { "Ganons Castle MQ Light Trial Recovery Heart 1" , RC_UNKNOWN_CHECK }, + { "Ganons Castle MQ Light Trial Recovery Heart 2" , RC_UNKNOWN_CHECK }, + { "Ganons Castle MQ Water Trial Pot 1" , RC_GANONS_CASTLE_MQ_WATER_TRIAL_POT_1 }, + { "Ganons Castle MQ Water Trial Pot 2" , RC_GANONS_CASTLE_MQ_WATER_TRIAL_POT_2 }, + { "Ganons Castle MQ Forest Trial Pot 1" , RC_GANONS_CASTLE_MQ_FOREST_TRIAL_POT_1 }, + { "Ganons Castle MQ Forest Trial Pot 2" , RC_GANONS_CASTLE_MQ_FOREST_TRIAL_POT_2 }, + { "Ganons Castle MQ Light Trial Pot 1" , RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_POT_1 }, + { "Ganons Castle MQ Light Trial Pot 2" , RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_POT_2 }, + { "Ganons Castle MQ Shadow Trial Pot 1" , RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_POT_1 }, + { "Ganons Castle MQ Shadow Trial Pot 2" , RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_POT_2 }, + { "Ganons Castle MQ Fire Trial Pot 1" , RC_GANONS_CASTLE_MQ_FIRE_TRIAL_POT_1 }, + { "Ganons Castle MQ Fire Trial Pot 2" , RC_GANONS_CASTLE_MQ_FIRE_TRIAL_POT_2 }, + { "Ganons Castle MQ Spirit Trial Pot 1" , RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_POT_1 }, + { "Ganons Castle MQ Spirit Trial Pot 2" , RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_POT_2 }, + { "Ganons Tower Pot 1" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 2" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 3" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 4" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 5" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 6" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 7" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 8" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 9" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 10" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 11" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 12" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 13" , RC_UNKNOWN_CHECK }, + { "Ganons Tower Pot 14" , RC_UNKNOWN_CHECK } +}; diff --git a/soh/soh/Enhancements/randomizer/archipelago_settings_window.h b/soh/soh/Enhancements/randomizer/archipelago_settings_window.h new file mode 100644 index 000000000..d9d69e12e --- /dev/null +++ b/soh/soh/Enhancements/randomizer/archipelago_settings_window.h @@ -0,0 +1,36 @@ +#pragma once +#ifndef ARCHIPELAGO_H +#define ARCHIPELAGO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif // ARCHIPELAGO_H + +#include + +#ifdef __cplusplus + +class ArchipelagoClient; + +class ArchipelagoWindow : public Ship::GuiWindow { + public: + using GuiWindow::GuiWindow; + + void InitElement() override {}; + void DrawElement() override; + void UpdateElement() override{}; + + private: + //std::shared_ptr #include @@ -335,6 +337,18 @@ void Context::ParseSpoiler(const char* spoilerFileName) { } } +void Context::ParseArchipelago() { + mSeedGenerated = false; + mSpoilerLoaded = false; + + ArchipelagoClient& ap_client = ArchipelagoClient::getInstance(); + ParseArchipelagoItemsLocations(ap_client.get_scouted_items()); + + // lets see if counting AP_loaded as spoiler loaded does the trick + mSpoilerLoaded = true; + mSeedGenerated = false; +} + void Context::ParseHashIconIndexesJson(nlohmann::json spoilerFileJson) { nlohmann::json hashJson = spoilerFileJson["file_hash"]; int index = 0; @@ -367,6 +381,25 @@ void Context::ParseItemLocationsJson(nlohmann::json spoilerFileJson) { } } +void Context::ParseArchipelagoItemsLocations(std::vector scouted_items) { + int playerId = AP_GetPlayerID(); // todo change me when the client is developed further + for(const AP_NetworkItem& ap_item: scouted_items) { + const RandomizerCheck rc = StaticData::APcheckToSoh.find(ap_item.locationName)->second; + if(playerId == ap_item.player) { + // our item + SPDLOG_TRACE("Populated item {} at location {}", ap_item.itemName, ap_item.locationName); + const RandomizerGet item = StaticData::APitemToSoh.find(ap_item.itemName)->second; + itemLocationTable[rc].SetPlacedItem(item); + } else { + // other player item + itemLocationTable[rc].SetPlacedItem(RG_RECOVERY_HEART); // Ap item doesn't work yet + //overrides[rc] = ItemOverride(rc, RG_ZELDAS_LETTER); + //std::string getText = ap_item.playerName + "'s " + ap_item.itemName; + //overrides[rc].SetTrickName(Text(getText, getText, getText)); + } + } +} + void Context::WriteHintJson(nlohmann::ordered_json& spoilerFileJson){ for (Hint hint: hintTable){ hint.logHint(spoilerFileJson); diff --git a/soh/soh/Enhancements/randomizer/context.h b/soh/soh/Enhancements/randomizer/context.h index 0fbb18748..f50ddf532 100644 --- a/soh/soh/Enhancements/randomizer/context.h +++ b/soh/soh/Enhancements/randomizer/context.h @@ -14,6 +14,9 @@ #include #include +// forward declarations +struct AP_NetworkItem; + /** * @brief Singleton for storing and accessing dynamic Randomizer-related data * @@ -120,6 +123,9 @@ class Context { bool allLocationsReachable = false; RandomizerArea GetAreaFromString(std::string str); + void ParseArchipelago(); + void ParseArchipelagoItemsLocations(const std::vector); + /** * @brief Get the hash for the current seed. * diff --git a/soh/soh/Enhancements/randomizer/fixed_string.hpp b/soh/soh/Enhancements/randomizer/fixed_string.hpp new file mode 100644 index 000000000..92876e5c1 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/fixed_string.hpp @@ -0,0 +1,682 @@ +/* + Licensed under the MIT License . + SPDX-License-Identifier: MIT + Copyright (c) 2020 - 2020 Daniil Dudkin. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#ifndef FIXED_STRING_HPP +#define FIXED_STRING_HPP + +#include +#include +#include +#include +#include +#include + +#define FIXSTR_VERSION_MAJOR 0 +#define FIXSTR_VERSION_MINOR 1 +#define FIXSTR_VERSION_PATCH 1 + +#define FIXSTR_CPP20_CHAR8T_PRESENT __cpp_char8_t +#define FIXSTR_CPP20_SPACESHIP_OPERATOR_PRESENT __cpp_lib_three_way_comparison + +#define FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT (__cpp_lib_constexpr_algorithms) + +#ifdef _MSC_VER +#define FIXSTR_CPP_VERSION _MSVC_LANG +#else +#define FIXSTR_CPP_VERSION __cplusplus +#endif // _MSC_VER + +// Note that when ICC or Clang is in use, FIXSTR_GCC_VERSION might not fully match the actual GCC version on the system. +#define FIXSTR_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +// According to clang documentation, version can be vendor specific +#define FIXSTR_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) + +#if FIXSTR_GCC_VERSION >= 100'000 && FIXSTR_CPP_VERSION > 201703L +#define FIXSTR_CPP20_CNTTP_PRESENT 1 +#elif __cpp_nontype_template_args >= 201911 +#define FIXSTR_CPP20_CNTTP_PRESENT 1 +#elif __cpp_nontype_template_parameter_class >= 201806 +#define FIXSTR_CPP20_CNTTP_PRESENT 1 +#else +// Other compilers do not support cNTTP just yet +#define FIXSTR_CPP20_CNTTP_PRESENT 0 +#endif // FIXSTR_CPP20_CNTTP_PRESENT + +namespace fixstr +{ + +namespace details +{ +template +constexpr OutputIterator copy(InputIterator first, InputIterator last, OutputIterator d_first) +{ +#if FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT + return std::copy(first, last, d_first); +#else + while (first != last) + { + *d_first++ = *first++; + } + return d_first; +#endif // FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT +} + +template +constexpr void fill(ForwardIterator first, ForwardIterator last, const T& value) +{ +#if FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT + std::fill(first, last, value); +#else + for (; first != last; ++first) + { + *first = value; + } +#endif // FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT +} + +} // namespace details + +template > +struct basic_fixed_string // NOLINT(cppcoreguidelines-special-member-functions) +{ + // exposition only + using storage_type = std::array; + storage_type _data{}; + + using traits_type = TTraits; + using value_type = TChar; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = typename storage_type::iterator; + using const_iterator = typename storage_type::const_iterator; + using reverse_iterator = typename storage_type::reverse_iterator; + using const_reverse_iterator = typename storage_type::const_reverse_iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; + using string_view_type = std::basic_string_view; + static constexpr auto npos = string_view_type::npos; + + constexpr basic_fixed_string() noexcept = default; + + constexpr basic_fixed_string(const value_type (&array)[N + 1]) noexcept // NOLINT(google-explicit-constructor) + { + details::copy(std::begin(array), std::end(array), _data.begin()); + } + + constexpr basic_fixed_string& operator=(const value_type (&array)[N + 1]) noexcept + { + details::copy(std::begin(array), std::end(array), _data.begin()); + return *this; + } + + // iterators + [[nodiscard]] constexpr iterator begin() noexcept { return _data.begin(); } + [[nodiscard]] constexpr const_iterator begin() const noexcept { return _data.begin(); } + [[nodiscard]] constexpr iterator end() noexcept { return _data.end() - 1; } + [[nodiscard]] constexpr const_iterator end() const noexcept { return _data.end() - 1; } + [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return _data.cbegin(); } + [[nodiscard]] constexpr const_iterator cend() const noexcept { return _data.cend() - 1; } + [[nodiscard]] constexpr reverse_iterator rbegin() noexcept { return _data.rbegin() + 1; } + [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return _data.rbegin() + 1; } + [[nodiscard]] constexpr reverse_iterator rend() noexcept { return _data.rend(); } + [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return _data.rend(); } + [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return _data.crbegin() + 1; } + [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return _data.crend(); } + + private: + [[nodiscard]] constexpr static bool static_empty() noexcept { return N == 0; } + + public: + // capacity + [[nodiscard]] constexpr size_type size() const noexcept { return N; } + [[nodiscard]] constexpr size_type length() const noexcept { return N; } + [[nodiscard]] constexpr size_type max_size() const noexcept { return N; } + [[nodiscard]] constexpr bool empty() const noexcept { return static_empty(); } + + // element access + [[nodiscard]] constexpr reference operator[](size_type n) { return _data[n]; } + [[nodiscard]] constexpr const_reference operator[](size_type n) const { return _data[n]; } + [[nodiscard]] constexpr reference at(size_type n) { return _data.at(n); } + [[nodiscard]] constexpr const_reference at(size_type n) const { return _data.at(n); } + + // The lack of C++20 concepts is disappointing + // Basically what every `template<...>` line means is `requires (!empty())` + template > + [[nodiscard]] constexpr reference front() noexcept + { + return _data.front(); + } + template > + [[nodiscard]] constexpr const_reference front() const noexcept + { + return _data.front(); + } + template > + [[nodiscard]] constexpr reference back() noexcept + { + return _data[size() - 1]; + } + template > + [[nodiscard]] constexpr const_reference back() const noexcept + { + return _data[size() - 1]; + } + + [[nodiscard]] constexpr pointer data() noexcept { return _data.data(); } + [[nodiscard]] constexpr const_pointer data() const noexcept { return _data.data(); } + + [[nodiscard]] constexpr const_pointer c_str() const noexcept { return data(); } + + private: + template + using same_with_other_size = basic_fixed_string; + + template + constexpr static size_type calculate_substr_size() + { + if constexpr (pos >= size) + return 0; + + constexpr size_type rcount = std::min(count, size - pos); + + return rcount; + } + + template + using substr_result_type = same_with_other_size()>; + + public: + // string operations + [[nodiscard]] constexpr operator string_view_type() const noexcept // NOLINT(google-explicit-constructor) + { + return {data(), N}; + } + + // clang-format off + template > + [[nodiscard]] constexpr auto substr() const noexcept + -> substr_result_type + // clang-format on + { + substr_result_type result; + details::copy(begin() + pos, begin() + pos + result.size(), result.begin()); + return result; + } + + template + [[nodiscard]] constexpr size_type find(const same_with_other_size& str, size_type pos = 0) const noexcept + { + if constexpr (M > N) + return npos; + return sv().find(str.sv(), pos); + } + [[nodiscard]] constexpr size_type find(string_view_type sv, size_type pos = 0) const noexcept { return sv().find(sv, pos); } + [[nodiscard]] constexpr size_type find(const value_type* s, size_type pos, size_type n) const { return sv().find(s, pos, n); } + [[nodiscard]] constexpr size_type find(const value_type* s, size_type pos = 0) const { return sv().find(s, pos); } + [[nodiscard]] constexpr size_type find(value_type c, size_type pos = 0) const noexcept { return sv().find(c, pos); } + + template + [[nodiscard]] constexpr size_type rfind(const same_with_other_size& str, size_type pos = npos) const noexcept + { + if constexpr (M > N) + return npos; + return sv().rfind(str.sv(), pos); + } + [[nodiscard]] constexpr size_type rfind(string_view_type sv, size_type pos = npos) const noexcept { return sv().rfind(sv, pos); } + [[nodiscard]] constexpr size_type rfind(const value_type* s, size_type pos, size_type n) const { return sv().rfind(s, pos, n); } + [[nodiscard]] constexpr size_type rfind(const value_type* s, size_type pos = npos) const { return sv().rfind(s, pos); } + [[nodiscard]] constexpr size_type rfind(value_type c, size_type pos = npos) const noexcept { return sv().rfind(c, pos); } + + template + [[nodiscard]] constexpr size_type find_first_of(const same_with_other_size& str, size_type pos = 0) const noexcept + { + if constexpr (M > N) + return npos; + return sv().find_first_of(str.sv(), pos); + } + [[nodiscard]] constexpr size_type find_first_of(string_view_type sv, size_type pos = 0) const noexcept { return sv().find_first_of(sv, pos); } + [[nodiscard]] constexpr size_type find_first_of(const value_type* s, size_type pos, size_type n) const { return sv().find_first_of(s, pos, n); } + [[nodiscard]] constexpr size_type find_first_of(const value_type* s, size_type pos = 0) const { return sv().find_first_of(s, pos); } + [[nodiscard]] constexpr size_type find_first_of(value_type c, size_type pos = 0) const noexcept { return sv().find_first_of(c, pos); } + + template + [[nodiscard]] constexpr size_type find_last_of(const same_with_other_size& str, size_type pos = npos) const noexcept + { + if constexpr (M > N) + return npos; + return sv().find_last_of(str.sv(), pos); + } + [[nodiscard]] constexpr size_type find_last_of(string_view_type sv, size_type pos = npos) const noexcept { return sv().find_last_of(sv, pos); } + [[nodiscard]] constexpr size_type find_last_of(const value_type* s, size_type pos, size_type n) const { return sv().find_last_of(s, pos, n); } + [[nodiscard]] constexpr size_type find_last_of(const value_type* s, size_type pos = npos) const { return sv().find_last_of(s, pos); } + [[nodiscard]] constexpr size_type find_last_of(value_type c, size_type pos = npos) const noexcept { return sv().find_last_of(c, pos); } + + template + [[nodiscard]] constexpr size_type find_first_not_of(const same_with_other_size& str, size_type pos = 0) const noexcept + { + if constexpr (M > N) + return npos; + return sv().find_first_of(str.sv(), pos); + } + [[nodiscard]] constexpr size_type find_first_not_of(string_view_type sv, size_type pos = 0) const noexcept { return sv().find_first_not_of(sv, pos); } + [[nodiscard]] constexpr size_type find_first_not_of(const value_type* s, size_type pos, size_type n) const { return sv().find_first_not_of(s, pos, n); } + [[nodiscard]] constexpr size_type find_first_not_of(const value_type* s, size_type pos = 0) const { return sv().find_first_not_of(s, pos); } + [[nodiscard]] constexpr size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept { return sv().find_first_not_of(c, pos); } + + template + [[nodiscard]] constexpr size_type find_last_not_of(const same_with_other_size& str, size_type pos = npos) const noexcept + { + if constexpr (M > N) + return npos; + return sv().find_last_of(str.sv(), pos); + } + [[nodiscard]] constexpr size_type find_last_not_of(string_view_type sv, size_type pos = npos) const noexcept { return sv().find_last_not_of(sv, pos); } + [[nodiscard]] constexpr size_type find_last_not_of(const value_type* s, size_type pos, size_type n) const { return sv().find_last_not_of(s, pos, n); } + [[nodiscard]] constexpr size_type find_last_not_of(const value_type* s, size_type pos = npos) const { return sv().find_last_not_of(s, pos); } + [[nodiscard]] constexpr size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept { return sv().find_last_not_of(c, pos); } + + [[nodiscard]] constexpr int compare(string_view_type v) const noexcept { return sv().compare(v); } + [[nodiscard]] constexpr int compare(size_type pos1, size_type count1, string_view_type v) const { return sv().compare(pos1, count1, v); } + [[nodiscard]] constexpr int compare(size_type pos1, size_type count1, string_view_type v, size_type pos2, size_type count2) const + { + return sv().compare(pos1, count1, v, pos2, count2); + } + [[nodiscard]] constexpr int compare(const value_type* s) const { return sv().compare(s); } + [[nodiscard]] constexpr int compare(size_type pos1, size_type count1, const value_type* s) const { return sv().compare(pos1, count1, s); } + [[nodiscard]] constexpr int compare(size_type pos1, size_type count1, const value_type* s, size_type count2) const + { + return sv().compare(pos1, count1, s, count2); + } + + [[nodiscard]] constexpr bool starts_with(string_view_type v) const noexcept { return sv().substr(0, v.size()) == v; } + [[nodiscard]] constexpr bool starts_with(char c) const noexcept { return !empty() && traits_type::eq(front(), c); } + [[nodiscard]] constexpr bool starts_with(const value_type* s) const noexcept { return starts_with(string_view_type(s)); } + + [[nodiscard]] constexpr bool ends_with(string_view_type sv) const noexcept { return size() >= sv.size() && compare(size() - sv.size(), npos, sv) == 0; } + [[nodiscard]] constexpr bool ends_with(value_type c) const noexcept { return !empty() && traits_type::eq(back(), c); } + [[nodiscard]] constexpr bool ends_with(const value_type* s) const { return ends_with(string_view_type(s)); } + + [[nodiscard]] constexpr bool contains(string_view_type sv) const noexcept { return find(sv) != npos; } + [[nodiscard]] constexpr bool contains(value_type c) const noexcept { return find(c) != npos; } + [[nodiscard]] constexpr bool contains(const value_type* s) const { return find(s) != npos; } + + void swap(basic_fixed_string& other) noexcept(std::is_nothrow_swappable_v) { _data.swap(other._data); } + + private: + constexpr string_view_type sv() const { return *this; } +}; + +template +void swap(basic_fixed_string& lhs, basic_fixed_string& rhs) noexcept(noexcept(lhs.swap(rhs))) +{ + lhs.swap(rhs); +} + +template +[[nodiscard]] constexpr bool operator==(const basic_fixed_string& lhs, const basic_fixed_string& rhs) +{ + if constexpr (M1 != M2) + return false; + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) == rhs; +} + +template +[[nodiscard]] constexpr bool operator==(const basic_fixed_string& lhs, std::basic_string_view rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) == rhs; +} + +template +[[nodiscard]] constexpr bool operator==(std::basic_string_view lhs, const basic_fixed_string& rhs) +{ + using rhs_type = std::decay_t; + using sv_type = typename rhs_type::string_view_type; + return lhs == static_cast(rhs); +} + +#if FIXSTR_CPP20_SPACESHIP_OPERATOR_PRESENT + +template +[[nodiscard]] constexpr auto operator<=>(const basic_fixed_string& lhs, const basic_fixed_string& rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) <=> rhs; +} + +template +[[nodiscard]] constexpr auto operator<=>(const basic_fixed_string& lhs, std::basic_string_view rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) <=> rhs; +} + +template +[[nodiscard]] constexpr auto operator<=>(std::basic_string_view lhs, const basic_fixed_string& rhs) +{ + using rhs_type = std::decay_t; + using sv_type = typename rhs_type::string_view_type; + return lhs <=> static_cast(rhs); +} + +#else + +template +[[nodiscard]] constexpr bool operator!=(const basic_fixed_string& lhs, const basic_fixed_string& rhs) +{ + if constexpr (M1 != M2) + return true; + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) != rhs; +} + +template +[[nodiscard]] constexpr bool operator!=(const basic_fixed_string& lhs, std::basic_string_view rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) != rhs; +} + +template +[[nodiscard]] constexpr bool operator!=(std::basic_string_view lhs, const basic_fixed_string& rhs) +{ + using rhs_type = std::decay_t; + using sv_type = typename rhs_type::string_view_type; + return lhs != static_cast(rhs); +} + +template +[[nodiscard]] constexpr bool operator<(const basic_fixed_string& lhs, const basic_fixed_string& rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) < rhs; +} + +template +[[nodiscard]] constexpr bool operator<(const basic_fixed_string& lhs, std::basic_string_view rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) < rhs; +} + +template +[[nodiscard]] constexpr bool operator<(std::basic_string_view lhs, const basic_fixed_string& rhs) +{ + using rhs_type = std::decay_t; + using sv_type = typename rhs_type::string_view_type; + return lhs < static_cast(rhs); +} + +template +[[nodiscard]] constexpr bool operator<=(const basic_fixed_string& lhs, const basic_fixed_string& rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) <= rhs; +} + +template +[[nodiscard]] constexpr bool operator<=(const basic_fixed_string& lhs, std::basic_string_view rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) <= rhs; +} + +template +[[nodiscard]] constexpr bool operator<=(std::basic_string_view lhs, const basic_fixed_string& rhs) +{ + using rhs_type = std::decay_t; + using sv_type = typename rhs_type::string_view_type; + return lhs <= static_cast(rhs); +} + +template +[[nodiscard]] constexpr bool operator>(const basic_fixed_string& lhs, const basic_fixed_string& rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) > rhs; +} + +template +[[nodiscard]] constexpr bool operator>(const basic_fixed_string& lhs, std::basic_string_view rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) > rhs; +} + +template +[[nodiscard]] constexpr bool operator>(std::basic_string_view lhs, const basic_fixed_string& rhs) +{ + using rhs_type = std::decay_t; + using sv_type = typename rhs_type::string_view_type; + return lhs > static_cast(rhs); +} + +template +[[nodiscard]] constexpr bool operator>=(const basic_fixed_string& lhs, const basic_fixed_string& rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) >= rhs; +} + +template +[[nodiscard]] constexpr bool operator>=(const basic_fixed_string& lhs, std::basic_string_view rhs) +{ + using lhs_type = std::decay_t; + using sv_type = typename lhs_type::string_view_type; + return static_cast(lhs) >= rhs; +} + +template +[[nodiscard]] constexpr bool operator>=(std::basic_string_view lhs, const basic_fixed_string& rhs) +{ + using rhs_type = std::decay_t; + using sv_type = typename rhs_type::string_view_type; + return lhs >= static_cast(rhs); +} + +#endif // FIXSTR_CPP20_SPACESHIP_OPERATOR_PRESENT + +template +basic_fixed_string(const TChar (&)[N]) -> basic_fixed_string; + +// Early GCC versions that support cNTTP were not able to deduce size_t parameter +// of basic_fixed_string when fixed_string and other typedef were just type aliases. +// That's why the following code is written in this way. +template +struct fixed_string : basic_fixed_string +{ + using basic_fixed_string::basic_fixed_string; +}; +template +fixed_string(const char (&)[N]) -> fixed_string; + +#if FIXSTR_CPP20_CHAR8T_PRESENT +template +struct fixed_u8string : basic_fixed_string +{ + using basic_fixed_string::basic_fixed_string; +}; +template +fixed_u8string(const char8_t (&)[N]) -> fixed_u8string; +#endif // FIXSTR_CPP20_CHAR8T_PRESENT + +template +struct fixed_u16string : basic_fixed_string +{ + using basic_fixed_string::basic_fixed_string; +}; +template +fixed_u16string(const char16_t (&)[N]) -> fixed_u16string; + +template +struct fixed_u32string : basic_fixed_string +{ + using basic_fixed_string::basic_fixed_string; +}; +template +fixed_u32string(const char32_t (&)[N]) -> fixed_u32string; + +template +struct fixed_wstring : basic_fixed_string +{ + using basic_fixed_string::basic_fixed_string; +}; +template +fixed_wstring(const wchar_t (&)[N]) -> fixed_wstring; + +template +constexpr basic_fixed_string operator+(const basic_fixed_string& lhs, const basic_fixed_string& rhs) +{ + basic_fixed_string result; + details::copy(lhs.begin(), lhs.end(), result.begin()); + details::copy(rhs.begin(), rhs.end(), result.begin() + N); + return result; +} + +template +constexpr basic_fixed_string operator+(const TChar (&lhs)[N], const basic_fixed_string& rhs) +{ + basic_fixed_string lhs2 = lhs; + return lhs2 + rhs; +} + +template +constexpr basic_fixed_string operator+(const basic_fixed_string& lhs, const TChar (&rhs)[M]) +{ + basic_fixed_string rhs2 = rhs; + return lhs + rhs2; +} + +namespace details +{ +template +constexpr basic_fixed_string from_char(TChar ch) +{ + basic_fixed_string fs; + fs[0] = ch; + return fs; +} +} // namespace details + +template +constexpr basic_fixed_string operator+(TChar lhs, const basic_fixed_string& rhs) +{ + return details::from_char(lhs) + rhs; +} + +template +constexpr basic_fixed_string operator+(const basic_fixed_string& lhs, TChar rhs) +{ + return lhs + details::from_char(rhs); +} + +template +std::basic_ostream& operator<<(std::basic_ostream& out, const basic_fixed_string& str) +{ + out << str.data(); + return out; +} + +} // namespace fixstr + +// hash support +namespace std +{ +template +struct hash> +{ + using argument_type = fixstr::fixed_string; + size_t operator()(const argument_type& str) const + { + using sv_t = typename argument_type::string_view_type; + return std::hash()(static_cast(str)); + } +}; + +#if FIXSTR_CPP20_CHAR8T_PRESENT +template +struct hash> +{ + using argument_type = fixstr::fixed_u8string; + size_t operator()(const argument_type& str) const + { + using sv_t = typename argument_type::string_view_type; + return std::hash()(static_cast(str)); + } +}; +#endif // FIXSTR_CPP20_CHAR8T_PRESENT + +template +struct hash> +{ + using argument_type = fixstr::fixed_u16string; + size_t operator()(const argument_type& str) const + { + using sv_t = typename argument_type::string_view_type; + return std::hash()(static_cast(str)); + } +}; + +template +struct hash> +{ + using argument_type = fixstr::fixed_u32string; + size_t operator()(const argument_type& str) const + { + using sv_t = typename argument_type::string_view_type; + return std::hash()(static_cast(str)); + } +}; + +template +struct hash> +{ + using argument_type = fixstr::fixed_wstring; + size_t operator()(const argument_type& str) const + { + using sv_t = typename argument_type::string_view_type; + return std::hash()(static_cast(str)); + } +}; + +} // namespace std + +#endif // FIXED_STRING_HPP diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp index 0b94aab39..ea01565b7 100644 --- a/soh/soh/Enhancements/randomizer/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/item_list.cpp @@ -392,6 +392,9 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_MAGIC_DOUBLE] = Item(RG_MAGIC_DOUBLE, Text{ "Enhanced Magic Meter", "Jauge de Magie améliorée", "Verbessertes Magisches Maß" }, ITEMTYPE_ITEM, 0x8A, true, LOGIC_PROGRESSIVE_MAGIC, RHT_MAGIC_DOUBLE, RG_MAGIC_DOUBLE, OBJECT_GI_MAGICPOT, GID_MAGIC_LARGE, 0xE8, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); itemTable[RG_TRIFORCE_PIECE] = Item(RG_TRIFORCE_PIECE, Text{ "Triforce Piece", "Triforce Piece", "Triforce-Fragment" }, ITEMTYPE_ITEM, 0xDF, true, LOGIC_TRIFORCE_PIECES, RHT_TRIFORCE_PIECE, RG_TRIFORCE_PIECE, OBJECT_GI_BOMB_2, GID_TRIFORCE_PIECE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + // Archipelago + itemTable[RG_ARCHIPELAGO_ITEM] = /* doesn't work :P*/ Item(RG_ARCHIPELAGO_ITEM, Text{"AP Item", "AP Item", "AP_Item"}, ITEMTYPE_ITEM, GI_RUPEE_GREEN, false, LOGIC_NONE, RHT_NONE, RG_ARCHIPELAGO_ITEM, OBJECT_GI_LETTER, GID_LETTER_ZELDA, TEXT_RANDOMIZER_CUSTOM_ITEM, 0, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE); + // Init itemNameToEnum for (auto& item : itemTable) { // Easiest way to filter out all the empty values from the array, since we still technically want the 0/RG_NONE diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 66128d50f..9dd085f6c 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -3392,6 +3392,7 @@ typedef enum { RG_BACK_TOWER_KEY, RG_HYLIA_LAB_KEY, RG_FISHING_HOLE_KEY, + RG_ARCHIPELAGO_ITEM, // Logic Only RG_DISTANT_SCARECROW, RG_STICKS, diff --git a/soh/soh/Enhancements/randomizer/static_data.cpp b/soh/soh/Enhancements/randomizer/static_data.cpp index 84da0d3c1..a0ed4d5ef 100644 --- a/soh/soh/Enhancements/randomizer/static_data.cpp +++ b/soh/soh/Enhancements/randomizer/static_data.cpp @@ -1,6 +1,7 @@ #include #include "static_data.h" #include +#include "archipelago_mappings.h" namespace Rando { @@ -302,4 +303,34 @@ std::unordered_map StaticData::grottoChestParamsToHint{ }; std::array StaticData::hintTextTable = {}; + +const std::unordered_mapgenerate_APitemToSoh_mapping() { + std::unordered_map mapping; + for(const auto& pairing : ap_item_mapping_pairs) { + mapping[pairing.first] = pairing.second; + } + return mapping; +} + +const std::unordered_mapgenerate_APcheckToSoh_mapping() { + std::unordered_map mapping; + for(const auto& pairing : ap_check_mapping_pairs) { + mapping[pairing.first] = pairing.second; + } + return mapping; +} + +const std::unordered_mapgenerate_SohcheckToAP_mapping() { + std::unordered_map mapping; + for(const auto& pairing : ap_check_mapping_pairs) { + mapping[pairing.second] = pairing.first; + } + return mapping; +} + +std::unordered_map StaticData::APitemToSoh = generate_APitemToSoh_mapping(); +std::unordered_map StaticData::APcheckToSoh = generate_APcheckToSoh_mapping(); +std::unordered_map StaticData::SohCheckToAP = generate_SohcheckToAP_mapping(); + + } diff --git a/soh/soh/Enhancements/randomizer/static_data.h b/soh/soh/Enhancements/randomizer/static_data.h index 4a516d72f..bbf83de00 100644 --- a/soh/soh/Enhancements/randomizer/static_data.h +++ b/soh/soh/Enhancements/randomizer/static_data.h @@ -69,6 +69,10 @@ class StaticData { static std::unordered_map grottoChestParamsToHint; static std::array hintTextTable; + static std::unordered_map APitemToSoh; + static std::unordered_map APcheckToSoh; + static std::unordered_map SohCheckToAP; + StaticData(); ~StaticData(); }; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 9bc33593d..0c4bc77e3 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2468,4 +2468,8 @@ void SoH_ProcessDroppedFiles(std::string filePath) { return; } } + +extern "C" void parse_archipelago() { + OTRGlobals::Instance->gRandoContext->ParseArchipelago(); +} // #endregion diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index f056cad5e..cab8e86a3 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -156,6 +156,7 @@ void CheckTracker_OnMessageClose(); GetItemID RetrieveGetItemIDFromItemID(ItemID itemID); RandomizerGet RetrieveRandomizerGetFromItemID(ItemID itemID); +void parse_archipelago(); #endif #ifdef __cplusplus diff --git a/soh/soh/SohGui.cpp b/soh/soh/SohGui.cpp index f91f263c9..4d406ac96 100644 --- a/soh/soh/SohGui.cpp +++ b/soh/soh/SohGui.cpp @@ -129,6 +129,7 @@ namespace SohGui { std::shared_ptr mItemTrackerWindow; std::shared_ptr mTimeSplitWindow; std::shared_ptr mPlandomizerWindow; + std::shared_ptr mArchipelagoWindow; std::shared_ptr mRandomizerSettingsWindow; std::shared_ptr mAdvancedResolutionSettingsWindow; std::shared_ptr mModalWindow; @@ -212,6 +213,8 @@ namespace SohGui { gui->AddGuiWindow(mTimeSplitWindow); mPlandomizerWindow = std::make_shared(CVAR_WINDOW("PlandomizerWindow"), "Plandomizer Editor", ImVec2(850, 760)); gui->AddGuiWindow(mPlandomizerWindow); + mArchipelagoWindow = std::make_shared(CVAR_WINDOW("ArchipelagoWindow"), "Archipelago", ImVec2(850, 760)); + gui->AddGuiWindow(mArchipelagoWindow); mAdvancedResolutionSettingsWindow = std::make_shared(CVAR_WINDOW("AdvancedResolutionEditor"), "Advanced Resolution Settings", ImVec2(497, 599)); gui->AddGuiWindow(mAdvancedResolutionSettingsWindow); mModalWindow = std::make_shared(CVAR_WINDOW("ModalWindow"), "Modal Window"); @@ -259,6 +262,7 @@ namespace SohGui { mInputViewerSettings = nullptr; mTimeSplitWindow = nullptr; mPlandomizerWindow = nullptr; + mArchipelagoWindow = nullptr; mTimeDisplayWindow = nullptr; mAboutWindow = nullptr; } diff --git a/soh/soh/SohGui.hpp b/soh/soh/SohGui.hpp index 526db64bf..e07b7d8ca 100644 --- a/soh/soh/SohGui.hpp +++ b/soh/soh/SohGui.hpp @@ -26,6 +26,7 @@ #include "Enhancements/randomizer/randomizer_settings_window.h" #include "Enhancements/timesplits/TimeSplits.h" #include "Enhancements/randomizer/Plandomizer.h" +#include "Enhancements/randomizer/archipelago.h" #include "AboutWindow.h" #include "SohModals.h" diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 250106530..83bbe9730 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -43,6 +43,7 @@ #include "Enhancements/enemyrandomizer.h" #include "Enhancements/timesplits/TimeSplits.h" #include "Enhancements/randomizer/Plandomizer.h" +#include "Enhancements/randomizer/archipelago.h" #include "Enhancements/TimeDisplay/TimeDisplay.h" #include "AboutWindow.h" @@ -2134,6 +2135,7 @@ void DrawRemoteControlMenu() { extern std::shared_ptr mRandomizerSettingsWindow; extern std::shared_ptr mPlandomizerWindow; +extern std::shared_ptr mArchipelagoWindow; extern std::shared_ptr mItemTrackerWindow; extern std::shared_ptr mItemTrackerSettingsWindow; extern std::shared_ptr mEntranceTrackerWindow; @@ -2175,6 +2177,14 @@ void DrawRandomizerMenu() { } } + UIWidgets::Spacer(0); + + if (mArchipelagoWindow) { + if (ImGui::Button(GetWindowButtonText("Archipelago", CVarGetInteger(CVAR_WINDOW("ArchipelagoWindow"), 0)).c_str(), buttonSize)) { + mArchipelagoWindow->ToggleVisibility(); + } + } + UIWidgets::Spacer(0); if (mItemTrackerWindow) { diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 6b2d0546f..e18eb305f 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -1005,6 +1005,7 @@ void DrawSeedHashSprites(FileChooseContext* this) { u8 generating; int retries = 0; bool fileSelectSpoilerFileLoaded = false; +bool fileSelectarchipelagoloaded = false; void FileChoose_UpdateRandomizer() { if (CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0) != 0 && generating == 0) { @@ -1045,6 +1046,13 @@ void FileChoose_UpdateRandomizer() { remove(fileLoc); } } + + if (CVarGetInteger("archipelago_connected", 0) != 0 + && !fileSelectarchipelagoloaded) { + parse_archipelago(); + fileSelectarchipelagoloaded = true; + Audio_PlayFanfare(NA_BGM_HORSE_GOAL); + } } static s16 sLastFileChooseButtonIndex; @@ -3711,6 +3719,7 @@ void FileChoose_Init(GameState* thisx) { this->questType[1] = MIN_QUEST; this->questType[2] = MIN_QUEST; fileSelectSpoilerFileLoaded = false; + fileSelectarchipelagoloaded = false; CVarSetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0); SREG(30) = 1; From 51be4612542f7a7a7fec3a37bd247b9d33ab8cf5 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Wed, 5 Feb 2025 21:22:43 +0100 Subject: [PATCH 02/11] added APCpp submodule --- APCpp | 1 + 1 file changed, 1 insertion(+) create mode 160000 APCpp diff --git a/APCpp b/APCpp new file mode 160000 index 000000000..c671d9355 --- /dev/null +++ b/APCpp @@ -0,0 +1 @@ +Subproject commit c671d935530a544e83e65836e79499f54b734b95 From ea2e718c06fd5e7e72cd957d396ffd9e8b301d5e Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Mon, 10 Feb 2025 20:58:38 +0100 Subject: [PATCH 03/11] Added some basic Item recieving from server, not thoroughly tested yet --- APCpp | 2 +- .../Enhancements/randomizer/archipelago.cpp | 61 ++++++++++++++++--- soh/soh/Enhancements/randomizer/archipelago.h | 21 ++++++- soh/soh/Enhancements/randomizer/context.cpp | 29 ++++++++- soh/soh/Enhancements/randomizer/context.h | 3 + .../Enhancements/randomizer/hook_handlers.cpp | 33 +++++++++- soh/soh/Enhancements/randomizer/item_list.cpp | 2 +- .../Enhancements/randomizer/item_location.cpp | 2 + .../Enhancements/randomizer/randomizer.cpp | 8 ++- .../Enhancements/randomizer/randomizerTypes.h | 4 +- 10 files changed, 145 insertions(+), 20 deletions(-) diff --git a/APCpp b/APCpp index c671d9355..38d5cf079 160000 --- a/APCpp +++ b/APCpp @@ -1 +1 @@ -Subproject commit c671d935530a544e83e65836e79499f54b734b95 +Subproject commit 38d5cf0798fb4134b0414ad680a0c2798d0bc311 diff --git a/soh/soh/Enhancements/randomizer/archipelago.cpp b/soh/soh/Enhancements/randomizer/archipelago.cpp index 07d763fc4..bcbc615e6 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.cpp +++ b/soh/soh/Enhancements/randomizer/archipelago.cpp @@ -8,6 +8,8 @@ #include #include "fixed_string.hpp" +#include "randomizerTypes.h" +#include "static_data.h" //extern "C" { // #include "include/z64item.h" @@ -33,6 +35,8 @@ auto SubscribeToSlotData() { } ArchipelagoClient::ArchipelagoClient() { + ItemRecievedCallback = nullptr; + namespace apc = AP_Client_consts; CVarSetInteger("archipelago_connected", 0); strncpy(server_address, CVarGetString(apc::SETTING_ADDRESS, apc::DEFAULT_SERVER_NAME), apc::MAX_ADDRESS_LENGTH); @@ -183,6 +187,30 @@ void ArchipelagoClient::save_data() { CVarSetString(AP_Client_consts::SETTING_NAME, slot_name); } +bool ArchipelagoClient::isConnected() { + return AP_GetConnectionStatus() == AP_ConnectionStatus::Authenticated; +} + +void ArchipelagoClient::check_location(RandomizerCheck SoH_check_id) { + std::string_view ap_name = Rando::StaticData::SohCheckToAP[SoH_check_id]; + int64_t ap_item_id = CheckNameToId(std::string(ap_name)); + SPDLOG_TRACE("Checked: {}({}), sending to AP server", ap_name, ap_item_id); + +// currently not sending, because i only get so many real chances + if(!isConnected()) { + return; + } + AP_SendItem(ap_item_id); +} + +void ArchipelagoClient::addItemRecievedCallback(std::function callback) { + ItemRecievedCallback = callback; +} + +void ArchipelagoClient::removeItemRecievedCallback(std::function old_callback) { + ItemRecievedCallback = nullptr; +} + void ArchipelagoClient::on_connected() { // todo implement me SPDLOG_TRACE("AP Connected!!"); @@ -197,7 +225,14 @@ void ArchipelagoClient::on_clear_items() { } void ArchipelagoClient::on_item_recieved(int64_t recieved_item_id, bool notify_player) { - // todo implement me + // call each callback + SPDLOG_TRACE("Trying to give rupie..."); + std::string item_name = getAPitemName(recieved_item_id); + ArchipelagoClient& ap_client = ArchipelagoClient::getInstance(); + if(ap_client.ItemRecievedCallback) { + SPDLOG_TRACE("Giving Rupie! {}", item_name); + ap_client.ItemRecievedCallback.operator()(item_name); // somehow passing it through the itemname breaks it???? + } } void ArchipelagoClient::on_location_checked(int64_t location_id) { @@ -237,21 +272,23 @@ void ArchipelagoWindow::ArchipelagoDrawConnectPage() { ImGui::InputText("Slot Name", AP_client.get_slot_name_buff(), AP_Client_consts::MAX_PLAYER_NAME_LENGHT); ImGui::InputText("Password (leave blank for no password)", AP_client.get_password_buff(), AP_Client_consts::MAX_PASSWORD_LENGTH, ImGuiInputTextFlags_Password); - char connected_text[25] = "Disconnected"; + static char connected_text[25] = "Disconnected"; if(ImGui::Button("Connect")) { bool success = AP_client.start_client(); - if(success) { - strncpy(connected_text, "Connected!", 25); - SPDLOG_TRACE("Connected!!"); - } - else { - strncpy(connected_text, "Connection failed!", 25); - SPDLOG_TRACE("Connection failed :("); - } } ImGui::SameLine(); ImGui::Text(connected_text); + AP_ConnectionStatus con_status = AP_GetConnectionStatus(); + if(con_status == AP_ConnectionStatus::Connected) { + strncpy(connected_text, "Connected!", 25); + } else if(con_status == AP_ConnectionStatus::Authenticated) { + strncpy(connected_text, "Authenticated!", 25); + } + else { + strncpy(connected_text, "Not Connected", 25); + } + if(ImGui::Button("scout")) { AP_client.start_location_scouts(); } @@ -265,4 +302,8 @@ void ArchipelagoWindow::ArchipelagoDrawConnectPage() { void ArchipelagoWindow::DrawElement() { ArchipelagoDrawConnectPage(); UIWidgets::PaddedSeparator(); + + if(ImGui::Button("give blue ruppie")) { + ArchipelagoClient::getInstance().on_item_recieved(66077, true); + } }; \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/archipelago.h b/soh/soh/Enhancements/randomizer/archipelago.h index cbaad2348..9310b656d 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.h +++ b/soh/soh/Enhancements/randomizer/archipelago.h @@ -3,6 +3,11 @@ #include "fixed_string.hpp" +#include "randomizerTypes.h" +#include "static_data.h" +#include + + namespace AP_Client_consts { static constexpr int MAX_ADDRESS_LENGTH = 64; static constexpr int MAX_PLAYER_NAME_LENGHT = 17; @@ -30,6 +35,19 @@ class ArchipelagoClient { const std::vector& get_scouted_items(); void add_slot_data(std::string_view key, int id); + + //void add_slot_data(std::string_view key, int id); + + bool isConnected(); + void check_location(RandomizerCheck SoH_check_id); + + // callback slots + void addItemRecievedCallback(std::function callback); + void removeItemRecievedCallback(std::function old_callback); + + + // todo move me back down when done testing + static void on_item_recieved(int64_t recieved_item_id, bool notify_player); protected: ArchipelagoClient(); @@ -56,12 +74,13 @@ class ArchipelagoClient { static void on_connected(); static void on_couldntConnect(AP_ConnectionStatus connection_status); static void on_clear_items(); - static void on_item_recieved(int64_t recieved_item_id, bool notify_player); + static void on_location_checked(int64_t location_id); static void on_deathlink_recieved() { }; // TODO: implement me static void on_location_scouted(std::vector network_items); // callbacks + std::function ItemRecievedCallback; }; diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp index 9d4aba779..fa5f083b6 100644 --- a/soh/soh/Enhancements/randomizer/context.cpp +++ b/soh/soh/Enhancements/randomizer/context.cpp @@ -271,6 +271,30 @@ void Context::SetSpoilerLoaded(const bool spoilerLoaded) { mSpoilerLoaded = spoilerLoaded; } +void Context::AddRecievedArchipelagoItem(const std::string& ap_item_id) { + mAPrecieveQueue.emplace(ap_item_id); + SPDLOG_TRACE("Item Pushed {}", ap_item_id); +} + +GetItemEntry Context::GetArchipelagoGIEntry() { + SPDLOG_TRACE("Trying to get Item Entry"); + if(mAPrecieveQueue.empty()) { + // something must have gone wrong here, just give a rupee + return ItemTableManager::Instance->RetrieveItemEntry(MOD_NONE, GI_HEART); + } + + // get the first item from the archipelago queue + std::string_view recieved_ap_item = mAPrecieveQueue.front(); + RandomizerGet item_id = StaticData::APitemToSoh[recieved_ap_item]; + assert(item_id != RG_NONE); + + Item& item = StaticData::RetrieveItem(item_id); + SPDLOG_TRACE("Found item! {}, {}", recieved_ap_item, (int)item_id); + GetItemEntry item_entry = item.GetGIEntry_Copy(); + mAPrecieveQueue.pop(); + return item_entry; // todo: add custom text maybe? +} + GetItemEntry Context::GetFinalGIEntry(const RandomizerCheck rc, const bool checkObtainability, const GetItemID ogItemId) { const auto itemLoc = GetItemLocation(rc); if (itemLoc->GetPlacedRandomizerGet() == RG_NONE) { @@ -392,8 +416,9 @@ void Context::ParseArchipelagoItemsLocations(std::vector scouted itemLocationTable[rc].SetPlacedItem(item); } else { // other player item - itemLocationTable[rc].SetPlacedItem(RG_RECOVERY_HEART); // Ap item doesn't work yet - //overrides[rc] = ItemOverride(rc, RG_ZELDAS_LETTER); + itemLocationTable[rc].SetPlacedItem(RG_ARCHIPELAGO_ITEM); + // i'll have to figure out custom names at some point, this currently does nothing + //overrides[rc] = ItemOverride(rc, RG_DEKU_NUTS_5); //std::string getText = ap_item.playerName + "'s " + ap_item.itemName; //overrides[rc].SetTrickName(Text(getText, getText, getText)); } diff --git a/soh/soh/Enhancements/randomizer/context.h b/soh/soh/Enhancements/randomizer/context.h index f50ddf532..c308de715 100644 --- a/soh/soh/Enhancements/randomizer/context.h +++ b/soh/soh/Enhancements/randomizer/context.h @@ -107,6 +107,8 @@ class Context { */ RandoOptionLACSCondition LACSCondition() const; GetItemEntry GetFinalGIEntry(RandomizerCheck rc, bool checkObtainability = true, GetItemID ogItemId = GI_NONE); + void AddRecievedArchipelagoItem(const std::string& ap_item_id); + GetItemEntry GetArchipelagoGIEntry(); void ParseSpoiler(const char* spoilerFileName); void ParseHashIconIndexesJson(nlohmann::json spoilerFileJson); void ParseItemLocationsJson(nlohmann::json spoilerFileJson); @@ -186,5 +188,6 @@ class Context { std::string mHash; std::string mSeedString; uint32_t mFinalSeed = 0; + std::queue mAPrecieveQueue = {}; }; } // namespace Rando \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index cc9708789..b33ed267a 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -16,6 +16,7 @@ #include "soh/Notification/Notification.h" #include "soh/SaveManager.h" #include "soh/Enhancements/randomizer/ShuffleFairies.h" +#include "archipelago.h" extern "C" { #include "macros.h" @@ -215,6 +216,12 @@ static std::queue randomizerQueuedChecks; static RandomizerCheck randomizerQueuedCheck = RC_UNKNOWN_CHECK; static GetItemEntry randomizerQueuedItemEntry = GET_ITEM_NONE; +void ArchipelagoOnRecieveItem(const std::string& ap_item_id) { + SPDLOG_TRACE("Recieve item handler called! {}", ap_item_id); + randomizerQueuedChecks.push(RC_ARCHIPELAGO_RECIEVED_ITEM); + Rando::Context::GetInstance()->AddRecievedArchipelagoItem(ap_item_id); +} + void RandomizerOnFlagSetHandler(int16_t flagType, int16_t flag) { // Consume adult trade items if (RAND_GET_OPTION(RSK_SHUFFLE_ADULT_TRADE) && flagType == FLAG_RANDOMIZER_INF) { @@ -271,11 +278,17 @@ void RandomizerOnPlayerUpdateForRCQueueHandler() { return; } + GetItemEntry getItemEntry; RandomizerCheck rc = randomizerQueuedChecks.front(); auto loc = Rando::Context::GetInstance()->GetItemLocation(rc); - RandomizerGet vanillaRandomizerGet = Rando::StaticData::GetLocation(rc)->GetVanillaItem(); - GetItemID vanillaItem = (GetItemID)Rando::StaticData::RetrieveItem(vanillaRandomizerGet).GetItemID(); - GetItemEntry getItemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(rc, true, (GetItemID)vanillaRandomizerGet); + if(rc == RC_ARCHIPELAGO_RECIEVED_ITEM) { + getItemEntry = Rando::Context::GetInstance()->GetArchipelagoGIEntry(); + } else { + RandomizerGet vanillaRandomizerGet = Rando::StaticData::GetLocation(rc)->GetVanillaItem(); + GetItemID vanillaItem = (GetItemID)Rando::StaticData::RetrieveItem(vanillaRandomizerGet).GetItemID(); + getItemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(rc, true, (GetItemID)vanillaRandomizerGet); + } + SPDLOG_TRACE("RC found!"); if (loc->HasObtained()) { SPDLOG_INFO("RC {} already obtained, skipping", static_cast(rc)); @@ -331,9 +344,19 @@ void RandomizerOnPlayerUpdateForItemQueueHandler() { void RandomizerOnItemReceiveHandler(GetItemEntry receivedItemEntry) { if (randomizerQueuedCheck == RC_UNKNOWN_CHECK) return; + SPDLOG_TRACE("Dropped into recieve handler!"); + auto loc = Rando::Context::GetInstance()->GetItemLocation(randomizerQueuedCheck); if (randomizerQueuedItemEntry.modIndex == receivedItemEntry.modIndex && randomizerQueuedItemEntry.itemId == receivedItemEntry.itemId) { SPDLOG_INFO("Item received mod {} item {} from RC {}", receivedItemEntry.modIndex, receivedItemEntry.itemId, static_cast(randomizerQueuedCheck)); + + // todo maybe move to seperate function + // let arhipelago know we got this check + if(randomizerQueuedCheck != RC_ARCHIPELAGO_RECIEVED_ITEM) { + ArchipelagoClient& ap_client = ArchipelagoClient::getInstance(); + ap_client.check_location(randomizerQueuedCheck); + } + loc->SetCheckStatus(RCSHOW_COLLECTED); CheckTracker::SpoilAreaFromCheck(randomizerQueuedCheck); CheckTracker::RecalculateAllAreaTotals(); @@ -2406,6 +2429,8 @@ void RandomizerRegisterHooks() { GameInteractor::Instance->UnregisterGameHook(shuffleFreestandingOnVanillaBehaviorHook); + ArchipelagoClient::getInstance().removeItemRecievedCallback(ArchipelagoOnRecieveItem); + onFlagSetHook = 0; onSceneFlagSetHook = 0; onPlayerUpdateForRCQueueHook = 0; @@ -2486,5 +2511,7 @@ void RandomizerRegisterHooks() { if (RAND_GET_OPTION(RSK_SHUFFLE_FAIRIES)) { ShuffleFairies_RegisterHooks(); } + + ArchipelagoClient::getInstance().addItemRecievedCallback(ArchipelagoOnRecieveItem); }); } diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp index ea01565b7..16e413050 100644 --- a/soh/soh/Enhancements/randomizer/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/item_list.cpp @@ -393,7 +393,7 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_TRIFORCE_PIECE] = Item(RG_TRIFORCE_PIECE, Text{ "Triforce Piece", "Triforce Piece", "Triforce-Fragment" }, ITEMTYPE_ITEM, 0xDF, true, LOGIC_TRIFORCE_PIECES, RHT_TRIFORCE_PIECE, RG_TRIFORCE_PIECE, OBJECT_GI_BOMB_2, GID_TRIFORCE_PIECE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); // Archipelago - itemTable[RG_ARCHIPELAGO_ITEM] = /* doesn't work :P*/ Item(RG_ARCHIPELAGO_ITEM, Text{"AP Item", "AP Item", "AP_Item"}, ITEMTYPE_ITEM, GI_RUPEE_GREEN, false, LOGIC_NONE, RHT_NONE, RG_ARCHIPELAGO_ITEM, OBJECT_GI_LETTER, GID_LETTER_ZELDA, TEXT_RANDOMIZER_CUSTOM_ITEM, 0, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE); + itemTable[RG_ARCHIPELAGO_ITEM] = Item(RG_ARCHIPELAGO_ITEM, Text{"AP Item", "AP Item", "AP Item"}, ITEMTYPE_EVENT, GI_RUPEE_GREEN, false, LOGIC_NONE, RHT_NONE, RG_ARCHIPELAGO_ITEM, OBJECT_GI_LETTER, GID_LETTER_ZELDA, TEXT_RANDOMIZER_CUSTOM_ITEM, 0, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_RANDOMIZER); // Init itemNameToEnum for (auto& item : itemTable) { diff --git a/soh/soh/Enhancements/randomizer/item_location.cpp b/soh/soh/Enhancements/randomizer/item_location.cpp index 00e0366ab..94ca6be6c 100644 --- a/soh/soh/Enhancements/randomizer/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/item_location.cpp @@ -130,6 +130,8 @@ bool ItemLocation::HasObtained() const { } void ItemLocation::SetCheckStatus(RandomizerCheckStatus status_) { + if(rc == RC_ARCHIPELAGO_RECIEVED_ITEM) // never count the AP recieve trigger as 'collected' + return; status = status_; } diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 477c2f0da..5632c3fab 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3332,7 +3332,7 @@ CustomMessage Randomizer::GetGoronMessage(u16 index) { void Randomizer::CreateCustomMessages() { // RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED // with GIMESSAGE(getItemID, itemID, english, german, french). - const std::array getItemMessages = {{ + const std::array getItemMessages = {{ GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON, "You found %gGreg%w!", "%gGreg%w! Du hast ihn wirklich gefunden!", @@ -3767,6 +3767,7 @@ void Randomizer::CreateCustomMessages() { GIMESSAGE_NO_GERMAN(RG_DEKU_NUT_BAG, ITEM_NUT, "You found the %rDeku Nut Bag%w!&You can now hold deku nuts!", "Vous avez trouvé le %rSac de Noix Mojo%w!&Vous pouvez maintenant porter des Noix Mojo!"), + GIMESSAGE_NO_GERMAN(RG_ARCHIPELAGO_ITEM, ITEM_BEAN, "You found an %rAP_ITEM%w", "Je m'apelle not %rNot Translated%w"), }}; CreateGetItemMessages(&getItemMessages); CreateRupeeMessages(); @@ -3881,6 +3882,11 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { return Return_Item_Entry(giEntry, RG_NONE); } + //if it's an archipelago item, don't give anything + if(item == RG_ARCHIPELAGO_ITEM) { + return Return_Item_Entry(giEntry, RG_NONE); + } + //bottle items if (item >= RG_BOTTLE_WITH_RED_POTION && item <= RG_BOTTLE_WITH_BIG_POE) { for (u16 i = 0; i < 4; i++) { diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 9dd085f6c..d3685b664 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -13,7 +13,8 @@ // which doesn't exist yet. typedef enum { MOD_NONE, - MOD_RANDOMIZER + MOD_RANDOMIZER, + MOD_ARCHIPELAGO // no actually used yet i think } ModIndex; typedef enum { TABLE_VANILLA = MOD_NONE, @@ -2848,6 +2849,7 @@ typedef enum { RC_SHADOW_TEMPLE_MQ_WIND_HINT_SUN_FAIRY, RC_BOTTOM_OF_THE_WELL_MQ_CELL_SUN_FAIRY, RC_BOTTOM_OF_THE_WELL_MQ_BASEMENT_SUN_FAIRY, + RC_ARCHIPELAGO_RECIEVED_ITEM, RC_MAX } RandomizerCheck; From 61563fadba016053496a6c07c275b12c28f4338f Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Mon, 3 Mar 2025 21:24:59 +0100 Subject: [PATCH 04/11] Added some of the settings, loaded from the server, implemented game win condition (pretty untested) --- APCpp | 2 +- README.md | 15 ++- soh/soh/Enhancements/mods.cpp | 2 + .../Enhancements/randomizer/archipelago.cpp | 108 ++++++++++-------- soh/soh/Enhancements/randomizer/archipelago.h | 4 + soh/soh/Enhancements/randomizer/context.cpp | 15 ++- soh/soh/Enhancements/randomizer/context.h | 3 +- .../Enhancements/randomizer/randomizer.cpp | 2 + soh/soh/Enhancements/randomizer/settings.cpp | 90 +++++++++++++++ soh/soh/Enhancements/randomizer/settings.h | 2 + .../Enhancements/randomizer/static_data.cpp | 78 ++++++++++++- soh/soh/Enhancements/randomizer/static_data.h | 2 +- .../Enhancements/timesplits/TimeSplits.cpp | 2 + 13 files changed, 268 insertions(+), 57 deletions(-) diff --git a/APCpp b/APCpp index 38d5cf079..505a174a3 160000 --- a/APCpp +++ b/APCpp @@ -1 +1 @@ -Subproject commit 38d5cf0798fb4134b0414ad680a0c2798d0bc311 +Subproject commit 505a174a3b0f55f71f69e221d23003b223836fd7 diff --git a/README.md b/README.md index 128af0a73..40b5c669d 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,21 @@ ## Fork Overview -Currently playing around trying to see if we're able to hook the existing Archipelago Ocarina of time randomizer into Ship of Harkinian. +This Repo serves as a proof of concept for SoH to connect to Archipellago, the current implementation tries to implement the existing OoT AP world. +Mainly to check out the SoH Repo and to have something to develop against while the others on the discord are working on an AP world for SoH. + +I'm not entierly happy with this implementation, but I'd like to create a bespoke Client to connect to AP with instead of relying on the current 3rd party clien't I've just thrown in to try out. + You can currently connect to the multiworld server, scout the items. -If you have no randomizer genereted (the `Randomizer` folder is empty) and press the `Link up` button, you'll be able to start a randomizer save file +If you have no randomizer genereted (the `Randomizer` folder is empty) `Connect` to the multiworld from the main screen, click the `Scout` button to load all of the item locations and finally press the `Link up` button, you'll be able to start a randomizer save file. with the items populated with the location from the server. -Sending and recieving is not implemented yet, Multiworld items are currently just recovery hearts +Sending and Recieving should be implemented, Saving the game doesn't save the current item index localy (the library is a bit anoying with that). + +Not all checks have been mapped, and some may be mapped incorrectly. +The victory condition should be implemented but has largely gone untested. +Results may varry + ## Website diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index c5b59eac7..76a3fade2 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -41,6 +41,7 @@ #include "objects/object_link_child/object_link_child.h" #include "soh_assets.h" #include "kaleido.h" +#include "soh/Enhancements/randomizer/archipelago.h" extern "C" { #include @@ -876,6 +877,7 @@ void RegisterBossDefeatTimestamps() { case ACTOR_BOSS_GANON2: gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME; gSaveContext.ship.stats.gameComplete = true; + ArchipelagoClient::getInstance().send_game_won(); break; case ACTOR_BOSS_GANONDROF: gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_PHANTOM_GANON] = GAMEPLAYSTAT_TOTAL_TIME; diff --git a/soh/soh/Enhancements/randomizer/archipelago.cpp b/soh/soh/Enhancements/randomizer/archipelago.cpp index bcbc615e6..b14df700b 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.cpp +++ b/soh/soh/Enhancements/randomizer/archipelago.cpp @@ -36,6 +36,7 @@ auto SubscribeToSlotData() { ArchipelagoClient::ArchipelagoClient() { ItemRecievedCallback = nullptr; + game_won = false; namespace apc = AP_Client_consts; CVarSetInteger("archipelago_connected", 0); @@ -64,71 +65,71 @@ void registerSlotCallbacks() { SubscribeToSlotData<"bridge_medallions">(); SubscribeToSlotData<"bridge_rewards">(); SubscribeToSlotData<"bridge_tokens">(); - SubscribeToSlotData<"bridge_hearts">(); +// SubscribeToSlotData<"bridge_hearts">(); SubscribeToSlotData<"shuffle_ganon_bosskey">(); SubscribeToSlotData<"ganon_bosskey_medallions">(); SubscribeToSlotData<"ganon_bosskey_stones">(); SubscribeToSlotData<"ganon_bosskey_rewards">(); SubscribeToSlotData<"ganon_bosskey_tokens">(); - SubscribeToSlotData<"ganon_bosskey_hearts">(); +// SubscribeToSlotData<"ganon_bosskey_hearts">(); SubscribeToSlotData<"trials">(); SubscribeToSlotData<"triforce_hunt">(); SubscribeToSlotData<"triforce_goal">(); - SubscribeToSlotData<"extra_triforce_percentage">(); - SubscribeToSlotData<"shopsanity">(); - SubscribeToSlotData<"shop_slots">(); +// SubscribeToSlotData<"extra_triforce_percentage">(); +// SubscribeToSlotData<"shopsanity">(); +// SubscribeToSlotData<"shop_slots">(); SubscribeToSlotData<"shopsanity_prices">(); - SubscribeToSlotData<"tokensanity">(); - SubscribeToSlotData<"dungeon_shortcuts">(); - SubscribeToSlotData<"mq_dungeons_mode">(); - SubscribeToSlotData<"mq_dungeons_count">(); - SubscribeToSlotData<"shuffle_interior_entrances">(); - SubscribeToSlotData<"shuffle_grotto_entrances">(); - SubscribeToSlotData<"shuffle_dungeon_entrances">(); - SubscribeToSlotData<"shuffle_overworld_entrances">(); - SubscribeToSlotData<"shuffle_bosses">(); - SubscribeToSlotData<"key_rings">(); - SubscribeToSlotData<"enhance_map_compass">(); - SubscribeToSlotData<"shuffle_mapcompass">(); - SubscribeToSlotData<"shuffle_smallkeys">(); - SubscribeToSlotData<"shuffle_hideoutkeys">(); - SubscribeToSlotData<"shuffle_bosskeys">(); - SubscribeToSlotData<"logic_rules">(); - SubscribeToSlotData<"logic_no_night_tokens_without_suns_song">(); - SubscribeToSlotData<"warp_songs">(); - SubscribeToSlotData<"shuffle_song_items">(); - SubscribeToSlotData<"shuffle_medigoron_carpet_salesman">(); - SubscribeToSlotData<"shuffle_frog_song_rupees">(); - SubscribeToSlotData<"shuffle_scrubs">(); - SubscribeToSlotData<"shuffle_child_trade">(); - SubscribeToSlotData<"shuffle_freestanding_items">(); - SubscribeToSlotData<"shuffle_pots">(); - SubscribeToSlotData<"shuffle_crates">(); - SubscribeToSlotData<"shuffle_cows">(); - SubscribeToSlotData<"shuffle_beehives">(); - SubscribeToSlotData<"shuffle_kokiri_sword">(); - SubscribeToSlotData<"shuffle_ocarinas">(); - SubscribeToSlotData<"shuffle_gerudo_card">(); - SubscribeToSlotData<"shuffle_beans">(); +// SubscribeToSlotData<"tokensanity">(); +// SubscribeToSlotData<"dungeon_shortcuts">(); +// SubscribeToSlotData<"mq_dungeons_mode">(); +// SubscribeToSlotData<"mq_dungeons_count">(); +// SubscribeToSlotData<"shuffle_interior_entrances">(); +// SubscribeToSlotData<"shuffle_grotto_entrances">(); +// SubscribeToSlotData<"shuffle_dungeon_entrances">(); +// SubscribeToSlotData<"shuffle_overworld_entrances">(); +// SubscribeToSlotData<"shuffle_bosses">(); +// SubscribeToSlotData<"key_rings">(); +// SubscribeToSlotData<"enhance_map_compass">(); +// SubscribeToSlotData<"shuffle_mapcompass">(); +// SubscribeToSlotData<"shuffle_smallkeys">(); +// SubscribeToSlotData<"shuffle_hideoutkeys">(); +// SubscribeToSlotData<"shuffle_bosskeys">(); +// SubscribeToSlotData<"logic_rules">(); +// SubscribeToSlotData<"logic_no_night_tokens_without_suns_song">(); +// SubscribeToSlotData<"warp_songs">(); +// SubscribeToSlotData<"shuffle_song_items">(); +// SubscribeToSlotData<"shuffle_medigoron_carpet_salesman">(); +// SubscribeToSlotData<"shuffle_frog_song_rupees">(); +// SubscribeToSlotData<"shuffle_scrubs">(); +// SubscribeToSlotData<"shuffle_child_trade">(); +// SubscribeToSlotData<"shuffle_freestanding_items">(); +// SubscribeToSlotData<"shuffle_pots">(); +// SubscribeToSlotData<"shuffle_crates">(); +// SubscribeToSlotData<"shuffle_cows">(); +// SubscribeToSlotData<"shuffle_beehives">(); +// SubscribeToSlotData<"shuffle_kokiri_sword">(); +// SubscribeToSlotData<"shuffle_ocarinas">(); +// SubscribeToSlotData<"shuffle_gerudo_card">(); +// SubscribeToSlotData<"shuffle_beans">(); SubscribeToSlotData<"starting_age">(); - SubscribeToSlotData<"bombchus_in_logic">(); - SubscribeToSlotData<"spawn_positions">(); - SubscribeToSlotData<"owl_drops">(); +// SubscribeToSlotData<"bombchus_in_logic">(); +// SubscribeToSlotData<"spawn_positions">(); +// SubscribeToSlotData<"owl_drops">(); SubscribeToSlotData<"no_epona_race">(); - SubscribeToSlotData<"skip_some_minigame_phases">(); +// SubscribeToSlotData<"skip_some_minigame_phases">(); SubscribeToSlotData<"complete_mask_quest">(); SubscribeToSlotData<"free_scarecrow">(); - SubscribeToSlotData<"plant_beans">(); +// SubscribeToSlotData<"plant_beans">(); SubscribeToSlotData<"chicken_count">(); SubscribeToSlotData<"big_poe_count">(); - SubscribeToSlotData<"fae_torch_count">(); +// SubscribeToSlotData<"fae_torch_count">(); SubscribeToSlotData<"blue_fire_arrows">(); SubscribeToSlotData<"damage_multiplier">(); - SubscribeToSlotData<"deadly_bonks">(); - SubscribeToSlotData<"starting_tod">(); - SubscribeToSlotData<"junk_ice_traps">(); +// SubscribeToSlotData<"deadly_bonks">(); +// SubscribeToSlotData<"starting_tod">(); +// SubscribeToSlotData<"junk_ice_traps">(); SubscribeToSlotData<"start_with_consumables">(); - SubscribeToSlotData<"adult_trade_start">(); +// SubscribeToSlotData<"adult_trade_start">(); } bool ArchipelagoClient::start_client() { @@ -193,6 +194,9 @@ bool ArchipelagoClient::isConnected() { void ArchipelagoClient::check_location(RandomizerCheck SoH_check_id) { std::string_view ap_name = Rando::StaticData::SohCheckToAP[SoH_check_id]; + if(ap_name.empty()) { + return; + } int64_t ap_item_id = CheckNameToId(std::string(ap_name)); SPDLOG_TRACE("Checked: {}({}), sending to AP server", ap_name, ap_item_id); @@ -226,11 +230,10 @@ void ArchipelagoClient::on_clear_items() { void ArchipelagoClient::on_item_recieved(int64_t recieved_item_id, bool notify_player) { // call each callback - SPDLOG_TRACE("Trying to give rupie..."); std::string item_name = getAPitemName(recieved_item_id); ArchipelagoClient& ap_client = ArchipelagoClient::getInstance(); if(ap_client.ItemRecievedCallback) { - SPDLOG_TRACE("Giving Rupie! {}", item_name); + SPDLOG_TRACE("item recieved: {}, notify: {}", item_name, notify_player); ap_client.ItemRecievedCallback.operator()(item_name); // somehow passing it through the itemname breaks it???? } } @@ -246,6 +249,13 @@ void ArchipelagoClient::on_location_scouted(std::vector network_ getInstance().scouted_items = network_items; } +void ArchipelagoClient::send_game_won() { + if(!game_won) { + AP_StoryComplete(); + game_won = true; + } +} + char* ArchipelagoClient::get_server_address_buff() { return server_address; } diff --git a/soh/soh/Enhancements/randomizer/archipelago.h b/soh/soh/Enhancements/randomizer/archipelago.h index 9310b656d..8f4487b9a 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.h +++ b/soh/soh/Enhancements/randomizer/archipelago.h @@ -49,6 +49,8 @@ class ArchipelagoClient { // todo move me back down when done testing static void on_item_recieved(int64_t recieved_item_id, bool notify_player); + void send_game_won(); + protected: ArchipelagoClient(); @@ -62,6 +64,8 @@ class ArchipelagoClient { char slot_name[AP_Client_consts::MAX_PLAYER_NAME_LENGHT]; char password[AP_Client_consts::MAX_PLAYER_NAME_LENGHT]; + bool game_won; + std::map slot_data; std::set locations; std::vector scouted_items; diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp index fa5f083b6..3e700c1cb 100644 --- a/soh/soh/Enhancements/randomizer/context.cpp +++ b/soh/soh/Enhancements/randomizer/context.cpp @@ -366,6 +366,7 @@ void Context::ParseArchipelago() { mSpoilerLoaded = false; ArchipelagoClient& ap_client = ArchipelagoClient::getInstance(); + Rando::Settings::GetInstance()->ParseArchipelago(ap_client.get_slot_data()); ParseArchipelagoItemsLocations(ap_client.get_scouted_items()); // lets see if counting AP_loaded as spoiler loaded does the trick @@ -383,6 +384,7 @@ void Context::ParseHashIconIndexesJson(nlohmann::json spoilerFileJson) { } void Context::ParseItemLocationsJson(nlohmann::json spoilerFileJson) { + // first fill all the items with their vanilla location nlohmann::json locationsJson = spoilerFileJson["locations"]; for (auto it = locationsJson.begin(); it != locationsJson.end(); ++it) { RandomizerCheck rc = StaticData::locationNameToEnum[it.key()]; @@ -405,10 +407,21 @@ void Context::ParseItemLocationsJson(nlohmann::json spoilerFileJson) { } } -void Context::ParseArchipelagoItemsLocations(std::vector scouted_items) { +void Context::ParseArchipelagoItemsLocations(const std::vector& scouted_items) { int playerId = AP_GetPlayerID(); // todo change me when the client is developed further + + // init the item table with regular items first + for(int rc = 1; rc <= RC_MAX; rc++) { + itemLocationTable[rc].SetPlacedItem(StaticData::GetLocation(static_cast(rc))->GetVanillaItem()); + } + for(const AP_NetworkItem& ap_item: scouted_items) { const RandomizerCheck rc = StaticData::APcheckToSoh.find(ap_item.locationName)->second; + + if(rc == RC_KF_MIDOS_TOP_RIGHT_CHEST) { + continue; + } + if(playerId == ap_item.player) { // our item SPDLOG_TRACE("Populated item {} at location {}", ap_item.itemName, ap_item.locationName); diff --git a/soh/soh/Enhancements/randomizer/context.h b/soh/soh/Enhancements/randomizer/context.h index c308de715..6f63b3a4d 100644 --- a/soh/soh/Enhancements/randomizer/context.h +++ b/soh/soh/Enhancements/randomizer/context.h @@ -126,7 +126,8 @@ class Context { RandomizerArea GetAreaFromString(std::string str); void ParseArchipelago(); - void ParseArchipelagoItemsLocations(const std::vector); + void ParseArchipelagoSettings(const std::map& slot_data); + void ParseArchipelagoItemsLocations(const std::vector& slot_data); /** * @brief Get the hash for the current seed. diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 5632c3fab..10e3c625e 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -39,6 +39,7 @@ #include "soh/util.h" #include "fishsanity.h" #include "randomizerTypes.h" +#include "archipelago.h" extern std::map rcAreaNames; @@ -4109,6 +4110,7 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { if (gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected == (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1)) { gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED] = GAMEPLAYSTAT_TOTAL_TIME; gSaveContext.ship.stats.gameComplete = 1; + ArchipelagoClient::getInstance().send_game_won(); Flags_SetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY); Play_PerformSave(play); GameInteractor_SetTriforceHuntCreditsWarpActive(true); diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 2ca325635..df7c3cb50 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -2226,6 +2226,96 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { } } +void Settings::ParseArchipelago(const std::map& slot_data) { + for(const auto& slot_it : slot_data) { + const std::string& APname = slot_it.first; + int value = slot_it.second; + + // remap value if needed + if(APname == "open_forest") { + if(value == 0) { // open and closed options swapped + value = 2; + } else if (value == 2) { + value = 0; + } + } + if(APname == "open_kakoriko") { + if(value == 2) { + value = 0; // closed + } else { + value = 1; // count the "zelda" option as open + } + } + else if(APname == "open_door_of_time") { + if(value == 1) { + value = 2; // AP doesn't have the song only option + } + } + else if(APname == "zora_fountain") { + if(value == 0) { // open and closed options swapped + value = 2; + } else if (value == 2) { + value = 0; + } + } + else if(APname == "bridge") { + if(value == 0) { // always open and vanilla are swapped + value = 1; + } else if (value == 1) { + value = 0; + } else if (value == 6) { // no support for ap hearts option + value = 1; // revert to always open so its at least beatable + } else if (value == 5) { + value++; // Token option is one over, because AP doesn't have dungeon blue warp count as option + } + } + else if(APname == "shopsanity_prices") { + value = 1; // default shopsanity to cheap ballanced for now + } + else if(APname == "start_with_consumables") { // just setting this shouldn't magically work I think + if(value == 1) { + const RandomizerSettingKey stick_index = StaticData::optionNameToEnum["Start with Stick Ammo"]; + mContext->GetOption(stick_index).Set(mOptions[stick_index].GetValueFromText("Yes")); + const RandomizerSettingKey nut_index = StaticData::optionNameToEnum["Start with Stick Ammo"]; + mContext->GetOption(nut_index).Set(mOptions[nut_index].GetValueFromText("Yes")); + } else { + const RandomizerSettingKey stick_index = StaticData::optionNameToEnum["Start with Stick Ammo"]; + mContext->GetOption(stick_index).Set(mOptions[stick_index].GetValueFromText("No")); + const RandomizerSettingKey nut_index = StaticData::optionNameToEnum["Start with Stick Ammo"]; + mContext->GetOption(nut_index).Set(mOptions[nut_index].GetValueFromText("No")); + } + } + const std::string& setting_name = std::string(StaticData::APsettingToHoSsetting[APname]); + const RandomizerSettingKey index = StaticData::optionNameToEnum[setting_name]; + mContext->GetOption(index).Set(value); + SPDLOG_INFO("Parsed Setting {}: ({}, {})", APname, (int)index, value); + } + + // maybe we have to set a couple of settings manually, if ap doesn't set them + { + //const RandomizerSettingKey index = StaticData::optionNameToEnum["Starting Age"]; + //mContext->GetOption(index).Set(mOptions[index].GetValueFromText("Random")); + } + { + const RandomizerSettingKey index = StaticData::optionNameToEnum["Ganon's Trials"]; + mContext->GetOption(index).Set(mOptions[index].GetValueFromText("Set Number")); + } + { + const RandomizerSettingKey index = StaticData::optionNameToEnum["Logic"]; + mContext->GetOption(index).Set(mOptions[index].GetValueFromText("Glitchless")); + } + { + const RandomizerSettingKey index = StaticData::optionNameToEnum["Starting Hearts"]; + mContext->GetOption(index).Set(2); + } + { + const RandomizerSettingKey index = StaticData::optionNameToEnum["Token Shuffle"]; + mContext->GetOption(index).Set(mOptions[index].GetValueFromText("Off")); + } + //const RandomizerSettingKey index = StaticData::optionNameToEnum["Sleeping Waterfall"]; + //mContext->GetOption(index).Set(0); +} + void Settings::ReloadOptions() { for (int i = 0; i < RSK_MAX; i++) { mOptions[i].SetFromCVar(); diff --git a/soh/soh/Enhancements/randomizer/settings.h b/soh/soh/Enhancements/randomizer/settings.h index 6810b6832..3fb53d622 100644 --- a/soh/soh/Enhancements/randomizer/settings.h +++ b/soh/soh/Enhancements/randomizer/settings.h @@ -112,6 +112,8 @@ class Settings { * @param spoilerFileJson */ void ParseJson(nlohmann::json spoilerFileJson); + + void ParseArchipelago(const std::map& slot_data); std::map> mTricksByArea = {}; void ReloadOptions(); diff --git a/soh/soh/Enhancements/randomizer/static_data.cpp b/soh/soh/Enhancements/randomizer/static_data.cpp index a0ed4d5ef..66750b057 100644 --- a/soh/soh/Enhancements/randomizer/static_data.cpp +++ b/soh/soh/Enhancements/randomizer/static_data.cpp @@ -331,6 +331,82 @@ const std::unordered_mapgenerate_SohcheckToAP std::unordered_map StaticData::APitemToSoh = generate_APitemToSoh_mapping(); std::unordered_map StaticData::APcheckToSoh = generate_APcheckToSoh_mapping(); std::unordered_map StaticData::SohCheckToAP = generate_SohcheckToAP_mapping(); - +std::unordered_map StaticData::APsettingToHoSsetting = { + { "open_forest", "Closed Forest" }, + { "open_kakoriko", "Kakariko Gate" }, + { "open_door_of_time", "Door of Time" }, + { "zora_fountain", "Zora's Fountain" }, + { "gerudo_fortress", "Fortress Carpenters" }, + { "bridge", "Rainbow Bridge" }, // TODO underlying options may not overlap + { "bridge_stones", "Bridge Stone Count" }, + { "bridge_medallions", "Bridge Medallion Count" }, + { "bridge_rewards", "Bridge Reward Count" }, + { "bridge_tokens", "Bridge Token Count" }, + { "bridge_hearts", "NOT_SUPPORTED" }, + { "shuffle_ganon_bosskey", "Ganon's Boss Key" }, + { "ganon_bosskey_medallions", "GCBK Medallion Count" }, + { "ganon_bosskey_stones", "GCBK Stone Count" }, + { "ganon_bosskey_rewards", "GCBK Reward Count" }, + { "ganon_bosskey_tokens", "GCBK Token Count" }, + { "ganon_bosskey_hearts", "NOT_SUPPORTED" }, + { "trials", "Ganon's Trials Count" }, + { "triforce_hunt", "Triforce Hunt" }, + { "triforce_goal", "Triforce Hunt Required Pieces" }, + { "extra_triforce_percentage", "CUSTOM_IMPLEMENTATION" }, // TODO calc "Triforce Hunt Required Pieces" from percentage, Actually not really required to make the game run I think + { "shopsanity", "Shop Shuffle" }, + { "shop_slots", "Shops Item Count" }, + { "shopsanity_prices", "Shops Prices" }, // Item Prizes not in slot data, anything above starting wallet will be lowered to max 99 + { "tokensanity", "Token Shuffle" }, + { "dungeon_shortcuts", "NOT_SUPPORTED" }, // TODO could be implemented manually through + { "mq_dungeons_mode", "NOT_SUPORTED" }, // Not sure if we can figure this one out + { "mq_dungeons_count", "NOT_SUPPORTED" }, // Slot data doesn't expose the master quest dungeons used + { "shuffle_interior_entrances", "NOT_SUPPORTED" }, // Mapping not in Slot Data + { "shuffle_grotto_entrances", "NOT_SUPPORTED" }, // Mapping not in Slot Data + { "shuffle_dungeon_entrances", "NOT_SUPPORTED" }, // Mapping not in Slot Data + { "shuffle_overworld_entrances", "NOT_SUPPORTED" }, // Mapping not in Slot Data + { "shuffle_bosses", "NOT_SUPPORTED" }, // Mapping not in Slot Data + { "key_rings", "Key Rings" }, // slot data not exposed when set to random, however may not matter if you just can just recieve the key ring, may only be needed for logic + { "enhance_map_compass", "NOT_SUPPORTED" }, // Can't find it in rando settings, may be a qol setting + { "shuffle_mapcompass", "Maps/Compasses" }, // NOT REQUIRED + { "shuffle_smallkeys", "Small Key Shuffle" }, // NOT REQUIRED + { "shuffle_hideoutkeys", "Gerudo Fortress Keys" }, // NOT REQUIRED + { "shuffle_bosskeys", "Boss Key Shuffle" }, // NOT REQUIRED + { "logic_rules", "Logic" }, // NOT REQUIRED + { "logic_no_night_tokens_without_suns_song", "Night Skulltula's Expect Sun's Song" }, // NOT REQUIRED + { "warp_songs", "NOT_SUPORTED" }, // slot data not exposed + { "shuffle_song_items", "Shuffle Songs" }, // NOT REQUIRED + { "shuffle_medigoron_carpet_salesman", "NOT_SUPPORTED" }, // NOT REQURIED, , Should set "Shuffle Merchants" option (This option also sets granny) + { "shuffle_frog_song_rupees", "Shuffle Frog Song Rupees" }, // NOT REQUIRED + { "shuffle_scrubs", "Scrubs Shuffle" }, // NOT REQUIRED + { "shuffle_child_trade", "NOT_SUPPORTED" }, // NOT REQUIRED + { "shuffle_freestanding_items", "NOT_SUPPORTED" }, // NOT REQUIRED + { "shuffle_pots", "Shuffle Pots" }, // NOT REQUIRED + { "shuffle_crates", "MAYBE_SUPPORTED_TODO" }, // Maybe Requred, TODO TEST + { "shuffle_cows", "Shuffle Cows" }, // NOT REQUIRED + { "shuffle_beehives", "Shuffle Beehives" }, // NOT REQUIRED + { "shuffle_kokiri_sword", "Shuffle Kokiri Sword" }, // NOT REQUIRED + { "shuffle_ocarinas", "Shuffle Ocarinas" }, // NOT REQUIRED + { "shuffle_gerudo_card", "Shuffle Gerudo Membership Card" }, //NOT REQUIRED + { "shuffle_beans", "NOT_SUPPORTED" }, // NOT REQUIRED, Should set "Shuffle Merchants" option (This option also sets granny) + { "starting_age", "Selected Starting Age" }, // should this also set "Seelcted Starting Age" + { "bombchus_in_logic", "NOT_SUPPORTED" }, // NOT REQUIRED, Probably Implemented as a trick + { "spawn_positions", "NOT_SUPPORTED" }, + { "owl_drops", "NOT_SUPPORTRED" }, + { "no_epona_race", "Skip Epona Race" }, + { "skip_some_minigame_phases", "NOT_IMPLEMENTED" }, // should be under quality of life options + { "complete_mask_quest", "Complete Mask Quest" }, + { "free_scarecrow", "Skip Scarecrow's Song" }, + { "plant_beans", "NOT_SUPPORTRED" }, + { "chicken_count", "Cuccos to return" }, + { "big_poe_count", "Big Poe Target Count" }, + { "fae_torch_count", "NOT_SUPPORTED" }, + { "blue_fire_arrows", "Blue Fire Arrows" }, + { "damage_multiplier", "Damage Multiplier" }, + { "deadly_bonks", "NOT_SUPPORTED" }, + { "starting_tod", "NOT_SUPPORTED" }, + { "junk_ice_traps", "Ice Traps" }, // NOT REQUIRED + { "start_with_consumables", "CUSTOM_IMPLEMENTATION" }, // might be able to just set "Start with Stick Ammo" and "Start with Nut Ammo", TODO check starting consumables + { "adult_trade_start", "NOT_SUPPORTED" } +}; } diff --git a/soh/soh/Enhancements/randomizer/static_data.h b/soh/soh/Enhancements/randomizer/static_data.h index bbf83de00..f6a32e7f5 100644 --- a/soh/soh/Enhancements/randomizer/static_data.h +++ b/soh/soh/Enhancements/randomizer/static_data.h @@ -72,7 +72,7 @@ class StaticData { static std::unordered_map APitemToSoh; static std::unordered_map APcheckToSoh; static std::unordered_map SohCheckToAP; - + static std::unordered_map APsettingToHoSsetting; StaticData(); ~StaticData(); }; diff --git a/soh/soh/Enhancements/timesplits/TimeSplits.cpp b/soh/soh/Enhancements/timesplits/TimeSplits.cpp index b17f95b82..f7b8216f5 100644 --- a/soh/soh/Enhancements/timesplits/TimeSplits.cpp +++ b/soh/soh/Enhancements/timesplits/TimeSplits.cpp @@ -14,6 +14,7 @@ #include "soh/Enhancements/debugger/debugSaveEditor.h" #include "soh_assets.h" #include "assets/textures/parameter_static/parameter_static.h" +#include "soh/Enhancements/randomizer/archipelago.h" extern "C" { extern SaveContext gSaveContext; @@ -347,6 +348,7 @@ void HandleDragAndDrop(std::vector& objectList, int targetIndex, co void TimeSplitCompleteSplits() { gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME; gSaveContext.ship.stats.gameComplete = true; + ArchipelagoClient::getInstance().send_game_won(); } void TimeSplitsSkipSplit(uint32_t index) { From 3053d9201597b1e1856ea094104e84610b7f4df6 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Thu, 8 May 2025 19:20:24 +0200 Subject: [PATCH 05/11] Made some notes on differences between SoH and the existing OoT APworld --- differences.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 differences.md diff --git a/differences.md b/differences.md new file mode 100644 index 000000000..b685632a6 --- /dev/null +++ b/differences.md @@ -0,0 +1,26 @@ +# Differences between AP and Hos +AP Has a seperate option for shuffle beans and combines Medigoron and Carpet salesman +SoH combines the three and lumps Granny into the setting as well + +## Missing in Hos +[ ] HoS rainbow bridge does not support the "Heart count" option in Archipellago +[ ] Enhance map and compass to give info, couldn't find it in rando settings, but may be a qol thing +[ ] Option for preplanted beans +[ ] Option for Shadow temple torch count +[ ] Deadly Bonks Option (would be implemented in logic too, for crates) +[ ] Starting at Certain time of day + +[ ] "Zelda" option for Kakoriko Open setting + +## Missing in AP +No Greg (the green rupee) + + + +## missing slot data +[ ] Entrance mapping for entrance randomzier +[ ] Gossip Stone hints +[ ] Cosmetic settings +[ ] Dungeon Shortcuts when set to count +[ ] Used MQ dungeons when set to count +[ ] Shop sanity Item Prizes \ No newline at end of file From a0696518b1b8fe204b500afadc61e387ef573967 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Sun, 11 May 2025 21:47:29 +0200 Subject: [PATCH 06/11] Replaced APCpp library with APClientpp, project builds but doesn't work yet --- APCpp | 1 - soh/CMakeLists.txt | 11 - .../Enhancements/randomizer/archipelago.cpp | 319 ++++++++++-------- soh/soh/Enhancements/randomizer/archipelago.h | 42 ++- soh/soh/Enhancements/randomizer/context.cpp | 9 +- soh/soh/Enhancements/randomizer/context.h | 5 +- .../Enhancements/randomizer/hook_handlers.cpp | 6 +- soh/soh/SohGui/SohGui.cpp | 5 + soh/soh/SohGui/SohGui.hpp | 1 + soh/soh/SohGui/SohMenuBar.cpp | 1 + soh/soh/SohGui/SohMenuRandomizer.cpp | 9 + 11 files changed, 227 insertions(+), 182 deletions(-) delete mode 160000 APCpp diff --git a/APCpp b/APCpp deleted file mode 160000 index 505a174a3..000000000 --- a/APCpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 505a174a3b0f55f71f69e221d23003b223836fd7 diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 520b022eb..ded7bcf15 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -96,10 +96,6 @@ if (NOT TARGET ZAPDLib) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD ${CMAKE_BINARY_DIR}/ZAPD) endif() -if (NOT TARGET APCpp) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../APCpp ${CMAKE_BINARY_DIR}/APCpp) -endif() - set(PROJECT_NAME soh) ################################################################################ @@ -344,7 +340,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE assets ${SDL2-INCLUDE} ${SDL2-NET-INCLUDE} ${CMAKE_CURRENT_SOURCE_DIR}/assets/ - ${CMAKE_CURRENT_SOURCE_DIR}/../APCpp . ) @@ -628,9 +623,6 @@ endif() add_dependencies(${PROJECT_NAME} libultraship ) -add_dependencies(${PROJECT_NAME} - APCpp -) if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") add_dependencies(${PROJECT_NAME} ZAPDLib @@ -643,7 +635,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") set(ADDITIONAL_LIBRARY_DEPENDENCIES "libultraship;" "ZAPDLib;" - "APCpp;" "glu32;" "SDL2::SDL2;" "SDL2::SDL2main;" @@ -658,7 +649,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") set(ADDITIONAL_LIBRARY_DEPENDENCIES "libultraship;" "ZAPDLib;" - "APCpp;" "glu32;" "SDL2::SDL2;" "SDL2::SDL2main;" @@ -697,7 +687,6 @@ else() set(ADDITIONAL_LIBRARY_DEPENDENCIES "libultraship;" "ZAPDLib;" - "APCpp" SDL2::SDL2 "$<$:SDL2_net::SDL2_net>" ${CMAKE_DL_LIBS} diff --git a/soh/soh/Enhancements/randomizer/archipelago.cpp b/soh/soh/Enhancements/randomizer/archipelago.cpp index b14df700b..40bbfe4a7 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.cpp +++ b/soh/soh/Enhancements/randomizer/archipelago.cpp @@ -1,6 +1,8 @@ #include "archipelago.h" -#include "soh/UIWidgets.hpp" +#include "soh/SohGui/UIWidgets.hpp" #include "soh/util.h" +#include +#include #include #include @@ -35,6 +37,8 @@ auto SubscribeToSlotData() { } ArchipelagoClient::ArchipelagoClient() { + std::string uuid = ap_get_uuid("uuid"); + ItemRecievedCallback = nullptr; game_won = false; @@ -54,117 +58,89 @@ void ArchipelagoClient::add_slot_data(std::string_view key, int id) { slot_data.insert(std::pair(key, id)); } -void registerSlotCallbacks() { - SubscribeToSlotData<"open_forest">(); - SubscribeToSlotData<"open_kakoriko">(); - SubscribeToSlotData<"open_door_of_time">(); - SubscribeToSlotData<"zora_fountain">(); - SubscribeToSlotData<"gerudo_fortress">(); - SubscribeToSlotData<"bridge">(); - SubscribeToSlotData<"bridge_stones">(); - SubscribeToSlotData<"bridge_medallions">(); - SubscribeToSlotData<"bridge_rewards">(); - SubscribeToSlotData<"bridge_tokens">(); -// SubscribeToSlotData<"bridge_hearts">(); - SubscribeToSlotData<"shuffle_ganon_bosskey">(); - SubscribeToSlotData<"ganon_bosskey_medallions">(); - SubscribeToSlotData<"ganon_bosskey_stones">(); - SubscribeToSlotData<"ganon_bosskey_rewards">(); - SubscribeToSlotData<"ganon_bosskey_tokens">(); -// SubscribeToSlotData<"ganon_bosskey_hearts">(); - SubscribeToSlotData<"trials">(); - SubscribeToSlotData<"triforce_hunt">(); - SubscribeToSlotData<"triforce_goal">(); -// SubscribeToSlotData<"extra_triforce_percentage">(); -// SubscribeToSlotData<"shopsanity">(); -// SubscribeToSlotData<"shop_slots">(); - SubscribeToSlotData<"shopsanity_prices">(); -// SubscribeToSlotData<"tokensanity">(); -// SubscribeToSlotData<"dungeon_shortcuts">(); -// SubscribeToSlotData<"mq_dungeons_mode">(); -// SubscribeToSlotData<"mq_dungeons_count">(); -// SubscribeToSlotData<"shuffle_interior_entrances">(); -// SubscribeToSlotData<"shuffle_grotto_entrances">(); -// SubscribeToSlotData<"shuffle_dungeon_entrances">(); -// SubscribeToSlotData<"shuffle_overworld_entrances">(); -// SubscribeToSlotData<"shuffle_bosses">(); -// SubscribeToSlotData<"key_rings">(); -// SubscribeToSlotData<"enhance_map_compass">(); -// SubscribeToSlotData<"shuffle_mapcompass">(); -// SubscribeToSlotData<"shuffle_smallkeys">(); -// SubscribeToSlotData<"shuffle_hideoutkeys">(); -// SubscribeToSlotData<"shuffle_bosskeys">(); -// SubscribeToSlotData<"logic_rules">(); -// SubscribeToSlotData<"logic_no_night_tokens_without_suns_song">(); -// SubscribeToSlotData<"warp_songs">(); -// SubscribeToSlotData<"shuffle_song_items">(); -// SubscribeToSlotData<"shuffle_medigoron_carpet_salesman">(); -// SubscribeToSlotData<"shuffle_frog_song_rupees">(); -// SubscribeToSlotData<"shuffle_scrubs">(); -// SubscribeToSlotData<"shuffle_child_trade">(); -// SubscribeToSlotData<"shuffle_freestanding_items">(); -// SubscribeToSlotData<"shuffle_pots">(); -// SubscribeToSlotData<"shuffle_crates">(); -// SubscribeToSlotData<"shuffle_cows">(); -// SubscribeToSlotData<"shuffle_beehives">(); -// SubscribeToSlotData<"shuffle_kokiri_sword">(); -// SubscribeToSlotData<"shuffle_ocarinas">(); -// SubscribeToSlotData<"shuffle_gerudo_card">(); -// SubscribeToSlotData<"shuffle_beans">(); - SubscribeToSlotData<"starting_age">(); -// SubscribeToSlotData<"bombchus_in_logic">(); -// SubscribeToSlotData<"spawn_positions">(); -// SubscribeToSlotData<"owl_drops">(); - SubscribeToSlotData<"no_epona_race">(); -// SubscribeToSlotData<"skip_some_minigame_phases">(); - SubscribeToSlotData<"complete_mask_quest">(); - SubscribeToSlotData<"free_scarecrow">(); -// SubscribeToSlotData<"plant_beans">(); - SubscribeToSlotData<"chicken_count">(); - SubscribeToSlotData<"big_poe_count">(); -// SubscribeToSlotData<"fae_torch_count">(); - SubscribeToSlotData<"blue_fire_arrows">(); - SubscribeToSlotData<"damage_multiplier">(); -// SubscribeToSlotData<"deadly_bonks">(); -// SubscribeToSlotData<"starting_tod">(); -// SubscribeToSlotData<"junk_ice_traps">(); - SubscribeToSlotData<"start_with_consumables">(); -// SubscribeToSlotData<"adult_trade_start">(); -} +//void registerSlotCallbacks() { +// SubscribeToSlotData<"open_forest">(); +// SubscribeToSlotData<"open_kakoriko">(); +// SubscribeToSlotData<"open_door_of_time">(); +// SubscribeToSlotData<"zora_fountain">(); +// SubscribeToSlotData<"gerudo_fortress">(); +// SubscribeToSlotData<"bridge">(); +// SubscribeToSlotData<"bridge_stones">(); +// SubscribeToSlotData<"bridge_medallions">(); +// SubscribeToSlotData<"bridge_rewards">(); +// SubscribeToSlotData<"bridge_tokens">(); +//// SubscribeToSlotData<"bridge_hearts">(); +// SubscribeToSlotData<"shuffle_ganon_bosskey">(); +// SubscribeToSlotData<"ganon_bosskey_medallions">(); +// SubscribeToSlotData<"ganon_bosskey_stones">(); +// SubscribeToSlotData<"ganon_bosskey_rewards">(); +// SubscribeToSlotData<"ganon_bosskey_tokens">(); +//// SubscribeToSlotData<"ganon_bosskey_hearts">(); +// SubscribeToSlotData<"trials">(); +// SubscribeToSlotData<"triforce_hunt">(); +// SubscribeToSlotData<"triforce_goal">(); +//// SubscribeToSlotData<"extra_triforce_percentage">(); +//// SubscribeToSlotData<"shopsanity">(); +//// SubscribeToSlotData<"shop_slots">(); +// SubscribeToSlotData<"shopsanity_prices">(); +//// SubscribeToSlotData<"tokensanity">(); +//// SubscribeToSlotData<"dungeon_shortcuts">(); +//// SubscribeToSlotData<"mq_dungeons_mode">(); +//// SubscribeToSlotData<"mq_dungeons_count">(); +//// SubscribeToSlotData<"shuffle_interior_entrances">(); +//// SubscribeToSlotData<"shuffle_grotto_entrances">(); +//// SubscribeToSlotData<"shuffle_dungeon_entrances">(); +//// SubscribeToSlotData<"shuffle_overworld_entrances">(); +//// SubscribeToSlotData<"shuffle_bosses">(); +//// SubscribeToSlotData<"key_rings">(); +//// SubscribeToSlotData<"enhance_map_compass">(); +//// SubscribeToSlotData<"shuffle_mapcompass">(); +//// SubscribeToSlotData<"shuffle_smallkeys">(); +//// SubscribeToSlotData<"shuffle_hideoutkeys">(); +//// SubscribeToSlotData<"shuffle_bosskeys">(); +//// SubscribeToSlotData<"logic_rules">(); +//// SubscribeToSlotData<"logic_no_night_tokens_without_suns_song">(); +//// SubscribeToSlotData<"warp_songs">(); +//// SubscribeToSlotData<"shuffle_song_items">(); +//// SubscribeToSlotData<"shuffle_medigoron_carpet_salesman">(); +//// SubscribeToSlotData<"shuffle_frog_song_rupees">(); +//// SubscribeToSlotData<"shuffle_scrubs">(); +//// SubscribeToSlotData<"shuffle_child_trade">(); +//// SubscribeToSlotData<"shuffle_freestanding_items">(); +//// SubscribeToSlotData<"shuffle_pots">(); +//// SubscribeToSlotData<"shuffle_crates">(); +//// SubscribeToSlotData<"shuffle_cows">(); +//// SubscribeToSlotData<"shuffle_beehives">(); +//// SubscribeToSlotData<"shuffle_kokiri_sword">(); +//// SubscribeToSlotData<"shuffle_ocarinas">(); +//// SubscribeToSlotData<"shuffle_gerudo_card">(); +//// SubscribeToSlotData<"shuffle_beans">(); +// SubscribeToSlotData<"starting_age">(); +//// SubscribeToSlotData<"bombchus_in_logic">(); +//// SubscribeToSlotData<"spawn_positions">(); +//// SubscribeToSlotData<"owl_drops">(); +// SubscribeToSlotData<"no_epona_race">(); +//// SubscribeToSlotData<"skip_some_minigame_phases">(); +// SubscribeToSlotData<"complete_mask_quest">(); +// SubscribeToSlotData<"free_scarecrow">(); +//// SubscribeToSlotData<"plant_beans">(); +// SubscribeToSlotData<"chicken_count">(); +// SubscribeToSlotData<"big_poe_count">(); +//// SubscribeToSlotData<"fae_torch_count">(); +// SubscribeToSlotData<"blue_fire_arrows">(); +// SubscribeToSlotData<"damage_multiplier">(); +//// SubscribeToSlotData<"deadly_bonks">(); +//// SubscribeToSlotData<"starting_tod">(); +//// SubscribeToSlotData<"junk_ice_traps">(); +// SubscribeToSlotData<"start_with_consumables">(); +//// SubscribeToSlotData<"adult_trade_start">(); +//} bool ArchipelagoClient::start_client() { - switch(AP_GetConnectionStatus()) { - case AP_ConnectionStatus::ConnectionRefused: - SPDLOG_TRACE("refused"); - break; - case AP_ConnectionStatus::Authenticated: - SPDLOG_TRACE("Authenticated"); - break; - case AP_ConnectionStatus::Connected: - SPDLOG_TRACE("Connected"); - break; - case AP_ConnectionStatus::Disconnected: - SPDLOG_TRACE("Disconnected"); - break; - } - - if(AP_GetConnectionStatus() != AP_ConnectionStatus::Disconnected) { - SPDLOG_TRACE("AP already connected, shutting it down"); - AP_Shutdown(); - } - - AP_Init(server_address, "Ocarina of Time", slot_name, password); - //AP_SetClientConnectedCallback(&ArchipelagoClient::on_connected); // currently broken :( - //AP_SetClientCouldntConnectCallback(5, &ArchipelagoClient::on_couldntConnect); - AP_SetItemClearCallback(&ArchipelagoClient::on_clear_items); - AP_SetItemRecvCallback(&ArchipelagoClient::on_item_recieved); - AP_SetLocationCheckedCallback(&ArchipelagoClient::on_location_checked); - AP_SetLocationInfoCallback(&ArchipelagoClient::on_location_scouted); - registerSlotCallbacks(); - AP_Start(); - AP_ConnectionStatus conn_status = AP_GetConnectionStatus(); - - //switch(conn_status) { + //switch(AP_GetConnectionStatus()) { + // case AP_ConnectionStatus::ConnectionRefused: + // SPDLOG_TRACE("refused"); + // break; // case AP_ConnectionStatus::Authenticated: // SPDLOG_TRACE("Authenticated"); // break; @@ -175,12 +151,71 @@ bool ArchipelagoClient::start_client() { // SPDLOG_TRACE("Disconnected"); // break; //} + + //if(AP_GetConnectionStatus() != AP_ConnectionStatus::Disconnected) { + // SPDLOG_TRACE("AP already connected, shutting it down"); + // AP_Shutdown(); + //} + + if(apclient != NULL) { + apclient.reset(); + } + + apclient = std::unique_ptr(new APClient(uuid, AP_Client_consts::AP_GAME_NAME, server_address)); + + apclient->set_room_info_handler([&]() { + std::list tags; + // tags.push_back("DeathLink"); // todo, implement deathlink + apclient->ConnectSlot(slot_name, password, 0b001, tags); + }); + + apclient->set_items_received_handler([&](const std::list& items) { + for(const APClient::NetworkItem& item : items) { + on_item_recieved(item.item, false); // todo get rid of notify, since it doesn't work for us right now anyway + } + }); + + apclient->set_location_info_handler([&](const std::list& items) { + scouted_items.clear(); + + for(const APClient::NetworkItem& item: items) { + ApItem apItem; + const std::string game = apclient->get_player_game(item.player); + apItem.itemName = apclient->get_item_name(item.item, game); + apItem.locationName = apclient->get_location_name(item.location, game); + apItem.playerName = apclient->get_player_alias(item.player); + apItem.flags = item.flags; + apItem.index = item.index; + scouted_items.push_back(apItem); + + const std::string itemName = apItem.itemName; + const std::string playerName = apItem.playerName; + const std::string locationName = apItem.locationName; + SPDLOG_TRACE("Location scouted: {} for {} in location {}", itemName, playerName, locationName); + } + + }); // todo maybe move these functions to a lambda, since they don't have to be static anymore + apclient->set_location_checked_handler([&](const std::list locations) { + // todo implement me + }); + + //apclient.set_slot_connected_handler() // todo rewrite the old slot callbacks when i'm ready to read slot data again + //registerSlotCallbacks(); + //AP_Start(); + //AP_ConnectionStatus conn_status = AP_GetConnectionStatus(); + save_data(); - return conn_status == AP_ConnectionStatus::Connected; + //return conn_status == AP_ConnectionStatus::Connected; + return true; } void ArchipelagoClient::start_location_scouts() { - AP_SendLocationScouts(AP_GetAllLocations(), false); + std::set location_set = apclient->get_missing_locations(); + std::list missing_location_list; + for(const int64_t loc_id : location_set) { + missing_location_list.emplace_back(loc_id); + } + apclient->LocationScouts(missing_location_list); } void ArchipelagoClient::save_data() { @@ -189,7 +224,7 @@ void ArchipelagoClient::save_data() { } bool ArchipelagoClient::isConnected() { - return AP_GetConnectionStatus() == AP_ConnectionStatus::Authenticated; + return apclient->get_state() == APClient::State::SLOT_CONNECTED; } void ArchipelagoClient::check_location(RandomizerCheck SoH_check_id) { @@ -197,14 +232,14 @@ void ArchipelagoClient::check_location(RandomizerCheck SoH_check_id) { if(ap_name.empty()) { return; } - int64_t ap_item_id = CheckNameToId(std::string(ap_name)); + int64_t ap_item_id = apclient->get_location_id(std::string(ap_name)); SPDLOG_TRACE("Checked: {}({}), sending to AP server", ap_name, ap_item_id); // currently not sending, because i only get so many real chances if(!isConnected()) { return; } - AP_SendItem(ap_item_id); + apclient->LocationChecks({ap_item_id}); } void ArchipelagoClient::addItemRecievedCallback(std::function callback) { @@ -219,18 +254,13 @@ void ArchipelagoClient::on_connected() { // todo implement me SPDLOG_TRACE("AP Connected!!"); } -void ArchipelagoClient::on_couldntConnect(AP_ConnectionStatus connection_status) { - // todo implement me -} - - -void ArchipelagoClient::on_clear_items() { - // todo implement me -} +//void ArchipelagoClient::on_couldntConnect(AP_ConnectionStatus connection_status) { +// // todo implement me +//} void ArchipelagoClient::on_item_recieved(int64_t recieved_item_id, bool notify_player) { // call each callback - std::string item_name = getAPitemName(recieved_item_id); + const std::string item_name = apclient->get_item_name(recieved_item_id, "Ocarina of Time"); ArchipelagoClient& ap_client = ArchipelagoClient::getInstance(); if(ap_client.ItemRecievedCallback) { SPDLOG_TRACE("item recieved: {}, notify: {}", item_name, notify_player); @@ -238,24 +268,21 @@ void ArchipelagoClient::on_item_recieved(int64_t recieved_item_id, bool notify_p } } -void ArchipelagoClient::on_location_checked(int64_t location_id) { - // todo implement me -} - -void ArchipelagoClient::on_location_scouted(std::vector network_items) { - for(const AP_NetworkItem& item: network_items) { - SPDLOG_TRACE("Location scouted: {} for {} in location {}", item.itemName, item.playerName, item.locationName); - } - getInstance().scouted_items = network_items; -} - void ArchipelagoClient::send_game_won() { if(!game_won) { - AP_StoryComplete(); + apclient->StatusUpdate(APClient::ClientStatus::GOAL); game_won = true; } } +const std::string& ArchipelagoClient::get_slot_name() const { + if(apclient == NULL) { + return; + } + + return apclient->get_slot(); +} + char* ArchipelagoClient::get_server_address_buff() { return server_address; } @@ -270,7 +297,7 @@ const std::map& ArchipelagoClient::get_slot_data() { return slot_data; } -const std::vector& ArchipelagoClient::get_scouted_items() { +const std::vector& ArchipelagoClient::get_scouted_items() { return scouted_items; } @@ -289,15 +316,15 @@ void ArchipelagoWindow::ArchipelagoDrawConnectPage() { ImGui::SameLine(); ImGui::Text(connected_text); - AP_ConnectionStatus con_status = AP_GetConnectionStatus(); - if(con_status == AP_ConnectionStatus::Connected) { - strncpy(connected_text, "Connected!", 25); - } else if(con_status == AP_ConnectionStatus::Authenticated) { - strncpy(connected_text, "Authenticated!", 25); - } - else { - strncpy(connected_text, "Not Connected", 25); - } + //ArchipelagoDrawConnectPageAP_ConnectionStatus con_status = AP_GetConnectionStatus(); + //if(con_status == AP_ConnectionStatus::Connected) { + // strncpy(connected_text, "Connected!", 25); + //} else if(con_status == AP_ConnectionStatus::Authenticated) { + // strncpy(connected_text, "Authenticated!", 25); + //} + //else { + // strncpy(connected_text, "Not Connected", 25); + //} if(ImGui::Button("scout")) { AP_client.start_location_scouts(); diff --git a/soh/soh/Enhancements/randomizer/archipelago.h b/soh/soh/Enhancements/randomizer/archipelago.h index 8f4487b9a..3164de576 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.h +++ b/soh/soh/Enhancements/randomizer/archipelago.h @@ -1,5 +1,7 @@ +#pragma once #include "archipelago_settings_window.h" -#include "../../../../APCpp/Archipelago.h" + +#include #include "fixed_string.hpp" @@ -16,10 +18,20 @@ namespace AP_Client_consts { static constexpr char const* SETTING_ADDRESS = "AP_server_address"; static constexpr char const* SETTING_NAME = "AP_slot_name"; -}; -class ArchipelagoClient { + static constexpr char const* AP_GAME_NAME = "Ocarina of Time"; +} + +class ArchipelagoClient{ public: + struct ApItem { + std::string itemName; + std::string locationName; + std::string playerName; + unsigned int flags; + int index; + }; + static ArchipelagoClient& getInstance(); bool start_client(); @@ -28,11 +40,13 @@ class ArchipelagoClient { void start_location_scouts(); // getters + const std::string& get_slot_name() const; + char* get_server_address_buff(); char* get_slot_name_buff(); char* get_password_buff(); const std::map& get_slot_data(); - const std::vector& get_scouted_items(); + const std::vector& get_scouted_items(); void add_slot_data(std::string_view key, int id); @@ -47,7 +61,7 @@ class ArchipelagoClient { // todo move me back down when done testing - static void on_item_recieved(int64_t recieved_item_id, bool notify_player); + void on_item_recieved(int64_t recieved_item_id, bool notify_player); void send_game_won(); @@ -57,7 +71,10 @@ class ArchipelagoClient { private: ArchipelagoClient(ArchipelagoClient &) = delete; void operator=(const ArchipelagoClient &) = delete; - static std::shared_ptr instance; + std::string uuid; + std::unique_ptr apclient; + + static std::shared_ptr instance; // is this even used? static bool initialized; char server_address[AP_Client_consts::MAX_ADDRESS_LENGTH]; @@ -68,20 +85,19 @@ class ArchipelagoClient { std::map slot_data; std::set locations; - std::vector scouted_items; + std::vector scouted_items; //void registerSlotCallbacks(); void save_data(); // callback functions - static void on_connected(); - static void on_couldntConnect(AP_ConnectionStatus connection_status); - static void on_clear_items(); + void on_connected(); + //void on_couldntConnect(AP_ConnectionStatus connection_status); - static void on_location_checked(int64_t location_id); - static void on_deathlink_recieved() { }; // TODO: implement me - static void on_location_scouted(std::vector network_items); + void on_location_checked(int64_t location_id); + void on_deathlink_recieved() { }; // TODO: implement me + void on_location_scouted(const std::list& network_items); // callbacks std::function ItemRecievedCallback; diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp index c72c9cfe6..2a5968ba4 100644 --- a/soh/soh/Enhancements/randomizer/context.cpp +++ b/soh/soh/Enhancements/randomizer/context.cpp @@ -13,7 +13,6 @@ #include "3drando/hints.hpp" #include "../kaleido.h" #include "archipelago.h" -#include "Archipelago.h" #include #include @@ -481,22 +480,22 @@ void Context::ParseItemLocationsJson(nlohmann::json spoilerFileJson) { } } -void Context::ParseArchipelagoItemsLocations(const std::vector& scouted_items) { - int playerId = AP_GetPlayerID(); // todo change me when the client is developed further +void Context::ParseArchipelagoItemsLocations(const std::vector& scouted_items) { + const std::string SlotName = ArchipelagoClient::getInstance().get_slot_name(); // init the item table with regular items first for(int rc = 1; rc <= RC_MAX; rc++) { itemLocationTable[rc].SetPlacedItem(StaticData::GetLocation(static_cast(rc))->GetVanillaItem()); } - for(const AP_NetworkItem& ap_item: scouted_items) { + for(const ArchipelagoClient::ApItem& ap_item: scouted_items) { const RandomizerCheck rc = StaticData::APcheckToSoh.find(ap_item.locationName)->second; if(rc == RC_KF_MIDOS_TOP_RIGHT_CHEST) { continue; } - if(playerId == ap_item.player) { + if(SlotName == ap_item.playerName) { // our item SPDLOG_TRACE("Populated item {} at location {}", ap_item.itemName, ap_item.locationName); const RandomizerGet item = StaticData::APitemToSoh.find(ap_item.itemName)->second; diff --git a/soh/soh/Enhancements/randomizer/context.h b/soh/soh/Enhancements/randomizer/context.h index 0840439d4..b347158ae 100644 --- a/soh/soh/Enhancements/randomizer/context.h +++ b/soh/soh/Enhancements/randomizer/context.h @@ -8,14 +8,13 @@ #include "hint.h" #include "fishsanity.h" #include "trial.h" +#include "archipelago.h" #include #include #include #include -// forward declarations -struct AP_NetworkItem; /** * @brief Singleton for storing and accessing dynamic Randomizer-related data @@ -128,7 +127,7 @@ class Context { void ParseArchipelago(); void ParseArchipelagoSettings(const std::map& slot_data); - void ParseArchipelagoItemsLocations(const std::vector& slot_data); + void ParseArchipelagoItemsLocations(const std::vector& slot_data); /** * @brief Get the hash for the current seed. diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 3f73ff602..ea8f8c327 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -222,10 +222,10 @@ static std::queue randomizerQueuedChecks; static RandomizerCheck randomizerQueuedCheck = RC_UNKNOWN_CHECK; static GetItemEntry randomizerQueuedItemEntry = GET_ITEM_NONE; -void ArchipelagoOnRecieveItem(const std::string& ap_item_id) { - SPDLOG_TRACE("Recieve item handler called! {}", ap_item_id); +void ArchipelagoOnRecieveItem(const std::string& ap_item_name) { + SPDLOG_TRACE("Recieve item handler called! {}", ap_item_name); randomizerQueuedChecks.push(RC_ARCHIPELAGO_RECIEVED_ITEM); - Rando::Context::GetInstance()->AddRecievedArchipelagoItem(ap_item_id); + Rando::Context::GetInstance()->AddRecievedArchipelagoItem(ap_item_name); } void RandomizerOnFlagSetHandler(int16_t flagType, int16_t flag) { diff --git a/soh/soh/SohGui/SohGui.cpp b/soh/soh/SohGui/SohGui.cpp index 7eb3fc6c7..7be045873 100644 --- a/soh/soh/SohGui/SohGui.cpp +++ b/soh/soh/SohGui/SohGui.cpp @@ -94,6 +94,7 @@ std::shared_ptr mItemTrackerSettingsWindow; std::shared_ptr mItemTrackerWindow; std::shared_ptr mTimeSplitWindow; std::shared_ptr mPlandomizerWindow; +std::shared_ptr mArchipelagoWindow; std::shared_ptr mRandomizerSettingsWindow; std::shared_ptr mModalWindow; std::shared_ptr mNotificationWindow; @@ -195,6 +196,9 @@ void SetupGuiElements() { mPlandomizerWindow = std::make_shared(CVAR_WINDOW("PlandomizerEditor"), "Plandomizer Editor", ImVec2(850, 760)); gui->AddGuiWindow(mPlandomizerWindow); + mArchipelagoWindow = + std::make_shared(CVAR_WINDOW("ArchipelagoWindow"), "Archipelago", ImVec2(850, 760)); + gui->AddGuiWindow(mArchipelagoWindow); mModalWindow = std::make_shared(CVAR_WINDOW("ModalWindow"), "Modal Window"); gui->AddGuiWindow(mModalWindow); mModalWindow->Show(); @@ -237,6 +241,7 @@ void Destroy() { mInputViewerSettings = nullptr; mTimeSplitWindow = nullptr; mPlandomizerWindow = nullptr; + mArchipelagoWindow = nullptr; mTimeDisplayWindow = nullptr; } diff --git a/soh/soh/SohGui/SohGui.hpp b/soh/soh/SohGui/SohGui.hpp index d9b7bb644..7d5a37459 100644 --- a/soh/soh/SohGui/SohGui.hpp +++ b/soh/soh/SohGui/SohGui.hpp @@ -29,6 +29,7 @@ #include "soh/Enhancements/randomizer/randomizer_settings_window.h" #include "soh/Enhancements/timesplits/TimeSplits.h" #include "soh/Enhancements/randomizer/Plandomizer.h" +#include "soh/Enhancements/randomizer/archipelago.h" #include "SohModals.h" namespace SohGui { diff --git a/soh/soh/SohGui/SohMenuBar.cpp b/soh/soh/SohGui/SohMenuBar.cpp index aa747c168..577f33b14 100644 --- a/soh/soh/SohGui/SohMenuBar.cpp +++ b/soh/soh/SohGui/SohMenuBar.cpp @@ -41,6 +41,7 @@ #include "soh/Enhancements/enemyrandomizer.h" #include "soh/Enhancements/timesplits/TimeSplits.h" #include "soh/Enhancements/randomizer/Plandomizer.h" +#include "soh/Enhancements/randomizer/archipelago.h" #include "soh/Enhancements/TimeDisplay/TimeDisplay.h" // FA icons are kind of wonky, if they worked how I expected them to the "+ 2.0f" wouldn't be needed, but diff --git a/soh/soh/SohGui/SohMenuRandomizer.cpp b/soh/soh/SohGui/SohMenuRandomizer.cpp index 8f4e6e43b..617990a42 100644 --- a/soh/soh/SohGui/SohMenuRandomizer.cpp +++ b/soh/soh/SohGui/SohMenuRandomizer.cpp @@ -100,6 +100,15 @@ void SohMenu::AddMenuRandomizer() { .WindowName("Plandomizer Editor") .Options(WindowButtonOptions().Tooltip("Enables the separate Randomizer Settings Window.")); + // Archipelago + path.sidebarName = "Archipelago"; + AddSidebarEntry("Randomizer", path.sidebarName, 1); + AddWidget(path, "Popout Archipelago Development Window", WIDGET_WINDOW_BUTTON) + .CVar(CVAR_WINDOW("ArchipelagoWindow")) + .RaceDisable(false) + .WindowName("Archipelago Development") + .Options(WindowButtonOptions().Tooltip("Enables the Archipelago development Window.")); + // Item Tracker path.sidebarName = "Item Tracker"; AddSidebarEntry("Randomizer", path.sidebarName, 1); From ead3d2f515869e62e4a54c9617c793e519eb1de5 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Mon, 12 May 2025 21:12:44 +0200 Subject: [PATCH 07/11] Fixed menu and added poll call to apcpp to help connecting --- .../Enhancements/randomizer/archipelago.cpp | 52 +++++++++++++++---- soh/soh/Enhancements/randomizer/archipelago.h | 12 +++-- soh/soh/SohGui/SohMenuRandomizer.cpp | 2 +- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/archipelago.cpp b/soh/soh/Enhancements/randomizer/archipelago.cpp index 40bbfe4a7..94444d69d 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.cpp +++ b/soh/soh/Enhancements/randomizer/archipelago.cpp @@ -12,6 +12,7 @@ #include "fixed_string.hpp" #include "randomizerTypes.h" #include "static_data.h" +#include "../game-interactor/GameInteractor.h" //extern "C" { // #include "include/z64item.h" @@ -46,6 +47,9 @@ ArchipelagoClient::ArchipelagoClient() { CVarSetInteger("archipelago_connected", 0); strncpy(server_address, CVarGetString(apc::SETTING_ADDRESS, apc::DEFAULT_SERVER_NAME), apc::MAX_ADDRESS_LENGTH); strncpy(slot_name, CVarGetString(apc::SETTING_NAME, ""), apc::MAX_PLAYER_NAME_LENGHT); + + // call poll every frame + GameInteractor::Instance->RegisterGameHook([](){ArchipelagoClient::getInstance().poll();}); } ArchipelagoClient& ArchipelagoClient::getInstance() { @@ -275,9 +279,17 @@ void ArchipelagoClient::send_game_won() { } } +void ArchipelagoClient::poll() { + if(apclient == nullptr) { + return; + } + + apclient->poll(); +} + const std::string& ArchipelagoClient::get_slot_name() const { if(apclient == NULL) { - return; + return ""; } return apclient->get_slot(); @@ -316,16 +328,36 @@ void ArchipelagoWindow::ArchipelagoDrawConnectPage() { ImGui::SameLine(); ImGui::Text(connected_text); - //ArchipelagoDrawConnectPageAP_ConnectionStatus con_status = AP_GetConnectionStatus(); - //if(con_status == AP_ConnectionStatus::Connected) { - // strncpy(connected_text, "Connected!", 25); - //} else if(con_status == AP_ConnectionStatus::Authenticated) { - // strncpy(connected_text, "Authenticated!", 25); - //} - //else { - // strncpy(connected_text, "Not Connected", 25); - //} + APClient::State con_state = APClient::State::DISCONNECTED; + + if(AP_client.apclient) { + con_state = AP_client.apclient->get_state(); + } + + switch (con_state) { + case APClient::State::DISCONNECTED: { + strncpy(connected_text, "Disconnected!", 25); + break; + } + case APClient::State::SOCKET_CONNECTING: { + strncpy(connected_text, "Socket Connecting!", 25); + break; + } + case APClient::State::SOCKET_CONNECTED: { + strncpy(connected_text, "Socket Connected!", 25); + break; + } + case APClient::State::ROOM_INFO: { + strncpy(connected_text, "Room info Recieved!", 25); + break; + } + case APClient::State::SLOT_CONNECTED: { + strncpy(connected_text, "Slot Connected!", 25); + break; + } + }; + if(ImGui::Button("scout")) { AP_client.start_location_scouts(); } diff --git a/soh/soh/Enhancements/randomizer/archipelago.h b/soh/soh/Enhancements/randomizer/archipelago.h index 3164de576..bda296a19 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.h +++ b/soh/soh/Enhancements/randomizer/archipelago.h @@ -1,14 +1,15 @@ #pragma once #include "archipelago_settings_window.h" -#include - #include "fixed_string.hpp" #include "randomizerTypes.h" #include "static_data.h" #include +// forward declerations +class APClient; + namespace AP_Client_consts { static constexpr int MAX_ADDRESS_LENGTH = 64; @@ -65,6 +66,10 @@ class ArchipelagoClient{ void send_game_won(); + void poll(); + + std::unique_ptr apclient; + protected: ArchipelagoClient(); @@ -72,7 +77,6 @@ class ArchipelagoClient{ ArchipelagoClient(ArchipelagoClient &) = delete; void operator=(const ArchipelagoClient &) = delete; std::string uuid; - std::unique_ptr apclient; static std::shared_ptr instance; // is this even used? static bool initialized; @@ -97,7 +101,7 @@ class ArchipelagoClient{ void on_location_checked(int64_t location_id); void on_deathlink_recieved() { }; // TODO: implement me - void on_location_scouted(const std::list& network_items); + //void on_location_scouted(const std::list& network_items); // callbacks std::function ItemRecievedCallback; diff --git a/soh/soh/SohGui/SohMenuRandomizer.cpp b/soh/soh/SohGui/SohMenuRandomizer.cpp index 617990a42..63bfa9bc9 100644 --- a/soh/soh/SohGui/SohMenuRandomizer.cpp +++ b/soh/soh/SohGui/SohMenuRandomizer.cpp @@ -106,7 +106,7 @@ void SohMenu::AddMenuRandomizer() { AddWidget(path, "Popout Archipelago Development Window", WIDGET_WINDOW_BUTTON) .CVar(CVAR_WINDOW("ArchipelagoWindow")) .RaceDisable(false) - .WindowName("Archipelago Development") + .WindowName("Archipelago") .Options(WindowButtonOptions().Tooltip("Enables the Archipelago development Window.")); // Item Tracker From ae736e6f2c23c80efa5132512c4f4fb2a583d1d5 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Mon, 12 May 2025 21:22:37 +0200 Subject: [PATCH 08/11] Bump apclientpp to version 0.6.0 --- subprojects/apclientpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/apclientpp b/subprojects/apclientpp index 4ab7ba634..a5b7b96b6 160000 --- a/subprojects/apclientpp +++ b/subprojects/apclientpp @@ -1 +1 @@ -Subproject commit 4ab7ba634809459196f476d3a485ddb076d62565 +Subproject commit a5b7b96b6bfbdc7f2831796a4e126bcc09c35da1 From e2d0d8f511a902c81f357c0ec4e307626899616d Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Mon, 12 May 2025 21:39:05 +0200 Subject: [PATCH 09/11] Added found locations to scouts as well --- soh/soh/Enhancements/randomizer/archipelago.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/archipelago.cpp b/soh/soh/Enhancements/randomizer/archipelago.cpp index 94444d69d..29be3b1f4 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.cpp +++ b/soh/soh/Enhancements/randomizer/archipelago.cpp @@ -214,12 +214,16 @@ bool ArchipelagoClient::start_client() { } void ArchipelagoClient::start_location_scouts() { - std::set location_set = apclient->get_missing_locations(); - std::list missing_location_list; - for(const int64_t loc_id : location_set) { - missing_location_list.emplace_back(loc_id); + std::set missing_loc_set = apclient->get_missing_locations(); + std::set found_loc_set = apclient->get_checked_locations(); + std::list location_list; + for(const int64_t loc_id : missing_loc_set) { + location_list.emplace_back(loc_id); } - apclient->LocationScouts(missing_location_list); + for(const int64_t loc_id : found_loc_set) { + location_list.emplace_back(loc_id); + } + apclient->LocationScouts(location_list); } void ArchipelagoClient::save_data() { From ea13bc635f54fbb705c66b4b21e00b7626debf7e Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Tue, 13 May 2025 22:02:59 +0200 Subject: [PATCH 10/11] Fixed recieving items from chests --- soh/soh/Enhancements/randomizer/context.cpp | 8 +++----- soh/soh/Enhancements/randomizer/hook_handlers.cpp | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp index 2a5968ba4..f38faa1c9 100644 --- a/soh/soh/Enhancements/randomizer/context.cpp +++ b/soh/soh/Enhancements/randomizer/context.cpp @@ -485,15 +485,13 @@ void Context::ParseArchipelagoItemsLocations(const std::vector(rc))->GetVanillaItem()); + // This may not even be needed + const RandomizerGet vanillaItem = StaticData::GetLocation(static_cast(rc))->GetVanillaItem(); + itemLocationTable[rc].SetPlacedItem(vanillaItem); } for(const ArchipelagoClient::ApItem& ap_item: scouted_items) { const RandomizerCheck rc = StaticData::APcheckToSoh.find(ap_item.locationName)->second; - - if(rc == RC_KF_MIDOS_TOP_RIGHT_CHEST) { - continue; - } if(SlotName == ap_item.playerName) { // our item diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index ea8f8c327..df6be1e63 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -312,8 +312,7 @@ void RandomizerOnPlayerUpdateForRCQueueHandler() { } else { RandomizerGet vanillaRandomizerGet = Rando::StaticData::GetLocation(rc)->GetVanillaItem(); GetItemID vanillaItem = (GetItemID)Rando::StaticData::RetrieveItem(vanillaRandomizerGet).GetItemID(); - GetItemEntry getItemEntry = - Rando::Context::GetInstance()->GetFinalGIEntry(rc, true, (GetItemID)vanillaRandomizerGet); + getItemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(rc, true, (GetItemID)vanillaRandomizerGet); } SPDLOG_TRACE("RC found!"); From 82ef6c55ef6cec173b392f812dc4b5c97d479bd2 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Sat, 17 May 2025 20:05:37 +0200 Subject: [PATCH 11/11] Disabled (but not removed) mapping of old OoT ap items and locations. Not tested because I can't get the world to host yet :( --- .../Enhancements/randomizer/archipelago.cpp | 138 +--- soh/soh/Enhancements/randomizer/archipelago.h | 12 +- soh/soh/Enhancements/randomizer/context.cpp | 11 +- .../Enhancements/randomizer/fixed_string.hpp | 682 ------------------ 4 files changed, 11 insertions(+), 832 deletions(-) delete mode 100644 soh/soh/Enhancements/randomizer/fixed_string.hpp diff --git a/soh/soh/Enhancements/randomizer/archipelago.cpp b/soh/soh/Enhancements/randomizer/archipelago.cpp index 29be3b1f4..6953447e9 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.cpp +++ b/soh/soh/Enhancements/randomizer/archipelago.cpp @@ -9,34 +9,10 @@ #include #include -#include "fixed_string.hpp" #include "randomizerTypes.h" #include "static_data.h" #include "../game-interactor/GameInteractor.h" -//extern "C" { -// #include "include/z64item.h" -// #include "objects/gameplay_keep/gameplay_keep.h" -// extern SaveContext gSaveContext; -// extern PlayState* gPlayState; -//} - -//constexpr const char* requestedSlotData(int i) - -using namespace fixstr; //https://github.com/unterumarmung/fixed_string -template -struct CallbackWrapper { - static void SlotCallbackFunc(int id) { - ArchipelagoClient::getInstance().add_slot_data(key, id); - SPDLOG_TRACE("Recieved Slot data ({}, {})", key, id); - } -}; - -template -auto SubscribeToSlotData() { - AP_RegisterSlotDataIntCallback(std::string(key), CallbackWrapper::SlotCallbackFunc); -} - ArchipelagoClient::ArchipelagoClient() { std::string uuid = ap_get_uuid("uuid"); @@ -57,110 +33,7 @@ ArchipelagoClient& ArchipelagoClient::getInstance() { return Client; } - -void ArchipelagoClient::add_slot_data(std::string_view key, int id) { - slot_data.insert(std::pair(key, id)); -} - -//void registerSlotCallbacks() { -// SubscribeToSlotData<"open_forest">(); -// SubscribeToSlotData<"open_kakoriko">(); -// SubscribeToSlotData<"open_door_of_time">(); -// SubscribeToSlotData<"zora_fountain">(); -// SubscribeToSlotData<"gerudo_fortress">(); -// SubscribeToSlotData<"bridge">(); -// SubscribeToSlotData<"bridge_stones">(); -// SubscribeToSlotData<"bridge_medallions">(); -// SubscribeToSlotData<"bridge_rewards">(); -// SubscribeToSlotData<"bridge_tokens">(); -//// SubscribeToSlotData<"bridge_hearts">(); -// SubscribeToSlotData<"shuffle_ganon_bosskey">(); -// SubscribeToSlotData<"ganon_bosskey_medallions">(); -// SubscribeToSlotData<"ganon_bosskey_stones">(); -// SubscribeToSlotData<"ganon_bosskey_rewards">(); -// SubscribeToSlotData<"ganon_bosskey_tokens">(); -//// SubscribeToSlotData<"ganon_bosskey_hearts">(); -// SubscribeToSlotData<"trials">(); -// SubscribeToSlotData<"triforce_hunt">(); -// SubscribeToSlotData<"triforce_goal">(); -//// SubscribeToSlotData<"extra_triforce_percentage">(); -//// SubscribeToSlotData<"shopsanity">(); -//// SubscribeToSlotData<"shop_slots">(); -// SubscribeToSlotData<"shopsanity_prices">(); -//// SubscribeToSlotData<"tokensanity">(); -//// SubscribeToSlotData<"dungeon_shortcuts">(); -//// SubscribeToSlotData<"mq_dungeons_mode">(); -//// SubscribeToSlotData<"mq_dungeons_count">(); -//// SubscribeToSlotData<"shuffle_interior_entrances">(); -//// SubscribeToSlotData<"shuffle_grotto_entrances">(); -//// SubscribeToSlotData<"shuffle_dungeon_entrances">(); -//// SubscribeToSlotData<"shuffle_overworld_entrances">(); -//// SubscribeToSlotData<"shuffle_bosses">(); -//// SubscribeToSlotData<"key_rings">(); -//// SubscribeToSlotData<"enhance_map_compass">(); -//// SubscribeToSlotData<"shuffle_mapcompass">(); -//// SubscribeToSlotData<"shuffle_smallkeys">(); -//// SubscribeToSlotData<"shuffle_hideoutkeys">(); -//// SubscribeToSlotData<"shuffle_bosskeys">(); -//// SubscribeToSlotData<"logic_rules">(); -//// SubscribeToSlotData<"logic_no_night_tokens_without_suns_song">(); -//// SubscribeToSlotData<"warp_songs">(); -//// SubscribeToSlotData<"shuffle_song_items">(); -//// SubscribeToSlotData<"shuffle_medigoron_carpet_salesman">(); -//// SubscribeToSlotData<"shuffle_frog_song_rupees">(); -//// SubscribeToSlotData<"shuffle_scrubs">(); -//// SubscribeToSlotData<"shuffle_child_trade">(); -//// SubscribeToSlotData<"shuffle_freestanding_items">(); -//// SubscribeToSlotData<"shuffle_pots">(); -//// SubscribeToSlotData<"shuffle_crates">(); -//// SubscribeToSlotData<"shuffle_cows">(); -//// SubscribeToSlotData<"shuffle_beehives">(); -//// SubscribeToSlotData<"shuffle_kokiri_sword">(); -//// SubscribeToSlotData<"shuffle_ocarinas">(); -//// SubscribeToSlotData<"shuffle_gerudo_card">(); -//// SubscribeToSlotData<"shuffle_beans">(); -// SubscribeToSlotData<"starting_age">(); -//// SubscribeToSlotData<"bombchus_in_logic">(); -//// SubscribeToSlotData<"spawn_positions">(); -//// SubscribeToSlotData<"owl_drops">(); -// SubscribeToSlotData<"no_epona_race">(); -//// SubscribeToSlotData<"skip_some_minigame_phases">(); -// SubscribeToSlotData<"complete_mask_quest">(); -// SubscribeToSlotData<"free_scarecrow">(); -//// SubscribeToSlotData<"plant_beans">(); -// SubscribeToSlotData<"chicken_count">(); -// SubscribeToSlotData<"big_poe_count">(); -//// SubscribeToSlotData<"fae_torch_count">(); -// SubscribeToSlotData<"blue_fire_arrows">(); -// SubscribeToSlotData<"damage_multiplier">(); -//// SubscribeToSlotData<"deadly_bonks">(); -//// SubscribeToSlotData<"starting_tod">(); -//// SubscribeToSlotData<"junk_ice_traps">(); -// SubscribeToSlotData<"start_with_consumables">(); -//// SubscribeToSlotData<"adult_trade_start">(); -//} - bool ArchipelagoClient::start_client() { - //switch(AP_GetConnectionStatus()) { - // case AP_ConnectionStatus::ConnectionRefused: - // SPDLOG_TRACE("refused"); - // break; - // case AP_ConnectionStatus::Authenticated: - // SPDLOG_TRACE("Authenticated"); - // break; - // case AP_ConnectionStatus::Connected: - // SPDLOG_TRACE("Connected"); - // break; - // case AP_ConnectionStatus::Disconnected: - // SPDLOG_TRACE("Disconnected"); - // break; - //} - - //if(AP_GetConnectionStatus() != AP_ConnectionStatus::Disconnected) { - // SPDLOG_TRACE("AP already connected, shutting it down"); - // AP_Shutdown(); - //} - if(apclient != NULL) { apclient.reset(); } @@ -203,13 +76,7 @@ bool ArchipelagoClient::start_client() { // todo implement me }); - //apclient.set_slot_connected_handler() // todo rewrite the old slot callbacks when i'm ready to read slot data again - //registerSlotCallbacks(); - //AP_Start(); - //AP_ConnectionStatus conn_status = AP_GetConnectionStatus(); - save_data(); - //return conn_status == AP_ConnectionStatus::Connected; return true; } @@ -236,7 +103,8 @@ bool ArchipelagoClient::isConnected() { } void ArchipelagoClient::check_location(RandomizerCheck SoH_check_id) { - std::string_view ap_name = Rando::StaticData::SohCheckToAP[SoH_check_id]; + //std::string_view ap_name = Rando::StaticData::SohCheckToAP[SoH_check_id]; + std::string ap_name = Rando::StaticData::GetLocation(SoH_check_id)->GetName(); if(ap_name.empty()) { return; } @@ -268,7 +136,7 @@ void ArchipelagoClient::on_connected() { void ArchipelagoClient::on_item_recieved(int64_t recieved_item_id, bool notify_player) { // call each callback - const std::string item_name = apclient->get_item_name(recieved_item_id, "Ocarina of Time"); + const std::string item_name = apclient->get_item_name(recieved_item_id, AP_Client_consts::AP_GAME_NAME); ArchipelagoClient& ap_client = ArchipelagoClient::getInstance(); if(ap_client.ItemRecievedCallback) { SPDLOG_TRACE("item recieved: {}, notify: {}", item_name, notify_player); diff --git a/soh/soh/Enhancements/randomizer/archipelago.h b/soh/soh/Enhancements/randomizer/archipelago.h index bda296a19..5106427e8 100644 --- a/soh/soh/Enhancements/randomizer/archipelago.h +++ b/soh/soh/Enhancements/randomizer/archipelago.h @@ -1,8 +1,6 @@ #pragma once #include "archipelago_settings_window.h" -#include "fixed_string.hpp" - #include "randomizerTypes.h" #include "static_data.h" #include @@ -20,7 +18,7 @@ namespace AP_Client_consts { static constexpr char const* SETTING_ADDRESS = "AP_server_address"; static constexpr char const* SETTING_NAME = "AP_slot_name"; - static constexpr char const* AP_GAME_NAME = "Ocarina of Time"; + static constexpr char const* AP_GAME_NAME = "Ocarina of Time (SoH)"; } class ArchipelagoClient{ @@ -49,10 +47,6 @@ class ArchipelagoClient{ const std::map& get_slot_data(); const std::vector& get_scouted_items(); - void add_slot_data(std::string_view key, int id); - - //void add_slot_data(std::string_view key, int id); - bool isConnected(); void check_location(RandomizerCheck SoH_check_id); @@ -90,18 +84,14 @@ class ArchipelagoClient{ std::map slot_data; std::set locations; std::vector scouted_items; - - //void registerSlotCallbacks(); void save_data(); // callback functions void on_connected(); - //void on_couldntConnect(AP_ConnectionStatus connection_status); void on_location_checked(int64_t location_id); void on_deathlink_recieved() { }; // TODO: implement me - //void on_location_scouted(const std::list& network_items); // callbacks std::function ItemRecievedCallback; diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp index f38faa1c9..e875c7423 100644 --- a/soh/soh/Enhancements/randomizer/context.cpp +++ b/soh/soh/Enhancements/randomizer/context.cpp @@ -358,8 +358,9 @@ GetItemEntry Context::GetArchipelagoGIEntry() { } // get the first item from the archipelago queue - std::string_view recieved_ap_item = mAPrecieveQueue.front(); - RandomizerGet item_id = StaticData::APitemToSoh[recieved_ap_item]; + std::string recieved_ap_item = mAPrecieveQueue.front(); + RandomizerGet item_id = StaticData::itemNameToEnum[recieved_ap_item]; + //RandomizerGet item_id = StaticData::APitemToSoh[recieved_ap_item]; assert(item_id != RG_NONE); Item& item = StaticData::RetrieveItem(item_id); @@ -491,12 +492,14 @@ void Context::ParseArchipelagoItemsLocations(const std::vectorsecond; + //const RandomizerCheck rc = StaticData::APcheckToSoh.find(ap_item.locationName)->second; + const RandomizerCheck rc = StaticData::locationNameToEnum[ap_item.locationName]; if(SlotName == ap_item.playerName) { // our item SPDLOG_TRACE("Populated item {} at location {}", ap_item.itemName, ap_item.locationName); - const RandomizerGet item = StaticData::APitemToSoh.find(ap_item.itemName)->second; + const RandomizerGet item = StaticData::itemNameToEnum[ap_item.itemName]; + //const RandomizerGet item = StaticData::APitemToSoh.find(ap_item.itemName)->second; itemLocationTable[rc].SetPlacedItem(item); } else { // other player item diff --git a/soh/soh/Enhancements/randomizer/fixed_string.hpp b/soh/soh/Enhancements/randomizer/fixed_string.hpp deleted file mode 100644 index 92876e5c1..000000000 --- a/soh/soh/Enhancements/randomizer/fixed_string.hpp +++ /dev/null @@ -1,682 +0,0 @@ -/* - Licensed under the MIT License . - SPDX-License-Identifier: MIT - Copyright (c) 2020 - 2020 Daniil Dudkin. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -#ifndef FIXED_STRING_HPP -#define FIXED_STRING_HPP - -#include -#include -#include -#include -#include -#include - -#define FIXSTR_VERSION_MAJOR 0 -#define FIXSTR_VERSION_MINOR 1 -#define FIXSTR_VERSION_PATCH 1 - -#define FIXSTR_CPP20_CHAR8T_PRESENT __cpp_char8_t -#define FIXSTR_CPP20_SPACESHIP_OPERATOR_PRESENT __cpp_lib_three_way_comparison - -#define FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT (__cpp_lib_constexpr_algorithms) - -#ifdef _MSC_VER -#define FIXSTR_CPP_VERSION _MSVC_LANG -#else -#define FIXSTR_CPP_VERSION __cplusplus -#endif // _MSC_VER - -// Note that when ICC or Clang is in use, FIXSTR_GCC_VERSION might not fully match the actual GCC version on the system. -#define FIXSTR_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -// According to clang documentation, version can be vendor specific -#define FIXSTR_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) - -#if FIXSTR_GCC_VERSION >= 100'000 && FIXSTR_CPP_VERSION > 201703L -#define FIXSTR_CPP20_CNTTP_PRESENT 1 -#elif __cpp_nontype_template_args >= 201911 -#define FIXSTR_CPP20_CNTTP_PRESENT 1 -#elif __cpp_nontype_template_parameter_class >= 201806 -#define FIXSTR_CPP20_CNTTP_PRESENT 1 -#else -// Other compilers do not support cNTTP just yet -#define FIXSTR_CPP20_CNTTP_PRESENT 0 -#endif // FIXSTR_CPP20_CNTTP_PRESENT - -namespace fixstr -{ - -namespace details -{ -template -constexpr OutputIterator copy(InputIterator first, InputIterator last, OutputIterator d_first) -{ -#if FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT - return std::copy(first, last, d_first); -#else - while (first != last) - { - *d_first++ = *first++; - } - return d_first; -#endif // FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT -} - -template -constexpr void fill(ForwardIterator first, ForwardIterator last, const T& value) -{ -#if FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT - std::fill(first, last, value); -#else - for (; first != last; ++first) - { - *first = value; - } -#endif // FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT -} - -} // namespace details - -template > -struct basic_fixed_string // NOLINT(cppcoreguidelines-special-member-functions) -{ - // exposition only - using storage_type = std::array; - storage_type _data{}; - - using traits_type = TTraits; - using value_type = TChar; - using pointer = value_type*; - using const_pointer = const value_type*; - using reference = value_type&; - using const_reference = const value_type&; - using iterator = typename storage_type::iterator; - using const_iterator = typename storage_type::const_iterator; - using reverse_iterator = typename storage_type::reverse_iterator; - using const_reverse_iterator = typename storage_type::const_reverse_iterator; - using size_type = size_t; - using difference_type = ptrdiff_t; - using string_view_type = std::basic_string_view; - static constexpr auto npos = string_view_type::npos; - - constexpr basic_fixed_string() noexcept = default; - - constexpr basic_fixed_string(const value_type (&array)[N + 1]) noexcept // NOLINT(google-explicit-constructor) - { - details::copy(std::begin(array), std::end(array), _data.begin()); - } - - constexpr basic_fixed_string& operator=(const value_type (&array)[N + 1]) noexcept - { - details::copy(std::begin(array), std::end(array), _data.begin()); - return *this; - } - - // iterators - [[nodiscard]] constexpr iterator begin() noexcept { return _data.begin(); } - [[nodiscard]] constexpr const_iterator begin() const noexcept { return _data.begin(); } - [[nodiscard]] constexpr iterator end() noexcept { return _data.end() - 1; } - [[nodiscard]] constexpr const_iterator end() const noexcept { return _data.end() - 1; } - [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return _data.cbegin(); } - [[nodiscard]] constexpr const_iterator cend() const noexcept { return _data.cend() - 1; } - [[nodiscard]] constexpr reverse_iterator rbegin() noexcept { return _data.rbegin() + 1; } - [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return _data.rbegin() + 1; } - [[nodiscard]] constexpr reverse_iterator rend() noexcept { return _data.rend(); } - [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return _data.rend(); } - [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return _data.crbegin() + 1; } - [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return _data.crend(); } - - private: - [[nodiscard]] constexpr static bool static_empty() noexcept { return N == 0; } - - public: - // capacity - [[nodiscard]] constexpr size_type size() const noexcept { return N; } - [[nodiscard]] constexpr size_type length() const noexcept { return N; } - [[nodiscard]] constexpr size_type max_size() const noexcept { return N; } - [[nodiscard]] constexpr bool empty() const noexcept { return static_empty(); } - - // element access - [[nodiscard]] constexpr reference operator[](size_type n) { return _data[n]; } - [[nodiscard]] constexpr const_reference operator[](size_type n) const { return _data[n]; } - [[nodiscard]] constexpr reference at(size_type n) { return _data.at(n); } - [[nodiscard]] constexpr const_reference at(size_type n) const { return _data.at(n); } - - // The lack of C++20 concepts is disappointing - // Basically what every `template<...>` line means is `requires (!empty())` - template > - [[nodiscard]] constexpr reference front() noexcept - { - return _data.front(); - } - template > - [[nodiscard]] constexpr const_reference front() const noexcept - { - return _data.front(); - } - template > - [[nodiscard]] constexpr reference back() noexcept - { - return _data[size() - 1]; - } - template > - [[nodiscard]] constexpr const_reference back() const noexcept - { - return _data[size() - 1]; - } - - [[nodiscard]] constexpr pointer data() noexcept { return _data.data(); } - [[nodiscard]] constexpr const_pointer data() const noexcept { return _data.data(); } - - [[nodiscard]] constexpr const_pointer c_str() const noexcept { return data(); } - - private: - template - using same_with_other_size = basic_fixed_string; - - template - constexpr static size_type calculate_substr_size() - { - if constexpr (pos >= size) - return 0; - - constexpr size_type rcount = std::min(count, size - pos); - - return rcount; - } - - template - using substr_result_type = same_with_other_size()>; - - public: - // string operations - [[nodiscard]] constexpr operator string_view_type() const noexcept // NOLINT(google-explicit-constructor) - { - return {data(), N}; - } - - // clang-format off - template > - [[nodiscard]] constexpr auto substr() const noexcept - -> substr_result_type - // clang-format on - { - substr_result_type result; - details::copy(begin() + pos, begin() + pos + result.size(), result.begin()); - return result; - } - - template - [[nodiscard]] constexpr size_type find(const same_with_other_size& str, size_type pos = 0) const noexcept - { - if constexpr (M > N) - return npos; - return sv().find(str.sv(), pos); - } - [[nodiscard]] constexpr size_type find(string_view_type sv, size_type pos = 0) const noexcept { return sv().find(sv, pos); } - [[nodiscard]] constexpr size_type find(const value_type* s, size_type pos, size_type n) const { return sv().find(s, pos, n); } - [[nodiscard]] constexpr size_type find(const value_type* s, size_type pos = 0) const { return sv().find(s, pos); } - [[nodiscard]] constexpr size_type find(value_type c, size_type pos = 0) const noexcept { return sv().find(c, pos); } - - template - [[nodiscard]] constexpr size_type rfind(const same_with_other_size& str, size_type pos = npos) const noexcept - { - if constexpr (M > N) - return npos; - return sv().rfind(str.sv(), pos); - } - [[nodiscard]] constexpr size_type rfind(string_view_type sv, size_type pos = npos) const noexcept { return sv().rfind(sv, pos); } - [[nodiscard]] constexpr size_type rfind(const value_type* s, size_type pos, size_type n) const { return sv().rfind(s, pos, n); } - [[nodiscard]] constexpr size_type rfind(const value_type* s, size_type pos = npos) const { return sv().rfind(s, pos); } - [[nodiscard]] constexpr size_type rfind(value_type c, size_type pos = npos) const noexcept { return sv().rfind(c, pos); } - - template - [[nodiscard]] constexpr size_type find_first_of(const same_with_other_size& str, size_type pos = 0) const noexcept - { - if constexpr (M > N) - return npos; - return sv().find_first_of(str.sv(), pos); - } - [[nodiscard]] constexpr size_type find_first_of(string_view_type sv, size_type pos = 0) const noexcept { return sv().find_first_of(sv, pos); } - [[nodiscard]] constexpr size_type find_first_of(const value_type* s, size_type pos, size_type n) const { return sv().find_first_of(s, pos, n); } - [[nodiscard]] constexpr size_type find_first_of(const value_type* s, size_type pos = 0) const { return sv().find_first_of(s, pos); } - [[nodiscard]] constexpr size_type find_first_of(value_type c, size_type pos = 0) const noexcept { return sv().find_first_of(c, pos); } - - template - [[nodiscard]] constexpr size_type find_last_of(const same_with_other_size& str, size_type pos = npos) const noexcept - { - if constexpr (M > N) - return npos; - return sv().find_last_of(str.sv(), pos); - } - [[nodiscard]] constexpr size_type find_last_of(string_view_type sv, size_type pos = npos) const noexcept { return sv().find_last_of(sv, pos); } - [[nodiscard]] constexpr size_type find_last_of(const value_type* s, size_type pos, size_type n) const { return sv().find_last_of(s, pos, n); } - [[nodiscard]] constexpr size_type find_last_of(const value_type* s, size_type pos = npos) const { return sv().find_last_of(s, pos); } - [[nodiscard]] constexpr size_type find_last_of(value_type c, size_type pos = npos) const noexcept { return sv().find_last_of(c, pos); } - - template - [[nodiscard]] constexpr size_type find_first_not_of(const same_with_other_size& str, size_type pos = 0) const noexcept - { - if constexpr (M > N) - return npos; - return sv().find_first_of(str.sv(), pos); - } - [[nodiscard]] constexpr size_type find_first_not_of(string_view_type sv, size_type pos = 0) const noexcept { return sv().find_first_not_of(sv, pos); } - [[nodiscard]] constexpr size_type find_first_not_of(const value_type* s, size_type pos, size_type n) const { return sv().find_first_not_of(s, pos, n); } - [[nodiscard]] constexpr size_type find_first_not_of(const value_type* s, size_type pos = 0) const { return sv().find_first_not_of(s, pos); } - [[nodiscard]] constexpr size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept { return sv().find_first_not_of(c, pos); } - - template - [[nodiscard]] constexpr size_type find_last_not_of(const same_with_other_size& str, size_type pos = npos) const noexcept - { - if constexpr (M > N) - return npos; - return sv().find_last_of(str.sv(), pos); - } - [[nodiscard]] constexpr size_type find_last_not_of(string_view_type sv, size_type pos = npos) const noexcept { return sv().find_last_not_of(sv, pos); } - [[nodiscard]] constexpr size_type find_last_not_of(const value_type* s, size_type pos, size_type n) const { return sv().find_last_not_of(s, pos, n); } - [[nodiscard]] constexpr size_type find_last_not_of(const value_type* s, size_type pos = npos) const { return sv().find_last_not_of(s, pos); } - [[nodiscard]] constexpr size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept { return sv().find_last_not_of(c, pos); } - - [[nodiscard]] constexpr int compare(string_view_type v) const noexcept { return sv().compare(v); } - [[nodiscard]] constexpr int compare(size_type pos1, size_type count1, string_view_type v) const { return sv().compare(pos1, count1, v); } - [[nodiscard]] constexpr int compare(size_type pos1, size_type count1, string_view_type v, size_type pos2, size_type count2) const - { - return sv().compare(pos1, count1, v, pos2, count2); - } - [[nodiscard]] constexpr int compare(const value_type* s) const { return sv().compare(s); } - [[nodiscard]] constexpr int compare(size_type pos1, size_type count1, const value_type* s) const { return sv().compare(pos1, count1, s); } - [[nodiscard]] constexpr int compare(size_type pos1, size_type count1, const value_type* s, size_type count2) const - { - return sv().compare(pos1, count1, s, count2); - } - - [[nodiscard]] constexpr bool starts_with(string_view_type v) const noexcept { return sv().substr(0, v.size()) == v; } - [[nodiscard]] constexpr bool starts_with(char c) const noexcept { return !empty() && traits_type::eq(front(), c); } - [[nodiscard]] constexpr bool starts_with(const value_type* s) const noexcept { return starts_with(string_view_type(s)); } - - [[nodiscard]] constexpr bool ends_with(string_view_type sv) const noexcept { return size() >= sv.size() && compare(size() - sv.size(), npos, sv) == 0; } - [[nodiscard]] constexpr bool ends_with(value_type c) const noexcept { return !empty() && traits_type::eq(back(), c); } - [[nodiscard]] constexpr bool ends_with(const value_type* s) const { return ends_with(string_view_type(s)); } - - [[nodiscard]] constexpr bool contains(string_view_type sv) const noexcept { return find(sv) != npos; } - [[nodiscard]] constexpr bool contains(value_type c) const noexcept { return find(c) != npos; } - [[nodiscard]] constexpr bool contains(const value_type* s) const { return find(s) != npos; } - - void swap(basic_fixed_string& other) noexcept(std::is_nothrow_swappable_v) { _data.swap(other._data); } - - private: - constexpr string_view_type sv() const { return *this; } -}; - -template -void swap(basic_fixed_string& lhs, basic_fixed_string& rhs) noexcept(noexcept(lhs.swap(rhs))) -{ - lhs.swap(rhs); -} - -template -[[nodiscard]] constexpr bool operator==(const basic_fixed_string& lhs, const basic_fixed_string& rhs) -{ - if constexpr (M1 != M2) - return false; - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) == rhs; -} - -template -[[nodiscard]] constexpr bool operator==(const basic_fixed_string& lhs, std::basic_string_view rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) == rhs; -} - -template -[[nodiscard]] constexpr bool operator==(std::basic_string_view lhs, const basic_fixed_string& rhs) -{ - using rhs_type = std::decay_t; - using sv_type = typename rhs_type::string_view_type; - return lhs == static_cast(rhs); -} - -#if FIXSTR_CPP20_SPACESHIP_OPERATOR_PRESENT - -template -[[nodiscard]] constexpr auto operator<=>(const basic_fixed_string& lhs, const basic_fixed_string& rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) <=> rhs; -} - -template -[[nodiscard]] constexpr auto operator<=>(const basic_fixed_string& lhs, std::basic_string_view rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) <=> rhs; -} - -template -[[nodiscard]] constexpr auto operator<=>(std::basic_string_view lhs, const basic_fixed_string& rhs) -{ - using rhs_type = std::decay_t; - using sv_type = typename rhs_type::string_view_type; - return lhs <=> static_cast(rhs); -} - -#else - -template -[[nodiscard]] constexpr bool operator!=(const basic_fixed_string& lhs, const basic_fixed_string& rhs) -{ - if constexpr (M1 != M2) - return true; - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) != rhs; -} - -template -[[nodiscard]] constexpr bool operator!=(const basic_fixed_string& lhs, std::basic_string_view rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) != rhs; -} - -template -[[nodiscard]] constexpr bool operator!=(std::basic_string_view lhs, const basic_fixed_string& rhs) -{ - using rhs_type = std::decay_t; - using sv_type = typename rhs_type::string_view_type; - return lhs != static_cast(rhs); -} - -template -[[nodiscard]] constexpr bool operator<(const basic_fixed_string& lhs, const basic_fixed_string& rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) < rhs; -} - -template -[[nodiscard]] constexpr bool operator<(const basic_fixed_string& lhs, std::basic_string_view rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) < rhs; -} - -template -[[nodiscard]] constexpr bool operator<(std::basic_string_view lhs, const basic_fixed_string& rhs) -{ - using rhs_type = std::decay_t; - using sv_type = typename rhs_type::string_view_type; - return lhs < static_cast(rhs); -} - -template -[[nodiscard]] constexpr bool operator<=(const basic_fixed_string& lhs, const basic_fixed_string& rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) <= rhs; -} - -template -[[nodiscard]] constexpr bool operator<=(const basic_fixed_string& lhs, std::basic_string_view rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) <= rhs; -} - -template -[[nodiscard]] constexpr bool operator<=(std::basic_string_view lhs, const basic_fixed_string& rhs) -{ - using rhs_type = std::decay_t; - using sv_type = typename rhs_type::string_view_type; - return lhs <= static_cast(rhs); -} - -template -[[nodiscard]] constexpr bool operator>(const basic_fixed_string& lhs, const basic_fixed_string& rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) > rhs; -} - -template -[[nodiscard]] constexpr bool operator>(const basic_fixed_string& lhs, std::basic_string_view rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) > rhs; -} - -template -[[nodiscard]] constexpr bool operator>(std::basic_string_view lhs, const basic_fixed_string& rhs) -{ - using rhs_type = std::decay_t; - using sv_type = typename rhs_type::string_view_type; - return lhs > static_cast(rhs); -} - -template -[[nodiscard]] constexpr bool operator>=(const basic_fixed_string& lhs, const basic_fixed_string& rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) >= rhs; -} - -template -[[nodiscard]] constexpr bool operator>=(const basic_fixed_string& lhs, std::basic_string_view rhs) -{ - using lhs_type = std::decay_t; - using sv_type = typename lhs_type::string_view_type; - return static_cast(lhs) >= rhs; -} - -template -[[nodiscard]] constexpr bool operator>=(std::basic_string_view lhs, const basic_fixed_string& rhs) -{ - using rhs_type = std::decay_t; - using sv_type = typename rhs_type::string_view_type; - return lhs >= static_cast(rhs); -} - -#endif // FIXSTR_CPP20_SPACESHIP_OPERATOR_PRESENT - -template -basic_fixed_string(const TChar (&)[N]) -> basic_fixed_string; - -// Early GCC versions that support cNTTP were not able to deduce size_t parameter -// of basic_fixed_string when fixed_string and other typedef were just type aliases. -// That's why the following code is written in this way. -template -struct fixed_string : basic_fixed_string -{ - using basic_fixed_string::basic_fixed_string; -}; -template -fixed_string(const char (&)[N]) -> fixed_string; - -#if FIXSTR_CPP20_CHAR8T_PRESENT -template -struct fixed_u8string : basic_fixed_string -{ - using basic_fixed_string::basic_fixed_string; -}; -template -fixed_u8string(const char8_t (&)[N]) -> fixed_u8string; -#endif // FIXSTR_CPP20_CHAR8T_PRESENT - -template -struct fixed_u16string : basic_fixed_string -{ - using basic_fixed_string::basic_fixed_string; -}; -template -fixed_u16string(const char16_t (&)[N]) -> fixed_u16string; - -template -struct fixed_u32string : basic_fixed_string -{ - using basic_fixed_string::basic_fixed_string; -}; -template -fixed_u32string(const char32_t (&)[N]) -> fixed_u32string; - -template -struct fixed_wstring : basic_fixed_string -{ - using basic_fixed_string::basic_fixed_string; -}; -template -fixed_wstring(const wchar_t (&)[N]) -> fixed_wstring; - -template -constexpr basic_fixed_string operator+(const basic_fixed_string& lhs, const basic_fixed_string& rhs) -{ - basic_fixed_string result; - details::copy(lhs.begin(), lhs.end(), result.begin()); - details::copy(rhs.begin(), rhs.end(), result.begin() + N); - return result; -} - -template -constexpr basic_fixed_string operator+(const TChar (&lhs)[N], const basic_fixed_string& rhs) -{ - basic_fixed_string lhs2 = lhs; - return lhs2 + rhs; -} - -template -constexpr basic_fixed_string operator+(const basic_fixed_string& lhs, const TChar (&rhs)[M]) -{ - basic_fixed_string rhs2 = rhs; - return lhs + rhs2; -} - -namespace details -{ -template -constexpr basic_fixed_string from_char(TChar ch) -{ - basic_fixed_string fs; - fs[0] = ch; - return fs; -} -} // namespace details - -template -constexpr basic_fixed_string operator+(TChar lhs, const basic_fixed_string& rhs) -{ - return details::from_char(lhs) + rhs; -} - -template -constexpr basic_fixed_string operator+(const basic_fixed_string& lhs, TChar rhs) -{ - return lhs + details::from_char(rhs); -} - -template -std::basic_ostream& operator<<(std::basic_ostream& out, const basic_fixed_string& str) -{ - out << str.data(); - return out; -} - -} // namespace fixstr - -// hash support -namespace std -{ -template -struct hash> -{ - using argument_type = fixstr::fixed_string; - size_t operator()(const argument_type& str) const - { - using sv_t = typename argument_type::string_view_type; - return std::hash()(static_cast(str)); - } -}; - -#if FIXSTR_CPP20_CHAR8T_PRESENT -template -struct hash> -{ - using argument_type = fixstr::fixed_u8string; - size_t operator()(const argument_type& str) const - { - using sv_t = typename argument_type::string_view_type; - return std::hash()(static_cast(str)); - } -}; -#endif // FIXSTR_CPP20_CHAR8T_PRESENT - -template -struct hash> -{ - using argument_type = fixstr::fixed_u16string; - size_t operator()(const argument_type& str) const - { - using sv_t = typename argument_type::string_view_type; - return std::hash()(static_cast(str)); - } -}; - -template -struct hash> -{ - using argument_type = fixstr::fixed_u32string; - size_t operator()(const argument_type& str) const - { - using sv_t = typename argument_type::string_view_type; - return std::hash()(static_cast(str)); - } -}; - -template -struct hash> -{ - using argument_type = fixstr::fixed_wstring; - size_t operator()(const argument_type& str) const - { - using sv_t = typename argument_type::string_view_type; - return std::hash()(static_cast(str)); - } -}; - -} // namespace std - -#endif // FIXED_STRING_HPP