Fix rando generation crash (#5076)

Assertion failed in CreateChildAltarHints because all 3 stones were placed on fairies/beehives while those were disabled

Fix: consolidate on Context building settings dependant location lists. Overworld vs Dungeon should not operate so differently
This commit is contained in:
Philip Dubé 2025-02-21 03:37:57 +00:00 committed by GitHub
parent b6e2a995f1
commit 49c5e19041
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 12 additions and 46 deletions

View File

@ -1077,7 +1077,7 @@ static void RandomizeDungeonItems() {
//Randomize Any Dungeon and Overworld pools //Randomize Any Dungeon and Overworld pools
AssumedFill(anyDungeonItems, anyDungeonLocations, true); AssumedFill(anyDungeonItems, anyDungeonLocations, true);
AssumedFill(overworldItems, Rando::StaticData::GetOverworldLocations(), true); AssumedFill(overworldItems, ctx->overworldLocations, true);
//Randomize maps and compasses after since they're not advancement items //Randomize maps and compasses after since they're not advancement items
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) { for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {
@ -1086,7 +1086,7 @@ static void RandomizeDungeonItems() {
AssumedFill(mapAndCompassItems, anyDungeonLocations, true); AssumedFill(mapAndCompassItems, anyDungeonLocations, true);
} else if (ctx->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD)) { } else if (ctx->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD)) {
auto mapAndCompassItems = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){return i == dungeon->GetMap() || i == dungeon->GetCompass();}); auto mapAndCompassItems = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){return i == dungeon->GetMap() || i == dungeon->GetCompass();});
AssumedFill(mapAndCompassItems, Rando::StaticData::GetOverworldLocations(), true); AssumedFill(mapAndCompassItems, ctx->overworldLocations, true);
} }
} }
} }

View File

