Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions soh/soh/Enhancements/game-interactor/GameInteractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state);
#pragma message("Compiling without <source_location> support, the Hook Debugger will not be available")
#endif

// Forward Declarations
namespace Rando {
class Location;
};

typedef uint32_t HOOK_ID;

enum HookType {
Expand Down Expand Up @@ -188,6 +193,16 @@ struct HookInfo {
hookId = REGISTER_VB_SHOULD(id, body); \
} \
}
#define SHOULD_SHUFFLE_LOCATION(body) \
{ \
static HOOK_ID hookId = 0; \
GameInteractor::Instance->UnregisterGameHook<GameInteractor::ShouldAddLocationToPool>(hookId); \
hookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::ShouldAddLocationToPool>( \
[](Rando::Location* location, bool* should) { \
auto ctx = OTRGlobals::Instance->gRandoContext; \
body; \
}); \
}

class GameInteractor {
public:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ DEFINE_HOOK(OnUpdateFileBossRushOptionSelection, (uint8_t optionIndex, uint8_t o
DEFINE_HOOK(OnUpdateFileRandomizerOptionSelection, (uint8_t optionIndex));
DEFINE_HOOK(OnUpdateFileNameSelection, (int16_t charCode));
DEFINE_HOOK(OnFileChooseMain, (void* gameState));

// Rando Generation
DEFINE_HOOK(OnGenerationCompletion, ());
DEFINE_HOOK(ShouldAddLocationToPool, (Rando::Location * location, bool* result));
Copy link
Contributor

@serprex serprex Nov 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
DEFINE_HOOK(ShouldAddLocationToPool, (Rando::Location * location, bool* result));
DEFINE_HOOK(ShouldAddLocationToPool, (Rando::Location* location, bool* result));

surprised clang-format let this by

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had it like that before, clang-format was the one that changed it.


DEFINE_HOOK(OnSetGameLanguage, ());
DEFINE_HOOK(OnAssetAltChange, ());
Expand Down
6 changes: 6 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleBeehives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ void ObjComb_RandomizerUpdate(void* actor) {
}

void RegisterShuffleBeehives() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRCType() == RCTYPE_BEEHIVE) {
*should = ctx->GetOption(RSK_SHUFFLE_BEEHIVES).Is(RO_GENERIC_ON);
}
});

bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_BEEHIVES);

COND_ID_HOOK(OnActorInit, ACTOR_OBJ_COMB, shouldRegister, ObjComb_RandomizerInit);
Expand Down
6 changes: 6 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleCows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ void EnCow_MoveForRandomizer(EnCow* enCow, PlayState* play) {
}

void RegisterShuffleCows() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRCType() == RCTYPE_COW) {
*should = ctx->GetOption(RSK_SHUFFLE_COWS).Is(RO_GENERIC_ON);
}
});

bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_COWS);

COND_VB_SHOULD(VB_GIVE_ITEM_FROM_COW, shouldRegister, {
Expand Down
32 changes: 32 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleCrates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,38 @@ void ObjKibako_RandomizerInit(void* actorRef) {
}

void RegisterShuffleCrates() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRCType() == RCTYPE_CRATE || location->GetRCType() == RCTYPE_SMALL_CRATE) {
if (RAND_GET_OPTION(RSK_SHUFFLE_CRATES) == RO_SHUFFLE_CRATES_OFF) {
*should = false;
} else if (ctx->GetOption(RSK_SHUFFLE_CRATES).Is(RO_SHUFFLE_CRATES_ALL)) {
*should = true;
} else {
if (location->IsOverworld()) {
*should = RAND_GET_OPTION(RSK_SHUFFLE_CRATES) == RO_SHUFFLE_CRATES_OVERWORLD;
} else {
*should = RAND_GET_OPTION(RSK_SHUFFLE_CRATES) == RO_SHUFFLE_CRATES_DUNGEONS;
}
}
} else if (location->GetRCType() == RCTYPE_NLCRATE) {
if (RAND_GET_OPTION(RSK_LOGIC_RULES) == RO_LOGIC_NO_LOGIC) {
if (RAND_GET_OPTION(RSK_SHUFFLE_CRATES) == RO_SHUFFLE_CRATES_OFF) {
*should = false;
} else if (ctx->GetOption(RSK_SHUFFLE_CRATES).Is(RO_SHUFFLE_CRATES_ALL)) {
*should = true;
} else {
if (location->IsOverworld()) {
*should = RAND_GET_OPTION(RSK_SHUFFLE_CRATES) == RO_SHUFFLE_CRATES_OVERWORLD;
} else {
*should = RAND_GET_OPTION(RSK_SHUFFLE_CRATES) == RO_SHUFFLE_CRATES_DUNGEONS;
}
}
Comment on lines +301 to +307
Copy link
Contributor

@serprex serprex Nov 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate why you didn't make this one long else-if chain, but the extra level of indentation still irks me

ofc I'm degenerate enough to use ?: here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a few of the earlier ones I converted that I may go back and clean up a bit

} else {
*should = false;
}
}
});

bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_CRATES);

COND_ID_HOOK(OnActorInit, ACTOR_OBJ_KIBAKO2, shouldRegister, ObjKibako2_RandomizerInit);
Expand Down
15 changes: 15 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleFairies.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "soh/Enhancements/randomizer/randomizerTypes.h"
#include "soh/OTRGlobals.h"
#include "randomizer_grotto.h"
#include "draw.h"
Expand Down Expand Up @@ -89,6 +90,20 @@ static bool SpawnFairy(f32 posX, f32 posY, f32 posZ, int32_t params, FairyType f
}

void RegisterShuffleFairies() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRCType() == RCTYPE_FOUNTAIN_FAIRY) {
*should = RAND_GET_OPTION(RSK_SHUFFLE_FOUNTAIN_FAIRIES) == RO_GENERIC_ON;
}
if (location->GetRCType() == RCTYPE_STONE_FAIRY) {
*should = RAND_GET_OPTION(RSK_SHUFFLE_STONE_FAIRIES) == RO_GENERIC_ON;
}
if (location->GetRCType() == RCTYPE_BEAN_FAIRY) {
*should = RAND_GET_OPTION(RSK_SHUFFLE_BEAN_FAIRIES) == RO_GENERIC_ON;
}
if (location->GetRCType() == RCTYPE_SONG_FAIRY) {
*should = RAND_GET_OPTION(RSK_SHUFFLE_SONG_FAIRIES) == RO_GENERIC_ON;
}
});
bool shouldRegisterFountain = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_FOUNTAIN_FAIRIES);
bool shouldRegisterStone = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_STONE_FAIRIES);
bool shouldRegisterBean = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_BEAN_FAIRIES);
Expand Down
14 changes: 14 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleFreestanding.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "soh/Enhancements/randomizer/randomizerTypes.h"
#include <soh/OTRGlobals.h>

extern "C" {
Expand All @@ -9,6 +10,19 @@ extern PlayState* gPlayState;
extern void EnItem00_DrawRandomizedItem(EnItem00* enItem00, PlayState* play);

void RegisterShuffleFreestanding() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRCType() == RCTYPE_FREESTANDING) {
if (RAND_GET_OPTION(RSK_SHUFFLE_FREESTANDING) == RO_SHUFFLE_FREESTANDING_OFF) {
*should = false;
}
if (RAND_GET_OPTION(RSK_SHUFFLE_FREESTANDING) == RO_SHUFFLE_FREESTANDING_OVERWORLD) {
*should = location->IsOverworld();
}
if (RAND_GET_OPTION(RSK_SHUFFLE_FREESTANDING) == RO_SHUFFLE_FREESTANDING_DUNGEONS) {
*should = location->IsDungeon();
}
}
});
bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_FREESTANDING);

COND_VB_SHOULD(VB_ITEM00_DESPAWN, shouldRegister, {
Expand Down
15 changes: 15 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleFrogs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/randomizer/randomizerTypes.h"
#include "soh/OTRGlobals.h"
#include "soh/ShipInit.hpp"
void RegisterShuffleFrogs() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRCType() == RCTYPE_FROG_SONG) {
if (RAND_GET_OPTION(RSK_SHUFFLE_FROG_SONG_RUPEES) == RO_GENERIC_OFF) {
*should = false;
}
}
});
}

static RegisterShipInitFunc registerShuffleFrogs(RegisterShuffleFrogs, { "IS_RANDO" });
13 changes: 13 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleGrass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,19 @@ void EnKusa_RandomizerInit(void* actorRef) {
}

void RegisterShuffleGrass() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRCType() == RCTYPE_GRASS) {
if (RAND_GET_OPTION(RSK_SHUFFLE_GRASS) == RO_SHUFFLE_GRASS_OFF) {
*should = false;
}
if (RAND_GET_OPTION(RSK_SHUFFLE_GRASS) == RO_SHUFFLE_GRASS_OVERWORLD) {
*should = location->IsOverworld();
}
if (RAND_GET_OPTION(RSK_SHUFFLE_GRASS) == RO_SHUFFLE_GRASS_DUNGEONS) {
*should = location->IsDungeon();
}
}
});
bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_GRASS);

