From ff0c309b5a9d01abb205228e88e93f77582f2f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Fri, 2 Jan 2026 01:08:39 +0000 Subject: [PATCH] shuffle scrubs: use object extensions (#5853) --- .../Enhancements/randomizer/hook_handlers.cpp | 54 ++++++++++++------- .../Enhancements/randomizer/randomizer.cpp | 15 +++--- .../Enhancements/randomizer/randomizerTypes.h | 1 - soh/soh/OTRGlobals.cpp | 15 +++--- soh/src/overlays/actors/ovl_En_Dns/z_en_dns.h | 4 -- 5 files changed, 51 insertions(+), 38 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 7b4cd7645..1605f6fc4 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -13,6 +13,7 @@ #include "soh/Notification/Notification.h" #include "soh/SaveManager.h" #include "soh/ShipInit.hpp" +#include "soh/ObjectExtension/ObjectExtension.h" extern "C" { #include "macros.h" @@ -58,6 +59,9 @@ extern "C" { #include "src/overlays/actors/ovl_Obj_Bean/z_obj_bean.h" #include "draw.h" +static ObjectExtension::Register RegisterDnsItemEntryOverride; +static ObjectExtension::Register RegisterScrubIdentity; + extern SaveContext gSaveContext; extern PlayState* gPlayState; extern void func_8084DFAC(PlayState* play, Player* player); @@ -767,8 +771,11 @@ void RandomizerOnDialogMessageHandler() { case TEXT_SCRUB_RANDOM: if (ctx->GetOption(RSK_SCRUB_TEXT_HINT).Get() != RO_GENERIC_OFF) { EnDns* enDns = (EnDns*)actor; - reveal = OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf( - (RandomizerInf)enDns->sohScrubIdentity.randomizerInf); + auto checkIdentity = ObjectExtension::GetInstance().Get(actor); + if (checkIdentity != nullptr) { + reveal = + OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf(checkIdentity->randomizerInf); + } } break; case TEXT_BEAN_SALESMAN_BUY_FOR_10: @@ -1391,14 +1398,14 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l ScrubIdentity scrubIdentity = OTRGlobals::Instance->gRandomizer->IdentifyScrub( gPlayState->sceneNum, enShopnuts->actor.params, respawnData); - if (scrubIdentity.isShuffled) { + if (scrubIdentity.randomizerCheck != RC_UNKNOWN_CHECK) { *should = Flags_GetRandomizerInf(scrubIdentity.randomizerInf); } break; } case VB_GIVE_ITEM_FROM_BUSINESS_SCRUB: { EnDns* enDns = va_arg(args, EnDns*); - *should = !enDns->sohScrubIdentity.isShuffled; + *should = !ObjectExtension::GetInstance().Has(enDns); break; } // To explain the logic because Fado and Grog are linked: @@ -1981,18 +1988,22 @@ void EnSi_DrawRandomizedItem(EnSi* enSi, PlayState* play) { } u32 EnDns_RandomizerPurchaseableCheck(EnDns* enDns) { - if (Flags_GetRandomizerInf(enDns->sohScrubIdentity.randomizerInf)) { - return 3; // Can't get this now + auto checkIdentity = ObjectExtension::GetInstance().Get(enDns); + if (checkIdentity != nullptr && Flags_GetRandomizerInf(checkIdentity->randomizerInf)) { + return DNS_CANBUY_RESULT_CANT_GET_NOW; } if (gSaveContext.rupees < enDns->dnsItemEntry->itemPrice) { - return 0; // Not enough rupees + return DNS_CANBUY_RESULT_NEED_RUPEES; } - return 4; + return DNS_CANBUY_RESULT_SUCCESS; } void EnDns_RandomizerPurchase(EnDns* enDns) { Rupees_ChangeBy(-enDns->dnsItemEntry->itemPrice); - Flags_SetRandomizerInf(enDns->sohScrubIdentity.randomizerInf); + auto checkIdentity = ObjectExtension::GetInstance().Get(enDns); + if (checkIdentity != nullptr) { + Flags_SetRandomizerInf(checkIdentity->randomizerInf); + } } void RandomizerOnActorInitHandler(void* actorRef) { @@ -2061,21 +2072,25 @@ void RandomizerOnActorInitHandler(void* actorRef) { if (actor->id == ACTOR_EN_DNS) { EnDns* enDns = static_cast(actorRef); s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1); - enDns->sohScrubIdentity = + auto scrubIdentity = OTRGlobals::Instance->gRandomizer->IdentifyScrub(gPlayState->sceneNum, enDns->actor.params, respawnData); - if (enDns->sohScrubIdentity.isShuffled) { + if (scrubIdentity.randomizerCheck != RC_UNKNOWN_CHECK) { // DNS uses pointers so we're creating our own entry instead of modifying the original - enDns->sohDnsItemEntry = { - enDns->dnsItemEntry->itemPrice, 1, enDns->sohScrubIdentity.getItemId, EnDns_RandomizerPurchaseableCheck, - EnDns_RandomizerPurchase, - }; - enDns->dnsItemEntry = &enDns->sohDnsItemEntry; + ObjectExtension::GetInstance().Set(actorRef, std::move(DnsItemEntry{ + enDns->dnsItemEntry->itemPrice, + 1, + scrubIdentity.getItemId, + EnDns_RandomizerPurchaseableCheck, + EnDns_RandomizerPurchase, + })); + enDns->dnsItemEntry = ObjectExtension::GetInstance().Get(actorRef); - if (enDns->sohScrubIdentity.itemPrice != -1) { - enDns->dnsItemEntry->itemPrice = enDns->sohScrubIdentity.itemPrice; + if (scrubIdentity.itemPrice != -1) { + enDns->dnsItemEntry->itemPrice = scrubIdentity.itemPrice; } + ObjectExtension::GetInstance().Set(actorRef, std::move(scrubIdentity)); enDns->actor.textId = TEXT_SCRUB_RANDOM; static uint32_t enDnsUpdateHook = 0; @@ -2085,8 +2100,7 @@ void RandomizerOnActorInitHandler(void* actorRef) { GameInteractor::Instance->RegisterGameHook([](void* innerActorRef) { Actor* innerActor = static_cast(innerActorRef); if (innerActor->id == ACTOR_EN_DNS) { - EnDns* innerEnDns = static_cast(innerActorRef); - if (innerEnDns->sohScrubIdentity.isShuffled) { + if (ObjectExtension::GetInstance().Has(innerActor)) { innerActor->textId = TEXT_SCRUB_RANDOM; } } diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 77e8c0b3c..5064b61c0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3653,7 +3653,6 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa scrubIdentity.randomizerCheck = RC_UNKNOWN_CHECK; scrubIdentity.getItemId = GI_NONE; scrubIdentity.itemPrice = -1; - scrubIdentity.isShuffled = false; // Scrubs that are 0x06 are loaded as 0x03 when child, switching from selling arrows to seeds if (actorParams == 0x06) @@ -3666,17 +3665,19 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa Rando::Location* location = GetCheckObjectFromActor(ACTOR_EN_DNS, sceneNum, actorParams); if (location->GetRandomizerCheck() != RC_UNKNOWN_CHECK) { - scrubIdentity.randomizerInf = rcToRandomizerInf[location->GetRandomizerCheck()]; - scrubIdentity.randomizerCheck = location->GetRandomizerCheck(); - scrubIdentity.getItemId = (GetItemID)Rando::StaticData::RetrieveItem(location->GetVanillaItem()).GetItemID(); - scrubIdentity.isShuffled = GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) == RO_SCRUBS_ALL; - if (location->GetRandomizerCheck() == RC_HF_DEKU_SCRUB_GROTTO || location->GetRandomizerCheck() == RC_LW_DEKU_SCRUB_GROTTO_FRONT || location->GetRandomizerCheck() == RC_LW_DEKU_SCRUB_NEAR_BRIDGE) { - scrubIdentity.isShuffled = GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) != RO_SCRUBS_OFF; + if (GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) == RO_SCRUBS_OFF) { + return scrubIdentity; + } + } else if (GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) != RO_SCRUBS_ALL) { + return scrubIdentity; } + scrubIdentity.randomizerInf = rcToRandomizerInf[location->GetRandomizerCheck()]; + scrubIdentity.randomizerCheck = location->GetRandomizerCheck(); + scrubIdentity.getItemId = (GetItemID)Rando::StaticData::RetrieveItem(location->GetVanillaItem()).GetItemID(); scrubIdentity.itemPrice = OTRGlobals::Instance->gRandoContext->GetItemLocation(scrubIdentity.randomizerCheck)->GetPrice(); } diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 6809c7172..a94b15b9b 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -6856,7 +6856,6 @@ typedef struct ScrubIdentity { RandomizerCheck randomizerCheck; GetItemID getItemId; int32_t itemPrice; - uint8_t isShuffled; } ScrubIdentity; typedef struct ShopItemIdentity { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index a3e30bca4..77aaf6a52 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -37,6 +37,7 @@ #include "Enhancements/randomizer/static_data.h" #include "Enhancements/randomizer/dungeon.h" #include "Enhancements/gameplaystats.h" +#include "ObjectExtension/ObjectExtension.h" #include "frame_interpolation.h" #include "variables.h" #include "z64.h" @@ -2532,12 +2533,14 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { (RandomizerInf)((textId - TEXT_SHOP_ITEM_RANDOM_CONFIRM) + RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1)); messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(rc, TEXT_SHOP_ITEM_RANDOM_CONFIRM); } else if (textId == TEXT_SCRUB_RANDOM) { - EnDns* enDns = (EnDns*)player->talkActor; - RandomizerCheck rc = OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf( - (RandomizerInf)enDns->sohScrubIdentity.randomizerInf); - messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage( - rc, TEXT_SCRUB_RANDOM, TEXT_SCRUB_RANDOM_FREE, - Randomizer_GetSettingValue(RSK_SCRUB_TEXT_HINT) == RO_GENERIC_OFF); + auto scrubIdentity = ObjectExtension::GetInstance().Get(player->talkActor); + if (scrubIdentity != nullptr) { + RandomizerCheck rc = + OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf(scrubIdentity->randomizerInf); + messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage( + rc, TEXT_SCRUB_RANDOM, TEXT_SCRUB_RANDOM_FREE, + Randomizer_GetSettingValue(RSK_SCRUB_TEXT_HINT) == RO_GENERIC_OFF); + } } else if (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("RandomizeRupeeNames"), 1) && (textId == TEXT_BLUE_RUPEE || textId == TEXT_RED_RUPEE || textId == TEXT_PURPLE_RUPEE || textId == TEXT_HUGE_RUPEE)) { diff --git a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.h b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.h index 9924a9686..f56840e9f 100644 --- a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.h +++ b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.h @@ -62,10 +62,6 @@ typedef struct EnDns { /* 0x02BD */ u8 dropCollectible; /* 0x02C0 */ DnsItemEntry* dnsItemEntry; /* 0x02C4 */ f32 yInitPos; - // #region SOH [Randomizer] - /* */ DnsItemEntry sohDnsItemEntry; - /* */ ScrubIdentity sohScrubIdentity; - // #endregion } EnDns; // size = 0x02C8 #endif