From 50aed798a1e8bc71859b4943037890a0a6b6975e Mon Sep 17 00:00:00 2001 From: A Green Spoon <121978037+A-Green-Spoon@users.noreply.github.com> Date: Fri, 3 Apr 2026 15:01:07 +0900 Subject: [PATCH] [Rando] Shuffle Beggar (#6455) --- .../custom-message/CustomMessageTypes.h | 4 + .../vanilla-behavior/GIVanillaBehavior.h | 8 ++ .../hint_list/hint_list_exclude_overworld.cpp | 8 ++ .../randomizer/3drando/item_pool.cpp | 4 + .../Enhancements/randomizer/SeedContext.cpp | 1 + .../Enhancements/randomizer/ShuffleBeggar.cpp | 115 ++++++++++++++++++ .../location_access/overworld/kakariko.cpp | 3 + .../location_access/overworld/market.cpp | 3 + .../randomizer/option_descriptions.cpp | 3 + .../Enhancements/randomizer/randomizer.cpp | 23 ++++ soh/soh/Enhancements/randomizer/randomizer.h | 1 + .../randomizerEnums/RandomizerCheck.h | 7 ++ .../randomizerEnums/RandomizerHintTextKey.h | 3 + .../randomizerEnums/RandomizerInf.h | 7 ++ .../randomizerEnums/RandomizerMiscEnums.h | 1 + .../randomizerEnums/RandomizerSettingKey.h | 1 + .../randomizer/randomizer_check_objects.cpp | 2 + .../randomizer/randomizer_check_tracker.cpp | 4 + soh/soh/Enhancements/randomizer/settings.cpp | 3 + soh/soh/Enhancements/randomizer/static_data.h | 1 + soh/src/overlays/actors/ovl_En_Hy/z_en_hy.c | 4 +- 21 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 soh/soh/Enhancements/randomizer/ShuffleBeggar.cpp diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index 4df57e274..205e44dc6 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -219,6 +219,10 @@ typedef enum { TEXT_SHEIK_HAVE_HOOK = 0x7010, TEXT_ALTAR_CHILD = 0x7040, TEXT_CHEST_GAME_PROCEED = 0x704C, + TEXT_BEGGAR_BUY_BLUE_FIRE = 0x70F0, + TEXT_BEGGAR_BUY_FISH = 0x70F1, + TEXT_BEGGAR_BUY_BUGS = 0x70F2, + TEXT_BEGGAR_BUY_FAIRY = 0x70F3, TEXT_GHOST_SHOP_EXPLAINATION = 0x70F4, TEXT_GHOST_SHOP_CARD_HAS_POINTS = 0x70F5, TEXT_GHOST_SHOP_BUY_NORMAL_POE = 0x70F6, diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 9842c54ed..c94c5583c 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -195,6 +195,14 @@ typedef enum { // - `*EnTk` VB_BE_VALID_GRAVEDIGGING_SPOT, + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - 'EnHy*' + VB_BEGGAR_GIVE_ITEM, + // #### `result` // ```c // this->collider.base.acFlags & 2 || blueFireArrowHit diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp index 1299bafbd..325092bc1 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp @@ -2315,6 +2315,14 @@ void StaticData::HintTable_Init_Exclude_Overworld() { hintTextTable[RHT_WONDER_ITEM_DESERT_COLOSSUS] = HintText(CustomMessage("They say that a #wonder item near the temple of the sand# hides #[[1]]#.", /*german*/ "Man erzählt sich, daß sich ein #Wunder-Gegenstand nahe des Tempels des Sandes# #[[1]]# verstecke.", /*french*/ "Selon moi, un #objet merveilleux près du temple du sable# cache #[[1]]#.", {QM_RED, QM_GREEN})); + + hintTextTable[RHT_BEGGAR_MARKET] = HintText(CustomMessage("They say that #trading with a beggar in the market# gives #[[1]]#.", + /*german*/ "Man erzählt sich, daß das #Handeln mit einem Bettler auf dem Markt# #[[1]]# gäbe.", + /*french*/ "Selon moi, #échanger avec un mendiant sur le marché# donne #[[1]]#.", {QM_RED, QM_GREEN})); + + hintTextTable[RHT_BEGGAR_KAKARIKO_VILLAGE] = HintText(CustomMessage("They say that #trading with a beggar in Kakariko Village# gives #[[1]]#.", + /*german*/ "Man erzählt sich, daß das #Handeln mit einem Bettler in Kakariko# #[[1]]# gäbe.", + /*french*/ "Selon moi, #échanger avec un mendiant dans le Village de Cocorico# donne #[[1]]#.", {QM_RED, QM_GREEN})); // clang-format on } } // namespace Rando diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index 5a5e85cd5..7f1e886a9 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -497,6 +497,10 @@ void GenerateItemPool() { ctx->PlaceItemInLocation(RC_WASTELAND_BOMBCHU_SALESMAN, RG_BOMBCHU_10, false, true); } + // Shuffle Beggar + bool beggarActive = (bool)ctx->GetOption(RSK_SHUFFLE_BEGGAR); + PlaceItemsForType(RCTYPE_BEGGAR, beggarActive, false); + if (ctx->GetOption(RSK_SHUFFLE_FROG_SONG_RUPEES)) { AddFixedItemToPool(RG_PURPLE_RUPEE, 5); } else { diff --git a/soh/soh/Enhancements/randomizer/SeedContext.cpp b/soh/soh/Enhancements/randomizer/SeedContext.cpp index 62ff1f9cc..448d1c2aa 100644 --- a/soh/soh/Enhancements/randomizer/SeedContext.cpp +++ b/soh/soh/Enhancements/randomizer/SeedContext.cpp @@ -196,6 +196,7 @@ void Context::GenerateLocationPool() { !(location.GetRandomizerCheck() == RC_LW_DEKU_SCRUB_GROTTO_FRONT || location.GetRandomizerCheck() == RC_LW_DEKU_SCRUB_NEAR_BRIDGE || location.GetRandomizerCheck() == RC_HF_DEKU_SCRUB_GROTTO)) || + (location.GetRCType() == RCTYPE_BEGGAR && mOptions[RSK_SHUFFLE_BEGGAR].Is(RO_GENERIC_OFF)) || (location.GetRCType() == RCTYPE_ADULT_TRADE && mOptions[RSK_SHUFFLE_ADULT_TRADE].Is(RO_GENERIC_OFF)) || (location.GetRCType() == RCTYPE_COW && mOptions[RSK_SHUFFLE_COWS].Is(RO_GENERIC_OFF)) || (location.GetRandomizerCheck() == RC_LH_HYRULE_LOACH && diff --git a/soh/soh/Enhancements/randomizer/ShuffleBeggar.cpp b/soh/soh/Enhancements/randomizer/ShuffleBeggar.cpp new file mode 100644 index 000000000..6f7b8ada0 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/ShuffleBeggar.cpp @@ -0,0 +1,115 @@ +#include + +extern "C" { +#include "overlays/actors/ovl_En_Hy/z_en_hy.h" +extern PlayState* gPlayState; +} + +CheckIdentity ShuffleBeggar_GetBeggarIdentity(int32_t textId) { + CheckIdentity beggarIdentity; + s16 sceneNum = gPlayState->sceneNum; + + beggarIdentity = OTRGlobals::Instance->gRandomizer->IdentifyBeggar(sceneNum, textId); + + return beggarIdentity; +} + +uint8_t EnHy_RandomizerHoldsItem(int32_t textId) { + CheckIdentity beggarIdentity = ShuffleBeggar_GetBeggarIdentity(textId); + if (beggarIdentity.randomizerCheck == RC_UNKNOWN_CHECK || !IS_RANDO || + Flags_GetRandomizerInf(beggarIdentity.randomizerInf)) { + return false; + } + return true; +} + +void BuildEnHyMessage_BlueFire(uint16_t* textId, bool* loadFromMessageTable) { + if (!EnHy_RandomizerHoldsItem(TEXT_BEGGAR_BUY_BLUE_FIRE)) { + return; + } + + CustomMessage msg = CustomMessage( + "%cBlue Fire%w! I'll trade you %rsomething special%w for it. No returns! I get new " + "special inventory %bevery 7 years or so%w...", + "%cBlaues Feuer%w! Ich tausche es gegen %retwas Besonderes%w. Und nicht feilschen, okay! Ich bekomme neue " + "besondere Ware %balle 7 Jahre oder so%w...", + "%cFeu bleu%w ! Je l'échange contre %rquelque chose de spécial%w. Pas de retour ! Je reçois de nouveaux " + "articles spéciaux %btous les 7 ans environ%w..."); + msg.AutoFormat(); + msg.LoadIntoFont(); + *loadFromMessageTable = false; +} + +void BuildEnHyMessage_Fish(uint16_t* textId, bool* loadFromMessageTable) { + if (!EnHy_RandomizerHoldsItem(TEXT_BEGGAR_BUY_FISH)) { + return; + } + CustomMessage msg = CustomMessage( + "A %pfish%w! I'll trade you %rsomething special%w for it. No returns! I get new " + "special inventory %bevery 7 years or so%w...", + "Ein %pFisch%w! Ich tausche ihn gegen %retwas Besonderes%w. Und nicht feilschen, okay! Ich bekomme neue " + "besondere Ware %balle 7 Jahre oder so%w...", + "Un %ppoisson%w ! Je l'échange contre %rquelque chose de spécial%w. Pas de retour ! Je reçois de nouveaux " + "articles spéciaux %btous les 7 ans environ%w..."); + msg.AutoFormat(); + msg.LoadIntoFont(); + *loadFromMessageTable = false; +} + +void BuildEnHyMessage_Bug(uint16_t* textId, bool* loadFromMessageTable) { + if (!EnHy_RandomizerHoldsItem(TEXT_BEGGAR_BUY_BUGS)) { + return; + } + CustomMessage msg = + CustomMessage("A tiny %gbug%w! I'll trade you %rsomething special%w for it. No returns! I get new " + "special inventory %bevery 7 years or so%w...", + "Ein kleiner %gKäfer%w! Ich tausche ihn gegen %retwas Besonderes%w. Und nicht feilschen, okay! " + "Ich bekomme neue " + "besondere Ware %balle 7 Jahre oder so%w...", + "Un petit %ginsecte%w ! Je l'échange contre %rquelque chose de spécial%w. Pas de retour ! Je " + "reçois de nouveaux " + "articles spéciaux %btous les 7 ans environ%w..."); + msg.AutoFormat(); + msg.LoadIntoFont(); + *loadFromMessageTable = false; +} + +void RegisterShuffleBeggar() { + bool shouldRegister = IS_RANDO && Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_BEGGAR).Get(); + + COND_VB_SHOULD(VB_BEGGAR_GIVE_ITEM, shouldRegister, { + EnHy* enHy = va_arg(args, EnHy*); + int32_t beggarTextId = enHy->actor.textId; + + if (beggarTextId != TEXT_BEGGAR_BUY_FAIRY) { + if (EnHy_RandomizerHoldsItem(beggarTextId)) { + CheckIdentity beggarIdentity = ShuffleBeggar_GetBeggarIdentity(beggarTextId); + Flags_SetRandomizerInf(beggarIdentity.randomizerInf); + *should = false; + } + } + }); + + COND_ID_HOOK(OnOpenText, TEXT_BEGGAR_BUY_BLUE_FIRE, shouldRegister, BuildEnHyMessage_BlueFire); + COND_ID_HOOK(OnOpenText, TEXT_BEGGAR_BUY_FISH, shouldRegister, BuildEnHyMessage_Fish); + COND_ID_HOOK(OnOpenText, TEXT_BEGGAR_BUY_BUGS, shouldRegister, BuildEnHyMessage_Bug); +} + +void Rando::StaticData::RegisterBeggarLocations() { + static bool registered = false; + if (registered) + return; + registered = true; + // clang-format off + // Randomizer Check Randomizer Check Quest RCType Area Actor ID Scene ID Params Short Name Hint Text Key Vanilla Item Spoiler Collection Check + locationTable[RC_MK_BEGGAR_BUGS] = Location::Base(RC_MK_BEGGAR_BUGS, RCQUEST_BOTH, RCTYPE_BEGGAR, RCAREA_MARKET, ACTOR_EN_HY, SCENE_MARKET_DAY, 0x70F2, "Beggar Bugs", RHT_BEGGAR_MARKET, RG_PURPLE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_BEGGAR_BUGS)); + locationTable[RC_MK_BEGGAR_FISH] = Location::Base(RC_MK_BEGGAR_FISH, RCQUEST_BOTH, RCTYPE_BEGGAR, RCAREA_MARKET, ACTOR_EN_HY, SCENE_MARKET_DAY, 0x70F1, "Beggar Fish", RHT_BEGGAR_MARKET, RG_PURPLE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_BEGGAR_FISH)); + locationTable[RC_MK_BEGGAR_BLUE_FIRE] = Location::Base(RC_MK_BEGGAR_BLUE_FIRE, RCQUEST_BOTH, RCTYPE_BEGGAR, RCAREA_MARKET, ACTOR_EN_HY, SCENE_MARKET_DAY, 0x70F0, "Beggar Blue Fire", RHT_BEGGAR_MARKET, RG_HUGE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MK_BEGGAR_BLUE_FIRE)); + locationTable[RC_KAK_BEGGAR_BUGS] = Location::Base(RC_KAK_BEGGAR_BUGS, RCQUEST_BOTH, RCTYPE_BEGGAR, RCAREA_KAKARIKO_VILLAGE, ACTOR_EN_HY, SCENE_KAKARIKO_VILLAGE, 0x70F2, "Beggar Bugs", RHT_BEGGAR_KAKARIKO_VILLAGE, RG_PURPLE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_BEGGAR_BUGS)); + locationTable[RC_KAK_BEGGAR_FISH] = Location::Base(RC_KAK_BEGGAR_FISH, RCQUEST_BOTH, RCTYPE_BEGGAR, RCAREA_KAKARIKO_VILLAGE, ACTOR_EN_HY, SCENE_KAKARIKO_VILLAGE, 0x70F1, "Beggar Fish", RHT_BEGGAR_KAKARIKO_VILLAGE, RG_PURPLE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_BEGGAR_FISH)); + locationTable[RC_KAK_BEGGAR_BLUE_FIRE] = Location::Base(RC_KAK_BEGGAR_BLUE_FIRE, RCQUEST_BOTH, RCTYPE_BEGGAR, RCAREA_KAKARIKO_VILLAGE, ACTOR_EN_HY, SCENE_KAKARIKO_VILLAGE, 0x70F0, "Beggar Blue Fire", RHT_BEGGAR_KAKARIKO_VILLAGE, RG_HUGE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KAK_BEGGAR_BLUE_FIRE)); + // clang-format on +} + +static RegisterShipInitFunc registerShuffleBeggar(RegisterShuffleBeggar, { "IS_RANDO" }); +static RegisterShipInitFunc registerBeggarLocations(Rando::StaticData::RegisterBeggarLocations); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/kakariko.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/kakariko.cpp index 5cf4718c7..98105f5ed 100644 --- a/soh/soh/Enhancements/randomizer/location_access/overworld/kakariko.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/kakariko.cpp @@ -65,6 +65,9 @@ void RegionTable_Init_Kakariko() { LOCATION(RC_KAK_SOUTHEAST_EXIT_ARROW_SIGN, logic->CanRead()), LOCATION(RC_KAK_FRONT_GATE_ARROW_SIGN, logic->CanRead()), LOCATION(RC_KAK_WONDER_UNDER_CONSTRUCTION, logic->IsChild), + LOCATION(RC_KAK_BEGGAR_BUGS, logic->IsAdult && logic->CanUse(RG_BOTTLE_WITH_BUGS)), + LOCATION(RC_KAK_BEGGAR_FISH, logic->IsAdult && logic->CanUse(RG_BOTTLE_WITH_FISH)), + LOCATION(RC_KAK_BEGGAR_BLUE_FIRE, logic->IsAdult && logic->CanUse(RG_BOTTLE_WITH_BLUE_FIRE)), }, { //Exits ENTRANCE(RR_HYRULE_FIELD, true), diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp index 6a4648527..558c66539 100644 --- a/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp @@ -35,6 +35,9 @@ void RegionTable_Init_Market() { LOCATION(RC_MKT_WONDER_DAY_5, logic->IsChild && logic->AtDay), LOCATION(RC_MKT_WONDER_NIGHT_1, logic->IsChild && logic->AtNight), LOCATION(RC_MKT_WONDER_NIGHT_2, logic->IsChild && logic->AtNight), + LOCATION(RC_MK_BEGGAR_BUGS, logic->IsChild && logic->AtDay && logic->CanUse(RG_BOTTLE_WITH_BUGS)), + LOCATION(RC_MK_BEGGAR_FISH, logic->IsChild && logic->AtDay && logic->CanUse(RG_BOTTLE_WITH_FISH)), + LOCATION(RC_MK_BEGGAR_BLUE_FIRE, logic->IsChild && logic->AtDay && logic->CanUse(RG_BOTTLE_WITH_BLUE_FIRE)), }, { //Exits ENTRANCE(RR_MARKET_ENTRANCE, true), diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index 017ed13ca..d187c8dcd 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -495,6 +495,9 @@ void Settings::CreateOptionDescriptions() { "\n" "This setting does not effect the item earned from playing\n" "the Song of Storms and the frog song minigame."; + mOptionDescriptions[RSK_SHUFFLE_BEGGAR] = + "Shuffle the rewards the Beggar gives for selling bugs, fish, and Blue Fire.\n" + "The Beggar will give separate rewards to child and adult."; mOptionDescriptions[RSK_SHUFFLE_ADULT_TRADE] = "Adds all of the adult trade quest items into the pool, each of which " "can be traded for a unique reward.\n" diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index b48dbda99..a79e12972 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3272,6 +3272,13 @@ std::map rcToRandomizerInf = { { RC_GERUDO_TRAINING_GROUND_MQ_WONDER_DINOLFOS_ROOM, RAND_INF_GERUDO_TRAINING_GROUND_MQ_WONDER_DINOLFOS_ROOM }, { RC_GERUDO_TRAINING_GROUND_MQ_WONDER_EYE_STATUE, RAND_INF_GERUDO_TRAINING_GROUND_MQ_WONDER_EYE_STATUE }, { RC_GANONS_CASTLE_MQ_WONDER_SHADOW_TRIAL, RAND_INF_GANONS_CASTLE_MQ_WONDER_SHADOW_TRIAL }, + // Beggar + { RC_MK_BEGGAR_BUGS, RAND_INF_MK_BEGGAR_BUGS }, + { RC_MK_BEGGAR_FISH, RAND_INF_MK_BEGGAR_FISH }, + { RC_MK_BEGGAR_BLUE_FIRE, RAND_INF_MK_BEGGAR_BLUE_FIRE }, + { RC_KAK_BEGGAR_BUGS, RAND_INF_KAK_BEGGAR_BUGS }, + { RC_KAK_BEGGAR_FISH, RAND_INF_KAK_BEGGAR_FISH }, + { RC_KAK_BEGGAR_BLUE_FIRE, RAND_INF_KAK_BEGGAR_BLUE_FIRE }, }; CheckIdentity Randomizer::IdentifyBeehive(s32 sceneNum, s16 xPosition, s32 respawnData) { @@ -3817,6 +3824,22 @@ CheckIdentity Randomizer::IdentifyWonderItem(s32 sceneNum, s32 par1, s32 par2) { return wonderIdentity; } +CheckIdentity Randomizer::IdentifyBeggar(s32 sceneNum, s32 textId) { + CheckIdentity beggarIdentity; + beggarIdentity.randomizerInf = RAND_INF_MAX; + beggarIdentity.randomizerCheck = RC_UNKNOWN_CHECK; + + Rando::Location* location = GetCheckObjectFromActor(ACTOR_EN_HY, sceneNum, textId); + if (location->GetRandomizerCheck() == RC_UNKNOWN_CHECK) { + LUSLOG_WARN("IdentifyBeggar did not receive a valid RC value (%d).", location->GetRandomizerCheck()); + } else { + beggarIdentity.randomizerInf = rcToRandomizerInf[location->GetRandomizerCheck()]; + beggarIdentity.randomizerCheck = location->GetRandomizerCheck(); + } + + return beggarIdentity; +} + u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) { return Rando::Context::GetInstance()->GetOption(randoSettingKey).Get(); } diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 7b1fcdba4..ae2d45893 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -45,6 +45,7 @@ class Randomizer { CheckIdentity IdentifyTree(s32 sceneNum, s32 posX, s32 posZ); CheckIdentity IdentifySign(s32 sceneNum, s32 posX, s32 posZ, s32 id); CheckIdentity IdentifyWonderItem(s32 sceneNum, s32 par1, s32 par2); + CheckIdentity IdentifyBeggar(s32 sceneNum, s32 textId); GetItemEntry GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogItemId, bool checkObtainability = true); GetItemEntry GetItemFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogItemId, diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerCheck.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerCheck.h index a0056c0d0..07c9f1967 100644 --- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerCheck.h +++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerCheck.h @@ -2859,6 +2859,13 @@ RANDO_ENUM_ITEM(RC_SHADOW_TEMPLE_TRUTHSPINNER_RECTANGLE_SIGN) RANDO_ENUM_ITEM(RC_SHADOW_TEMPLE_FALLING_SPIKES_RECTANGLE_SIGN) // MQ Dungeon Signs RANDO_ENUM_ITEM(RC_SHADOW_TEMPLE_MQ_LOWER_PIT_RECTANGLE_SIGN) +// Beggar +RANDO_ENUM_ITEM(RC_MK_BEGGAR_BUGS) +RANDO_ENUM_ITEM(RC_MK_BEGGAR_FISH) +RANDO_ENUM_ITEM(RC_MK_BEGGAR_BLUE_FIRE) +RANDO_ENUM_ITEM(RC_KAK_BEGGAR_BUGS) +RANDO_ENUM_ITEM(RC_KAK_BEGGAR_FISH) +RANDO_ENUM_ITEM(RC_KAK_BEGGAR_BLUE_FIRE) RANDO_ENUM_ITEM(RC_MAX) RANDO_ENUM_END(RandomizerCheck) diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerHintTextKey.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerHintTextKey.h index cb69dca98..b9f653acc 100644 --- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerHintTextKey.h +++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerHintTextKey.h @@ -1605,6 +1605,9 @@ RANDO_ENUM_ITEM(RHT_SIGN_GERUDO_FORTRESS) RANDO_ENUM_ITEM(RHT_SIGN_HAUNTED_WASTELAND) RANDO_ENUM_ITEM(RHT_SIGN_DODONGOS_CAVERN) RANDO_ENUM_ITEM(RHT_SIGN_SHADOW_TEMPLE) +// BEGGAR +RANDO_ENUM_ITEM(RHT_BEGGAR_MARKET) +RANDO_ENUM_ITEM(RHT_BEGGAR_KAKARIKO_VILLAGE) // MAX RANDO_ENUM_ITEM(RHT_MAX) RANDO_ENUM_END(RandomizerHintTextKey) diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h index 95d5ff1cd..cb6f75891 100644 --- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h +++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h @@ -2426,6 +2426,13 @@ RANDO_ENUM_ITEM(RAND_INF_SHADOW_TEMPLE_TRUTHSPINNER_RECTANGLE_SIGN) RANDO_ENUM_ITEM(RAND_INF_SHADOW_TEMPLE_FALLING_SPIKES_RECTANGLE_SIGN) // MQ Dungeon Signs RANDO_ENUM_ITEM(RAND_INF_SHADOW_TEMPLE_MQ_LOWER_PIT_RECTANGLE_SIGN) +// Beggar +RANDO_ENUM_ITEM(RAND_INF_MK_BEGGAR_BUGS) +RANDO_ENUM_ITEM(RAND_INF_MK_BEGGAR_FISH) +RANDO_ENUM_ITEM(RAND_INF_MK_BEGGAR_BLUE_FIRE) +RANDO_ENUM_ITEM(RAND_INF_KAK_BEGGAR_BUGS) +RANDO_ENUM_ITEM(RAND_INF_KAK_BEGGAR_FISH) +RANDO_ENUM_ITEM(RAND_INF_KAK_BEGGAR_BLUE_FIRE) RANDO_ENUM_ITEM(RAND_INF_MAX) diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerMiscEnums.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerMiscEnums.h index 9581e44e1..bd5f53930 100644 --- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerMiscEnums.h +++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerMiscEnums.h @@ -132,6 +132,7 @@ RANDO_ENUM_ITEM(RCTYPE_SONG_FAIRY) // Fairies from Songs RANDO_ENUM_ITEM(RCTYPE_BUTTERFLY_FAIRY) // Fairies from Butterflies RANDO_ENUM_ITEM(RCTYPE_GRASS) // Grass RANDO_ENUM_ITEM(RCTYPE_SIGN) // Signs +RANDO_ENUM_ITEM(RCTYPE_BEGGAR) // Beggar RANDO_ENUM_END(RandomizerCheckType) RANDO_ENUM_BEGIN(RandomizerCheckQuest) diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h index 762f747c7..663208650 100644 --- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h +++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h @@ -160,6 +160,7 @@ RANDO_ENUM_ITEM(RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT) RANDO_ENUM_ITEM(RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT) RANDO_ENUM_ITEM(RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT) RANDO_ENUM_ITEM(RSK_MERCHANT_PRICES_AFFORDABLE) +RANDO_ENUM_ITEM(RSK_SHUFFLE_BEGGAR) RANDO_ENUM_ITEM(RSK_BLUE_FIRE_ARROWS) RANDO_ENUM_ITEM(RSK_SUNLIGHT_ARROWS) RANDO_ENUM_ITEM(RSK_SLINGBOW_BREAK_BEEHIVES) diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp index 23b7f505e..973db5993 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp @@ -140,6 +140,8 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() { (location.GetRCType() != RCTYPE_MERCHANT || CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), RO_SHUFFLE_MERCHANTS_OFF) != RO_SHUFFLE_MERCHANTS_OFF) && + (location.GetRCType() != RCTYPE_BEGGAR || + CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleBeggar"), RO_GENERIC_NO)) && (location.GetRCType() != RCTYPE_SONG_LOCATION || (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleSongs"), RO_SONG_SHUFFLE_SONG_LOCATIONS) != RO_SONG_SHUFFLE_SONG_LOCATIONS && diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index e52f6bd0a..3efe70ad6 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -83,6 +83,7 @@ bool showOverworldSigns; bool showDungeonSigns; bool showOverworldWonderItems; bool showDungeonWonderItems; +bool showBeggar; bool showFrogSongRupees; bool showFountainFairies; bool showStoneFairies; @@ -1512,6 +1513,7 @@ void LoadSettings() { showDungeonWonderItems = false; break; } + showBeggar = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BEGGAR); } else { // Vanilla showOverworldTokens = true; showDungeonTokens = true; @@ -1527,6 +1529,7 @@ void LoadSettings() { showBushes = false; showOverworldWonderItems = false; showDungeonWonderItems = false; + showBeggar = false; } fortressFast = false; @@ -1617,6 +1620,7 @@ bool IsCheckShuffled(RandomizerCheck rc) { (showMajorScrubs && (rc == RC_LW_DEKU_SCRUB_NEAR_BRIDGE || // The 3 scrubs that are always randomized rc == RC_HF_DEKU_SCRUB_GROTTO || rc == RC_LW_DEKU_SCRUB_GROTTO_FRONT))) && (loc->GetRCType() != RCTYPE_MERCHANT || showMerchants) && + (loc->GetRCType() != RCTYPE_BEGGAR || showBeggar) && (loc->GetRCType() != RCTYPE_SONG_LOCATION || showSongs) && (loc->GetRCType() != RCTYPE_BEEHIVE || showBeehives) && (loc->GetRCType() != RCTYPE_OCARINA || showOcarinas) && diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 581ce39bf..a69d95445 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -1009,6 +1009,7 @@ void Settings::CreateOptions() { OPT_U8(RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT, "Merchant Giant Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantGiantWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT], WIDGET_CVAR_SLIDER_INT, 10, true, nullptr, IMFLAG_NONE); OPT_U8(RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT, "Merchant Tycoon Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantTycoonWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT], WIDGET_CVAR_SLIDER_INT, 10, true, nullptr, IMFLAG_NONE); OPT_BOOL(RSK_MERCHANT_PRICES_AFFORDABLE, "Merchant Affordable Prices", CVAR_RANDOMIZER_SETTING("MerchantPricesAffordable"), mOptionDescriptions[RSK_MERCHANT_PRICES_AFFORDABLE]); + OPT_BOOL(RSK_SHUFFLE_BEGGAR, "Shuffle Beggar", CVAR_RANDOMIZER_SETTING("ShuffleBeggar"), mOptionDescriptions[RSK_SHUFFLE_BEGGAR]); OPT_BOOL(RSK_SHUFFLE_FROG_SONG_RUPEES, "Shuffle Frog Song Rupees", CVAR_RANDOMIZER_SETTING("ShuffleFrogSongRupees"), mOptionDescriptions[RSK_SHUFFLE_FROG_SONG_RUPEES]); OPT_BOOL(RSK_SHUFFLE_ADULT_TRADE, "Shuffle Adult Trade", CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), mOptionDescriptions[RSK_SHUFFLE_ADULT_TRADE]); OPT_U8(RSK_SHUFFLE_CHEST_MINIGAME, "Shuffle Chest Minigame", {"Off", "On (Separate)", "On (Pack)"}); @@ -1909,6 +1910,7 @@ void Settings::CreateOptions() { &mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT], &mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT], &mOptions[RSK_MERCHANT_PRICES_AFFORDABLE], + &mOptions[RSK_SHUFFLE_BEGGAR], }, WidgetContainerType::SECTION); mOptionGroups[RSG_MENU_COLUMN_SHOP_SHUFFLES] = @@ -2164,6 +2166,7 @@ void Settings::CreateOptions() { &mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT], &mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT], &mOptions[RSK_MERCHANT_PRICES_AFFORDABLE], + &mOptions[RSK_SHUFFLE_BEGGAR], &mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES], &mOptions[RSK_SHUFFLE_ADULT_TRADE], &mOptions[RSK_SHUFFLE_CHEST_MINIGAME], diff --git a/soh/soh/Enhancements/randomizer/static_data.h b/soh/soh/Enhancements/randomizer/static_data.h index 8d91f9b70..91a9ba64f 100644 --- a/soh/soh/Enhancements/randomizer/static_data.h +++ b/soh/soh/Enhancements/randomizer/static_data.h @@ -64,6 +64,7 @@ class StaticData { static void RegisterTreeLocations(); static void RegisterSignLocations(); static void RegisterWonderItemLocations(); + static void RegisterBeggarLocations(); static void InitHashMaps(); static std::array, 17> randomizerFishingPondFish; static std::unordered_map randomizerGrottoFishMap; diff --git a/soh/src/overlays/actors/ovl_En_Hy/z_en_hy.c b/soh/src/overlays/actors/ovl_En_Hy/z_en_hy.c index bcd1f362d..3d03a129c 100644 --- a/soh/src/overlays/actors/ovl_En_Hy/z_en_hy.c +++ b/soh/src/overlays/actors/ovl_En_Hy/z_en_hy.c @@ -610,7 +610,9 @@ s16 func_80A70058(PlayState* play, Actor* thisx) { case 0x70F1: case 0x70F2: case 0x70F3: - Rupees_ChangeBy(beggarRewards[this->actor.textId - 0x70F0]); + if (GameInteractor_Should(VB_BEGGAR_GIVE_ITEM, true, this)) { + Rupees_ChangeBy(beggarRewards[this->actor.textId - 0x70F0]); + } Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENHY_ANIM_17); Player_UpdateBottleHeld(play, GET_PLAYER(play), ITEM_BOTTLE, PLAYER_IA_BOTTLE); break;