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

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

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();
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;

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

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));
ParseSpoilerHintText(spoilerFileJson, "sariaText", gSaveContext.sariaText, true, sizeof(gSaveContext.sariaText));
CheckNameToEnum(spoilerFileJson, "sariaHintLoc", &gSaveContext.sariaCheck);
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, "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>();
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<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();
};