From 1ca8d0ab7331d82d3e1e042d9882a5a4630caa4e Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Fri, 5 Jul 2024 22:52:59 +0100 Subject: [PATCH] Implement Mask Hints (#4152) * Implement Mask Hints * fix typo --- .../Enhancements/custom-message/CustomMessageTypes.h | 1 + soh/soh/Enhancements/randomizer/3drando/hint_list.cpp | 4 ++++ soh/soh/Enhancements/randomizer/3drando/hints.cpp | 2 +- .../3drando/location_access/locacc_castle_town.cpp | 6 ++++-- soh/soh/Enhancements/randomizer/location_list.cpp | 4 +++- .../Enhancements/randomizer/option_descriptions.cpp | 1 + soh/soh/Enhancements/randomizer/randomizerTypes.h | 4 ++++ soh/soh/Enhancements/randomizer/settings.cpp | 11 ++++++++--- soh/soh/Enhancements/randomizer/static_data.cpp | 8 +++++--- soh/soh/OTRGlobals.cpp | 3 +++ 10 files changed, 34 insertions(+), 10 deletions(-) diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index 1f5a093c7..6d25d9f8a 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -74,6 +74,7 @@ typedef enum { TEXT_SARIAS_SONG_IMPRISON_GANONDORF = 0x016C, TEXT_SARIAS_SONG_CHANNELING_POWER = 0x016D, TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI = 0x01B3, // 0x1yy for Navi msg range + TEXT_MASK_SHOP_SIGN = 0x0207, TEXT_FROGS_UNDERWATER = 0x022E, TEXT_GF_HBA_SIGN = 0x031A, TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN = 0x0346, // 0x3yy for cuttable sign range diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp index 22ef9f962..c437bcecd 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp @@ -2861,6 +2861,10 @@ void StaticData::HintTable_Init() { /*french*/ "Yeaaarrgh! Je suis maudit!^Détruit encore #[[d]] Araignées de la Malédiction# et j'aurai quelque chose à te donner! #([[1]])#", {QM_YELLOW, QM_GREEN})); + hintTextTable[RHT_MASK_SHOP_HINT] = HintText(CustomMessage("Some young scrubs in the #Deku Theatre# love seeing Masks!^" + "They'll give you #[[1]]# if you show them the #Skull Mask#, and #[[2]]# if you show them the #Mask of Truth#!", + {QM_GREEN, QM_GREEN, QM_RED, QM_GREEN, QM_RED})); + /*-------------------------- | GANON LINE TEXT | ---------------------------*/ diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.cpp b/soh/soh/Enhancements/randomizer/3drando/hints.cpp index a01f2a4ce..09930fa25 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hints.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hints.cpp @@ -277,7 +277,7 @@ std::vector>> conditionalAlways }), // Remember, the option's value being 3 means 4 are required std::make_pair(RC_DEKU_THEATER_MASK_OF_TRUTH, []() { auto ctx = Rando::Context::GetInstance(); - return !ctx->GetOption(RSK_COMPLETE_MASK_QUEST); + return !ctx->GetOption(RSK_MASK_SHOP_HINT) && !ctx->GetOption(RSK_COMPLETE_MASK_QUEST); }), std::make_pair(RC_SONG_FROM_OCARINA_OF_TIME, []() { return StonesRequiredBySettings() < 2; }), std::make_pair(RC_HF_OCARINA_OF_TIME_ITEM, []() { return StonesRequiredBySettings() < 2; }), 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 fbff295ad..160fff18d 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 @@ -191,9 +191,11 @@ void AreaTable_Init_CastleTown() { areaTable[RR_MARKET_MASK_SHOP] = Area("Market Mask Shop", "Market Mask Shop", RA_NONE, NO_DAY_NIGHT_CYCLE, { //Events - EventAccess(&logic->SkullMask, {[]{return logic->SkullMask || (logic->ZeldasLetter && (randoCtx->GetOption(RSK_COMPLETE_MASK_QUEST) || ChildCanAccess(RR_KAKARIKO_VILLAGE)));}}), + EventAccess(&logic->SkullMask, {[]{return logic->SkullMask || (logic->ZeldasLetter && (randoCtx->GetOption(RSK_COMPLETE_MASK_QUEST) || ChildCanAccess(RR_KAKARIKO_VILLAGE)));}}), //RANDOTODO Complete mask quest does not need this location, so should be tied to link'd pocket EventAccess(&logic->MaskOfTruth, {[]{return logic->MaskOfTruth || (logic->SkullMask && (randoCtx->GetOption(RSK_COMPLETE_MASK_QUEST) || (ChildCanAccess(RR_THE_LOST_WOODS) && logic->CanUse(RG_SARIAS_SONG) && AreaTable(RR_THE_GRAVEYARD)->childDay && ChildCanAccess(RR_HYRULE_FIELD) && logic->HasAllStones)));}}), - }, {}, { + }, { + LocationAccess(RC_MASK_SHOP_HINT, {[]{return true;}}), + }, { //Exits Entrance(RR_THE_MARKET, {[]{return true;}}), }); diff --git a/soh/soh/Enhancements/randomizer/location_list.cpp b/soh/soh/Enhancements/randomizer/location_list.cpp index 454520d48..a380e0d02 100644 --- a/soh/soh/Enhancements/randomizer/location_list.cpp +++ b/soh/soh/Enhancements/randomizer/location_list.cpp @@ -558,7 +558,8 @@ std::vector Rando::StaticData::staticHintLocations = { RC_SARIA_SONG_HINT, RC_ALTAR_HINT_CHILD, RC_ALTAR_HINT_ADULT, - RC_FISHING_POLE_HINT + RC_FISHING_POLE_HINT, + RC_MASK_SHOP_HINT, }; std::vector Rando::StaticData::pondFishLocations = { @@ -1564,6 +1565,7 @@ void Rando::StaticData::InitLocationTable() { // 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, "ToT Child Altar Hint"); 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, "ToT Adult Altar Hint"); locationTable[RC_FISHING_POLE_HINT] = Location::OtherHint(RC_FISHING_POLE_HINT, RCQUEST_BOTH, RCTYPE_GOSSIP_STONE, RCAREA_LAKE_HYLIA, ACTOR_FISHING, SCENE_FISHING_POND, "Fishing Pole Hint"); + locationTable[RC_MASK_SHOP_HINT] = Location::OtherHint(RC_MASK_SHOP_HINT, RCQUEST_BOTH, RCTYPE_GOSSIP_STONE, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_HAPPY_MASK_SHOP, "Mask Shop Hint"); 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/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index b0160a6c6..3344a8cc1 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -532,6 +532,7 @@ void Settings::CreateOptionDescriptions() { mOptionDescriptions[RSK_KAK_40_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 40 tokens will tell you the reward"; mOptionDescriptions[RSK_KAK_50_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 50 tokens will tell you the reward"; mOptionDescriptions[RSK_KAK_100_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 100 tokens will tell you the reward"; + mOptionDescriptions[RSK_MASK_SHOP_HINT] = "Reading the mask shop sign will tell you rewards from showing masks at the Deku Theatre."; mOptionDescriptions[RSK_FULL_WALLETS] = "Start with a full wallet. All wallet upgrades come filled with rupees."; mOptionDescriptions[RSK_BOMBCHUS_IN_LOGIC] = diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 35d0b48ec..c48bfeeb5 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1489,6 +1489,7 @@ typedef enum { RC_ALTAR_HINT_CHILD, RC_ALTAR_HINT_ADULT, RC_FISHING_POLE_HINT, + RC_MASK_SHOP_HINT, RC_DMC_UPPER_GROTTO_FISH, RC_DMT_STORMS_GROTTO_FISH, RC_HF_SOUTHEAST_GROTTO_FISH, @@ -2086,6 +2087,7 @@ typedef enum { RH_KAK_40_SKULLS_HINT, RH_KAK_50_SKULLS_HINT, RH_KAK_100_SKULLS_HINT, + RH_MASK_SHOP_HINT, RH_MAX, } RandomizerHint; @@ -3447,6 +3449,7 @@ typedef enum { RHT_BIGGORON_HINT, RHT_FROGS_HINT, RHT_SKULLS_HINT, + RHT_MASK_SHOP_HINT, // Ganon Line RHT_GANON_JOKE01, RHT_GANON_JOKE02, @@ -3607,6 +3610,7 @@ typedef enum { RSK_KAK_40_SKULLS_HINT, RSK_KAK_50_SKULLS_HINT, RSK_KAK_100_SKULLS_HINT, + RSK_MASK_SHOP_HINT, RSK_BIGGORON_HINT, RSK_BIG_POES_HINT, RSK_CHICKENS_HINT, diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 939da09ad..9d836371b 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -176,7 +176,8 @@ void Settings::CreateOptions() { mOptions[RSK_KAK_30_SKULLS_HINT] = Option::Bool("30 GS Hint", CVAR_RANDOMIZER_SETTING("30GSHint"), mOptionDescriptions[RSK_KAK_30_SKULLS_HINT], IMFLAG_NONE); mOptions[RSK_KAK_40_SKULLS_HINT] = Option::Bool("40 GS Hint", CVAR_RANDOMIZER_SETTING("40GSHint"), mOptionDescriptions[RSK_KAK_40_SKULLS_HINT], IMFLAG_NONE); mOptions[RSK_KAK_50_SKULLS_HINT] = Option::Bool("50 GS Hint", CVAR_RANDOMIZER_SETTING("50GSHint"), mOptionDescriptions[RSK_KAK_50_SKULLS_HINT], IMFLAG_NONE); - mOptions[RSK_KAK_100_SKULLS_HINT] = Option::Bool("100 GS Hint", CVAR_RANDOMIZER_SETTING("100GSHint"), mOptionDescriptions[RSK_KAK_100_SKULLS_HINT]); + mOptions[RSK_KAK_100_SKULLS_HINT] = Option::Bool("100 GS Hint", CVAR_RANDOMIZER_SETTING("100GSHint"), mOptionDescriptions[RSK_KAK_100_SKULLS_HINT], IMFLAG_NONE); + mOptions[RSK_MASK_SHOP_HINT] = Option::Bool("Mask Shop Hint", CVAR_RANDOMIZER_SETTING("MaskShopHint"), mOptionDescriptions[RSK_MASK_SHOP_HINT]); // TODO: Compasses show rewards/woth, maps show dungeon mode mOptions[RSK_BLUE_FIRE_ARROWS] = Option::Bool("Blue Fire Arrows", CVAR_RANDOMIZER_SETTING("BlueFireArrows"), mOptionDescriptions[RSK_BLUE_FIRE_ARROWS]); mOptions[RSK_SUNLIGHT_ARROWS] = Option::Bool("Sunlight Arrows", CVAR_RANDOMIZER_SETTING("SunlightArrows"), mOptionDescriptions[RSK_SUNLIGHT_ARROWS]); @@ -745,7 +746,8 @@ void Settings::CreateOptions() { &mOptions[RSK_KAK_30_SKULLS_HINT], &mOptions[RSK_KAK_40_SKULLS_HINT], &mOptions[RSK_KAK_50_SKULLS_HINT], - &mOptions[RSK_KAK_100_SKULLS_HINT] + &mOptions[RSK_KAK_100_SKULLS_HINT], + &mOptions[RSK_MASK_SHOP_HINT] }, false, WidgetContainerType::SECTION, "This setting adds some hints at locations other than Gossip Stones."); mOptionGroups[RSG_ITEM_POOL_HINTS_IMGUI_COLUMN] = OptionGroup::SubGroup("Item Pool & Hints", std::initializer_list{ &mOptionGroups[RSG_ITEM_POOL_HINTS_IMGUI], @@ -974,6 +976,7 @@ void Settings::CreateOptions() { &mOptions[RSK_KAK_40_SKULLS_HINT], &mOptions[RSK_KAK_50_SKULLS_HINT], &mOptions[RSK_KAK_100_SKULLS_HINT], + &mOptions[RSK_MASK_SHOP_HINT], &mOptions[RSK_SCRUB_TEXT_HINT], &mOptions[RSK_FISHING_POLE_HINT], // TODO: Compasses show Reward/WOTH, Maps show Dungeon Mode, Starting Time @@ -1185,7 +1188,8 @@ void Settings::CreateOptions() { { "Miscellaneous Settings:30 GS Hint", RSK_KAK_30_SKULLS_HINT }, { "Miscellaneous Settings:40 GS Hint", RSK_KAK_40_SKULLS_HINT }, { "Miscellaneous Settings:50 GS Hint", RSK_KAK_50_SKULLS_HINT }, - { "Miscellaneous Settings:50 GS Hint", RSK_KAK_100_SKULLS_HINT }, + { "Miscellaneous Settings:100 GS Hint", RSK_KAK_100_SKULLS_HINT }, + { "Miscellaneous Settings:Mask Shop Hint", RSK_MASK_SHOP_HINT }, { "Miscellaneous Settings:Biggoron's Hint", RSK_BIGGORON_HINT }, { "Miscellaneous Settings:Big Poes Hint", RSK_BIG_POES_HINT }, { "Miscellaneous Settings:Warp Song Hints", RSK_WARP_SONG_HINTS }, @@ -2295,6 +2299,7 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_KAK_40_SKULLS_HINT: case RSK_KAK_50_SKULLS_HINT: case RSK_KAK_100_SKULLS_HINT: + case RSK_MASK_SHOP_HINT: case RSK_BIGGORON_HINT: case RSK_BIG_POES_HINT: case RSK_CHICKENS_HINT: diff --git a/soh/soh/Enhancements/randomizer/static_data.cpp b/soh/soh/Enhancements/randomizer/static_data.cpp index 524ab4700..bf7a93f17 100644 --- a/soh/soh/Enhancements/randomizer/static_data.cpp +++ b/soh/soh/Enhancements/randomizer/static_data.cpp @@ -93,7 +93,8 @@ std::unordered_map StaticData::hintNames = { {RH_KAK_30_SKULLS_HINT, CustomMessage("30 Skulls Hint")}, {RH_KAK_40_SKULLS_HINT, CustomMessage("40 Skulls Hint")}, {RH_KAK_50_SKULLS_HINT, CustomMessage("50 Skulls Hint")}, - {RH_KAK_100_SKULLS_HINT, CustomMessage("100 Skulls Hint")} + {RH_KAK_100_SKULLS_HINT, CustomMessage("100 Skulls Hint")}, + {RH_MASK_SHOP_HINT, CustomMessage("Mask Shop Hint")}, }; std::unordered_map StaticData::gossipStoneCheckToHint { @@ -203,7 +204,7 @@ std::unordered_map StaticData::staticHintInfoMap {RH_CARPET_SALESMAN, StaticHintInfo(HINT_TYPE_MERCHANT, {RHT_CARPET_SALESMAN_DIALOG_HINTED}, RSK_SHUFFLE_MERCHANTS, (uint8_t)RO_SHUFFLE_MERCHANTS_ON_HINT, {RC_WASTELAND_BOMBCHU_SALESMAN})}, {RH_BEAN_SALESMAN, StaticHintInfo(HINT_TYPE_MERCHANT, {RHT_BEAN_SALESMAN_HINT}, RSK_SHUFFLE_MAGIC_BEANS, true, {RC_ZR_MAGIC_BEAN_SALESMAN})}, {RH_HBA_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_HBA_HINT_SIGN, RHT_HBA_HINT_NOT_ON_HORSE, RHT_HBA_HINT_INITIAL, RHT_HBA_HINT_HAVE_1000}, RSK_HBA_HINT, true, {RC_GF_HBA_1000_POINTS, RC_GF_HBA_1500_POINTS})}, - {RH_MALON_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_MALON_HINT_TURNING_EVIL, RHT_MALON_HINT_HOW_IS_EPONA, RHT_MALON_HINT_OBSTICLE_COURSE, RHT_MALON_HINT_INGO_TEMPTED},RSK_MALON_HINT, true, {RC_KF_LINKS_HOUSE_COW})}, + {RH_MALON_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_MALON_HINT_TURNING_EVIL, RHT_MALON_HINT_HOW_IS_EPONA, RHT_MALON_HINT_OBSTICLE_COURSE, RHT_MALON_HINT_INGO_TEMPTED}, RSK_MALON_HINT, true, {RC_KF_LINKS_HOUSE_COW})}, {RH_BIG_POES_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_BIG_POES_HINT}, RSK_BIG_POES_HINT, true, {RC_MARKET_10_BIG_POES})}, {RH_CHICKENS_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_CHICKENS_HINT}, RSK_CHICKENS_HINT, true, {RC_KAK_ANJU_AS_CHILD})}, {RH_BIGGORON_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_BIGGORON_HINT}, RSK_BIGGORON_HINT, true, {RC_DMT_TRADE_CLAIM_CHECK})}, @@ -213,7 +214,8 @@ std::unordered_map StaticData::staticHintInfoMap {RH_KAK_30_SKULLS_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_SKULLS_HINT}, RSK_KAK_30_SKULLS_HINT, true, {RC_KAK_30_GOLD_SKULLTULA_REWARD}, {}, {}, false, 30)}, {RH_KAK_40_SKULLS_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_SKULLS_HINT}, RSK_KAK_40_SKULLS_HINT, true, {RC_KAK_40_GOLD_SKULLTULA_REWARD}, {}, {}, false, 40)}, {RH_KAK_50_SKULLS_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_SKULLS_HINT}, RSK_KAK_50_SKULLS_HINT, true, {RC_KAK_50_GOLD_SKULLTULA_REWARD}, {}, {}, false, 50)}, - {RH_KAK_100_SKULLS_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_SKULLS_HINT}, RSK_KAK_100_SKULLS_HINT, true, {RC_KAK_100_GOLD_SKULLTULA_REWARD}, {}, {}, false, 100)} + {RH_KAK_100_SKULLS_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_SKULLS_HINT}, RSK_KAK_100_SKULLS_HINT, true, {RC_KAK_100_GOLD_SKULLTULA_REWARD}, {}, {}, false, 100)}, + {RH_MASK_SHOP_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_MASK_SHOP_HINT}, RSK_MASK_SHOP_HINT, true, {RC_DEKU_THEATER_SKULL_MASK, RC_DEKU_THEATER_MASK_OF_TRUTH}, {}, {RC_MASK_SHOP_HINT})} }; std::unordered_map StaticData::PopulateTranslationMap(std::unordered_map input){ diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index a5f325350..18da01c2c 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2754,6 +2754,9 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { else if (textId == TEXT_HBA_ALREADY_HAVE_1000 && ctx->GetOption(RSK_HBA_HINT)) { messageEntry = ctx->GetHint(RH_HBA_HINT)->GetHintMessage(MF_AUTO_FORMAT, 3); } + else if (textId == TEXT_MASK_SHOP_SIGN && ctx->GetOption(RSK_MASK_SHOP_HINT)) { + messageEntry = ctx->GetHint(RH_MASK_SHOP_HINT)->GetHintMessage(MF_AUTO_FORMAT); + } } if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) { if (CVarGetInteger(CVAR_ENHANCEMENT("InjectItemCounts"), 0) != 0) {