[Feature] Entrance Rando v2 (#2071)

This commit is contained in:
Adam Bird 2022-12-06 18:37:50 -05:00 committed by GitHub
parent 598cac725e
commit d9f3844b2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1599 additions and 536 deletions

View File

@ -261,6 +261,12 @@ typedef struct {
/* */ char adultAltarText[750];
/* */ char ganonHintText[150];
/* */ char ganonText[250];
/* */ char warpMinuetText[100];
/* */ char warpBoleroText[100];
/* */ char warpSerenadeText[100];
/* */ char warpRequiemText[100];
/* */ char warpNocturneText[100];
/* */ char warpPreludeText[100];
/* */ u8 seedIcons[5];
/* */ u16 randomizerInf[9];
/* */ u16 adultTradeItems;

View File

@ -28,6 +28,13 @@ typedef enum {
TEXT_SCRUB_RANDOM_FREE = 0x9001,
TEXT_SHOP_ITEM_RANDOM = 0x9100,
TEXT_SHOP_ITEM_RANDOM_CONFIRM = 0x9101,
TEXT_WARP_MINUET_OF_FOREST = 0x88D,
TEXT_WARP_BOLERO_OF_FIRE = 0x88E,
TEXT_WARP_SERENADE_OF_WATER = 0x88F,
TEXT_WARP_REQUIEM_OF_SPIRIT = 0x890,
TEXT_WARP_NOCTURNE_OF_SHADOW = 0x891,
TEXT_WARP_PRELUDE_OF_LIGHT = 0x892,
TEXT_WARP_RANDOM_REPLACED_TEXT = 0x9200,
} TextIDs;
#ifdef __cplusplus

View File

@ -570,6 +570,7 @@ const std::vector<PresetEntry> s6PresetEntries = {
PRESET_ENTRY_S32("gRandomizeShuffleDungeonReward", RO_DUNGEON_REWARDS_END_OF_DUNGEON),
PRESET_ENTRY_S32("gRandomizeShuffleGanonBossKey", RO_GANON_BOSS_KEY_STARTWITH),
PRESET_ENTRY_S32("gRandomizeShuffleKokiriSword", 1),
PRESET_ENTRY_S32("gRandomizeShuffleOverworldSpawns", RO_GENERIC_ON),
PRESET_ENTRY_S32("gRandomizeSkipChildStealth", 1),
PRESET_ENTRY_S32("gRandomizeSkipChildZelda", 1),
PRESET_ENTRY_S32("gRandomizeSkipEponaRace", 1),
@ -674,7 +675,7 @@ const std::map<PresetType, PresetTypeDefinition> presetTypes = {
{ RANDOMIZER_PRESET_S6, {
"S6 Tournament (Adapted)",
"Matches OOTR S6 tournament settings as close as we can get with the options available in SoH. The following differences are notable:\n" \
"- Child overworld spawn not randomized\n" \
"- Both child and adult overworld spawns are randomized" \
"- Dungeon rewards are shuffled at the end of dungeons, rather than at the end of their own dungeon\n" \
"- Full adult trade sequence is shuffled instead of the selected 4\n" \
"- Hint distribution no \"tournament\" mode, falling back to balanced",

File diff suppressed because it is too large Load Diff

View File

@ -21,11 +21,15 @@ enum class EntranceType {
WarpSong,
Dungeon,
GanonDungeon,
DungeonReverse,
Interior,
InteriorReverse,
SpecialInterior,
GrottoGrave,
GrottoGraveReverse,
Overworld,
Extra,
Mixed,
All,
};
@ -40,6 +44,11 @@ public:
}
}
// Resets the glitchless condition for the entrance
void SetCondition(ConditionFn newCondition) {
conditions_met[0] = newCondition;
}
bool GetConditionsMet() const {
if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) {
return true;

View File

@ -296,7 +296,7 @@ std::vector<uint32_t> GetAccessibleLocations(const std::vector<uint32_t>& allowe
entranceSphere.push_back(&exit);
exit.AddToPool();
// Don't list a coupled entrance from both directions
if (exit.GetReplacement()->GetReverse() != nullptr /*&& !DecoupleEntrances*/) {
if (exit.GetReplacement()->GetReverse() != nullptr && !Settings::DecoupleEntrances) {
exit.GetReplacement()->GetReverse()->AddToPool();
}
}

View File

@ -116,6 +116,12 @@ Text childAltarText;
Text adultAltarText;
Text ganonText;
Text ganonHintText;
Text warpMinuetText;
Text warpBoleroText;
Text warpSerenadeText;
Text warpRequiemText;
Text warpNocturneText;
Text warpPreludeText;
Text& GetChildAltarText() {
return childAltarText;
@ -133,6 +139,30 @@ Text& GetGanonHintText() {
return ganonHintText;
}
Text& GetWarpMinuetText() {
return warpMinuetText;
}
Text& GetWarpBoleroText() {
return warpBoleroText;
}
Text& GetWarpSerenadeText() {
return warpSerenadeText;
}
Text& GetWarpRequiemText() {
return warpRequiemText;
}
Text& GetWarpNocturneText() {
return warpNocturneText;
}
Text& GetWarpPreludeText() {
return warpPreludeText;
}
static Area* GetHintRegion(const uint32_t area) {
std::vector<uint32_t> alreadyChecked = {};
@ -707,10 +737,49 @@ void CreateMerchantsHints() {
CreateMessageFromTextObject(0x6078, 0, 2, 3, AddColorsAndFormat(carpetSalesmanTextTwo, {QM_RED, QM_YELLOW, QM_RED}));
}
void CreateWarpSongTexts() {
auto warpSongEntrances = GetShuffleableEntrances(EntranceType::WarpSong, false);
for (auto entrance : warpSongEntrances) {
Text resolvedHint;
// Start with entrance location text
auto region = entrance->GetConnectedRegion()->regionName;
resolvedHint = Text{"","",""} + region;
auto destination = entrance->GetConnectedRegion()->GetHint().GetText();
// Prefer hint location when available
if (destination.GetEnglish() != "No Hint") {
resolvedHint = destination;
}
switch (entrance->GetIndex()) {
case 0x0600: // minuet
warpMinuetText = resolvedHint;
break;
case 0x04F6: // bolero
warpBoleroText = resolvedHint;
break;
case 0x0604: // serenade
warpSerenadeText = resolvedHint;
break;
case 0x01F1: // requiem
warpRequiemText = resolvedHint;
break;
case 0x0568: // nocturne
warpNocturneText = resolvedHint;
break;
case 0x05F4: // prelude
warpPreludeText = resolvedHint;
break;
}
}
}
void CreateAllHints() {
CreateGanonText();
CreateAltarText();
CreateWarpSongTexts();
SPDLOG_DEBUG("\nNOW CREATING HINTS\n");
const HintSetting& hintSetting = hintSettingTable[Settings::HintDistribution.Value<uint8_t>()];

View File

@ -225,3 +225,10 @@ Text& GetChildAltarText();
Text& GetAdultAltarText();
Text& GetGanonText();
Text& GetGanonHintText();
Text& GetWarpMinuetText();
Text& GetWarpBoleroText();
Text& GetWarpSerenadeText();
Text& GetWarpRequiemText();
Text& GetWarpNocturneText();
Text& GetWarpPreludeText();

View File

@ -2,7 +2,10 @@
#include <cstdint>
using AreaKey = uint32_t;
using HintKey = uint32_t;
using ItemKey = uint32_t;
using LocationKey = uint32_t;
using AreaKey = uint32_t;
typedef enum {
NONE,
@ -1082,6 +1085,14 @@ typedef enum {
//AREAS
ROOT,
ROOT_EXITS,
CHILD_SPAWN,
ADULT_SPAWN,
MINUET_OF_FOREST_WARP,
BOLERO_OF_FIRE_WARP,
SERENADE_OF_WATER_WARP,
REQUIEM_OF_SPIRIT_WARP,
NOCTURNE_OF_SHADOW_WARP,
PRELUDE_OF_LIGHT_WARP,
KOKIRI_FOREST,
KF_LINKS_HOUSE,
KF_MIDOS_HOUSE,
@ -1135,6 +1146,7 @@ typedef enum {
HAUNTED_WASTELAND,
WASTELAND_NEAR_COLOSSUS,
DESERT_COLOSSUS,
DESERT_COLOSSUS_FROM_SPIRIT_ENTRYWAY,
COLOSSUS_GREAT_FAIRY_FOUNTAIN,
COLOSSUS_GROTTO,
MARKET_ENTRANCE,
@ -1173,6 +1185,7 @@ typedef enum {
KAK_POTION_SHOP_FRONT,
KAK_POTION_SHOP_BACK,
KAK_ROOFTOP,
KAK_IMPAS_ROOFTOP,
KAK_BEHIND_GATE,
KAK_BACKYARD,
KAK_ODD_POTION_BUILDING,

View File

@ -264,25 +264,66 @@ void AreaTable_Init() {
areaTable[ROOT_EXITS] = Area("Root Exits", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(KF_LINKS_HOUSE, {[]{return IsChild;}}),
Entrance(TEMPLE_OF_TIME, {[]{return (CanPlay(PreludeOfLight) && CanLeaveForest) || IsAdult;},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && PreludeOfLight && CanLeaveForest;}}),
Entrance(SACRED_FOREST_MEADOW, {[]{return CanPlay(MinuetOfForest);},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
Entrance(CHILD_SPAWN, {[]{return IsChild;}}),
Entrance(ADULT_SPAWN, {[]{return IsAdult;}}),
Entrance(MINUET_OF_FOREST_WARP, {[]{return CanPlay(MinuetOfForest);},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && MinuetOfForest;}}),
Entrance(DMC_CENTRAL_LOCAL, {[]{return CanPlay(BoleroOfFire) && CanLeaveForest;},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
Entrance(BOLERO_OF_FIRE_WARP, {[]{return CanPlay(BoleroOfFire) && CanLeaveForest;},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && BoleroOfFire && CanLeaveForest;}}),
Entrance(LAKE_HYLIA, {[]{return CanPlay(SerenadeOfWater) && CanLeaveForest;},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
Entrance(SERENADE_OF_WATER_WARP, {[]{return CanPlay(SerenadeOfWater) && CanLeaveForest;},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && SerenadeOfWater && CanLeaveForest;}}),
Entrance(GRAVEYARD_WARP_PAD_REGION, {[]{return CanPlay(NocturneOfShadow) && CanLeaveForest;},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
Entrance(NOCTURNE_OF_SHADOW_WARP, {[]{return CanPlay(NocturneOfShadow) && CanLeaveForest;},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && NocturneOfShadow && CanLeaveForest;}}),
Entrance(DESERT_COLOSSUS, {[]{return CanPlay(RequiemOfSpirit) && CanLeaveForest;},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
Entrance(REQUIEM_OF_SPIRIT_WARP, {[]{return CanPlay(RequiemOfSpirit) && CanLeaveForest;},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && RequiemOfSpirit && CanLeaveForest;}}),
Entrance(PRELUDE_OF_LIGHT_WARP, {[]{return CanPlay(PreludeOfLight) && CanLeaveForest;},
/*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) ||
((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && PreludeOfLight && CanLeaveForest;}}),
});
areaTable[CHILD_SPAWN] = Area("Child Spawn", "", TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(KF_LINKS_HOUSE, {[]{return true;}}),
});
areaTable[ADULT_SPAWN] = Area("Adult Spawn", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(TEMPLE_OF_TIME, {[]{return true;}}),
});
areaTable[MINUET_OF_FOREST_WARP] = Area("Minuet of Forest Warp", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(SACRED_FOREST_MEADOW, {[]{return true;}}),
});
areaTable[BOLERO_OF_FIRE_WARP] = Area("Bolero of Fire Warp", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(DMC_CENTRAL_LOCAL, {[]{return true;}}),
});
areaTable[SERENADE_OF_WATER_WARP] = Area("Serenade of Water Warp", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(LAKE_HYLIA, {[]{return true;}}),
});
areaTable[REQUIEM_OF_SPIRIT_WARP] = Area("Requiem of Spirit Warp", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(DESERT_COLOSSUS, {[]{return true;}}),
});
areaTable[NOCTURNE_OF_SHADOW_WARP] = Area("Nocturne of Shadow Warp", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(GRAVEYARD_WARP_PAD_REGION, {[]{return true;}}),
});
areaTable[PRELUDE_OF_LIGHT_WARP] = Area("Prelude of Light Warp", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(TEMPLE_OF_TIME, {[]{return true;}}),
});
// Overworld
@ -330,10 +371,19 @@ void AreaTable_Init() {
namespace Areas {
static std::array<const uint32_t, 414> allAreas = {
static std::array<const uint32_t, 424> allAreas = {
ROOT,
ROOT_EXITS,
CHILD_SPAWN,
ADULT_SPAWN,
MINUET_OF_FOREST_WARP,
BOLERO_OF_FIRE_WARP,
SERENADE_OF_WATER_WARP,
REQUIEM_OF_SPIRIT_WARP,
NOCTURNE_OF_SHADOW_WARP,
PRELUDE_OF_LIGHT_WARP,
KOKIRI_FOREST,
KF_LINKS_HOUSE,
KF_MIDOS_HOUSE,
@ -373,6 +423,7 @@ namespace Areas {
KAK_POTION_SHOP_FRONT,
KAK_POTION_SHOP_BACK,
KAK_ROOFTOP,
KAK_IMPAS_ROOFTOP,
KAK_BEHIND_GATE,
KAK_BACKYARD,
KAK_ODD_POTION_BUILDING,
@ -473,6 +524,7 @@ namespace Areas {
HAUNTED_WASTELAND,
WASTELAND_NEAR_COLOSSUS,
DESERT_COLOSSUS,
DESERT_COLOSSUS_FROM_SPIRIT_ENTRYWAY,
COLOSSUS_GREAT_FAIRY_FOUNTAIN,
COLOSSUS_GROTTO,
SPIRIT_TEMPLE_ENTRYWAY,

View File

@ -50,7 +50,7 @@ void AreaTable_Init_CastleTown() {
Entrance(TEMPLE_OF_TIME, {[]{return true;}}),
});
areaTable[TEMPLE_OF_TIME] = Area("Temple of Time", "", TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[TEMPLE_OF_TIME] = Area("Temple of Time", "Temple of Time", TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(TOT_LIGHT_ARROWS_CUTSCENE, {[]{return IsAdult && CanTriggerLACS;}}),
}, {
@ -61,7 +61,7 @@ void AreaTable_Init_CastleTown() {
((Bugs || Fish) && Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)));}}),
});
areaTable[TOT_BEYOND_DOOR_OF_TIME] = Area("Beyond Door of Time", "", TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, {
areaTable[TOT_BEYOND_DOOR_OF_TIME] = Area("Beyond Door of Time", "Beyond Door of Time", TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, {
//Events
//EventAccess(&TimeTravel, {[]{return true;}}),
}, {
@ -111,7 +111,7 @@ void AreaTable_Init_CastleTown() {
Entrance(HYRULE_CASTLE_GROUNDS, {[]{return true;}}),
});
areaTable[HC_GREAT_FAIRY_FOUNTAIN] = Area("HC Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[HC_GREAT_FAIRY_FOUNTAIN] = Area("HC Great Fairy Fountain", "HC Great Fairy Fountain", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(HC_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}),
@ -120,7 +120,7 @@ void AreaTable_Init_CastleTown() {
Entrance(CASTLE_GROUNDS, {[]{return true;}}),
});
areaTable[HC_STORMS_GROTTO] = Area("HC Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[HC_STORMS_GROTTO] = Area("HC Storms Grotto", "HC Storms Grotto", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&NutPot, {[]{return NutPot || CanBlastOrSmash;}}),
EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || (CanBlastOrSmash && CanSummonGossipFairy);}}),
@ -146,7 +146,7 @@ void AreaTable_Init_CastleTown() {
/*Glitched*/[]{return (HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::ADVANCED) || (HoverBoots && CanShield && Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::EXPERT)) || (HoverBoots && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::ADVANCED));}}),
});
areaTable[OGC_GREAT_FAIRY_FOUNTAIN] = Area("OGC Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[OGC_GREAT_FAIRY_FOUNTAIN] = Area("OGC Great Fairy Fountain", "OGC Great Fairy Fountain", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(OGC_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}),
@ -155,7 +155,7 @@ void AreaTable_Init_CastleTown() {
Entrance(CASTLE_GROUNDS, {[]{return true;}}),
});
areaTable[MARKET_GUARD_HOUSE] = Area("Market Guard House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[MARKET_GUARD_HOUSE] = Area("Market Guard House", "Market Guard House", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(MARKET_10_BIG_POES, {[]{return IsAdult && BigPoeKill;}}),
LocationAccess(MARKET_GS_GUARD_HOUSE, {[]{return IsChild;}}),
@ -164,7 +164,7 @@ void AreaTable_Init_CastleTown() {
Entrance(MARKET_ENTRANCE, {[]{return true;}}),
});
areaTable[MARKET_BAZAAR] = Area("Market Bazaar", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[MARKET_BAZAAR] = Area("Market Bazaar", "Market Bazaar", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(MARKET_BAZAAR_ITEM_1, {[]{return true;}}),
LocationAccess(MARKET_BAZAAR_ITEM_2, {[]{return true;}}),
@ -179,7 +179,7 @@ void AreaTable_Init_CastleTown() {
Entrance(THE_MARKET, {[]{return true;}}),
});
areaTable[MARKET_MASK_SHOP] = Area("Market Mask Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[MARKET_MASK_SHOP] = Area("Market Mask Shop", "Market Mask Shop", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&SkullMask, {[]{return SkullMask || (ZeldasLetter && (CompleteMaskQuest || ChildCanAccess(KAKARIKO_VILLAGE)));}}),
EventAccess(&MaskOfTruth, {[]{return MaskOfTruth || (SkullMask && (CompleteMaskQuest || (ChildCanAccess(THE_LOST_WOODS) && CanPlay(SariasSong) && AreaTable(THE_GRAVEYARD)->childDay && ChildCanAccess(HYRULE_FIELD) && HasAllStones)));}}),
@ -188,7 +188,7 @@ void AreaTable_Init_CastleTown() {
Entrance(THE_MARKET, {[]{return true;}}),
});
areaTable[MARKET_SHOOTING_GALLERY] = Area("Market Shooting Gallery", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[MARKET_SHOOTING_GALLERY] = Area("Market Shooting Gallery", "Market Shooting Gallery", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(MARKET_SHOOTING_GALLERY_REWARD, {[]{return IsChild;}}),
}, {
@ -196,7 +196,7 @@ void AreaTable_Init_CastleTown() {
Entrance(THE_MARKET, {[]{return true;}}),
});
areaTable[MARKET_BOMBCHU_BOWLING] = Area("Market Bombchu Bowling", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[MARKET_BOMBCHU_BOWLING] = Area("Market Bombchu Bowling", "Market Bombchu Bowling", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, {[]{return CanPlayBowling;}}),
LocationAccess(MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, {[]{return CanPlayBowling;}}),
@ -206,7 +206,7 @@ void AreaTable_Init_CastleTown() {
Entrance(THE_MARKET, {[]{return true;}}),
});
areaTable[MARKET_POTION_SHOP] = Area("Market Potion Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[MARKET_POTION_SHOP] = Area("Market Potion Shop", "Market Potion Shop", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(MARKET_POTION_SHOP_ITEM_1, {[]{return true;}}),
LocationAccess(MARKET_POTION_SHOP_ITEM_2, {[]{return true;}}),
@ -221,7 +221,7 @@ void AreaTable_Init_CastleTown() {
Entrance(THE_MARKET, {[]{return true;}}),
});
areaTable[MARKET_TREASURE_CHEST_GAME] = Area("Market Treasure Chest Game", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[MARKET_TREASURE_CHEST_GAME] = Area("Market Treasure Chest Game", "Market Treasure Chest Game", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(MARKET_TREASURE_CHEST_GAME_REWARD, {[]{return (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 6)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1));},
/*Glitched*/[]{return !ShuffleChestMinigame && (CanUse(FARORES_WIND) && (HasBottle || WeirdEgg) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE));}}),
@ -235,7 +235,7 @@ void AreaTable_Init_CastleTown() {
Entrance(THE_MARKET, {[]{return true;}}),
});
areaTable[MARKET_BOMBCHU_SHOP] = Area("Market Bombchu Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[MARKET_BOMBCHU_SHOP] = Area("Market Bombchu Shop", "Market Bombchu Shop", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_1, {[]{return true;}}),
LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_2, {[]{return true;}}),
@ -250,7 +250,7 @@ void AreaTable_Init_CastleTown() {
Entrance(MARKET_BACK_ALLEY, {[]{return true;}}),
});
areaTable[MARKET_DOG_LADY_HOUSE] = Area("Market Dog Lady House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[MARKET_DOG_LADY_HOUSE] = Area("Market Dog Lady House", "Market Dog Lady House", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(MARKET_LOST_DOG, {[]{return IsChild && AtNight;}}),
}, {
@ -258,7 +258,7 @@ void AreaTable_Init_CastleTown() {
Entrance(MARKET_BACK_ALLEY, {[]{return true;}}),
});
areaTable[MARKET_MAN_IN_GREEN_HOUSE] = Area("Market Man in Green House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
areaTable[MARKET_MAN_IN_GREEN_HOUSE] = Area("Market Man in Green House", "Market Man in Green House", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(MARKET_BACK_ALLEY, {[]{return true;}}),
});

View File

@ -55,10 +55,10 @@ void AreaTable_Init_DeathMountain() {
areaTable[DMT_OWL_FLIGHT] = Area("DMT Owl Flight", "Death Mountain", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(KAK_IMPAS_LEDGE, {[]{return true;}}),
Entrance(KAK_IMPAS_ROOFTOP, {[]{return true;}}),
});
areaTable[DMT_COW_GROTTO] = Area("DMT Cow Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[DMT_COW_GROTTO] = Area("DMT Cow Grotto", "DMT Cow Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(DMT_COW_GROTTO_COW, {[]{return CanPlay(EponasSong);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) ||
@ -69,7 +69,7 @@ void AreaTable_Init_DeathMountain() {
});
areaTable[DMT_STORMS_GROTTO] = Area("DMT Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
areaTable[DMT_STORMS_GROTTO] = Area("DMT Storms Grotto", "DMT Storms Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
//Locations
LocationAccess(DMT_STORMS_GROTTO_CHEST, {[]{return true;}}),
LocationAccess(DMT_STORMS_GROTTO_GOSSIP_STONE, {[]{return true;}}),
@ -78,7 +78,7 @@ void AreaTable_Init_DeathMountain() {
Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}),
});
areaTable[DMT_GREAT_FAIRY_FOUNTAIN] = Area("DMT Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[DMT_GREAT_FAIRY_FOUNTAIN] = Area("DMT Great Fairy Fountain", "DMT Great Fairy Fountain", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(DMT_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) ||
@ -156,7 +156,7 @@ void AreaTable_Init_DeathMountain() {
Entrance(GORON_CITY, {[]{return EffectiveHealth > 2 || CanUse(GORON_TUNIC) || CanUse(NAYRUS_LOVE) || ((IsChild || CanPlay(SongOfTime)) && CanUse(LONGSHOT));}}),
});
areaTable[GC_SHOP] = Area("GC Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[GC_SHOP] = Area("GC Shop", "GC Shop", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(GC_SHOP_ITEM_1, {[]{return true;}}),
LocationAccess(GC_SHOP_ITEM_2, {[]{return true;}}),
@ -171,7 +171,7 @@ void AreaTable_Init_DeathMountain() {
Entrance(GORON_CITY, {[]{return true;}}),
});
areaTable[GC_GROTTO] = Area("GC Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[GC_GROTTO] = Area("GC Grotto", "GC Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(GC_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}),
LocationAccess(GC_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}),
@ -262,7 +262,7 @@ void AreaTable_Init_DeathMountain() {
/*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) && FireTimer >= 48;}}),
});
areaTable[DMC_GREAT_FAIRY_FOUNTAIN] = Area("DMC Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[DMC_GREAT_FAIRY_FOUNTAIN] = Area("DMC Great Fairy Fountain", "DMC Great Fairy Fountain", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(DMC_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanTakeDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) ||
@ -272,7 +272,7 @@ void AreaTable_Init_DeathMountain() {
Entrance(DMC_LOWER_LOCAL, {[]{return true;}}),
});
areaTable[DMC_UPPER_GROTTO] = Area("DMC Upper Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
areaTable[DMC_UPPER_GROTTO] = Area("DMC Upper Grotto", "DMC Upper Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
//Locations
LocationAccess(DMC_UPPER_GROTTO_CHEST, {[]{return true;}}),
LocationAccess(DMC_UPPER_GROTTO_GOSSIP_STONE, {[]{return true;}}),
@ -281,7 +281,7 @@ void AreaTable_Init_DeathMountain() {
Entrance(DMC_UPPER_LOCAL, {[]{return true;}}),
});
areaTable[DMC_HAMMER_GROTTO] = Area("DMC Hammer Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[DMC_HAMMER_GROTTO] = Area("DMC Hammer Grotto", "DMC Hammer Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(DMC_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}),
LocationAccess(DMC_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}),

View File

@ -84,17 +84,17 @@ void AreaTable_Init_GerudoValley() {
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsAdult && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}),
});
areaTable[GV_CARPENTER_TENT] = Area("GV Carpenter Tent", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
areaTable[GV_CARPENTER_TENT] = Area("GV Carpenter Tent", "GV Carpenter Tent", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(GV_FORTRESS_SIDE, {[]{return true;}}),
});
areaTable[GV_OCTOROK_GROTTO] = Area("GV Octorok Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
areaTable[GV_OCTOROK_GROTTO] = Area("GV Octorok Grotto", "GV Octorok Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(GV_GROTTO_LEDGE, {[]{return true;}}),
});
areaTable[GV_STORMS_GROTTO] = Area("GV Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[GV_STORMS_GROTTO] = Area("GV Storms Grotto", "GV Storms Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(GV_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}),
LocationAccess(GV_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}),
@ -148,7 +148,7 @@ void AreaTable_Init_GerudoValley() {
Entrance(WASTELAND_NEAR_FORTRESS, {[]{return true;}}),
});
areaTable[GF_STORMS_GROTTO] = Area("GF Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[GF_STORMS_GROTTO] = Area("GF Storms Grotto", "GF Storms Grotto", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&FreeFairies, {[]{return true;}}),
}, {}, {
@ -200,7 +200,6 @@ void AreaTable_Init_GerudoValley() {
LocationAccess(COLOSSUS_FREESTANDING_POH, {[]{return IsAdult && CanPlantBean(DESERT_COLOSSUS);},
/*Glitched*/[]{return (HoverBoots && CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED)) || (((IsChild && (ChildCanAccess(SPIRIT_TEMPLE_OUTDOOR_HANDS) || ChildCanAccess(SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND) || ChildCanAccess(SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND))) ||
(IsAdult && (AdultCanAccess(SPIRIT_TEMPLE_OUTDOOR_HANDS) || AdultCanAccess(SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND) || AdultCanAccess(SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND)))) && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::ADVANCED) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE)));}}),
LocationAccess(SHEIK_AT_COLOSSUS, {[]{return true;}}),
LocationAccess(COLOSSUS_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}),
LocationAccess(COLOSSUS_GS_TREE, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}),
LocationAccess(COLOSSUS_GS_HILL, {[]{return IsAdult && AtNight && (CanPlantBean(DESERT_COLOSSUS) || CanUse(LONGSHOT) || (LogicColossusGS && CanUse(HOOKSHOT))) && CanGetNightTimeGS;},
@ -214,7 +213,15 @@ void AreaTable_Init_GerudoValley() {
Entrance(COLOSSUS_GROTTO, {[]{return CanUse(SILVER_GAUNTLETS);}}),
});
areaTable[COLOSSUS_GREAT_FAIRY_FOUNTAIN] = Area("Colossus Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[DESERT_COLOSSUS_FROM_SPIRIT_ENTRYWAY] = Area("Desert Colossus From Spirit Entryway", "Desert Colossus", DESERT_COLOSSUS, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(SHEIK_AT_COLOSSUS, {[]{return true;}}),
}, {
//Exist
Entrance(DESERT_COLOSSUS, {[]{return true;}}),
});
areaTable[COLOSSUS_GREAT_FAIRY_FOUNTAIN] = Area("Colossus Great Fairy Fountain", "Colossus Great Fairy Fountain", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(COLOSSUS_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}),
@ -223,7 +230,7 @@ void AreaTable_Init_GerudoValley() {
Entrance(DESERT_COLOSSUS, {[]{return true;}}),
});
areaTable[COLOSSUS_GROTTO] = Area("Colossus Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[COLOSSUS_GROTTO] = Area("Colossus Grotto", "Colossus Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(COLOSSUS_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}),
LocationAccess(COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}),

View File

@ -39,7 +39,7 @@ void AreaTable_Init_HyruleField() {
/*Glitched*/[]{return Sticks && IsChild && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}),
});
areaTable[HF_SOUTHEAST_GROTTO] = Area("HF Southeast Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
areaTable[HF_SOUTHEAST_GROTTO] = Area("HF Southeast Grotto", "HF Southeast Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
//Locations
LocationAccess(HF_SOUTHEAST_GROTTO_CHEST, {[]{return true;}}),
LocationAccess(HF_SOUTHEAST_GROTTO_GOSSIP_STONE, {[]{return true;}}),
@ -48,7 +48,7 @@ void AreaTable_Init_HyruleField() {
Entrance(HYRULE_FIELD, {[]{return true;}}),
});
areaTable[HF_OPEN_GROTTO] = Area("HF Open Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
areaTable[HF_OPEN_GROTTO] = Area("HF Open Grotto", "HF Open Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
//Locations
LocationAccess(HF_OPEN_GROTTO_CHEST, {[]{return true;}}),
LocationAccess(HF_OPEN_GROTTO_GOSSIP_STONE, {[]{return true;}}),
@ -57,7 +57,7 @@ void AreaTable_Init_HyruleField() {
Entrance(HYRULE_FIELD, {[]{return true;}}),
});
areaTable[HF_INSIDE_FENCE_GROTTO] = Area("HF Inside Fence Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[HF_INSIDE_FENCE_GROTTO] = Area("HF Inside Fence Grotto", "HF Inside Fence Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(HF_DEKU_SCRUB_GROTTO, {[]{return CanStunDeku;}}),
}, {
@ -65,7 +65,7 @@ void AreaTable_Init_HyruleField() {
Entrance(HYRULE_FIELD, {[]{return true;}}),
});
areaTable[HF_COW_GROTTO] = Area("HF Cow Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
areaTable[HF_COW_GROTTO] = Area("HF Cow Grotto", "HF Cow Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
//Locations
LocationAccess(HF_GS_COW_GROTTO, {[]{return HasFireSource && HookshotOrBoomerang;},
/*Glitched*/[]{return (CanUse(STICKS) && Bombs && CanSurviveDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) && HookshotOrBoomerang;}}),
@ -79,7 +79,7 @@ void AreaTable_Init_HyruleField() {
Entrance(HYRULE_FIELD, {[]{return true;}}),
});
areaTable[HF_NEAR_MARKET_GROTTO] = Area("HF Near Market Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
areaTable[HF_NEAR_MARKET_GROTTO] = Area("HF Near Market Grotto", "HF Near Market Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
//Locations
LocationAccess(HF_NEAR_MARKET_GROTTO_CHEST, {[]{return true;}}),
LocationAccess(HF_NEAR_MARKET_GROTTO_GOSSIP_STONE, {[]{return true;}}),
@ -88,7 +88,7 @@ void AreaTable_Init_HyruleField() {
Entrance(HYRULE_FIELD, {[]{return true;}}),
});
areaTable[HF_FAIRY_GROTTO] = Area("HF Fairy Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[HF_FAIRY_GROTTO] = Area("HF Fairy Grotto", "HF Fairy Grotto", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&FreeFairies, {[]{return true;}}),
}, {}, {
@ -96,7 +96,7 @@ void AreaTable_Init_HyruleField() {
Entrance(HYRULE_FIELD, {[]{return true;}}),
});
areaTable[HF_NEAR_KAK_GROTTO] = Area("HF Near Kak Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[HF_NEAR_KAK_GROTTO] = Area("HF Near Kak Grotto", "HF Near Kak Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(HF_GS_NEAR_KAK_GROTTO, {[]{return HookshotOrBoomerang;}}),
}, {
@ -104,7 +104,7 @@ void AreaTable_Init_HyruleField() {
Entrance(HYRULE_FIELD, {[]{return true;}}),
});
areaTable[HF_TEKTITE_GROTTO] = Area("HF Tektite Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[HF_TEKTITE_GROTTO] = Area("HF Tektite Grotto", "HF Tektite Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(HF_TEKTITE_GROTTO_FREESTANDING_POH, {[]{return ProgressiveScale >= 2 || CanUse(IRON_BOOTS);}}),
}, {
@ -163,7 +163,7 @@ void AreaTable_Init_HyruleField() {
Entrance(HYRULE_FIELD, {[]{return true;}}),
});
areaTable[LH_LAB] = Area("LH Lab", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[LH_LAB] = Area("LH Lab", "LH Lab", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&EyedropsAccess, {[]{return EyedropsAccess || (IsAdult && (EyeballFrogAccess || (EyeballFrog && DisableTradeRevert)));}}),
}, {
@ -182,7 +182,7 @@ void AreaTable_Init_HyruleField() {
Entrance(LAKE_HYLIA, {[]{return true;}}),
});
areaTable[LH_FISHING_HOLE] = Area("LH Fishing Hole", "", NONE, DAY_NIGHT_CYCLE, {}, {
areaTable[LH_FISHING_HOLE] = Area("LH Fishing Hole", "LH Fishing Hole", NONE, DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(LH_CHILD_FISHING, {[]{return IsChild;}}),
LocationAccess(LH_ADULT_FISHING, {[]{return IsAdult;}}),
@ -191,7 +191,7 @@ void AreaTable_Init_HyruleField() {
Entrance(LH_FISHING_ISLAND, {[]{return true;}}),
});
areaTable[LH_GROTTO] = Area("LH Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[LH_GROTTO] = Area("LH Grotto", "LH Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(LH_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}),
LocationAccess(LH_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}),
@ -224,7 +224,7 @@ void AreaTable_Init_HyruleField() {
Entrance(LLR_GROTTO, {[]{return IsChild;}}),
});
areaTable[LLR_TALONS_HOUSE] = Area("LLR Talons House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[LLR_TALONS_HOUSE] = Area("LLR Talons House", "LLR Talons House", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(LLR_TALONS_CHICKENS, {[]{return IsChild && AtDay && ZeldasLetter;}}),
}, {
@ -232,7 +232,7 @@ void AreaTable_Init_HyruleField() {
Entrance(LON_LON_RANCH, {[]{return true;}}),
});
areaTable[LLR_STABLES] = Area("LLR Stables", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[LLR_STABLES] = Area("LLR Stables", "LLR Stables", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(LLR_STABLES_LEFT_COW, {[]{return CanPlay(EponasSong);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE))) && EponasSong;}}),
@ -243,7 +243,7 @@ void AreaTable_Init_HyruleField() {
Entrance(LON_LON_RANCH, {[]{return true;}}),
});
areaTable[LLR_TOWER] = Area("LLR Tower", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[LLR_TOWER] = Area("LLR Tower", "LLR Tower", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(LLR_FREESTANDING_POH, {[]{return IsChild;}}),
LocationAccess(LLR_TOWER_LEFT_COW, {[]{return CanPlay(EponasSong);},
@ -255,7 +255,7 @@ void AreaTable_Init_HyruleField() {
Entrance(LON_LON_RANCH, {[]{return true;}}),
});
areaTable[LLR_GROTTO] = Area("LLR Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[LLR_GROTTO] = Area("LLR Grotto", "LLR Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(LLR_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}),
LocationAccess(LLR_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}),

View File

@ -23,8 +23,6 @@ void AreaTable_Init_Kakariko() {
LocationAccess(KAK_GS_TREE, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}),
LocationAccess(KAK_GS_WATCHTOWER, {[]{return IsChild && (Slingshot || HasBombchus || CanUse(BOW) || CanUse(LONGSHOT)) && AtNight && CanGetNightTimeGS;},
/*Glitched*/[]{return IsChild && AtNight && CanGetNightTimeGS && (CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE) || (Sticks && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE)));}}),
LocationAccess(KAK_GS_ABOVE_IMPAS_HOUSE, {[]{return IsAdult && CanUse(HOOKSHOT) && AtNight && CanGetNightTimeGS;},
/*Glitched*/[]{return IsAdult && AtNight && CanGetNightTimeGS && ((HoverBoots && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE));}}),
}, {
//Exits
Entrance(HYRULE_FIELD, {[]{return true;}}),
@ -45,6 +43,8 @@ void AreaTable_Init_Kakariko() {
/*Glitched*/[]{return IsAdult && ((HoverBoots && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE));}}),
Entrance(KAK_ROOFTOP, {[]{return CanUse(HOOKSHOT) || (LogicManOnRoof && (IsAdult || AtDay || Slingshot || HasBombchus || CanUse(BOW) || CanUse(LONGSHOT)));},
/*Glitched*/[]{return LogicManOnRoof && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}),
Entrance(KAK_IMPAS_ROOFTOP, {[]{return CanUse(HOOKSHOT);},
/*Glitched*/[]{return (HoverBoots && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE);}}),
Entrance(THE_GRAVEYARD, {[]{return true;}}),
Entrance(KAK_BEHIND_GATE, {[]{return IsAdult || (KakarikoVillageGateOpen);},
/*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}),
@ -56,6 +56,15 @@ void AreaTable_Init_Kakariko() {
Entrance(KAKARIKO_VILLAGE, {[]{return true;}}),
});
areaTable[KAK_IMPAS_ROOFTOP] = Area("Kak Impas Rooftop", "Kakariko Village", KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KAK_GS_ABOVE_IMPAS_HOUSE, {[]{return IsAdult && AtNight && CanGetNightTimeGS && (CanJumpslash || CanUseProjectile);}}),
}, {
//Exits
Entrance(KAK_IMPAS_LEDGE, {[]{return true;}}),
Entrance(KAKARIKO_VILLAGE, {[]{return true;}}),
});
areaTable[KAK_ROOFTOP] = Area("Kak Rooftop", "Kakariko Village", KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KAK_MAN_ON_ROOF, {[]{return true;}}),
@ -73,7 +82,7 @@ void AreaTable_Init_Kakariko() {
/*Glitched*/[]{return CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE);}}),
});
areaTable[KAK_CARPENTER_BOSS_HOUSE] = Area("Kak Carpenter Boss House", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[KAK_CARPENTER_BOSS_HOUSE] = Area("Kak Carpenter Boss House", "Kak Carpenter Boss House", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&WakeUpAdultTalon, {[]{return WakeUpAdultTalon || (IsAdult && PocketEgg);}}),
}, {}, {
@ -81,7 +90,7 @@ void AreaTable_Init_Kakariko() {
Entrance(KAKARIKO_VILLAGE, {[]{return true;}}),
});
areaTable[KAK_HOUSE_OF_SKULLTULA] = Area("Kak House of Skulltula", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[KAK_HOUSE_OF_SKULLTULA] = Area("Kak House of Skulltula", "Kak House of Skulltula", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KAK_10_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 10;}}),
LocationAccess(KAK_20_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 20;}}),
@ -93,13 +102,13 @@ void AreaTable_Init_Kakariko() {
Entrance(KAKARIKO_VILLAGE, {[]{return true;}}),
});
areaTable[KAK_IMPAS_HOUSE] = Area("Kak Impas House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
areaTable[KAK_IMPAS_HOUSE] = Area("Kak Impas House", "Kak Impas House", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(KAK_IMPAS_HOUSE_NEAR_COW, {[]{return true;}}),
Entrance(KAKARIKO_VILLAGE, {[]{return true;}}),
});
areaTable[KAK_IMPAS_HOUSE_BACK] = Area("Kak Impas House Back", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[KAK_IMPAS_HOUSE_BACK] = Area("Kak Impas House Back", "Kak Impas House", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KAK_IMPAS_HOUSE_FREESTANDING_POH, {[]{return true;}}),
}, {
@ -108,13 +117,13 @@ void AreaTable_Init_Kakariko() {
Entrance(KAK_IMPAS_HOUSE_NEAR_COW, {[]{return true;}}),
});
areaTable[KAK_IMPAS_HOUSE_NEAR_COW] = Area("Kak Impas House Near Cow", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[KAK_IMPAS_HOUSE_NEAR_COW] = Area("Kak Impas House Near Cow", "Kak Impas House", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KAK_IMPAS_HOUSE_COW, {[]{return CanPlay(EponasSong);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED))) && EponasSong;}}),
}, {});
areaTable[KAK_WINDMILL] = Area("Kak Windmill", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[KAK_WINDMILL] = Area("Kak Windmill", "Windmill and Dampes Grave", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&DrainWell, {[]{return DrainWell || (IsChild && CanPlay(SongOfStorms));},
/*Glitched*/[]{return IsChild && SongOfStorms && (CanDoGlitch(GlitchType::WindmillBombOI, GlitchDifficulty::ADVANCED) || ((Fish || Bugs) && CanShield && ((Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2))) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) &&
@ -131,7 +140,7 @@ void AreaTable_Init_Kakariko() {
Entrance(KAKARIKO_VILLAGE, {[]{return true;}}),
});
areaTable[KAK_BAZAAR] = Area("Kak Bazaar", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[KAK_BAZAAR] = Area("Kak Bazaar", "Kak Bazaar", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KAK_BAZAAR_ITEM_1, {[]{return true;}}),
LocationAccess(KAK_BAZAAR_ITEM_2, {[]{return true;}}),
@ -146,7 +155,7 @@ void AreaTable_Init_Kakariko() {
Entrance(KAKARIKO_VILLAGE, {[]{return true;}}),
});
areaTable[KAK_SHOOTING_GALLERY] = Area("Kak Shooting Gallery", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[KAK_SHOOTING_GALLERY] = Area("Kak Shooting Gallery", "Kak Shooting Gallery", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KAK_SHOOTING_GALLERY_REWARD, {[]{return IsAdult && Bow;}}),
}, {
@ -154,7 +163,7 @@ void AreaTable_Init_Kakariko() {
Entrance(KAKARIKO_VILLAGE, {[]{return true;}}),
});
areaTable[KAK_POTION_SHOP_FRONT] = Area("Kak Potion Shop Front", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[KAK_POTION_SHOP_FRONT] = Area("Kak Potion Shop Front", "Kak Potion Shop", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KAK_POTION_SHOP_ITEM_1, {[]{return IsAdult;}}),
LocationAccess(KAK_POTION_SHOP_ITEM_2, {[]{return IsAdult;}}),
@ -170,13 +179,13 @@ void AreaTable_Init_Kakariko() {
Entrance(KAK_POTION_SHOP_BACK, {[]{return IsAdult;}}),
});
areaTable[KAK_POTION_SHOP_BACK] = Area("Kak Potion Shop Back", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
areaTable[KAK_POTION_SHOP_BACK] = Area("Kak Potion Shop Back", "Kak Potion Shop", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(KAK_BACKYARD, {[]{return IsAdult;}}),
Entrance(KAK_POTION_SHOP_FRONT, {[]{return true;}}),
});
areaTable[KAK_ODD_POTION_BUILDING] = Area("Kak Granny's Potion Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[KAK_ODD_POTION_BUILDING] = Area("Kak Granny's Potion Shop", "Kak Granny's Potion Shop", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&OddPoulticeAccess, {[]{return OddPoulticeAccess || (IsAdult && (OddMushroomAccess || (OddMushroom && DisableTradeRevert)));}}),
}, {
@ -186,7 +195,7 @@ void AreaTable_Init_Kakariko() {
Entrance(KAK_BACKYARD, {[]{return true;}}),
});
areaTable[KAK_REDEAD_GROTTO] = Area("Kak Redead Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[KAK_REDEAD_GROTTO] = Area("Kak Redead Grotto", "Kak Redead Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KAK_REDEAD_GROTTO_CHEST, {[]{return IsAdult || (Sticks || KokiriSword || CanUse(DINS_FIRE) || CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD));}}),
}, {
@ -194,7 +203,7 @@ void AreaTable_Init_Kakariko() {
Entrance(KAKARIKO_VILLAGE, {[]{return true;}}),
});
areaTable[KAK_OPEN_GROTTO] = Area("Kak Open Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
areaTable[KAK_OPEN_GROTTO] = Area("Kak Open Grotto", "Kak Open Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
//Locations
LocationAccess(KAK_OPEN_GROTTO_CHEST, {[]{return true;}}),
LocationAccess(KAK_OPEN_GROTTO_GOSSIP_STONE, {[]{return true;}}),
@ -230,7 +239,7 @@ void AreaTable_Init_Kakariko() {
/*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE);}}),
});
areaTable[GRAVEYARD_SHIELD_GRAVE] = Area("Graveyard Shield Grave", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[GRAVEYARD_SHIELD_GRAVE] = Area("Graveyard Shield Grave", "Graveyard Shield Grave", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(GRAVEYARD_SHIELD_GRAVE_CHEST, {[]{return true;}}),
//Free Fairies
@ -239,7 +248,7 @@ void AreaTable_Init_Kakariko() {
Entrance(THE_GRAVEYARD, {[]{return true;}}),
});
areaTable[GRAVEYARD_HEART_PIECE_GRAVE] = Area("Graveyard Heart Piece Grave", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[GRAVEYARD_HEART_PIECE_GRAVE] = Area("Graveyard Heart Piece Grave", "Graveyard Heart Piece Grave", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(GRAVEYARD_HEART_PIECE_GRAVE_CHEST, {[]{return CanPlay(SunsSong);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || ((Bugs || Fish) && CanShield && (Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2))) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SunsSong;}}),
@ -248,7 +257,7 @@ void AreaTable_Init_Kakariko() {
Entrance(THE_GRAVEYARD, {[]{return true;}}),
});
areaTable[GRAVEYARD_COMPOSERS_GRAVE] = Area("Graveyard Composers Grave", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[GRAVEYARD_COMPOSERS_GRAVE] = Area("Graveyard Composers Grave", "Graveyard Composers Grave", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(GRAVEYARD_COMPOSERS_GRAVE_CHEST, {[]{return HasFireSource;},
/*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE);}}),
@ -258,7 +267,7 @@ void AreaTable_Init_Kakariko() {
Entrance(THE_GRAVEYARD, {[]{return true;}}),
});
areaTable[GRAVEYARD_DAMPES_GRAVE] = Area("Graveyard Dampes Grave", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[GRAVEYARD_DAMPES_GRAVE] = Area("Graveyard Dampes Grave", "Windmill and Dampes Grave", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&NutPot, {[]{return true;}}),
EventAccess(&DampesWindmillAccess, {[]{return DampesWindmillAccess || (IsAdult && CanPlay(SongOfTime));},
@ -276,7 +285,7 @@ void AreaTable_Init_Kakariko() {
((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsAdult && SongOfTime;}}),
});
areaTable[GRAVEYARD_DAMPES_HOUSE] = Area("Graveyard Dampes House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
areaTable[GRAVEYARD_DAMPES_HOUSE] = Area("Graveyard Dampes House", "Graveyard Dampes House", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(THE_GRAVEYARD, {[]{return true;}}),
});

View File

@ -53,7 +53,7 @@ void AreaTable_Init_LostWoods() {
/*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}),
});
areaTable[KF_LINKS_HOUSE] = Area("KF Link's House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[KF_LINKS_HOUSE] = Area("KF Link's House", "KF Link's House", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KF_LINKS_HOUSE_COW, {[]{return IsAdult && CanPlay(EponasSong) && LinksCow;},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (NumBottles >= 2 && Fairy)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT))) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && Bombs && IsAdult && EponasSong && LinksCow;}}),
@ -62,7 +62,7 @@ void AreaTable_Init_LostWoods() {
Entrance(KOKIRI_FOREST, {[]{return true;}})
});
areaTable[KF_MIDOS_HOUSE] = Area("KF Mido's House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[KF_MIDOS_HOUSE] = Area("KF Mido's House", "KF Mido's House", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KF_MIDOS_TOP_LEFT_CHEST, {[]{return true;}}),
LocationAccess(KF_MIDOS_TOP_RIGHT_CHEST, {[]{return true;}}),
@ -73,22 +73,22 @@ void AreaTable_Init_LostWoods() {
Entrance(KOKIRI_FOREST, {[]{return true;}}),
});
areaTable[KF_SARIAS_HOUSE] = Area("KF Saria's House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
areaTable[KF_SARIAS_HOUSE] = Area("KF Saria's House", "KF Saria's House", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(KOKIRI_FOREST, {[]{return true;}}),
});
areaTable[KF_HOUSE_OF_TWINS] = Area("KF House of Twins", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
areaTable[KF_HOUSE_OF_TWINS] = Area("KF House of Twins", "KF House of Twins", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(KOKIRI_FOREST, {[]{return true;}}),
});
areaTable[KF_KNOW_IT_ALL_HOUSE] = Area("KF Know It All House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
areaTable[KF_KNOW_IT_ALL_HOUSE] = Area("KF Know It All House", "KF Know It All House", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(KOKIRI_FOREST, {[]{return true;}}),
});
areaTable[KF_KOKIRI_SHOP] = Area("KF Kokiri Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[KF_KOKIRI_SHOP] = Area("KF Kokiri Shop", "KF Kokiri Shop", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(KF_SHOP_ITEM_1, {[]{return true;}}),
LocationAccess(KF_SHOP_ITEM_2, {[]{return true;}}),
@ -103,7 +103,7 @@ void AreaTable_Init_LostWoods() {
Entrance(KOKIRI_FOREST, {[]{return true;}}),
});
areaTable[KF_STORMS_GROTTO] = Area("KF Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
areaTable[KF_STORMS_GROTTO] = Area("KF Storms Grotto", "KF Storms Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
//Locations
LocationAccess(KF_STORMS_GROTTO_CHEST, {[]{return true;}}),
LocationAccess(KF_STORMS_GROTTO_GOSSIP_STONE, {[]{return true;}}),
@ -177,7 +177,7 @@ void AreaTable_Init_LostWoods() {
/*Glitched*/[]{return Here(LW_BEYOND_MIDO, []{return IsChild && CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}),
});
areaTable[LW_NEAR_SHORTCUTS_GROTTO] = Area("LW Near Shortcuts Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
areaTable[LW_NEAR_SHORTCUTS_GROTTO] = Area("LW Near Shortcuts Grotto", "LW Near Shortcuts Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
//Locations
LocationAccess(LW_NEAR_SHORTCUTS_GROTTO_CHEST, {[]{return true;}}),
LocationAccess(LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, {[]{return true;}}),
@ -186,7 +186,7 @@ void AreaTable_Init_LostWoods() {
Entrance(THE_LOST_WOODS, {[]{return true;}}),
});
areaTable[DEKU_THEATER] = Area("Deku Theater", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[DEKU_THEATER] = Area("Deku Theater", "Deku Theater", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(DEKU_THEATER_SKULL_MASK, {[]{return IsChild && SkullMask;}}),
LocationAccess(DEKU_THEATER_MASK_OF_TRUTH, {[]{return IsChild && MaskOfTruth;}}),
@ -195,7 +195,7 @@ void AreaTable_Init_LostWoods() {
Entrance(LW_BEYOND_MIDO, {[]{return true;}}),
});
areaTable[LW_SCRUBS_GROTTO] = Area("LW Scrubs Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[LW_SCRUBS_GROTTO] = Area("LW Scrubs Grotto", "LW Scrubs Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(LW_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}),
LocationAccess(LW_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}),
@ -232,7 +232,7 @@ void AreaTable_Init_LostWoods() {
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}),
});
areaTable[SFM_FAIRY_GROTTO] = Area("SFM Fairy Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[SFM_FAIRY_GROTTO] = Area("SFM Fairy Grotto", "SFM Fairy Grotto", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&FreeFairies, {[]{return true;}}),
}, {}, {
@ -240,7 +240,7 @@ void AreaTable_Init_LostWoods() {
Entrance(SACRED_FOREST_MEADOW, {[]{return true;}}),
});
areaTable[SFM_WOLFOS_GROTTO] = Area("SFM Wolfos Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[SFM_WOLFOS_GROTTO] = Area("SFM Wolfos Grotto", "SFM Wolfos Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(SFM_WOLFOS_GROTTO_CHEST, {[]{return IsAdult || Slingshot || Sticks || KokiriSword || CanUse(DINS_FIRE) || CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}}),
}, {
@ -248,7 +248,7 @@ void AreaTable_Init_LostWoods() {
Entrance(SFM_ENTRYWAY, {[]{return true;}}),
});
areaTable[SFM_STORMS_GROTTO] = Area("SFM Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[SFM_STORMS_GROTTO] = Area("SFM Storms Grotto", "SFM Storms Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(SFM_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}),
LocationAccess(SFM_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}),