@ -695,16 +695,14 @@ std::vector<RandomizerCheck> FindItemsAndMarkHinted(std::vector<RandomizerGet> i
void CreateChildAltarHint() { void CreateChildAltarHint() {
auto ctx = Rando::Context::GetInstance(); auto ctx = Rando::Context::GetInstance();
if (!ctx->GetHint(RH_ALTAR_CHILD)->IsEnabled()){ if (!ctx->GetHint(RH_ALTAR_CHILD)->IsEnabled() && ctx->GetOption(RSK_TOT_ALTAR_HINT)){
std::vector<RandomizerCheck> stoneLocs = {}; std::vector<RandomizerCheck> stoneLocs = {};
if (ctx->GetOption(RSK_TOT_ALTAR_HINT)) {
//force marking the rewards as hinted if they are at the end of dungeons as they can be inferred //force marking the rewards as hinted if they are at the end of dungeons as they can be inferred
if (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON) || ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_VANILLA)) { if (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON) || ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_VANILLA)) {
stoneLocs = FindItemsAndMarkHinted({RG_KOKIRI_EMERALD, RG_GORON_RUBY, RG_ZORA_SAPPHIRE}, {}); stoneLocs = FindItemsAndMarkHinted({RG_KOKIRI_EMERALD, RG_GORON_RUBY, RG_ZORA_SAPPHIRE}, {});
} else { } else {
stoneLocs = FindItemsAndMarkHinted({RG_KOKIRI_EMERALD, RG_GORON_RUBY, RG_ZORA_SAPPHIRE}, {RC_ALTAR_HINT_CHILD}); stoneLocs = FindItemsAndMarkHinted({RG_KOKIRI_EMERALD, RG_GORON_RUBY, RG_ZORA_SAPPHIRE}, {RC_ALTAR_HINT_CHILD});
} }
}
std::vector<RandomizerArea> stoneAreas = {}; std::vector<RandomizerArea> stoneAreas = {};
for (auto loc : stoneLocs){ for (auto loc : stoneLocs){
if (loc != RC_UNKNOWN_CHECK) { if (loc != RC_UNKNOWN_CHECK) {

View File

@ -203,6 +203,7 @@ void Context::GenerateLocationPool() {
} }
// If we've gotten past all the conditions where an overworld location should not be // If we've gotten past all the conditions where an overworld location should not be
// shuffled, add it to the pool. // shuffled, add it to the pool.
AddLocation(location.GetRandomizerCheck(), &overworldLocations);
AddLocation(location.GetRandomizerCheck()); AddLocation(location.GetRandomizerCheck());
} else { // is a dungeon check } else { // is a dungeon check
auto* dungeon = GetDungeon(location.GetArea() - RCAREA_DEKU_TREE); auto* dungeon = GetDungeon(location.GetArea() - RCAREA_DEKU_TREE);

View File

@ -47,6 +47,7 @@ class Context {
void PlaceItemInLocation(RandomizerCheck locKey, RandomizerGet item, bool applyEffectImmediately = false, void PlaceItemInLocation(RandomizerCheck locKey, RandomizerGet item, bool applyEffectImmediately = false,
bool setHidden = false); bool setHidden = false);
std::vector<RandomizerCheck> allLocations; std::vector<RandomizerCheck> allLocations;
std::vector<RandomizerCheck> overworldLocations;
void AddLocation(RandomizerCheck loc, std::vector<RandomizerCheck>* destination = nullptr); void AddLocation(RandomizerCheck loc, std::vector<RandomizerCheck>* destination = nullptr);
template <typename Container> template <typename Container>
void AddLocations(const Container& locations, std::vector<RandomizerCheck>* destination = nullptr); void AddLocations(const Container& locations, std::vector<RandomizerCheck>* destination = nullptr);

View File

@ -229,7 +229,7 @@ namespace Rando {
if (ageSplit && !IsFish(&mCurrPondFish.second) && tableEntry.second != RC_UNKNOWN_CHECK && if (ageSplit && !IsFish(&mCurrPondFish.second) && tableEntry.second != RC_UNKNOWN_CHECK &&
(!Flags_GetRandomizerInf(OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(tableEntry.second)) || i == pondCount - 1)) { (!Flags_GetRandomizerInf(OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(tableEntry.second)) || i == pondCount - 1)) {
mCurrPondFish.second = mCurrPondFish.second = GetPondFish(params, true); mCurrPondFish.second = GetPondFish(params, true);
} }
} }
} }

View File

@ -5,7 +5,7 @@ using namespace Rando;
void RegionTable_Init_CastleGrounds() { void RegionTable_Init_CastleGrounds() {
//With multi-area support {RA_CASTLE_GROUNDS} is not strictly required anymore, as any interior here could inherit both //With multi-area support {RA_CASTLE_GROUNDS} is not strictly required anymore, as any interior here could inherit both
//{RA_HYRULE_CASTLE} and {RA_OUTSIDE_GANONS_CASTLE}, but an setting to merge the latter 2 into the former may be preffered //{RA_HYRULE_CASTLE} and {RA_OUTSIDE_GANONS_CASTLE}, but a setting to merge the latter 2 into the former may be preferred
areaTable[RR_CASTLE_GROUNDS] = Region("Castle Grounds", "Castle Grounds", {RA_CASTLE_GROUNDS}, NO_DAY_NIGHT_CYCLE, {}, {}, { areaTable[RR_CASTLE_GROUNDS] = Region("Castle Grounds", "Castle Grounds", {RA_CASTLE_GROUNDS}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits //Exits
Entrance(RR_THE_MARKET, []{return true;}), Entrance(RR_THE_MARKET, []{return true;}),

View File

@ -33,16 +33,6 @@ std::vector<RandomizerCheck> Rando::StaticData::GetOverworldFishLocations() {
return overworldFishLocations; return overworldFishLocations;
} }
std::vector<RandomizerCheck> Rando::StaticData::GetOverworldPotLocations() {
std::vector<RandomizerCheck> overworldPotLocations = {};
for (Location& location : locationTable) {
if (location.GetRCType() == RCTYPE_POT && location.IsOverworld() && location.GetRandomizerCheck() != RC_UNKNOWN_CHECK) {
overworldPotLocations.push_back(location.GetRandomizerCheck());
}
}
return overworldPotLocations;
}
std::vector<RandomizerCheck> Rando::StaticData::GetStaticHintLocations() { std::vector<RandomizerCheck> Rando::StaticData::GetStaticHintLocations() {
std::vector<RandomizerCheck> staticHintLocations = {}; std::vector<RandomizerCheck> staticHintLocations = {};
for (Location& location : locationTable) { for (Location& location : locationTable) {
@ -103,28 +93,6 @@ std::vector<RandomizerCheck> Rando::StaticData::GetShopLocations() {
return shopLocations; return shopLocations;
} }
std::vector<RandomizerCheck> Rando::StaticData::GetOverworldLocations() {
//RANDOTODO better way of filling the initial location pool, among other things.
std::vector<RandomizerCheck> overworldLocations = {};
auto ctx = Rando::Context::GetInstance();
for (Location& location : locationTable) {
if (
location.IsOverworld() &&
location.GetRandomizerCheck() != RC_UNKNOWN_CHECK &&
location.GetRandomizerCheck() != RC_TRIFORCE_COMPLETED && //not really an overworld check
location.GetRCType() != RCTYPE_FISH && // temp fix while locations are properly sorted out
location.GetRCType() != RCTYPE_POT && // Same as fish
location.GetRCType() != RCTYPE_CHEST_GAME && //this is supposed to be excluded
(ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) || location.GetRCType() != RCTYPE_ADULT_TRADE) && //trade is handled elsewhere in location pool
location.GetRCType() != RCTYPE_STATIC_HINT &&
location.GetRCType() != RCTYPE_GOSSIP_STONE //don't put items on hints
) {
overworldLocations.push_back(location.GetRandomizerCheck());
}
}
return overworldLocations;
}
std::vector<RandomizerCheck> Rando::StaticData::GetAllDungeonLocations() { std::vector<RandomizerCheck> Rando::StaticData::GetAllDungeonLocations() {
auto ctx = Rando::Context::GetInstance(); auto ctx = Rando::Context::GetInstance();
std::vector<RandomizerCheck> dungeonLocations; std::vector<RandomizerCheck> dungeonLocations;

View File

@ -35,7 +35,6 @@ class StaticData {
static std::unordered_map<std::string, uint32_t> PopulateTranslationMap(std::unordered_map<uint32_t, CustomMessage> input); static std::unordered_map<std::string, uint32_t> PopulateTranslationMap(std::unordered_map<uint32_t, CustomMessage> input);
static std::unordered_map<std::string, uint32_t> PopulateTranslationMap(std::unordered_map<uint32_t, RandomizerHintTextKey> input); static std::unordered_map<std::string, uint32_t> PopulateTranslationMap(std::unordered_map<uint32_t, RandomizerHintTextKey> input);
static std::multimap<std::tuple<s16, s16, s32>, RandomizerCheck> CheckFromActorMultimap; static std::multimap<std::tuple<s16, s16, s32>, RandomizerCheck> CheckFromActorMultimap;
static std::vector<RandomizerCheck> GetOverworldLocations();
static std::vector<RandomizerCheck> GetAllDungeonLocations(); static std::vector<RandomizerCheck> GetAllDungeonLocations();
static std::vector<RandomizerCheck> dungeonRewardLocations; static std::vector<RandomizerCheck> dungeonRewardLocations;
static std::vector<RandomizerCheck> GetShopLocations(); static std::vector<RandomizerCheck> GetShopLocations();
@ -46,7 +45,6 @@ class StaticData {
static std::vector<RandomizerCheck> GetStaticHintLocations(); static std::vector<RandomizerCheck> GetStaticHintLocations();
static std::vector<RandomizerCheck> GetPondFishLocations(); static std::vector<RandomizerCheck> GetPondFishLocations();
static std::vector<RandomizerCheck> GetOverworldFishLocations(); static std::vector<RandomizerCheck> GetOverworldFishLocations();
static std::vector<RandomizerCheck> GetOverworldPotLocations();
static std::vector<RandomizerCheck> GetOverworldFairyLocations(); static std::vector<RandomizerCheck> GetOverworldFairyLocations();
static void RegisterFishLocations(); static void RegisterFishLocations();
static void RegisterFairyLocations(); static void RegisterFairyLocations();