Remove disabled special hints and warp song hints from the spoiler log (#3110)

* Initial implementation of no-duplicates of special hints

* stupid fixes

* fix always hints being suppressed by special hints

* Impa's song will no longer be hinted when you skip child zelda

* fix building

* Remove disabled special hints from the spoiler log

* Fix Loading spoiler logs causing corrupt hints, remove disabled warp song shuffle text from spoiler logs

* Fix not detecting text size correctly and badly named greg hint

* Remove disabled special hints from the spoiler log

* 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
This commit is contained in:
Pepper0ni 2023-10-22 16:11:36 +01:00 committed by GitHub
parent 2a52493d1f
commit 15ebcd30fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 297 additions and 193 deletions

View File

@ -996,7 +996,7 @@ void RegisterAltTrapTypes() {
void RegisterRandomizerSheikSpawn() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneSpawnActors>([]() {
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) {

View File

@ -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;
}

View File

@ -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<ConditionalAlwaysHint, 9> conditionalAlwaysHints = {
std::array<ConditionalAlwaysHint, 10> conditionalAlwaysHints = {
std::make_pair(RC_MARKET_10_BIG_POES,
[]() {
return Settings::BigPoeTargetCount.Value<uint8_t>() >= 3;
@ -3203,9 +3213,10 @@ std::array<ConditionalAlwaysHint, 9> 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) {

View File

@ -275,6 +275,25 @@ static std::vector<RandomizerCheck> GetAccessibleGossipStones(const RandomizerCh
return accessibleGossipStones;
}
bool IsReachableWithout(std::vector<RandomizerCheck> 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<uint8_t>& 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,16 +611,20 @@ 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));
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<RandomizerCheck> 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);
@ -613,24 +632,35 @@ void CreateGanonText() {
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();
ganonHintText = hint.GetText() + "%r" + lightArrowArea;
lightArrowHintLoc = Rando::StaticData::GetLocation(lightArrowLocation[0])->GetName();
}
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());
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];
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<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_KOKIRI_EMERALD)) +
: BuildDungeonRewardText(RG_KOKIRI_EMERALD, true)) +
(StartingGoronRuby.Value<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_GORON_RUBY)) +
: BuildDungeonRewardText(RG_GORON_RUBY, true)) +
(StartingZoraSapphire.Value<uint8_t>() ? 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<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_LIGHT_MEDALLION)) +
: BuildDungeonRewardText(RG_LIGHT_MEDALLION, false)) +
(StartingForestMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_FOREST_MEDALLION)) +
: BuildDungeonRewardText(RG_FOREST_MEDALLION, false)) +
(StartingFireMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_FIRE_MEDALLION)) +
: BuildDungeonRewardText(RG_FIRE_MEDALLION, false)) +
(StartingWaterMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_WATER_MEDALLION)) +
: BuildDungeonRewardText(RG_WATER_MEDALLION, false)) +
(StartingSpiritMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_SPIRIT_MEDALLION)) +
: BuildDungeonRewardText(RG_SPIRIT_MEDALLION, false)) +
(StartingShadowMedallion.Value<uint8_t>() ? 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,27 +929,14 @@ 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() {
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;});
sariaHintLoc = Rando::StaticData::GetLocation(magicLocation[0])->GetName();
Text area = GetHintRegion(ctx->GetItemLocation(magicLocation[0])->GetParentRegionKey())->GetHint().GetText();
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",
@ -924,6 +948,11 @@ void CreateSariaText() {
"%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<int>(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<RandomizerCheck> songHintLocations =

View File

@ -114,7 +114,7 @@ public:
static auto LightArrow(std::vector<Text>&& obscureText, std::vector<Text>&& 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<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::GanonLine};
@ -198,7 +198,7 @@ using ConditionalAlwaysHint = std::pair<RandomizerCheck, std::function<bool()>>;
//10 dungeons as GTG and GC are excluded
extern std::array<DungeonInfo, 10> dungeonInfoData;
extern std::array<ConditionalAlwaysHint, 9> conditionalAlwaysHints;
extern std::array<ConditionalAlwaysHint, 10> 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();

View File

@ -260,6 +260,7 @@ void AreaTable_Init() {
//Locations
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;}})

View File

@ -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);}}),