View File

@ -12,9 +12,9 @@ void AreaTable_Init_SpiritTemple() {
---------------------------*/
areaTable[SPIRIT_TEMPLE_ENTRYWAY] = Area("Spirit Temple Entryway", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(SPIRIT_TEMPLE_LOBBY, {[]{return Dungeon::SpiritTemple.IsVanilla();}}),
Entrance(SPIRIT_TEMPLE_MQ_LOBBY, {[]{return Dungeon::SpiritTemple.IsMQ();}}),
Entrance(DESERT_COLOSSUS, {[]{return true;}}),
Entrance(SPIRIT_TEMPLE_LOBBY, {[]{return Dungeon::SpiritTemple.IsVanilla();}}),
Entrance(SPIRIT_TEMPLE_MQ_LOBBY, {[]{return Dungeon::SpiritTemple.IsMQ();}}),
Entrance(DESERT_COLOSSUS_FROM_SPIRIT_ENTRYWAY, {[]{return true;}}),
});
/*--------------------------

View File

@ -76,7 +76,7 @@ void AreaTable_Init_ZorasDomain() {
Entrance(ZORAS_DOMAIN, {[]{return true;}}),
});
areaTable[ZR_OPEN_GROTTO] = Area("ZR Open Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
areaTable[ZR_OPEN_GROTTO] = Area("ZR Open Grotto", "ZR Open Grotto", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, {
//Locations
LocationAccess(ZR_OPEN_GROTTO_CHEST, {[]{return true;}}),
LocationAccess(ZR_OPEN_GROTTO_GOSSIP_STONE, {[]{return true;}}),
@ -85,7 +85,7 @@ void AreaTable_Init_ZorasDomain() {
Entrance(ZORAS_RIVER, {[]{return true;}}),
});
areaTable[ZR_FAIRY_GROTTO] = Area("ZR Fairy Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[ZR_FAIRY_GROTTO] = Area("ZR Fairy Grotto", "ZR Fairy Grotto", NONE, NO_DAY_NIGHT_CYCLE, {
//Event
EventAccess(&FreeFairies, {[]{return true;}}),
}, {}, {
@ -93,7 +93,7 @@ void AreaTable_Init_ZorasDomain() {
Entrance(ZORAS_RIVER, {[]{return true;}}),
});
areaTable[ZR_STORMS_GROTTO] = Area("ZR Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[ZR_STORMS_GROTTO] = Area("ZR Storms Grotto", "ZR Storms Grotto", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(ZR_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}),
LocationAccess(ZR_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}),
@ -142,7 +142,7 @@ void AreaTable_Init_ZorasDomain() {
Entrance(ZORAS_FOUNTAIN, {[]{return true;}}),
});
areaTable[ZD_SHOP] = Area("ZD Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[ZD_SHOP] = Area("ZD Shop", "ZD Shop", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(ZD_SHOP_ITEM_1, {[]{return true;}}),
LocationAccess(ZD_SHOP_ITEM_2, {[]{return true;}}),
@ -157,7 +157,7 @@ void AreaTable_Init_ZorasDomain() {
Entrance(ZORAS_DOMAIN, {[]{return true;}}),
});
areaTable[ZD_STORMS_GROTTO] = Area("ZD Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {
areaTable[ZD_STORMS_GROTTO] = Area("ZD Storms Grotto", "ZD Storms Grotto", NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&FreeFairies, {[]{return true;}}),
}, {}, {
@ -191,7 +191,7 @@ void AreaTable_Init_ZorasDomain() {
/*Glitched*/[]{return IsChild && (KokiriSword || Sticks) && CanShield && (CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::ADVANCED) || (CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::INTERMEDIATE)));}}),
});
areaTable[ZF_GREAT_FAIRY_FOUNTAIN] = Area("ZF Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {
areaTable[ZF_GREAT_FAIRY_FOUNTAIN] = Area("ZF Great Fairy Fountain", "ZF Great Fairy Fountain", NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(ZF_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);},
/*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) ||

View File

@ -194,6 +194,52 @@ string_view grottoEntrancesDesc = "Shuffle the pool of grotto entrances, i
"all graves, small Fairy Fountains and the Lost\n" //
"Woods Stage."; //
/*------------------------------ //
| OWL DROPS | //
------------------------------*/ //
string_view owlDropsDesc = "Randomize where Kaepora Gaebora (the Owl) drops\n"//
"you at when you talk to him at Lake Hylia or at\n"//
"the top of Death Mountain Trail."; //
/*------------------------------ //
| WARP SONGS | //
------------------------------*/ //
string_view warpSongsDesc = "Randomize where each of the 6 warp songs leads to.";
//
/*------------------------------ //
| OVERWORLD SPAWNS | //
------------------------------*/ //
string_view overworldSpawnsDesc = "Randomize where you start as Child or Adult when\n"
"loading a save in the Overworld. This means you\n"//
"may not necessarily spawn inside Link's House or\n"
"Temple of Time.\n" //
"\n" //
"This stays consistent after saving and loading the"
"game again."; //
/*------------------------------ //
| MIXED ENTRANCE POOLS | //
------------------------------*/ //
string_view mixedPoolsDesc = "Shuffle entrances into a mixed pool instead of\n" //
"separate ones. For example, enabling the settings\n"
"to shuffle grotto, dungeon, and overworld\n" //
"entrances and selecting grotto and dungeon\n" //
"entrances here will allow a dungeon to be inside a"
"grotto or vice versa, while overworld entrances\n"//
"are shuffled in their own separate pool and\n" //
"indoors stay vanilla."; //
string_view mixDungeonsDesc = "Dungeon entrances will be part of the mixed pool.";
string_view mixOverworldDesc = "Overworld entrances will be part of the mixed\n" //
"pool."; //
string_view mixInteriorsDesc = "Interior entrances will be part of the mixed pool.";
string_view mixGrottosDesc = "Grotto entrances will be part of the mixed pool.";//
/*------------------------------ //
| DECOUPLED ENTRANCES | //
------------------------------*/ //
string_view decoupledEntrancesDesc = "Decouple entrances when shuffling them. This means"
"you are no longer guaranteed to end up back where "
"you came from when you go back through an\n" //
"entrance. This also adds the one-way entrance from"
"Gerudo Valley to Lake Hylia in the pool of\n" //
"overworld entrances when they are shuffled."; //
/*------------------------------ //
| BOMBCHUS IN LOGIC | //
------------------------------*/ //
string_view bombchuLogicDesc = "Bombchus are properly considered in logic.\n" //

View File

@ -61,6 +61,20 @@ extern string_view overworldEntrancesDesc;
extern string_view grottoEntrancesDesc;
extern string_view owlDropsDesc;
extern string_view warpSongsDesc;
extern string_view overworldSpawnsDesc;
extern string_view mixedPoolsDesc;
extern string_view mixDungeonsDesc;
extern string_view mixOverworldDesc;
extern string_view mixInteriorsDesc;
extern string_view mixGrottosDesc;
extern string_view decoupledEntrancesDesc;
extern string_view interiorEntrancesOff;
extern string_view interiorEntrancesSimple;
extern string_view interiorEntrancesAll;

View File

@ -88,10 +88,19 @@ namespace Settings {
Option StartingAge = Option::U8 ("Starting Age", {"Child", "Adult", "Random"}, {ageDesc}, OptionCategory::Setting, AGE_CHILD);
uint8_t ResolvedStartingAge;
Option ShuffleEntrances = Option::Bool("Shuffle Entrances", {"Off", "On"}, {shuffleEntrancesDesc});
Option ShuffleDungeonEntrances = Option::U8 ("Dungeon Entrances", {"Off", "On", "On + Ganon"}, {dungeonEntrancesDesc});
Option ShuffleOverworldEntrances = Option::Bool("Overworld Entrances", {"Off", "On"}, {overworldEntrancesDesc});
Option ShuffleInteriorEntrances = Option::U8 ("Interior Entrances", {"Off", "Simple", "All"}, {interiorEntrancesOff, interiorEntrancesSimple, interiorEntrancesAll});
Option ShuffleGrottoEntrances = Option::Bool("Grottos Entrances", {"Off", "On"}, {grottoEntrancesDesc});
Option ShuffleDungeonEntrances = Option::U8 ("Dungeon Entrances", {"Off", "On", "On + Ganon"}, {dungeonEntrancesDesc});
Option ShuffleOverworldEntrances = Option::Bool("Overworld Entrances", {"Off", "On"}, {overworldEntrancesDesc});
Option ShuffleInteriorEntrances = Option::U8 ("Interior Entrances", {"Off", "Simple", "All"}, {interiorEntrancesOff, interiorEntrancesSimple, interiorEntrancesAll});
Option ShuffleGrottoEntrances = Option::Bool("Grottos Entrances", {"Off", "On"}, {grottoEntrancesDesc});
Option ShuffleOwlDrops = Option::Bool("Owl Drops", {"Off", "On"}, {owlDropsDesc});
Option ShuffleWarpSongs = Option::Bool("Warp Songs", {"Off", "On"}, {warpSongsDesc});
Option ShuffleOverworldSpawns = Option::Bool("Overworld Spawns", {"Off", "On"}, {overworldSpawnsDesc});
Option MixedEntrancePools = Option::Bool("Mixed Entrance Pools", {"Off", "On"}, {mixedPoolsDesc});
Option MixDungeons = Option::Bool("Mix Dungeons", {"Off", "On"}, {mixDungeonsDesc});
Option MixOverworld = Option::Bool("Mix Overworld", {"Off", "On"}, {mixOverworldDesc});
Option MixInteriors = Option::Bool("Mix Interiors", {"Off", "On"}, {mixInteriorsDesc});
Option MixGrottos = Option::Bool("Mix Grottos", {"Off", "On"}, {mixGrottosDesc});
Option DecoupleEntrances = Option::Bool("Decouple Entrances", {"Off", "On"}, {decoupledEntrancesDesc});
Option BombchusInLogic = Option::Bool("Bombchus in Logic", {"Off", "On"}, {bombchuLogicDesc});
Option AmmoDrops = Option::U8 ("Ammo Drops", {"On", "On + Bombchu", "Off"}, {defaultAmmoDropsDesc, bombchuDropsDesc, noAmmoDropsDesc}, OptionCategory::Setting, AMMODROPS_BOMBCHU);
Option HeartDropRefill = Option::U8 ("Heart Drops and Refills",{"On", "No Drop", "No Refill", "Off"}, {defaultHeartDropsDesc, noHeartDropsDesc, noHeartRefillDesc, scarceHeartsDesc}, OptionCategory::Setting, HEARTDROPREFILL_VANILLA);
@ -119,6 +128,15 @@ namespace Settings {
&ShuffleOverworldEntrances,
&ShuffleInteriorEntrances,
&ShuffleGrottoEntrances,
&ShuffleOwlDrops,
&ShuffleWarpSongs,
&ShuffleOverworldSpawns,
&MixedEntrancePools,
&MixDungeons,
&MixOverworld,
&MixInteriors,
&MixGrottos,
&DecoupleEntrances,
&BombchusInLogic,
&AmmoDrops,
&HeartDropRefill,
@ -1256,6 +1274,15 @@ namespace Settings {
ctx.shuffleOverworldEntrances = (ShuffleOverworldEntrances) ? 1 : 0;
ctx.shuffleInteriorEntrances = ShuffleInteriorEntrances.Value<uint8_t>();
ctx.shuffleGrottoEntrances = (ShuffleGrottoEntrances) ? 1 : 0;
ctx.shuffleOwlDrops = (ShuffleOwlDrops) ? 1 : 0;
ctx.shuffleWarpSongs = (ShuffleWarpSongs) ? 1 : 0;
ctx.shuffleOverworldSpawns = (ShuffleOverworldSpawns) ? 1 : 0;
ctx.mixedEntrancePools = (MixedEntrancePools) ? 1 : 0;
ctx.mixDungeons = (MixDungeons) ? 1 : 0;
ctx.mixOverworld = (MixOverworld) ? 1 : 0;
ctx.mixInteriors = (MixInteriors) ? 1 : 0;
ctx.mixGrottos = (MixGrottos) ? 1 : 0;
ctx.decoupleEntrances = (DecoupleEntrances) ? 1 : 0;
ctx.bombchusInLogic = (BombchusInLogic) ? 1 : 0;
ctx.ammoDrops = AmmoDrops.Value<uint8_t>();
ctx.heartDropRefill = HeartDropRefill.Value<uint8_t>();
@ -1929,6 +1956,11 @@ namespace Settings {
ShuffleOverworldEntrances.Unhide();
ShuffleInteriorEntrances.Unhide();
ShuffleGrottoEntrances.Unhide();
ShuffleOwlDrops.Unhide();
ShuffleWarpSongs.Unhide();
ShuffleOverworldSpawns.Unhide();
MixedEntrancePools.Unhide();
DecoupleEntrances.Unhide();
} else {
ShuffleDungeonEntrances.SetSelectedIndex(SHUFFLEDUNGEONS_OFF);
ShuffleDungeonEntrances.Hide();
@ -1938,6 +1970,56 @@ namespace Settings {
ShuffleInteriorEntrances.Hide();
ShuffleGrottoEntrances.SetSelectedIndex(OFF);
ShuffleGrottoEntrances.Hide();
ShuffleOwlDrops.SetSelectedIndex(OFF);
ShuffleOwlDrops.Hide();
ShuffleWarpSongs.SetSelectedIndex(OFF);
ShuffleWarpSongs.Hide();
ShuffleOverworldSpawns.SetSelectedIndex(OFF);
ShuffleOverworldSpawns.Hide();
MixedEntrancePools.SetSelectedIndex(OFF);
MixedEntrancePools.Hide();
DecoupleEntrances.SetSelectedIndex(OFF);
DecoupleEntrances.Hide();
}
// Only show the options for mixing each pool if they're already being shuffled
if (MixedEntrancePools) {
if (ShuffleDungeonEntrances) {
MixDungeons.Unhide();
} else {
MixDungeons.Hide();
MixDungeons.SetSelectedIndex(OFF);
}
if (ShuffleOverworldEntrances) {
MixOverworld.Unhide();
} else {
MixOverworld.Hide();
MixOverworld.SetSelectedIndex(OFF);
}
if (ShuffleInteriorEntrances.IsNot(OFF)) {
MixInteriors.Unhide();
} else {
MixInteriors.Hide();
MixInteriors.SetSelectedIndex(OFF);
}
if (ShuffleGrottoEntrances) {
MixGrottos.Unhide();
} else {
MixGrottos.Hide();
MixGrottos.SetSelectedIndex(OFF);
}
} else {
MixDungeons.Hide();
MixDungeons.SetSelectedIndex(OFF);
MixOverworld.Hide();
MixOverworld.SetSelectedIndex(OFF);
MixInteriors.Hide();
MixInteriors.SetSelectedIndex(OFF);
MixGrottos.Hide();
MixGrottos.SetSelectedIndex(OFF);
}
}
@ -2365,6 +2447,18 @@ namespace Settings {
ShuffleOverworldEntrances.SetSelectedIndex(OFF);
ShuffleInteriorEntrances.SetSelectedIndex(OFF);
ShuffleGrottoEntrances.SetSelectedIndex(OFF);
ShuffleOwlDrops.SetSelectedIndex(OFF);
ShuffleWarpSongs.SetSelectedIndex(OFF);
ShuffleOverworldSpawns.SetSelectedIndex(OFF);
MixedEntrancePools.SetSelectedIndex(OFF);
DecoupleEntrances.SetSelectedIndex(OFF);
}
if (!MixedEntrancePools) {
MixDungeons.SetSelectedIndex(OFF);
MixOverworld.SetSelectedIndex(OFF);
MixInteriors.SetSelectedIndex(OFF);
MixGrottos.SetSelectedIndex(OFF);
}
// Shuffle Settings
@ -2569,6 +2663,15 @@ namespace Settings {
ShuffleOverworldEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_OVERWORLD_ENTRANCES]);
ShuffleInteriorEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_INTERIOR_ENTRANCES]);
ShuffleGrottoEntrances.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_GROTTO_ENTRANCES]);
ShuffleOwlDrops.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_OWL_DROPS]);
ShuffleWarpSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_WARP_SONGS]);
ShuffleOverworldSpawns.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_OVERWORLD_SPAWNS]);
MixedEntrancePools.SetSelectedIndex(cvarSettings[RSK_MIXED_ENTRANCE_POOLS]);
MixDungeons.SetSelectedIndex(cvarSettings[RSK_MIX_DUNGEON_ENTRANCES]);
MixOverworld.SetSelectedIndex(cvarSettings[RSK_MIX_OVERWORLD_ENTRANCES]);
MixInteriors.SetSelectedIndex(cvarSettings[RSK_MIX_INTERIOR_ENTRANCES]);
MixGrottos.SetSelectedIndex(cvarSettings[RSK_MIX_GROTTO_ENTRANCES]);
DecoupleEntrances.SetSelectedIndex(cvarSettings[RSK_DECOUPLED_ENTRANCES]);
// if we skip child zelda, we start with zelda's letter, and malon starts
// at the ranch, so we should *not* shuffle the weird egg

