diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 28c786a19..a2cc40d24 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -233,6 +233,7 @@ const std::vector randomizerCvars = { "gRandomizeShopsanity", "gRandomizeShuffleAdultTrade", "gRandomizeShuffleBeans", + "gRandomizeShuffleBossEntrances", "gRandomizeShuffleCows", "gRandomizeShuffleDungeonReward", "gRandomizeShuffleDungeonsEntrances", diff --git a/soh/soh/Enhancements/randomizer/3drando/entrance.cpp b/soh/soh/Enhancements/randomizer/3drando/entrance.cpp index 442d07f08..e1eeb69d9 100644 --- a/soh/soh/Enhancements/randomizer/3drando/entrance.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/entrance.cpp @@ -81,12 +81,25 @@ void SetAllEntrancesData(std::vector& entranceShuffleTable) { forwardEntrance->SetBlueWarp(forwardEntry.blueWarp); forwardEntrance->SetType(forwardEntry.type); forwardEntrance->SetAsPrimary(); + + // When decouple entrances is on, mark it for entrances except boss rooms + if (Settings::DecoupleEntrances && forwardEntry.type != EntranceType::ChildBoss && + forwardEntry.type != EntranceType::AdultBoss) { + forwardEntrance->SetDecoupled(); + } + if (returnEntry.parentRegion != NONE) { Entrance* returnEntrance = AreaTable(returnEntry.parentRegion)->GetExit(returnEntry.connectedRegion); returnEntrance->SetIndex(returnEntry.index); returnEntrance->SetBlueWarp(returnEntry.blueWarp); returnEntrance->SetType(returnEntry.type); forwardEntrance->BindTwoWay(returnEntrance); + + // Mark reverse entrance as decoupled + if (Settings::DecoupleEntrances && returnEntry.type != EntranceType::ChildBoss && + returnEntry.type != EntranceType::AdultBoss) { + returnEntrance->SetDecoupled(); + } } } } @@ -96,7 +109,7 @@ static std::vector AssumeEntrancePool(std::vector& entranc for (Entrance* entrance : entrancePool) { totalRandomizableEntrances++; Entrance* assumedForward = entrance->AssumeReachable(); - if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) { + if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) { Entrance* assumedReturn = entrance->GetReverse()->AssumeReachable(); if (!(Settings::MixedEntrancePools && (Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances.Is(SHUFFLEINTERIORS_ALL)))) { auto type = entrance->GetType(); @@ -218,7 +231,7 @@ static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) { SPDLOG_DEBUG(message); entrance->Connect(targetEntrance->Disconnect()); entrance->SetReplacement(targetEntrance->GetReplacement()); - if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) { + if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) { targetEntrance->GetReplacement()->GetReverse()->Connect(entrance->GetReverse()->GetAssumed()->Disconnect()); targetEntrance->GetReplacement()->GetReverse()->SetReplacement(entrance->GetReverse()); } @@ -229,7 +242,7 @@ static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) { static void RestoreConnections(Entrance* entrance, Entrance* targetEntrance) { targetEntrance->Connect(entrance->Disconnect()); entrance->SetReplacement(nullptr); - if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) { + if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) { entrance->GetReverse()->GetAssumed()->Connect(targetEntrance->GetReplacement()->GetReverse()->Disconnect()); targetEntrance->GetReplacement()->GetReverse()->SetReplacement(nullptr); } @@ -247,7 +260,7 @@ static void DeleteTargetEntrance(Entrance* targetEntrance) { static void ConfirmReplacement(Entrance* entrance, Entrance* targetEntrance) { DeleteTargetEntrance(targetEntrance); - if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) { + if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) { auto replacedReverse = targetEntrance->GetReplacement()->GetReverse(); DeleteTargetEntrance(replacedReverse->GetReverse()->GetAssumed()); } @@ -786,9 +799,9 @@ int ShuffleAllEntrances() { {EntranceType::SpecialInterior, KAK_POTION_SHOP_BACK, KAK_BACKYARD, 0x04FF}}, // Grotto Loads use an entrance index of 0x0700 + their grotto id. The id is used as index for the - // grottoLoadTable in src/grotto.c + // grottoLoadTable in soh/soh/Enhancements/randomizer/randomizer_grotto.c // Grotto Returns use an entrance index of 0x0800 + their grotto id. The id is used as index for the - // grottoReturnTable in src/grotto.c + // grottoReturnTable in soh/soh/Enhancements/randomizer/randomizer_grotto.c {{EntranceType::GrottoGrave, DESERT_COLOSSUS, COLOSSUS_GROTTO, 0x0700}, {EntranceType::GrottoGrave, COLOSSUS_GROTTO, DESERT_COLOSSUS, 0x0800}}, {{EntranceType::GrottoGrave, LAKE_HYLIA, LH_GROTTO, 0x0701}, @@ -933,6 +946,23 @@ int ShuffleAllEntrances() { {{EntranceType::WarpSong, REQUIEM_OF_SPIRIT_WARP, DESERT_COLOSSUS, 0x01F1}, NO_RETURN_ENTRANCE}, {{EntranceType::WarpSong, NOCTURNE_OF_SHADOW_WARP, GRAVEYARD_WARP_PAD_REGION, 0x0568}, NO_RETURN_ENTRANCE}, {{EntranceType::WarpSong, PRELUDE_OF_LIGHT_WARP, TEMPLE_OF_TIME, 0x05F4}, NO_RETURN_ENTRANCE}, + + {{EntranceType::ChildBoss, DEKU_TREE_BOSS_ENTRYWAY, DEKU_TREE_BOSS_ROOM, 0x040F}, + {EntranceType::ChildBoss, DEKU_TREE_BOSS_ROOM, DEKU_TREE_BOSS_ENTRYWAY, 0x0252, 0x0457}}, + {{EntranceType::ChildBoss, DODONGOS_CAVERN_BOSS_ENTRYWAY, DODONGOS_CAVERN_BOSS_ROOM, 0x040B}, + {EntranceType::ChildBoss, DODONGOS_CAVERN_BOSS_ROOM, DODONGOS_CAVERN_BOSS_ENTRYWAY, 0x00C5, 0x047A}}, + {{EntranceType::ChildBoss, JABU_JABUS_BELLY_BOSS_ENTRYWAY, JABU_JABUS_BELLY_BOSS_ROOM, 0x0301}, + {EntranceType::ChildBoss, JABU_JABUS_BELLY_BOSS_ROOM, JABU_JABUS_BELLY_BOSS_ENTRYWAY, 0x0407, 0x010E}}, + {{EntranceType::AdultBoss, FOREST_TEMPLE_BOSS_ENTRYWAY, FOREST_TEMPLE_BOSS_ROOM, 0x000C}, + {EntranceType::AdultBoss, FOREST_TEMPLE_BOSS_ROOM, FOREST_TEMPLE_BOSS_ENTRYWAY, 0x024E, 0x0608}}, + {{EntranceType::AdultBoss, FIRE_TEMPLE_BOSS_ENTRYWAY, FIRE_TEMPLE_BOSS_ROOM, 0x0305}, + {EntranceType::AdultBoss, FIRE_TEMPLE_BOSS_ROOM, FIRE_TEMPLE_BOSS_ENTRYWAY, 0x0175, 0x0564}}, + {{EntranceType::AdultBoss, WATER_TEMPLE_BOSS_ENTRYWAY, WATER_TEMPLE_BOSS_ROOM, 0x0417}, + {EntranceType::AdultBoss, WATER_TEMPLE_BOSS_ROOM, WATER_TEMPLE_BOSS_ENTRYWAY, 0x0423, 0x060C}}, + {{EntranceType::AdultBoss, SPIRIT_TEMPLE_BOSS_ENTRYWAY, SPIRIT_TEMPLE_BOSS_ROOM, 0x008D}, + {EntranceType::AdultBoss, SPIRIT_TEMPLE_BOSS_ROOM, SPIRIT_TEMPLE_BOSS_ENTRYWAY, 0x02F5, 0x0610}}, + {{EntranceType::AdultBoss, SHADOW_TEMPLE_BOSS_ENTRYWAY, SHADOW_TEMPLE_BOSS_ROOM, 0x0413}, + {EntranceType::AdultBoss, SHADOW_TEMPLE_BOSS_ROOM, SHADOW_TEMPLE_BOSS_ENTRYWAY, 0x02B2, 0x0580}}, }; std::map priorityEntranceTable = { @@ -971,6 +1001,28 @@ int ShuffleAllEntrances() { } } + // Shuffle Bosses + if (Settings::ShuffleBossEntrances.IsNot(SHUFFLEBOSSES_OFF)) { + if (Settings::ShuffleBossEntrances.Is(SHUFFLEBOSSES_FULL)) { + entrancePools[EntranceType::Boss] = GetShuffleableEntrances(EntranceType::ChildBoss); + AddElementsToPool(entrancePools[EntranceType::Boss], GetShuffleableEntrances(EntranceType::AdultBoss)); + // If forest is closed, ensure Ghoma is inside the Deku tree + // Deku tree being in its vanilla location is handled below + if (Settings::OpenForest.Is(OPENFOREST_CLOSED) && !(Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances)) { + FilterAndEraseFromPool(entrancePools[EntranceType::Boss], [](const Entrance* entrance){return entrance->GetParentRegionKey() == DEKU_TREE_BOSS_ENTRYWAY && + entrance->GetConnectedRegionKey() == DEKU_TREE_BOSS_ROOM;}); + } + } else { + entrancePools[EntranceType::ChildBoss] = GetShuffleableEntrances(EntranceType::ChildBoss); + entrancePools[EntranceType::AdultBoss] = GetShuffleableEntrances(EntranceType::AdultBoss); + // If forest is closed, ensure Ghoma is inside the Deku tree + if (Settings::OpenForest.Is(OPENFOREST_CLOSED) && !(Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances)) { + FilterAndEraseFromPool(entrancePools[EntranceType::ChildBoss], [](const Entrance* entrance){return entrance->GetParentRegionKey() == DEKU_TREE_BOSS_ENTRYWAY && + entrance->GetConnectedRegionKey() == DEKU_TREE_BOSS_ROOM;}); + } + } + } + //Shuffle Dungeon Entrances if (Settings::ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) { entrancePools[EntranceType::Dungeon] = GetShuffleableEntrances(EntranceType::Dungeon); diff --git a/soh/soh/Enhancements/randomizer/3drando/entrance.hpp b/soh/soh/Enhancements/randomizer/3drando/entrance.hpp index 42ef1cb50..6634820b1 100644 --- a/soh/soh/Enhancements/randomizer/3drando/entrance.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/entrance.hpp @@ -22,6 +22,9 @@ enum class EntranceType { Dungeon, GanonDungeon, DungeonReverse, + Boss, + ChildBoss, + AdultBoss, Interior, InteriorReverse, SpecialInterior, @@ -180,6 +183,14 @@ public: return primary; } + bool IsDecoupled() const { + return decoupled; + } + + void SetDecoupled() { + decoupled = true; + } + int16_t GetIndex() const { return index; } @@ -269,6 +280,7 @@ private: bool shuffled = false; bool primary = false; bool addedToPool = false; + bool decoupled = false; std::string name = ""; }; diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index 2baf26b8b..0e8ab67e1 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -296,7 +296,7 @@ std::vector GetAccessibleLocations(const std::vector& allowe entranceSphere.push_back(&exit); exit.AddToPool(); // Don't list a two-way coupled entrance from both directions - if (exit.GetReverse() != nullptr && exit.GetReplacement()->GetReverse() != nullptr && !Settings::DecoupleEntrances) { + if (exit.GetReverse() != nullptr && exit.GetReplacement()->GetReverse() != nullptr && !exit.IsDecoupled()) { exit.GetReplacement()->GetReverse()->AddToPool(); } } diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp index 8111d3fb5..f52d1091c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp @@ -2519,93 +2519,61 @@ void HintTable_Init() { | BOSS HINT TEXT | ---------------------------*/ - hintTable[QUEEN_GOHMA] = HintText::Boss( - { - // obscure text - Text{ "An #ancient tree# rewards", /*french*/ "le #vieil arbre# octroie", - /*spanish*/ "un #ancestral árbol# premia con" }, - }, - {}, - // clear text - Text{ "the #Deku Tree# rewards", /*french*/ "l'#Arbre Mojo# octroie", - /*spanish*/ "el #Gran Árbol Deku# premia con" }); + hintTable[QUEEN_GOHMA] = HintText::Boss({ + // obscure text + Text{"the #Parasitic Armored Arachnid# holds", /*french*/"le #monstre insectoïde géant# possède", /*spanish*/"el #arácnido parasitario acorazado# porta"}, + }, {}, + //clear text + Text{"#Queen Gohma# holds", /*french*/"la #Reine Gohma# possède", /*spanish*/"la #Reina Goma# porta"}); - hintTable[KING_DODONGO] = HintText::Boss( - { - // obscure text - Text{ "An #immense cavern# rewards", /*french*/ "l'#immense caverne# octroie", - /*spanish*/ "una #descomunal cueva# premia con" }, - }, - {}, - // clear text - Text{ "#Dodongo's Cavern# rewards", /*french*/ "la #Caverne Dodongo# octroie", - /*spanish*/ "la #Cueva de los Dodongos# premia con" }); + hintTable[KING_DODONGO] = HintText::Boss({ + //obscure text + Text{"the #Infernal Dinosaur# holds", /*french*/"le #dinosaure infernal# possède", /*spanish*/"el #dinosaurio infernal# porta"}, + }, {}, + //clear text + Text{"#King Dodongo# holds", /*french*/"le #Roi Dodongo# possède", /*spanish*/"el #Rey Dodongo# porta"}); - hintTable[BARINADE] = HintText::Boss( - { - // obscure text - Text{ "the #belly of a deity# rewards", /*french*/ "le #ventre du gardien# octroie", - /*spanish*/ "la #tripa de cierta deidad# premia con" }, - }, - {}, - // clear text - Text{ "#Jabu-Jabu's Belly# rewards", /*french*/ "le #Ventre de Jabu-Jabu# octroie", - /*spanish*/ "la #tripa de Jabu-Jabu# premia con" }); + hintTable[BARINADE] = HintText::Boss({ + //obscure text + Text{"the #Bio-Electric Anemone# holds", /*french*/"l'#anémone bioélectrique# possède", /*spanish*/"la #anémona bioeléctrica# porta"}, + }, {}, + //clear text + Text{"#Barinade# holds", /*french*/"#Barinade# possède", /*spanish*/"#Barinade# porta"}); - hintTable[PHANTOM_GANON] = HintText::Boss( - { - // obscure text - Text{ "a #deep forest# rewards", /*french*/ "la #profonde forêt# octroie", - /*spanish*/ "el #profundo bosque# premia con" }, - }, - {}, - // clear text - Text{ "the #Forest Temple# rewards", /*french*/ "le #Temple de la Forêt# octroie", - /*spanish*/ "el #Templo del Bosque# premia con" }); + hintTable[PHANTOM_GANON] = HintText::Boss({ + //obscure text + Text{"the #Evil Spirit from Beyond# holds", /*french*/"l'#esprit maléfique de l'au-delà# possède", /*spanish*/"el #espíritu maligno de ultratumba# porta"}, + }, {}, + //clear text + Text{"#Phantom Ganon# holds", /*french*/"#Ganon Spectral# possède", /*spanish*/"#Ganon Fantasma# porta"}); - hintTable[VOLVAGIA] = HintText::Boss( - { - // obscure text - Text{ "a #high mountain# rewards", /*french*/ "la #grande montagne# octroie", - /*spanish*/ "una #alta montaña# premia con" }, - }, - {}, - // clear text - Text{ "the #Fire Temple# rewards", /*french*/ "le #Temple du Feu# octroie", - /*spanish*/ "el #Templo del Fuego# premia con" }); + hintTable[VOLVAGIA] = HintText::Boss({ + //obscure text + Text{"the #Subterranean Lava Dragon# holds", /*french*/"le #dragon des profondeurs# possède", /*spanish*/"el #dragón de lava subterráneo# porta"}, + }, {}, + //clear text + Text{"#Volvagia# holds", /*french*/"#Volvagia# possède", /*spanish*/"#Volvagia# porta"}); - hintTable[MORPHA] = HintText::Boss( - { - // obscure text - Text{ "a #vast lake# rewards", /*french*/ "le #vaste lac# octroie", - /*spanish*/ "un #lago inmenso# premia con" }, - }, - {}, - // clear text - Text{ "the #Water Temple# rewards", /*french*/ "le #Temple de l'Eau# octroie", - /*spanish*/ "el #Templo del Agua# premia con" }); + hintTable[MORPHA] = HintText::Boss({ + //obscure text + Text{"the #Giant Aquatic Amoeba# holds", /*french*/"l'#amibe aquatique géante# possède", /*spanish*/"la #ameba acuática gigante# porta"}, + }, {}, + //clear text + Text{"#Morpha# holds", /*french*/"#Morpha# possède", /*spanish*/"#Morpha# porta"}); - hintTable[BONGO_BONGO] = HintText::Boss( - { - // obscure text - Text{ "the #house of the dead# rewards", /*french*/ "la #maison des morts# octroie", - /*spanish*/ "la #casa de la muerte# premia con" }, - }, - {}, - // clear text - Text{ "the #Shadow Temple# rewards", /*french*/ "le #Temple de l'Ombre# octroie", - /*spanish*/ "el #Templo de las Sombras#" }); + hintTable[BONGO_BONGO] = HintText::Boss({ + //obscure text + Text{"the #Phantom Shadow Beast# holds", /*french*/"le #monstre de l'ombre# possède", /*spanish*/"la #alimaña oscura espectral# porta"}, + }, {}, + //clear text + Text{"#Bongo Bongo# holds", /*french*/"#Bongo Bongo# possède", /*spanish*/"#Bongo Bongo# porta"}); - hintTable[TWINROVA] = HintText::Boss( - { - // obscure text - Text{ "a #goddess of the sand# rewards", /*french*/ "la #déesse des sables# octroie", - /*spanish*/ "la #diosa de la arena# premia con" }, - }, - {}, - // clear text - Text{ "the #Spirit Temple# rewards", /*french*/ "le #Temple de l'Esprit# octroie", - /*spanish*/ "el #Templo del Espíritu# premia con" }); + hintTable[TWINROVA] = HintText::Boss({ + //obscure text + Text{"the #Sorceress Sisters# hold", /*french*/"#les sorcières jumelles# possède", /*spanish*/"las #hermanas hechiceras# portan"}, + }, {}, + //clear text + Text{"#Twinrova# holds", /*french*/"#Twinrova# possède", /*spanish*/"#Birova# porta"}); // // [LINKS_POCKET_BOSS] = HintText::Boss({ // //obscure text diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.cpp b/soh/soh/Enhancements/randomizer/3drando/hints.cpp index ac1aec641..6b613246b 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hints.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hints.cpp @@ -317,17 +317,12 @@ static void CreateWothHint(uint8_t* remainingDungeonWothHints) { Location(hintedLocation)->SetAsHinted(); uint32_t gossipStone = RandomElement(gossipStoneLocations); - // form hint text - Text locationText; if (Location(hintedLocation)->IsDungeon()) { *remainingDungeonWothHints -= 1; - uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); - locationText = AreaTable(parentRegion)->GetHint().GetText(); - - } else { - uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); - locationText = GetHintRegion(parentRegion)->GetHint().GetText(); } + + // form hint text + Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); Text finalWothHint = Hint(PREFIX).GetText() + "#" + locationText + "#" + Hint(WAY_OF_THE_HERO).GetText(); SPDLOG_DEBUG("\tMessage: "); SPDLOG_DEBUG(finalWothHint.english); @@ -365,16 +360,12 @@ static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vectorSetAsHinted(); uint32_t gossipStone = RandomElement(gossipStoneLocations); - // form hint text - Text locationText; if (Location(hintedLocation)->IsDungeon()) { *remainingDungeonBarrenHints -= 1; - uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); - locationText = Hint(AreaTable(parentRegion)->hintKey).GetText(); - } else { - uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); - locationText = Hint(GetHintRegion(parentRegion)->hintKey).GetText(); } + + // form hint text + Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); Text finalBarrenHint = Hint(PREFIX).GetText() + Hint(PLUNDERING).GetText() + "#" + locationText + "#" + Hint(FOOLISH).GetText(); SPDLOG_DEBUG("\tMessage: "); @@ -419,16 +410,15 @@ static void CreateRandomLocationHint(const bool goodItem = false) { //form hint text Text itemText = Location(hintedLocation)->GetPlacedItem().GetHint().GetText(); + Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); + // RANDOTODO: reconsider dungeon vs non-dungeon item location hints when boss shuffle mixed pools happens if (Location(hintedLocation)->IsDungeon()) { - uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); - Text locationText = AreaTable(parentRegion)->GetHint().GetText(); Text finalHint = Hint(PREFIX).GetText()+"#"+locationText+"# "+Hint(HOARDS).GetText()+" #"+itemText+"#."; SPDLOG_DEBUG("\tMessage: "); SPDLOG_DEBUG(finalHint.english); SPDLOG_DEBUG("\n\n"); AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}); } else { - Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); Text finalHint = Hint(PREFIX).GetText()+"#"+itemText+"# "+Hint(CAN_BE_FOUND_AT).GetText()+" #"+locationText+"#."; SPDLOG_DEBUG("\tMessage: "); SPDLOG_DEBUG(finalHint.english); diff --git a/soh/soh/Enhancements/randomizer/3drando/keys.hpp b/soh/soh/Enhancements/randomizer/3drando/keys.hpp index 1ef1e018e..0016ff205 100644 --- a/soh/soh/Enhancements/randomizer/3drando/keys.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/keys.hpp @@ -1083,6 +1083,8 @@ typedef enum { DEATH_MOUNTAIN_CRATER, //AREAS + MARKER_AREAS_START, // Used for area key count + ROOT, ROOT_EXITS, CHILD_SPAWN, @@ -1263,6 +1265,16 @@ typedef enum { DEKU_TREE_BASEMENT_BACK_ROOM, DEKU_TREE_BASEMENT_UPPER, DEKU_TREE_OUTSIDE_BOSS_ROOM, + + DEKU_TREE_MQ_LOBBY, + DEKU_TREE_MQ_COMPASS_ROOM, + DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, + DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, + DEKU_TREE_MQ_BASEMENT_BACK_ROOM, + DEKU_TREE_MQ_BASEMENT_LEDGE, + DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, + + DEKU_TREE_BOSS_ENTRYWAY, DEKU_TREE_BOSS_ROOM, DODONGOS_CAVERN_BEGINNING, @@ -1287,6 +1299,14 @@ typedef enum { DODONGOS_CAVERN_FAR_BRIDGE, DODONGOS_CAVERN_BOSS_AREA, DODONGOS_CAVERN_BACK_ROOM, + + DODONGOS_CAVERN_MQ_BEGINNING, + DODONGOS_CAVERN_MQ_LOBBY, + DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, + DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, + DODONGOS_CAVERN_MQ_BOSS_AREA, + + DODONGOS_CAVERN_BOSS_ENTRYWAY, DODONGOS_CAVERN_BOSS_ROOM, JABU_JABUS_BELLY_BEGINNING, @@ -1306,6 +1326,13 @@ typedef enum { JABU_JABUS_BELLY_ABOVE_BIGOCTO, JABU_JABUS_BELLY_LIFT_UPPER, JABU_JABUS_BELLY_NEAR_BOSS_ROOM, + + JABU_JABUS_BELLY_MQ_BEGINNING, + JABU_JABUS_BELLY_MQ_MAIN, + JABU_JABUS_BELLY_MQ_DEPTHS, + JABU_JABUS_BELLY_MQ_BOSS_AREA, + + JABU_JABUS_BELLY_BOSS_ENTRYWAY, JABU_JABUS_BELLY_BOSS_ROOM, FOREST_TEMPLE_FIRST_ROOM, @@ -1335,11 +1362,24 @@ typedef enum { FOREST_TEMPLE_GREEN_POE_ROOM, FOREST_TEMPLE_EAST_CORRIDOR, FOREST_TEMPLE_BOSS_REGION, + + FOREST_TEMPLE_MQ_LOBBY, + FOREST_TEMPLE_MQ_CENTRAL_AREA, + FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, + FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, + FOREST_TEMPLE_MQ_NW_OUTDOORS, + FOREST_TEMPLE_MQ_NE_OUTDOORS, + FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, + FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, + FOREST_TEMPLE_MQ_BOW_REGION, + FOREST_TEMPLE_MQ_FALLING_ROOM, + FOREST_TEMPLE_MQ_BOSS_REGION, + + FOREST_TEMPLE_BOSS_ENTRYWAY, FOREST_TEMPLE_BOSS_ROOM, FIRE_TEMPLE_FIRST_ROOM, FIRE_TEMPLE_NEAR_BOSS_ROOM, - FIRE_TEMPLE_BOSS_ROOM, FIRE_TEMPLE_LOOP_ENEMIES, FIRE_TEMPLE_LOOP_TILES, FIRE_TEMPLE_LOOP_FLARE_DANCER, @@ -1374,6 +1414,16 @@ typedef enum { FIRE_TEMPLE_HAMMER_RETURN_PATH, FIRE_TEMPLE_ABOVE_FIRE_MAZE, + FIRE_TEMPLE_MQ_LOWER, + FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, + FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, + FIRE_TEMPLE_MQ_LOWER_MAZE, + FIRE_TEMPLE_MQ_UPPER_MAZE, + FIRE_TEMPLE_MQ_UPPER, + + FIRE_TEMPLE_BOSS_ENTRYWAY, + FIRE_TEMPLE_BOSS_ROOM, + WATER_TEMPLE_LOBBY, WATER_TEMPLE_EAST_LOWER, WATER_TEMPLE_MAP_ROOM, @@ -1401,6 +1451,14 @@ typedef enum { WATER_TEMPLE_LONGSHOT_ROOM, WATER_TEMPLE_RIVER, WATER_TEMPLE_PRE_BOSS_ROOM, + + WATER_TEMPLE_MQ_LOBBY, + WATER_TEMPLE_MQ_DIVE, + WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS, + WATER_TEMPLE_MQ_DARK_LINK_REGION, + WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS, + + WATER_TEMPLE_BOSS_ENTRYWAY, WATER_TEMPLE_BOSS_ROOM, SPIRIT_TEMPLE_LOBBY, @@ -1411,82 +1469,7 @@ typedef enum { SPIRIT_TEMPLE_OUTDOOR_HANDS, SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, - - SHADOW_TEMPLE_BEGINNING, - SHADOW_TEMPLE_FIRST_BEAMOS, - SHADOW_TEMPLE_HUGE_PIT, - SHADOW_TEMPLE_WIND_TUNNEL, - SHADOW_TEMPLE_BEYOND_BOAT, - - BOTTOM_OF_THE_WELL, - BOTTOM_OF_THE_WELL_MAIN_AREA, - - ICE_CAVERN_BEGINNING, - ICE_CAVERN_MAIN, - - GERUDO_TRAINING_GROUNDS_LOBBY, - GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, - GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, - GERUDO_TRAINING_GROUNDS_LAVA_ROOM, - GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, - GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, - GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, - GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, - GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, - - GANONS_CASTLE_LOBBY, - GANONS_CASTLE_DEKU_SCRUBS, - GANONS_CASTLE_FOREST_TRIAL, - GANONS_CASTLE_FIRE_TRIAL, - GANONS_CASTLE_WATER_TRIAL, - GANONS_CASTLE_SHADOW_TRIAL, - GANONS_CASTLE_SPIRIT_TRIAL, - GANONS_CASTLE_LIGHT_TRIAL, - GANONS_CASTLE_TOWER, - - DEKU_TREE_MQ_LOBBY, - DEKU_TREE_MQ_COMPASS_ROOM, - DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, - DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, - DEKU_TREE_MQ_BASEMENT_BACK_ROOM, - DEKU_TREE_MQ_BASEMENT_LEDGE, - - DODONGOS_CAVERN_MQ_BEGINNING, - DODONGOS_CAVERN_MQ_LOBBY, - DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, - DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, - DODONGOS_CAVERN_MQ_BOSS_AREA, - - JABU_JABUS_BELLY_MQ_BEGINNING, - JABU_JABUS_BELLY_MQ_MAIN, - JABU_JABUS_BELLY_MQ_DEPTHS, - JABU_JABUS_BELLY_MQ_BOSS_AREA, - - FOREST_TEMPLE_MQ_LOBBY, - FOREST_TEMPLE_MQ_CENTRAL_AREA, - FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, - FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, - FOREST_TEMPLE_MQ_NW_OUTDOORS, - FOREST_TEMPLE_MQ_NE_OUTDOORS, - FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, - FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, - FOREST_TEMPLE_MQ_BOW_REGION, - FOREST_TEMPLE_MQ_FALLING_ROOM, - FOREST_TEMPLE_MQ_BOSS_REGION, - - FIRE_TEMPLE_MQ_LOWER, - FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, - FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, - FIRE_TEMPLE_MQ_LOWER_MAZE, - FIRE_TEMPLE_MQ_UPPER_MAZE, - FIRE_TEMPLE_MQ_UPPER, - FIRE_TEMPLE_MQ_BOSS_ROOM, - - WATER_TEMPLE_MQ_LOBBY, - WATER_TEMPLE_MQ_DIVE, - WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS, - WATER_TEMPLE_MQ_DARK_LINK_REGION, - WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS, + SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, SPIRIT_TEMPLE_MQ_LOBBY, SPIRIT_TEMPLE_MQ_CHILD, @@ -1496,6 +1479,16 @@ typedef enum { SPIRIT_TEMPLE_MQ_BOSS_AREA, SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, + SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD, + + SPIRIT_TEMPLE_BOSS_ENTRYWAY, + SPIRIT_TEMPLE_BOSS_ROOM, + + SHADOW_TEMPLE_BEGINNING, + SHADOW_TEMPLE_FIRST_BEAMOS, + SHADOW_TEMPLE_HUGE_PIT, + SHADOW_TEMPLE_WIND_TUNNEL, + SHADOW_TEMPLE_BEYOND_BOAT, SHADOW_TEMPLE_MQ_ENTRYWAY, SHADOW_TEMPLE_MQ_BEGINNING, @@ -1507,15 +1500,32 @@ typedef enum { SHADOW_TEMPLE_MQ_BEYOND_BOAT, SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, - BOTTOM_OF_THE_WELL_MQ, + SHADOW_TEMPLE_BOSS_ENTRYWAY, + SHADOW_TEMPLE_BOSS_ROOM, + + BOTTOM_OF_THE_WELL_MAIN_AREA, + BOTTOM_OF_THE_WELL_MQ_PERIMETER, BOTTOM_OF_THE_WELL_MQ_MIDDLE, + ICE_CAVERN_BEGINNING, + ICE_CAVERN_MAIN, + ICE_CAVERN_MQ_BEGINNING, ICE_CAVERN_MQ_MAP_ROOM, ICE_CAVERN_MQ_IRON_BOOTS_REGION, ICE_CAVERN_MQ_COMPASS_ROOM, + GERUDO_TRAINING_GROUNDS_LOBBY, + GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, + GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, + GERUDO_TRAINING_GROUNDS_LAVA_ROOM, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, + GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, + GERUDO_TRAINING_GROUNDS_MQ_LOBBY, GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, @@ -1524,6 +1534,16 @@ typedef enum { GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, + GANONS_CASTLE_LOBBY, + GANONS_CASTLE_DEKU_SCRUBS, + GANONS_CASTLE_FOREST_TRIAL, + GANONS_CASTLE_FIRE_TRIAL, + GANONS_CASTLE_WATER_TRIAL, + GANONS_CASTLE_SHADOW_TRIAL, + GANONS_CASTLE_SPIRIT_TRIAL, + GANONS_CASTLE_LIGHT_TRIAL, + GANONS_CASTLE_TOWER, + GANONS_CASTLE_MQ_LOBBY, GANONS_CASTLE_MQ_DEKU_SCRUBS, GANONS_CASTLE_MQ_FOREST_TRIAL, @@ -1533,6 +1553,8 @@ typedef enum { GANONS_CASTLE_MQ_SPIRIT_TRIAL, GANONS_CASTLE_MQ_LIGHT_TRIAL, + MARKER_AREAS_END, // Used for area key count + //DUNGEONS DEKU_TREE, DODONGOS_CAVERN, @@ -1542,8 +1564,8 @@ typedef enum { WATER_TEMPLE, SPIRIT_TEMPLE, SHADOW_TEMPLE, + BOTTOM_OF_THE_WELL, ICE_CAVERN, - //BOTTOM_OF_THE_WELL, GERUDO_TRAINING_GROUNDS, GANONS_CASTLE, diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp index e77d7943c..cefa5229f 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp @@ -371,458 +371,24 @@ void AreaTable_Init() { namespace Areas { - static std::array allAreas = { - ROOT, - ROOT_EXITS, + const auto GetAllAreas() { + static const size_t areaCount = MARKER_AREAS_END - (MARKER_AREAS_START + 1); - CHILD_SPAWN, - ADULT_SPAWN, - MINUET_OF_FOREST_WARP, - BOLERO_OF_FIRE_WARP, - SERENADE_OF_WATER_WARP, - REQUIEM_OF_SPIRIT_WARP, - NOCTURNE_OF_SHADOW_WARP, - PRELUDE_OF_LIGHT_WARP, + static std::array allAreas = {}; - KOKIRI_FOREST, - KF_LINKS_HOUSE, - KF_MIDOS_HOUSE, - KF_SARIAS_HOUSE, - KF_HOUSE_OF_TWINS, - KF_KNOW_IT_ALL_HOUSE, - KF_KOKIRI_SHOP, - KF_STORMS_GROTTO, - KF_OUTSIDE_DEKU_TREE, - DEKU_TREE_ENTRYWAY, + static bool intialized = false; + if (!intialized) { + for (size_t i = 0; i < areaCount; i++) { + allAreas[i] = (MARKER_AREAS_START + 1) + i; + } + intialized = true; + } - THE_LOST_WOODS, - LW_BRIDGE_FROM_FOREST, - LW_BRIDGE, - LW_FOREST_EXIT, - LW_BEYOND_MIDO, - LW_NEAR_SHORTCUTS_GROTTO, - DEKU_THEATER, - LW_SCRUBS_GROTTO, - SFM_ENTRYWAY, - SACRED_FOREST_MEADOW, - SFM_WOLFOS_GROTTO, - SFM_FAIRY_GROTTO, - SFM_STORMS_GROTTO, - FOREST_TEMPLE_ENTRYWAY, - - KAKARIKO_VILLAGE, - KAK_CARPENTER_BOSS_HOUSE, - KAK_HOUSE_OF_SKULLTULA, - KAK_IMPAS_HOUSE, - KAK_IMPAS_LEDGE, - KAK_IMPAS_HOUSE_BACK, - KAK_IMPAS_HOUSE_NEAR_COW, - KAK_WINDMILL, - KAK_BAZAAR, - KAK_SHOOTING_GALLERY, - KAK_POTION_SHOP_FRONT, - KAK_POTION_SHOP_BACK, - KAK_ROOFTOP, - KAK_IMPAS_ROOFTOP, - KAK_BEHIND_GATE, - KAK_BACKYARD, - KAK_ODD_POTION_BUILDING, - KAK_REDEAD_GROTTO, - KAK_OPEN_GROTTO, - BOTTOM_OF_THE_WELL_ENTRYWAY, - - THE_GRAVEYARD, - GRAVEYARD_DAMPES_GRAVE, - GRAVEYARD_DAMPES_HOUSE, - GRAVEYARD_SHIELD_GRAVE, - GRAVEYARD_COMPOSERS_GRAVE, - GRAVEYARD_HEART_PIECE_GRAVE, - GRAVEYARD_WARP_PAD_REGION, - SHADOW_TEMPLE_ENTRYWAY, - - DEATH_MOUNTAIN_TRAIL, - DEATH_MOUNTAIN_SUMMIT, - DMT_OWL_FLIGHT, - DMT_GREAT_FAIRY_FOUNTAIN, - DMT_COW_GROTTO, - DMT_STORMS_GROTTO, - DODONGOS_CAVERN_ENTRYWAY, - - DMC_UPPER_LOCAL, - DMC_CENTRAL_LOCAL, - DMC_LOWER_LOCAL, - DMC_LOWER_NEARBY, - DMC_UPPER_NEARBY, - DMC_CENTRAL_NEARBY, - DMC_LADDER_AREA_NEARBY, - DMC_UPPER_GROTTO, - DMC_HAMMER_GROTTO, - DMC_GREAT_FAIRY_FOUNTAIN, - FIRE_TEMPLE_ENTRYWAY, - - GORON_CITY, - GC_WOODS_WARP, - GC_DARUNIAS_CHAMBER, - GC_GROTTO_PLATFORM, - GC_SHOP, - GC_GROTTO, - - ZR_FRONT, - ZORAS_RIVER, - ZR_BEHIND_WATERFALL, - ZR_OPEN_GROTTO, - ZR_FAIRY_GROTTO, - ZR_STORMS_GROTTO, - ZORAS_DOMAIN, - ZD_BEHIND_KING_ZORA, - ZD_SHOP, - ZD_STORMS_GROTTO, - ZORAS_FOUNTAIN, - ZF_GREAT_FAIRY_FOUNTAIN, - JABU_JABUS_BELLY_ENTRYWAY, - ICE_CAVERN_ENTRYWAY, - - HYRULE_FIELD, - HF_SOUTHEAST_GROTTO, - HF_OPEN_GROTTO, - HF_INSIDE_FENCE_GROTTO, - HF_COW_GROTTO, - HF_NEAR_MARKET_GROTTO, - HF_FAIRY_GROTTO, - HF_NEAR_KAK_GROTTO, - HF_TEKTITE_GROTTO, - - LON_LON_RANCH, - LLR_TALONS_HOUSE, - LLR_STABLES, - LLR_TOWER, - LLR_GROTTO, - - LAKE_HYLIA, - LH_OWL_FLIGHT, - LH_LAB, - LH_FISHING_ISLAND, - LH_FISHING_HOLE, - LH_GROTTO, - WATER_TEMPLE_ENTRYWAY, - - GERUDO_VALLEY, - GV_UPPER_STREAM, - GV_LOWER_STREAM, - GV_GROTTO_LEDGE, - GV_CRATE_LEDGE, - GV_OCTOROK_GROTTO, - GV_FORTRESS_SIDE, - GV_CARPENTER_TENT, - GV_STORMS_GROTTO, - GERUDO_FORTRESS, - GF_OUTSIDE_GATE, - GF_STORMS_GROTTO, - GERUDO_TRAINING_GROUNDS_ENTRYWAY, - - WASTELAND_NEAR_FORTRESS, - HAUNTED_WASTELAND, - WASTELAND_NEAR_COLOSSUS, - DESERT_COLOSSUS, - DESERT_COLOSSUS_FROM_SPIRIT_ENTRYWAY, - COLOSSUS_GREAT_FAIRY_FOUNTAIN, - COLOSSUS_GROTTO, - SPIRIT_TEMPLE_ENTRYWAY, - - MARKET_ENTRANCE, - THE_MARKET, - MARKET_GUARD_HOUSE, - MARKET_BAZAAR, - MARKET_MASK_SHOP, - MARKET_SHOOTING_GALLERY, - MARKET_BOMBCHU_BOWLING, - MARKET_TREASURE_CHEST_GAME, - MARKET_POTION_SHOP, - MARKET_BACK_ALLEY, - MARKET_BOMBCHU_SHOP, - MARKET_DOG_LADY_HOUSE, - MARKET_MAN_IN_GREEN_HOUSE, - TOT_ENTRANCE, - TEMPLE_OF_TIME, - TOT_BEYOND_DOOR_OF_TIME, - - CASTLE_GROUNDS, - HYRULE_CASTLE_GROUNDS, - HC_GARDEN, - HC_GREAT_FAIRY_FOUNTAIN, - HC_STORMS_GROTTO, - GANONS_CASTLE_GROUNDS, - OGC_GREAT_FAIRY_FOUNTAIN, - GANONS_CASTLE_ENTRYWAY, - - DEKU_TREE_LOBBY, - DEKU_TREE_2F_MIDDLE_ROOM, - DEKU_TREE_SLINGSHOT_ROOM, - DEKU_TREE_COMPASS_ROOM, - DEKU_TREE_BASEMENT_LOWER, - DEKU_TREE_BASEMENT_SCRUB_ROOM, - DEKU_TREE_BASEMENT_WATER_ROOM, - DEKU_TREE_BASEMENT_TORCH_ROOM, - DEKU_TREE_BASEMENT_BACK_LOBBY, - DEKU_TREE_BASEMENT_BACK_ROOM, - DEKU_TREE_BASEMENT_UPPER, - DEKU_TREE_OUTSIDE_BOSS_ROOM, - DEKU_TREE_BOSS_ROOM, - - DODONGOS_CAVERN_BEGINNING, - DODONGOS_CAVERN_LOBBY, - DODONGOS_CAVERN_LOBBY_SWITCH, - DODONGOS_CAVERN_SE_CORRIDOR, - DODONGOS_CAVERN_SE_ROOM, - DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, - DODONGOS_CAVERN_LOWER_LIZALFOS, - DODONGOS_CAVERN_DODONGO_ROOM, - DODONGOS_CAVERN_NEAR_DODONGO_ROOM, - DODONGOS_CAVERN_STAIRS_LOWER, - DODONGOS_CAVERN_STAIRS_UPPER, - DODONGOS_CAVERN_COMPASS_ROOM, - DODONGOS_CAVERN_ARMOS_ROOM, - DODONGOS_CAVERN_BOMB_ROOM_LOWER, - DODONGOS_CAVERN_2F_SIDE_ROOM, - DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, - DODONGOS_CAVERN_UPPER_LIZALFOS, - DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, - DODONGOS_CAVERN_BOMB_ROOM_UPPER, - DODONGOS_CAVERN_FAR_BRIDGE, - DODONGOS_CAVERN_BOSS_AREA, - DODONGOS_CAVERN_BACK_ROOM, - DODONGOS_CAVERN_BOSS_ROOM, - - JABU_JABUS_BELLY_BEGINNING, - JABU_JABUS_BELLY_LIFT_MIDDLE, - JABU_JABUS_BELLY_MAIN_UPPER, - JABU_JABUS_BELLY_MAIN_LOWER, - JABU_JABUS_BELLY_SHABOMB_CORRIDOR, - JABU_JABUS_BELLY_LOWER_SIDE_ROOM, - JABU_JABUS_BELLY_LIFT_LOWER, - JABU_JABUS_BELLY_FORKED_CORRIDOR, - JABU_JABUS_BELLY_BOOMERANG_ROOM, - JABU_JABUS_BELLY_MAP_ROOM, - JABU_JABUS_BELLY_COMPASS_ROOM, - JABU_JABUS_BELLY_BLUE_TENTACLE, - JABU_JABUS_BELLY_GREEN_TENTACLE, - JABU_JABUS_BELLY_BIGOCTO_ROOM, - JABU_JABUS_BELLY_ABOVE_BIGOCTO, - JABU_JABUS_BELLY_LIFT_UPPER, - JABU_JABUS_BELLY_NEAR_BOSS_ROOM, - JABU_JABUS_BELLY_BOSS_ROOM, - - FOREST_TEMPLE_FIRST_ROOM, - FOREST_TEMPLE_SOUTH_CORRIDOR, - FOREST_TEMPLE_LOBBY, - FOREST_TEMPLE_NORTH_CORRIDOR, - FOREST_TEMPLE_LOWER_STALFOS, - FOREST_TEMPLE_NW_OUTDOORS_LOWER, - FOREST_TEMPLE_NW_OUTDOORS_UPPER, - FOREST_TEMPLE_NE_OUTDOORS_LOWER, - FOREST_TEMPLE_NE_OUTDOORS_UPPER, - FOREST_TEMPLE_MAP_ROOM, - FOREST_TEMPLE_SEWER, - FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, - FOREST_TEMPLE_FLOORMASTER_ROOM, - FOREST_TEMPLE_WEST_CORRIDOR, - FOREST_TEMPLE_BLOCK_PUSH_ROOM, - FOREST_TEMPLE_NW_CORRIDOR_TWISTED, - FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, - FOREST_TEMPLE_RED_POE_ROOM, - FOREST_TEMPLE_UPPER_STALFOS, - FOREST_TEMPLE_BLUE_POE_ROOM, - FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, - FOREST_TEMPLE_NE_CORRIDOR_TWISTED, - FOREST_TEMPLE_FROZEN_EYE_ROOM, - FOREST_TEMPLE_FALLING_ROOM, - FOREST_TEMPLE_GREEN_POE_ROOM, - FOREST_TEMPLE_EAST_CORRIDOR, - FOREST_TEMPLE_BOSS_REGION, - FOREST_TEMPLE_BOSS_ROOM, - - FIRE_TEMPLE_FIRST_ROOM, - FIRE_TEMPLE_NEAR_BOSS_ROOM, - FIRE_TEMPLE_BOSS_ROOM, - FIRE_TEMPLE_LOOP_ENEMIES, - FIRE_TEMPLE_LOOP_TILES, - FIRE_TEMPLE_LOOP_FLARE_DANCER, - FIRE_TEMPLE_LOOP_HAMMER_SWITCH, - FIRE_TEMPLE_LOOP_GORON_ROOM, - FIRE_TEMPLE_LOOP_EXIT, - FIRE_TEMPLE_BIG_LAVA_ROOM, - FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON, - FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, - FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON, - FIRE_TEMPLE_FIRE_PILLAR_ROOM, - FIRE_TEMPLE_SHORTCUT_ROOM, - FIRE_TEMPLE_SHORTCUT_CLIMB, - FIRE_TEMPLE_BOULDER_MAZE_LOWER, - FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM, - FIRE_TEMPLE_EAST_CENTRAL_ROOM, - FIRE_TEMPLE_FIRE_WALL_CHASE, - FIRE_TEMPLE_MAP_AREA, - FIRE_TEMPLE_BOULDER_MAZE_UPPER, - FIRE_TEMPLE_SCARECROW_ROOM, - FIRE_TEMPLE_EAST_PEAK, - FIRE_TEMPLE_CORRIDOR, - FIRE_TEMPLE_FIRE_MAZE_ROOM, - FIRE_TEMPLE_FIRE_MAZE_UPPER, - FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM, - FIRE_TEMPLE_WEST_CENTRAL_LOWER, - FIRE_TEMPLE_WEST_CENTRAL_UPPER, - FIRE_TEMPLE_LATE_FIRE_MAZE, - FIRE_TEMPLE_UPPER_FLARE_DANCER, - FIRE_TEMPLE_WEST_CLIMB, - FIRE_TEMPLE_WEST_PEAK, - FIRE_TEMPLE_HAMMER_RETURN_PATH, - FIRE_TEMPLE_ABOVE_FIRE_MAZE, - - WATER_TEMPLE_LOBBY, - WATER_TEMPLE_EAST_LOWER, - WATER_TEMPLE_MAP_ROOM, - WATER_TEMPLE_CRACKED_WALL, - WATER_TEMPLE_TORCH_ROOM, - WATER_TEMPLE_NORTH_LOWER, - WATER_TEMPLE_BOULDERS_LOWER, - WATER_TEMPLE_BLOCK_ROOM, - WATER_TEMPLE_JETS_ROOM, - WATER_TEMPLE_BOULDERS_UPPER, - WATER_TEMPLE_BOSS_KEY_ROOM, - WATER_TEMPLE_SOUTH_LOWER, - WATER_TEMPLE_WEST_LOWER, - WATER_TEMPLE_DRAGON_ROOM, - WATER_TEMPLE_CENTRAL_PILLAR_LOWER, - WATER_TEMPLE_CENTRAL_PILLAR_UPPER, - WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT, - WATER_TEMPLE_EAST_MIDDLE, - WATER_TEMPLE_WEST_MIDDLE, - WATER_TEMPLE_HIGH_WATER, - WATER_TEMPLE_BLOCK_CORRIDOR, - WATER_TEMPLE_FALLING_PLATFORM_ROOM, - WATER_TEMPLE_DRAGON_PILLARS_ROOM, - WATER_TEMPLE_DARK_LINK_ROOM, - WATER_TEMPLE_LONGSHOT_ROOM, - WATER_TEMPLE_RIVER, - WATER_TEMPLE_PRE_BOSS_ROOM, - WATER_TEMPLE_BOSS_ROOM, - - SPIRIT_TEMPLE_LOBBY, - SPIRIT_TEMPLE_CHILD, - SPIRIT_TEMPLE_CHILD_CLIMB, - SPIRIT_TEMPLE_EARLY_ADULT, - SPIRIT_TEMPLE_CENTRAL_CHAMBER, - SPIRIT_TEMPLE_OUTDOOR_HANDS, - SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, - SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, - SHADOW_TEMPLE_BEGINNING, - SHADOW_TEMPLE_FIRST_BEAMOS, - SHADOW_TEMPLE_HUGE_PIT, - SHADOW_TEMPLE_WIND_TUNNEL, - SHADOW_TEMPLE_BEYOND_BOAT, - BOTTOM_OF_THE_WELL, - BOTTOM_OF_THE_WELL_MAIN_AREA, - ICE_CAVERN_BEGINNING, - ICE_CAVERN_MAIN, - GERUDO_TRAINING_GROUNDS_LOBBY, - GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, - GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, - GERUDO_TRAINING_GROUNDS_LAVA_ROOM, - GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, - GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, - GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, - GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, - GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, - GANONS_CASTLE_LOBBY, - GANONS_CASTLE_DEKU_SCRUBS, - GANONS_CASTLE_FOREST_TRIAL, - GANONS_CASTLE_FIRE_TRIAL, - GANONS_CASTLE_WATER_TRIAL, - GANONS_CASTLE_SHADOW_TRIAL, - GANONS_CASTLE_SPIRIT_TRIAL, - GANONS_CASTLE_LIGHT_TRIAL, - GANONS_CASTLE_TOWER, - DEKU_TREE_MQ_LOBBY, - DEKU_TREE_MQ_COMPASS_ROOM, - DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, - DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, - DEKU_TREE_MQ_BASEMENT_BACK_ROOM, - DEKU_TREE_MQ_BASEMENT_LEDGE, - DODONGOS_CAVERN_MQ_BEGINNING, - DODONGOS_CAVERN_MQ_LOBBY, - DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, - DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, - DODONGOS_CAVERN_MQ_BOSS_AREA, - JABU_JABUS_BELLY_MQ_BEGINNING, - JABU_JABUS_BELLY_MQ_MAIN, - JABU_JABUS_BELLY_MQ_DEPTHS, - JABU_JABUS_BELLY_MQ_BOSS_AREA, - FOREST_TEMPLE_MQ_LOBBY, - FOREST_TEMPLE_MQ_CENTRAL_AREA, - FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, - FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, - FOREST_TEMPLE_MQ_NW_OUTDOORS, - FOREST_TEMPLE_MQ_NE_OUTDOORS, - FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, - FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, - FOREST_TEMPLE_MQ_BOW_REGION, - FOREST_TEMPLE_MQ_FALLING_ROOM, - FOREST_TEMPLE_MQ_BOSS_REGION, - FIRE_TEMPLE_MQ_LOWER, - FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, - FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, - FIRE_TEMPLE_MQ_LOWER_MAZE, - FIRE_TEMPLE_MQ_UPPER_MAZE, - FIRE_TEMPLE_MQ_UPPER, - FIRE_TEMPLE_MQ_BOSS_ROOM, - WATER_TEMPLE_MQ_LOBBY, - WATER_TEMPLE_MQ_DIVE, - WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS, - WATER_TEMPLE_MQ_DARK_LINK_REGION, - WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS, - SPIRIT_TEMPLE_MQ_LOBBY, - SPIRIT_TEMPLE_MQ_CHILD, - SPIRIT_TEMPLE_MQ_ADULT, - SPIRIT_TEMPLE_MQ_SHARED, - SPIRIT_TEMPLE_MQ_LOWER_ADULT, - SPIRIT_TEMPLE_MQ_BOSS_AREA, - SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, - SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, - SHADOW_TEMPLE_MQ_ENTRYWAY, - SHADOW_TEMPLE_MQ_BEGINNING, - SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, - SHADOW_TEMPLE_MQ_FIRST_BEAMOS, - SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, - SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, - SHADOW_TEMPLE_MQ_WIND_TUNNEL, - SHADOW_TEMPLE_MQ_BEYOND_BOAT, - SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, - BOTTOM_OF_THE_WELL_MQ, - BOTTOM_OF_THE_WELL_MQ_PERIMETER, - BOTTOM_OF_THE_WELL_MQ_MIDDLE, - ICE_CAVERN_MQ_BEGINNING, - ICE_CAVERN_MQ_MAP_ROOM, - ICE_CAVERN_MQ_IRON_BOOTS_REGION, - ICE_CAVERN_MQ_COMPASS_ROOM, - GERUDO_TRAINING_GROUNDS_MQ_LOBBY, - GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, - GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, - GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, - GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, - GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, - GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, - GANONS_CASTLE_MQ_LOBBY, - GANONS_CASTLE_MQ_DEKU_SCRUBS, - GANONS_CASTLE_MQ_FOREST_TRIAL, - GANONS_CASTLE_MQ_FIRE_TRIAL, - GANONS_CASTLE_MQ_WATER_TRIAL, - GANONS_CASTLE_MQ_SHADOW_TRIAL, - GANONS_CASTLE_MQ_SPIRIT_TRIAL, - GANONS_CASTLE_MQ_LIGHT_TRIAL, - }; + return allAreas; + } void AccessReset() { - for (const uint32_t area : allAreas) { + for (const uint32_t area : GetAllAreas()) { AreaTable(area)->ResetVariables(); } @@ -843,7 +409,7 @@ namespace Areas { //Reset exits and clear items from locations void ResetAllLocations() { - for (const uint32_t area : allAreas) { + for (const uint32_t area : GetAllAreas()) { AreaTable(area)->ResetVariables(); //Erase item from every location in this exit for (LocationAccess& locPair : AreaTable(area)->locations) { @@ -868,7 +434,7 @@ namespace Areas { } bool HasTimePassAccess(uint8_t age) { - for (const uint32_t areaKey : allAreas) { + for (const uint32_t areaKey : GetAllAreas()) { auto area = AreaTable(areaKey); if (area->timePass && ((age == AGE_CHILD && area->Child()) || (age == AGE_ADULT && area->Adult()))) { return true; @@ -886,7 +452,7 @@ namespace Areas { worldGraph.open (str + ".dot"); worldGraph << "digraph {\n\tcenter=true;\n"; - for (const uint32_t areaKey : allAreas) { + for (const uint32_t areaKey : GetAllAreas()) { auto area = AreaTable(areaKey); for (auto exit : area->exits) { if (exit.GetConnectedRegion()->regionName != "Invalid Area") { @@ -939,7 +505,7 @@ Area* AreaTable(const uint32_t areaKey) { //Retrieve all the shuffable entrances of a specific type std::vector GetShuffleableEntrances(EntranceType type, bool onlyPrimary /*= true*/) { std::vector entrancesToShuffle = {}; - for (uint32_t area : Areas::allAreas) { + for (uint32_t area : Areas::GetAllAreas()) { for (auto& exit: AreaTable(area)->exits) { if ((exit.GetType() == type || type == EntranceType::All) && (exit.IsPrimary() || !onlyPrimary) && exit.GetType() != EntranceType::None) { entrancesToShuffle.push_back(&exit); diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp index c67e5d3bd..9f22eea63 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp @@ -38,7 +38,7 @@ void AreaTable_Init_DekuTree() { /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return false;}, /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), - Entrance(DEKU_TREE_BOSS_ROOM, {[]{return false;}, + Entrance(DEKU_TREE_BOSS_ENTRYWAY, {[]{return false;}, /*Glitched*/[]{return IsChild && CanUse(KOKIRI_SWORD) && Nuts && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::EXPERT);}}), }); @@ -72,7 +72,7 @@ void AreaTable_Init_DekuTree() { }, { //Exits Entrance(DEKU_TREE_LOBBY, {[]{return HasFireSourceWithTorch || CanUse(BOW);}}), - Entrance(DEKU_TREE_BOSS_ROOM, {[]{return false;}, + Entrance(DEKU_TREE_BOSS_ENTRYWAY, {[]{return false;}, /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED);}}), }); @@ -161,21 +161,7 @@ void AreaTable_Init_DekuTree() { areaTable[DEKU_TREE_OUTSIDE_BOSS_ROOM] = Area("Deku Tree Outside Boss Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits Entrance(DEKU_TREE_BASEMENT_UPPER, {[]{return true;}}), - Entrance(DEKU_TREE_BOSS_ROOM, {[]{return Here(DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return HasShield;});}}), - }); - - areaTable[DEKU_TREE_BOSS_ROOM] = Area("Deku Tree Boss Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&DekuTreeClear, {[]{return DekuTreeClear || ((IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang));}, - /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), - }, { - //Locations - LocationAccess(QUEEN_GOHMA, {[]{return DekuTreeClear;}}), - LocationAccess(DEKU_TREE_QUEEN_GOHMA_HEART, {[]{return DekuTreeClear;}}), - }, { - //Exits - Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return true;}}), - Entrance(DEKU_TREE_ENTRYWAY, {[]{return DekuTreeClear;}}), + Entrance(DEKU_TREE_BOSS_ENTRYWAY, {[]{return Here(DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return HasShield;});}}), }); } @@ -261,6 +247,51 @@ void AreaTable_Init_DekuTree() { //Exits Entrance(DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return IsChild;}}), Entrance(DEKU_TREE_MQ_LOBBY, {[]{return true;}}), + Entrance(DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, + { [] { return Here(DEKU_TREE_MQ_BASEMENT_LEDGE, [] { return HasFireSourceWithTorch; }); } }), }); + + areaTable[DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM] = + Area("Deku Tree MQ Outside Boss Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(DEKU_TREE_MQ_BASEMENT_LEDGE, { [] { return true; } }), + Entrance(DEKU_TREE_BOSS_ENTRYWAY, + { [] { return Here(DEKU_TREE_MQ_BASEMENT_LEDGE, [] { return HasShield; }); } }), + }); } + + /*--------------------------- + | BOSS ROOM | + ---------------------------*/ + areaTable[DEKU_TREE_BOSS_ENTRYWAY] = + Area("Deku Tree Boss Entryway", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, { [] { return Dungeon::DekuTree.IsVanilla(); } }), + Entrance(DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, { [] { return Dungeon::DekuTree.IsMQ(); } }), + Entrance(DEKU_TREE_BOSS_ROOM, { [] { return true; } }), + }); + + areaTable[DEKU_TREE_BOSS_ROOM] = + Area("Deku Tree Boss Room", "Deku Tree", NONE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&DekuTreeClear, { [] { + return DekuTreeClear || + (CanJumpslash && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || + HookshotOrBoomerang)); + }, + /*Glitched*/ + [] { return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE); } }), + }, + { + // Locations + LocationAccess(QUEEN_GOHMA, { [] { return DekuTreeClear; } }), + LocationAccess(DEKU_TREE_QUEEN_GOHMA_HEART, { [] { return DekuTreeClear; } }), + }, + { + // Exits + Entrance(DEKU_TREE_BOSS_ENTRYWAY, { [] { return true; } }), + }); } diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp index 6c57b161b..fa6985077 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp @@ -50,7 +50,7 @@ void AreaTable_Init_DodongosCavern() { Entrance(DODONGOS_CAVERN_FAR_BRIDGE, {[]{return HasAccessTo(DODONGOS_CAVERN_FAR_BRIDGE);}, /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE);}}), Entrance(DODONGOS_CAVERN_BOSS_AREA, {[]{return Here(DODONGOS_CAVERN_FAR_BRIDGE, []{return HasExplosives;});}}), - Entrance(DODONGOS_CAVERN_BOSS_ROOM, {[]{return false;}, + Entrance(DODONGOS_CAVERN_BOSS_ENTRYWAY,{[]{return false;}, /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED);}}), }); @@ -220,7 +220,7 @@ void AreaTable_Init_DodongosCavern() { Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), Entrance(DODONGOS_CAVERN_BACK_ROOM, {[]{return Here(DODONGOS_CAVERN_BOSS_AREA, []{return CanBlastOrSmash;});}, /*Glitched*/[]{return Here(DODONGOS_CAVERN_BOSS_AREA, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), - Entrance(DODONGOS_CAVERN_BOSS_ROOM, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_BOSS_ENTRYWAY, {[]{return true;}}), }); areaTable[DODONGOS_CAVERN_BACK_ROOM] = Area("Dodongos Cavern Back Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { @@ -231,21 +231,6 @@ void AreaTable_Init_DodongosCavern() { //Exits Entrance(DODONGOS_CAVERN_BOSS_AREA, {[]{return true;}}), }); - - areaTable[DODONGOS_CAVERN_BOSS_ROOM] = Area("Dodongos Cavern Boss Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&DodongosCavernClear, {[]{return DodongosCavernClear || (Here(DODONGOS_CAVERN_BOSS_ROOM, []{return HasExplosives || (CanUse(MEGATON_HAMMER) && CanShield);}) && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword));}, - /*Glitched*/[]{return Here(DODONGOS_CAVERN_BOSS_ROOM, []{return HasExplosives || (CanUse(MEGATON_HAMMER) && CanShield) || (GlitchBlueFireWall && HasBottle && BlueFireAccess);}) && (HasExplosives || GoronBracelet) && (IsAdult || Sticks || KokiriSword || CanUse(MEGATON_HAMMER));}}), - }, { - //Locations - LocationAccess(DODONGOS_CAVERN_BOSS_ROOM_CHEST, {[]{return true;}}), - LocationAccess(DODONGOS_CAVERN_KING_DODONGO_HEART, {[]{return DodongosCavernClear;}}), - LocationAccess(KING_DODONGO, {[]{return DodongosCavernClear;}}), - }, { - //Exits - Entrance(DODONGOS_CAVERN_BOSS_AREA, {[]{return true;}}), - Entrance(DODONGOS_CAVERN_ENTRYWAY, {[]{return DodongosCavernClear;}}), - }); } /*--------------------------- @@ -314,6 +299,53 @@ void AreaTable_Init_DodongosCavern() { LocationAccess(DODONGOS_CAVERN_KING_DODONGO_HEART, {[]{return CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword);}}), LocationAccess(KING_DODONGO, {[]{return CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword);}}), LocationAccess(DODONGOS_CAVERN_MQ_GS_BACK_AREA, {[]{return true;}}), - }, {}); + }, { + //Exits + Entrance(DODONGOS_CAVERN_BOSS_ENTRYWAY, {[]{return true;}}), + }); } + + /*--------------------------- + | BOSS ROOM | + ---------------------------*/ + areaTable[DODONGOS_CAVERN_BOSS_ENTRYWAY] = + Area("Dodongos Cavern Boss Entryway", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(DODONGOS_CAVERN_BOSS_AREA, { [] { return Dungeon::DodongosCavern.IsVanilla(); } }), + Entrance(DODONGOS_CAVERN_MQ_BOSS_AREA, { [] { return Dungeon::DodongosCavern.IsMQ(); } }), + Entrance(DODONGOS_CAVERN_BOSS_ROOM, { [] { return true; } }), + }); + + areaTable[DODONGOS_CAVERN_BOSS_ROOM] = + Area("Dodongos Cavern Boss Room", "Dodongos Cavern", NONE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&DodongosCavernClear, + { [] { + return DodongosCavernClear || + (Here(DODONGOS_CAVERN_BOSS_ROOM, + [] { return HasExplosives || (CanUse(MEGATON_HAMMER) && CanShield); }) && + (Bombs || GoronBracelet) && CanJumpslash); + }, + /*Glitched*/ + [] { + return Here(DODONGOS_CAVERN_BOSS_ROOM, + [] { + return HasExplosives || (CanUse(MEGATON_HAMMER) && CanShield) || + (GlitchBlueFireWall && BlueFire); + }) && + (HasExplosives || GoronBracelet) && CanJumpslash; + } }), + }, + { + // Locations + LocationAccess(DODONGOS_CAVERN_BOSS_ROOM_CHEST, { [] { return true; } }), + LocationAccess(DODONGOS_CAVERN_KING_DODONGO_HEART, { [] { return DodongosCavernClear; } }), + LocationAccess(KING_DODONGO, { [] { return DodongosCavernClear; } }), + }, + { + // Exits + Entrance(DODONGOS_CAVERN_BOSS_ENTRYWAY, { [] { return true; } }), + }); } diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp index ae3c08374..3cbd1c6a7 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp @@ -42,25 +42,11 @@ void AreaTable_Init_FireTemple() { }, { //Exits Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}), - Entrance(FIRE_TEMPLE_BOSS_ROOM, {[]{return BossKeyFireTemple && ((IsAdult && LogicFireBossDoorJump) || CanUse(HOVER_BOOTS) || Here(FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return CanUse(MEGATON_HAMMER);}));}, + Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyFireTemple && ((IsAdult && LogicFireBossDoorJump) || CanUse(HOVER_BOOTS) || Here(FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return CanUse(MEGATON_HAMMER);}));}, /*Glitched*/[]{return BossKeyFireTemple && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)));}}), }); - areaTable[FIRE_TEMPLE_BOSS_ROOM] = Area("Fire Temple Boss Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&FireTempleClear, {[]{return FireTempleClear || (FireTimer >= 64 && CanUse(MEGATON_HAMMER));}, - /*Glitched*/[]{return FireTimer >= 48 && ((CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || - CanUse(MEGATON_HAMMER)) && Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), - }, { - //Locations - LocationAccess(FIRE_TEMPLE_VOLVAGIA_HEART, {[]{return FireTempleClear;}}), - LocationAccess(VOLVAGIA, {[]{return FireTempleClear;}}), - }, { - //Exits - Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return FireTempleClear;}}), - }); - areaTable[FIRE_TEMPLE_LOOP_ENEMIES] = Area("Fire Temple Loop Enemies", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 8) || !IsKeysanity;}}), @@ -308,7 +294,7 @@ void AreaTable_Init_FireTemple() { areaTable[FIRE_TEMPLE_WEST_CENTRAL_UPPER] = Area("Fire Temple West Central Upper", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits - Entrance(FIRE_TEMPLE_BOSS_ROOM, {[]{return false;}, + Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return false;}, /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), Entrance(FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return true;}}), Entrance(FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return true;}}), @@ -375,7 +361,7 @@ void AreaTable_Init_FireTemple() { }, { //Exits Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(FIRE_TEMPLE_MQ_BOSS_ROOM, {[]{return IsAdult && CanUse(GORON_TUNIC) && CanUse(MEGATON_HAMMER) && BossKeyFireTemple && ((HasFireSource && (LogicFireBossDoorJump || HoverBoots)) || HasAccessTo(FIRE_TEMPLE_MQ_UPPER));}}), + Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return IsAdult && CanUse(GORON_TUNIC) && CanUse(MEGATON_HAMMER) && BossKeyFireTemple && ((HasFireSource && (LogicFireBossDoorJump || HoverBoots)) || HasAccessTo(FIRE_TEMPLE_MQ_UPPER));}}), Entrance(FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, {[]{return SmallKeys(FIRE_TEMPLE, 5) && (IsAdult || KokiriSword);}}), Entrance(FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, {[]{return IsAdult && FireTimer >= 24 && CanUse(MEGATON_HAMMER);}}), }); @@ -443,14 +429,41 @@ void AreaTable_Init_FireTemple() { LocationAccess(FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, {[]{return IsAdult && CanUse(HOOKSHOT) && SmallKeys(FIRE_TEMPLE, 5);}}), //Trick: (IsAdult && CanUse(HOOKSHOT) && SmallKeys(FIRE_TEMPLE, 5)) || (LogicFireMQAboveMazeGS && IsAdult && CanUse(LONGSHOT)) }, {}); - - areaTable[FIRE_TEMPLE_MQ_BOSS_ROOM] = Area("Fire Temple MQ Boss Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&FireTempleClear, {[]{return true;}}), - }, { - //Locations - LocationAccess(FIRE_TEMPLE_VOLVAGIA_HEART, {[]{return true;}}), - LocationAccess(VOLVAGIA, {[]{return true;}}), - }, {}); } + + /*--------------------------- + | BOSS ROOM | + ---------------------------*/ + areaTable[FIRE_TEMPLE_BOSS_ENTRYWAY] = + Area("Fire Temple Boss Entryway", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(FIRE_TEMPLE_NEAR_BOSS_ROOM, { [] { return Dungeon::FireTemple.IsVanilla() && false; } }), + Entrance(FIRE_TEMPLE_MQ_LOWER, { [] { return Dungeon::FireTemple.IsMQ() && false; } }), + Entrance(FIRE_TEMPLE_BOSS_ROOM, { [] { return true; } }), + }); + + areaTable[FIRE_TEMPLE_BOSS_ROOM] = + Area("Fire Temple Boss Room", "Fire Temple", NONE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&FireTempleClear, + { [] { return FireTempleClear || (FireTimer >= 64 && CanUse(MEGATON_HAMMER)); }, + /*Glitched*/ + [] { + return FireTimer >= 48 && + ((CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || + CanUse(MEGATON_HAMMER)) && + Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE); + } }), + }, + { + // Locations + LocationAccess(FIRE_TEMPLE_VOLVAGIA_HEART, { [] { return FireTempleClear; } }), + LocationAccess(VOLVAGIA, { [] { return FireTempleClear; } }), + }, + { + // Exits + Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), + }); } diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp index 138f6672b..cfed92c33 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp @@ -58,7 +58,7 @@ void AreaTable_Init_ForestTemple() { Entrance(FOREST_TEMPLE_EAST_CORRIDOR, {[]{return false;}, /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), Entrance(FOREST_TEMPLE_BOSS_REGION, {[]{return ForestTempleMeg;}}), - Entrance(FOREST_TEMPLE_BOSS_ROOM, {[]{return false;}, + Entrance(FOREST_TEMPLE_BOSS_ENTRYWAY, {[]{return false;}, /*Glitched*/[]{return IsAdult && (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT)) && GlitchForestBKSkip;}}), }); @@ -97,7 +97,7 @@ void AreaTable_Init_ForestTemple() { /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || (IsAdult && CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::NOVICE)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), Entrance(FOREST_TEMPLE_MAP_ROOM, {[]{return true;}}), Entrance(FOREST_TEMPLE_SEWER, {[]{return GoldScale || CanUse(IRON_BOOTS) || HasAccessTo(FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}), - Entrance(FOREST_TEMPLE_BOSS_ROOM, {[]{return false;}, + Entrance(FOREST_TEMPLE_BOSS_ENTRYWAY, {[]{return false;}, /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE);}}), }); @@ -304,19 +304,7 @@ void AreaTable_Init_ForestTemple() { }, { //Exits Entrance(FOREST_TEMPLE_LOBBY, {[]{return true;}}), - Entrance(FOREST_TEMPLE_BOSS_ROOM, {[]{return BossKeyForestTemple;}}), - }); - - areaTable[FOREST_TEMPLE_BOSS_ROOM] = Area("Forest Temple Boss Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&ForestTempleClear, {[]{return ForestTempleClear || ((IsAdult || KokiriSword) && (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT)));}}), - }, { - //Locations - LocationAccess(FOREST_TEMPLE_PHANTOM_GANON_HEART, {[]{return ForestTempleClear;}}), - LocationAccess(PHANTOM_GANON, {[]{return ForestTempleClear;}}), - }, { - //Exits - Entrance(FOREST_TEMPLE_ENTRYWAY, {[]{return ForestTempleClear;}}), + Entrance(FOREST_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyForestTemple;}}), }); } @@ -439,14 +427,43 @@ void AreaTable_Init_ForestTemple() { Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return true;}}), }); - areaTable[FOREST_TEMPLE_MQ_BOSS_REGION] = Area("Forest Temple MQ Boss Region", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&ForestTempleClear, {[]{return ForestTempleClear || BossKeyForestTemple;}}), - }, { + areaTable[FOREST_TEMPLE_MQ_BOSS_REGION] = Area("Forest Temple MQ Boss Region", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { //Locations LocationAccess(FOREST_TEMPLE_MQ_BASEMENT_CHEST, {[]{return true;}}), - LocationAccess(FOREST_TEMPLE_PHANTOM_GANON_HEART, {[]{return BossKeyForestTemple;}}), - LocationAccess(PHANTOM_GANON, {[]{return BossKeyForestTemple;}}), - }, {}); + }, { + //Exits + Entrance(FOREST_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyForestTemple;}}), + }); } + + /*--------------------------- + | BOSS ROOM | + ---------------------------*/ + areaTable[FOREST_TEMPLE_BOSS_ENTRYWAY] = + Area("Forest Temple Boss Entryway", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(FOREST_TEMPLE_BOSS_REGION, { [] { return Dungeon::ForestTemple.IsVanilla() && false; } }), + Entrance(FOREST_TEMPLE_MQ_BOSS_REGION, { [] { return Dungeon::ForestTemple.IsMQ() && false; } }), + Entrance(FOREST_TEMPLE_BOSS_ROOM, { [] { return true; } }), + }); + + areaTable[FOREST_TEMPLE_BOSS_ROOM] = Area( + "Forest Temple Boss Room", "Forest Temple", NONE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&ForestTempleClear, { [] { + return ForestTempleClear || ((CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && + (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT))); + } }), + }, + { + // Locations + LocationAccess(FOREST_TEMPLE_PHANTOM_GANON_HEART, { [] { return ForestTempleClear; } }), + LocationAccess(PHANTOM_GANON, { [] { return ForestTempleClear; } }), + }, + { + // Exits + Entrance(FOREST_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), + }); } diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp index 9d24ab031..5cb561c7e 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp @@ -162,23 +162,10 @@ void AreaTable_Init_JabuJabusBelly() { }, { //Exits Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), - Entrance(JABU_JABUS_BELLY_BOSS_ROOM, {[]{return CanUse(BOOMERANG);}, + Entrance(JABU_JABUS_BELLY_BOSS_ENTRYWAY, {[]{return CanUse(BOOMERANG);}, /*Glitched*/[]{return (CanUse(HOVER_BOOTS) && (CanUse(BOW) || CanUse(SLINGSHOT))) || CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || (Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE);}}), }); - - areaTable[JABU_JABUS_BELLY_BOSS_ROOM] = Area("Jabu Jabus Belly Boss Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&JabuJabusBellyClear, {[]{return JabuJabusBellyClear || CanUse(BOOMERANG);}}), - }, { - //Locations - LocationAccess(JABU_JABUS_BELLY_BARINADE_HEART, {[]{return JabuJabusBellyClear;}}), - LocationAccess(BARINADE, {[]{return JabuJabusBellyClear;}}), - }, { - //Exits - Entrance(JABU_JABUS_BELLY_NEAR_BOSS_ROOM, {[]{return JabuJabusBellyClear;}}), - Entrance(JABU_JABUS_BELLY_ENTRYWAY, {[]{return JabuJabusBellyClear;}}), - }); } /*--------------------------- @@ -234,12 +221,39 @@ void AreaTable_Init_JabuJabusBelly() { //Locations LocationAccess(JABU_JABUS_BELLY_MQ_COW, {[]{return CanPlay(EponasSong);}}), LocationAccess(JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, {[]{return true;}}), - LocationAccess(JABU_JABUS_BELLY_BARINADE_HEART, {[]{return true;}}), - LocationAccess(BARINADE, {[]{return true;}}), LocationAccess(JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, {[]{return true;}}), }, { //Exits Entrance(JABU_JABUS_BELLY_MQ_MAIN, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_BOSS_ENTRYWAY, {[]{return CanUse(SLINGSHOT);}}), }); } + + /*--------------------------- + | BOSS ROOM | + ---------------------------*/ + areaTable[JABU_JABUS_BELLY_BOSS_ENTRYWAY] = + Area("Jabu Jabus Belly Boss Entryway", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(JABU_JABUS_BELLY_NEAR_BOSS_ROOM, { [] { return Dungeon::JabuJabusBelly.IsVanilla(); } }), + Entrance(JABU_JABUS_BELLY_MQ_BOSS_AREA, { [] { return Dungeon::JabuJabusBelly.IsMQ(); } }), + Entrance(JABU_JABUS_BELLY_BOSS_ROOM, { [] { return true; } }), + }); + + areaTable[JABU_JABUS_BELLY_BOSS_ROOM] = + Area("Jabu Jabus Belly Boss Room", "Jabu Jabus Belly", NONE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&JabuJabusBellyClear, { [] { return JabuJabusBellyClear || CanUse(BOOMERANG); } }), + }, + { + // Locations + LocationAccess(JABU_JABUS_BELLY_BARINADE_HEART, { [] { return JabuJabusBellyClear; } }), + LocationAccess(BARINADE, { [] { return JabuJabusBellyClear; } }), + }, + { + // Exits + Entrance(JABU_JABUS_BELLY_BOSS_ENTRYWAY, { [] { return false; } }), + }); } diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp index e9216f743..5d0a4e085 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp @@ -81,18 +81,16 @@ void AreaTable_Init_ShadowTemple() { Entrance(SHADOW_TEMPLE_BEYOND_BOAT, {[]{return CanPlay(ZeldasLullaby) && SmallKeys(SHADOW_TEMPLE, 4, 5);}}), }); - areaTable[SHADOW_TEMPLE_BEYOND_BOAT] = Area("Shadow Temple Beyond Boat", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&ShadowTempleClear, {[]{return ShadowTempleClear || (SmallKeys(SHADOW_TEMPLE, 5) && BossKeyShadowTemple && (Bow || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus)));}}), - }, { + areaTable[SHADOW_TEMPLE_BEYOND_BOAT] = Area("Shadow Temple Beyond Boat", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { //Locations LocationAccess(SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, {[]{return CanUse(DINS_FIRE);}}), LocationAccess(SHADOW_TEMPLE_BOSS_KEY_CHEST, {[]{return CanUse(DINS_FIRE);}}), LocationAccess(SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, {[]{return true;}}), - LocationAccess(SHADOW_TEMPLE_BONGO_BONGO_HEART, {[]{return SmallKeys(SHADOW_TEMPLE, 5) && BossKeyShadowTemple && (Bow || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus));}}), - LocationAccess(BONGO_BONGO, {[]{return SmallKeys(SHADOW_TEMPLE, 5) && BossKeyShadowTemple && (Bow || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus));}}), LocationAccess(SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, {[]{return true;}}), - }, {}); + }, { + //Exits + Entrance(SHADOW_TEMPLE_BOSS_ENTRYWAY, {[]{return (CanUse(BOW) || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus)) && SmallKeys(SHADOW_TEMPLE, 5) && CanUse(HOVER_BOOTS) && BossKeyShadowTemple;}}) + }); } /*--------------------------- @@ -164,18 +162,14 @@ void AreaTable_Init_ShadowTemple() { Entrance(SHADOW_TEMPLE_MQ_BEYOND_BOAT, {[]{return CanPlay(ZeldasLullaby) && SmallKeys(SHADOW_TEMPLE, 5);}}), }); - areaTable[SHADOW_TEMPLE_MQ_BEYOND_BOAT] = Area("Shadow Temple MQ Beyond Boat", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&ShadowTempleClear, {[]{return ShadowTempleClear || ((Bow || (LogicShadowStatue && HasBombchus)) && BossKeyShadowTemple);}}), - }, { + areaTable[SHADOW_TEMPLE_MQ_BEYOND_BOAT] = Area("Shadow Temple MQ Beyond Boat", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LocationAccess(SHADOW_TEMPLE_BONGO_BONGO_HEART, {[]{return (Bow || (LogicShadowStatue && HasBombchus)) && BossKeyShadowTemple;}}), - LocationAccess(BONGO_BONGO, {[]{return (Bow || (LogicShadowStatue && HasBombchus)) && BossKeyShadowTemple;}}), LocationAccess(SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, {[]{return true;}}), LocationAccess(SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, {[]{return Bow || (LogicShadowStatue && HasBombchus);}}), }, { //Exits Entrance(SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, {[]{return Bow && CanPlay(SongOfTime) && IsAdult && CanUse(LONGSHOT);}}), + Entrance(SHADOW_TEMPLE_BOSS_ENTRYWAY, {[]{return (CanUse(BOW) || (LogicShadowStatue && HasBombchus)) && CanUse(HOVER_BOOTS) && BossKeyShadowTemple;}}), }); areaTable[SHADOW_TEMPLE_MQ_INVISIBLE_MAZE] = Area("Shadow Temple MQ Invisible Maze", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { @@ -186,4 +180,37 @@ void AreaTable_Init_ShadowTemple() { LocationAccess(SHADOW_TEMPLE_MQ_FREESTANDING_KEY, {[]{return true;}}), }, {}); } + + /*--------------------------- + | BOSS ROOM | + ---------------------------*/ + areaTable[SHADOW_TEMPLE_BOSS_ENTRYWAY] = + Area("Shadow Temple Boss Entryway", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(SHADOW_TEMPLE_BEYOND_BOAT, { [] { return Dungeon::ShadowTemple.IsVanilla() && false; } }), + Entrance(SHADOW_TEMPLE_MQ_BEYOND_BOAT, { [] { return Dungeon::ShadowTemple.IsMQ() && false; } }), + Entrance(SHADOW_TEMPLE_BOSS_ROOM, { [] { return true; } }), + }); + + areaTable[SHADOW_TEMPLE_BOSS_ROOM] = + Area("Shadow Temple Boss Room", "Shadow Temple", NONE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&ShadowTempleClear, { [] { + return ShadowTempleClear || + ((CanUse(LENS_OF_TRUTH) || ((Dungeon::ShadowTemple.IsVanilla() && LogicLensShadowBack) || + (Dungeon::ShadowTemple.IsMQ() && LogicLensShadowMQBack))) && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))); + } }), + }, + { + // Locations + LocationAccess(SHADOW_TEMPLE_BONGO_BONGO_HEART, { [] { return ShadowTempleClear; } }), + LocationAccess(BONGO_BONGO, { [] { return ShadowTempleClear; } }), + }, + { + // Exits + Entrance(SHADOW_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), + }); } diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp index cfe99555b..32e71cb8e 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp @@ -122,16 +122,22 @@ void AreaTable_Init_SpiritTemple() { Entrance(SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, {[]{return SmallKeys(SPIRIT_TEMPLE, 5) && (LogicSpiritWall || CanUse(LONGSHOT) || HasBombchus || ((Bombs || Nuts || CanUse(DINS_FIRE)) && (Bow || CanUse(HOOKSHOT) || Hammer)));}}), }); - areaTable[SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR] = Area("Spirit Temple Beyond Final Locked Door", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&SpiritTempleClear, {[]{return SpiritTempleClear || (MirrorShield && HasExplosives && Hookshot && BossKeySpiritTemple);}}), - }, { + areaTable[SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR] = Area("Spirit Temple Beyond Final Locked Door", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { //Locations LocationAccess(SPIRIT_TEMPLE_BOSS_KEY_CHEST, {[]{return CanPlay(ZeldasLullaby) && ((CanTakeDamage && LogicFlamingChests) || (Bow && Hookshot));}}), LocationAccess(SPIRIT_TEMPLE_TOPMOST_CHEST, {[]{return MirrorShield || (SunlightArrows && CanUse(LIGHT_ARROWS));}}), - LocationAccess(SPIRIT_TEMPLE_TWINROVA_HEART, {[]{return MirrorShield && HasExplosives && Hookshot && BossKeySpiritTemple;}}), - LocationAccess(TWINROVA, {[]{return MirrorShield && HasExplosives && Hookshot && BossKeySpiritTemple;}}), - }, {}); + }, { + //Exits + Entrance(SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, {[]{return MirrorShield && HasExplosives && Hookshot;}}), + }); + + areaTable[SPIRIT_TEMPLE_INSIDE_STATUE_HEAD] = + Area("Spirit Temple Inside Statue Head", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(SPIRIT_TEMPLE_CENTRAL_CHAMBER, { [] { return true; } }), + Entrance(SPIRIT_TEMPLE_BOSS_ENTRYWAY, { [] { return BossKeySpiritTemple; } }), + }); } /*--------------------------- @@ -209,15 +215,21 @@ void AreaTable_Init_SpiritTemple() { LocationAccess(SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, {[]{return SmallKeys(SPIRIT_TEMPLE, 7) && Hammer && Ocarina && SongOfTime && EponasSong && SunsSong && SongOfStorms && ZeldasLullaby;}}), }, {}); - areaTable[SPIRIT_TEMPLE_MQ_BOSS_AREA] = Area("Spirit Temple MQ Boss Area", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&SpiritTempleClear, {[]{return SpiritTempleClear || (MirrorShield && BossKeySpiritTemple);}}), - }, { + areaTable[SPIRIT_TEMPLE_MQ_BOSS_AREA] = Area("Spirit Temple MQ Boss Area", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { //Locations LocationAccess(SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, {[]{return LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH);}}), - LocationAccess(SPIRIT_TEMPLE_TWINROVA_HEART, {[]{return MirrorShield && BossKeySpiritTemple;}}), - LocationAccess(TWINROVA, {[]{return MirrorShield && BossKeySpiritTemple;}}), - }, {}); + }, { + //Exits + Entrance(SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD, {[]{return MirrorShield && Hookshot;}}), + }); + + areaTable[SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD] = + Area("Spirit Temple MQ Inside Statue Head", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(SPIRIT_TEMPLE_MQ_SHARED, { [] { return true; } }), + Entrance(SPIRIT_TEMPLE_BOSS_ENTRYWAY, { [] { return BossKeySpiritTemple; } }), + }); areaTable[SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND] = Area("Spirit Temple MQ Mirror Shield Hand", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { //Locations @@ -229,4 +241,35 @@ void AreaTable_Init_SpiritTemple() { LocationAccess(SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, {[]{return true;}}), }, {}); } + + /*--------------------------- + | BOSS ROOM | + ---------------------------*/ + areaTable[SPIRIT_TEMPLE_BOSS_ENTRYWAY] = Area( + "Spirit Temple Boss Entryway", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, { [] { return Dungeon::SpiritTemple.IsVanilla() && false; } }), + Entrance(SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD, { [] { return Dungeon::SpiritTemple.IsMQ() && false; } }), + Entrance(SPIRIT_TEMPLE_BOSS_ROOM, { [] { return true; } }), + }); + + areaTable[SPIRIT_TEMPLE_BOSS_ROOM] = Area( + "Spirit Temple Boss Room", "Spirit Temple", NONE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&SpiritTempleClear, { [] { + return SpiritTempleClear || (CanUse(MIRROR_SHIELD) && + (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))); + } }), + }, + { + // Locations + LocationAccess(SPIRIT_TEMPLE_TWINROVA_HEART, { [] { return SpiritTempleClear; } }), + LocationAccess(TWINROVA, { [] { return SpiritTempleClear; } }), + }, + { + // Exits + Entrance(SPIRIT_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), + }); } diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp index d2f566b2c..212f4bf1a 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp @@ -275,19 +275,7 @@ void AreaTable_Init_WaterTemple() { }, {}, { //Exits Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), - Entrance(WATER_TEMPLE_BOSS_ROOM, {[]{return BossKeyWaterTemple;}}), - }); - - areaTable[WATER_TEMPLE_BOSS_ROOM] = Area("Water Temple Boss Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&WaterTempleClear, {[]{return WaterTempleClear || (CanUse(HOOKSHOT) && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)));}}), - }, { - //Locations - LocationAccess(WATER_TEMPLE_MORPHA_HEART, {[]{return WaterTempleClear;}}), - LocationAccess(MORPHA, {[]{return WaterTempleClear;}}), - }, { - //Exits - Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return WaterTempleClear;}}), + Entrance(WATER_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyWaterTemple;}}), }); } @@ -295,18 +283,12 @@ void AreaTable_Init_WaterTemple() { | MASTER QUEST DUNGEON | ---------------------------*/ if (Dungeon::WaterTemple.IsMQ()) { - areaTable[WATER_TEMPLE_MQ_LOBBY] = Area("Water Temple MQ Lobby", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&WaterTempleClear, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}), - }, { - //Locations - LocationAccess(WATER_TEMPLE_MORPHA_HEART, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}), - LocationAccess(MORPHA, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}), - }, { + areaTable[WATER_TEMPLE_MQ_LOBBY] = Area("Water Temple MQ Lobby", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return true;}}), Entrance(WATER_TEMPLE_MQ_DIVE, {[]{return IsAdult && WaterTimer >= 24 && CanUse(IRON_BOOTS);}}), Entrance(WATER_TEMPLE_MQ_DARK_LINK_REGION, {[]{return SmallKeys(WATER_TEMPLE, 1) && IsAdult && CanUse(LONGSHOT);}}), + Entrance(WATER_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}), }); areaTable[WATER_TEMPLE_MQ_DIVE] = Area("Water Temple MQ Dive", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { @@ -348,4 +330,35 @@ void AreaTable_Init_WaterTemple() { //Trick: LogicWaterMQLockedGS || (SmallKeys(WATER_TEMPLE, 2) && (HoverBoots || CanUse(SCARECROW) || LogicWaterNorthBasementLedgeJump)) }, {}); } + + /*--------------------------- + | BOSS ROOM | + ---------------------------*/ + areaTable[WATER_TEMPLE_BOSS_ENTRYWAY] = + Area("Water Temple Boss Entryway", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, + { + // Exits + Entrance(WATER_TEMPLE_PRE_BOSS_ROOM, { [] { return Dungeon::WaterTemple.IsVanilla() && false; } }), + Entrance(WATER_TEMPLE_MQ_LOBBY, { [] { return Dungeon::WaterTemple.IsMQ() && false; } }), + Entrance(WATER_TEMPLE_BOSS_ROOM, { [] { return true; } }), + }); + + areaTable[WATER_TEMPLE_BOSS_ROOM] = Area( + "Water Temple Boss Room", "Water Temple", NONE, NO_DAY_NIGHT_CYCLE, + { + // Events + EventAccess(&WaterTempleClear, { [] { + return WaterTempleClear || + (CanUse(HOOKSHOT) && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))); + } }), + }, + { + // Locations + LocationAccess(WATER_TEMPLE_MORPHA_HEART, { [] { return WaterTempleClear; } }), + LocationAccess(MORPHA, { [] { return WaterTempleClear; } }), + }, + { + // Exits + Entrance(WATER_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), + }); } diff --git a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp index bcadae7ed..8c404f354 100644 --- a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp @@ -164,6 +164,17 @@ string_view dungeonEntrancesDesc = "Shuffle the pool of dungeon entrances, "Temple, Bottom of the Well and Gerudo Training\n" // "Ground are opened for both adult and child."; // /*------------------------------ // +| BOSS ENTRANCES | // +------------------------------*/ // +string_view bossEntrancesDesc = "Shuffle the pool of dungeon boss entrances.\n" // + "This affects the boss rooms of all stone and\n" // + "medallion dungeons.\n" // + "\n" // + "Child and adult boss rooms can be shuffled\n" // + "separately.\n" // + "Child may be expected to defeat Phantom Ganon\n" // + "and/or Bongo Bongo."; // +/*------------------------------ // | OVERWORLD ENTRANCES | // ------------------------------*/ // string_view overworldEntrancesDesc = "Shuffle the pool of Overworld entrances, which\n" // @@ -238,7 +249,9 @@ string_view decoupledEntrancesDesc = "Decouple entrances when shuffling them. "you came from when you go back through an\n" // "entrance. This also adds the one-way entrance from" "Gerudo Valley to Lake Hylia in the pool of\n" // - "overworld entrances when they are shuffled."; // + "overworld entrances when they are shuffled.\n" // + "Boss entrances are currently excluded from this\n"// + "and remain coupled regardless."; // /*------------------------------ // | BOMBCHUS IN LOGIC | // ------------------------------*/ // diff --git a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp index 4594cc3a6..096ebf658 100644 --- a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp @@ -57,6 +57,8 @@ extern string_view shuffleEntrancesDesc; extern string_view dungeonEntrancesDesc; +extern string_view bossEntrancesDesc; + extern string_view overworldEntrancesDesc; extern string_view grottoEntrancesDesc; diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 673f6d97f..1a4e10a65 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -89,6 +89,7 @@ namespace Settings { uint8_t ResolvedStartingAge; Option ShuffleEntrances = Option::Bool("Shuffle Entrances", {"Off", "On"}, {shuffleEntrancesDesc}); Option ShuffleDungeonEntrances = Option::U8 ("Dungeon Entrances", {"Off", "On", "On + Ganon"}, {dungeonEntrancesDesc}); + Option ShuffleBossEntrances = Option::U8 ("Boss Entrances", {"Off", "Age Restricted", "Full"}, {bossEntrancesDesc}); Option ShuffleOverworldEntrances = Option::Bool("Overworld Entrances", {"Off", "On"}, {overworldEntrancesDesc}); Option ShuffleInteriorEntrances = Option::U8 ("Interior Entrances", {"Off", "Simple", "All"}, {interiorEntrancesOff, interiorEntrancesSimple, interiorEntrancesAll}); Option ShuffleGrottoEntrances = Option::Bool("Grottos Entrances", {"Off", "On"}, {grottoEntrancesDesc}); @@ -125,6 +126,7 @@ namespace Settings { &StartingAge, &ShuffleEntrances, &ShuffleDungeonEntrances, + &ShuffleBossEntrances, &ShuffleOverworldEntrances, &ShuffleInteriorEntrances, &ShuffleGrottoEntrances, @@ -1291,6 +1293,7 @@ namespace Settings { ctx.startingAge = StartingAge.Value(); ctx.resolvedStartingAge = ResolvedStartingAge; ctx.shuffleDungeonEntrances = ShuffleDungeonEntrances.Value(); + ctx.shuffleBossEntrances = ShuffleBossEntrances.Value(); ctx.shuffleOverworldEntrances = (ShuffleOverworldEntrances) ? 1 : 0; ctx.shuffleInteriorEntrances = ShuffleInteriorEntrances.Value(); ctx.shuffleGrottoEntrances = (ShuffleGrottoEntrances) ? 1 : 0; @@ -1973,6 +1976,7 @@ namespace Settings { //Show Shuffle options when Shuffle Entrances is On if (ShuffleEntrances) { ShuffleDungeonEntrances.Unhide(); + ShuffleBossEntrances.Unhide(); ShuffleOverworldEntrances.Unhide(); ShuffleInteriorEntrances.Unhide(); ShuffleGrottoEntrances.Unhide(); @@ -1984,6 +1988,8 @@ namespace Settings { } else { ShuffleDungeonEntrances.SetSelectedIndex(SHUFFLEDUNGEONS_OFF); ShuffleDungeonEntrances.Hide(); + ShuffleBossEntrances.SetSelectedIndex(SHUFFLEBOSSES_OFF); + ShuffleBossEntrances.Hide(); ShuffleOverworldEntrances.SetSelectedIndex(OFF); ShuffleOverworldEntrances.Hide(); ShuffleInteriorEntrances.SetSelectedIndex(SHUFFLEINTERIORS_OFF); @@ -2464,6 +2470,7 @@ namespace Settings { // Sanity Check Entrance Shuffling if (!ShuffleEntrances) { ShuffleDungeonEntrances.SetSelectedIndex(OFF); + ShuffleBossEntrances.SetSelectedIndex(OFF); ShuffleOverworldEntrances.SetSelectedIndex(OFF); ShuffleInteriorEntrances.SetSelectedIndex(OFF); ShuffleGrottoEntrances.SetSelectedIndex(OFF); @@ -2681,6 +2688,7 @@ namespace Settings { // Shuffle Entrances ShuffleEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_ENTRANCES]); ShuffleDungeonEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_ENTRANCES]); + ShuffleBossEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_BOSS_ENTRANCES]); ShuffleOverworldEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_OVERWORLD_ENTRANCES]); ShuffleInteriorEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_INTERIOR_ENTRANCES]); ShuffleGrottoEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_GROTTO_ENTRANCES]); diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.hpp b/soh/soh/Enhancements/randomizer/3drando/settings.hpp index 4f3287fa5..9a51032cf 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.hpp @@ -92,6 +92,12 @@ typedef enum { SHUFFLEDUNGEONS_GANON, } ShuffleDungeonEntrancesSetting; +typedef enum { + SHUFFLEBOSSES_OFF, + SHUFFLEBOSSES_AGE_RESTRICTED, + SHUFFLEBOSSES_FULL, +} ShuffleBossEntrancesSetting; + typedef enum { SHUFFLEINTERIORS_OFF, SHUFFLEINTERIORS_SIMPLE, @@ -387,6 +393,7 @@ typedef struct { uint8_t startingAge; uint8_t resolvedStartingAge; uint8_t shuffleDungeonEntrances; + uint8_t shuffleBossEntrances; uint8_t shuffleOverworldEntrances; uint8_t shuffleInteriorEntrances; uint8_t shuffleGrottoEntrances; @@ -903,6 +910,7 @@ void UpdateSettings(std::unordered_map cvarSettin extern uint8_t ResolvedStartingAge; extern Option ShuffleEntrances; extern Option ShuffleDungeonEntrances; + extern Option ShuffleBossEntrances; extern Option ShuffleOverworldEntrances; extern Option ShuffleInteriorEntrances; extern Option ShuffleGrottoEntrances; diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index c5a2d4611..0c5a03820 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -306,7 +306,7 @@ static void WriteShuffledEntrance(std::string sphereString, Entrance* entrance) std::string name = entrance->GetName(); std::string text = entrance->GetConnectedRegion()->regionName + " from " + entrance->GetReplacement()->GetParentRegion()->regionName; - if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) { + if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) { destinationIndex = entrance->GetReverse()->GetIndex(); replacementDestinationIndex = entrance->GetReplacement()->GetReverse()->GetIndex(); replacementBlueWarp = entrance->GetReplacement()->GetReverse()->GetBlueWarp(); @@ -323,7 +323,7 @@ static void WriteShuffledEntrance(std::string sphereString, Entrance* entrance) jsonData["entrances"].push_back(entranceJson); // When decoupled entrances is off, handle saving reverse entrances with blue warps - if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) { + if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) { json reverseEntranceJson = json::object({ {"index", replacementDestinationIndex}, {"destination", replacementIndex}, diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 2a4f54ce9..cb14871a8 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -236,6 +236,7 @@ std::unordered_map SpoilerfileSettingNameToEn { "World Settings:Bombchus in Logic", RSK_BOMBCHUS_IN_LOGIC }, { "World Settings:Shuffle Entrances", RSK_SHUFFLE_ENTRANCES }, { "World Settings:Dungeon Entrances", RSK_SHUFFLE_DUNGEON_ENTRANCES }, + { "World Settings:Boss Entrances", RSK_SHUFFLE_BOSS_ENTRANCES }, { "World Settings:Overworld Entrances", RSK_SHUFFLE_OVERWORLD_ENTRANCES }, { "World Settings:Interior Entrances", RSK_SHUFFLE_INTERIOR_ENTRANCES }, { "World Settings:Grottos Entrances", RSK_SHUFFLE_GROTTO_ENTRANCES }, @@ -987,6 +988,15 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { gSaveContext.randoSettings[index].value = RO_DUNGEON_ENTRANCE_SHUFFLE_ON_PLUS_GANON; } break; + case RSK_SHUFFLE_BOSS_ENTRANCES: + if (it.value() == "Off") { + gSaveContext.randoSettings[index].value = RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF; + } else if (it.value() == "Age Restricted") { + gSaveContext.randoSettings[index].value = RO_BOSS_ROOM_ENTRANCE_SHUFFLE_AGE_RESTRICTED; + } else if (it.value() == "Full") { + gSaveContext.randoSettings[index].value = RO_BOSS_ROOM_ENTRANCE_SHUFFLE_FULL; + } + break; case RSK_SHUFFLE_INTERIOR_ENTRANCES: if (it.value() == "Off") { gSaveContext.randoSettings[index].value = RO_INTERIOR_ENTRANCE_SHUFFLE_OFF; @@ -2870,6 +2880,7 @@ void GenerateRandomizerImgui() { // Enable if any of the entrance rando options are enabled. cvarSettings[RSK_SHUFFLE_ENTRANCES] = CVarGetInteger("gRandomizeShuffleDungeonsEntrances", RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) || + CVarGetInteger("gRandomizeShuffleBossEntrances", RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF) || CVarGetInteger("gRandomizeShuffleOverworldEntrances", RO_GENERIC_OFF) || CVarGetInteger("gRandomizeShuffleInteriorsEntrances", RO_INTERIOR_ENTRANCE_SHUFFLE_OFF) || CVarGetInteger("gRandomizeShuffleGrottosEntrances", RO_GENERIC_OFF) || @@ -2878,6 +2889,7 @@ void GenerateRandomizerImgui() { CVarGetInteger("gRandomizeShuffleOverworldSpawns", RO_GENERIC_OFF); cvarSettings[RSK_SHUFFLE_DUNGEON_ENTRANCES] = CVarGetInteger("gRandomizeShuffleDungeonsEntrances", RO_DUNGEON_ENTRANCE_SHUFFLE_OFF); + cvarSettings[RSK_SHUFFLE_BOSS_ENTRANCES] = CVarGetInteger("gRandomizeShuffleBossEntrances", RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF); cvarSettings[RSK_SHUFFLE_OVERWORLD_ENTRANCES] = CVarGetInteger("gRandomizeShuffleOverworldEntrances", RO_GENERIC_OFF); cvarSettings[RSK_SHUFFLE_INTERIOR_ENTRANCES] = CVarGetInteger("gRandomizeShuffleInteriorsEntrances", RO_INTERIOR_ENTRANCE_SHUFFLE_OFF); cvarSettings[RSK_SHUFFLE_GROTTO_ENTRANCES] = CVarGetInteger("gRandomizeShuffleGrottosEntrances", RO_GENERIC_OFF); @@ -2937,6 +2949,7 @@ void DrawRandoEditor(bool& open) { // World Settings static const char* randoStartingAge[3] = { "Child", "Adult", "Random" }; static const char* randoShuffleDungeonsEntrances[3] = { "Off", "On", "On + Ganon" }; + static const char* randoShuffleBossEntrances[3] = { "Off", "Age Restricted", "Full" }; static const char* randoShuffleInteriorsEntrances[3] = { "Off", "Simple", "All" }; static const char* randoBombchusInLogic[2] = { "Off", "On" }; static const char* randoAmmoDrops[3] = { "On + Bombchu", "Off", "On" }; @@ -3273,6 +3286,19 @@ void DrawRandoEditor(bool& open) { UIWidgets::PaddedSeparator(); + // Shuffle Boss Entrances + ImGui::Text("Shuffle Boss Entrances"); + UIWidgets::InsertHelpHoverText( + "Shuffle the pool of dungeon boss entrances. This affects the boss rooms of all stone and medallion dungeons.\n" + "\n" + "Age Restricted - Shuffle the entrances of child and adult boss rooms separately.\n" + "\n" + "Full - Shuffle the entrances of all boss rooms together. Child may be expected to defeat Phantom Ganon and/or Bongo Bongo." + ); + UIWidgets::EnhancementCombobox("gRandomizeShuffleBossEntrances", randoShuffleBossEntrances, RO_BOSS_ROOM_ENTRANCE_SHUFFLE_MAX, RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF); + + UIWidgets::PaddedSeparator(); + // Shuffle Overworld Entrances UIWidgets::EnhancementCheckbox("Shuffle Overworld Entrances", "gRandomizeShuffleOverworldEntrances"); UIWidgets::InsertHelpHoverText( diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 3274a021b..a8f9a9c14 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1090,6 +1090,7 @@ typedef enum { RSK_DECOUPLED_ENTRANCES, RSK_STARTING_SKULLTULA_TOKEN, RSK_ALL_LOCATIONS_REACHABLE, + RSK_SHUFFLE_BOSS_ENTRANCES, RSK_MAX } RandomizerSettingKey; @@ -1267,6 +1268,14 @@ typedef enum { RO_DUNGEON_ENTRANCE_SHUFFLE_MAX, } RandoOptionDungeonEntranceShuffle; +//Shuffle Boss Room Entrance Settings (Off, Age Restricted, Full) +typedef enum { + RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF, + RO_BOSS_ROOM_ENTRANCE_SHUFFLE_AGE_RESTRICTED, + RO_BOSS_ROOM_ENTRANCE_SHUFFLE_FULL, + RO_BOSS_ROOM_ENTRANCE_SHUFFLE_MAX, +} RandoOptionBossRoomEntranceShuffle; + //Shuffle Interior Entrance Settings (Off, simple, all) typedef enum { RO_INTERIOR_ENTRANCE_SHUFFLE_OFF, diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index 14c8e4fb0..03b663b8c 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -25,9 +25,39 @@ s16 dynamicExitList[] = { 0x045B, 0x0482, 0x03E8, 0x044B, 0x02A2, 0x0201, 0x03B8 // Owl Flights : 0x492064 and 0x492080 static s16 entranceOverrideTable[ENTRANCE_TABLE_SIZE] = {0}; +// Boss scenes (normalize boss scene range to 0 on lookup) to the replaced dungeon scene it is connected to +static s16 dungeonBossSceneOverrides[SHUFFLEABLE_BOSS_COUNT] = {0}; +static ActorEntry modifiedLinkActorEntry = {0}; EntranceInfo originalEntranceTable[ENTRANCE_TABLE_SIZE] = {0}; +typedef struct { + s16 blueWarp; + s16 destination; +} BlueWarpReplacement; + +typedef struct { + s16 entryway; + s16 exit; + s16 bossDoor; + s16 bossDoorReverse; + s16 blueWarp; + s16 scene; + s16 bossScene; +} DungeonEntranceInfo; + +static DungeonEntranceInfo dungeons[] = { + //entryway exit, boss, reverse,bluewarp,dungeon scene, boss scene + { DEKU_TREE_ENTRANCE, 0x0209, 0x040F, 0x0252, 0x0457, SCENE_YDAN, SCENE_YDAN_BOSS }, + { DODONGOS_CAVERN_ENTRANCE, 0x0242, 0x040B, 0x00C5, 0x047A, SCENE_DDAN, SCENE_DDAN_BOSS }, + { JABU_JABUS_BELLY_ENTRANCE, 0x0221, 0x0301, 0x0407, 0x010E, SCENE_BDAN, SCENE_BDAN_BOSS }, + { FOREST_TEMPLE_ENTRANCE, 0x0215, 0x000C, 0x024E, 0x0608, SCENE_BMORI1, SCENE_MORIBOSSROOM }, + { FIRE_TEMPLE_ENTRANCE, 0x024A, 0x0305, 0x0175, 0x0564, SCENE_HIDAN, SCENE_FIRE_BS }, + { WATER_TEMPLE_ENTRANCE, 0x021D, 0x0417, 0x0423, 0x060C, SCENE_MIZUSIN, SCENE_MIZUSIN_BS }, + { SPIRIT_TEMPLE_ENTRANCE, 0x01E1, 0x008D, 0x02F5, 0x0610, SCENE_JYASINZOU, SCENE_JYASINBOSS }, + { SHADOW_TEMPLE_ENTRANCE, 0x0205, 0x0413, 0x02B2, 0x0580, SCENE_HAKADAN, SCENE_HAKADAN_BS }, +}; + //These variables store the new entrance indices for dungeons so that //savewarping and game overs respawn players at the proper entrance. //By default, these will be their vanilla values. @@ -86,6 +116,9 @@ void Entrance_ResetEntranceTable(void) { void Entrance_Init(void) { s32 index; + size_t blueWarpRemapIdx = 0; + BlueWarpReplacement bluewarps[SHUFFLEABLE_BOSS_COUNT] = {0}; + Entrance_CopyOriginalEntranceTable(); // Skip Child Stealth if given by settings @@ -109,6 +142,11 @@ void Entrance_Init(void) { entranceOverrideTable[i] = i; } + // Initialize all boss rooms connected to their vanilla dungeon + for (s16 i = 1; i < SHUFFLEABLE_BOSS_COUNT; i++) { + dungeonBossSceneOverrides[i] = i; + } + // Initialize the grotto exit and load lists Grotto_InitExitAndLoadLists(); @@ -138,7 +176,33 @@ void Entrance_Init(void) { entranceOverrideTable[originalIndex] = overrideIndex; if (blueWarpIndex != 0) { - entranceOverrideTable[blueWarpIndex] = overrideIndex; + // When boss shuffle is enabled, we need to know what dungeon the boss room is connected to for + // death/save warping, and for the blue warp + if (Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF) { + s16 bossScene = -1; + s16 replacedDungeonScene = -1; + s16 replacedDungeonExit = -1; + // Search for the boss scene and replaced blue warp exits + for (s16 j = 0; j <= SHUFFLEABLE_BOSS_COUNT; j++) { + if (blueWarpIndex == dungeons[j].blueWarp) { + bossScene = dungeons[j].bossScene; + } + if (overrideIndex == dungeons[j].bossDoorReverse) { + replacedDungeonScene = dungeons[j].scene; + replacedDungeonExit = dungeons[j].exit; + } + } + + // assign the boss scene override + if (bossScene != -1 && replacedDungeonScene != -1 && replacedDungeonExit != -1) { + dungeonBossSceneOverrides[bossScene - SCENE_YDAN_BOSS] = replacedDungeonScene; + bluewarps[blueWarpRemapIdx].blueWarp = blueWarpIndex; + bluewarps[blueWarpRemapIdx].destination = replacedDungeonExit; + blueWarpRemapIdx++; + } + } else { + entranceOverrideTable[blueWarpIndex] = overrideIndex; + } } //Override both land and water entrances for Hyrule Field -> ZR Front and vice versa @@ -149,6 +213,14 @@ void Entrance_Init(void) { } } + // If we have remapped blue warps from boss shuffle, handle setting those and grabbing the override for + // the replaced dungeons exit in the event that dungeon shuffle is also turned on + for (size_t i = 0; i < ARRAY_COUNT(bluewarps); i++) { + if (bluewarps[i].blueWarp != 0 && bluewarps[i].destination != 0) { + entranceOverrideTable[bluewarps[i].blueWarp] = Entrance_GetOverride(bluewarps[i].destination); + } + } + // Stop playing background music during shuffled entrance transitions // so that we don't get duplicated or overlapping music tracks if (Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_ENTRANCES)) { @@ -236,12 +308,20 @@ u32 Entrance_SceneAndSpawnAre(u8 scene, u8 spawn) { return currentEntrance.scene == scene && currentEntrance.spawn == spawn; } -//Properly respawn the player after a game over, accounding for dungeon entrance -//randomizer. It's easier to rewrite this entirely compared to performing an ASM -//dance for just the boss rooms. Entrance Indexes can be found here: -//https://wiki.cloudmodding.com/oot/Entrance_Table_(Data) +// Properly respawn the player after a game over, accounting for dungeon entrance randomizer void Entrance_SetGameOverEntrance(void) { + s16 scene = gPlayState->sceneNum; + + // When in a boss room and boss shuffle is on, get the connected dungeon's original boss room entrance + // then run the normal game over overrides on it + if (Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF && + scene >= SCENE_YDAN_BOSS && scene <= SCENE_HAKADAN_BS) { + // Normalize boss scene range to 0 on lookup + scene = dungeonBossSceneOverrides[scene - SCENE_YDAN_BOSS]; + gSaveContext.entranceIndex = dungeons[scene].bossDoor; + } + //Set the current entrance depending on which entrance the player last came through switch (gSaveContext.entranceIndex) { case 0x040F : //Deku Tree Boss Room @@ -274,14 +354,19 @@ void Entrance_SetGameOverEntrance(void) { } } -//Properly savewarp the player accounting for dungeon entrance randomizer. -//It's easier to rewrite this entirely compared to performing an ASM -//dance for just the boss rooms. -//https://wiki.cloudmodding.com/oot/Entrance_Table_(Data) +// Properly savewarp the player accounting for dungeon entrance randomizer. void Entrance_SetSavewarpEntrance(void) { s16 scene = gSaveContext.savedSceneNum; + // When in a boss room and boss shuffle is on, use the boss scene override to remap to its + // connected dungeon and use that for the final entrance + if (Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF && + scene >= SCENE_YDAN_BOSS && scene <= SCENE_HAKADAN_BS) { + // Normalize boss scene range to 0 on lookup + scene = dungeonBossSceneOverrides[scene - SCENE_YDAN_BOSS]; + } + if (scene == SCENE_YDAN || scene == SCENE_YDAN_BOSS) { gSaveContext.entranceIndex = newDekuTreeEntrance; } else if (scene == SCENE_DDAN || scene == SCENE_DDAN_BOSS) { @@ -586,23 +671,71 @@ void Entrance_OverrideGeurdoGuardCapture(void) { } void Entrance_OverrideSpawnScene(s32 sceneNum, s32 spawn) { + // Copy the actorEntry properties to avoid modifying the original cached pointer + // Then assign a pointer of our modified actoreEntry back + modifiedLinkActorEntry.id = gPlayState->linkActorEntry->id; + modifiedLinkActorEntry.pos = gPlayState->linkActorEntry->pos; + modifiedLinkActorEntry.rot = gPlayState->linkActorEntry->rot; + modifiedLinkActorEntry.params = gPlayState->linkActorEntry->params; + if (Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) == RO_DUNGEON_ENTRANCE_SHUFFLE_ON_PLUS_GANON) { // Move Hyrule's Castle Courtyard exit spawn to be before the crates so players don't skip Talon if (sceneNum == 95 && spawn == 1) { - gPlayState->linkActorEntry->pos.x = 0x033A; - gPlayState->linkActorEntry->pos.y = 0x0623; - gPlayState->linkActorEntry->pos.z = 0xFF22; + modifiedLinkActorEntry.pos.x = 0x033A; + modifiedLinkActorEntry.pos.y = 0x0623; + modifiedLinkActorEntry.pos.z = 0xFF22; + gPlayState->linkActorEntry = &modifiedLinkActorEntry; } // Move Ganon's Castle exit spawn to be on the small ledge near the castle and not over the void + // to prevent Link from falling if the bridge isn't spawned if (sceneNum == 100 && spawn == 1) { - gPlayState->linkActorEntry->pos.x = 0xFEA8; - gPlayState->linkActorEntry->pos.y = 0x065C; - gPlayState->linkActorEntry->pos.z = 0x0290; - gPlayState->linkActorEntry->rot.y = 0x0700; - gPlayState->linkActorEntry->params = 0x0DFF; // stationary spawn + modifiedLinkActorEntry.pos.x = 0xFEA8; + modifiedLinkActorEntry.pos.y = 0x065C; + modifiedLinkActorEntry.pos.z = 0x0290; + modifiedLinkActorEntry.rot.y = 0x0700; + modifiedLinkActorEntry.params = 0x0DFF; // stationary spawn + gPlayState->linkActorEntry = &modifiedLinkActorEntry; } } + + if (Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF) { + // Repair the authentically bugged entrance when leaving Barniades boss room -> JabuJabu's belly + // Link's position needs to be adjusted to prevent him from falling through the floor + if (sceneNum == SCENE_BDAN && spawn == 1) { + modifiedLinkActorEntry.pos.z = 0xF7F4; + gPlayState->linkActorEntry = &modifiedLinkActorEntry; + } + + // Repair the authentically bugged entrance when leaving Morpha's boass room -> Water Temple + // Link's position was at the start of the Water Temple entrance + // This updates it to place him in the hallway outside of Morpha's boss room. + if (sceneNum == SCENE_MIZUSIN && spawn == 1) { + modifiedLinkActorEntry.pos.x = 0xFF4C; + modifiedLinkActorEntry.pos.y = 0x0406; + modifiedLinkActorEntry.pos.z = 0xF828; + modifiedLinkActorEntry.rot.y = 0x0; + gPlayState->linkActorEntry = &modifiedLinkActorEntry; + } + } +} + +s32 Entrance_OverrideSpawnSceneRoom(s32 sceneNum, s32 spawn, s32 roomNum) { + if (Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF) { + // Repair the authentically bugged scene/spawn info for leaving Barinade's boss room -> JabuJabu's belly + // to load the correct room outside Barniade's boss room + if (sceneNum == SCENE_BDAN && spawn == 1) { + return 5; + } + + // Repair the authentically bugged scene/spawn info for leaving Morhpa's boss room -> Water Temple + // to load the correct room for the hallway before Morpha's boss room + if (sceneNum == SCENE_MIZUSIN && spawn == 1) { + return 11; + } + } + + return roomNum; } u8 Entrance_GetIsSceneDiscovered(u8 sceneNum) { diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.h b/soh/soh/Enhancements/randomizer/randomizer_entrance.h index e9c3bfc16..57e58d93b 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.h +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.h @@ -26,7 +26,8 @@ #define ENTRANCE_RANDO_GROTTO_EXIT_START 0x0800 #define MAX_ENTRANCE_RANDO_USED_INDEX 0x0820 -#define ENTRANCE_OVERRIDES_MAX_COUNT 256 +#define ENTRANCE_OVERRIDES_MAX_COUNT 259 // 11 one-way entrances + 124 two-way entrances (x2) +#define SHUFFLEABLE_BOSS_COUNT 8 #define SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT 66 // Max entrance rando index is 0x0820, (2080 / 32 == 65) + 1 #define SAVEFILE_SCENES_DISCOVERED_IDX_COUNT 4 // Max scene ID is 0x6E, (110 / 32 == 3) + 1 @@ -46,6 +47,7 @@ int16_t Entrance_GetOverride(int16_t index); int16_t Entrance_OverrideNextIndex(int16_t nextEntranceIndex); int16_t Entrance_OverrideDynamicExit(int16_t dynamicExitIndex); uint32_t Entrance_SceneAndSpawnAre(uint8_t scene, uint8_t spawn); +void Entrance_SetGameOverEntrance(void); void Entrance_SetSavewarpEntrance(void); void Entrance_SetWarpSongEntrance(void); void Entrance_OverrideBlueWarp(void); @@ -54,6 +56,7 @@ void Entrance_HandleEponaState(void); void Entrance_OverrideWeatherState(void); void Entrance_OverrideGeurdoGuardCapture(void); void Entrance_OverrideSpawnScene(int32_t sceneNum, int32_t spawn); +int32_t Entrance_OverrideSpawnSceneRoom(int32_t sceneNum, int32_t spawn, int32_t room); void Entrance_EnableFW(void); uint8_t Entrance_GetIsEntranceDiscovered(uint16_t entranceIndex); void Entrance_SetEntranceDiscovered(uint16_t entranceIndex); diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp index 53315d636..bddc7a1d0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp @@ -85,24 +85,26 @@ const EntranceData entranceData[] = { { 0x027E, -1, SINGLE_SCENE_INFO(0x57), "LH Owl Flight", "Hyrule Field Owl Drop", ENTRANCE_GROUP_ONE_WAY, ENTRANCE_GROUP_ONE_WAY, ENTRANCE_TYPE_ONE_WAY}, // Kokiri Forest - { 0x05E0, 0x020D, SINGLE_SCENE_INFO(0x55), "KF", "Lost Woods Bridge", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_TYPE_OVERWORLD, "lw"}, - { 0x011E, 0x0286, SINGLE_SCENE_INFO(0x55), "KF", "Lost Woods", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_TYPE_OVERWORLD, "lw"}, - { 0x0272, 0x0211, SINGLE_SCENE_INFO(0x55), "KF", "Link's House", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, - { 0x0433, 0x0443, SINGLE_SCENE_INFO(0x55), "KF", "Mido's House", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, - { 0x0437, 0x0447, SINGLE_SCENE_INFO(0x55), "KF", "Saria's House", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, - { 0x009C, 0x033C, SINGLE_SCENE_INFO(0x55), "KF", "House of Twins", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, - { 0x00C9, 0x026A, SINGLE_SCENE_INFO(0x55), "KF", "Know-It-All House", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, - { 0x00C1, 0x0266, SINGLE_SCENE_INFO(0x55), "KF", "KF Shop", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, - { 0x071B, 0x081B, SINGLE_SCENE_INFO(0x55), "KF", "KF Storms Grotto", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_GROTTO, "chest", 1}, - { 0x0000, 0x0209, SINGLE_SCENE_INFO(0x55), "KF", "Deku Tree", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_DUNGEON, "", 1}, - { 0x0211, 0x0272, SINGLE_SCENE_INFO(0x34), "Link's House", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, - { 0x0443, 0x0433, SINGLE_SCENE_INFO(0x28), "Mido's House", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, - { 0x0447, 0x0437, SINGLE_SCENE_INFO(0x29), "Saria's House", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, - { 0x033C, 0x009C, SINGLE_SCENE_INFO(0x27), "House of Twins", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, - { 0x026A, 0x00C9, SINGLE_SCENE_INFO(0x26), "Know-It-All House", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, - { 0x0266, 0x00C1, SINGLE_SCENE_INFO(0x2D), "KF Shop", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, - { 0x081B, 0x071B, {{ 0x3E, 0x00 }}, "KF Storms Grotto", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_GROTTO, "chest"}, - { 0x0209, 0x0000, SINGLE_SCENE_INFO(0x00), "Deku Tree", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_DUNGEON, ""}, + { 0x05E0, 0x020D, SINGLE_SCENE_INFO(0x55), "KF", "Lost Woods Bridge", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_TYPE_OVERWORLD, "lw"}, + { 0x011E, 0x0286, SINGLE_SCENE_INFO(0x55), "KF", "Lost Woods", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_TYPE_OVERWORLD, "lw"}, + { 0x0272, 0x0211, SINGLE_SCENE_INFO(0x55), "KF", "Link's House", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, + { 0x0433, 0x0443, SINGLE_SCENE_INFO(0x55), "KF", "Mido's House", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, + { 0x0437, 0x0447, SINGLE_SCENE_INFO(0x55), "KF", "Saria's House", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, + { 0x009C, 0x033C, SINGLE_SCENE_INFO(0x55), "KF", "House of Twins", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, + { 0x00C9, 0x026A, SINGLE_SCENE_INFO(0x55), "KF", "Know-It-All House", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, + { 0x00C1, 0x0266, SINGLE_SCENE_INFO(0x55), "KF", "KF Shop", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, "", 1}, + { 0x071B, 0x081B, SINGLE_SCENE_INFO(0x55), "KF", "KF Storms Grotto", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_GROTTO, "chest", 1}, + { 0x0000, 0x0209, SINGLE_SCENE_INFO(0x55), "KF", "Deku Tree", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x0211, 0x0272, SINGLE_SCENE_INFO(0x34), "Link's House", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, + { 0x0443, 0x0433, SINGLE_SCENE_INFO(0x28), "Mido's House", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, + { 0x0447, 0x0437, SINGLE_SCENE_INFO(0x29), "Saria's House", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, + { 0x033C, 0x009C, SINGLE_SCENE_INFO(0x27), "House of Twins", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, + { 0x026A, 0x00C9, SINGLE_SCENE_INFO(0x26), "Know-It-All House", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, + { 0x0266, 0x00C1, SINGLE_SCENE_INFO(0x2D), "KF Shop", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_INTERIOR, ""}, + { 0x081B, 0x071B, {{ 0x3E, 0x00 }}, "KF Storms Grotto", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_GROTTO, "chest"}, + { 0x0209, 0x0000, SINGLE_SCENE_INFO(0x00), "Deku Tree", "KF", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_DUNGEON, ""}, + { 0x040F, 0x0252, SINGLE_SCENE_INFO(0x00), "Deku Tree Boss Door", "Gohma", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x0252, 0x040F, SINGLE_SCENE_INFO(0x11), "Gohma", "Deku Tree Boss Door", ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_DUNGEON, "", 1}, // Lost Woods { 0x020D, 0x05E0, SINGLE_SCENE_INFO(0x5B), "Lost Woods Bridge", "KF", ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_OVERWORLD, "lw"}, @@ -119,15 +121,17 @@ const EntranceData entranceData[] = { { 0x0820, 0x0720, {{ 0x3E, 0x0C }}, "Deku Theater", "Lost Woods", ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_TYPE_GROTTO, "lw,mask,stage"}, // Sacred Forest Meadow - { 0x01A9, 0x00FC, SINGLE_SCENE_INFO(0x56), "SFM", "Lost Woods", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_TYPE_OVERWORLD, "lw"}, - { 0x0716, 0x0816, SINGLE_SCENE_INFO(0x56), "SFM", "SFM Wolfos Grotto", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO, "chest", 1}, - { 0x0718, 0x0818, SINGLE_SCENE_INFO(0x56), "SFM", "SFM Fairy Grotto", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO, "", 1}, - { 0x0717, 0x0817, SINGLE_SCENE_INFO(0x56), "SFM", "SFM Storms Grotto", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO, "scrubs", 1}, - { 0x0169, 0x0215, SINGLE_SCENE_INFO(0x56), "SFM", "Forest Temple", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_DUNGEON, "", 1}, - { 0x0816, 0x0716, {{ 0x3E, 0x08 }}, "SFM Wolfos Grotto", "SFM", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO}, - { 0x0818, 0x0718, {{ 0x3C, 0x00 }}, "SFM Fairy Grotto", "SFM", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO}, - { 0x0817, 0x0717, {{ 0x3E, 0x0A }}, "SFM Storms Grotto", "SFM", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO, "scrubs"}, - { 0x0215, 0x0169, SINGLE_SCENE_INFO(0x03), "Forest Temple", "SFM", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_DUNGEON}, + { 0x01A9, 0x00FC, SINGLE_SCENE_INFO(0x56), "SFM", "Lost Woods", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_TYPE_OVERWORLD, "lw"}, + { 0x0716, 0x0816, SINGLE_SCENE_INFO(0x56), "SFM", "SFM Wolfos Grotto", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO, "chest", 1}, + { 0x0718, 0x0818, SINGLE_SCENE_INFO(0x56), "SFM", "SFM Fairy Grotto", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO, "", 1}, + { 0x0717, 0x0817, SINGLE_SCENE_INFO(0x56), "SFM", "SFM Storms Grotto", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO, "scrubs", 1}, + { 0x0169, 0x0215, SINGLE_SCENE_INFO(0x56), "SFM", "Forest Temple", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x0816, 0x0716, {{ 0x3E, 0x08 }}, "SFM Wolfos Grotto", "SFM", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO}, + { 0x0818, 0x0718, {{ 0x3C, 0x00 }}, "SFM Fairy Grotto", "SFM", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO}, + { 0x0817, 0x0717, {{ 0x3E, 0x0A }}, "SFM Storms Grotto", "SFM", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_GROTTO, "scrubs"}, + { 0x0215, 0x0169, SINGLE_SCENE_INFO(0x03), "Forest Temple", "SFM", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_DUNGEON}, + { 0x000C, 0x024E, SINGLE_SCENE_INFO(0x03), "Forest Temple Boss Door", "Phantom Ganon", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x024E, 0x000C, SINGLE_SCENE_INFO(0x14), "Phantom Ganon", "Forest Temple Boss Door", ENTRANCE_GROUP_SFM, ENTRANCE_GROUP_SFM, ENTRANCE_TYPE_DUNGEON, "", 1}, // Kakariko Village { 0x017D, 0x00DB, SINGLE_SCENE_INFO(0x52), "Kakariko", "Hyrule Field", ENTRANCE_GROUP_KAKARIKO, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "hf"}, @@ -161,32 +165,36 @@ const EntranceData entranceData[] = { { 0x02A6, 0x0098, SINGLE_SCENE_INFO(0x08), "Bottom of the Well", "Kakariko", ENTRANCE_GROUP_KAKARIKO, ENTRANCE_GROUP_KAKARIKO, ENTRANCE_TYPE_DUNGEON, "botw"}, // The Graveyard - { 0x0195, 0x00E4, SINGLE_SCENE_INFO(0x53), "Graveyard", "Kakariko", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_KAKARIKO, ENTRANCE_TYPE_OVERWORLD}, - { 0x030D, 0x0355, SINGLE_SCENE_INFO(0x53), "Graveyard", "Dampe's Shack", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_INTERIOR, "", 1}, - { 0x004B, 0x035D, SINGLE_SCENE_INFO(0x53), "Graveyard", "Shield Grave", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO, "", 1}, - { 0x031C, 0x0361, SINGLE_SCENE_INFO(0x53), "Graveyard", "Heart Piece Grave", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO, "", 1}, - { 0x002D, 0x050B, SINGLE_SCENE_INFO(0x53), "Graveyard", "Composer's Grave", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO, "", 1}, - { 0x044F, 0x0359, SINGLE_SCENE_INFO(0x53), "Graveyard", "Dampe's Grave", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO, "race", 1}, - { 0x0037, 0x0205, SINGLE_SCENE_INFO(0x53), "Graveyard", "Shadow Temple", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_DUNGEON, "", 1}, - { 0x0355, 0x030D, SINGLE_SCENE_INFO(0x3A), "Dampe's Shack", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_INTERIOR}, - { 0x035D, 0x004B, SINGLE_SCENE_INFO(0x40), "Shield Grave", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO}, - { 0x0361, 0x031C, SINGLE_SCENE_INFO(0x3F), "Heart Piece Grave", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO}, - { 0x050B, 0x002D, SINGLE_SCENE_INFO(0x41), "Composer's Grave", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO}, - { 0x0359, 0x044F, SINGLE_SCENE_INFO(0x48), "Dampe's Grave", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO, "race"}, - { 0x0205, 0x0037, SINGLE_SCENE_INFO(0x07), "Shadow Temple", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_DUNGEON}, + { 0x0195, 0x00E4, SINGLE_SCENE_INFO(0x53), "Graveyard", "Kakariko", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_KAKARIKO, ENTRANCE_TYPE_OVERWORLD}, + { 0x030D, 0x0355, SINGLE_SCENE_INFO(0x53), "Graveyard", "Dampe's Shack", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_INTERIOR, "", 1}, + { 0x004B, 0x035D, SINGLE_SCENE_INFO(0x53), "Graveyard", "Shield Grave", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO, "", 1}, + { 0x031C, 0x0361, SINGLE_SCENE_INFO(0x53), "Graveyard", "Heart Piece Grave", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO, "", 1}, + { 0x002D, 0x050B, SINGLE_SCENE_INFO(0x53), "Graveyard", "Composer's Grave", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO, "", 1}, + { 0x044F, 0x0359, SINGLE_SCENE_INFO(0x53), "Graveyard", "Dampe's Grave", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO, "race", 1}, + { 0x0037, 0x0205, SINGLE_SCENE_INFO(0x53), "Graveyard", "Shadow Temple", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x0355, 0x030D, SINGLE_SCENE_INFO(0x3A), "Dampe's Shack", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_INTERIOR}, + { 0x035D, 0x004B, SINGLE_SCENE_INFO(0x40), "Shield Grave", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO}, + { 0x0361, 0x031C, SINGLE_SCENE_INFO(0x3F), "Heart Piece Grave", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO}, + { 0x050B, 0x002D, SINGLE_SCENE_INFO(0x41), "Composer's Grave", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO}, + { 0x0359, 0x044F, SINGLE_SCENE_INFO(0x48), "Dampe's Grave", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_GROTTO, "race"}, + { 0x0205, 0x0037, SINGLE_SCENE_INFO(0x07), "Shadow Temple", "Graveyard", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_DUNGEON}, + { 0x0413, 0x02B2, SINGLE_SCENE_INFO(0x07), "Shadow Temple Boss Door", "Bongo-Bongo", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x02B2, 0x0413, SINGLE_SCENE_INFO(0x18), "Bongo-Bongo", "Shadow Temple Boss Door", ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_GROUP_GRAVEYARD, ENTRANCE_TYPE_DUNGEON, "", 1}, // Death Mountain Trail - { 0x0191, 0x013D, SINGLE_SCENE_INFO(0x60), "DMT", "Kakariko", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_KAKARIKO, ENTRANCE_TYPE_OVERWORLD}, - { 0x014D, 0x01B9, SINGLE_SCENE_INFO(0x60), "DMT", "Goron City", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_GORON_CITY, ENTRANCE_TYPE_OVERWORLD, "gc"}, - { 0x0147, 0x01BD, SINGLE_SCENE_INFO(0x60), "DMT", "DMC", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_OVERWORLD}, - { 0x0315, 0x045B, SINGLE_SCENE_INFO(0x60), "DMT", "DMT Great Fairy Fountain", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_INTERIOR, "", 1}, - { 0x0708, 0x0808, SINGLE_SCENE_INFO(0x60), "DMT", "DMT Storms Grotto", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_GROTTO, "chest", 1}, - { 0x0709, 0x0809, SINGLE_SCENE_INFO(0x60), "DMT", "DMT Cow Grotto", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_GROTTO, "", 1}, - { 0x0004, 0x0242, SINGLE_SCENE_INFO(0x60), "DMT", "Dodongo's Cavern", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_DUNGEON, "dc", 1}, - { 0x045B, 0x0315, {{ 0x3B, 0x00 }}, "DMT Great Fairy Fountain", "DMT", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_INTERIOR}, - { 0x0808, 0x0708, {{ 0x3E, 0x00 }}, "DMT Storms Grotto", "DMT", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_GROTTO, "chest"}, - { 0x0809, 0x0709, {{ 0x3E, 0x0D }}, "DMT Cow Grotto", "DMT", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_GROTTO}, - { 0x0242, 0x0004, SINGLE_SCENE_INFO(0x01), "Dodongo's Cavern", "DMT", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_DUNGEON, "dc"}, + { 0x0191, 0x013D, SINGLE_SCENE_INFO(0x60), "DMT", "Kakariko", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_KAKARIKO, ENTRANCE_TYPE_OVERWORLD}, + { 0x014D, 0x01B9, SINGLE_SCENE_INFO(0x60), "DMT", "Goron City", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_GORON_CITY, ENTRANCE_TYPE_OVERWORLD, "gc"}, + { 0x0147, 0x01BD, SINGLE_SCENE_INFO(0x60), "DMT", "DMC", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_OVERWORLD}, + { 0x0315, 0x045B, SINGLE_SCENE_INFO(0x60), "DMT", "DMT Great Fairy Fountain", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_INTERIOR, "", 1}, + { 0x0708, 0x0808, SINGLE_SCENE_INFO(0x60), "DMT", "DMT Storms Grotto", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_GROTTO, "chest", 1}, + { 0x0709, 0x0809, SINGLE_SCENE_INFO(0x60), "DMT", "DMT Cow Grotto", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_GROTTO, "", 1}, + { 0x0004, 0x0242, SINGLE_SCENE_INFO(0x60), "DMT", "Dodongo's Cavern", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_DUNGEON, "dc", 1}, + { 0x045B, 0x0315, {{ 0x3B, 0x00 }}, "DMT Great Fairy Fountain", "DMT", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_INTERIOR}, + { 0x0808, 0x0708, {{ 0x3E, 0x00 }}, "DMT Storms Grotto", "DMT", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_GROTTO, "chest"}, + { 0x0809, 0x0709, {{ 0x3E, 0x0D }}, "DMT Cow Grotto", "DMT", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_GROTTO}, + { 0x0242, 0x0004, SINGLE_SCENE_INFO(0x01), "Dodongo's Cavern", "DMT", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_DUNGEON, "dc"}, + { 0x040B, 0x00C5, SINGLE_SCENE_INFO(0x01), "Dodongo's Cavern Boss Door", "King Dodongo", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_DUNGEON, "dc", 1}, + { 0x00C5, 0x040B, SINGLE_SCENE_INFO(0x12), "King Dodongo", "Dodongo's Cavern Boss Door", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_DUNGEON, "dc", 1}, // Death Mountain Crater { 0x01C1, 0x0246, SINGLE_SCENE_INFO(0x61), "DMC", "Goron City", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_GORON_CITY, ENTRANCE_TYPE_OVERWORLD, "gc"}, @@ -199,6 +207,8 @@ const EntranceData entranceData[] = { { 0x0806, 0x0706, {{ 0x3E, 0x00 }}, "DMC Upper Grotto", "DMC", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_GROTTO, "chest"}, { 0x0805, 0x0705, {{ 0x3E, 0x04 }}, "DMC Hammer Grotto", "DMC", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_GROTTO, "scrubs"}, { 0x024A, 0x0165, SINGLE_SCENE_INFO(0x04), "Fire Temple", "DMC", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_DUNGEON}, + { 0x0305, 0x0175, SINGLE_SCENE_INFO(0x04), "Fire Temple Boss Door", "Volvagia", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x0175, 0x0305, SINGLE_SCENE_INFO(0x15), "Volvagia", "Fire Temple Boss Door", ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, ENTRANCE_TYPE_DUNGEON, "", 1}, // Goron City { 0x01B9, 0x014D, SINGLE_SCENE_INFO(0x62), "Goron City", "DMT", ENTRANCE_GROUP_GORON_CITY, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_OVERWORLD, "gc"}, @@ -230,13 +240,15 @@ const EntranceData entranceData[] = { { 0x081C, 0x071C, {{ 0x3C, 0x00 }}, "ZD Storms Grotto", "Zora's Domain", ENTRANCE_GROUP_ZORAS_DOMAIN, ENTRANCE_GROUP_ZORAS_DOMAIN, ENTRANCE_TYPE_GROTTO, "fairy"}, // Zora's Fountain - { 0x01A1, 0x0225, SINGLE_SCENE_INFO(0x59), "ZF", "Zora's Domain", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_DOMAIN, ENTRANCE_TYPE_OVERWORLD}, - { 0x0371, 0x0394, SINGLE_SCENE_INFO(0x59), "ZF", "ZF Great Fairy Fountain", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_INTERIOR, "", 1}, - { 0x0028, 0x0221, SINGLE_SCENE_INFO(0x59), "ZF", "Jabu Jabu's Belly", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON, "", 1}, - { 0x0088, 0x03D4, SINGLE_SCENE_INFO(0x59), "ZF", "Ice Cavern", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON, "", 1}, - { 0x0394, 0x0371, {{ 0x3D, 0x00 }}, "ZF Great Fairy Fountain", "ZF", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_INTERIOR}, - { 0x0221, 0x0028, SINGLE_SCENE_INFO(0x02), "Jabu Jabu's Belly", "ZF", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON}, - { 0x03D4, 0x0088, SINGLE_SCENE_INFO(0x09), "Ice Cavern", "ZF", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON}, + { 0x01A1, 0x0225, SINGLE_SCENE_INFO(0x59), "ZF", "Zora's Domain", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_DOMAIN, ENTRANCE_TYPE_OVERWORLD}, + { 0x0371, 0x0394, SINGLE_SCENE_INFO(0x59), "ZF", "ZF Great Fairy Fountain", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_INTERIOR, "", 1}, + { 0x0028, 0x0221, SINGLE_SCENE_INFO(0x59), "ZF", "Jabu Jabu's Belly", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x0088, 0x03D4, SINGLE_SCENE_INFO(0x59), "ZF", "Ice Cavern", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x0394, 0x0371, {{ 0x3D, 0x00 }}, "ZF Great Fairy Fountain", "ZF", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_INTERIOR}, + { 0x0221, 0x0028, SINGLE_SCENE_INFO(0x02), "Jabu Jabu's Belly", "ZF", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON}, + { 0x0301, 0x0407, SINGLE_SCENE_INFO(0x02), "Jabu Jabu's Belly Boss Door", "Barinade", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x0407, 0x0301, SINGLE_SCENE_INFO(0x13), "Barinade", "Jabu Jabu's Belly Boss Door", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x03D4, 0x0088, SINGLE_SCENE_INFO(0x09), "Ice Cavern", "ZF", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON}, // Hyrule Field { 0x04DE, 0x0185, SINGLE_SCENE_INFO(0x51), "Hyrule Field", "Lost Woods Bridge", ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_TYPE_OVERWORLD, "hf,lw"}, @@ -275,16 +287,18 @@ const EntranceData entranceData[] = { { 0x0815, 0x0715, {{ 0x3E, 0x04 }}, "LLR Grotto", "Lon Lon Ranch", ENTRANCE_GROUP_LON_LON_RANCH, ENTRANCE_GROUP_LON_LON_RANCH, ENTRANCE_TYPE_GROTTO, "scrubs"}, // Lake Hylia - { 0x0189, 0x0102, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "Hyrule Field", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "lh"}, - { 0x0328, 0x0560, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "Zora's Domain", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_ZORAS_DOMAIN, ENTRANCE_TYPE_OVERWORLD, "lh"}, - { 0x0043, 0x03CC, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "LH Lab", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_INTERIOR, "lh", 1}, - { 0x045F, 0x0309, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "Fishing Hole", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_INTERIOR, "lh", 1}, - { 0x0701, 0x0801, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "LH Grotto", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_GROTTO, "scrubs", 1}, - { 0x0010, 0x021D, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "Water Temple", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_DUNGEON, "lh", 1}, - { 0x03CC, 0x0043, SINGLE_SCENE_INFO(0x38), "LH Lab", "Lake Hylia", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_INTERIOR, "lh"}, - { 0x0309, 0x045F, SINGLE_SCENE_INFO(0x49), "Fishing Hole", "Lake Hylia", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_INTERIOR, "lh"}, - { 0x0801, 0x0701, {{ 0x3E, 0x04 }}, "LH Grotto", "Lake Hylia", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_GROTTO, "lh,scrubs"}, - { 0x021D, 0x0010, SINGLE_SCENE_INFO(0x05), "Water Temple", "Lake Hylia", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_DUNGEON, "lh"}, + { 0x0189, 0x0102, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "Hyrule Field", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "lh"}, + { 0x0328, 0x0560, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "Zora's Domain", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_ZORAS_DOMAIN, ENTRANCE_TYPE_OVERWORLD, "lh"}, + { 0x0043, 0x03CC, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "LH Lab", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_INTERIOR, "lh", 1}, + { 0x045F, 0x0309, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "Fishing Hole", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_INTERIOR, "lh", 1}, + { 0x0701, 0x0801, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "LH Grotto", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_GROTTO, "scrubs", 1}, + { 0x0010, 0x021D, SINGLE_SCENE_INFO(0x57), "Lake Hylia", "Water Temple", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_DUNGEON, "lh", 1}, + { 0x03CC, 0x0043, SINGLE_SCENE_INFO(0x38), "LH Lab", "Lake Hylia", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_INTERIOR, "lh"}, + { 0x0309, 0x045F, SINGLE_SCENE_INFO(0x49), "Fishing Hole", "Lake Hylia", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_INTERIOR, "lh"}, + { 0x0801, 0x0701, {{ 0x3E, 0x04 }}, "LH Grotto", "Lake Hylia", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_GROTTO, "lh,scrubs"}, + { 0x021D, 0x0010, SINGLE_SCENE_INFO(0x05), "Water Temple", "Lake Hylia", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_DUNGEON, "lh"}, + { 0x0417, 0x0423, SINGLE_SCENE_INFO(0x05), "Water Temple Boss Door", "Morpha", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_DUNGEON, "lh", 1}, + { 0x0423, 0x0417, SINGLE_SCENE_INFO(0x16), "Morpha", "Water Temple Boss Door", ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_GROUP_LAKE_HYLIA, ENTRANCE_TYPE_DUNGEON, "lh", 1}, // Gerudo Area { 0x018D, 0x0117, SINGLE_SCENE_INFO(0x5A), "GV", "Hyrule Field", ENTRANCE_GROUP_GERUDO_VALLEY, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "hf"}, @@ -313,6 +327,8 @@ const EntranceData entranceData[] = { { 0x057C, 0x0588, {{ 0x3D, 0x02 }}, "Colossus Great Fairy Fountain", "Colossus", ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_TYPE_INTERIOR, "dc"}, { 0x0800, 0x0700, {{ 0x3E, 0x0A }}, "Colossus Grotto", "Desert Colossus", ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_TYPE_GROTTO, "dc,scrubs"}, { 0x01E1, 0x0082, SINGLE_SCENE_INFO(0x06), "Spirit Temple", "Desert Colossus", ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_TYPE_DUNGEON, "dc"}, + { 0x008D, 0x02F5, SINGLE_SCENE_INFO(0x06), "Spirit Temple Boss Door", "Twinrova", ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_TYPE_DUNGEON, "", 1}, + { 0x02F5, 0x008D, SINGLE_SCENE_INFO(0x17), "Twinrova", "Spirit Temple Boss Door", ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_GROUP_HAUNTED_WASTELAND, ENTRANCE_TYPE_DUNGEON, "", 1}, // Market { 0x01FD, 0x0276, {SCENE_NO_SPAWN(0x1B), SCENE_NO_SPAWN(0x1C), SCENE_NO_SPAWN(0x1D)}, "Market Entrance", "Hyrule Field", ENTRANCE_GROUP_MARKET, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "hf"}, diff --git a/soh/src/code/z_room.c b/soh/src/code/z_room.c index c135123f8..23fb6a4d7 100644 --- a/soh/src/code/z_room.c +++ b/soh/src/code/z_room.c @@ -1,5 +1,6 @@ #include "global.h" #include "vt.h" +#include "soh/Enhancements/randomizer/randomizer_entrance.h" void func_80095AB4(PlayState* play, Room* room, u32 flags); void func_80095D04(PlayState* play, Room* room, u32 flags); @@ -575,6 +576,12 @@ u32 func_80096FE8(PlayState* play, RoomContext* roomCtx) { s32 func_8009728C(PlayState* play, RoomContext* roomCtx, s32 roomNum) { size_t size; + // In ER, override roomNum to load based on scene and spawn + if (gSaveContext.n64ddFlag && gSaveContext.respawnFlag <= 0 && + Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) { + roomNum = Entrance_OverrideSpawnSceneRoom(play->sceneNum, play->curSpawn, roomNum); + } + return OTRfunc_8009728C(play, roomCtx, roomNum); if (roomCtx->status == 0) { diff --git a/soh/src/overlays/actors/ovl_Bg_Spot01_Idosoko/z_bg_spot01_idosoko.c b/soh/src/overlays/actors/ovl_Bg_Spot01_Idosoko/z_bg_spot01_idosoko.c index 2a752c297..b684a3b85 100644 --- a/soh/src/overlays/actors/ovl_Bg_Spot01_Idosoko/z_bg_spot01_idosoko.c +++ b/soh/src/overlays/actors/ovl_Bg_Spot01_Idosoko/z_bg_spot01_idosoko.c @@ -49,8 +49,9 @@ void BgSpot01Idosoko_Init(Actor* thisx, PlayState* play) { this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, colHeader); // If dungeon entrance randomizer is on, remove the well stone as adult Link when // child Link has drained the water to the well - if (!LINK_IS_ADULT || gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) && - Flags_GetEventChkInf(0x67)) { + if (!LINK_IS_ADULT || (gSaveContext.n64ddFlag && + Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF && + Flags_GetEventChkInf(0x67))) { Actor_Kill(&this->dyna.actor); } else { BgSpot01Idosoko_SetupAction(this, func_808ABF54); diff --git a/soh/src/overlays/actors/ovl_Bg_Spot12_Saku/z_bg_spot12_saku.c b/soh/src/overlays/actors/ovl_Bg_Spot12_Saku/z_bg_spot12_saku.c index 768991f45..790e06dd3 100644 --- a/soh/src/overlays/actors/ovl_Bg_Spot12_Saku/z_bg_spot12_saku.c +++ b/soh/src/overlays/actors/ovl_Bg_Spot12_Saku/z_bg_spot12_saku.c @@ -60,7 +60,7 @@ void BgSpot12Saku_Init(Actor* thisx, PlayState* play) { // If ER is on, force the gate to always use its permanent flag // (which it only uses in Child Gerudo Fortress in the vanilla game) - if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) { + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) { thisx->params = 0x0002; } @@ -132,7 +132,7 @@ void BgSpot12Saku_Update(Actor* thisx, PlayState* play) { BgSpot12Saku* this = (BgSpot12Saku*)thisx; // If ER is on, when the guard opens the GtG gate its permanent flag will be set. - if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) && + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF && Flags_GetSwitch(play, 0x3A)) { Flags_SetSwitch(play, 0x2); } diff --git a/soh/src/overlays/actors/ovl_Bg_Treemouth/z_bg_treemouth.c b/soh/src/overlays/actors/ovl_Bg_Treemouth/z_bg_treemouth.c index 4d2400b62..5f7ed2f54 100644 --- a/soh/src/overlays/actors/ovl_Bg_Treemouth/z_bg_treemouth.c +++ b/soh/src/overlays/actors/ovl_Bg_Treemouth/z_bg_treemouth.c @@ -73,8 +73,10 @@ void BgTreemouth_Init(Actor* thisx, PlayState* play) { if ((gSaveContext.sceneSetupIndex < 4) && !LINK_IS_ADULT) { BgTreemouth_SetupAction(this, func_808BC8B8); - // If dungeon entrance randomizer is on, keep the tree mouth open when link is adult and sword & shield have been shown to mido - } else if ((LINK_IS_ADULT && (!gSaveContext.n64ddFlag || !Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) || + // If dungeon entrance randomizer is on, keep the tree mouth open + // when Link is adult and sword & shield have been shown to mido + } else if ((LINK_IS_ADULT && (!gSaveContext.n64ddFlag || + Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) == RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) || !Flags_GetEventChkInf(0x4)) || (gSaveContext.sceneSetupIndex == 7)) { this->unk_168 = 0.0f; BgTreemouth_SetupAction(this, BgTreemouth_DoNothing); diff --git a/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c b/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c index 599055594..d42458235 100644 --- a/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c +++ b/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c @@ -582,7 +582,8 @@ void DoorWarp1_ChildWarpOut(DoorWarp1* this, PlayState* play) { gSaveContext.nextCutsceneIndex = 0; } - if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) { + if (gSaveContext.n64ddFlag && (Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF || + Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF)) { Entrance_OverrideBlueWarp(); } @@ -688,7 +689,8 @@ void DoorWarp1_RutoWarpOut(DoorWarp1* this, PlayState* play) { gSaveContext.nextCutsceneIndex = 0xFFF0; } - if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) { + if (gSaveContext.n64ddFlag && (Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF || + Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF)) { Entrance_OverrideBlueWarp(); } @@ -903,7 +905,8 @@ void DoorWarp1_AdultWarpOut(DoorWarp1* this, PlayState* play) { } } - if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) { + if (gSaveContext.n64ddFlag && (Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF || + Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF)) { Entrance_OverrideBlueWarp(); } diff --git a/soh/src/overlays/actors/ovl_En_Ishi/z_en_ishi.c b/soh/src/overlays/actors/ovl_En_Ishi/z_en_ishi.c index 1d37cea7e..ca69b2fa4 100644 --- a/soh/src/overlays/actors/ovl_En_Ishi/z_en_ishi.c +++ b/soh/src/overlays/actors/ovl_En_Ishi/z_en_ishi.c @@ -332,7 +332,8 @@ void EnIshi_Init(Actor* thisx, PlayState* play) { } // If dungeon entrance randomizer is on, remove the grey boulders that normally // block child Link from reaching the Fire Temple entrance. - if (type == ROCK_LARGE && gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) && + if (type == ROCK_LARGE && gSaveContext.n64ddFlag && + Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF && play->sceneNum == 0x061) { // Death Mountain Creater Actor_Kill(&this->actor); } diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 916bb192d..f2e87db28 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -4127,6 +4127,11 @@ void KaleidoScope_Update(PlayState* play) gSaveContext.entranceIndex = 0x041B; break; } + + // In ER, handle overriding the game over respawn entrance + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) { + Entrance_SetGameOverEntrance(); + } } else { Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); }