View File

@ -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;}}),

View File

@ -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;}}),
});

View File

@ -858,6 +858,8 @@ void UpdateSettings(std::unordered_map<RandomizerSettingKey, uint8_t> 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;

View File

@ -689,12 +689,15 @@ static void WriteHints(int language) {
unformattedGregText = GetGregHintText().GetEnglish();
unformattedSheikText = GetSheikHintText().GetEnglish();
unformattedSariaText = GetSariaHintText().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();
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;
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();
jsonData["sheikText"] = sheikText;
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;

View File

@ -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() {

View File

@ -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<Category>&& 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_,

View File

@ -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<Category>&& 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_,

View File

@ -507,6 +507,17 @@ std::vector<RandomizerCheck> Rando::StaticData::gossipStoneLocations = {
RC_ZR_OPEN_GROTTO_GOSSIP_STONE,
};
std::vector<RandomizerCheck> 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,
@ -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
}

View File

@ -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<std::string>();
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<std::string>()];
};
}
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>();
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>();
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>();
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>();
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));
std::string sheikJsonText = spoilerFileJson["sheikText"].get<std::string>();
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, "sariaText", gSaveContext.sariaText, true, sizeof(gSaveContext.sariaText));
CheckNameToEnum(spoilerFileJson, "sariaHintLoc", &gSaveContext.sariaCheck);
std::string sariaJsonText = spoilerFileJson["sariaText"].get<std::string>();
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"]];
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 warpMinuetJsonText = spoilerFileJson["warpMinuetText"].get<std::string>();
strncpy(gSaveContext.warpMinuetText, warpMinuetJsonText.c_str(), sizeof(gSaveContext.warpMinuetText) - 1);
gSaveContext.warpMinuetText[sizeof(gSaveContext.warpMinuetText) - 1] = 0;
std::string warpBoleroJsonText = spoilerFileJson["warpBoleroText"].get<std::string>();
strncpy(gSaveContext.warpBoleroText, warpBoleroJsonText.c_str(), sizeof(gSaveContext.warpBoleroText) - 1);
gSaveContext.warpBoleroText[sizeof(gSaveContext.warpBoleroText) - 1] = 0;
std::string warpSerenadeJsonText = spoilerFileJson["warpSerenadeText"].get<std::string>();
strncpy(gSaveContext.warpSerenadeText, warpSerenadeJsonText.c_str(), sizeof(gSaveContext.warpSerenadeText) - 1);
gSaveContext.warpSerenadeText[sizeof(gSaveContext.warpSerenadeText) - 1] = 0;
std::string warpRequiemJsonText = spoilerFileJson["warpRequiemText"].get<std::string>();
strncpy(gSaveContext.warpRequiemText, warpRequiemJsonText.c_str(), sizeof(gSaveContext.warpRequiemText) - 1);
gSaveContext.warpRequiemText[sizeof(gSaveContext.warpRequiemText) - 1] = 0;
std::string warpNocturneJsonText = spoilerFileJson["warpNocturneText"].get<std::string>();
strncpy(gSaveContext.warpNocturneText, warpNocturneJsonText.c_str(), sizeof(gSaveContext.warpNocturneText) - 1);
gSaveContext.warpNocturneText[sizeof(gSaveContext.warpNocturneText) - 1] = 0;
std::string warpPreludeJsonText = spoilerFileJson["warpPreludeText"].get<std::string>();
strncpy(gSaveContext.warpPreludeText, warpPreludeJsonText.c_str(), sizeof(gSaveContext.warpPreludeText) - 1);
gSaveContext.warpPreludeText[sizeof(gSaveContext.warpPreludeText) - 1] = 0;
json hintsJson = spoilerFileJson["hints"];
int index = 0;
@ -1416,7 +1401,6 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) {
index++;
}
success = true;
} catch (const std::exception& e) {
return;
}

View File

@ -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

View File

@ -31,6 +31,7 @@ class StaticData {
static std::vector<std::vector<RandomizerCheck>> shopLocationLists;
static std::vector<RandomizerCheck> scrubLocations;
static std::vector<RandomizerCheck> gossipStoneLocations;
static std::vector<RandomizerCheck> otherHintLocations;
StaticData();
~StaticData();
};