View File

@ -390,6 +390,15 @@ typedef struct {
uint8_t shuffleOverworldEntrances;
uint8_t shuffleInteriorEntrances;
uint8_t shuffleGrottoEntrances;
uint8_t shuffleOwlDrops;
uint8_t shuffleWarpSongs;
uint8_t shuffleOverworldSpawns;
uint8_t mixedEntrancePools;
uint8_t mixDungeons;
uint8_t mixOverworld;
uint8_t mixInteriors;
uint8_t mixGrottos;
uint8_t decoupleEntrances;
uint8_t bombchusInLogic;
uint8_t ammoDrops;
uint8_t heartDropRefill;
@ -897,6 +906,15 @@ void UpdateSettings(std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettin
extern Option ShuffleOverworldEntrances;
extern Option ShuffleInteriorEntrances;
extern Option ShuffleGrottoEntrances;
extern Option ShuffleOwlDrops;
extern Option ShuffleWarpSongs;
extern Option ShuffleOverworldSpawns;
extern Option MixedEntrancePools;
extern Option MixDungeons;
extern Option MixOverworld;
extern Option MixInteriors;
extern Option MixGrottos;
extern Option DecoupleEntrances;
extern Option BombchusInLogic;
extern Option AmmoDrops;
extern Option HeartDropRefill;

View File

@ -298,41 +298,47 @@ static void WriteLocation(
//Writes a shuffled entrance to the specified node
static void WriteShuffledEntrance(std::string sphereString, Entrance* entrance) {
int16_t originalIndex = entrance->GetIndex();
int16_t destinationIndex = entrance->GetReverse()->GetIndex();
int16_t destinationIndex = -1;
int16_t originalBlueWarp = entrance->GetBlueWarp();
int16_t replacementBlueWarp = entrance->GetReplacement()->GetReverse()->GetBlueWarp();
int16_t replacementBlueWarp = -1;
int16_t replacementIndex = entrance->GetReplacement()->GetIndex();
int16_t replacementDestinationIndex = entrance->GetReplacement()->GetReverse()->GetIndex();
int16_t replacementDestinationIndex = -1;
std::string name = entrance->GetName();
std::string text = entrance->GetConnectedRegion()->regionName + " from " + entrance->GetReplacement()->GetParentRegion()->regionName;
if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) {
destinationIndex = entrance->GetReverse()->GetIndex();
replacementDestinationIndex = entrance->GetReplacement()->GetReverse()->GetIndex();
replacementBlueWarp = entrance->GetReplacement()->GetReverse()->GetBlueWarp();
}
json entranceJson = json::object({
{"index", originalIndex},
{"destination", destinationIndex},
{"blueWarp", originalBlueWarp},
{"override", replacementIndex},
{"overrideDestination", replacementDestinationIndex},
});
jsonData["entrances"].push_back(entranceJson);
// When decoupled entrances is off, handle saving reverse entrances with blue warps
if (entrance->GetReverse() != nullptr && !Settings::DecoupleEntrances) {
json reverseEntranceJson = json::object({
{"index", replacementDestinationIndex},
{"destination", replacementIndex},
{"blueWarp", replacementBlueWarp},
{"override", destinationIndex},
{"overrideDestination", originalIndex},
});
jsonData["entrances"].push_back(reverseEntranceJson);
}
switch (gSaveContext.language) {
case LANGUAGE_ENG:
case LANGUAGE_FRA:
default:
json entranceJson = json::object({
{"index", originalIndex},
{"destination", destinationIndex},
{"blueWarp", originalBlueWarp},
{"override", replacementIndex},
{"overrideDestination", replacementDestinationIndex},
});
jsonData["entrances"].push_back(entranceJson);
// When decoupled entrances is off, handle saving reverse entrances with blue warps
if (!false) { // RANDOTODO: add check for decoupled entrances
json reverseEntranceJson = json::object({
{"index", replacementDestinationIndex},
{"destination", replacementIndex},
{"blueWarp", replacementBlueWarp},
{"override", destinationIndex},
{"overrideDestination", originalIndex},
});
jsonData["entrances"].push_back(reverseEntranceJson);
}
jsonData["entrancesMap"][sphereString][name] = text;
break;
}
@ -628,12 +634,24 @@ static void WriteHints(int language) {
default:
unformattedGanonText = GetGanonText().GetEnglish();
unformattedGanonHintText = GetGanonHintText().GetEnglish();
jsonData["warpMinuetText"] = GetWarpMinuetText().GetEnglish();
jsonData["warpBoleroText"] = GetWarpBoleroText().GetEnglish();
jsonData["warpSerenadeText"] = GetWarpSerenadeText().GetEnglish();
jsonData["warpRequiemText"] = GetWarpRequiemText().GetEnglish();
jsonData["warpNocturne"] = GetWarpNocturneText().GetEnglish();
jsonData["warpPreludeText"] = GetWarpPreludeText().GetEnglish();
jsonData["childAltarText"] = GetChildAltarText().GetEnglish();
jsonData["adultAltarText"] = GetAdultAltarText().GetEnglish();
break;
case 2:
unformattedGanonText = GetGanonText().GetFrench();
unformattedGanonHintText = GetGanonHintText().GetFrench();
jsonData["warpMinuetText"] = GetWarpMinuetText().GetFrench();
jsonData["warpBoleroText"] = GetWarpBoleroText().GetFrench();
jsonData["warpSerenadeText"] = GetWarpSerenadeText().GetFrench();
jsonData["warpRequiemText"] = GetWarpRequiemText().GetFrench();
jsonData["warpNocturne"] = GetWarpNocturneText().GetFrench();
jsonData["warpPreludeText"] = GetWarpPreludeText().GetFrench();
jsonData["childAltarText"] = GetChildAltarText().GetFrench();
jsonData["adultAltarText"] = GetAdultAltarText().GetFrench();
break;

View File

@ -224,6 +224,15 @@ std::unordered_map<std::string, RandomizerSettingKey> SpoilerfileSettingNameToEn
{ "World Settings:Overworld Entrances", RSK_SHUFFLE_OVERWORLD_ENTRANCES },
{ "World Settings:Interior Entrances", RSK_SHUFFLE_INTERIOR_ENTRANCES },
{ "World Settings:Grottos Entrances", RSK_SHUFFLE_GROTTO_ENTRANCES },
{ "World Settings:Owl Drops", RSK_SHUFFLE_OWL_DROPS },
{ "World Settings:Warp Songs", RSK_SHUFFLE_WARP_SONGS },
{ "World Settings:Overworld Spawns", RSK_SHUFFLE_OVERWORLD_SPAWNS },
{ "World Settings:Mixed Entrance Pools", RSK_MIXED_ENTRANCE_POOLS },
{ "World Settings:Mix Dungeons", RSK_MIX_DUNGEON_ENTRANCES },
{ "World Settings:Mix Overworld", RSK_MIX_OVERWORLD_ENTRANCES },
{ "World Settings:Mix Interiors", RSK_MIX_INTERIOR_ENTRANCES },
{ "World Settings:Mix Grottos", RSK_MIX_GROTTO_ENTRANCES },
{ "World Settings:Decouple Entrances", RSK_DECOUPLED_ENTRANCES },
{ "Misc Settings:Gossip Stone Hints", RSK_GOSSIP_STONE_HINTS },
{ "Misc Settings:Hint Clarity", RSK_HINT_CLARITY },
{ "Misc Settings:Hint Distribution", RSK_HINT_DISTRIBUTION },
@ -327,6 +336,12 @@ void Randomizer::LoadHintLocations(const char* spoilerFileName) {
CustomMessageManager::Instance->CreateMessage(
Randomizer::hintMessageTableID, hintLocation.check, { TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, hintLocation.hintText, hintLocation.hintText, hintLocation.hintText });
}
CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_WARP_RANDOM_REPLACED_TEXT,
{ TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM,
"Warp to&{{location}}?\x1B&%gOK&No%w\x02",
"Warp to&{{location}}?\x1B&%gOK&No%w\x02", // TODO: German translation
"Se téléporter vers&{{location}}?\x1B&%gOK!&Non%w\x02" });
}
std::vector<RandomizerCheck> shopItemRandomizerChecks = {
@ -716,6 +731,15 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) {
case RSK_SHUFFLE_ENTRANCES:
case RSK_SHUFFLE_OVERWORLD_ENTRANCES:
case RSK_SHUFFLE_GROTTO_ENTRANCES:
case RSK_SHUFFLE_OWL_DROPS:
case RSK_SHUFFLE_WARP_SONGS:
case RSK_SHUFFLE_OVERWORLD_SPAWNS:
case RSK_MIXED_ENTRANCE_POOLS:
case RSK_MIX_DUNGEON_ENTRANCES:
case RSK_MIX_OVERWORLD_ENTRANCES:
case RSK_MIX_INTERIOR_ENTRANCES:
case RSK_MIX_GROTTO_ENTRANCES:
case RSK_DECOUPLED_ENTRANCES:
if(it.value() == "Off") {
gSaveContext.randoSettings[index].value = RO_GENERIC_OFF;
} else if(it.value() == "On") {
@ -1101,6 +1125,30 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
strncpy(gSaveContext.ganonText, formattedGanonJsonText.c_str(), sizeof(gSaveContext.ganonText) - 1);
gSaveContext.ganonText[sizeof(gSaveContext.ganonText) - 1] = 0;
std::string warpMinuetJsonText = spoilerFileJson["warpMinuetText"].get<std::string>();
strncpy(gSaveContext.warpMinuetText, warpMinuetJsonText.c_str(), sizeof(gSaveContext.warpMinuetText) - 1);
gSaveContext.warpMinuetText[sizeof(gSaveContext.warpMinuetText) - 1] = 0;
std::string warpBoleroJsonText = spoilerFileJson["warpBoleroText"].get<std::string>();
strncpy(gSaveContext.warpBoleroText, warpBoleroJsonText.c_str(), sizeof(gSaveContext.warpBoleroText) - 1);
gSaveContext.warpBoleroText[sizeof(gSaveContext.warpBoleroText) - 1] = 0;
std::string warpSerenadeJsonText = spoilerFileJson["warpSerenadeText"].get<std::string>();
strncpy(gSaveContext.warpSerenadeText, warpSerenadeJsonText.c_str(), sizeof(gSaveContext.warpSerenadeText) - 1);
gSaveContext.warpSerenadeText[sizeof(gSaveContext.warpSerenadeText) - 1] = 0;
std::string warpRequiemJsonText = spoilerFileJson["warpRequiemText"].get<std::string>();
strncpy(gSaveContext.warpRequiemText, warpRequiemJsonText.c_str(), sizeof(gSaveContext.warpRequiemText) - 1);
gSaveContext.warpRequiemText[sizeof(gSaveContext.warpRequiemText) - 1] = 0;
std::string warpNocturneJsonText = spoilerFileJson["warpNocturneText"].get<std::string>();
strncpy(gSaveContext.warpNocturneText, warpNocturneJsonText.c_str(), sizeof(gSaveContext.warpNocturneText) - 1);
gSaveContext.warpNocturneText[sizeof(gSaveContext.warpNocturneText) - 1] = 0;
std::string warpPreludeJsonText = spoilerFileJson["warpPreludeText"].get<std::string>();
strncpy(gSaveContext.warpPreludeText, warpPreludeJsonText.c_str(), sizeof(gSaveContext.warpPreludeText) - 1);
gSaveContext.warpPreludeText[sizeof(gSaveContext.warpPreludeText) - 1] = 0;
json hintsJson = spoilerFileJson["hints"];
int index = 0;
for (auto it = hintsJson.begin(); it != hintsJson.end(); ++it) {
@ -2682,15 +2730,27 @@ void GenerateRandomizerImgui() {
}
// Enable if any of the entrance rando options are enabled.
cvarSettings[RSK_SHUFFLE_ENTRANCES] = CVar_GetS32("gRandomizeShuffleDungeonsEntrances", 0) ||
CVar_GetS32("gRandomizeShuffleOverworldEntrances", 0) ||
CVar_GetS32("gRandomizeShuffleInteriorsEntrances", 0) ||
CVar_GetS32("gRandomizeShuffleGrottosEntrances", 0);
cvarSettings[RSK_SHUFFLE_ENTRANCES] = CVar_GetS32("gRandomizeShuffleDungeonsEntrances", RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) ||
CVar_GetS32("gRandomizeShuffleOverworldEntrances", RO_GENERIC_OFF) ||
CVar_GetS32("gRandomizeShuffleInteriorsEntrances", RO_INTERIOR_ENTRANCE_SHUFFLE_OFF) ||
CVar_GetS32("gRandomizeShuffleGrottosEntrances", RO_GENERIC_OFF) ||
CVar_GetS32("gRandomizeShuffleOwlDrops", RO_GENERIC_OFF) ||
CVar_GetS32("gRandomizeShuffleWarpSongs", RO_GENERIC_OFF) ||
CVar_GetS32("gRandomizeShuffleOverworldSpawns", RO_GENERIC_OFF);
cvarSettings[RSK_SHUFFLE_DUNGEON_ENTRANCES] = CVar_GetS32("gRandomizeShuffleDungeonsEntrances", 0);
cvarSettings[RSK_SHUFFLE_OVERWORLD_ENTRANCES] = CVar_GetS32("gRandomizeShuffleOverworldEntrances", 0);
cvarSettings[RSK_SHUFFLE_INTERIOR_ENTRANCES] = CVar_GetS32("gRandomizeShuffleInteriorsEntrances", 0);
cvarSettings[RSK_SHUFFLE_GROTTO_ENTRANCES] = CVar_GetS32("gRandomizeShuffleGrottosEntrances", 0);
cvarSettings[RSK_SHUFFLE_DUNGEON_ENTRANCES] = CVar_GetS32("gRandomizeShuffleDungeonsEntrances", RO_DUNGEON_ENTRANCE_SHUFFLE_OFF);
cvarSettings[RSK_SHUFFLE_OVERWORLD_ENTRANCES] = CVar_GetS32("gRandomizeShuffleOverworldEntrances", RO_GENERIC_OFF);
cvarSettings[RSK_SHUFFLE_INTERIOR_ENTRANCES] = CVar_GetS32("gRandomizeShuffleInteriorsEntrances", RO_INTERIOR_ENTRANCE_SHUFFLE_OFF);
cvarSettings[RSK_SHUFFLE_GROTTO_ENTRANCES] = CVar_GetS32("gRandomizeShuffleGrottosEntrances", RO_GENERIC_OFF);
cvarSettings[RSK_SHUFFLE_OWL_DROPS] = CVar_GetS32("gRandomizeShuffleOwlDrops", RO_GENERIC_OFF);
cvarSettings[RSK_SHUFFLE_WARP_SONGS] = CVar_GetS32("gRandomizeShuffleWarpSongs", RO_GENERIC_OFF);
cvarSettings[RSK_SHUFFLE_OVERWORLD_SPAWNS] = CVar_GetS32("gRandomizeShuffleOverworldSpawns", RO_GENERIC_OFF);
cvarSettings[RSK_MIXED_ENTRANCE_POOLS] = CVar_GetS32("gRandomizeMixedEntrances", RO_GENERIC_OFF);
cvarSettings[RSK_MIX_DUNGEON_ENTRANCES] = CVar_GetS32("gRandomizeMixDungeons", RO_GENERIC_OFF);
cvarSettings[RSK_MIX_OVERWORLD_ENTRANCES] = CVar_GetS32("gRandomizeMixOverworld", RO_GENERIC_OFF);
cvarSettings[RSK_MIX_INTERIOR_ENTRANCES] = CVar_GetS32("gRandomizeMixInteriors", RO_GENERIC_OFF);
cvarSettings[RSK_MIX_GROTTO_ENTRANCES] = CVar_GetS32("gRandomizeMixGrottos", RO_GENERIC_OFF);
cvarSettings[RSK_DECOUPLED_ENTRANCES] = CVar_GetS32("gRandomizeShuffleDecoupledEntrances", RO_GENERIC_OFF);
// todo: this efficently when we build out cvar array support
std::set<RandomizerCheck> excludedLocations;
@ -3108,6 +3168,88 @@ void DrawRandoEditor(bool& open) {
"Shuffle the pool of grotto entrances, including all graves, small Fairy fountains and the Deku Theatre."
);
UIWidgets::PaddedSeparator();
// Shuffle Owl Drops
UIWidgets::EnhancementCheckbox("Shuffle Owl Drops", "gRandomizeShuffleOwlDrops");
UIWidgets::InsertHelpHoverText(
"Randomize where Kaepora Gaebora (the Owl) drops you at when you talk "
"to him at Lake Hylia or at the top of Death Mountain Trail."
);
UIWidgets::PaddedSeparator();
// Shuffle Warp Songs
UIWidgets::EnhancementCheckbox("Shuffle Warp Songs", "gRandomizeShuffleWarpSongs");
UIWidgets::InsertHelpHoverText(
"Randomize where each of the 6 warp songs leads to."
);
UIWidgets::PaddedSeparator();
// Shuffle Overworld Spawns
UIWidgets::EnhancementCheckbox("Shuffle Overworld Spawns", "gRandomizeShuffleOverworldSpawns");
UIWidgets::InsertHelpHoverText(
"Randomize where you start as Child or Adult when loading a save in the Overworld. This "
"means you may not necessarily spawn inside Link's House or Temple of Time.\n"
"\n"
"This stays consistent after saving and loading the game again.\n"
"\n"
"Keep in mind you may need to temporarily disable the \"Remember Save Location\" time saver to "
"be able use the spawn positions, especially if they are the only logical way to get to certain areas."
);
UIWidgets::PaddedSeparator();
// Shuffle Decoupled Entrances
UIWidgets::EnhancementCheckbox("Shuffle Decoupled Entrances", "gRandomizeShuffleDecoupledEntrances");
UIWidgets::InsertHelpHoverText(
"Decouple entrances when shuffling them. This means you are no longer guaranteed "
"to end up back where you came from when you go back through an entrance.\n"
"\n"
"This also adds the one-way entrance from Gerudo Valley to Lake Hylia in the pool of "
"overworld entrances when they are shuffled."
);
UIWidgets::PaddedSeparator();
// Mixed Entrance Pools
UIWidgets::EnhancementCheckbox("Mixed Entrance Pools", "gRandomizeMixedEntrances");
UIWidgets::InsertHelpHoverText(
"Shuffle entrances into a mixed pool instead of separate ones.\n"
"\n"
"For example, enabling the settings to shuffle grotto, dungeon, and overworld entrances and "
"selecting grotto and dungeon entrances here will allow a dungeon to be inside a grotto or "
"vice versa, while overworld entrances are shuffled in their own separate pool and indoors stay vanilla."
);
if (CVar_GetS32("gRandomizeMixedEntrances", RO_GENERIC_OFF)) {
if (CVar_GetS32("gRandomizeShuffleDungeonsEntrances", RO_GENERIC_OFF)) {
UIWidgets::Spacer(0);
ImGui::SetCursorPosX(20);
UIWidgets::EnhancementCheckbox("Mix Dungeons", "gRandomizeMixDungeons");
UIWidgets::InsertHelpHoverText("Dungeon entrances will be part of the mixed pool");
}
if (CVar_GetS32("gRandomizeShuffleOverworldEntrances", RO_GENERIC_OFF)) {
UIWidgets::Spacer(0);
ImGui::SetCursorPosX(20);
UIWidgets::EnhancementCheckbox("Mix Overworld", "gRandomizeMixOverworld");
UIWidgets::InsertHelpHoverText("Overworld entrances will be part of the mixed pool");
}
if (CVar_GetS32("gRandomizeShuffleInteriorsEntrances", RO_GENERIC_OFF)) {
UIWidgets::Spacer(0);
ImGui::SetCursorPosX(20);
UIWidgets::EnhancementCheckbox("Mix Interiors", "gRandomizeMixInteriors");
UIWidgets::InsertHelpHoverText("Interior entrances will be part of the mixed pool");
}
if (CVar_GetS32("gRandomizeShuffleGrottosEntrances", RO_GENERIC_OFF)) {
UIWidgets::Spacer(0);
ImGui::SetCursorPosX(20);
UIWidgets::EnhancementCheckbox("Mix Grotts", "gRandomizeMixGrottos");
UIWidgets::InsertHelpHoverText("Grotto entrances will be part of the mixed pool");
}
}
ImGui::PopItemWidth();
ImGui::EndChild();
ImGui::EndTable();
@ -4016,6 +4158,47 @@ void DrawRandoEditor(bool& open) {
ImGui::End();
}
CustomMessageEntry Randomizer::GetWarpSongMessage(u16 textId, bool mysterious) {
CustomMessageEntry messageEntry = CustomMessageManager::Instance->RetrieveMessage(
Randomizer::hintMessageTableID, TEXT_WARP_RANDOM_REPLACED_TEXT);
if (mysterious) {
std::vector<std::string> locationName ={
"a mysterious place",
"a mysterious place", // TODO: German translation
"un endroit mystérieux",
};
CustomMessageManager::ReplaceStringInMessage(messageEntry, "{{location}}", locationName[0],
locationName[1], locationName[2]);
return messageEntry;
}
std::string locationName;
switch (textId) {
case TEXT_WARP_MINUET_OF_FOREST:
locationName = std::string(gSaveContext.warpMinuetText);
break;
case TEXT_WARP_BOLERO_OF_FIRE:
locationName = std::string(gSaveContext.warpBoleroText);
break;
case TEXT_WARP_SERENADE_OF_WATER:
locationName = std::string(gSaveContext.warpSerenadeText);
break;
case TEXT_WARP_REQUIEM_OF_SPIRIT:
locationName = std::string(gSaveContext.warpRequiemText);
break;
case TEXT_WARP_NOCTURNE_OF_SHADOW:
locationName = std::string(gSaveContext.warpNocturneText);
break;
case TEXT_WARP_PRELUDE_OF_LIGHT:
locationName = std::string(gSaveContext.warpPreludeText);
break;
}
CustomMessageManager::ReplaceStringInMessage(messageEntry, "{{location}}", locationName);
return messageEntry;
}
CustomMessageEntry Randomizer::GetMerchantMessage(RandomizerInf randomizerInf, u16 textId, bool mysterious) {
CustomMessageEntry messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, textId);
RandomizerCheck rc = GetCheckFromRandomizerInf(randomizerInf);

View File

@ -77,6 +77,7 @@ class Randomizer {
GetItemID GetItemIdFromRandomizerGet(RandomizerGet randoGet, GetItemID ogItemId);
ItemObtainability GetItemObtainabilityFromRandomizerCheck(RandomizerCheck randomizerCheck);
ItemObtainability GetItemObtainabilityFromRandomizerGet(RandomizerGet randomizerCheck);
CustomMessageEntry GetWarpSongMessage(u16 textId, bool mysterious = false);
CustomMessageEntry GetMerchantMessage(RandomizerInf randomizerInf, u16 textId, bool mysterious = false);
CustomMessageEntry GetMapGetItemMessageWithHint(GetItemEntry itemEntry);
static void CreateCustomMessages();

View File

@ -59,6 +59,14 @@ static void Entrance_SeparateOGCFairyFountainExit(void) {
}
}
static void Entrance_SeparateAdultSpawnAndPrelude() {
// Overwrite unused entrance 0x0282 with values from 0x05F4 to use it as the
// Adult Spawn index and separate it from Prelude of Light
for (size_t i = 0; i < 4; ++i) {
gEntranceTable[0x282 + i] = gEntranceTable[0x5F4 + i];
}
}
void Entrance_CopyOriginalEntranceTable(void) {
if (!hasCopiedEntranceTable) {
memcpy(originalEntranceTable, gEntranceTable, sizeof(EntranceInfo) * 1556);
@ -91,6 +99,7 @@ void Entrance_Init(void) {
}
Entrance_SeparateOGCFairyFountainExit();
Entrance_SeparateAdultSpawnAndPrelude();
// Initialize the entrance override table with each index leading to itself. An
// index referring to itself means that the entrance is not currently shuffled.
@ -188,7 +197,7 @@ s16 Entrance_OverrideNextIndex(s16 nextEntranceIndex) {
// Exiting through the crawl space from Hyrule Castle courtyard is the same exit as leaving Ganon's castle
// If we came from the Castle courtyard, then don't override the entrance to keep Link in Hyrule Castle area
if (gPlayState->sceneNum == 69 && nextEntranceIndex == 0x023D) {
if (gPlayState != NULL && gPlayState->sceneNum == 69 && nextEntranceIndex == 0x023D) {
return nextEntranceIndex;
}
@ -279,15 +288,58 @@ void Entrance_SetSavewarpEntrance(void) {
} else if (scene == SCENE_GERUDOWAY) { // Theives hideout
gSaveContext.entranceIndex = 0x0486; // Gerudo Fortress -> Thieve's Hideout spawn 0
} else if (scene == SCENE_LINK_HOME) {
gSaveContext.entranceIndex = LINK_HOUSE_SAVEWARP_ENTRANCE;
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(LINK_HOUSE_SAVEWARP_ENTRANCE);
} else if (LINK_IS_CHILD) {
gSaveContext.entranceIndex = Entrance_GetOverride(LINK_HOUSE_SAVEWARP_ENTRANCE);
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(LINK_HOUSE_SAVEWARP_ENTRANCE); // Child Overworld Spawn
} else {
gSaveContext.entranceIndex = Entrance_GetOverride(0x05F4); // Temple of Time Adult Spawn
gSaveContext.entranceIndex = Entrance_OverrideNextIndex(0x0282); // Adult Overworld Spawn (Normally 0x5F4, but 0x282 has been repurposed to differentiate from Prelude which also uses 0x5F4)
}
}
void Entrance_SetWarpSongEntrance(void) {
gPlayState->sceneLoadFlag = 0x14;
gPlayState->fadeTransition = 5;
switch (gPlayState->msgCtx.lastPlayedSong) {
case 0:
gPlayState->nextEntranceIndex = Entrance_OverrideNextIndex(0x0600); // Minuet
break;
case 1:
gPlayState->nextEntranceIndex = Entrance_OverrideNextIndex(0x04F6); // Bolero
break;
case 2:
gPlayState->nextEntranceIndex = Entrance_OverrideNextIndex(0x0604); // Serenade
break;
case 3:
gPlayState->nextEntranceIndex = Entrance_OverrideNextIndex(0x01F1); // Requiem
break;
case 4:
gPlayState->nextEntranceIndex = Entrance_OverrideNextIndex(0x0568); // Nocturne
break;
case 5:
gPlayState->nextEntranceIndex = Entrance_OverrideNextIndex(0x05F4); // Prelude
break;
default:
gPlayState->sceneLoadFlag = 0; // if something goes wrong, the animation plays normally
}
// If one of the warp songs happens to lead to a grotto return, then we
// have to force the grotto return afterwards
Grotto_ForceGrottoReturnOnSpecialEntrance();
if (gSaveContext.gameMode != 0) {
// During DHWW the cutscene must play at the destination
gSaveContext.respawnFlag = -3;
} else if (gSaveContext.respawnFlag == -3) {
// Unset Zoneout Type -3 to avoid cutscene at destination (technically it's not needed)
gSaveContext.respawnFlag = 0;
}
}
void Entrance_OverrideBlueWarp(void) {
// Set nextEntranceIndex as a flag so that Grotto_CheckSpecialEntrance
// won't return index 0x7FFF, which can't work to override blue warps.
gPlayState->nextEntranceIndex = 0;
switch (gPlayState->sceneNum) {
case SCENE_YDAN_BOSS: // Ghoma boss room
gPlayState->nextEntranceIndex = Entrance_OverrideNextIndex(0x0457);
@ -322,6 +374,8 @@ void Entrance_OverrideCutsceneEntrance(u16 cutsceneCmd) {
gPlayState->nextEntranceIndex = Entrance_OverrideNextIndex(newJabuJabusBellyEntrance);
gPlayState->sceneLoadFlag = 0x14;
gPlayState->fadeTransition = 2;
// In case Jabu's mouth leads to a grotto return
Grotto_ForceGrottoReturnOnSpecialEntrance();
break;
}
}
@ -506,7 +560,7 @@ void Entrance_OverrideGeurdoGuardCapture(void) {
}
void Entrance_OverrideSpawnScene(s32 sceneNum, s32 spawn) {
if (Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) == 2) { // Shuffle Ganon's Castle
if (Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) == RO_DUNGEON_ENTRANCE_SHUFFLE_ON_PLUS_GANON) {
// Move Hyrule's Castle Courtyard exit spawn to be before the crates so players don't skip Talon
if (sceneNum == 95 && spawn == 1) {
gPlayState->linkActorEntry->pos.x = 0x033A;

View File

@ -40,6 +40,7 @@ int16_t Entrance_OverrideNextIndex(int16_t nextEntranceIndex);
int16_t Entrance_OverrideDynamicExit(int16_t dynamicExitIndex);
uint32_t Entrance_SceneAndSpawnAre(uint8_t scene, uint8_t spawn);
void Entrance_SetSavewarpEntrance(void);
void Entrance_SetWarpSongEntrance(void);
void Entrance_OverrideBlueWarp(void);
void Entrance_OverrideCutsceneEntrance(uint16_t cutsceneCmd);
void Entrance_HandleEponaState(void);

View File

@ -87,6 +87,7 @@ static s16 grottoExitList[NUM_GROTTOS] = {0};
static s16 grottoLoadList[NUM_GROTTOS] = {0};
static s8 grottoId = 0xFF;
static s8 lastEntranceType = NOT_GROTTO;
static u8 overridingNextEntrance = false;
// Initialize both lists so that each index refers to itself. An index referring
// to itself means that the entrance is not shuffled. Indices will be overwritten
@ -111,24 +112,20 @@ void Grotto_SetLoadOverride(s16 originalIndex, s16 overrideIndex) {
}
static void Grotto_SetupReturnInfo(GrottoReturnInfo grotto, RespawnMode respawnMode) {
// Set necessary grotto return data to the Entrance Point, so that voiding out and setting FW work correctly
gSaveContext.respawn[respawnMode].entranceIndex = grotto.entranceIndex;
gSaveContext.respawn[respawnMode].roomIndex = grotto.room;
if (false /*mixGrottos == ON*/ || false /*decoupledEntrances == ON*/) {
// Set necessary grotto return data to the Entrance Point, so that voiding out and setting FW work correctly
gSaveContext.respawn[respawnMode].entranceIndex = grotto.entranceIndex;
gSaveContext.respawn[respawnMode].roomIndex = grotto.room;
gSaveContext.respawn[respawnMode].playerParams = 0x04FF; // exiting grotto with no initial camera focus
}
gSaveContext.respawn[respawnMode].yaw = grotto.angle;
gSaveContext.respawn[respawnMode].pos = grotto.pos;
//TODO If Mixed Entrance Pools or decoupled entrances are active, set these flags to 0 instead of restoring them
if (false /*mixGrottos == ON*/ || false /*decoupledEntrances == ON*/) {
gSaveContext.respawn[respawnMode].tempSwchFlags = 0;
gSaveContext.respawn[respawnMode].tempCollectFlags = 0;
} else {
gSaveContext.respawn[respawnMode].tempSwchFlags = gSaveContext.respawn[RESPAWN_MODE_RETURN].tempSwchFlags;
gSaveContext.respawn[respawnMode].tempCollectFlags = gSaveContext.respawn[RESPAWN_MODE_RETURN].tempCollectFlags;
}
gSaveContext.respawn[respawnMode].yaw = grotto.angle;
gSaveContext.respawn[respawnMode].pos = grotto.pos;
// If Mixed Entrance Pools or decoupled entrances are active, set these flags to 0 instead of restoring them
if (Randomizer_GetSettingValue(RSK_MIX_GROTTO_ENTRANCES) || Randomizer_GetSettingValue(RSK_DECOUPLED_ENTRANCES)) {
gSaveContext.respawn[respawnMode].tempSwchFlags = 0;
gSaveContext.respawn[respawnMode].tempCollectFlags = 0;
} else {
gSaveContext.respawn[respawnMode].tempSwchFlags = gSaveContext.respawn[RESPAWN_MODE_RETURN].tempSwchFlags;
gSaveContext.respawn[respawnMode].tempCollectFlags = gSaveContext.respawn[RESPAWN_MODE_RETURN].tempCollectFlags;
}
}
// Translates and overrides the passed in entrance index if it corresponds to a
@ -136,7 +133,7 @@ static void Grotto_SetupReturnInfo(GrottoReturnInfo grotto, RespawnMode respawnM
s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex) {
// Don't change anything unless grotto shuffle has been enabled
if (!Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES)) {
if (!Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES) && !Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS) && !Randomizer_GetSettingValue(RSK_SHUFFLE_WARP_SONGS)) {
return nextEntranceIndex;
}
@ -157,13 +154,18 @@ s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex) {
Grotto_SetupReturnInfo(grotto, RESPAWN_MODE_RETURN);
Grotto_SetupReturnInfo(grotto, RESPAWN_MODE_DOWN);
// When the nextEntranceIndex is determined by a dynamic exit, we have
// to set the respawn information and nextEntranceIndex manually
// When the nextEntranceIndex is determined by a dynamic exit,
// or set by Entrance_OverrideBlueWarp to mark a blue warp entrance,
// we have to set the respawn information and nextEntranceIndex manually
if (gPlayState != NULL && gPlayState->nextEntranceIndex != -1) {
gSaveContext.respawnFlag = 2;
nextEntranceIndex = grotto.entranceIndex;
gPlayState->fadeTransition = 3;
gSaveContext.nextTransitionType = 3;
} else if (gPlayState == NULL) { // Handle spawn position when loading from a save file
gSaveContext.respawnFlag = 2;
nextEntranceIndex = grotto.entranceIndex;
gSaveContext.nextTransitionType = 3;
// Otherwise return 0x7FFF and let the game handle it
} else {
nextEntranceIndex = 0x7FFF;
@ -185,6 +187,7 @@ s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex) {
lastEntranceType = NOT_GROTTO;
}
overridingNextEntrance = true;
return nextEntranceIndex;
}
@ -192,8 +195,8 @@ s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex) {
// thisx - pointer to the grotto actor
void Grotto_OverrideActorEntrance(Actor* thisx) {
// Vanilla Behavior if grottos aren't shuffled
if (!Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES)) {
// Vanilla Behavior if there's no possibility of ending up in a grotto randomly
if (!Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES) && !Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS) && !Randomizer_GetSettingValue(RSK_SHUFFLE_WARP_SONGS)) {
return;
}
@ -216,10 +219,22 @@ void Grotto_OverrideActorEntrance(Actor* thisx) {
}
}
// Set necessary flags for when warp songs/overworld spawns are shuffled to grotto return points
void Grotto_ForceGrottoReturnOnSpecialEntrance(void) {
if (lastEntranceType == GROTTO_RETURN && (Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES) || Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS) || Randomizer_GetSettingValue(RSK_SHUFFLE_WARP_SONGS))) {
gSaveContext.respawnFlag = 2;
gSaveContext.respawn[RESPAWN_MODE_RETURN].playerParams = 0x4FF;
gSaveContext.respawn[RESPAWN_MODE_RETURN].pos = grottoReturnTable[grottoId].pos;
// Clear current temp flags
gSaveContext.respawn[RESPAWN_MODE_RETURN].tempSwchFlags = 0;
gSaveContext.respawn[RESPAWN_MODE_RETURN].tempCollectFlags = 0;
}
}
// Set the respawn flag for when we want to return from a grotto entrance
// Used for Sun's Song and Game Over, which usually don't restore saved position data
void Grotto_ForceGrottoReturn(void) {
if (lastEntranceType == GROTTO_RETURN && Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES)) {
if (lastEntranceType == GROTTO_RETURN && (Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES) || Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS) || Randomizer_GetSettingValue(RSK_SHUFFLE_WARP_SONGS))) {
gSaveContext.respawnFlag = 2;
gSaveContext.respawn[RESPAWN_MODE_RETURN].playerParams = 0x0DFF;
gSaveContext.respawn[RESPAWN_MODE_RETURN].pos = grottoReturnTable[grottoId].pos;
@ -231,7 +246,7 @@ void Grotto_ForceGrottoReturn(void) {
// Used for the DMT special voids, which usually don't restore saved position data
void Grotto_ForceRegularVoidOut(void) {
if (lastEntranceType == GROTTO_RETURN && Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES)) {
if (lastEntranceType == GROTTO_RETURN && (Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES) || Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS) || Randomizer_GetSettingValue(RSK_SHUFFLE_WARP_SONGS))) {
gSaveContext.respawn[RESPAWN_MODE_DOWN] = gSaveContext.respawn[RESPAWN_MODE_RETURN];
gSaveContext.respawn[RESPAWN_MODE_DOWN].playerParams = 0x0DFF;
gSaveContext.respawn[RESPAWN_MODE_DOWN].pos = grottoReturnTable[grottoId].pos;
@ -242,13 +257,26 @@ void Grotto_ForceRegularVoidOut(void) {
// If returning to a FW point saved at a grotto exit, copy the FW data to the Grotto Return Point
// so that Sun's Song and Game Over will behave correctly
void Grotto_SetupReturnInfoOnFWReturn(void) {
if (Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES)) {
if (Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES) || Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS) || Randomizer_GetSettingValue(RSK_SHUFFLE_WARP_SONGS) &&
gSaveContext.fw.playerParams == 0x4FF) {
gSaveContext.respawn[RESPAWN_MODE_RETURN] = gSaveContext.respawn[RESPAWN_MODE_TOP];
gSaveContext.respawn[RESPAWN_MODE_RETURN].playerParams = 0x0DFF;
lastEntranceType = GROTTO_RETURN;
} else {
lastEntranceType = NOT_GROTTO;
}
}
// If a scene transition is not overridden at all (i.e. guards throwing Link out / quitting game)
// the lastEntranceType must be cleared to avoid messing up savewarps and deathwarps.
// This does not apply to void out and other respawns, which should keep the lastEntranceType.
void Grotto_SanitizeEntranceType(void) {
if (!overridingNextEntrance && gSaveContext.respawnFlag == 0) {
lastEntranceType = NOT_GROTTO;
}
overridingNextEntrance = false;
}
// Get the renamed entrance index based on the grotto contents and exit scene number
s16 Grotto_GetRenamedGrottoIndexFromOriginal(s8 content, s8 scene) {
for (s16 index = 0; index < NUM_GROTTOS; index++) {

View File

@ -25,8 +25,10 @@ void Grotto_InitExitAndLoadLists(void);
void Grotto_SetExitOverride(s16 originalIndex, s16 overrideIndex);
void Grotto_SetLoadOverride(s16 originalIndex, s16 overrideIndex);
s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex);
void Grotto_ForceGrottoReturnOnSpecialEntrance(void);
void Grotto_ForceGrottoReturn(void);
void Grotto_ForceRegularVoidOut(void);
void Grotto_SanitizeEntranceType(void);
s16 Grotto_GetRenamedGrottoIndexFromOriginal(s8 content, s8 scene);
#endif //_RANDO_GROTTO_H_

View File

@ -1992,6 +1992,9 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
} else if (Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) &&
(textId == TEXT_BUY_BOMBCHU_10_DESC || textId == TEXT_BUY_BOMBCHU_10_PROMPT)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId);
} else if (Randomizer_GetSettingValue(RSK_SHUFFLE_WARP_SONGS) &&
(textId >= TEXT_WARP_MINUET_OF_FOREST && textId <= TEXT_WARP_PRELUDE_OF_LIGHT)) {
messageEntry = OTRGlobals::Instance->gRandomizer->GetWarpSongMessage(textId, false);
}
}
if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) {

View File

@ -175,6 +175,24 @@ void SaveManager::LoadRandomizerVersion2() {
std::string ganonText;
SaveManager::Instance->LoadData("ganonText", ganonText);
memcpy(gSaveContext.ganonText, ganonText.c_str(), ganonText.length());
std::string warpMinuetText;
SaveManager::Instance->LoadData("warpMinuetText", warpMinuetText);
memcpy(gSaveContext.warpMinuetText, warpMinuetText.c_str(), warpMinuetText.length());
std::string warpBoleroText;
SaveManager::Instance->LoadData("warpBoleroText", warpBoleroText);
memcpy(gSaveContext.warpBoleroText, warpBoleroText.c_str(), warpBoleroText.length());
std::string warpSerenadeText;
SaveManager::Instance->LoadData("warpSerenadeText", warpSerenadeText);
memcpy(gSaveContext.warpSerenadeText, warpSerenadeText.c_str(), warpSerenadeText.length());
std::string warpRequiemText;
SaveManager::Instance->LoadData("warpRequiemText", warpRequiemText);
memcpy(gSaveContext.warpRequiemText, warpRequiemText.c_str(), warpRequiemText.length());
std::string warpNocturneText;
SaveManager::Instance->LoadData("warpNocturneText", warpNocturneText);
memcpy(gSaveContext.warpNocturneText, warpNocturneText.c_str(), warpNocturneText.length());
std::string warpPreludeText;
SaveManager::Instance->LoadData("warpPreludeText", warpPreludeText);
memcpy(gSaveContext.warpPreludeText, warpPreludeText.c_str(), warpPreludeText.length());
SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems);
@ -246,6 +264,12 @@ void SaveManager::SaveRandomizer() {
SaveManager::Instance->SaveData("adultAltarText", gSaveContext.adultAltarText);
SaveManager::Instance->SaveData("ganonHintText", gSaveContext.ganonHintText);
SaveManager::Instance->SaveData("ganonText", gSaveContext.ganonText);
SaveManager::Instance->SaveData("warpMinuetText", gSaveContext.warpMinuetText);
SaveManager::Instance->SaveData("warpBoleroText", gSaveContext.warpBoleroText);
SaveManager::Instance->SaveData("warpSerenadeText", gSaveContext.warpSerenadeText);
SaveManager::Instance->SaveData("warpRequiemText", gSaveContext.warpRequiemText);
SaveManager::Instance->SaveData("warpNocturneText", gSaveContext.warpNocturneText);
SaveManager::Instance->SaveData("warpPreludeText", gSaveContext.warpPreludeText);
SaveManager::Instance->SaveData("adultTradeItems", gSaveContext.adultTradeItems);

View File

@ -200,14 +200,6 @@ void Sram_OpenSave() {
// Setup the modified entrance table and entrance shuffle table for rando
if (gSaveContext.n64ddFlag) {
Entrance_Init();
if (!CVar_GetS32("gRememberSaveLocation", 0) || gSaveContext.savedSceneNum == SCENE_YOUSEI_IZUMI_TATE ||
gSaveContext.savedSceneNum == SCENE_KAKUSIANA) {
Entrance_SetSavewarpEntrance();
}
} else {
// When going from a rando save to a vanilla save within the same game instance
// we need to reset the entrance table back to its vanilla state
Entrance_ResetEntranceTable();
}
osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex);
@ -390,11 +382,18 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
break;
case RO_AGE_CHILD: //Child
gSaveContext.linkAge = 1;
gSaveContext.savedSceneNum = -1;
break;
default:
break;
}
if (Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS)) {
// Override the spawn entrance so entrance rando can take control,
// and to prevent remember save location from breaking inital spawn
gSaveContext.entranceIndex = -1;
}
int doorOfTime = Randomizer_GetSettingValue(RSK_DOOR_OF_TIME);
switch (doorOfTime) {
case RO_DOOROFTIME_OPEN:
@ -580,4 +579,8 @@ void Sram_InitSram(GameState* gameState) {
Save_Init();
func_800F6700(gSaveContext.audioSetting);
// When going from a rando save to a vanilla save within the same game instance
// we need to reset the entrance table back to its vanilla state
Entrance_ResetEntranceTable();
}

View File

@ -425,6 +425,11 @@ void DemoKankyo_KillDoorOfTimeCollision(DemoKankyo* this, PlayState* play) {
void DemoKankyo_Update(Actor* thisx, PlayState* play) {
DemoKankyo* this = (DemoKankyo*)thisx;
this->actionFunc(this, play);
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_WARP_SONGS) &&
thisx->params == 0x000F) { // Warp Song particles
Entrance_SetWarpSongEntrance();
}
}
void DemoKankyo_Draw(Actor* thisx, PlayState* play) {

View File

@ -958,7 +958,11 @@ void func_80ACC00C(EnOwl* this, PlayState* play) {
osSyncPrintf("SPOT 06 の デモがはしった\n"); // "Demo of SPOT 06 has been completed"
osSyncPrintf(VT_RST);
if (gSaveContext.n64ddFlag) {
play->nextEntranceIndex = 0x027E;
if (Randomizer_GetSettingValue(RSK_SHUFFLE_OWL_DROPS)) {
play->nextEntranceIndex = Entrance_OverrideNextIndex(0x027E);
} else {
play->nextEntranceIndex = 0x027E;
}
play->sceneLoadFlag = 0x14;
play->fadeTransition = 2;
break;
@ -969,7 +973,11 @@ void func_80ACC00C(EnOwl* this, PlayState* play) {
case 8:
case 9:
if (gSaveContext.n64ddFlag) {
play->nextEntranceIndex = 0x0554;
if (Randomizer_GetSettingValue(RSK_SHUFFLE_OWL_DROPS)) {
play->nextEntranceIndex = Entrance_OverrideNextIndex(0x0554);
} else {
play->nextEntranceIndex = 0x0554;
}
play->sceneLoadFlag = 0x14;
play->fadeTransition = 2;
break;

View File

@ -9591,6 +9591,11 @@ void Player_Init(Actor* thisx, PlayState* play2) {
s32 sp50;
s32 sp4C;
// In ER, once Link has spawned we know the scene has loaded, so we can sanitize the last known entrance type
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
Grotto_SanitizeEntranceType();
}
play->shootingGalleryStatus = play->bombchuBowlingStatus = 0;
play->playerInit = Player_InitCommon;

View File

@ -2197,6 +2197,15 @@ void FileChoose_LoadGame(GameState* thisx) {
gSaveContext.inventory.equipment ^= (gBitFlags[swordEquipMask - 1] << BOMSWAP16(gEquipShifts[EQUIP_SWORD]));
}
}
// Handle randomized spawn positions after the save context has been setup from load
// When remeber save location is on, set save warp if the save was in an a grotto, or
// the entrance index is -1 from shuffle overwarld spawn
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES) && ((!CVar_GetS32("gRememberSaveLocation", 0) ||
gSaveContext.savedSceneNum == SCENE_YOUSEI_IZUMI_TATE || gSaveContext.savedSceneNum == SCENE_KAKUSIANA) ||
(CVar_GetS32("gRememberSaveLocation", 0) && Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS) && gSaveContext.entranceIndex == -1))) {
Entrance_SetSavewarpEntrance();
}
}
static void (*gSelectModeUpdateFuncs[])(GameState*) = {