COND_ID_HOOK(OnActorInit, ACTOR_EN_KUSA, shouldRegister, EnKusa_RandomizerInit);
Expand Down
19 changes: 19 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleMasterSword.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/randomizer/context.h"
#include "soh/OTRGlobals.h"
#include "soh/ShipInit.hpp"

// RANDOTODO: Convert remaining Shuffle Master Sword Changes to use
// hooks in this file.

void RegisterShuffleMasterSword() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRandomizerCheck() == RC_TOT_MASTER_SWORD) {
if (RAND_GET_OPTION(RSK_SHUFFLE_MASTER_SWORD) == RO_GENERIC_OFF) {
*should = false;
}
}
});
}

static RegisterShipInitFunc registerShuffleMasterSword(RegisterShuffleMasterSword, { "IS_RANDO" });
15 changes: 15 additions & 0 deletions soh/soh/Enhancements/randomizer/ShufflePots.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,21 @@ void ObjTsubo_RandomizerSpawnCollectible(ObjTsubo* potActor, PlayState* play) {
}

void RegisterShufflePots() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRCType() == RCTYPE_POT) {
switch (RAND_GET_OPTION(RSK_SHUFFLE_POTS)) {
case RO_SHUFFLE_POTS_OFF:
*should = false;
break;
case RO_SHUFFLE_POTS_OVERWORLD:
*should = location->IsOverworld();
break;
case RO_SHUFFLE_POTS_DUNGEONS:
*should = location->IsDungeon();
break;
}
}
});
bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_POTS);

COND_ID_HOOK(OnActorInit, ACTOR_OBJ_TSUBO, shouldRegister, [](void* actorRef) {
Expand Down
32 changes: 32 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleScrubs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/randomizer/context.h"
#include "soh/Enhancements/randomizer/randomizerTypes.h"
#include "soh/OTRGlobals.h"
#include "soh/ShipInit.hpp"

// RANDOTODO: Convert the reset of Scrub Shuffle to be in this file and
// use hooks appropriately

void RegisterShuffleScrubs() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRCType() == RCTYPE_SCRUB) {
switch (RAND_GET_OPTION(RSK_SHUFFLE_SCRUBS)) {
case RO_SCRUBS_OFF:
*should = false;
break;
case RO_SCRUBS_ONE_TIME_ONLY:
switch (location->GetRandomizerCheck()) {
case RC_LW_DEKU_SCRUB_GROTTO_FRONT:
case RC_LW_DEKU_SCRUB_NEAR_BRIDGE:
case RC_HF_DEKU_SCRUB_GROTTO:
Copy link
Contributor

@serprex serprex Nov 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
case RC_HF_DEKU_SCRUB_GROTTO:
case RC_HF_DEKU_SCRUB_GROTTO:
*should = true;

need this no? I'm confused what not setting *should does since everything is wrapped in checking RCTYPE first, where if RCTYPE mismatch happens we don't touch *should so I'd expect default is false

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*should defaults to true, you only need to change it if it should be false. I did it that way on purpose so if you try to do a new shuffle, it's true and all the basic checks that we always shuffle don't need any hooks. Some of the ones I converted first set *should to a boolean expression, it's just that setting it to true is effectively "doing nothing" in those cases. These are what I meant when I said I might go back and clean some of those up a bit more.

break;
default:
*should = false;
break;
}
}
}
});
}

static RegisterShipInitFunc registerShuffleScrubs(RegisterShuffleScrubs, { "IS_RANDO" });
20 changes: 20 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleSkulltulaRewards.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/randomizer/context.h"
#include "soh/Enhancements/randomizer/randomizerTypes.h"
#include "soh/OTRGlobals.h"
#include "soh/ShipInit.hpp"

// RANDOTODO: Convert the rest of the skulltula reward handling
// to use hooks in this file.

void RegisterShuffleSkulltulaRewards() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRandomizerCheck() == RC_KAK_100_GOLD_SKULLTULA_REWARD) {
if (RAND_GET_OPTION(RSK_SHUFFLE_100_GS_REWARD) == RO_GENERIC_OFF) {
*should = false;
}
}
});
}

static RegisterShipInitFunc registerShuffleSkulltulaRewards(RegisterShuffleSkulltulaRewards, { "IS_RANDO" });
Original file line number Diff line number Diff line change
@@ -1,49 +1,68 @@
#include "soh/Enhancements/randomizer/context.h"
#include "soh/Enhancements/randomizer/randomizerTypes.h"
#include "soh/OTRGlobals.h"
#include "functions.h"
extern "C" {
#include "variables.h"
#include "macros.h"
}

// RANDOTODO: Migrate other aspects of adult trade shuffle to hooks here.

