From 39e62697317cc58c8afd49f5f57d996d9b9bba8d Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Tue, 23 Apr 2024 10:26:59 -0400 Subject: [PATCH] Fixes bugs with spoiler file parsing (#4066) * Fix bugs with spoiler file parsing * Hopefully fix mac build issue * fix typo --- soh/soh/Enhancements/randomizer/context.cpp | 56 +++++++------------ soh/soh/Enhancements/randomizer/context.h | 2 - soh/soh/Enhancements/randomizer/item_list.cpp | 12 ++++ .../Enhancements/randomizer/location_list.cpp | 11 ++++ .../Enhancements/randomizer/randomizer.cpp | 22 +------- soh/soh/Enhancements/randomizer/settings.cpp | 2 +- soh/soh/Enhancements/randomizer/static_data.h | 4 ++ 7 files changed, 49 insertions(+), 60 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp index 5cf0dc087..3f5e09db3 100644 --- a/soh/soh/Enhancements/randomizer/context.cpp +++ b/soh/soh/Enhancements/randomizer/context.cpp @@ -20,19 +20,6 @@ namespace Rando { std::weak_ptr Context::mContext; Context::Context() { - mSpoilerfileCheckNameToEnum["Invalid Location"] = RC_UNKNOWN_CHECK; - mSpoilerfileCheckNameToEnum["Link's Pocket"] = RC_LINKS_POCKET; - - for (auto& item : StaticData::GetItemTable()) { - // Easiest way to filter out all the empty values from the array, since we still technically want the 0/RG_NONE - // entry - if (item.GetName().english.empty()) { - continue; - } - mSpoilerfileGetNameToEnum[item.GetName().english] = item.GetRandomizerGet(); - mSpoilerfileGetNameToEnum[item.GetName().french] = item.GetRandomizerGet(); - } - mSpoilerfileHintTypeNameToEnum = { { "Static", HINT_TYPE_STATIC }, { "Trial", HINT_TYPE_TRIAL }, @@ -93,9 +80,6 @@ Context::Context() { mTrials = std::make_shared(); mSettings = std::make_shared(); mFishsanity = std::make_shared(); - for (auto& location : StaticData::GetLocationTable()) { - mSpoilerfileCheckNameToEnum[location.GetName()] = location.GetRandomizerCheck(); - } } RandomizerArea Context::GetAreaFromString(std::string str) { @@ -409,22 +393,22 @@ void Context::ParseHashIconIndexesJson(nlohmann::json spoilerFileJson) { void Context::ParseItemLocationsJson(nlohmann::json spoilerFileJson) { nlohmann::json locationsJson = spoilerFileJson["locations"]; for (auto it = locationsJson.begin(); it != locationsJson.end(); ++it) { - RandomizerCheck rc = mSpoilerfileCheckNameToEnum[it.key()]; + RandomizerCheck rc = StaticData::SpoilerfileCheckNameToEnum[it.key()]; if (it->is_structured()) { nlohmann::json itemJson = *it; for (auto itemit = itemJson.begin(); itemit != itemJson.end(); ++itemit) { if (itemit.key() == "item") { - itemLocationTable[rc].SetPlacedItem(mSpoilerfileGetNameToEnum[itemit.value().get()]); + itemLocationTable[rc].SetPlacedItem(StaticData::SpoilerfileItemNameToEnum[itemit.value().get()]); } else if (itemit.key() == "price") { itemLocationTable[rc].SetCustomPrice(itemit.value().get()); } else if (itemit.key() == "model") { - overrides[rc] = ItemOverride(rc, mSpoilerfileGetNameToEnum[itemit.value().get()]); + overrides[rc] = ItemOverride(rc, StaticData::SpoilerfileItemNameToEnum[itemit.value().get()]); } else if (itemit.key() == "trickName") { overrides[rc].SetTrickName(Text(itemit.value().get())); } } } else { - itemLocationTable[rc].SetPlacedItem(mSpoilerfileGetNameToEnum[it.value().get()]); + itemLocationTable[rc].SetPlacedItem(StaticData::SpoilerfileItemNameToEnum[it.value().get()]); } } } @@ -433,23 +417,23 @@ void Context::ParseHintJson(nlohmann::json spoilerFileJson) { // Child Altar std::string childAltarText = spoilerFileJson["childAltar"]["hintText"].get(); AddHint(RH_ALTAR_CHILD, Text(childAltarText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, "Static", RA_NONE); - mEmeraldLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["emeraldLoc"]]; - mRubyLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["rubyLoc"]]; - mSapphireLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["sapphireLoc"]]; + mEmeraldLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["emeraldLoc"]]; + mRubyLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["rubyLoc"]]; + mSapphireLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["sapphireLoc"]]; // Adult Altar std::string adultAltarText = spoilerFileJson["adultAltar"]["hintText"].get(); AddHint(RH_ALTAR_ADULT, Text(adultAltarText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, "Static", RA_NONE); - mForestMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["forestMedallionLoc"].get()]; - mFireMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["fireMedallionLoc"].get()]; - mWaterMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["waterMedallionLoc"].get()]; - mShadowMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["shadowMedallionLoc"].get()]; - mSpiritMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["spiritMedallionLoc"].get()]; - mLightMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["lightMedallionLoc"].get()]; + mForestMedallionLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["forestMedallionLoc"].get()]; + mFireMedallionLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["fireMedallionLoc"].get()]; + mWaterMedallionLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["waterMedallionLoc"].get()]; + mShadowMedallionLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["shadowMedallionLoc"].get()]; + mSpiritMedallionLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["spiritMedallionLoc"].get()]; + mLightMedallionLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["lightMedallionLoc"].get()]; // Ganondorf and Sheik Light Arrow Hints std::string ganonHintText = spoilerFileJson["ganonHintText"].get(); - RandomizerCheck lightArrowLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["lightArrowHintLoc"].get()]; + RandomizerCheck lightArrowLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["lightArrowHintLoc"].get()]; std::string lightArrowRegion = spoilerFileJson["lightArrowArea"].get(); AddHint(RH_GANONDORF_HINT, Text(ganonHintText), lightArrowLoc, HINT_TYPE_STATIC, "Static", mSpoilerfileAreaNameToEnum[lightArrowRegion]); if (spoilerFileJson.contains("sheikText")) { @@ -463,7 +447,7 @@ void Context::ParseHintJson(nlohmann::json spoilerFileJson) { if (spoilerFileJson.contains("dampeText")) { std::string dampeText = spoilerFileJson["dampeText"].get(); std::string dampeRegion = spoilerFileJson["dampeRegion"].get(); - RandomizerCheck dampeHintLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["dampeHintLoc"].get()]; + RandomizerCheck dampeHintLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["dampeHintLoc"].get()]; AddHint(RH_DAMPES_DIARY, Text(dampeText), dampeHintLoc, HINT_TYPE_STATIC, "Static", mSpoilerfileAreaNameToEnum[dampeRegion]); } @@ -471,7 +455,7 @@ void Context::ParseHintJson(nlohmann::json spoilerFileJson) { if (spoilerFileJson.contains("gregText")) { std::string gregText = spoilerFileJson["gregText"].get(); std::string gregRegion = spoilerFileJson["gregRegion"].get(); - RandomizerCheck gregLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["gregLoc"].get()]; + RandomizerCheck gregLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["gregLoc"].get()]; AddHint(RH_GREG_RUPEE, Text(gregText), gregLoc, HINT_TYPE_STATIC, "Static", mSpoilerfileAreaNameToEnum[gregRegion]); } @@ -479,7 +463,7 @@ void Context::ParseHintJson(nlohmann::json spoilerFileJson) { if (spoilerFileJson.contains("sariaText")) { std::string sariaText = spoilerFileJson["sariaText"].get(); std::string sariaRegion = spoilerFileJson["sariaRegion"].get(); - RandomizerCheck sariaHintLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["sariaHintLoc"].get()]; + RandomizerCheck sariaHintLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["sariaHintLoc"].get()]; AddHint(RH_SARIA, Text(sariaText), sariaHintLoc, HINT_TYPE_STATIC, "Static", mSpoilerfileAreaNameToEnum[sariaRegion]); } @@ -487,7 +471,7 @@ void Context::ParseHintJson(nlohmann::json spoilerFileJson) { if(spoilerFileJson.contains("fishingPoleText")) { std::string fishingPoleText = spoilerFileJson["fishingPoleText"].get(); std::string fishingPoleRegion = spoilerFileJson["fishingPoleRegion"].get(); - RandomizerCheck fishingPoleHintLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["fishingPoleHintLoc"].get()]; + RandomizerCheck fishingPoleHintLoc = StaticData::SpoilerfileCheckNameToEnum[spoilerFileJson["fishingPoleHintLoc"].get()]; AddHint(RH_FISHING_POLE, Text(fishingPoleText), fishingPoleHintLoc, HINT_TYPE_STATIC, "Static", mSpoilerfileAreaNameToEnum[fishingPoleRegion]); } @@ -520,11 +504,11 @@ void Context::ParseHintJson(nlohmann::json spoilerFileJson) { // Gossip Stones nlohmann::json hintsJson = spoilerFileJson["hints"]; for (auto it = hintsJson.begin(); it != hintsJson.end(); ++it) { - RandomizerCheck gossipStoneLoc = mSpoilerfileCheckNameToEnum[it.key()]; + RandomizerCheck gossipStoneLoc = StaticData::SpoilerfileCheckNameToEnum[it.key()]; nlohmann::json hintInfo = it.value(); std::string hintText = hintInfo["hint"].get(); HintType hintType = mSpoilerfileHintTypeNameToEnum[hintInfo["type"].get()]; - RandomizerCheck hintedLocation = hintInfo.contains("location") ? mSpoilerfileCheckNameToEnum[hintInfo["location"]] : RC_UNKNOWN_CHECK; + RandomizerCheck hintedLocation = hintInfo.contains("location") ? StaticData::SpoilerfileCheckNameToEnum[hintInfo["location"]] : RC_UNKNOWN_CHECK; RandomizerArea hintedArea = hintInfo.contains("area") ? mSpoilerfileAreaNameToEnum[hintInfo["area"].get()] : RA_NONE; std::string distribution = hintInfo["distribution"].get(); AddHint(static_cast(gossipStoneLoc - RC_COLOSSUS_GOSSIP_STONE + 1), Text(hintText), hintedLocation, hintType, distribution, hintedArea); diff --git a/soh/soh/Enhancements/randomizer/context.h b/soh/soh/Enhancements/randomizer/context.h index cef9e5292..06dd44628 100644 --- a/soh/soh/Enhancements/randomizer/context.h +++ b/soh/soh/Enhancements/randomizer/context.h @@ -87,14 +87,12 @@ class Context { std::vector possibleIceTrapModels = {}; std::unordered_map iceTrapModels = {}; std::array hashIconIndexes = {}; - std::unordered_map mSpoilerfileCheckNameToEnum; bool playthroughBeatable = false; bool allLocationsReachable = false; RandomizerArea GetAreaFromString(std::string str); private: static std::weak_ptr mContext; - std::unordered_map mSpoilerfileGetNameToEnum; std::unordered_map mSpoilerfileHintTypeNameToEnum; std::unordered_map mSpoilerfileAreaNameToEnum; std::array hintTable = {}; diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp index 343f680b1..4541550e8 100644 --- a/soh/soh/Enhancements/randomizer/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/item_list.cpp @@ -8,6 +8,7 @@ using namespace Rando; std::array Rando::StaticData::itemTable; +std::unordered_map Rando::StaticData::SpoilerfileItemNameToEnum; void Rando::StaticData::InitItemTable() { auto logic = Context::GetInstance()->GetLogic(); @@ -320,6 +321,17 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_MAGIC_SINGLE] = Item(RG_MAGIC_SINGLE, Text{ "Magic Meter", "Jauge de Magie", "Magisches Messgerät" }, ITEMTYPE_ITEM, 0x8A, true, &logic->ProgressiveMagic, RHT_MAGIC_SINGLE, RG_MAGIC_SINGLE, OBJECT_GI_MAGICPOT, GID_MAGIC_SMALL, 0xE4, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); itemTable[RG_MAGIC_DOUBLE] = Item(RG_MAGIC_DOUBLE, Text{ "Enhanced Magic Meter", "Jauge de Magie améliorée", "Verbesserte Magieanzeige" }, ITEMTYPE_ITEM, 0x8A, true, &logic->ProgressiveMagic, RHT_MAGIC_DOUBLE, RG_MAGIC_DOUBLE, OBJECT_GI_MAGICPOT, GID_MAGIC_LARGE, 0xE8, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER); itemTable[RG_TRIFORCE_PIECE] = Item(RG_TRIFORCE_PIECE, Text{ "Triforce Piece", "Triforce Piece", "Triforce Piece" }, ITEMTYPE_ITEM, 0xDF, true, &logic->TriforcePieces, RHT_TRIFORCE_PIECE, RG_TRIFORCE_PIECE, OBJECT_GI_BOMB_2, GID_TRIFORCE_PIECE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + + // Init SpoilerfileItemNameToEnum + for (auto& item : itemTable) { + // Easiest way to filter out all the empty values from the array, since we still technically want the 0/RG_NONE + // entry + if (item.GetName().english.empty()) { + continue; + } + SpoilerfileItemNameToEnum[item.GetName().english] = item.GetRandomizerGet(); + SpoilerfileItemNameToEnum[item.GetName().french] = item.GetRandomizerGet(); + } } Item& Rando::StaticData::RetrieveItem(const RandomizerGet rgid) { diff --git a/soh/soh/Enhancements/randomizer/location_list.cpp b/soh/soh/Enhancements/randomizer/location_list.cpp index ea4775d46..c5418dda2 100644 --- a/soh/soh/Enhancements/randomizer/location_list.cpp +++ b/soh/soh/Enhancements/randomizer/location_list.cpp @@ -3,6 +3,8 @@ #define TWO_ACTOR_PARAMS(a, b) (abs(a) << 16) | abs(b) std::array Rando::StaticData::locationTable; +std::unordered_map Rando::StaticData::SpoilerfileCheckNameToEnum; +std::multimap, RandomizerCheck> Rando::StaticData::CheckFromActorMultimap; std::vector KF_ShopLocations = { RC_KF_SHOP_ITEM_1, RC_KF_SHOP_ITEM_2, RC_KF_SHOP_ITEM_3, RC_KF_SHOP_ITEM_4, @@ -1569,6 +1571,15 @@ void Rando::StaticData::InitLocationTable() { locationTable[RC_TRIFORCE_COMPLETED] = Location::Reward(RC_TRIFORCE_COMPLETED, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, 0x00, "Completed Triforce", "Completed Triforce", RHT_NONE, RG_NONE, {}, SpoilerCollectionCheck::None(), SpoilerCollectionCheckGroup::GROUP_NO_GROUP); // clang-format on + + // Init SpoilerfileCheckNameToEnum + SpoilerfileCheckNameToEnum["Invalid Location"] = RC_UNKNOWN_CHECK; + SpoilerfileCheckNameToEnum["Link's Pocket"] = RC_LINKS_POCKET; + + for (auto& location : locationTable) { + SpoilerfileCheckNameToEnum[location.GetName()] = location.GetRandomizerCheck(); + CheckFromActorMultimap.emplace(std::make_tuple((int16_t)location.GetActorID(), (int16_t)location.GetScene(), location.GetActorParams()), location.GetRandomizerCheck()); + } } Location* Rando::StaticData::GetLocation(RandomizerCheck locKey) { diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 3e861962b..1a4d21f7d 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -47,11 +47,8 @@ extern std::array hintTypeNames; using json = nlohmann::json; using namespace std::literals::string_literals; -std::unordered_map SpoilerfileCheckNameToEnum; -std::unordered_map SpoilerfileGetNameToEnum; std::unordered_map SpoilerfileAreaNameToEnum; std::unordered_map SpoilerfileHintTypeNameToEnum; -std::multimap, RandomizerCheck> checkFromActorMultimap; std::set excludedLocations; std::set spoilerExcludedLocations; std::set enabledTricks; @@ -129,24 +126,7 @@ static const char* frenchRupeeNames[36] = { Randomizer::Randomizer() { Rando::StaticData::InitItemTable(); Rando::StaticData::InitLocationTable(); - for (auto& location : Rando::StaticData::GetLocationTable()) { - SpoilerfileCheckNameToEnum[location.GetName()] = location.GetRandomizerCheck(); - checkFromActorMultimap.emplace(std::make_tuple((s16)location.GetActorID(), (s16)location.GetScene(), location.GetActorParams()), location.GetRandomizerCheck()); - } - SpoilerfileCheckNameToEnum["Invalid Location"] = RC_UNKNOWN_CHECK; - SpoilerfileCheckNameToEnum["Link's Pocket"] = RC_LINKS_POCKET; - for (auto& item: Rando::StaticData::GetItemTable()) { - // Easiest way to filter out all the empty values from the array, since we still technically want the 0/RG_NONE entry - if (item.GetName().english.empty()) continue; - SpoilerfileGetNameToEnum[item.GetName().english] = item.GetRandomizerGet(); - SpoilerfileGetNameToEnum[item.GetName().french] = item.GetRandomizerGet(); - EnumToSpoilerfileGetName[item.GetRandomizerGet()] = { - item.GetName().english, - item.GetName().english, - item.GetName().french, - }; - } for (auto area : rcAreaNames) { SpoilerfileAreaNameToEnum[area.second] = area.first; } @@ -1758,7 +1738,7 @@ Rando::Location* Randomizer::GetCheckObjectFromActor(s16 actorId, s16 sceneNum, return Rando::StaticData::GetLocation(specialRc); } - auto range = checkFromActorMultimap.equal_range(std::make_tuple(actorId, sceneNum, actorParams)); + auto range = Rando::StaticData::CheckFromActorMultimap.equal_range(std::make_tuple(actorId, sceneNum, actorParams)); for (auto it = range.first; it != range.second; ++it) { if ( diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index ac947d4da..b664b0898 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -2644,7 +2644,7 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { ctx->AddExcludedOptions(); for (auto it = jsonExcludedLocations.begin(); it != jsonExcludedLocations.end(); ++it) { - const RandomizerCheck rc = ctx->mSpoilerfileCheckNameToEnum[it.value()]; + const RandomizerCheck rc = StaticData::SpoilerfileCheckNameToEnum[it.value()]; ctx->GetItemLocation(rc)->GetExcludedOption()->SetSelectedIndex(RO_GENERIC_ON); } diff --git a/soh/soh/Enhancements/randomizer/static_data.h b/soh/soh/Enhancements/randomizer/static_data.h index 7650b5dc4..0e5ba4c03 100644 --- a/soh/soh/Enhancements/randomizer/static_data.h +++ b/soh/soh/Enhancements/randomizer/static_data.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "randomizerTypes.h" #include "item.h" @@ -27,6 +28,9 @@ class StaticData { static void InitLocationTable(); static Location* GetLocation(RandomizerCheck locKey); static std::array& GetLocationTable(); + static std::unordered_map SpoilerfileCheckNameToEnum; + static std::unordered_map SpoilerfileItemNameToEnum; + static std::multimap, RandomizerCheck> CheckFromActorMultimap; static std::vector overworldLocations; static std::vector dungeonRewardLocations; static std::vector> shopLocationLists;