From 051314e8b1f452cbfa62abe7decac73b8b5ae071 Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Thu, 2 Nov 2023 16:42:33 +0000 Subject: [PATCH] Refactor Hint Creation and add support for hint Copies and fixed number of hints. (#3205) * Initial implementation of no-duplicates of special hints * stupid fixes * Impa's song will no longer be hinted when you skip child zelda * fix building * Fix Loading spoiler logs causing corrupt hints, remove disabled warp song shuffle text from spoiler logs * Remove Sheik and Saria hints from the spoiler log when are not enabled * Prevent Magic hinted by Saria and Light Arrows hinted by Sheik from being hinted elsewhere unless they are locked by that item. * Prevent the Final Frogs gossip stone hint from spawning when the special final frogs hint is enabled. * Fix building after rebasing in deduplication * redelete keys.hpp * Remove Sheik and Saria hints from the spoiler log when are not enabled * Prevent the Final Frogs gossip stone hint from spawning when the special final frogs hint is enabled. * First part of copies implementation * Refactor hint system (broken) * fix building * fix obvious errors * fix fixed hints doubling after failing to place a hint * Fix bugs with hint distrabution * Split PlaceRandomHint and fix hint bugs * Merge special hint functions, move special hint text to the HintTable, expand LightArrow hint category into OtherHint category. * Fix remaining hint distribution errors * Forgot to stage dampe diary update * Restore building after conflict resolution * fix SetAllInRegionAsHinted --- .../Enhancements/randomizer/3drando/fill.cpp | 21 +- .../Enhancements/randomizer/3drando/fill.hpp | 4 +- .../randomizer/3drando/hint_list.cpp | 70 +- .../Enhancements/randomizer/3drando/hints.cpp | 864 ++++++++---------- .../Enhancements/randomizer/3drando/hints.hpp | 21 +- .../randomizer/3drando/spoiler_log.cpp | 12 +- .../Enhancements/randomizer/randomizer.cpp | 14 +- .../Enhancements/randomizer/randomizerTypes.h | 17 +- 8 files changed, 480 insertions(+), 543 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index 3f1f685be..a3db898b3 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -1098,20 +1098,13 @@ int Fill() { printf("Done"); ctx->CreateItemOverrides(); CreateEntranceOverrides(); - //Always execute ganon hint generation for the funny line - CreateGanonAndSheikText(); - CreateAltarText(); - CreateDampesDiaryText(); - CreateGregRupeeHint(); - CreateSariaText(); - if (GossipStoneHints.IsNot(HINTS_NO_HINTS)) { - printf("\x1b[10;10HCreating Hints..."); - CreateAllHints(); - printf("Done"); - } - if (ShuffleMerchants.Is(SHUFFLEMERCHANTS_HINTS)) { - CreateMerchantsHints(); - } + + //funny ganon line + Text ganonText = RandomElement(GetHintCategory(HintCategory::GanonLine)).GetText(); + CreateMessageFromTextObject(0x70CB, 0, 2, 3, AddColorsAndFormat(ganonText)); + SetGanonText(ganonText); + + CreateAllHints(); CreateWarpSongTexts(); return 1; } diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.hpp b/soh/soh/Enhancements/randomizer/3drando/fill.hpp index 0b0ab59d8..0a9f1fab2 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.hpp @@ -21,7 +21,9 @@ void ClearProgress(); void VanillaFill(); int Fill(); +std::vector GetEmptyLocations(std::vector allowedLocations); + std::vector GetAccessibleLocations(const std::vector& allowedLocations, SearchMode mode = SearchMode::ReachabilitySearch, std::string ignore = "", bool checkPoeCollectorAccess = false, - bool checkOtherEntranceAccess = false); + bool checkOtherEntranceAccess = false); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp index c8e1d4fa2..5fd267b88 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp @@ -472,7 +472,7 @@ void HintTable_Init() { Text{ "a #cow behind webs# in a grotto gifts", /*french*/ "la #vache derrière les toiles# d'une grotte donne", /*spanish*/ "una #vaca tras la telaraña# de una cueva brinda" }); - hintTable[RHT_ZR_FROGS_OCARINA_GAME] = HintText::Always( + hintTable[RHT_ZR_FROGS_OCARINA_GAME] = HintText::Sometimes( { // obscure text Text{ "an #amphibian feast# yields", /*french*/ "un #festin d'amphibiens# donne", @@ -2949,7 +2949,7 @@ void HintTable_Init() { | LIGHT ARROW LOCATION TEXT| ---------------------------*/ - hintTable[RHT_LIGHT_ARROW_LOCATION_HINT] = HintText::LightArrow({ + hintTable[RHT_LIGHT_ARROW_LOCATION_HINT] = HintText::OtherHint({ // obscure text Text{ "Ha ha ha... You'll never beat me by reflecting my lightning bolts and unleashing the arrows from ", @@ -2959,7 +2959,7 @@ void HintTable_Init() { "Ja, ja, ja... Nunca me derrotarás reflejando mis esferas de energía y desplegando la flecha de luz de " }, }); - hintTable[RHT_SHEIK_LIGHT_ARROW_HINT] = HintText::LightArrow({ + hintTable[RHT_SHEIK_LIGHT_ARROW_HINT] = HintText::OtherHint({ // obscure text Text{ "I overheard Ganondorf say that he misplaced the %yLight Arrows%w in&%r", @@ -2974,6 +2974,70 @@ void HintTable_Init() { Text{ "your pocket", /*french*/ "tes poches", /*spanish*/ "tu bolsillo" }, }); + /*-------------------------- + | OTHER HINT TEXT | + ---------------------------*/ + + hintTable[RHT_DAMPE_DIARY01] = HintText::OtherHint({ + // obscure text + Text{ + "Whoever reads this, please enter %r", + /*french*/ + "Toi qui lit ce journal, rends-toi dans %r", + /*german?*/ + "Wer immer dies liest, der möge folgenden Ort aufsuchen: %r"}, + }); + + hintTable[RHT_DAMPE_DIARY02] = HintText::OtherHint({ + // obscure text + Text{ + "%w. I will let you have my stretching, shrinking keepsake.^I'm waiting for you.&--Dampé", + /*french*/ + "%w. Et peut-être auras-tu droit à mon précieux %rtrésor%w.^Je t'attends...&--Igor", + /*german?*/ + "%w. Ihm gebe ich meinen langen, kurzen Schatz.^Ich warte!&Boris"}, + }); + + hintTable[RHT_GREG_HINT01] = HintText::OtherHint({ + // obscure text + Text{ + "By the way, if you're interested, I saw the shiniest %gGreen Rupee%w somewhere in%g ", + /*french*/ + "Au fait, si ça t'intéresse, j'ai aperçu le plus éclatant des %gRubis Verts%w quelque part à %g", + /*spanish*/ + ""}, + }); + + hintTable[RHT_GREG_HINT02] = HintText::OtherHint({ + // obscure text + Text{ + "%w.^It's said to have %rmysterious powers%w...^But then, it could just be another regular rupee.&Oh well.", + /*french*/ + "%w. On dit qu'il possède des pouvoirs mystérieux... Mais bon, ça pourrait juste être un autre rubis ordinaire.", + /*spanish*/ + ""}, + }); + + hintTable[RHT_SARIA_TEXT01] = HintText::OtherHint({ + // obscure text + Text{ + "Did you feel the %gsurge of magic%w recently? A mysterious bird told me it came from %g", + /*french*/ + "As-tu récemment ressenti une vague de %gpuissance magique%w? Un mystérieux hibou m'a dit qu'elle provenait du %g", + /*spanish*/ + ""}, + }); + + hintTable[RHT_SARIA_TEXT02] = HintText::OtherHint({ + // obscure text + Text{ + "%w.^You should check that place out, @!$C", + /*french*/ + "%w. Tu devrais aller y jeter un coup d'oeil, @!$C", + /*spanish*/ + "%w.$C"}, + }); + /*-------------------------- | GANON LINE TEXT | ---------------------------*/ diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.cpp b/soh/soh/Enhancements/randomizer/3drando/hints.cpp index f3d2051bb..f3d44dfc8 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hints.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hints.cpp @@ -20,20 +20,20 @@ using namespace Logic; using namespace Settings; using namespace Trial; -std::unordered_map hintTypeNames = { - { HINT_TYPE_TRIAL, "Trial" }, - { HINT_TYPE_ALWAYS, "Always" }, - { HINT_TYPE_WOTH, "WotH" }, - { HINT_TYPE_BARREN, "Barren" }, - { HINT_TYPE_ENTRANCE, "Entrance" }, - { HINT_TYPE_SOMETIMES, "Sometimes" }, - { HINT_TYPE_RANDOM, "Random"}, - { HINT_TYPE_ITEM, "Item" }, - { HINT_TYPE_SONG, "Song" }, - { HINT_TYPE_OVERWORLD, "Overworld" }, - { HINT_TYPE_DUNGEON, "Dungeon" }, - { HINT_TYPE_JUNK, "Junk" }, - { HINT_TYPE_NAMED_ITEM, "NamedItem" }, +std::array hintTypeNames = { + "Static", + "Trial", + "WotH", + "Barren", + "Entrance", + "Always", + "Sometimes", + "Song", + "Overworld", + "Dungeon", + "Named Item", + "Random", + "Junk" }; constexpr std::array hintSettingTable{{ @@ -43,19 +43,19 @@ constexpr std::array hintSettingTable{{ .dungeonsBarrenLimit = 1, .namedItemsRequired = false, .distTable = {{ - {.type = HINT_TYPE_TRIAL, .order = 1, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_ALWAYS, .order = 2, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_WOTH, .order = 3, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_BARREN, .order = 4, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_ENTRANCE, .order = 5, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_SOMETIMES, .order = 6, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_RANDOM, .order = 7, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_ITEM, .order = 8, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_SONG, .order = 9, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_OVERWORLD, .order = 10, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_DUNGEON, .order = 11, .weight = 0, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_JUNK, .order = 12, .weight = 99, .fixed = 0, .copies = 0}, - {.type = HINT_TYPE_NAMED_ITEM, .order = 13, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_STATIC, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_TRIAL, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_WOTH, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_BARREN, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_ENTRANCE, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_ALWAYS, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_SOMETIMES, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_SONG, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_OVERWORLD, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_DUNGEON, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_NAMED_ITEM,.weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_RANDOM, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_JUNK, .weight = 1, .fixed = 0, .copies = 1}, }}, }, @@ -65,19 +65,19 @@ constexpr std::array hintSettingTable{{ .dungeonsBarrenLimit = 1, .namedItemsRequired = true, .distTable = {{ - {.type = HINT_TYPE_TRIAL, .order = 1, .weight = 0, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_ALWAYS, .order = 2, .weight = 0, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_WOTH, .order = 3, .weight = 7, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_BARREN, .order = 4, .weight = 4, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_ENTRANCE, .order = 5, .weight = 6, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_SOMETIMES, .order = 6, .weight = 0, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_RANDOM, .order = 7, .weight = 12, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_ITEM, .order = 8, .weight = 10, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_SONG, .order = 9, .weight = 2, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_OVERWORLD, .order = 10, .weight = 4, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_DUNGEON, .order = 11, .weight = 3, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_JUNK, .order = 12, .weight = 6, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_NAMED_ITEM, .order = 13, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_STATIC, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_TRIAL, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_WOTH, .weight = 7, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_BARREN, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_ENTRANCE, .weight = 0, .fixed = 0, .copies = 1}, //not yet implemented, should be 6 weight + {.type = HINT_TYPE_ALWAYS, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_SOMETIMES, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_SONG, .weight = 2, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_OVERWORLD, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_DUNGEON, .weight = 3, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_NAMED_ITEM,.weight = 10, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_RANDOM, .weight = 12, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_JUNK, .weight = 6, .fixed = 0, .copies = 1}, //Junk is hardcoded to 1 copy to avoid fill in issues, this setting is ignored }}, }, @@ -87,19 +87,19 @@ constexpr std::array hintSettingTable{{ .dungeonsBarrenLimit = 1, .namedItemsRequired = true, .distTable = {{ - {.type = HINT_TYPE_TRIAL, .order = 1, .weight = 0, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_ALWAYS, .order = 2, .weight = 0, .fixed = 0, .copies = 2}, - {.type = HINT_TYPE_WOTH, .order = 3, .weight = 12, .fixed = 0, .copies = 2}, - {.type = HINT_TYPE_BARREN, .order = 4, .weight = 12, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_ENTRANCE, .order = 5, .weight = 4, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_SOMETIMES, .order = 6, .weight = 0, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_RANDOM, .order = 7, .weight = 8, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_ITEM, .order = 8, .weight = 8, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_SONG, .order = 9, .weight = 4, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_OVERWORLD, .order = 10, .weight = 6, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_DUNGEON, .order = 11, .weight = 6, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_JUNK, .order = 12, .weight = 0, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_NAMED_ITEM, .order = 13, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_STATIC, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_TRIAL, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_WOTH, .weight = 12, .fixed = 0, .copies = 2}, + {.type = HINT_TYPE_BARREN, .weight = 12, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_ENTRANCE, .weight = 0, .fixed = 0, .copies = 1}, //not yet implemented, should be 4 weight + {.type = HINT_TYPE_ALWAYS, .weight = 0, .fixed = 0, .copies = 2}, + {.type = HINT_TYPE_SOMETIMES, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_SONG, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_OVERWORLD, .weight = 6, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_DUNGEON, .weight = 6, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_NAMED_ITEM,.weight = 8, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_RANDOM, .weight = 8, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_JUNK, .weight = 0, .fixed = 0, .copies = 1}, }}, }, @@ -109,25 +109,23 @@ constexpr std::array hintSettingTable{{ .dungeonsBarrenLimit = 40, .namedItemsRequired = true, .distTable = {{ - {.type = HINT_TYPE_TRIAL, .order = 1, .weight = 0, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_ALWAYS, .order = 2, .weight = 0, .fixed = 0, .copies = 2}, - {.type = HINT_TYPE_WOTH, .order = 3, .weight = 15, .fixed = 0, .copies = 2}, - {.type = HINT_TYPE_BARREN, .order = 4, .weight = 15, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_ENTRANCE, .order = 5, .weight = 10, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_SOMETIMES, .order = 6, .weight = 0, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_RANDOM, .order = 7, .weight = 0, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_ITEM, .order = 8, .weight = 5, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_SONG, .order = 9, .weight = 2, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_OVERWORLD, .order = 10, .weight = 7, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_DUNGEON, .order = 11, .weight = 7, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_JUNK, .order = 12, .weight = 0, .fixed = 0, .copies = 1}, - {.type = HINT_TYPE_NAMED_ITEM, .order = 13, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_STATIC, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HINT_TYPE_TRIAL, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_WOTH, .weight = 15, .fixed = 0, .copies = 2}, + {.type = HINT_TYPE_BARREN, .weight = 15, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_ENTRANCE, .weight = 0, .fixed = 0, .copies = 1}, //not yet implemented, should be 10 weight + {.type = HINT_TYPE_ALWAYS, .weight = 0, .fixed = 0, .copies = 2}, + {.type = HINT_TYPE_SOMETIMES, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_SONG, .weight = 2, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_OVERWORLD, .weight = 7, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_DUNGEON, .weight = 7, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_NAMED_ITEM,.weight = 5, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_RANDOM, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HINT_TYPE_JUNK, .weight = 0, .fixed = 0, .copies = 1}, }}, }, }}; -std::array dungeonInfoData; - Text childAltarText; Text adultAltarText; Text ganonText; @@ -144,8 +142,10 @@ Text warpNocturneText; Text warpPreludeText; std::string lightArrowHintLoc; -std::string sariaHintLoc; std::string dampeHintLoc; +std::string gregHintLoc; +std::string sariaHintLoc; + Text& GetChildAltarText() { return childAltarText; @@ -155,6 +155,10 @@ Text& GetAdultAltarText() { return adultAltarText; } +void SetGanonText(Text text){ + ganonText = text; +} + Text& GetGanonText() { return ganonText; } @@ -211,6 +215,10 @@ std::string GetDampeHintLoc() { return dampeHintLoc; } +std::string GetGregHintLoc() { + return gregHintLoc; +} + std::string GetSariaHintLoc() { return sariaHintLoc; } @@ -260,6 +268,11 @@ uint32_t GetLocationRegionuint32_t(const RandomizerCheck location) { return GetHintRegion(Rando::Context::GetInstance()->GetItemLocation(location)->GetParentRegionKey())->hintKey; } +static std::vector GetEmptyGossipStones() { + auto emptyGossipStones = GetEmptyLocations(Rando::StaticData::gossipStoneLocations); + return emptyGossipStones; +} + static std::vector GetAccessibleGossipStones(const RandomizerCheck hintedLocation = RC_GANON) { auto ctx = Rando::Context::GetInstance(); //temporarily remove the hinted location's item, and then perform a @@ -294,7 +307,17 @@ bool IsReachableWithout(std::vector locsToCheck, RandomizerChec return true; } -static void AddHint(Text hint, const RandomizerCheck gossipStone, const std::vector& colors = {}, HintType hintType = HINT_TYPE_ITEM, const RandomizerCheck hintedLocation = RC_UNKNOWN_CHECK) { +static void SetAllInRegionAsHinted(RandomizerHintTextKey region, std::vector locations){ + auto ctx = Rando::Context::GetInstance(); + std::vector locsInRegion = FilterFromPool(locations, [region, ctx](const RandomizerCheck loc){ + return GetHintRegion(ctx->GetItemLocation(loc)->GetParentRegionKey())->hintKey == region; + }); + for(RandomizerCheck loc: locsInRegion){ + ctx->GetItemLocation(loc)->SetAsHinted(); + } +} + +static void AddHint(Text hint, const RandomizerCheck gossipStone, const std::vector& colors = {}, HintType hintType = HINT_TYPE_NAMED_ITEM, const RandomizerCheck hintedLocation = RC_UNKNOWN_CHECK) { //save hints as dummy items for writing to the spoiler log //NewItem(gossipStone, Item{RG_HINT, hint, ITEMTYPE_EVENT, GI_RUPEE_BLUE_LOSE, false, &noVariable, NONE}); //GetLocation(gossipStone)->SetPlacedItem(gossipStone); @@ -304,68 +327,104 @@ static void AddHint(Text hint, const RandomizerCheck gossipStone, const std::vec ctx->GetItemLocation(gossipStone)->SetPlacedItem(RG_HINT); } -static void CreateLocationHint(const std::vector& possibleHintLocations) { - auto ctx = Rando::Context::GetInstance(); - //return if there aren't any hintable locations or gossip stones available - if (possibleHintLocations.empty()) { - SPDLOG_DEBUG("\tNO LOCATIONS TO HINT\n\n"); - return; +static void AddHintCopies(uint8_t copies, Text hint, std::vector colours, HintType type, RandomizerCheck location = RC_UNKNOWN_CHECK, RandomizerCheck firstStone = RC_UNKNOWN_CHECK){ + if (firstStone != RC_UNKNOWN_CHECK && copies > 0){ + AddHint(hint, firstStone, colours, type, location); + copies -= 1; } - - RandomizerCheck hintedLocation = RandomElement(possibleHintLocations); - const std::vector accessibleGossipStones = GetAccessibleGossipStones(hintedLocation); - - SPDLOG_DEBUG("\tLocation: "); - SPDLOG_DEBUG(Rando::StaticData::GetLocation(hintedLocation)->GetName()); - SPDLOG_DEBUG("\n"); - - SPDLOG_DEBUG("\tItem: "); - SPDLOG_DEBUG(ctx->GetItemLocation(hintedLocation)->GetPlacedItemName().GetEnglish()); - SPDLOG_DEBUG("\n"); - - if (accessibleGossipStones.empty()) { + for(int c=0; c gossipStoneLocations; + gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); + + if (gossipStoneLocations.empty()) { + SPDLOG_DEBUG("\tNO IN LOGIC GOSSIP STONE\n\n"); + return false; } - RandomizerCheck gossipStone = RandomElement(accessibleGossipStones); - ctx->GetItemLocation(hintedLocation)->SetAsHinted(); + RandomizerCheck gossipStone = RandomElement(gossipStoneLocations); //make hint text - Text locationHintText = Rando::StaticData::GetLocation(hintedLocation)->GetHint()->GetText(); - Text itemHintText = ctx->GetItemLocation(hintedLocation)->GetPlacedItem().GetHint().GetText(); + Text finalHint; Text prefix = Hint(RHT_PREFIX).GetText(); + std::vector colours = {QM_GREEN, QM_RED}; + if (type == HINT_TYPE_WOTH){ + Text regionText = GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); + finalHint = prefix + "%r#" + regionText + "#%w" + Hint(RHT_WAY_OF_THE_HERO).GetText(); + colours = {QM_LBLUE}; + } + else if(type == HINT_TYPE_BARREN){ + Text regionText = GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); + finalHint = prefix + Hint(RHT_PLUNDERING).GetText() + "%r#" + regionText + "#%w" + Hint(RHT_FOOLISH).GetText(); + colours = {QM_PINK}; + } + else { + Text itemText = ctx->GetItemLocation(hintedLocation)->GetPlacedItem().GetHint().GetText(); + if (type >= HINT_TYPE_ALWAYS && type < HINT_TYPE_NAMED_ITEM){ + Text locationText = Rando::StaticData::GetLocation(hintedLocation)->GetHint()->GetText(); + finalHint = prefix + locationText + " #"+itemText+"#."; + } + else if (type == HINT_TYPE_NAMED_ITEM || type == HINT_TYPE_RANDOM){ + Text regionText = GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); + // RANDOTODO: reconsider dungeon vs non-dungeon item location hints when boss shuffle mixed pools happens + if (Rando::StaticData::GetLocation(hintedLocation)->IsDungeon()) { + finalHint = prefix+"%r#"+regionText+"#%w "+Hint(RHT_HOARDS).GetText()+" %g#"+itemText+"#%w."; + } else { + finalHint = prefix+"%r#"+itemText+"#%w "+Hint(RHT_CAN_BE_FOUND_AT).GetText()+" %g#"+regionText+"#%w."; + colours = {QM_RED, QM_GREEN}; + } + } + else{ + SPDLOG_DEBUG("\tINVALID HINT TYPE\n\n"); + return false; + } + } - Text finalHint = prefix + "%r" + locationHintText + " #%g" + itemHintText + "#%w."; + ctx->GetItemLocation(hintedLocation)->SetAsHinted(); + SPDLOG_DEBUG("\tMessage: "); SPDLOG_DEBUG(finalHint.english); SPDLOG_DEBUG("\n\n"); - AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}, HINT_TYPE_ITEM, hintedLocation); + AddHintCopies(copies, finalHint, colours, type, hintedLocation, gossipStone); + + return true; } -static void CreateWothHint(uint8_t* remainingDungeonWothHints) { - auto ctx = Rando::Context::GetInstance(); - // get locations that are in the current playthrough - std::vector possibleHintLocations = {}; - // iterate through playthrough locations by sphere - std::vector wothHintLocations = - FilterFromPool(ctx->wothLocations, [remainingDungeonWothHints, ctx](RandomizerCheck loc) { - return ctx->GetItemLocation(loc)->IsHintable() && // only filter hintable locations - !(ctx->GetItemLocation(loc)->IsHintedAt()) && // only filter locations that haven't been hinted at - (Rando::StaticData::GetLocation(loc)->IsOverworld() || - (Rando::StaticData::GetLocation(loc)->IsDungeon() && - (*remainingDungeonWothHints) > 0)); // make sure we haven't surpassed the woth dungeon limit - }); - AddElementsToPool(possibleHintLocations, wothHintLocations); - // If no more locations can be hinted at for woth, then just try to get another hint +static RandomizerCheck CreateRandomHint(std::vector& possibleHintLocations, uint8_t copies, HintType type) { + auto ctx = Rando::Context::GetInstance(); + + //return if there aren't any hintable locations or gossip stones available + if (GetEmptyGossipStones().size() < copies) { + SPDLOG_DEBUG("\tNOT ENOUGH GOSSIP STONES TO PLACE HINTS\n\n"); + return RC_UNKNOWN_CHECK; + } + + RandomizerCheck hintedLocation; + bool placed = false; + while (!placed){ if (possibleHintLocations.empty()) { SPDLOG_DEBUG("\tNO LOCATIONS TO HINT\n\n"); - return; + return RC_UNKNOWN_CHECK; } - RandomizerCheck hintedLocation = RandomElement(possibleHintLocations); - + hintedLocation = RandomElement(possibleHintLocations, true); //removing the location to avoid it being hinted again on fail + SPDLOG_DEBUG("\tLocation: "); SPDLOG_DEBUG(Rando::StaticData::GetLocation(hintedLocation)->GetName()); SPDLOG_DEBUG("\n"); @@ -374,147 +433,32 @@ static void CreateWothHint(uint8_t* remainingDungeonWothHints) { SPDLOG_DEBUG(ctx->GetItemLocation(hintedLocation)->GetPlacedItemName().GetEnglish()); SPDLOG_DEBUG("\n"); - // get an accessible gossip stone - const std::vector gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); - - if (gossipStoneLocations.empty()) { - SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n"); - return; - } - ctx->GetItemLocation(hintedLocation)->SetAsHinted(); - RandomizerCheck gossipStone = RandomElement(gossipStoneLocations); - - if (Rando::StaticData::GetLocation(hintedLocation)->IsDungeon()) { - *remainingDungeonWothHints -= 1; - } - - // form hint text - Text locationText = GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); - Text finalWothHint = Hint(RHT_PREFIX).GetText() + "%r#" + locationText + "#%w" + Hint(RHT_WAY_OF_THE_HERO).GetText(); - SPDLOG_DEBUG("\tMessage: "); - SPDLOG_DEBUG(finalWothHint.english); - SPDLOG_DEBUG("\n\n"); - AddHint(finalWothHint, gossipStone, { QM_LBLUE }, HINT_TYPE_WOTH, hintedLocation); + placed = CreateHint(hintedLocation, copies, type); + } + if (type == HINT_TYPE_BARREN){ + SetAllInRegionAsHinted(GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->hintKey, possibleHintLocations); + } + return hintedLocation; } -static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector& barrenLocations) { - auto ctx = Rando::Context::GetInstance(); - // remove dungeon locations if necessary - if (*remainingDungeonBarrenHints < 1) { - barrenLocations = - FilterFromPool(barrenLocations, [](const RandomizerCheck loc) { - return !(Rando::StaticData::GetLocation(loc)->IsDungeon()); - }); - } - - if (barrenLocations.empty()) { - return; - } - - RandomizerCheck hintedLocation = RandomElement(barrenLocations, true); - - SPDLOG_DEBUG("\tLocation: "); - SPDLOG_DEBUG(Rando::StaticData::GetLocation(hintedLocation)->GetName()); - SPDLOG_DEBUG("\n"); - - SPDLOG_DEBUG("\tItem: "); - SPDLOG_DEBUG(ctx->GetItemLocation(hintedLocation)->GetPlacedItemName().GetEnglish()); - SPDLOG_DEBUG("\n"); - - // get an accessible gossip stone - const std::vector gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); - if (gossipStoneLocations.empty()) { - SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n"); - return; - } - ctx->GetItemLocation(hintedLocation)->SetAsHinted(); - RandomizerCheck gossipStone = RandomElement(gossipStoneLocations); - - if (Rando::StaticData::GetLocation(hintedLocation)->IsDungeon()) { - *remainingDungeonBarrenHints -= 1; - } - - // form hint text - Text locationText = GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); - Text finalBarrenHint = - Hint(RHT_PREFIX).GetText() + Hint(RHT_PLUNDERING).GetText() + "%r#" + locationText + "#%w" + Hint(RHT_FOOLISH).GetText(); - SPDLOG_DEBUG("\tMessage: "); - SPDLOG_DEBUG(finalBarrenHint.english); - SPDLOG_DEBUG("\n\n"); - AddHint(finalBarrenHint, gossipStone, { QM_PINK }, HINT_TYPE_BARREN, hintedLocation); - - // get rid of all other locations in this same barren region - barrenLocations = FilterFromPool(barrenLocations, [hintedLocation, ctx](RandomizerCheck loc) { - return GetHintRegion(ctx->GetItemLocation(loc)->GetParentRegionKey())->hintKey != - GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->hintKey; - }); -} - -static void CreateRandomLocationHint(const bool goodItem = false) { +static std::vector FilterHintability(std::vector& locations, const bool goodItemsOnly = false, const bool dungeonsOK = true){ auto ctx = Rando::Context::GetInstance(); - const std::vector possibleHintLocations = FilterFromPool(ctx->allLocations, [goodItem, ctx](const RandomizerCheck loc) { - return ctx->GetItemLocation(loc)->IsHintable() && !(ctx->GetItemLocation(loc)->IsHintedAt()) && (!goodItem || ctx->GetItemLocation(loc)->GetPlacedItem().IsMajorItem()); + return FilterFromPool(locations, [goodItemsOnly, dungeonsOK, ctx](const RandomizerCheck loc) { + return ctx->GetItemLocation(loc)->IsHintable() && !(ctx->GetItemLocation(loc)->IsHintedAt()) && + (!goodItemsOnly || ctx->GetItemLocation(loc)->GetPlacedItem().IsMajorItem()) && (dungeonsOK || Rando::StaticData::GetLocation(loc)->IsOverworld()); }); - //If no more locations can be hinted at, then just try to get another hint - if (possibleHintLocations.empty()) { - SPDLOG_DEBUG("\tNO LOCATIONS TO HINT\n\n"); - return; - } - RandomizerCheck hintedLocation = RandomElement(possibleHintLocations); - - SPDLOG_DEBUG("\tLocation: "); - SPDLOG_DEBUG(Rando::StaticData::GetLocation(hintedLocation)->GetName()); - SPDLOG_DEBUG("\n"); - - SPDLOG_DEBUG("\tItem: "); - SPDLOG_DEBUG(ctx->GetItemLocation(hintedLocation)->GetPlacedItemName().GetEnglish()); - SPDLOG_DEBUG("\n"); - - //get an acessible gossip stone - const std::vector gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); - if (gossipStoneLocations.empty()) { - SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n"); - return; - } - ctx->GetItemLocation(hintedLocation)->SetAsHinted(); - RandomizerCheck gossipStone = RandomElement(gossipStoneLocations); - - //form hint text - Text itemText = ctx->GetItemLocation(hintedLocation)->GetPlacedItem().GetHint().GetText(); - Text locationText = GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); - // RANDOTODO: reconsider dungeon vs non-dungeon item location hints when boss shuffle mixed pools happens - if (Rando::StaticData::GetLocation(hintedLocation)->IsDungeon()) { - Text finalHint = Hint(RHT_PREFIX).GetText()+"%r#"+locationText+"#%w "+Hint(RHT_HOARDS).GetText()+" %g#"+itemText+"#%w."; - SPDLOG_DEBUG("\tMessage: "); - SPDLOG_DEBUG(finalHint.english); - SPDLOG_DEBUG("\n\n"); - AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}, HINT_TYPE_NAMED_ITEM, hintedLocation); - } else { - Text finalHint = Hint(RHT_PREFIX).GetText()+"%r#"+itemText+"#%w "+Hint(RHT_CAN_BE_FOUND_AT).GetText()+" %g#"+locationText+"#%w."; - SPDLOG_DEBUG("\tMessage: "); - SPDLOG_DEBUG(finalHint.english); - SPDLOG_DEBUG("\n\n"); - AddHint(finalHint, gossipStone, { QM_RED, QM_GREEN }, HINT_TYPE_NAMED_ITEM, hintedLocation); - } } static void CreateJunkHint() { //duplicate junk hints are possible for now const HintText junkHint = RandomElement(GetHintCategory(HintCategory::Junk)); - LogicReset(); - const std::vector gossipStones = GetAccessibleLocations(Rando::StaticData::gossipStoneLocations); - if (gossipStones.empty()) { - SPDLOG_DEBUG("\tNO GOSSIP STONES TO PLACE HINT\n\n"); - return; - } - RandomizerCheck gossipStone = RandomElement(gossipStones); Text hint = junkHint.GetText(); SPDLOG_DEBUG("\tMessage: "); SPDLOG_DEBUG(hint.english); SPDLOG_DEBUG("\n\n"); - AddHint(hint, gossipStone, { QM_PINK }, HINT_TYPE_JUNK); + AddHintCopies(1, hint, {QM_PINK}, HINT_TYPE_JUNK); } static std::vector CalculateBarrenRegions() { @@ -550,32 +494,16 @@ static std::vector CalculateBarrenRegions() { return finalBarrenLocations; } -static void CreateTrialHints() { +static void CreateTrialHints(uint8_t copies) { + Text prefix = Hint(RHT_PREFIX).GetText(); //six trials if (RandomGanonsTrials && GanonsTrialsCount.Is(6)) { - - //get a random gossip stone - auto gossipStones = GetAccessibleGossipStones(); - auto gossipStone = RandomElement(gossipStones, false); - - //make hint - auto hint = Hint(RHT_PREFIX).GetText() + Hint(RHT_SIX_TRIALS).GetText(); - AddHint(hint, gossipStone, { QM_PINK }, HINT_TYPE_TRIAL); - + AddHintCopies(copies, prefix + Hint(RHT_SIX_TRIALS).GetText(), {QM_PINK}, HINT_TYPE_TRIAL); //zero trials } else if (RandomGanonsTrials && GanonsTrialsCount.Is(0)) { - - //get a random gossip stone - auto gossipStones = GetAccessibleGossipStones(); - auto gossipStone = RandomElement(gossipStones, false); - - //make hint - auto hint = Hint(RHT_PREFIX).GetText() + Hint(RHT_ZERO_TRIALS).GetText(); - AddHint(hint, gossipStone, { QM_YELLOW }, HINT_TYPE_TRIAL); - + AddHintCopies(copies, prefix + Hint(RHT_ZERO_TRIALS).GetText(), {QM_YELLOW}, HINT_TYPE_TRIAL); //4 or 5 required trials } else if (GanonsTrialsCount.Is(5) || GanonsTrialsCount.Is(4)) { - //get skipped trials std::vector trials = {}; trials.assign(trialList.begin(), trialList.end()); @@ -583,13 +511,9 @@ static void CreateTrialHints() { //create a hint for each skipped trial for (auto& trial : skippedTrials) { - //get a random gossip stone - auto gossipStones = GetAccessibleGossipStones(); - auto gossipStone = RandomElement(gossipStones, false); - //make hint - auto hint = Hint(RHT_PREFIX).GetText()+"#"+trial->GetName()+"#"+Hint(RHT_FOUR_TO_FIVE_TRIALS).GetText(); - AddHint(hint, gossipStone, { QM_YELLOW }, HINT_TYPE_TRIAL); + auto hint = prefix+"#"+trial->GetName()+"#"+Hint(RHT_FOUR_TO_FIVE_TRIALS).GetText(); + AddHintCopies(copies, hint, {QM_YELLOW}, HINT_TYPE_TRIAL); } //1 to 3 trials } else if (GanonsTrialsCount.Value() >= 1 && GanonsTrialsCount.Value() <= 3) { @@ -600,23 +524,16 @@ static void CreateTrialHints() { //create a hint for each required trial for (auto& trial : requiredTrials) { - //get a random gossip stone - auto gossipStones = GetAccessibleGossipStones(); - auto gossipStone = RandomElement(gossipStones, false); - //make hint - auto hint = Hint(RHT_PREFIX).GetText()+"#"+trial->GetName()+"#"+Hint(RHT_ONE_TO_THREE_TRIALS).GetText(); - AddHint(hint, gossipStone, { QM_PINK }, HINT_TYPE_TRIAL); + auto hint = prefix+"#"+trial->GetName()+"#"+Hint(RHT_ONE_TO_THREE_TRIALS).GetText(); + AddHintCopies(copies, hint, {QM_PINK}, HINT_TYPE_TRIAL); } } } +//RANDOTODO clean this mess up once starting items are expanded void CreateGanonAndSheikText() { auto ctx = Rando::Context::GetInstance(); - //funny ganon line - ganonText = RandomElement(GetHintCategory(HintCategory::GanonLine)).GetText(); - CreateMessageFromTextObject(0x70CB, 0, 2, 3, AddColorsAndFormat(ganonText)); - if(Settings::LightArrowHintText){ //Get the location of the light arrows auto lightArrowLocation = FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) { @@ -838,17 +755,16 @@ void CreateAltarText() { void CreateMerchantsHints() { auto ctx = Rando::Context::GetInstance(); Text medigoronItemText = ctx->GetItemLocation(RC_GC_MEDIGORON)->GetPlacedItem().GetHint().GetText(); - Text grannyItemText = ctx->GetItemLocation(RC_KAK_GRANNYS_SHOP)->GetPlacedItem().GetHint().GetText(); + Text grannyItemText = ctx->GetItemLocation(RC_KAK_GRANNYS_SHOP)->GetPlacedItem().GetHint().GetText().Capitalize(); Text carpetSalesmanItemText = ctx->GetItemLocation(RC_WASTELAND_BOMBCHU_SALESMAN)->GetPlacedItem().GetHint().GetText(); Text carpetSalesmanItemClearText = ctx->GetItemLocation(RC_WASTELAND_BOMBCHU_SALESMAN)->GetPlacedItem().GetHint().GetClear(); - Text grannyCapitalItemText = grannyItemText.Capitalize(); Text medigoronText = Hint(RHT_MEDIGORON_DIALOG_FIRST).GetText() + medigoronItemText + Hint(RHT_MEDIGORON_DIALOG_SECOND).GetText(); - Text grannyText = grannyCapitalItemText + Hint(RHT_GRANNY_DIALOG).GetText(); + Text grannyText = grannyItemText + Hint(RHT_GRANNY_DIALOG).GetText(); Text carpetSalesmanTextOne = Hint(RHT_CARPET_SALESMAN_DIALOG_FIRST).GetText() + carpetSalesmanItemText + Hint(RHT_CARPET_SALESMAN_DIALOG_SECOND).GetText(); Text carpetSalesmanTextTwo = Hint(RHT_CARPET_SALESMAN_DIALOG_THIRD).GetText() + carpetSalesmanItemClearText + @@ -864,94 +780,24 @@ void CreateMerchantsHints() { ctx->AddHint(RH_WASTELAND_BOMBCHU_SALESMAN, carpetSalesmanTextOne, RC_WASTELAND_BOMBCHU_SALESMAN, HINT_TYPE_STATIC, GetHintRegion(RR_HAUNTED_WASTELAND)->GetHint().GetText()); } -void CreateDampesDiaryText() { +//RANDOTODO add Better Links Pocket and starting item handling once more starting items are added +void CreateSpecialItemHint(uint32_t item, std::vector hints, RandomizerHintTextKey text1, RandomizerHintTextKey text2, Text& textLoc, std::string& nameLoc, bool condition, bool yourpocket = false) { auto ctx = Rando::Context::GetInstance(); - if (!DampeHintText) { - dampesText = Text(); - dampeHintLoc = ""; - return; - } - - RandomizerGet item = RG_PROGRESSIVE_HOOKSHOT; - RandomizerCheck location = FilterFromPool(ctx->allLocations, [item, ctx](const RandomizerCheck loc) { + if(condition){ + RandomizerCheck location = FilterFromPool(ctx->allLocations, [item, ctx](const RandomizerCheck loc) { return ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == item; })[0]; - if (IsReachableWithout({RC_DAMPE_HINT},location,true)){ - ctx->GetItemLocation(location)->SetAsHinted(); - } - Text area = GetHintRegion(ctx->GetItemLocation(location)->GetParentRegionKey())->GetHint().GetText(); - Text temp1 = Text{ - "Whoever reads this, please enter %r", - "Toi qui lit ce journal, rends-toi dans %r", - "Wer immer dies liest, der möge folgenden Ort aufsuchen: %r" - }; - - Text temp2 = { - "%w. I will let you have my stretching, shrinking keepsake.^I'm waiting for you.&--Dampé", - "%w. Et peut-être auras-tu droit à mon précieux %rtrésor%w.^Je t'attends...&--Igor", - "%w. Ihm gebe ich meinen langen, kurzen Schatz.^Ich warte!&Boris" - }; - - dampesText = temp1 + area + temp2; - dampeHintLoc = Rando::StaticData::GetLocation(location)->GetName(); - ctx->AddHint(RH_DAMPES_DIARY, dampesText, location, HINT_TYPE_STATIC, area); -} - -void CreateGregRupeeHint() { - auto ctx = Rando::Context::GetInstance(); - if (!GregHintText) { - gregText = Text(); - return; - } - - RandomizerCheck location = FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) { - return ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == RG_GREG_RUPEE; - })[0]; - Text area = GetHintRegion(ctx->GetItemLocation(location)->GetParentRegionKey())->GetHint().GetText(); - if (IsReachableWithout({RC_GREG_HINT},location,true)){ - ctx->GetItemLocation(location)->SetAsHinted(); - } - - Text temp1 = Text{ - "By the way, if you're interested, I saw the shiniest %gGreen Rupee%w somewhere in%r ", - "Au fait, si ça t'intéresse, j'ai aperçu le plus éclatant des %gRubis Verts%w quelque part à %r", - "" - }; - - Text temp2 = { - "%w.^It's said to have %cmysterious powers%w...^But then, it could just be another regular rupee.&Oh well.", - "%w. On dit qu'il possède des pouvoirs mystérieux... Mais bon, ça pourrait juste être un autre rubis ordinaire.", - "" - }; - - gregText = temp1 + area + temp2; - ctx->AddHint(RH_GREG_RUPEE, gregText, location, HINT_TYPE_STATIC, area); -} - - -void CreateSariaText() { - if(Settings::SariaHintText){ - auto ctx = Rando::Context::GetInstance(); - //Get the location of a magic upgrade - auto magicLocation = FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc){return ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == RG_PROGRESSIVE_MAGIC_METER;})[0]; - sariaHintLoc = Rando::StaticData::GetLocation(magicLocation)->GetName(); - Text area = GetHintRegion(ctx->GetItemLocation(magicLocation)->GetParentRegionKey())->GetHint().GetText(); - Text temp1 = Text{ - "Did you feel the %gsurge of magic%w recently? A mysterious bird told me it came from %r", - "As-tu récemment ressenti une vague de %gpuissance magique%w? Un mystérieux hibou m'a dit qu'elle provenait du %r", - "" - }; - Text temp2 = Text{ - "%w.^You should check that place out, @!$C", - "%w. Tu devrais aller y jeter un coup d'oeil, @!$C", - "%w.$C" - }; - sariaText = temp1 + area + temp2; - - if (IsReachableWithout({RC_SARIA_SONG_HINT},magicLocation,true)){ - ctx->GetItemLocation(magicLocation)->SetAsHinted(); + if (IsReachableWithout(hints,location,true)){ + ctx->GetItemLocation(location)->SetAsHinted(); } + + Text area = GetHintRegion(ctx->GetItemLocation(location)->GetParentRegionKey())->GetHint().GetText(); + textLoc = Hint(text1).GetText() + area + Hint(text2).GetText(); + nameLoc = Rando::StaticData::GetLocation(location)->GetName(); + } else { + textLoc = Text(); + nameLoc = ""; } } @@ -1004,13 +850,134 @@ void CreateWarpSongTexts() { } } -void CreateAllHints() { + +int32_t getRandomWeight(int32_t totalWeight){ + if (totalWeight <= 1){ + return 1; + } + return Random(1,totalWeight); +} + + +static void DistrabuteHints(std::array& selected, uint8_t stoneCount, std::array distTable, bool addFixed = true){ + int32_t totalWeight = 0; + + distTable[HINT_TYPE_JUNK].copies = 1; //Junk is hardcoded to 1 copy to avoid fill in issues + + for (HintDistributionSetting setting: distTable){ + totalWeight += setting.weight; + if (addFixed){ + selected[setting.type] += setting.fixed; + stoneCount -= setting.fixed * setting.copies; + } + } + + int32_t currentWeight = getRandomWeight(totalWeight); + while(stoneCount > 0 && totalWeight > 0){ + for (uint8_t hintType = 0; hintType < HINT_TYPE_MAX; hintType++){ + currentWeight -= distTable[hintType].weight; + if (currentWeight <= 0){ + if (stoneCount >= distTable[hintType].copies){ + selected[hintType] += 1; + stoneCount -= distTable[hintType].copies; + break; + } + else { + totalWeight -= distTable[hintType].weight; + distTable[hintType].weight = 0; + break; + } + } + } + currentWeight = getRandomWeight(totalWeight); + } + //if stones are left, assign junk + if (stoneCount > 0){ + selected[HINT_TYPE_JUNK] += stoneCount; + } +} + + +uint8_t PlaceHints(std::array& selectedHints, + std::array& distTable, + uint8_t* remainingDungeonWothHints, + uint8_t* remainingDungeonBarrenHints){ + + std::vector blankList = {}; + auto ctx = Rando::Context::GetInstance(); + + std::array, HINT_TYPE_MAX> hintTypePools = { + blankList, //static, should not happen + blankList, //trial, should not happen + ctx->wothLocations, //woth + CalculateBarrenRegions(), //Barren + blankList, //enternce, not yet implemented + blankList, // always, should not happen + FilterFromPool(ctx->allLocations, [](const RandomizerCheck loc){return Rando::StaticData::GetLocation(loc)->GetHint()->GetType() == HintCategory::Sometimes;}), //sometimes + FilterFromPool(ctx->allLocations, [](const RandomizerCheck loc){return Rando::StaticData::GetLocation(loc)->IsCategory(Category::cSong);}), //songs + FilterFromPool(ctx->allLocations, [](const RandomizerCheck loc){return Rando::StaticData::GetLocation(loc)->IsOverworld();}), //overworld + FilterFromPool(ctx->allLocations, [](const RandomizerCheck loc){return Rando::StaticData::GetLocation(loc)->IsDungeon();}), //dungeon + ctx->allLocations, //Named item + ctx->allLocations, //random + blankList //junk, irrelevent + }; + + for (uint8_t hintType = 0; hintType < HINT_TYPE_MAX; hintType++){ + for (uint8_t numHint = 0; numHint < selectedHints[hintType]; numHint++){ + + SPDLOG_DEBUG("Attempting to make hint of type: "); + SPDLOG_DEBUG(hintTypeNames[hintType]); + SPDLOG_DEBUG("\n"); + + RandomizerCheck hintedLocation = RC_UNKNOWN_CHECK; + + //create the appropriate hint for the type + if (hintType == HINT_TYPE_JUNK){ + CreateJunkHint(); + } + else{ + hintTypePools[hintType] = FilterHintability(hintTypePools[hintType], (hintType == HINT_TYPE_NAMED_ITEM)); + hintedLocation = CreateRandomHint(hintTypePools[hintType], distTable[hintType].copies, (HintType)hintType); + if (hintedLocation == RC_UNKNOWN_CHECK){ //if hint failed to place + uint8_t hintsToRemove = (selectedHints[hintType] - numHint) * distTable[hintType].copies; + selectedHints[hintType] = 0; //RANDOTODO is there a better way to filter out things hinted between hintTypePools creation and now + distTable[hintType].weight = 0; + return hintsToRemove; + } + } + + switch(hintType){ + case HINT_TYPE_WOTH: + if (Rando::StaticData::GetLocation(hintedLocation)->IsDungeon()){ + *remainingDungeonWothHints -= 1; + if (*remainingDungeonWothHints <= 0){ + hintTypePools[hintType] = FilterHintability(hintTypePools[hintType], false, false); + } + } + break; + case HINT_TYPE_BARREN: + if (Rando::StaticData::GetLocation(hintedLocation)->IsDungeon()){ + *remainingDungeonBarrenHints -= 1; + if (*remainingDungeonBarrenHints <= 0){ + hintTypePools[hintType] = FilterHintability(hintTypePools[hintType], false, false); + } + } + break; + } + } + selectedHints[hintType] = 0; + } + return 0; +} + +void CreateStoneHints() { auto ctx = Rando::Context::GetInstance(); SPDLOG_DEBUG("\nNOW CREATING HINTS\n"); const HintSetting& hintSetting = hintSettingTable[Settings::HintDistribution.Value()]; + std::array distTable = hintSetting.distTable; - uint8_t remainingDungeonWothHints = hintSetting.dungeonsWothLimit; - uint8_t remainingDungeonBarrenHints = hintSetting.dungeonsBarrenLimit; + uint8_t* remainingDungeonWothHints = new uint8_t(hintSetting.dungeonsWothLimit); + uint8_t* remainingDungeonBarrenHints = new uint8_t(hintSetting.dungeonsBarrenLimit); // Apply Special hint exclusions with no requirements if (Settings::Kak10GSHintText){ @@ -1036,7 +1003,8 @@ void CreateAllHints() { } // Add 'always' location hints - if (hintSetting.distTable[static_cast(HINT_TYPE_ALWAYS)].copies > 0) { + auto alwaysCopies = distTable[static_cast(HINT_TYPE_ALWAYS)].copies; + if (alwaysCopies > 0) { // Only filter locations that had a random item placed at them (e.g. don't get cow locations if shuffle cows is // off) auto alwaysHintLocations = FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) { @@ -1054,151 +1022,47 @@ void CreateAllHints() { } } - for (RandomizerCheck location : alwaysHintLocations) { - CreateLocationHint({ location }); - } + for (RandomizerCheck location : alwaysHintLocations) { + CreateHint(location, alwaysCopies, HINT_TYPE_ALWAYS); + } } //Add 'trial' location hints - if (hintSetting.distTable[static_cast(HINT_TYPE_TRIAL)].copies > 0) { - CreateTrialHints(); + auto trialCopies = distTable[static_cast(HINT_TYPE_TRIAL)].copies; + if (trialCopies > 0) { + CreateTrialHints(trialCopies); } - //create a vector with each hint type proportional to it's weight in the distribution setting. - //ootr uses a weighted probability function to decide hint types, but selecting randomly from - //this vector will do for now - std::vector remainingHintTypes = {}; - for (HintDistributionSetting hds : hintSetting.distTable) { - remainingHintTypes.insert(remainingHintTypes.end(), hds.weight, hds.type); - } - Shuffle(remainingHintTypes); + uint8_t totalStones = GetEmptyGossipStones().size(); + std::array selectedHints = {}; + DistrabuteHints(selectedHints, totalStones, distTable); - //get barren regions - auto barrenLocations = CalculateBarrenRegions(); - - //Calculate dungeon woth/barren info - - std::vector dungeonNames = {"Deku Tree", "Dodongos Cavern", "Jabu Jabus Belly", "Forest Temple", "Fire Temple", - "Water Temple", "Spirit Temple", "Shadow Temple", "Bottom of the Well", "Ice Cavern"}; - //Get list of all barren dungeons - std::vector barrenDungeons; - for (RandomizerCheck barrenLocation : barrenLocations) { - std::string barrenRegion = GetHintRegion(ctx->GetItemLocation(barrenLocation)->GetParentRegionKey())->scene; - bool isDungeon = std::find(dungeonNames.begin(), dungeonNames.end(), barrenRegion) != dungeonNames.end(); - //If it hasn't already been added to the list and is a dungeon, add to list - if (isDungeon && std::find(barrenDungeons.begin(), barrenDungeons.end(), barrenRegion) == barrenDungeons.end()) { - barrenDungeons.push_back(barrenRegion); + while(totalStones != 0){ + totalStones = PlaceHints(selectedHints, distTable, remainingDungeonWothHints, remainingDungeonBarrenHints); + if (totalStones != 0){ + DistrabuteHints(selectedHints, totalStones, distTable, false); } } - SPDLOG_DEBUG("\nBarren Dungeons:\n"); - for (std::string barrenDungeon : barrenDungeons) { - SPDLOG_DEBUG(barrenDungeon + "\n"); - } - - //Get list of all woth dungeons - std::vector wothDungeons; - for (RandomizerCheck wothLocation : ctx->wothLocations) { - std::string wothRegion = GetHintRegion(ctx->GetItemLocation(wothLocation)->GetParentRegionKey())->scene; - bool isDungeon = std::find(dungeonNames.begin(), dungeonNames.end(), wothRegion) != dungeonNames.end(); - //If it hasn't already been added to the list and is a dungeon, add to list - if (isDungeon && std::find(wothDungeons.begin(), wothDungeons.end(), wothRegion) == wothDungeons.end()) { - wothDungeons.push_back(wothRegion); - } - } - SPDLOG_DEBUG("\nWoth Dungeons:\n"); - for (std::string wothDungeon : wothDungeons) { - SPDLOG_DEBUG(wothDungeon + "\n"); - } - - //Set DungeonInfo array for each dungeon - for (uint32_t i = 0; i < dungeonInfoData.size(); i++) { - std::string dungeonName = dungeonNames[i]; - if (std::find(barrenDungeons.begin(), barrenDungeons.end(), dungeonName) != barrenDungeons.end()) { - dungeonInfoData[i] = DungeonInfo::DUNGEON_BARREN; - } else if (std::find(wothDungeons.begin(), wothDungeons.end(), dungeonName) != wothDungeons.end()) { - dungeonInfoData[i] = DungeonInfo::DUNGEON_WOTH; - } else { - dungeonInfoData[i] = DungeonInfo::DUNGEON_NEITHER; - } - } - - //while there are still gossip stones remaining - while (FilterFromPool(Rando::StaticData::gossipStoneLocations, [ctx](const RandomizerCheck loc) { - return ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == RG_NONE; - }).size() != 0) { - // TODO: fixed hint types - - if (remainingHintTypes.empty()) { - break; - } - - // get a random hint type from the remaining hints - HintType type = RandomElement(remainingHintTypes, true); - - SPDLOG_DEBUG("Attempting to make hint of type: "); - SPDLOG_DEBUG(hintTypeNames.find(type)->second); - SPDLOG_DEBUG("\n"); - - // create the appropriate hint for the type - if (type == HINT_TYPE_WOTH) { - CreateWothHint(&remainingDungeonWothHints); - - } else if (type == HINT_TYPE_BARREN) { - CreateBarrenHint(&remainingDungeonBarrenHints, barrenLocations); - - } else if (type == HINT_TYPE_SOMETIMES) { - std::vector sometimesHintLocations = - FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) { - return ctx->GetHint(ctx->GetItemLocation(loc)->GetHintKey())->GetHintType() == HINT_TYPE_SOMETIMES && - ctx->GetItemLocation(loc)->IsHintable() && !(ctx->GetItemLocation(loc)->IsHintedAt()); - }); - CreateLocationHint(sometimesHintLocations); - - } else if (type == HINT_TYPE_RANDOM) { - CreateRandomLocationHint(); - - } else if (type == HINT_TYPE_ITEM) { - CreateRandomLocationHint(true); - - } else if (type == HINT_TYPE_SONG) { - std::vector songHintLocations = - FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) { - return Rando::StaticData::GetLocation(loc)->IsCategory(Category::cSong) && - ctx->GetItemLocation(loc)->IsHintable() && !(ctx->GetItemLocation(loc)->IsHintedAt()); - }); - CreateLocationHint(songHintLocations); - - } else if (type == HINT_TYPE_OVERWORLD) { - std::vector overworldHintLocations = - FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) { - return Rando::StaticData::GetLocation(loc)->IsOverworld() && ctx->GetItemLocation(loc)->IsHintable() && - !(ctx->GetItemLocation(loc)->IsHintedAt()); - }); - CreateLocationHint(overworldHintLocations); - - } else if (type == HINT_TYPE_DUNGEON) { - std::vector dungeonHintLocations = - FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) { - return Rando::StaticData::GetLocation(loc)->IsDungeon() && ctx->GetItemLocation(loc)->IsHintable() && - !(ctx->GetItemLocation(loc)->IsHintedAt()); - }); - CreateLocationHint(dungeonHintLocations); - - } else if (type == HINT_TYPE_JUNK) { - CreateJunkHint(); - } - } - - //If any gossip stones failed to have a hint placed on them for some reason, place a junk hint as a failsafe. - for (RandomizerCheck gossipStone : FilterFromPool(Rando::StaticData::gossipStoneLocations, [ctx](const RandomizerCheck loc) { - return ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == RG_NONE; - })) { - const HintText junkHint = RandomElement(GetHintCategory(HintCategory::Junk)); - AddHint(junkHint.GetText(), gossipStone, { QM_PINK }); - } //Getting gossip stone locations temporarily sets one location to not be reachable. //Call the function one last time to get rid of false positives on locations not //being reachable. GetAccessibleLocations({}); } + +void CreateAllHints(){ + CreateGanonAndSheikText(); + CreateAltarText(); + CreateSpecialItemHint(RG_PROGRESSIVE_HOOKSHOT, {RC_DAMPE_HINT}, RHT_DAMPE_DIARY01, RHT_DAMPE_DIARY02, dampesText, dampeHintLoc, (bool)DampeHintText); + CreateSpecialItemHint(RG_GREG_RUPEE, {RC_GREG_HINT}, RHT_GREG_HINT01, RHT_GREG_HINT02, gregText, gregHintLoc, (bool)GregHintText); + CreateSpecialItemHint(RG_PROGRESSIVE_MAGIC_METER, {RC_SARIA_SONG_HINT, RC_SONG_FROM_SARIA}, RHT_SARIA_TEXT01, RHT_SARIA_TEXT02, sariaText, sariaHintLoc, (bool)SariaHintText); + + if (ShuffleMerchants.Is(SHUFFLEMERCHANTS_HINTS)) { + CreateMerchantsHints(); + } + if (GossipStoneHints.IsNot(HINTS_NO_HINTS)) { + printf("\x1b[10;10HCreating Hints..."); + CreateStoneHints(); + printf("Done"); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.hpp b/soh/soh/Enhancements/randomizer/3drando/hints.hpp index c4261cab5..51defc8f0 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hints.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/hints.hpp @@ -12,7 +12,6 @@ struct HintDistributionSetting { HintType type; - uint8_t order; size_t weight; uint8_t fixed; uint8_t copies; @@ -42,7 +41,7 @@ enum class HintCategory { LACS, Altar, Validation, - LightArrow, + OtherHint, GanonLine, MerchantsDialogs, }; @@ -112,9 +111,9 @@ public: return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Validation}; } - static auto LightArrow(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { - return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::LightArrow}; - } //RANDOTODO Concert to generic special hints? + static auto OtherHint(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::OtherHint}; + } static auto GanonLine(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::GanonLine}; @@ -197,22 +196,17 @@ using ConditionalAlwaysHint = std::pair>; //10 dungeons as GTG and GC are excluded extern std::array dungeonInfoData; - extern std::array conditionalAlwaysHints; extern RandomizerHintTextKey GetHintRegionHintKey(const RandomizerRegion area); extern void CreateAllHints(); -extern void CreateMerchantsHints(); extern void CreateWarpSongTexts(); -extern void CreateDampesDiaryText(); -extern void CreateGregRupeeHint(); -extern void CreateSariaText(); -extern void CreateGanonAndSheikText(); -extern void CreateAltarText(); + Text& GetChildAltarText(); Text& GetAdultAltarText(); Text& GetGanonText(); +void SetGanonText(Text text); Text& GetGanonHintText(); Text& GetDampeHintText(); Text& GetGregHintText(); @@ -226,6 +220,7 @@ Text& GetWarpRequiemText(); Text& GetWarpNocturneText(); Text& GetWarpPreludeText(); -std::string GetDampeHintLoc(); std::string GetLightArrowHintLoc(); +std::string GetDampeHintLoc(); +std::string GetGregHintLoc(); std::string GetSariaHintLoc(); diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index aea9f1ebc..1f647fb54 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -37,7 +37,7 @@ using json = nlohmann::ordered_json; json jsonData; std::map hintedLocations; -extern std::unordered_map hintTypeNames; +extern std::array hintTypeNames; extern std::array hintCategoryNames; extern Area* GetHintRegion(uint32_t); @@ -775,7 +775,7 @@ static void WriteHints(int language) { } if (Settings::GregHintText){ jsonData["gregText"] = gregText; - jsonData["gregLoc"] = Rando::StaticData::GetLocation(GetItemLocation(RG_GREG_RUPEE)->GetRandomizerCheck())->GetName(); + jsonData["gregLoc"] = GetGregHintLoc(); } if (Settings::SariaHintText){ jsonData["sariaText"] = sariaText; @@ -804,16 +804,16 @@ static void WriteHints(int language) { std::string textStr = AutoFormatHintTextString(unformattedHintTextString); jsonData["hints"][Rando::StaticData::GetLocation(key)->GetName()]["hint"] = textStr; - jsonData["hints"][Rando::StaticData::GetLocation(key)->GetName()]["type"] = hintTypeNames.find(hintType)->second; - if (hintType == HINT_TYPE_ITEM || hintType == HINT_TYPE_NAMED_ITEM || hintType == HINT_TYPE_WOTH) { + jsonData["hints"][Rando::StaticData::GetLocation(key)->GetName()]["type"] = hintTypeNames[(int)hintType]; + if ((hintType >= HINT_TYPE_ALWAYS && hintType < HINT_TYPE_JUNK) || hintType == HINT_TYPE_WOTH) { jsonData["hints"][Rando::StaticData::GetLocation(key)->GetName()]["item"] = hintedLocation->GetPlacedItemName().GetEnglish(); - if (hintType != HINT_TYPE_NAMED_ITEM || hintType == HINT_TYPE_WOTH) { + if (hintType != HINT_TYPE_NAMED_ITEM) { jsonData["hints"][Rando::StaticData::GetLocation(key)->GetName()]["location"] = Rando::StaticData::GetLocation(hintedLocation->GetRandomizerCheck())->GetName(); } } if (hintType != HINT_TYPE_TRIAL && hintType != HINT_TYPE_JUNK) { - jsonData["hints"][Rando::StaticData::GetLocation(key)->GetName()]["area"] = hint->GetHintedRegion(); + jsonData["hints"][Rando::StaticData::GetLocation(key)->GetName()]["area"] = hint->GetHintedRegion(); //RANDOTODO find elegent way to capitalise this } } } diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 896b739c2..6c3fa7c38 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -36,7 +36,7 @@ extern "C" uint32_t ResourceMgr_IsGameMasterQuest(); extern "C" uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum); extern std::map rcAreaNames; -extern std::unordered_map hintTypeNames; +extern std::array hintTypeNames; using json = nlohmann::json; using namespace std::literals::string_literals; @@ -139,6 +139,18 @@ Randomizer::Randomizer() { item.GetName().french, }; } + for (auto area : rcAreaNames) { + SpoilerfileAreaNameToEnum[area.second] = area.first; + } + SpoilerfileAreaNameToEnum["Inside Ganon's Castle"] = RCAREA_GANONS_CASTLE; + SpoilerfileAreaNameToEnum["the Lost Woods"] = RCAREA_LOST_WOODS; + SpoilerfileAreaNameToEnum["the Market"] = RCAREA_MARKET; + SpoilerfileAreaNameToEnum["the Graveyard"] = RCAREA_GRAVEYARD; + SpoilerfileAreaNameToEnum["Haunted Wasteland"] = RCAREA_WASTELAND; + SpoilerfileAreaNameToEnum["outside Ganon's Castle"] = RCAREA_HYRULE_CASTLE; + for (int c = 0; c < hintTypeNames.size(); c++) { + SpoilerfileHintTypeNameToEnum[hintTypeNames[c]] = (HintType)c; + } } Sprite* Randomizer::GetSeedTexture(uint8_t index) { diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index ff2a88b7e..657034d84 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -31,23 +31,23 @@ typedef enum { } RandomizerCheckStatus; typedef enum { + HINT_TYPE_STATIC, HINT_TYPE_TRIAL, - HINT_TYPE_ALWAYS, HINT_TYPE_WOTH, // Way of the Hero HINT_TYPE_BARREN, HINT_TYPE_ENTRANCE, + HINT_TYPE_ALWAYS, HINT_TYPE_SOMETIMES, - HINT_TYPE_RANDOM, - HINT_TYPE_ITEM, HINT_TYPE_SONG, HINT_TYPE_OVERWORLD, HINT_TYPE_DUNGEON, - HINT_TYPE_JUNK, HINT_TYPE_NAMED_ITEM, - HINT_TYPE_STATIC, // For special hints, like Light Arrows or Hookshot Hints + HINT_TYPE_RANDOM, + HINT_TYPE_JUNK, HINT_TYPE_MAX } HintType; + // Check types based on main settings typedef enum { RCTYPE_STANDARD, // Base set of rando checks @@ -3182,6 +3182,13 @@ typedef enum { RHT_SHEIK_LIGHT_ARROW_HINT, // Your Pocket RHT_YOUR_POCKET, + // Other Hints + RHT_DAMPE_DIARY01, + RHT_DAMPE_DIARY02, + RHT_GREG_HINT01, + RHT_GREG_HINT02, + RHT_SARIA_TEXT01, + RHT_SARIA_TEXT02, // Ganon Line RHT_GANON_LINE01, RHT_GANON_LINE02,