shuffle scrubs: use object extensions (#5853)

This commit is contained in:
Philip Dubé
2026-01-02 01:08:39 +00:00
committed by GitHub
parent 14a241ed3f
commit ff0c309b5a
5 changed files with 51 additions and 38 deletions

View File

@@ -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<DnsItemEntry> RegisterDnsItemEntryOverride;
static ObjectExtension::Register<ScrubIdentity> 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<ScrubIdentity>(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<ScrubIdentity>(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<ScrubIdentity>(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<ScrubIdentity>(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<EnDns*>(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<DnsItemEntry>(actorRef, std::move(DnsItemEntry{
enDns->dnsItemEntry->itemPrice,
1,
scrubIdentity.getItemId,
EnDns_RandomizerPurchaseableCheck,
EnDns_RandomizerPurchase,
}));
enDns->dnsItemEntry = ObjectExtension::GetInstance().Get<DnsItemEntry>(actorRef);
if (enDns->sohScrubIdentity.itemPrice != -1) {
enDns->dnsItemEntry->itemPrice = enDns->sohScrubIdentity.itemPrice;
if (scrubIdentity.itemPrice != -1) {
enDns->dnsItemEntry->itemPrice = scrubIdentity.itemPrice;
}
ObjectExtension::GetInstance().Set<ScrubIdentity>(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<GameInteractor::OnActorUpdate>([](void* innerActorRef) {
Actor* innerActor = static_cast<Actor*>(innerActorRef);
if (innerActor->id == ACTOR_EN_DNS) {
EnDns* innerEnDns = static_cast<EnDns*>(innerActorRef);
if (innerEnDns->sohScrubIdentity.isShuffled) {
if (ObjectExtension::GetInstance().Has<ScrubIdentity>(innerActor)) {
innerActor->textId = TEXT_SCRUB_RANDOM;
}
}

View File

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

View File

@@ -6856,7 +6856,6 @@ typedef struct ScrubIdentity {
RandomizerCheck randomizerCheck;
GetItemID getItemId;
int32_t itemPrice;
uint8_t isShuffled;
} ScrubIdentity;
typedef struct ShopItemIdentity {

View File

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

View File

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