diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 73d6c4634..838816997 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -996,7 +996,7 @@ void RegisterAltTrapTypes() { void RegisterRandomizerSheikSpawn() { GameInteractor::Instance->RegisterGameHook([]() { if (!gPlayState) return; - bool canSheik = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIAL_COUNT) != RO_GANONS_TRIALS_SKIP && + bool canSheik = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIAL_COUNT) != 0 && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LIGHT_ARROWS_HINT)); if (!IS_RANDO || !LINK_IS_ADULT || !canSheik) return; switch (gPlayState->sceneNum) { diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index b0a99d85d..3f1f685be 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -1098,6 +1098,12 @@ 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(); @@ -1106,13 +1112,6 @@ int Fill() { if (ShuffleMerchants.Is(SHUFFLEMERCHANTS_HINTS)) { CreateMerchantsHints(); } - //Always execute ganon hint generation for the funny line - CreateGanonText(); - CreateAltarText(); - CreateDampesDiaryText(); - CreateGregRupeeHint(); - CreateSheikText(); - CreateSariaText(); CreateWarpSongTexts(); return 1; } diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp index fc47069fe..c8e1d4fa2 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp @@ -48,22 +48,6 @@ void HintTable_Init() { | ALWAYS HINT TEXT | ---------------------------*/ - hintTable[RHT_ZR_FROGS_OCARINA_GAME] = HintText::Always( - { - // obscure text - Text{ "an #amphibian feast# yields", /*french*/ "un #festin d'amphibiens# donne", - /*spanish*/ "una #fiesta anfibia# brinda" }, - Text{ "the #croaking choir's magnum opus# awards", /*french*/ "la #chorale coassante# donne", - /*spanish*/ "un #coro maestro de ancas# premia" }, - Text{ "the #froggy finale# yields", /*french*/ "la #finale amphibienne# donne", - /*spanish*/ "el #gran final batracio# brinda" }, - }, - {}, - // clear text - Text{ "the final reward from the #Frogs of Zora's River# is", - /*french*/ "la dernière récompense des #grenouilles de la Rivière Zora# est", - /*spanish*/ "la recompensa final de las #ranas del Río Zora# premia" }); - hintTable[RHT_KF_LINKS_HOUSE_COW] = HintText::Always( { // obscure text @@ -488,6 +472,22 @@ 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( + { + // obscure text + Text{ "an #amphibian feast# yields", /*french*/ "un #festin d'amphibiens# donne", + /*spanish*/ "una #fiesta anfibia# brinda" }, + Text{ "the #croaking choir's magnum opus# awards", /*french*/ "la #chorale coassante# donne", + /*spanish*/ "un #coro maestro de ancas# premia" }, + Text{ "the #froggy finale# yields", /*french*/ "la #finale amphibienne# donne", + /*spanish*/ "el #gran final batracio# brinda" }, + }, + {}, + // clear text + Text{ "the final reward from the #Frogs of Zora's River# is", + /*french*/ "la dernière récompense des #grenouilles de la Rivière Zora# est", + /*spanish*/ "la recompensa final de las #ranas del Río Zora# premia" }); + hintTable[RHT_ZF_GS_HIDDEN_CAVE] = HintText::Sometimes({ // obscure text Text{ "a spider high #above the icy waters# holds", /*french*/ "l'araignée #en haut des eaux glacées# donne", @@ -2959,6 +2959,16 @@ 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({ + // obscure text + Text{ + "I overheard Ganondorf say that he misplaced the %yLight Arrows%w in&%r", + /*french*/ + "J'ai entendu dire que Ganondorf aurait caché les %yFlèches de Lumière%w dans %r", + /*spanish*/ + ""}, + }); + hintTable[RHT_YOUR_POCKET] = HintText::Exclude({ // obscure text Text{ "your pocket", /*french*/ "tes poches", /*spanish*/ "tu bolsillo" }, @@ -3193,7 +3203,7 @@ int32_t TokensRequiredBySettings() { return tokens; } -std::array conditionalAlwaysHints = { +std::array conditionalAlwaysHints = { std::make_pair(RC_MARKET_10_BIG_POES, []() { return Settings::BigPoeTargetCount.Value() >= 3; @@ -3203,9 +3213,10 @@ std::array conditionalAlwaysHints = { std::make_pair(RC_HF_OCARINA_OF_TIME_ITEM, []() { return StonesRequiredBySettings() < 2; }), std::make_pair(RC_SHEIK_IN_KAKARIKO, []() { return MedallionsRequiredBySettings() < 5; }), std::make_pair(RC_DMT_TRADE_CLAIM_CHECK, []() { return false; }), - std::make_pair(RC_KAK_30_GOLD_SKULLTULA_REWARD, []() { return TokensRequiredBySettings() < 30; }), - std::make_pair(RC_KAK_40_GOLD_SKULLTULA_REWARD, []() { return TokensRequiredBySettings() < 40; }), - std::make_pair(RC_KAK_50_GOLD_SKULLTULA_REWARD, []() { return TokensRequiredBySettings() < 50; }) + std::make_pair(RC_KAK_30_GOLD_SKULLTULA_REWARD, []() { return TokensRequiredBySettings() < 30 && !Settings::Kak30GSHintText; }), + std::make_pair(RC_KAK_40_GOLD_SKULLTULA_REWARD, []() { return TokensRequiredBySettings() < 40 && !Settings::Kak40GSHintText; }), + std::make_pair(RC_KAK_50_GOLD_SKULLTULA_REWARD, []() { return TokensRequiredBySettings() < 50 && !Settings::Kak50GSHintText; }), + std::make_pair(RC_ZR_FROGS_OCARINA_GAME, []() { return !Settings::FrogsHintText; }), }; const HintText& Hint(const RandomizerHintTextKey hintKey) { diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.cpp b/soh/soh/Enhancements/randomizer/3drando/hints.cpp index e0ae47dd0..f3d2051bb 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hints.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hints.cpp @@ -275,6 +275,25 @@ static std::vector GetAccessibleGossipStones(const RandomizerCh return accessibleGossipStones; } +bool IsReachableWithout(std::vector locsToCheck, RandomizerCheck excludedCheck, bool resetAfter = true){ + //temporarily remove the hinted location's item, and then perform a + //reachability search for this check + auto ctx = Rando::Context::GetInstance(); + RandomizerGet originalItem = ctx->GetItemLocation(excludedCheck)->GetPlacedRandomizerGet(); + ctx->GetItemLocation(excludedCheck)->SetPlacedItem(RG_NONE); + LogicReset(); + const auto rechableWithout = GetAccessibleLocations(locsToCheck); + ctx->GetItemLocation(excludedCheck)->SetPlacedItem(originalItem); + if (resetAfter){ + //if resetAfter is on, reset logic we are done + LogicReset(); + } + if (rechableWithout.empty()) { + return false; + } + 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) { //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}); @@ -479,10 +498,6 @@ static void CreateRandomLocationHint(const bool goodItem = false) { } } -static void CreateGoodItemHint() { - CreateRandomLocationHint(true); -} - static void CreateJunkHint() { //duplicate junk hints are possible for now const HintText junkHint = RandomElement(GetHintCategory(HintCategory::Junk)); @@ -596,41 +611,56 @@ static void CreateTrialHints() { } } -void CreateGanonText() { +void CreateGanonAndSheikText() { auto ctx = Rando::Context::GetInstance(); //funny ganon line ganonText = RandomElement(GetHintCategory(HintCategory::GanonLine)).GetText(); CreateMessageFromTextObject(0x70CB, 0, 2, 3, AddColorsAndFormat(ganonText)); - //Get the location of the light arrows - auto lightArrowLocation = FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) { + if(Settings::LightArrowHintText){ + //Get the location of the light arrows + auto lightArrowLocation = FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) { return ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == RG_LIGHT_ARROWS; - }); + }); + Text lightArrowArea = GetHintRegion(ctx->GetItemLocation(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText(); + std::vector locsToCheck = {RC_GANONDORF_HINT}; + - //If there is no light arrow location, it was in the player's inventory at the start - auto hint = Hint(RHT_LIGHT_ARROW_LOCATION_HINT); - if (lightArrowLocation.empty()) { - ganonHintText = hint.GetText()+Hint(RHT_YOUR_POCKET).GetText(); - lightArrowHintLoc = "Link's Pocket"; - } else { - ganonHintText = - hint.GetText() + "%r" + - GetHintRegion(ctx->GetItemLocation(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText(); + //If there is no light arrow location, it was in the player's inventory at the start + auto hint = Hint(RHT_LIGHT_ARROW_LOCATION_HINT); + if (lightArrowLocation.empty()) { + ganonHintText = hint.GetText()+Hint(RHT_YOUR_POCKET).GetText(); + lightArrowHintLoc = "Link's Pocket"; + } else { + ganonHintText = hint.GetText() + "%r" + lightArrowArea; lightArrowHintLoc = Rando::StaticData::GetLocation(lightArrowLocation[0])->GetName(); - } - ganonHintText = ganonHintText + "!"; + } + ganonHintText = ganonHintText + "!"; + CreateMessageFromTextObject(0x70CC, 0, 2, 3, AddColorsAndFormat(ganonHintText)); + ctx->AddHint(RH_GANONDORF_HINT, ganonHintText, lightArrowLocation[0], HINT_TYPE_STATIC, GetHintRegion(ctx->GetItemLocation(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText()); - CreateMessageFromTextObject(0x70CC, 0, 2, 3, AddColorsAndFormat(ganonHintText)); - ctx->AddHint(RH_GANONDORF_HINT, ganonHintText, lightArrowLocation[0], HINT_TYPE_STATIC, GetHintRegion(ctx->GetItemLocation(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText()); + if(!Settings::GanonsTrialsCount.Is(0)){ + sheikText = Hint(RHT_SHEIK_LIGHT_ARROW_HINT).GetText() + lightArrowArea + "%w."; + locsToCheck = {RC_GANONDORF_HINT, RC_SHEIK_HINT_GC, RC_SHEIK_HINT_MQ_GC}; + } + + if (IsReachableWithout(locsToCheck,lightArrowLocation[0],true)){ + ctx->GetItemLocation(lightArrowLocation[0])->SetAsHinted(); + } + } } //Find the location which has the given itemKey and create the generic altar text for the reward -static Text BuildDungeonRewardText(const RandomizerGet itemKey) { +static Text BuildDungeonRewardText(const RandomizerGet itemKey, bool isChild) { auto ctx = Rando::Context::GetInstance(); + RandomizerCheck altarLoc = RC_ALTAR_HINT_ADULT; + if(isChild){altarLoc = RC_ALTAR_HINT_CHILD;} RandomizerCheck location = FilterFromPool(ctx->allLocations, [itemKey, ctx](const RandomizerCheck loc) { return ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == itemKey; })[0]; - ctx->GetItemLocation(location)->SetAsHinted(); + if (IsReachableWithout({altarLoc}, location, true) || ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON)){ //RANDOTODO check if works properly + ctx->GetItemLocation(location)->SetAsHinted(); + } std::string rewardString = "$" + std::to_string(itemKey - RG_KOKIRI_EMERALD); @@ -760,11 +790,11 @@ void CreateAltarText() { childAltarText = Hint(RHT_SPIRITUAL_STONE_TEXT_START).GetText()+"^"+ //Spiritual Stones (StartingKokiriEmerald.Value() ? Text{ "##", "##", "##" } - : BuildDungeonRewardText(RG_KOKIRI_EMERALD)) + + : BuildDungeonRewardText(RG_KOKIRI_EMERALD, true)) + (StartingGoronRuby.Value() ? Text{ "##", "##", "##" } - : BuildDungeonRewardText(RG_GORON_RUBY)) + + : BuildDungeonRewardText(RG_GORON_RUBY, true)) + (StartingZoraSapphire.Value() ? Text{ "##", "##", "##" } - : BuildDungeonRewardText(RG_ZORA_SAPPHIRE)) + + : BuildDungeonRewardText(RG_ZORA_SAPPHIRE, true)) + //How to open Door of Time, the event trigger is necessary to read the altar multiple times BuildDoorOfTimeText(); } else { @@ -780,17 +810,17 @@ void CreateAltarText() { adultAltarText = adultAltarText + //Medallion Areas (StartingLightMedallion.Value() ? Text{ "##", "##", "##" } - : BuildDungeonRewardText(RG_LIGHT_MEDALLION)) + + : BuildDungeonRewardText(RG_LIGHT_MEDALLION, false)) + (StartingForestMedallion.Value() ? Text{ "##", "##", "##" } - : BuildDungeonRewardText(RG_FOREST_MEDALLION)) + + : BuildDungeonRewardText(RG_FOREST_MEDALLION, false)) + (StartingFireMedallion.Value() ? Text{ "##", "##", "##" } - : BuildDungeonRewardText(RG_FIRE_MEDALLION)) + + : BuildDungeonRewardText(RG_FIRE_MEDALLION, false)) + (StartingWaterMedallion.Value() ? Text{ "##", "##", "##" } - : BuildDungeonRewardText(RG_WATER_MEDALLION)) + + : BuildDungeonRewardText(RG_WATER_MEDALLION, false)) + (StartingSpiritMedallion.Value() ? Text{ "##", "##", "##" } - : BuildDungeonRewardText(RG_SPIRIT_MEDALLION)) + + : BuildDungeonRewardText(RG_SPIRIT_MEDALLION, false)) + (StartingShadowMedallion.Value() ? Text{ "##", "##", "##" } - : BuildDungeonRewardText(RG_SHADOW_MEDALLION)); + : BuildDungeonRewardText(RG_SHADOW_MEDALLION, false)); } adultAltarText = adultAltarText + //Bridge requirement @@ -846,6 +876,10 @@ void CreateDampesDiaryText() { 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", @@ -875,6 +909,9 @@ void CreateGregRupeeHint() { 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 ", @@ -892,38 +929,30 @@ void CreateGregRupeeHint() { ctx->AddHint(RH_GREG_RUPEE, gregText, location, HINT_TYPE_STATIC, area); } -void CreateSheikText() { - auto ctx = Rando::Context::GetInstance(); - //Get the location of the light arrows - auto lightArrowLocation = FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc){return ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == RG_LIGHT_ARROWS;}); - lightArrowHintLoc = Rando::StaticData::GetLocation(lightArrowLocation[0])->GetName(); - Text area = GetHintRegion(ctx->GetItemLocation(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText(); - Text temp1 = Text{ - "I overheard Ganondorf say that he misplaced the %yLight Arrows%w in&%r", - "J'ai entendu dire que Ganondorf aurait caché les %yFlèches de Lumière%w dans %r", - "" - }; - Text temp2 = Text{"%w.", "%w.", "%w."}; - sheikText = temp1 + area + temp2; -} void CreateSariaText() { - 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;}); - sariaHintLoc = Rando::StaticData::GetLocation(magicLocation[0])->GetName(); - Text area = GetHintRegion(ctx->GetItemLocation(magicLocation[0])->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(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(); + } + } } @@ -983,6 +1012,29 @@ void CreateAllHints() { uint8_t remainingDungeonWothHints = hintSetting.dungeonsWothLimit; uint8_t remainingDungeonBarrenHints = hintSetting.dungeonsBarrenLimit; + // Apply Special hint exclusions with no requirements + if (Settings::Kak10GSHintText){ + ctx->GetItemLocation(RC_KAK_10_GOLD_SKULLTULA_REWARD)->SetAsHinted(); + } + if (Settings::Kak20GSHintText){ + ctx->GetItemLocation(RC_KAK_20_GOLD_SKULLTULA_REWARD)->SetAsHinted(); + } + if (Settings::Kak30GSHintText){ + ctx->GetItemLocation(RC_KAK_30_GOLD_SKULLTULA_REWARD)->SetAsHinted(); + } + if (Settings::Kak40GSHintText){ + ctx->GetItemLocation(RC_KAK_40_GOLD_SKULLTULA_REWARD)->SetAsHinted(); + } + if (Settings::Kak50GSHintText){ + ctx->GetItemLocation(RC_KAK_50_GOLD_SKULLTULA_REWARD)->SetAsHinted(); + } + if (Settings::FrogsHintText){ + ctx->GetItemLocation(RC_ZR_FROGS_OCARINA_GAME)->SetAsHinted(); + } + if (Settings::skipChildZelda){ + ctx->GetItemLocation(RC_SONG_FROM_IMPA)->SetAsHinted(); + } + // Add 'always' location hints if (hintSetting.distTable[static_cast(HINT_TYPE_ALWAYS)].copies > 0) { // Only filter locations that had a random item placed at them (e.g. don't get cow locations if shuffle cows is @@ -990,14 +1042,14 @@ void CreateAllHints() { auto alwaysHintLocations = FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) { return ((Rando::StaticData::GetLocation(loc)->GetHint()->GetType() == HintCategory::Always) || // If we have Rainbow Bridge set to Greg, add a hint for where Greg is - (Bridge.Is(RAINBOWBRIDGE_GREG) && !GregHintText && + (Bridge.Is(RAINBOWBRIDGE_GREG) && ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == RG_GREG_RUPEE)) && ctx->GetItemLocation(loc)->IsHintable() && !(ctx->GetItemLocation(loc)->IsHintedAt()); }); for (auto& hint : conditionalAlwaysHints) { RandomizerCheck loc = hint.first; - if (hint.second() && ctx->GetItemLocation(loc)->IsHintable() && !ctx->GetItemLocation(loc)->IsHintedAt()) { + if (hint.second() && ctx->GetItemLocation(loc)->IsHintable()) { alwaysHintLocations.push_back(loc); } } @@ -1106,7 +1158,7 @@ void CreateAllHints() { CreateRandomLocationHint(); } else if (type == HINT_TYPE_ITEM) { - CreateGoodItemHint(); + CreateRandomLocationHint(true); } else if (type == HINT_TYPE_SONG) { std::vector songHintLocations = diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.hpp b/soh/soh/Enhancements/randomizer/3drando/hints.hpp index ea942909c..c4261cab5 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hints.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/hints.hpp @@ -114,7 +114,7 @@ public: 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 GanonLine(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::GanonLine}; @@ -198,7 +198,7 @@ using ConditionalAlwaysHint = std::pair>; //10 dungeons as GTG and GC are excluded extern std::array dungeonInfoData; -extern std::array conditionalAlwaysHints; +extern std::array conditionalAlwaysHints; extern RandomizerHintTextKey GetHintRegionHintKey(const RandomizerRegion area); extern void CreateAllHints(); @@ -206,9 +206,8 @@ extern void CreateMerchantsHints(); extern void CreateWarpSongTexts(); extern void CreateDampesDiaryText(); extern void CreateGregRupeeHint(); -extern void CreateSheikText(); extern void CreateSariaText(); -extern void CreateGanonText(); +extern void CreateGanonAndSheikText(); extern void CreateAltarText(); Text& GetChildAltarText(); diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp index b04bf8207..f2e227324 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp @@ -258,8 +258,9 @@ void AreaTable_Init() { //name, scene, hint text, events, locations, exits areaTable[RR_ROOT] = Area("Root", "", RHT_LINKS_POCKET, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LocationAccess(RC_LINKS_POCKET, {[]{return true;}}), - LocationAccess(RC_TRIFORCE_COMPLETED, { [] { return CanCompleteTriforce;}}), + LocationAccess(RC_LINKS_POCKET, {[]{return true;}}), + LocationAccess(RC_TRIFORCE_COMPLETED, {[]{return CanCompleteTriforce;}}), + LocationAccess(RC_SARIA_SONG_HINT, {[]{return CanPlay(SariasSong);}}), }, { //Exits Entrance(RR_ROOT_EXITS, {[]{return true;}}) diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp index b69787769..57e9f6d63 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp @@ -53,6 +53,8 @@ void AreaTable_Init_CastleTown() { areaTable[RR_TEMPLE_OF_TIME] = Area("Temple of Time", "Temple of Time", RHT_TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, {}, { //Locations LocationAccess(RC_TOT_LIGHT_ARROWS_CUTSCENE, {[]{return IsAdult && CanTriggerLACS;}}), + LocationAccess(RC_ALTAR_HINT_CHILD, {[]{return IsChild;}}), + LocationAccess(RC_ALTAR_HINT_ADULT, {[]{return IsAdult;}}), }, { //Exits Entrance(RR_TOT_ENTRANCE, {[]{return true;}}), @@ -231,6 +233,7 @@ void AreaTable_Init_CastleTown() { areaTable[RR_MARKET_TREASURE_CHEST_GAME] = Area("Market Treasure Chest Game", "Market Treasure Chest Game", RHT_NONE, NO_DAY_NIGHT_CYCLE, {}, { //Locations + LocationAccess(RC_GREG_HINT, {[]{return true;}}), LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_REWARD, {[]{return (CanUse(RG_LENS_OF_TRUTH) && !ShuffleChestMinigame) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 6)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1));}}), LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 2)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp index 3aa73962f..9df23eedd 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp @@ -22,7 +22,10 @@ void AreaTable_Init_GanonsCastle() { | VANILLA DUNGEON | ---------------------------*/ if (Dungeon::GanonsCastle.IsVanilla()) { - areaTable[RR_GANONS_CASTLE_LOBBY] = Area("Ganon's Castle Lobby", "Ganon's Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + areaTable[RR_GANONS_CASTLE_LOBBY] = Area("Ganon's Castle Lobby", "Ganon's Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(RC_SHEIK_HINT_GC, {[]{return true;}}), + }, { //Exits Entrance(RR_GANONS_CASTLE_ENTRYWAY, {[]{return true;}}), Entrance(RR_GANONS_CASTLE_FOREST_TRIAL, {[]{return true;}}), @@ -121,7 +124,10 @@ void AreaTable_Init_GanonsCastle() { | MASTER QUEST DUNGEON | ---------------------------*/ if (Dungeon::GanonsCastle.IsMQ()) { - areaTable[RR_GANONS_CASTLE_MQ_LOBBY] = Area("Ganon's Castle MQ Lobby", "Ganons Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + areaTable[RR_GANONS_CASTLE_MQ_LOBBY] = Area("Ganon's Castle MQ Lobby", "Ganons Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(RC_SHEIK_HINT_MQ_GC, {[]{return true;}}), + }, { //Exits Entrance(RR_GANONS_CASTLE_ENTRYWAY, {[]{return (IsAdult || (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword))));}}), Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL, {[]{return true;}}), diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp index 0c4dd31fc..5e6e46417 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp @@ -267,7 +267,10 @@ void AreaTable_Init_Kakariko() { Entrance(RR_KAK_WINDMILL, {[]{return IsAdult && CanPlay(SongOfTime);}}), }); - areaTable[RR_GRAVEYARD_DAMPES_HOUSE] = Area("Graveyard Dampes House", "Graveyard Dampes House", RHT_NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + areaTable[RR_GRAVEYARD_DAMPES_HOUSE] = Area("Graveyard Dampes House", "Graveyard Dampes House", RHT_NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(RC_DAMPE_HINT, {[]{return IsAdult;}}), + }, { //Exits Entrance(RR_THE_GRAVEYARD, {[]{return true;}}), }); diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.hpp b/soh/soh/Enhancements/randomizer/3drando/settings.hpp index a29df2a9b..6dff0bfd8 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.hpp @@ -858,6 +858,8 @@ void UpdateSettings(std::unordered_map cvarSettin extern Option HintDistribution; extern Option AltarHintText; extern Option LightArrowHintText; + extern Option SariaHintText; + extern Option FrogsHintText; extern Option DampeHintText; extern Option GregHintText; extern Option Kak10GSHintText; diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index c7f443bd8..aea9f1ebc 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -689,12 +689,15 @@ static void WriteHints(int language) { unformattedGregText = GetGregHintText().GetEnglish(); unformattedSheikText = GetSheikHintText().GetEnglish(); unformattedSariaText = GetSariaHintText().GetEnglish(); - jsonData["warpMinuetText"] = GetWarpMinuetText().GetEnglish(); - jsonData["warpBoleroText"] = GetWarpBoleroText().GetEnglish(); - jsonData["warpSerenadeText"] = GetWarpSerenadeText().GetEnglish(); - jsonData["warpRequiemText"] = GetWarpRequiemText().GetEnglish(); - jsonData["warpNocturneText"] = GetWarpNocturneText().GetEnglish(); - jsonData["warpPreludeText"] = GetWarpPreludeText().GetEnglish(); + + if (Settings::ShuffleWarpSongs){ + jsonData["warpMinuetText"] = GetWarpMinuetText().GetEnglish(); + jsonData["warpBoleroText"] = GetWarpBoleroText().GetEnglish(); + jsonData["warpSerenadeText"] = GetWarpSerenadeText().GetEnglish(); + jsonData["warpRequiemText"] = GetWarpRequiemText().GetEnglish(); + jsonData["warpNocturneText"] = GetWarpNocturneText().GetEnglish(); + jsonData["warpPreludeText"] = GetWarpPreludeText().GetEnglish(); + } jsonData["childAltar"]["hintText"] = GetChildAltarText().GetEnglish(); jsonData["adultAltar"]["hintText"] = GetAdultAltarText().GetEnglish(); break; @@ -705,12 +708,15 @@ static void WriteHints(int language) { unformattedGregText = GetGregHintText().GetFrench(); unformattedSheikText = GetSheikHintText().GetFrench(); unformattedSariaText = GetSariaHintText().GetFrench(); - jsonData["warpMinuetText"] = GetWarpMinuetText().GetFrench(); - jsonData["warpBoleroText"] = GetWarpBoleroText().GetFrench(); - jsonData["warpSerenadeText"] = GetWarpSerenadeText().GetFrench(); - jsonData["warpRequiemText"] = GetWarpRequiemText().GetFrench(); - jsonData["warpNocturneText"] = GetWarpNocturneText().GetFrench(); - jsonData["warpPreludeText"] = GetWarpPreludeText().GetFrench(); + + if (Settings::ShuffleWarpSongs){ + jsonData["warpMinuetText"] = GetWarpMinuetText().GetFrench(); + jsonData["warpBoleroText"] = GetWarpBoleroText().GetFrench(); + jsonData["warpSerenadeText"] = GetWarpSerenadeText().GetFrench(); + jsonData["warpRequiemText"] = GetWarpRequiemText().GetFrench(); + jsonData["warpNocturneText"] = GetWarpNocturneText().GetFrench(); + jsonData["warpPreludeText"] = GetWarpPreludeText().GetFrench(); + } jsonData["childAltar"]["hintText"] = GetChildAltarText().GetFrench(); jsonData["adultAltar"]["hintText"] = GetAdultAltarText().GetFrench(); break; @@ -756,16 +762,25 @@ static void WriteHints(int language) { std::string sariaText = AutoFormatHintTextString(unformattedSariaText); jsonData["ganonText"] = ganonText; - jsonData["ganonHintText"] = ganonHintText; - jsonData["lightArrowHintLoc"] = GetLightArrowHintLoc(); - jsonData["dampeText"] = dampesText; - jsonData["dampeHintLoc"] = GetDampeHintLoc(); - jsonData["gregText"] = gregText; - jsonData["gregLoc"] = - Rando::StaticData::GetLocation(GetItemLocation(RG_GREG_RUPEE)->GetRandomizerCheck())->GetName(); - jsonData["sheikText"] = sheikText; - jsonData["sariaText"] = sariaText; - jsonData["sariaHintLoc"] = GetSariaHintLoc(); + if (Settings::LightArrowHintText){ + jsonData["ganonHintText"] = ganonHintText; + jsonData["lightArrowHintLoc"] = GetLightArrowHintLoc(); + if (!Settings::GanonsTrialsCount.Is(0)){ + jsonData["sheikText"] = sheikText; + } + } + if (Settings::DampeHintText){ + jsonData["dampeText"] = dampesText; + jsonData["dampeHintLoc"] = GetDampeHintLoc(); + } + if (Settings::GregHintText){ + jsonData["gregText"] = gregText; + jsonData["gregLoc"] = Rando::StaticData::GetLocation(GetItemLocation(RG_GREG_RUPEE)->GetRandomizerCheck())->GetName(); + } + if (Settings::SariaHintText){ + jsonData["sariaText"] = sariaText; + jsonData["sariaHintLoc"] = GetSariaHintLoc(); + } if (Settings::GossipStoneHints.Is(HINTS_NO_HINTS)) { return; diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp index 8995fa06b..bf38b32fa 100644 --- a/soh/soh/Enhancements/randomizer/context.cpp +++ b/soh/soh/Enhancements/randomizer/context.cpp @@ -144,7 +144,9 @@ void Context::LocationReset() { GetItemLocation(il)->RemoveFromPool(); } - GetItemLocation(RC_GANONDORF_HINT)->RemoveFromPool(); + for (RandomizerCheck il : Rando::StaticData::otherHintLocations) { + GetItemLocation(il)->RemoveFromPool(); + } } void Context::HintReset() { diff --git a/soh/soh/Enhancements/randomizer/location.cpp b/soh/soh/Enhancements/randomizer/location.cpp index e50b21be0..f8ef0cd7f 100644 --- a/soh/soh/Enhancements/randomizer/location.cpp +++ b/soh/soh/Enhancements/randomizer/location.cpp @@ -235,11 +235,11 @@ Rando::Location Rando::Location::Reward(RandomizerCheck rc, RandomizerCheckQuest Rando::Location Rando::Location::OtherHint(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, RandomizerCheckArea area_, ActorID actorId_, - uint8_t scene_, int32_t actorParams_, uint8_t flag_, + uint8_t scene_, std::string&& shortName_, std::string&& spoilerName_, - std::vector&& categories, bool isVanillaCompletion_) { - return Location(rc, quest_, checkType_, area_, LocationType::OtherHint, actorId_, scene_, actorParams_, flag_, - std::move(shortName_), std::move(spoilerName_), RHT_NONE, RG_NONE, std::move(categories), isVanillaCompletion_); + bool isVanillaCompletion_) { + return Location(rc, quest_, checkType_, area_, LocationType::OtherHint, actorId_, scene_, 0x00, 0x00, + std::move(shortName_), std::move(spoilerName_), RHT_NONE, RG_NONE, {}, isVanillaCompletion_); } Rando::Location Rando::Location::HintStone(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckArea area_, diff --git a/soh/soh/Enhancements/randomizer/location.h b/soh/soh/Enhancements/randomizer/location.h index a1a47fd8f..c21a56166 100644 --- a/soh/soh/Enhancements/randomizer/location.h +++ b/soh/soh/Enhancements/randomizer/location.h @@ -253,9 +253,8 @@ class Location { SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP, bool isVanillaCompletion_ = false); static Location OtherHint(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, - RandomizerCheckArea area_, ActorID actorId_, uint8_t scene, int32_t actorParams_, - uint8_t flag_, std::string&& shortName_, std::string&& spoilerName_, - std::vector&& categories, bool isVanillaCompletion_ = false); + RandomizerCheckArea area_, ActorID actorId_, uint8_t scene, + std::string&& shortName_, std::string&& spoilerName_, bool isVanillaCompletion_ = false); static Location HintStone(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckArea area_, uint8_t scene, int32_t actorParams_, uint8_t flag_, std::string&& shortName_, std::string&& spoilerName_, diff --git a/soh/soh/Enhancements/randomizer/location_list.cpp b/soh/soh/Enhancements/randomizer/location_list.cpp index 3a07c3a08..fafae2661 100644 --- a/soh/soh/Enhancements/randomizer/location_list.cpp +++ b/soh/soh/Enhancements/randomizer/location_list.cpp @@ -507,6 +507,17 @@ std::vector Rando::StaticData::gossipStoneLocations = { RC_ZR_OPEN_GROTTO_GOSSIP_STONE, }; +std::vector Rando::StaticData::otherHintLocations = { + RC_GANONDORF_HINT, + RC_SHEIK_HINT_GC, + RC_SHEIK_HINT_MQ_GC, + RC_DAMPE_HINT, + RC_GREG_HINT, + RC_SARIA_SONG_HINT, + RC_ALTAR_HINT_CHILD, + RC_ALTAR_HINT_ADULT +}; + typedef enum { DUNGEON_DEKU_TREE = 0, DUNGEON_DODONGOS_CAVERN, @@ -1221,7 +1232,7 @@ void Rando::StaticData::InitLocationTable() { // Bosses Randomizer Check Randomizer Check Quest Type Area Actor ID Scene ID Params Flags Short Name Spoiler Name Hint Text Key Vanilla Item Categories Spoiler Collection Check Collection Check Group Vanilla Progression locationTable[RC_LINKS_POCKET] = Location::Reward(RC_LINKS_POCKET, RCQUEST_BOTH, RCTYPE_LINKS_POCKET, RCAREA_KOKIRI_FOREST, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, 0x00, "Link's Pocket", "Link's Pocket", RHT_LINKS_POCKET, RG_LIGHT_MEDALLION, {}, SpoilerCollectionCheck::AlwaysCollected(), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST, true); - locationTable[RC_QUEEN_GOHMA] = Location::Reward( RC_QUEEN_GOHMA, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, RCAREA_DEKU_TREE, ACTOR_DOOR_WARP1, SCENE_DEKU_TREE_BOSS, 0x00, DungeonId::DUNGEON_DEKU_TREE, "Queen Gohma", "Queen Gohma", RHT_QUEEN_GOHMA, RG_KOKIRI_EMERALD, {}, SpoilerCollectionCheck::Chest(0x11, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE, true); + locationTable[RC_QUEEN_GOHMA] = Location::Reward(RC_QUEEN_GOHMA, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, RCAREA_DEKU_TREE, ACTOR_DOOR_WARP1, SCENE_DEKU_TREE_BOSS, 0x00, DungeonId::DUNGEON_DEKU_TREE, "Queen Gohma", "Queen Gohma", RHT_QUEEN_GOHMA, RG_KOKIRI_EMERALD, {}, SpoilerCollectionCheck::Chest(0x11, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE, true); locationTable[RC_KING_DODONGO] = Location::Reward(RC_KING_DODONGO, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, RCAREA_DODONGOS_CAVERN, ACTOR_DOOR_WARP1, SCENE_DODONGOS_CAVERN_BOSS, 0x00, DungeonId::DUNGEON_DODONGOS_CAVERN, "King Dodongo", "King Dodongo", RHT_KING_DODONGO, RG_GORON_RUBY, {}, SpoilerCollectionCheck::Chest(0x12, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN, true); locationTable[RC_BARINADE] = Location::Reward(RC_BARINADE, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, RCAREA_JABU_JABUS_BELLY, ACTOR_DOOR_WARP1, SCENE_JABU_JABU_BOSS, 0x00, DungeonId::DUNGEON_JABUJABUS_BELLY, "Barinade", "Barinade", RHT_BARINADE, RG_ZORA_SAPPHIRE, {}, SpoilerCollectionCheck::Chest(0x13, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY, true); locationTable[RC_PHANTOM_GANON] = Location::Reward(RC_PHANTOM_GANON, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, RCAREA_FOREST_TEMPLE, ACTOR_DOOR_WARP1, SCENE_FOREST_TEMPLE_BOSS, 0x00, DungeonId::DUNGEON_FOREST_TEMPLE, "Phantom Ganon", "Phantom Ganon", RHT_PHANTOM_GANON, RG_FOREST_MEDALLION, {}, SpoilerCollectionCheck::Chest(0x14, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE, true); @@ -1403,7 +1414,15 @@ void Rando::StaticData::InitLocationTable() { locationTable[RC_DMC_UPPER_GROTTO_GOSSIP_STONE] = Location::HintStone(RC_DMC_UPPER_GROTTO_GOSSIP_STONE, RCQUEST_BOTH, RCAREA_DEATH_MOUNTAIN_CRATER, SCENE_GROTTOS, -23802, 0x3A, "Upper Grotto Gossip Stone", "DMC Upper Grotto Gossip Stone", {}); // Other Hints - locationTable[RC_GANONDORF_HINT] = Location::OtherHint(RC_GANONDORF_HINT, RCQUEST_BOTH, RCTYPE_GOSSIP_STONE, RCAREA_GANONS_CASTLE, ACTOR_EN_GANON_MANT, SCENE_GANON_BOSS, 0x00, 0x00, "Hint", "Ganondorf Hint", {}); + locationTable[RC_GANONDORF_HINT] = Location::OtherHint(RC_GANONDORF_HINT, RCQUEST_BOTH, RCTYPE_GOSSIP_STONE, RCAREA_GANONS_CASTLE, ACTOR_EN_GANON_MANT, SCENE_GANON_BOSS, "Ganondorf Hint", "Ganondorf Hint"); + locationTable[RC_SHEIK_HINT_GC] = Location::OtherHint(RC_SHEIK_HINT_GC, RCQUEST_VANILLA, RCTYPE_GOSSIP_STONE, RCAREA_GANONS_CASTLE, ACTOR_EN_XC, SCENE_INSIDE_GANONS_CASTLE, "Sheik Hint", "Sheik Hint in Ganons Castle"); + locationTable[RC_SHEIK_HINT_MQ_GC] = Location::OtherHint(RC_SHEIK_HINT_MQ_GC, RCQUEST_MQ, RCTYPE_GOSSIP_STONE, RCAREA_GANONS_CASTLE, ACTOR_EN_XC, SCENE_INSIDE_GANONS_CASTLE, "Sheik Hint", "Sheik Hint in MQ Ganons Castle"); + locationTable[RC_DAMPE_HINT] = Location::OtherHint(RC_DAMPE_HINT, RCQUEST_BOTH, RCTYPE_GOSSIP_STONE, RCAREA_GRAVEYARD, ACTOR_ID_MAX, SCENE_GRAVEKEEPERS_HUT, "Diary Hint", "Dampe's Diary Hint"); + locationTable[RC_GREG_HINT] = Location::OtherHint(RC_GREG_HINT, RCQUEST_BOTH, RCTYPE_GOSSIP_STONE, RCAREA_MARKET, ACTOR_EN_TAKARA_MAN, SCENE_TREASURE_BOX_SHOP, "Greg Hint", "Greg Hint"); + locationTable[RC_SARIA_SONG_HINT] = Location::OtherHint(RC_SARIA_SONG_HINT, RCQUEST_BOTH, RCTYPE_GOSSIP_STONE, RCAREA_KOKIRI_FOREST, ACTOR_ID_MAX, SCENE_ID_MAX, "Sarias Song Hint", "Magic Hint Via Saria's Song"); + locationTable[RC_ALTAR_HINT_CHILD] = Location::OtherHint(RC_ALTAR_HINT_CHILD, RCQUEST_BOTH, RCTYPE_GOSSIP_STONE, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_TEMPLE_OF_TIME, "Child Altar Hint", "ToT Child Altar Text"); + locationTable[RC_ALTAR_HINT_ADULT] = Location::OtherHint(RC_ALTAR_HINT_ADULT, RCQUEST_BOTH, RCTYPE_GOSSIP_STONE, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_TEMPLE_OF_TIME, "Adult Altar Hint", "ToT Adult Altar Text"); + 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 } diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 06112f3de..896b739c2 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -474,11 +474,15 @@ void Randomizer::LoadHintLocations(const char* spoilerFileName) { ); CustomMessageManager::Instance->CreateMessage( Randomizer::randoMiscHintsTableID, TEXT_DAMPES_DIARY, - CustomMessage(gSaveContext.dampeText, gSaveContext.dampeText, gSaveContext.dampeText) + CustomMessage(gSaveContext.dampeText, + gSaveContext.dampeText, + gSaveContext.dampeText) ); CustomMessageManager::Instance->CreateMessage( Randomizer::randoMiscHintsTableID, TEXT_CHEST_GAME_PROCEED, - CustomMessage(gSaveContext.gregHintText, gSaveContext.gregHintText, gSaveContext.gregHintText) + CustomMessage(gSaveContext.gregHintText, + gSaveContext.gregHintText, + gSaveContext.gregHintText) ); CustomMessageManager::Instance->CreateMessage( Randomizer::randoMiscHintsTableID, TEXT_FROGS_UNDERWATER, @@ -491,7 +495,6 @@ void Randomizer::LoadHintLocations(const char* spoilerFileName) { CustomMessage("{{message}}", "{{message}}", "{{message}}", TEXTBOX_TYPE_BLUE) ); - CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_WARP_RANDOM_REPLACED_TEXT, CustomMessage("Warp to&{{location}}?\x1B&%gOK&No%w\x02", "Zu {{location}}?\x1B&%gOK&No%w\x02", @@ -1289,16 +1292,34 @@ std::string FormatJsonHintText(std::string jsonHint) { formattedHintMessage.replace(start_pos, textToReplace.length(), iconString); } } + formattedHintMessage += 0x02; return formattedHintMessage; } +void ParseSpoilerHintText(json Json, std::string field, char* saveLoc, bool format, int size){ + auto jsonIter = Json.find(field); + if (jsonIter != Json.end()){ + std::string jsonText = jsonIter.value().get(); + if (format){ + jsonText = FormatJsonHintText(jsonText); + } + strncpy(saveLoc, jsonText.c_str(), size-1); + saveLoc[size - 1] = 0; + } +} + +void CheckNameToEnum(json Json, std::string field, RandomizerCheck* saveLoc){ + auto jsonIter = Json.find(field); + if (jsonIter != Json.end()){ + *saveLoc = SpoilerfileCheckNameToEnum[jsonIter.value().get()]; + }; +} + void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { std::ifstream spoilerFileStream(sanitize(spoilerFileName)); if (!spoilerFileStream) return; - bool success = false; - // Have all these use strncpy so that the null terminator is copied // and also set the last index to null for safety try { @@ -1324,64 +1345,28 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { gSaveContext.rewardCheck[7] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["spiritMedallionLoc"]]; gSaveContext.rewardCheck[8] = SpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["lightMedallionLoc"]]; - std::string ganonHintJsonText = spoilerFileJson["ganonHintText"].get(); - std::string formattedGanonHintJsonText = FormatJsonHintText(ganonHintJsonText); - strncpy(gSaveContext.ganonHintText, formattedGanonHintJsonText.c_str(), sizeof(gSaveContext.ganonHintText) - 1); - gSaveContext.ganonHintText[sizeof(gSaveContext.ganonHintText) - 1] = 0; - gSaveContext.lightArrowHintCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["lightArrowHintLoc"]]; + ParseSpoilerHintText(spoilerFileJson, "ganonHintText", gSaveContext.ganonHintText, true, sizeof(gSaveContext.ganonHintText)); + CheckNameToEnum(spoilerFileJson, "lightArrowHintLoc", &gSaveContext.lightArrowHintCheck); + ParseSpoilerHintText(spoilerFileJson, "ganonText", gSaveContext.ganonText, true, sizeof(gSaveContext.ganonText)); - std::string ganonJsonText = spoilerFileJson["ganonText"].get(); - std::string formattedGanonJsonText = FormatJsonHintText(ganonJsonText); - strncpy(gSaveContext.ganonText, formattedGanonJsonText.c_str(), sizeof(gSaveContext.ganonText) - 1); - gSaveContext.ganonText[sizeof(gSaveContext.ganonText) - 1] = 0; + ParseSpoilerHintText(spoilerFileJson, "dampeText", gSaveContext.dampeText, true, sizeof(gSaveContext.dampeText)); + CheckNameToEnum(spoilerFileJson, "dampeHintLoc", &gSaveContext.dampeCheck); - std::string dampeJsonText = spoilerFileJson["dampeText"].get(); - std::string formattedDampeJsonText = FormatJsonHintText(dampeJsonText); - strncpy(gSaveContext.dampeText, formattedDampeJsonText.c_str(), sizeof(gSaveContext.dampeText) - 1); - gSaveContext.dampeText[sizeof(gSaveContext.dampeText) - 1] = 0; - gSaveContext.dampeCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["dampeHintLoc"]]; + ParseSpoilerHintText(spoilerFileJson, "gregText", gSaveContext.gregHintText, true, sizeof(gSaveContext.gregHintText)); + CheckNameToEnum(spoilerFileJson, "gregLoc", &gSaveContext.gregCheck); - std::string gregJsonText = spoilerFileJson["gregText"].get(); - std::string formattedGregJsonText = FormatJsonHintText(gregJsonText); - strncpy(gSaveContext.gregHintText, formattedGregJsonText.c_str(), sizeof(gSaveContext.gregHintText) - 1); - gSaveContext.gregHintText[sizeof(gSaveContext.gregHintText) - 1] = 0; - gSaveContext.gregCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["gregLoc"]]; + ParseSpoilerHintText(spoilerFileJson, "sheikText", gSaveContext.sheikText, true, sizeof(gSaveContext.sheikText)); + + ParseSpoilerHintText(spoilerFileJson, "sariaText", gSaveContext.sariaText, true, sizeof(gSaveContext.sariaText)); + CheckNameToEnum(spoilerFileJson, "sariaHintLoc", &gSaveContext.sariaCheck); - std::string sheikJsonText = spoilerFileJson["sheikText"].get(); - std::string formattedSheikJsonText = FormatJsonHintText(sheikJsonText); - strncpy(gSaveContext.sheikText, formattedSheikJsonText.c_str(), sizeof(gSaveContext.sheikText) - 1); - gSaveContext.sheikText[sizeof(gSaveContext.sheikText) - 1] = 0; - gSaveContext.lightArrowHintCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["lightArrowHintLoc"]]; + ParseSpoilerHintText(spoilerFileJson, "warpMinuetText", gSaveContext.warpMinuetText, false, sizeof(gSaveContext.warpMinuetText)); + ParseSpoilerHintText(spoilerFileJson, "warpBoleroText", gSaveContext.warpBoleroText, false, sizeof(gSaveContext.warpBoleroText)); + ParseSpoilerHintText(spoilerFileJson, "warpSerenadeText", gSaveContext.warpSerenadeText, false, sizeof(gSaveContext.warpSerenadeText)); + ParseSpoilerHintText(spoilerFileJson, "warpRequiemText", gSaveContext.warpRequiemText, false, sizeof(gSaveContext.warpRequiemText)); + ParseSpoilerHintText(spoilerFileJson, "warpNocturneText", gSaveContext.warpNocturneText, false, sizeof(gSaveContext.warpNocturneText)); + ParseSpoilerHintText(spoilerFileJson, "warpPreludeText", gSaveContext.warpPreludeText, false, sizeof(gSaveContext.warpPreludeText)); - std::string sariaJsonText = spoilerFileJson["sariaText"].get(); - std::string formattedSariaJsonText = FormatJsonHintText(sariaJsonText); - strncpy(gSaveContext.sariaText, formattedSariaJsonText.c_str(), sizeof(gSaveContext.sariaText) - 1); - gSaveContext.sariaText[sizeof(gSaveContext.sariaText) - 1] = 0; - gSaveContext.sariaCheck = SpoilerfileCheckNameToEnum[spoilerFileJson["sariaHintLoc"]]; - - std::string warpMinuetJsonText = spoilerFileJson["warpMinuetText"].get(); - strncpy(gSaveContext.warpMinuetText, warpMinuetJsonText.c_str(), sizeof(gSaveContext.warpMinuetText) - 1); - gSaveContext.warpMinuetText[sizeof(gSaveContext.warpMinuetText) - 1] = 0; - - std::string warpBoleroJsonText = spoilerFileJson["warpBoleroText"].get(); - strncpy(gSaveContext.warpBoleroText, warpBoleroJsonText.c_str(), sizeof(gSaveContext.warpBoleroText) - 1); - gSaveContext.warpBoleroText[sizeof(gSaveContext.warpBoleroText) - 1] = 0; - - std::string warpSerenadeJsonText = spoilerFileJson["warpSerenadeText"].get(); - strncpy(gSaveContext.warpSerenadeText, warpSerenadeJsonText.c_str(), sizeof(gSaveContext.warpSerenadeText) - 1); - gSaveContext.warpSerenadeText[sizeof(gSaveContext.warpSerenadeText) - 1] = 0; - - std::string warpRequiemJsonText = spoilerFileJson["warpRequiemText"].get(); - strncpy(gSaveContext.warpRequiemText, warpRequiemJsonText.c_str(), sizeof(gSaveContext.warpRequiemText) - 1); - gSaveContext.warpRequiemText[sizeof(gSaveContext.warpRequiemText) - 1] = 0; - - std::string warpNocturneJsonText = spoilerFileJson["warpNocturneText"].get(); - strncpy(gSaveContext.warpNocturneText, warpNocturneJsonText.c_str(), sizeof(gSaveContext.warpNocturneText) - 1); - gSaveContext.warpNocturneText[sizeof(gSaveContext.warpNocturneText) - 1] = 0; - - std::string warpPreludeJsonText = spoilerFileJson["warpPreludeText"].get(); - strncpy(gSaveContext.warpPreludeText, warpPreludeJsonText.c_str(), sizeof(gSaveContext.warpPreludeText) - 1); - gSaveContext.warpPreludeText[sizeof(gSaveContext.warpPreludeText) - 1] = 0; json hintsJson = spoilerFileJson["hints"]; int index = 0; @@ -1416,7 +1401,6 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { index++; } - success = true; } catch (const std::exception& e) { return; } diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 4dc5a590a..ff2a88b7e 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1348,7 +1348,14 @@ typedef enum { RC_ZR_NEAR_GROTTOS_GOSSIP_STONE, RC_ZR_OPEN_GROTTO_GOSSIP_STONE, RC_GANONDORF_HINT, + RC_SHEIK_HINT_GC, + RC_SHEIK_HINT_MQ_GC, RC_TRIFORCE_COMPLETED, + RC_DAMPE_HINT, + RC_GREG_HINT, + RC_SARIA_SONG_HINT, + RC_ALTAR_HINT_CHILD, + RC_ALTAR_HINT_ADULT, RC_MAX } RandomizerCheck; @@ -3172,6 +3179,7 @@ typedef enum { RHT_VALIDATION_LINE, // Light Arrow Location RHT_LIGHT_ARROW_LOCATION_HINT, + RHT_SHEIK_LIGHT_ARROW_HINT, // Your Pocket RHT_YOUR_POCKET, // Ganon Line diff --git a/soh/soh/Enhancements/randomizer/static_data.h b/soh/soh/Enhancements/randomizer/static_data.h index 3c8328590..9a0000da2 100644 --- a/soh/soh/Enhancements/randomizer/static_data.h +++ b/soh/soh/Enhancements/randomizer/static_data.h @@ -31,6 +31,7 @@ class StaticData { static std::vector> shopLocationLists; static std::vector scrubLocations; static std::vector gossipStoneLocations; + static std::vector otherHintLocations; StaticData(); ~StaticData(); };