Rando: Boss Entrance Shuffle (#2194)

* sync 3ds upstream logic changes for boss rooms

* add boss shuffle settings and handling to 3ds code

* add boss shuffle handling to game code

* repair authentically bugged entrances for boss shuffle

* add boss entrances to the entrance tracker

* unset hint area for boss rooms to fix altar hint

* update boss reward hints to not mention dungeons

* one more boss heart container hint fix

* reorder entrance rando funcs

* support closed forest with boss shuffle and simple boss room entrance pairs in shuffle table

* fix death warp in boss rooms without saving; fix KD boss room in tracker

* remove boss shuffle check from dungeon open checks and some cleanups

* add boss shuffle to preset clear

* remove dungeon entry exit connection from boss rooms

* another no hint fix for boss shuffle

* undo change for exact location hints

* clarify comments
This commit is contained in:
Adam Bird 2023-01-20 01:00:12 -05:00 committed by GitHub
parent 7964bde063
commit 261db2c3e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 919 additions and 881 deletions

View File

@ -233,6 +233,7 @@ const std::vector<const char*> randomizerCvars = {
"gRandomizeShopsanity", "gRandomizeShopsanity",
"gRandomizeShuffleAdultTrade", "gRandomizeShuffleAdultTrade",
"gRandomizeShuffleBeans", "gRandomizeShuffleBeans",
"gRandomizeShuffleBossEntrances",
"gRandomizeShuffleCows", "gRandomizeShuffleCows",
"gRandomizeShuffleDungeonReward", "gRandomizeShuffleDungeonReward",
"gRandomizeShuffleDungeonsEntrances", "gRandomizeShuffleDungeonsEntrances",

View File

@ -81,12 +81,25 @@ void SetAllEntrancesData(std::vector<EntranceInfoPair>& entranceShuffleTable) {
forwardEntrance->SetBlueWarp(forwardEntry.blueWarp); forwardEntrance->SetBlueWarp(forwardEntry.blueWarp);
forwardEntrance->SetType(forwardEntry.type); forwardEntrance->SetType(forwardEntry.type);
forwardEntrance->SetAsPrimary(); 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) { if (returnEntry.parentRegion != NONE) {
Entrance* returnEntrance = AreaTable(returnEntry.parentRegion)->GetExit(returnEntry.connectedRegion); Entrance* returnEntrance = AreaTable(returnEntry.parentRegion)->GetExit(returnEntry.connectedRegion);
returnEntrance->SetIndex(returnEntry.index); returnEntrance->SetIndex(returnEntry.index);
returnEntrance->SetBlueWarp(returnEntry.blueWarp); returnEntrance->SetBlueWarp(returnEntry.blueWarp);
returnEntrance->SetType(returnEntry.type); returnEntrance->SetType(returnEntry.type);
forwardEntrance->BindTwoWay(returnEntrance); 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<Entrance*> AssumeEntrancePool(std::vector<Entrance*>& entranc
for (Entrance* entrance : entrancePool) { for (Entrance* entrance : entrancePool) {
totalRandomizableEntrances++; totalRandomizableEntrances++;
Entrance* assumedForward = entrance->AssumeReachable(); Entrance* assumedForward = entrance->AssumeReachable();
if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) { if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) {
Entrance* assumedReturn = entrance->GetReverse()->AssumeReachable(); Entrance* assumedReturn = entrance->GetReverse()->AssumeReachable();
if (!(Settings::MixedEntrancePools && (Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances.Is(SHUFFLEINTERIORS_ALL)))) { if (!(Settings::MixedEntrancePools && (Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances.Is(SHUFFLEINTERIORS_ALL)))) {
auto type = entrance->GetType(); auto type = entrance->GetType();
@ -218,7 +231,7 @@ static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) {
SPDLOG_DEBUG(message); SPDLOG_DEBUG(message);
entrance->Connect(targetEntrance->Disconnect()); entrance->Connect(targetEntrance->Disconnect());
entrance->SetReplacement(targetEntrance->GetReplacement()); 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()->Connect(entrance->GetReverse()->GetAssumed()->Disconnect());
targetEntrance->GetReplacement()->GetReverse()->SetReplacement(entrance->GetReverse()); targetEntrance->GetReplacement()->GetReverse()->SetReplacement(entrance->GetReverse());
} }
@ -229,7 +242,7 @@ static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) {
static void RestoreConnections(Entrance* entrance, Entrance* targetEntrance) { static void RestoreConnections(Entrance* entrance, Entrance* targetEntrance) {
targetEntrance->Connect(entrance->Disconnect()); targetEntrance->Connect(entrance->Disconnect());
entrance->SetReplacement(nullptr); entrance->SetReplacement(nullptr);
if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) { if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) {
entrance->GetReverse()->GetAssumed()->Connect(targetEntrance->GetReplacement()->GetReverse()->Disconnect()); entrance->GetReverse()->GetAssumed()->Connect(targetEntrance->GetReplacement()->GetReverse()->Disconnect());
targetEntrance->GetReplacement()->GetReverse()->SetReplacement(nullptr); targetEntrance->GetReplacement()->GetReverse()->SetReplacement(nullptr);
} }
@ -247,7 +260,7 @@ static void DeleteTargetEntrance(Entrance* targetEntrance) {
static void ConfirmReplacement(Entrance* entrance, Entrance* targetEntrance) { static void ConfirmReplacement(Entrance* entrance, Entrance* targetEntrance) {
DeleteTargetEntrance(targetEntrance); DeleteTargetEntrance(targetEntrance);
if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) { if (entrance->GetReverse() != nullptr && !entrance->IsDecoupled()) {
auto replacedReverse = targetEntrance->GetReplacement()->GetReverse(); auto replacedReverse = targetEntrance->GetReplacement()->GetReverse();
DeleteTargetEntrance(replacedReverse->GetReverse()->GetAssumed()); DeleteTargetEntrance(replacedReverse->GetReverse()->GetAssumed());
} }
@ -786,9 +799,9 @@ int ShuffleAllEntrances() {
{EntranceType::SpecialInterior, KAK_POTION_SHOP_BACK, KAK_BACKYARD, 0x04FF}}, {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 // 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 // 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, DESERT_COLOSSUS, COLOSSUS_GROTTO, 0x0700},
{EntranceType::GrottoGrave, COLOSSUS_GROTTO, DESERT_COLOSSUS, 0x0800}}, {EntranceType::GrottoGrave, COLOSSUS_GROTTO, DESERT_COLOSSUS, 0x0800}},
{{EntranceType::GrottoGrave, LAKE_HYLIA, LH_GROTTO, 0x0701}, {{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, 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, 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::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<std::string, PriorityEntrance> priorityEntranceTable = { std::map<std::string, PriorityEntrance> 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 //Shuffle Dungeon Entrances
if (Settings::ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) { if (Settings::ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) {
entrancePools[EntranceType::Dungeon] = GetShuffleableEntrances(EntranceType::Dungeon); entrancePools[EntranceType::Dungeon] = GetShuffleableEntrances(EntranceType::Dungeon);

View File

@ -22,6 +22,9 @@ enum class EntranceType {
Dungeon, Dungeon,
GanonDungeon, GanonDungeon,
DungeonReverse, DungeonReverse,
Boss,
ChildBoss,
AdultBoss,
Interior, Interior,
InteriorReverse, InteriorReverse,
SpecialInterior, SpecialInterior,
@ -180,6 +183,14 @@ public:
return primary; return primary;
} }
bool IsDecoupled() const {
return decoupled;
}
void SetDecoupled() {
decoupled = true;
}
int16_t GetIndex() const { int16_t GetIndex() const {
return index; return index;
} }
@ -269,6 +280,7 @@ private:
bool shuffled = false; bool shuffled = false;
bool primary = false; bool primary = false;
bool addedToPool = false; bool addedToPool = false;
bool decoupled = false;
std::string name = ""; std::string name = "";
}; };

View File

@ -296,7 +296,7 @@ std::vector<uint32_t> GetAccessibleLocations(const std::vector<uint32_t>& allowe
entranceSphere.push_back(&exit); entranceSphere.push_back(&exit);
exit.AddToPool(); exit.AddToPool();
// Don't list a two-way coupled entrance from both directions // 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(); exit.GetReplacement()->GetReverse()->AddToPool();
} }
} }

View File

@ -2519,93 +2519,61 @@ void HintTable_Init() {
| BOSS HINT TEXT | | BOSS HINT TEXT |
---------------------------*/ ---------------------------*/
hintTable[QUEEN_GOHMA] = HintText::Boss( hintTable[QUEEN_GOHMA] = HintText::Boss({
{
// obscure text // obscure text
Text{ "An #ancient tree# rewards", /*french*/ "le #vieil arbre# octroie", Text{"the #Parasitic Armored Arachnid# holds", /*french*/"le #monstre insectoïde géant# possède", /*spanish*/"el #arácnido parasitario acorazado# porta"},
/*spanish*/ "un #ancestral árbol# premia con" }, }, {},
}, //clear text
{}, Text{"#Queen Gohma# holds", /*french*/"la #Reine Gohma# possède", /*spanish*/"la #Reina Goma# porta"});
// clear text
Text{ "the #Deku Tree# rewards", /*french*/ "l'#Arbre Mojo# octroie",
/*spanish*/ "el #Gran Árbol Deku# premia con" });
hintTable[KING_DODONGO] = HintText::Boss( hintTable[KING_DODONGO] = HintText::Boss({
{ //obscure text
// obscure text Text{"the #Infernal Dinosaur# holds", /*french*/"le #dinosaure infernal# possède", /*spanish*/"el #dinosaurio infernal# porta"},
Text{ "An #immense cavern# rewards", /*french*/ "l'#immense caverne# octroie", }, {},
/*spanish*/ "una #descomunal cueva# premia con" }, //clear text
}, Text{"#King Dodongo# holds", /*french*/"le #Roi Dodongo# possède", /*spanish*/"el #Rey Dodongo# porta"});
{},
// clear text
Text{ "#Dodongo's Cavern# rewards", /*french*/ "la #Caverne Dodongo# octroie",
/*spanish*/ "la #Cueva de los Dodongos# premia con" });
hintTable[BARINADE] = HintText::Boss( hintTable[BARINADE] = HintText::Boss({
{ //obscure text
// obscure text Text{"the #Bio-Electric Anemone# holds", /*french*/"l'#anémone bioélectrique# possède", /*spanish*/"la #anémona bioeléctrica# porta"},
Text{ "the #belly of a deity# rewards", /*french*/ "le #ventre du gardien# octroie", }, {},
/*spanish*/ "la #tripa de cierta deidad# premia con" }, //clear text
}, Text{"#Barinade# holds", /*french*/"#Barinade# possède", /*spanish*/"#Barinade# porta"});
{},
// clear text
Text{ "#Jabu-Jabu's Belly# rewards", /*french*/ "le #Ventre de Jabu-Jabu# octroie",
/*spanish*/ "la #tripa de Jabu-Jabu# premia con" });
hintTable[PHANTOM_GANON] = HintText::Boss( hintTable[PHANTOM_GANON] = HintText::Boss({
{ //obscure text
// 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"},
Text{ "a #deep forest# rewards", /*french*/ "la #profonde forêt# octroie", }, {},
/*spanish*/ "el #profundo bosque# premia con" }, //clear text
}, Text{"#Phantom Ganon# holds", /*french*/"#Ganon Spectral# possède", /*spanish*/"#Ganon Fantasma# porta"});
{},
// clear text
Text{ "the #Forest Temple# rewards", /*french*/ "le #Temple de la Forêt# octroie",
/*spanish*/ "el #Templo del Bosque# premia con" });
hintTable[VOLVAGIA] = HintText::Boss( hintTable[VOLVAGIA] = HintText::Boss({
{ //obscure text
// obscure text Text{"the #Subterranean Lava Dragon# holds", /*french*/"le #dragon des profondeurs# possède", /*spanish*/"el #dragón de lava subterráneo# porta"},
Text{ "a #high mountain# rewards", /*french*/ "la #grande montagne# octroie", }, {},
/*spanish*/ "una #alta montaña# premia con" }, //clear text
}, Text{"#Volvagia# holds", /*french*/"#Volvagia# possède", /*spanish*/"#Volvagia# porta"});
{},
// clear text
Text{ "the #Fire Temple# rewards", /*french*/ "le #Temple du Feu# octroie",
/*spanish*/ "el #Templo del Fuego# premia con" });
hintTable[MORPHA] = HintText::Boss( hintTable[MORPHA] = HintText::Boss({
{ //obscure text
// obscure text Text{"the #Giant Aquatic Amoeba# holds", /*french*/"l'#amibe aquatique géante# possède", /*spanish*/"la #ameba acuática gigante# porta"},
Text{ "a #vast lake# rewards", /*french*/ "le #vaste lac# octroie", }, {},
/*spanish*/ "un #lago inmenso# premia con" }, //clear text
}, Text{"#Morpha# holds", /*french*/"#Morpha# possède", /*spanish*/"#Morpha# porta"});
{},
// clear text
Text{ "the #Water Temple# rewards", /*french*/ "le #Temple de l'Eau# octroie",
/*spanish*/ "el #Templo del Agua# premia con" });
hintTable[BONGO_BONGO] = HintText::Boss( hintTable[BONGO_BONGO] = HintText::Boss({
{ //obscure text
// obscure text Text{"the #Phantom Shadow Beast# holds", /*french*/"le #monstre de l'ombre# possède", /*spanish*/"la #alimaña oscura espectral# porta"},
Text{ "the #house of the dead# rewards", /*french*/ "la #maison des morts# octroie", }, {},
/*spanish*/ "la #casa de la muerte# premia con" }, //clear text
}, Text{"#Bongo Bongo# holds", /*french*/"#Bongo Bongo# possède", /*spanish*/"#Bongo Bongo# porta"});
{},
// clear text
Text{ "the #Shadow Temple# rewards", /*french*/ "le #Temple de l'Ombre# octroie",
/*spanish*/ "el #Templo de las Sombras#" });
hintTable[TWINROVA] = HintText::Boss( hintTable[TWINROVA] = HintText::Boss({
{ //obscure text
// obscure text Text{"the #Sorceress Sisters# hold", /*french*/"#les sorcières jumelles# possède", /*spanish*/"las #hermanas hechiceras# portan"},
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{"#Twinrova# holds", /*french*/"#Twinrova# possède", /*spanish*/"#Birova# porta"});
{},
// clear text
Text{ "the #Spirit Temple# rewards", /*french*/ "le #Temple de l'Esprit# octroie",
/*spanish*/ "el #Templo del Espíritu# premia con" });
// //
// [LINKS_POCKET_BOSS] = HintText::Boss({ // [LINKS_POCKET_BOSS] = HintText::Boss({
// //obscure text // //obscure text

View File

@ -317,17 +317,12 @@ static void CreateWothHint(uint8_t* remainingDungeonWothHints) {
Location(hintedLocation)->SetAsHinted(); Location(hintedLocation)->SetAsHinted();
uint32_t gossipStone = RandomElement(gossipStoneLocations); uint32_t gossipStone = RandomElement(gossipStoneLocations);
// form hint text
Text locationText;
if (Location(hintedLocation)->IsDungeon()) { if (Location(hintedLocation)->IsDungeon()) {
*remainingDungeonWothHints -= 1; *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(); Text finalWothHint = Hint(PREFIX).GetText() + "#" + locationText + "#" + Hint(WAY_OF_THE_HERO).GetText();
SPDLOG_DEBUG("\tMessage: "); SPDLOG_DEBUG("\tMessage: ");
SPDLOG_DEBUG(finalWothHint.english); SPDLOG_DEBUG(finalWothHint.english);
@ -365,16 +360,12 @@ static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector<u
Location(hintedLocation)->SetAsHinted(); Location(hintedLocation)->SetAsHinted();
uint32_t gossipStone = RandomElement(gossipStoneLocations); uint32_t gossipStone = RandomElement(gossipStoneLocations);
// form hint text
Text locationText;
if (Location(hintedLocation)->IsDungeon()) { if (Location(hintedLocation)->IsDungeon()) {
*remainingDungeonBarrenHints -= 1; *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 = Text finalBarrenHint =
Hint(PREFIX).GetText() + Hint(PLUNDERING).GetText() + "#" + locationText + "#" + Hint(FOOLISH).GetText(); Hint(PREFIX).GetText() + Hint(PLUNDERING).GetText() + "#" + locationText + "#" + Hint(FOOLISH).GetText();
SPDLOG_DEBUG("\tMessage: "); SPDLOG_DEBUG("\tMessage: ");
@ -419,16 +410,15 @@ static void CreateRandomLocationHint(const bool goodItem = false) {
//form hint text //form hint text
Text itemText = Location(hintedLocation)->GetPlacedItem().GetHint().GetText(); 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()) { 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+"#."; Text finalHint = Hint(PREFIX).GetText()+"#"+locationText+"# "+Hint(HOARDS).GetText()+" #"+itemText+"#.";
SPDLOG_DEBUG("\tMessage: "); SPDLOG_DEBUG("\tMessage: ");
SPDLOG_DEBUG(finalHint.english); SPDLOG_DEBUG(finalHint.english);
SPDLOG_DEBUG("\n\n"); SPDLOG_DEBUG("\n\n");
AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}); AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED});
} else { } else {
Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText();
Text finalHint = Hint(PREFIX).GetText()+"#"+itemText+"# "+Hint(CAN_BE_FOUND_AT).GetText()+" #"+locationText+"#."; Text finalHint = Hint(PREFIX).GetText()+"#"+itemText+"# "+Hint(CAN_BE_FOUND_AT).GetText()+" #"+locationText+"#.";
SPDLOG_DEBUG("\tMessage: "); SPDLOG_DEBUG("\tMessage: ");
SPDLOG_DEBUG(finalHint.english); SPDLOG_DEBUG(finalHint.english);

View File

@ -1083,6 +1083,8 @@ typedef enum {
DEATH_MOUNTAIN_CRATER, DEATH_MOUNTAIN_CRATER,
//AREAS //AREAS
MARKER_AREAS_START, // Used for area key count
ROOT, ROOT,
ROOT_EXITS, ROOT_EXITS,
CHILD_SPAWN, CHILD_SPAWN,
@ -1263,6 +1265,16 @@ typedef enum {
DEKU_TREE_BASEMENT_BACK_ROOM, DEKU_TREE_BASEMENT_BACK_ROOM,
DEKU_TREE_BASEMENT_UPPER, DEKU_TREE_BASEMENT_UPPER,
DEKU_TREE_OUTSIDE_BOSS_ROOM, 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, DEKU_TREE_BOSS_ROOM,
DODONGOS_CAVERN_BEGINNING, DODONGOS_CAVERN_BEGINNING,
@ -1287,6 +1299,14 @@ typedef enum {
DODONGOS_CAVERN_FAR_BRIDGE, DODONGOS_CAVERN_FAR_BRIDGE,
DODONGOS_CAVERN_BOSS_AREA, DODONGOS_CAVERN_BOSS_AREA,
DODONGOS_CAVERN_BACK_ROOM, 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, DODONGOS_CAVERN_BOSS_ROOM,
JABU_JABUS_BELLY_BEGINNING, JABU_JABUS_BELLY_BEGINNING,
@ -1306,6 +1326,13 @@ typedef enum {
JABU_JABUS_BELLY_ABOVE_BIGOCTO, JABU_JABUS_BELLY_ABOVE_BIGOCTO,
JABU_JABUS_BELLY_LIFT_UPPER, JABU_JABUS_BELLY_LIFT_UPPER,
JABU_JABUS_BELLY_NEAR_BOSS_ROOM, 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, JABU_JABUS_BELLY_BOSS_ROOM,
FOREST_TEMPLE_FIRST_ROOM, FOREST_TEMPLE_FIRST_ROOM,
@ -1335,11 +1362,24 @@ typedef enum {
FOREST_TEMPLE_GREEN_POE_ROOM, FOREST_TEMPLE_GREEN_POE_ROOM,
FOREST_TEMPLE_EAST_CORRIDOR, FOREST_TEMPLE_EAST_CORRIDOR,
FOREST_TEMPLE_BOSS_REGION, 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, FOREST_TEMPLE_BOSS_ROOM,
FIRE_TEMPLE_FIRST_ROOM, FIRE_TEMPLE_FIRST_ROOM,
FIRE_TEMPLE_NEAR_BOSS_ROOM, FIRE_TEMPLE_NEAR_BOSS_ROOM,
FIRE_TEMPLE_BOSS_ROOM,
FIRE_TEMPLE_LOOP_ENEMIES, FIRE_TEMPLE_LOOP_ENEMIES,
FIRE_TEMPLE_LOOP_TILES, FIRE_TEMPLE_LOOP_TILES,
FIRE_TEMPLE_LOOP_FLARE_DANCER, FIRE_TEMPLE_LOOP_FLARE_DANCER,
@ -1374,6 +1414,16 @@ typedef enum {
FIRE_TEMPLE_HAMMER_RETURN_PATH, FIRE_TEMPLE_HAMMER_RETURN_PATH,
FIRE_TEMPLE_ABOVE_FIRE_MAZE, 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_LOBBY,
WATER_TEMPLE_EAST_LOWER, WATER_TEMPLE_EAST_LOWER,
WATER_TEMPLE_MAP_ROOM, WATER_TEMPLE_MAP_ROOM,
@ -1401,6 +1451,14 @@ typedef enum {
WATER_TEMPLE_LONGSHOT_ROOM, WATER_TEMPLE_LONGSHOT_ROOM,
WATER_TEMPLE_RIVER, WATER_TEMPLE_RIVER,
WATER_TEMPLE_PRE_BOSS_ROOM, 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, WATER_TEMPLE_BOSS_ROOM,
SPIRIT_TEMPLE_LOBBY, SPIRIT_TEMPLE_LOBBY,
@ -1411,82 +1469,7 @@ typedef enum {
SPIRIT_TEMPLE_OUTDOOR_HANDS, SPIRIT_TEMPLE_OUTDOOR_HANDS,
SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR,
SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR,
SPIRIT_TEMPLE_INSIDE_STATUE_HEAD,
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_LOBBY,
SPIRIT_TEMPLE_MQ_CHILD, SPIRIT_TEMPLE_MQ_CHILD,
@ -1496,6 +1479,16 @@ typedef enum {
SPIRIT_TEMPLE_MQ_BOSS_AREA, SPIRIT_TEMPLE_MQ_BOSS_AREA,
SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND,
SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_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_ENTRYWAY,
SHADOW_TEMPLE_MQ_BEGINNING, SHADOW_TEMPLE_MQ_BEGINNING,
@ -1507,15 +1500,32 @@ typedef enum {
SHADOW_TEMPLE_MQ_BEYOND_BOAT, SHADOW_TEMPLE_MQ_BEYOND_BOAT,
SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, 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_PERIMETER,
BOTTOM_OF_THE_WELL_MQ_MIDDLE, BOTTOM_OF_THE_WELL_MQ_MIDDLE,
ICE_CAVERN_BEGINNING,
ICE_CAVERN_MAIN,
ICE_CAVERN_MQ_BEGINNING, ICE_CAVERN_MQ_BEGINNING,
ICE_CAVERN_MQ_MAP_ROOM, ICE_CAVERN_MQ_MAP_ROOM,
ICE_CAVERN_MQ_IRON_BOOTS_REGION, ICE_CAVERN_MQ_IRON_BOOTS_REGION,
ICE_CAVERN_MQ_COMPASS_ROOM, 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_LOBBY,
GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE,
GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER,
@ -1524,6 +1534,16 @@ typedef enum {
GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS,
GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, 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_LOBBY,
GANONS_CASTLE_MQ_DEKU_SCRUBS, GANONS_CASTLE_MQ_DEKU_SCRUBS,
GANONS_CASTLE_MQ_FOREST_TRIAL, GANONS_CASTLE_MQ_FOREST_TRIAL,
@ -1533,6 +1553,8 @@ typedef enum {
GANONS_CASTLE_MQ_SPIRIT_TRIAL, GANONS_CASTLE_MQ_SPIRIT_TRIAL,
GANONS_CASTLE_MQ_LIGHT_TRIAL, GANONS_CASTLE_MQ_LIGHT_TRIAL,
MARKER_AREAS_END, // Used for area key count
//DUNGEONS //DUNGEONS
DEKU_TREE, DEKU_TREE,
DODONGOS_CAVERN, DODONGOS_CAVERN,
@ -1542,8 +1564,8 @@ typedef enum {
WATER_TEMPLE, WATER_TEMPLE,
SPIRIT_TEMPLE, SPIRIT_TEMPLE,
SHADOW_TEMPLE, SHADOW_TEMPLE,
BOTTOM_OF_THE_WELL,
ICE_CAVERN, ICE_CAVERN,
//BOTTOM_OF_THE_WELL,
GERUDO_TRAINING_GROUNDS, GERUDO_TRAINING_GROUNDS,
GANONS_CASTLE, GANONS_CASTLE,

View File

@ -371,458 +371,24 @@ void AreaTable_Init() {
namespace Areas { namespace Areas {
static std::array<const uint32_t, 424> allAreas = { const auto GetAllAreas() {
ROOT, static const size_t areaCount = MARKER_AREAS_END - (MARKER_AREAS_START + 1);
ROOT_EXITS,
CHILD_SPAWN, static std::array<uint32_t, areaCount> allAreas = {};
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,
KOKIRI_FOREST, static bool intialized = false;
KF_LINKS_HOUSE, if (!intialized) {
KF_MIDOS_HOUSE, for (size_t i = 0; i < areaCount; i++) {
KF_SARIAS_HOUSE, allAreas[i] = (MARKER_AREAS_START + 1) + i;
KF_HOUSE_OF_TWINS, }
KF_KNOW_IT_ALL_HOUSE, intialized = true;
KF_KOKIRI_SHOP, }
KF_STORMS_GROTTO,
KF_OUTSIDE_DEKU_TREE,
DEKU_TREE_ENTRYWAY,
THE_LOST_WOODS, return allAreas;
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,
};
void AccessReset() { void AccessReset() {
for (const uint32_t area : allAreas) { for (const uint32_t area : GetAllAreas()) {
AreaTable(area)->ResetVariables(); AreaTable(area)->ResetVariables();
} }
@ -843,7 +409,7 @@ namespace Areas {
//Reset exits and clear items from locations //Reset exits and clear items from locations
void ResetAllLocations() { void ResetAllLocations() {
for (const uint32_t area : allAreas) { for (const uint32_t area : GetAllAreas()) {
AreaTable(area)->ResetVariables(); AreaTable(area)->ResetVariables();
//Erase item from every location in this exit //Erase item from every location in this exit
for (LocationAccess& locPair : AreaTable(area)->locations) { for (LocationAccess& locPair : AreaTable(area)->locations) {
@ -868,7 +434,7 @@ namespace Areas {
} }
bool HasTimePassAccess(uint8_t age) { bool HasTimePassAccess(uint8_t age) {
for (const uint32_t areaKey : allAreas) { for (const uint32_t areaKey : GetAllAreas()) {
auto area = AreaTable(areaKey); auto area = AreaTable(areaKey);
if (area->timePass && ((age == AGE_CHILD && area->Child()) || (age == AGE_ADULT && area->Adult()))) { if (area->timePass && ((age == AGE_CHILD && area->Child()) || (age == AGE_ADULT && area->Adult()))) {
return true; return true;
@ -886,7 +452,7 @@ namespace Areas {
worldGraph.open (str + ".dot"); worldGraph.open (str + ".dot");
worldGraph << "digraph {\n\tcenter=true;\n"; worldGraph << "digraph {\n\tcenter=true;\n";
for (const uint32_t areaKey : allAreas) { for (const uint32_t areaKey : GetAllAreas()) {
auto area = AreaTable(areaKey); auto area = AreaTable(areaKey);
for (auto exit : area->exits) { for (auto exit : area->exits) {
if (exit.GetConnectedRegion()->regionName != "Invalid Area") { 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 //Retrieve all the shuffable entrances of a specific type
std::vector<Entrance*> GetShuffleableEntrances(EntranceType type, bool onlyPrimary /*= true*/) { std::vector<Entrance*> GetShuffleableEntrances(EntranceType type, bool onlyPrimary /*= true*/) {
std::vector<Entrance*> entrancesToShuffle = {}; std::vector<Entrance*> entrancesToShuffle = {};
for (uint32_t area : Areas::allAreas) { for (uint32_t area : Areas::GetAllAreas()) {
for (auto& exit: AreaTable(area)->exits) { for (auto& exit: AreaTable(area)->exits) {
if ((exit.GetType() == type || type == EntranceType::All) && (exit.IsPrimary() || !onlyPrimary) && exit.GetType() != EntranceType::None) { if ((exit.GetType() == type || type == EntranceType::All) && (exit.IsPrimary() || !onlyPrimary) && exit.GetType() != EntranceType::None) {
entrancesToShuffle.push_back(&exit); entrancesToShuffle.push_back(&exit);

View File

@ -38,7 +38,7 @@ void AreaTable_Init_DekuTree() {
/*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}),
Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return false;}, Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return false;},
/*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), /*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);}}), /*Glitched*/[]{return IsChild && CanUse(KOKIRI_SWORD) && Nuts && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::EXPERT);}}),
}); });
@ -72,7 +72,7 @@ void AreaTable_Init_DekuTree() {
}, { }, {
//Exits //Exits
Entrance(DEKU_TREE_LOBBY, {[]{return HasFireSourceWithTorch || CanUse(BOW);}}), 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);}}), /*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, {}, {}, { areaTable[DEKU_TREE_OUTSIDE_BOSS_ROOM] = Area("Deku Tree Outside Boss Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits //Exits
Entrance(DEKU_TREE_BASEMENT_UPPER, {[]{return true;}}), Entrance(DEKU_TREE_BASEMENT_UPPER, {[]{return true;}}),
Entrance(DEKU_TREE_BOSS_ROOM, {[]{return Here(DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return HasShield;});}}), Entrance(DEKU_TREE_BOSS_ENTRYWAY, {[]{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;}}),
}); });
} }
@ -261,6 +247,51 @@ void AreaTable_Init_DekuTree() {
//Exits //Exits
Entrance(DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return IsChild;}}), Entrance(DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return IsChild;}}),
Entrance(DEKU_TREE_MQ_LOBBY, {[]{return true;}}), 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; } }),
});
} }

View File

@ -50,7 +50,7 @@ void AreaTable_Init_DodongosCavern() {
Entrance(DODONGOS_CAVERN_FAR_BRIDGE, {[]{return HasAccessTo(DODONGOS_CAVERN_FAR_BRIDGE);}, Entrance(DODONGOS_CAVERN_FAR_BRIDGE, {[]{return HasAccessTo(DODONGOS_CAVERN_FAR_BRIDGE);},
/*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE);}}), /*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_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);}}), /*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_LOBBY, {[]{return true;}}),
Entrance(DODONGOS_CAVERN_BACK_ROOM, {[]{return Here(DODONGOS_CAVERN_BOSS_AREA, []{return CanBlastOrSmash;});}, 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));});}}), /*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, {}, { 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 //Exits
Entrance(DODONGOS_CAVERN_BOSS_AREA, {[]{return true;}}), 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(DODONGOS_CAVERN_KING_DODONGO_HEART, {[]{return CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword);}}),
LocationAccess(KING_DODONGO, {[]{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;}}), 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; } }),
});
} }

View File

@ -42,25 +42,11 @@ void AreaTable_Init_FireTemple() {
}, { }, {
//Exits //Exits
Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}), 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) || /*Glitched*/[]{return BossKeyFireTemple && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) ||
(Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)));}}), (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, {}, {}, { areaTable[FIRE_TEMPLE_LOOP_ENEMIES] = Area("Fire Temple Loop Enemies", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits //Exits
Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 8) || !IsKeysanity;}}), 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, {}, {}, { areaTable[FIRE_TEMPLE_WEST_CENTRAL_UPPER] = Area("Fire Temple West Central Upper", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits //Exits
Entrance(FIRE_TEMPLE_BOSS_ROOM, {[]{return false;}, Entrance(FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return false;},
/*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}),
Entrance(FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return true;}}), Entrance(FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return true;}}),
Entrance(FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return true;}}), Entrance(FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return true;}}),
@ -375,7 +361,7 @@ void AreaTable_Init_FireTemple() {
}, { }, {
//Exits //Exits
Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return true;}}), 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_LOWER_LOCKED_DOOR, {[]{return SmallKeys(FIRE_TEMPLE, 5) && (IsAdult || KokiriSword);}}),
Entrance(FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, {[]{return IsAdult && FireTimer >= 24 && CanUse(MEGATON_HAMMER);}}), 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);}}), 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)) //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; } }),
});
} }

View File

@ -58,7 +58,7 @@ void AreaTable_Init_ForestTemple() {
Entrance(FOREST_TEMPLE_EAST_CORRIDOR, {[]{return false;}, Entrance(FOREST_TEMPLE_EAST_CORRIDOR, {[]{return false;},
/*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}),
Entrance(FOREST_TEMPLE_BOSS_REGION, {[]{return ForestTempleMeg;}}), 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;}}), /*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));}}), /*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_MAP_ROOM, {[]{return true;}}),
Entrance(FOREST_TEMPLE_SEWER, {[]{return GoldScale || CanUse(IRON_BOOTS) || HasAccessTo(FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}), 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);}}), /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE);}}),
}); });
@ -304,19 +304,7 @@ void AreaTable_Init_ForestTemple() {
}, { }, {
//Exits //Exits
Entrance(FOREST_TEMPLE_LOBBY, {[]{return true;}}), Entrance(FOREST_TEMPLE_LOBBY, {[]{return true;}}),
Entrance(FOREST_TEMPLE_BOSS_ROOM, {[]{return BossKeyForestTemple;}}), Entrance(FOREST_TEMPLE_BOSS_ENTRYWAY, {[]{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;}}),
}); });
} }
@ -439,14 +427,43 @@ void AreaTable_Init_ForestTemple() {
Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return true;}}), 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, { areaTable[FOREST_TEMPLE_MQ_BOSS_REGION] = Area("Forest Temple MQ Boss Region", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Events
EventAccess(&ForestTempleClear, {[]{return ForestTempleClear || BossKeyForestTemple;}}),
}, {
//Locations //Locations
LocationAccess(FOREST_TEMPLE_MQ_BASEMENT_CHEST, {[]{return true;}}), 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; } }),
});
} }

View File

@ -162,23 +162,10 @@ void AreaTable_Init_JabuJabusBelly() {
}, { }, {
//Exits //Exits
Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), 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) || /*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);}}), (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 //Locations
LocationAccess(JABU_JABUS_BELLY_MQ_COW, {[]{return CanPlay(EponasSong);}}), LocationAccess(JABU_JABUS_BELLY_MQ_COW, {[]{return CanPlay(EponasSong);}}),
LocationAccess(JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, {[]{return true;}}), 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;}}), LocationAccess(JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, {[]{return true;}}),
}, { }, {
//Exits //Exits
Entrance(JABU_JABUS_BELLY_MQ_MAIN, {[]{return true;}}), 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; } }),
});
} }

View File

@ -81,18 +81,16 @@ void AreaTable_Init_ShadowTemple() {
Entrance(SHADOW_TEMPLE_BEYOND_BOAT, {[]{return CanPlay(ZeldasLullaby) && SmallKeys(SHADOW_TEMPLE, 4, 5);}}), 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, { areaTable[SHADOW_TEMPLE_BEYOND_BOAT] = Area("Shadow Temple Beyond Boat", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Events
EventAccess(&ShadowTempleClear, {[]{return ShadowTempleClear || (SmallKeys(SHADOW_TEMPLE, 5) && BossKeyShadowTemple && (Bow || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus)));}}),
}, {
//Locations //Locations
LocationAccess(SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, {[]{return CanUse(DINS_FIRE);}}), LocationAccess(SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, {[]{return CanUse(DINS_FIRE);}}),
LocationAccess(SHADOW_TEMPLE_BOSS_KEY_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_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;}}), 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);}}), 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, { areaTable[SHADOW_TEMPLE_MQ_BEYOND_BOAT] = Area("Shadow Temple MQ Beyond Boat", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Events
EventAccess(&ShadowTempleClear, {[]{return ShadowTempleClear || ((Bow || (LogicShadowStatue && HasBombchus)) && BossKeyShadowTemple);}}),
}, {
//Locations //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_AFTER_SHIP, {[]{return true;}}),
LocationAccess(SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, {[]{return Bow || (LogicShadowStatue && HasBombchus);}}), LocationAccess(SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, {[]{return Bow || (LogicShadowStatue && HasBombchus);}}),
}, { }, {
//Exits //Exits
Entrance(SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, {[]{return Bow && CanPlay(SongOfTime) && IsAdult && CanUse(LONGSHOT);}}), 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, {}, { 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;}}), 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; } }),
});
} }

View File

@ -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)));}}), 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, { areaTable[SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR] = Area("Spirit Temple Beyond Final Locked Door", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Events
EventAccess(&SpiritTempleClear, {[]{return SpiritTempleClear || (MirrorShield && HasExplosives && Hookshot && BossKeySpiritTemple);}}),
}, {
//Locations //Locations
LocationAccess(SPIRIT_TEMPLE_BOSS_KEY_CHEST, {[]{return CanPlay(ZeldasLullaby) && ((CanTakeDamage && LogicFlamingChests) || (Bow && Hookshot));}}), 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_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;}}), 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, { areaTable[SPIRIT_TEMPLE_MQ_BOSS_AREA] = Area("Spirit Temple MQ Boss Area", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Events
EventAccess(&SpiritTempleClear, {[]{return SpiritTempleClear || (MirrorShield && BossKeySpiritTemple);}}),
}, {
//Locations //Locations
LocationAccess(SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, {[]{return LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH);}}), 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, {}, { areaTable[SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND] = Area("Spirit Temple MQ Mirror Shield Hand", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations //Locations
@ -229,4 +241,35 @@ void AreaTable_Init_SpiritTemple() {
LocationAccess(SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, {[]{return true;}}), 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; } }),
});
} }

View File

@ -275,19 +275,7 @@ void AreaTable_Init_WaterTemple() {
}, {}, { }, {}, {
//Exits //Exits
Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}),
Entrance(WATER_TEMPLE_BOSS_ROOM, {[]{return BossKeyWaterTemple;}}), Entrance(WATER_TEMPLE_BOSS_ENTRYWAY, {[]{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;}}),
}); });
} }
@ -295,18 +283,12 @@ void AreaTable_Init_WaterTemple() {
| MASTER QUEST DUNGEON | | MASTER QUEST DUNGEON |
---------------------------*/ ---------------------------*/
if (Dungeon::WaterTemple.IsMQ()) { if (Dungeon::WaterTemple.IsMQ()) {
areaTable[WATER_TEMPLE_MQ_LOBBY] = Area("Water Temple MQ Lobby", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { areaTable[WATER_TEMPLE_MQ_LOBBY] = Area("Water Temple MQ Lobby", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Events
EventAccess(&WaterTempleClear, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}),
}, {
//Locations
LocationAccess(WATER_TEMPLE_MORPHA_HEART, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}),
LocationAccess(MORPHA, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}),
}, {
//Exits //Exits
Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return true;}}), Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return true;}}),
Entrance(WATER_TEMPLE_MQ_DIVE, {[]{return IsAdult && WaterTimer >= 24 && CanUse(IRON_BOOTS);}}), 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_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, {}, { 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)) //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; } }),
});
} }

View File

@ -164,6 +164,17 @@ string_view dungeonEntrancesDesc = "Shuffle the pool of dungeon entrances,
"Temple, Bottom of the Well and Gerudo Training\n" // "Temple, Bottom of the Well and Gerudo Training\n" //
"Ground are opened for both adult and child."; // "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 | // | OVERWORLD ENTRANCES | //
------------------------------*/ // ------------------------------*/ //
string_view overworldEntrancesDesc = "Shuffle the pool of Overworld entrances, which\n" // 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" // "you came from when you go back through an\n" //
"entrance. This also adds the one-way entrance from" "entrance. This also adds the one-way entrance from"
"Gerudo Valley to Lake Hylia in the pool of\n" // "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 | // | BOMBCHUS IN LOGIC | //
------------------------------*/ // ------------------------------*/ //

View File

@ -57,6 +57,8 @@ extern string_view shuffleEntrancesDesc;
extern string_view dungeonEntrancesDesc; extern string_view dungeonEntrancesDesc;
extern string_view bossEntrancesDesc;
extern string_view overworldEntrancesDesc; extern string_view overworldEntrancesDesc;
extern string_view grottoEntrancesDesc; extern string_view grottoEntrancesDesc;

View File

@ -89,6 +89,7 @@ namespace Settings {
uint8_t ResolvedStartingAge; uint8_t ResolvedStartingAge;
Option ShuffleEntrances = Option::Bool("Shuffle Entrances", {"Off", "On"}, {shuffleEntrancesDesc}); Option ShuffleEntrances = Option::Bool("Shuffle Entrances", {"Off", "On"}, {shuffleEntrancesDesc});
Option ShuffleDungeonEntrances = Option::U8 ("Dungeon Entrances", {"Off", "On", "On + Ganon"}, {dungeonEntrancesDesc}); 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 ShuffleOverworldEntrances = Option::Bool("Overworld Entrances", {"Off", "On"}, {overworldEntrancesDesc});
Option ShuffleInteriorEntrances = Option::U8 ("Interior Entrances", {"Off", "Simple", "All"}, {interiorEntrancesOff, interiorEntrancesSimple, interiorEntrancesAll}); Option ShuffleInteriorEntrances = Option::U8 ("Interior Entrances", {"Off", "Simple", "All"}, {interiorEntrancesOff, interiorEntrancesSimple, interiorEntrancesAll});
Option ShuffleGrottoEntrances = Option::Bool("Grottos Entrances", {"Off", "On"}, {grottoEntrancesDesc}); Option ShuffleGrottoEntrances = Option::Bool("Grottos Entrances", {"Off", "On"}, {grottoEntrancesDesc});
@ -125,6 +126,7 @@ namespace Settings {
&StartingAge, &StartingAge,
&ShuffleEntrances, &ShuffleEntrances,
&ShuffleDungeonEntrances, &ShuffleDungeonEntrances,
&ShuffleBossEntrances,
&ShuffleOverworldEntrances, &ShuffleOverworldEntrances,
&ShuffleInteriorEntrances, &ShuffleInteriorEntrances,
&ShuffleGrottoEntrances, &ShuffleGrottoEntrances,
@ -1291,6 +1293,7 @@ namespace Settings {
ctx.startingAge = StartingAge.Value<uint8_t>(); ctx.startingAge = StartingAge.Value<uint8_t>();
ctx.resolvedStartingAge = ResolvedStartingAge; ctx.resolvedStartingAge = ResolvedStartingAge;
ctx.shuffleDungeonEntrances = ShuffleDungeonEntrances.Value<uint8_t>(); ctx.shuffleDungeonEntrances = ShuffleDungeonEntrances.Value<uint8_t>();
ctx.shuffleBossEntrances = ShuffleBossEntrances.Value<uint8_t>();
ctx.shuffleOverworldEntrances = (ShuffleOverworldEntrances) ? 1 : 0; ctx.shuffleOverworldEntrances = (ShuffleOverworldEntrances) ? 1 : 0;
ctx.shuffleInteriorEntrances = ShuffleInteriorEntrances.Value<uint8_t>(); ctx.shuffleInteriorEntrances = ShuffleInteriorEntrances.Value<uint8_t>();
ctx.shuffleGrottoEntrances = (ShuffleGrottoEntrances) ? 1 : 0; ctx.shuffleGrottoEntrances = (ShuffleGrottoEntrances) ? 1 : 0;
@ -1973,6 +1976,7 @@ namespace Settings {
//Show Shuffle options when Shuffle Entrances is On //Show Shuffle options when Shuffle Entrances is On
if (ShuffleEntrances) { if (ShuffleEntrances) {
ShuffleDungeonEntrances.Unhide(); ShuffleDungeonEntrances.Unhide();
ShuffleBossEntrances.Unhide();
ShuffleOverworldEntrances.Unhide(); ShuffleOverworldEntrances.Unhide();
ShuffleInteriorEntrances.Unhide(); ShuffleInteriorEntrances.Unhide();
ShuffleGrottoEntrances.Unhide(); ShuffleGrottoEntrances.Unhide();
@ -1984,6 +1988,8 @@ namespace Settings {
} else { } else {
ShuffleDungeonEntrances.SetSelectedIndex(SHUFFLEDUNGEONS_OFF); ShuffleDungeonEntrances.SetSelectedIndex(SHUFFLEDUNGEONS_OFF);
ShuffleDungeonEntrances.Hide(); ShuffleDungeonEntrances.Hide();
ShuffleBossEntrances.SetSelectedIndex(SHUFFLEBOSSES_OFF);
ShuffleBossEntrances.Hide();
ShuffleOverworldEntrances.SetSelectedIndex(OFF); ShuffleOverworldEntrances.SetSelectedIndex(OFF);
ShuffleOverworldEntrances.Hide(); ShuffleOverworldEntrances.Hide();
ShuffleInteriorEntrances.SetSelectedIndex(SHUFFLEINTERIORS_OFF); ShuffleInteriorEntrances.SetSelectedIndex(SHUFFLEINTERIORS_OFF);
@ -2464,6 +2470,7 @@ namespace Settings {
// Sanity Check Entrance Shuffling // Sanity Check Entrance Shuffling
if (!ShuffleEntrances) { if (!ShuffleEntrances) {
ShuffleDungeonEntrances.SetSelectedIndex(OFF); ShuffleDungeonEntrances.SetSelectedIndex(OFF);
ShuffleBossEntrances.SetSelectedIndex(OFF);
ShuffleOverworldEntrances.SetSelectedIndex(OFF); ShuffleOverworldEntrances.SetSelectedIndex(OFF);
ShuffleInteriorEntrances.SetSelectedIndex(OFF); ShuffleInteriorEntrances.SetSelectedIndex(OFF);
ShuffleGrottoEntrances.SetSelectedIndex(OFF); ShuffleGrottoEntrances.SetSelectedIndex(OFF);
@ -2681,6 +2688,7 @@ namespace Settings {
// Shuffle Entrances // Shuffle Entrances
ShuffleEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_ENTRANCES]); ShuffleEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_ENTRANCES]);
ShuffleDungeonEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_ENTRANCES]); ShuffleDungeonEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_ENTRANCES]);
ShuffleBossEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_BOSS_ENTRANCES]);
ShuffleOverworldEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_OVERWORLD_ENTRANCES]); ShuffleOverworldEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_OVERWORLD_ENTRANCES]);
ShuffleInteriorEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_INTERIOR_ENTRANCES]); ShuffleInteriorEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_INTERIOR_ENTRANCES]);
ShuffleGrottoEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_GROTTO_ENTRANCES]); ShuffleGrottoEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_GROTTO_ENTRANCES]);

View File

@ -92,6 +92,12 @@ typedef enum {
SHUFFLEDUNGEONS_GANON, SHUFFLEDUNGEONS_GANON,
} ShuffleDungeonEntrancesSetting; } ShuffleDungeonEntrancesSetting;
typedef enum {
SHUFFLEBOSSES_OFF,
SHUFFLEBOSSES_AGE_RESTRICTED,
SHUFFLEBOSSES_FULL,
} ShuffleBossEntrancesSetting;
typedef enum { typedef enum {
SHUFFLEINTERIORS_OFF, SHUFFLEINTERIORS_OFF,
SHUFFLEINTERIORS_SIMPLE, SHUFFLEINTERIORS_SIMPLE,
@ -387,6 +393,7 @@ typedef struct {
uint8_t startingAge; uint8_t startingAge;
uint8_t resolvedStartingAge; uint8_t resolvedStartingAge;
uint8_t shuffleDungeonEntrances; uint8_t shuffleDungeonEntrances;
uint8_t shuffleBossEntrances;
uint8_t shuffleOverworldEntrances; uint8_t shuffleOverworldEntrances;
uint8_t shuffleInteriorEntrances; uint8_t shuffleInteriorEntrances;
uint8_t shuffleGrottoEntrances; uint8_t shuffleGrottoEntrances;
@ -903,6 +910,7 @@ void UpdateSettings(std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettin
extern uint8_t ResolvedStartingAge; extern uint8_t ResolvedStartingAge;
extern Option ShuffleEntrances; extern Option ShuffleEntrances;
extern Option ShuffleDungeonEntrances; extern Option ShuffleDungeonEntrances;
extern Option ShuffleBossEntrances;
extern Option ShuffleOverworldEntrances; extern Option ShuffleOverworldEntrances;
extern Option ShuffleInteriorEntrances; extern Option ShuffleInteriorEntrances;
extern Option ShuffleGrottoEntrances; extern Option ShuffleGrottoEntrances;

View File

@ -306,7 +306,7 @@ static void WriteShuffledEntrance(std::string sphereString, Entrance* entrance)
std::string name = entrance->GetName(); std::string name = entrance->GetName();
std::string text = entrance->GetConnectedRegion()->regionName + " from " + entrance->GetReplacement()->GetParentRegion()->regionName; 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(); destinationIndex = entrance->GetReverse()->GetIndex();
replacementDestinationIndex = entrance->GetReplacement()->GetReverse()->GetIndex(); replacementDestinationIndex = entrance->GetReplacement()->GetReverse()->GetIndex();
replacementBlueWarp = entrance->GetReplacement()->GetReverse()->GetBlueWarp(); replacementBlueWarp = entrance->GetReplacement()->GetReverse()->GetBlueWarp();
@ -323,7 +323,7 @@ static void WriteShuffledEntrance(std::string sphereString, Entrance* entrance)
jsonData["entrances"].push_back(entranceJson); jsonData["entrances"].push_back(entranceJson);
// When decoupled entrances is off, handle saving reverse entrances with blue warps // 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({ json reverseEntranceJson = json::object({
{"index", replacementDestinationIndex}, {"index", replacementDestinationIndex},
{"destination", replacementIndex}, {"destination", replacementIndex},

View File

@ -236,6 +236,7 @@ std::unordered_map<std::string, RandomizerSettingKey> SpoilerfileSettingNameToEn
{ "World Settings:Bombchus in Logic", RSK_BOMBCHUS_IN_LOGIC }, { "World Settings:Bombchus in Logic", RSK_BOMBCHUS_IN_LOGIC },
{ "World Settings:Shuffle Entrances", RSK_SHUFFLE_ENTRANCES }, { "World Settings:Shuffle Entrances", RSK_SHUFFLE_ENTRANCES },
{ "World Settings:Dungeon Entrances", RSK_SHUFFLE_DUNGEON_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:Overworld Entrances", RSK_SHUFFLE_OVERWORLD_ENTRANCES },
{ "World Settings:Interior Entrances", RSK_SHUFFLE_INTERIOR_ENTRANCES }, { "World Settings:Interior Entrances", RSK_SHUFFLE_INTERIOR_ENTRANCES },
{ "World Settings:Grottos Entrances", RSK_SHUFFLE_GROTTO_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; gSaveContext.randoSettings[index].value = RO_DUNGEON_ENTRANCE_SHUFFLE_ON_PLUS_GANON;
} }
break; 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: case RSK_SHUFFLE_INTERIOR_ENTRANCES:
if (it.value() == "Off") { if (it.value() == "Off") {
gSaveContext.randoSettings[index].value = RO_INTERIOR_ENTRANCE_SHUFFLE_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. // Enable if any of the entrance rando options are enabled.
cvarSettings[RSK_SHUFFLE_ENTRANCES] = CVarGetInteger("gRandomizeShuffleDungeonsEntrances", RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) || 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("gRandomizeShuffleOverworldEntrances", RO_GENERIC_OFF) ||
CVarGetInteger("gRandomizeShuffleInteriorsEntrances", RO_INTERIOR_ENTRANCE_SHUFFLE_OFF) || CVarGetInteger("gRandomizeShuffleInteriorsEntrances", RO_INTERIOR_ENTRANCE_SHUFFLE_OFF) ||
CVarGetInteger("gRandomizeShuffleGrottosEntrances", RO_GENERIC_OFF) || CVarGetInteger("gRandomizeShuffleGrottosEntrances", RO_GENERIC_OFF) ||
@ -2878,6 +2889,7 @@ void GenerateRandomizerImgui() {
CVarGetInteger("gRandomizeShuffleOverworldSpawns", RO_GENERIC_OFF); CVarGetInteger("gRandomizeShuffleOverworldSpawns", RO_GENERIC_OFF);
cvarSettings[RSK_SHUFFLE_DUNGEON_ENTRANCES] = CVarGetInteger("gRandomizeShuffleDungeonsEntrances", RO_DUNGEON_ENTRANCE_SHUFFLE_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_OVERWORLD_ENTRANCES] = CVarGetInteger("gRandomizeShuffleOverworldEntrances", RO_GENERIC_OFF);
cvarSettings[RSK_SHUFFLE_INTERIOR_ENTRANCES] = CVarGetInteger("gRandomizeShuffleInteriorsEntrances", RO_INTERIOR_ENTRANCE_SHUFFLE_OFF); cvarSettings[RSK_SHUFFLE_INTERIOR_ENTRANCES] = CVarGetInteger("gRandomizeShuffleInteriorsEntrances", RO_INTERIOR_ENTRANCE_SHUFFLE_OFF);
cvarSettings[RSK_SHUFFLE_GROTTO_ENTRANCES] = CVarGetInteger("gRandomizeShuffleGrottosEntrances", RO_GENERIC_OFF); cvarSettings[RSK_SHUFFLE_GROTTO_ENTRANCES] = CVarGetInteger("gRandomizeShuffleGrottosEntrances", RO_GENERIC_OFF);
@ -2937,6 +2949,7 @@ void DrawRandoEditor(bool& open) {
// World Settings // World Settings
static const char* randoStartingAge[3] = { "Child", "Adult", "Random" }; static const char* randoStartingAge[3] = { "Child", "Adult", "Random" };
static const char* randoShuffleDungeonsEntrances[3] = { "Off", "On", "On + Ganon" }; 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* randoShuffleInteriorsEntrances[3] = { "Off", "Simple", "All" };
static const char* randoBombchusInLogic[2] = { "Off", "On" }; static const char* randoBombchusInLogic[2] = { "Off", "On" };
static const char* randoAmmoDrops[3] = { "On + Bombchu", "Off", "On" }; static const char* randoAmmoDrops[3] = { "On + Bombchu", "Off", "On" };
@ -3273,6 +3286,19 @@ void DrawRandoEditor(bool& open) {
UIWidgets::PaddedSeparator(); 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 // Shuffle Overworld Entrances
UIWidgets::EnhancementCheckbox("Shuffle Overworld Entrances", "gRandomizeShuffleOverworldEntrances"); UIWidgets::EnhancementCheckbox("Shuffle Overworld Entrances", "gRandomizeShuffleOverworldEntrances");
UIWidgets::InsertHelpHoverText( UIWidgets::InsertHelpHoverText(

View File

@ -1090,6 +1090,7 @@ typedef enum {
RSK_DECOUPLED_ENTRANCES, RSK_DECOUPLED_ENTRANCES,
RSK_STARTING_SKULLTULA_TOKEN, RSK_STARTING_SKULLTULA_TOKEN,
RSK_ALL_LOCATIONS_REACHABLE, RSK_ALL_LOCATIONS_REACHABLE,
RSK_SHUFFLE_BOSS_ENTRANCES,
RSK_MAX RSK_MAX
} RandomizerSettingKey; } RandomizerSettingKey;
@ -1267,6 +1268,14 @@ typedef enum {
RO_DUNGEON_ENTRANCE_SHUFFLE_MAX, RO_DUNGEON_ENTRANCE_SHUFFLE_MAX,
} RandoOptionDungeonEntranceShuffle; } 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) //Shuffle Interior Entrance Settings (Off, simple, all)
typedef enum { typedef enum {
RO_INTERIOR_ENTRANCE_SHUFFLE_OFF, RO_INTERIOR_ENTRANCE_SHUFFLE_OFF,

View File

@ -25,9 +25,39 @@ s16 dynamicExitList[] = { 0x045B, 0x0482, 0x03E8, 0x044B, 0x02A2, 0x0201, 0x03B8
// Owl Flights : 0x492064 and 0x492080 // Owl Flights : 0x492064 and 0x492080
static s16 entranceOverrideTable[ENTRANCE_TABLE_SIZE] = {0}; 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}; 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 //These variables store the new entrance indices for dungeons so that
//savewarping and game overs respawn players at the proper entrance. //savewarping and game overs respawn players at the proper entrance.
//By default, these will be their vanilla values. //By default, these will be their vanilla values.
@ -86,6 +116,9 @@ void Entrance_ResetEntranceTable(void) {
void Entrance_Init(void) { void Entrance_Init(void) {
s32 index; s32 index;
size_t blueWarpRemapIdx = 0;
BlueWarpReplacement bluewarps[SHUFFLEABLE_BOSS_COUNT] = {0};
Entrance_CopyOriginalEntranceTable(); Entrance_CopyOriginalEntranceTable();
// Skip Child Stealth if given by settings // Skip Child Stealth if given by settings
@ -109,6 +142,11 @@ void Entrance_Init(void) {
entranceOverrideTable[i] = i; 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 // Initialize the grotto exit and load lists
Grotto_InitExitAndLoadLists(); Grotto_InitExitAndLoadLists();
@ -138,8 +176,34 @@ void Entrance_Init(void) {
entranceOverrideTable[originalIndex] = overrideIndex; entranceOverrideTable[originalIndex] = overrideIndex;
if (blueWarpIndex != 0) { if (blueWarpIndex != 0) {
// 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; entranceOverrideTable[blueWarpIndex] = overrideIndex;
} }
}
//Override both land and water entrances for Hyrule Field -> ZR Front and vice versa //Override both land and water entrances for Hyrule Field -> ZR Front and vice versa
if (originalIndex == 0x00EA) { //Hyrule Field -> ZR Front land entrance if (originalIndex == 0x00EA) { //Hyrule Field -> ZR Front land entrance
@ -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 // Stop playing background music during shuffled entrance transitions
// so that we don't get duplicated or overlapping music tracks // so that we don't get duplicated or overlapping music tracks
if (Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_ENTRANCES)) { 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; return currentEntrance.scene == scene && currentEntrance.spawn == spawn;
} }
//Properly respawn the player after a game over, accounding for dungeon entrance // Properly respawn the player after a game over, accounting for dungeon entrance randomizer
//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)
void Entrance_SetGameOverEntrance(void) { 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 //Set the current entrance depending on which entrance the player last came through
switch (gSaveContext.entranceIndex) { switch (gSaveContext.entranceIndex) {
case 0x040F : //Deku Tree Boss Room case 0x040F : //Deku Tree Boss Room
@ -274,14 +354,19 @@ void Entrance_SetGameOverEntrance(void) {
} }
} }
//Properly savewarp the player accounting for dungeon entrance randomizer. // 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)
void Entrance_SetSavewarpEntrance(void) { void Entrance_SetSavewarpEntrance(void) {
s16 scene = gSaveContext.savedSceneNum; 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) { if (scene == SCENE_YDAN || scene == SCENE_YDAN_BOSS) {
gSaveContext.entranceIndex = newDekuTreeEntrance; gSaveContext.entranceIndex = newDekuTreeEntrance;
} else if (scene == SCENE_DDAN || scene == SCENE_DDAN_BOSS) { } else if (scene == SCENE_DDAN || scene == SCENE_DDAN_BOSS) {
@ -586,23 +671,71 @@ void Entrance_OverrideGeurdoGuardCapture(void) {
} }
void Entrance_OverrideSpawnScene(s32 sceneNum, s32 spawn) { 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) { 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 // Move Hyrule's Castle Courtyard exit spawn to be before the crates so players don't skip Talon
if (sceneNum == 95 && spawn == 1) { if (sceneNum == 95 && spawn == 1) {
gPlayState->linkActorEntry->pos.x = 0x033A; modifiedLinkActorEntry.pos.x = 0x033A;
gPlayState->linkActorEntry->pos.y = 0x0623; modifiedLinkActorEntry.pos.y = 0x0623;
gPlayState->linkActorEntry->pos.z = 0xFF22; 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 // 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) { if (sceneNum == 100 && spawn == 1) {
gPlayState->linkActorEntry->pos.x = 0xFEA8; modifiedLinkActorEntry.pos.x = 0xFEA8;
gPlayState->linkActorEntry->pos.y = 0x065C; modifiedLinkActorEntry.pos.y = 0x065C;
gPlayState->linkActorEntry->pos.z = 0x0290; modifiedLinkActorEntry.pos.z = 0x0290;
gPlayState->linkActorEntry->rot.y = 0x0700; modifiedLinkActorEntry.rot.y = 0x0700;
gPlayState->linkActorEntry->params = 0x0DFF; // stationary spawn 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) { u8 Entrance_GetIsSceneDiscovered(u8 sceneNum) {

View File

@ -26,7 +26,8 @@
#define ENTRANCE_RANDO_GROTTO_EXIT_START 0x0800 #define ENTRANCE_RANDO_GROTTO_EXIT_START 0x0800
#define MAX_ENTRANCE_RANDO_USED_INDEX 0x0820 #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_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 #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_OverrideNextIndex(int16_t nextEntranceIndex);
int16_t Entrance_OverrideDynamicExit(int16_t dynamicExitIndex); int16_t Entrance_OverrideDynamicExit(int16_t dynamicExitIndex);
uint32_t Entrance_SceneAndSpawnAre(uint8_t scene, uint8_t spawn); uint32_t Entrance_SceneAndSpawnAre(uint8_t scene, uint8_t spawn);
void Entrance_SetGameOverEntrance(void);
void Entrance_SetSavewarpEntrance(void); void Entrance_SetSavewarpEntrance(void);
void Entrance_SetWarpSongEntrance(void); void Entrance_SetWarpSongEntrance(void);
void Entrance_OverrideBlueWarp(void); void Entrance_OverrideBlueWarp(void);
@ -54,6 +56,7 @@ void Entrance_HandleEponaState(void);
void Entrance_OverrideWeatherState(void); void Entrance_OverrideWeatherState(void);
void Entrance_OverrideGeurdoGuardCapture(void); void Entrance_OverrideGeurdoGuardCapture(void);
void Entrance_OverrideSpawnScene(int32_t sceneNum, int32_t spawn); 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); void Entrance_EnableFW(void);
uint8_t Entrance_GetIsEntranceDiscovered(uint16_t entranceIndex); uint8_t Entrance_GetIsEntranceDiscovered(uint16_t entranceIndex);
void Entrance_SetEntranceDiscovered(uint16_t entranceIndex); void Entrance_SetEntranceDiscovered(uint16_t entranceIndex);

View File

@ -103,6 +103,8 @@ const EntranceData entranceData[] = {
{ 0x0266, 0x00C1, SINGLE_SCENE_INFO(0x2D), "KF Shop", "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"}, { 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, ""}, { 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 // Lost Woods
{ 0x020D, 0x05E0, SINGLE_SCENE_INFO(0x5B), "Lost Woods Bridge", "KF", ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_OVERWORLD, "lw"}, { 0x020D, 0x05E0, SINGLE_SCENE_INFO(0x5B), "Lost Woods Bridge", "KF", ENTRANCE_GROUP_LOST_WOODS, ENTRANCE_GROUP_KOKIRI_FOREST, ENTRANCE_TYPE_OVERWORLD, "lw"},
@ -128,6 +130,8 @@ const EntranceData entranceData[] = {
{ 0x0818, 0x0718, {{ 0x3C, 0x00 }}, "SFM Fairy 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"}, { 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}, { 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 // Kakariko Village
{ 0x017D, 0x00DB, SINGLE_SCENE_INFO(0x52), "Kakariko", "Hyrule Field", ENTRANCE_GROUP_KAKARIKO, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "hf"}, { 0x017D, 0x00DB, SINGLE_SCENE_INFO(0x52), "Kakariko", "Hyrule Field", ENTRANCE_GROUP_KAKARIKO, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "hf"},
@ -174,6 +178,8 @@ const EntranceData entranceData[] = {
{ 0x050B, 0x002D, SINGLE_SCENE_INFO(0x41), "Composer's 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"}, { 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}, { 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 // Death Mountain Trail
{ 0x0191, 0x013D, SINGLE_SCENE_INFO(0x60), "DMT", "Kakariko", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_KAKARIKO, ENTRANCE_TYPE_OVERWORLD}, { 0x0191, 0x013D, SINGLE_SCENE_INFO(0x60), "DMT", "Kakariko", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_KAKARIKO, ENTRANCE_TYPE_OVERWORLD},
@ -187,6 +193,8 @@ const EntranceData entranceData[] = {
{ 0x0808, 0x0708, {{ 0x3E, 0x00 }}, "DMT Storms Grotto", "DMT", ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_GROTTO, "chest"}, { 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}, { 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"}, { 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 // 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"}, { 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"}, { 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"}, { 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}, { 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 // Goron City
{ 0x01B9, 0x014D, SINGLE_SCENE_INFO(0x62), "Goron City", "DMT", ENTRANCE_GROUP_GORON_CITY, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_OVERWORLD, "gc"}, { 0x01B9, 0x014D, SINGLE_SCENE_INFO(0x62), "Goron City", "DMT", ENTRANCE_GROUP_GORON_CITY, ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, ENTRANCE_TYPE_OVERWORLD, "gc"},
@ -236,6 +246,8 @@ const EntranceData entranceData[] = {
{ 0x0088, 0x03D4, SINGLE_SCENE_INFO(0x59), "ZF", "Ice Cavern", 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}, { 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}, { 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}, { 0x03D4, 0x0088, SINGLE_SCENE_INFO(0x09), "Ice Cavern", "ZF", ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_GROUP_ZORAS_FOUNTAIN, ENTRANCE_TYPE_DUNGEON},
// Hyrule Field // Hyrule Field
@ -285,6 +297,8 @@ const EntranceData entranceData[] = {
{ 0x0309, 0x045F, SINGLE_SCENE_INFO(0x49), "Fishing Hole", "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"}, { 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"}, { 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 // Gerudo Area
{ 0x018D, 0x0117, SINGLE_SCENE_INFO(0x5A), "GV", "Hyrule Field", ENTRANCE_GROUP_GERUDO_VALLEY, ENTRANCE_GROUP_HYRULE_FIELD, ENTRANCE_TYPE_OVERWORLD, "hf"}, { 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"}, { 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"}, { 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"}, { 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 // 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"}, { 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"},

View File

@ -1,5 +1,6 @@
#include "global.h" #include "global.h"
#include "vt.h" #include "vt.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
void func_80095AB4(PlayState* play, Room* room, u32 flags); void func_80095AB4(PlayState* play, Room* room, u32 flags);
void func_80095D04(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) { s32 func_8009728C(PlayState* play, RoomContext* roomCtx, s32 roomNum) {
size_t size; 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); return OTRfunc_8009728C(play, roomCtx, roomNum);
if (roomCtx->status == 0) { if (roomCtx->status == 0) {

View File

@ -49,8 +49,9 @@ void BgSpot01Idosoko_Init(Actor* thisx, PlayState* play) {
this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, colHeader); 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 // If dungeon entrance randomizer is on, remove the well stone as adult Link when
// child Link has drained the water to the well // child Link has drained the water to the well
if (!LINK_IS_ADULT || gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) && if (!LINK_IS_ADULT || (gSaveContext.n64ddFlag &&
Flags_GetEventChkInf(0x67)) { Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF &&
Flags_GetEventChkInf(0x67))) {
Actor_Kill(&this->dyna.actor); Actor_Kill(&this->dyna.actor);
} else { } else {
BgSpot01Idosoko_SetupAction(this, func_808ABF54); BgSpot01Idosoko_SetupAction(this, func_808ABF54);

View File

@ -60,7 +60,7 @@ void BgSpot12Saku_Init(Actor* thisx, PlayState* play) {
// If ER is on, force the gate to always use its permanent flag // 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) // (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; thisx->params = 0x0002;
} }
@ -132,7 +132,7 @@ void BgSpot12Saku_Update(Actor* thisx, PlayState* play) {
BgSpot12Saku* this = (BgSpot12Saku*)thisx; BgSpot12Saku* this = (BgSpot12Saku*)thisx;
// If ER is on, when the guard opens the GtG gate its permanent flag will be set. // 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_GetSwitch(play, 0x3A)) {
Flags_SetSwitch(play, 0x2); Flags_SetSwitch(play, 0x2);
} }

View File

@ -73,8 +73,10 @@ void BgTreemouth_Init(Actor* thisx, PlayState* play) {
if ((gSaveContext.sceneSetupIndex < 4) && !LINK_IS_ADULT) { if ((gSaveContext.sceneSetupIndex < 4) && !LINK_IS_ADULT) {
BgTreemouth_SetupAction(this, func_808BC8B8); 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 // If dungeon entrance randomizer is on, keep the tree mouth open
} else if ((LINK_IS_ADULT && (!gSaveContext.n64ddFlag || !Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) || // 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)) { !Flags_GetEventChkInf(0x4)) || (gSaveContext.sceneSetupIndex == 7)) {
this->unk_168 = 0.0f; this->unk_168 = 0.0f;
BgTreemouth_SetupAction(this, BgTreemouth_DoNothing); BgTreemouth_SetupAction(this, BgTreemouth_DoNothing);

View File

@ -582,7 +582,8 @@ void DoorWarp1_ChildWarpOut(DoorWarp1* this, PlayState* play) {
gSaveContext.nextCutsceneIndex = 0; 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(); Entrance_OverrideBlueWarp();
} }
@ -688,7 +689,8 @@ void DoorWarp1_RutoWarpOut(DoorWarp1* this, PlayState* play) {
gSaveContext.nextCutsceneIndex = 0xFFF0; 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(); 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(); Entrance_OverrideBlueWarp();
} }

View File

@ -332,7 +332,8 @@ void EnIshi_Init(Actor* thisx, PlayState* play) {
} }
// If dungeon entrance randomizer is on, remove the grey boulders that normally // If dungeon entrance randomizer is on, remove the grey boulders that normally
// block child Link from reaching the Fire Temple entrance. // 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 play->sceneNum == 0x061) { // Death Mountain Creater
Actor_Kill(&this->actor); Actor_Kill(&this->actor);
} }

View File

@ -4127,6 +4127,11 @@ void KaleidoScope_Update(PlayState* play)
gSaveContext.entranceIndex = 0x041B; gSaveContext.entranceIndex = 0x041B;
break; break;
} }
// In ER, handle overriding the game over respawn entrance
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
Entrance_SetGameOverEntrance();
}
} else { } else {
Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
} }