void RegisterAdultTradeShuffle() {
SHOULD_SHUFFLE_LOCATION({
if (location->GetRCType() == RCTYPE_ADULT_TRADE) {
if (RAND_GET_OPTION(RSK_SHUFFLE_ADULT_TRADE) == RO_GENERIC_OFF) {
*should = false;
}
}
})
}

static RegisterShipInitFunc registerAdultTradeShuffle(RegisterAdultTradeShuffle, { "IS_RANDO" });

u8 Randomizer_GetNextChildTradeItem() {
extern "C" u8 Randomizer_GetNextChildTradeItem() {
const u8 numTradeItems = ITEM_MASK_TRUTH - ITEM_WEIRD_EGG + 1;
u8 currentTradeItemIndex = INV_CONTENT(ITEM_TRADE_CHILD) - ITEM_WEIRD_EGG;
for (int i = 0; i < numTradeItems; i++) {
u8 tradeIndex = (currentTradeItemIndex + i + 1) % numTradeItems;
if (Flags_GetRandomizerInf(tradeIndex + RAND_INF_CHILD_TRADES_HAS_WEIRD_EGG)) {
if (Flags_GetRandomizerInf(static_cast<RandomizerInf>(tradeIndex + RAND_INF_CHILD_TRADES_HAS_WEIRD_EGG))) {
return ITEM_WEIRD_EGG + tradeIndex;
}
}
return ITEM_NONE;
}

u8 Randomizer_GetPrevChildTradeItem() {
extern "C" u8 Randomizer_GetPrevChildTradeItem() {
const u8 numTradeItems = ITEM_MASK_TRUTH - ITEM_WEIRD_EGG + 1;
u8 currentTradeItemIndex = INV_CONTENT(ITEM_TRADE_CHILD) - ITEM_WEIRD_EGG;
for (int i = 0; i < numTradeItems; i++) {
u8 tradeIndex = (currentTradeItemIndex - i - 1 + numTradeItems) % numTradeItems;
if (Flags_GetRandomizerInf(tradeIndex + RAND_INF_CHILD_TRADES_HAS_WEIRD_EGG)) {
if (Flags_GetRandomizerInf(static_cast<RandomizerInf>(tradeIndex + RAND_INF_CHILD_TRADES_HAS_WEIRD_EGG))) {
return ITEM_WEIRD_EGG + tradeIndex;
}
}
return ITEM_NONE;
}

u8 Randomizer_GetNextAdultTradeItem() {
extern "C" u8 Randomizer_GetNextAdultTradeItem() {
const u8 numTradeItems = ITEM_CLAIM_CHECK - ITEM_POCKET_EGG + 1;
u8 currentTradeItemIndex = INV_CONTENT(ITEM_TRADE_ADULT) - ITEM_POCKET_EGG;
for (int i = 0; i < numTradeItems; i++) {
u8 tradeIndex = (currentTradeItemIndex + i + 1) % numTradeItems;
if (Flags_GetRandomizerInf(tradeIndex + RAND_INF_ADULT_TRADES_HAS_POCKET_EGG)) {
if (Flags_GetRandomizerInf(static_cast<RandomizerInf>(tradeIndex + RAND_INF_CHILD_TRADES_HAS_WEIRD_EGG))) {
return ITEM_POCKET_EGG + tradeIndex;
}
}
return ITEM_NONE;
}

u8 Randomizer_GetPrevAdultTradeItem() {
extern "C" u8 Randomizer_GetPrevAdultTradeItem() {
const u8 numTradeItems = ITEM_CLAIM_CHECK - ITEM_POCKET_EGG + 1;
u8 currentTradeItemIndex = INV_CONTENT(ITEM_TRADE_ADULT) - ITEM_POCKET_EGG;
for (int i = 0; i < numTradeItems; i++) {
u8 tradeIndex = (currentTradeItemIndex - i - 1 + numTradeItems) % numTradeItems;
if (Flags_GetRandomizerInf(tradeIndex + RAND_INF_ADULT_TRADES_HAS_POCKET_EGG)) {
if (Flags_GetRandomizerInf(static_cast<RandomizerInf>(tradeIndex + RAND_INF_CHILD_TRADES_HAS_WEIRD_EGG))) {
return ITEM_POCKET_EGG + tradeIndex;
}
}
Expand Down
6 changes: 6 additions & 0 deletions soh/soh/Enhancements/randomizer/ShuffleTradeItems.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@

#include <libultraship/libultra/types.h>

#ifdef __cplusplus
extern "C" {
#endif
u8 Randomizer_GetNextChildTradeItem();
u8 Randomizer_GetPrevChildTradeItem();
u8 Randomizer_GetNextAdultTradeItem();
u8 Randomizer_GetPrevAdultTradeItem();
#ifdef __cplusplus
}
#endif

#endif
Loading
Loading