diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index 8ac2d9dda39..2a9f8153278 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -108,6 +108,11 @@ void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state); #pragma message("Compiling without support, the Hook Debugger will not be available") #endif +// Forward Declarations +namespace Rando { +class Location; +}; + typedef uint32_t HOOK_ID; enum HookType { @@ -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(hookId); \ + hookId = GameInteractor::Instance->RegisterGameHook( \ + [](Rando::Location* location, bool* should) { \ + auto ctx = OTRGlobals::Instance->gRandoContext; \ + body; \ + }); \ + } class GameInteractor { public: diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h index 30aa16a2aa1..5d80146fafa 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h @@ -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)); DEFINE_HOOK(OnSetGameLanguage, ()); DEFINE_HOOK(OnAssetAltChange, ()); diff --git a/soh/soh/Enhancements/randomizer/ShuffleBeehives.cpp b/soh/soh/Enhancements/randomizer/ShuffleBeehives.cpp index 00c060cf901..a3722e832e5 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleBeehives.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleBeehives.cpp @@ -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); diff --git a/soh/soh/Enhancements/randomizer/ShuffleCows.cpp b/soh/soh/Enhancements/randomizer/ShuffleCows.cpp index 63fbd858cd5..f02a9f08473 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleCows.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleCows.cpp @@ -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, { diff --git a/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp b/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp index 007c12bc004..3294f8d6213 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleCrates.cpp @@ -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; + } + } + } else { + *should = false; + } + } + }); + bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_CRATES); COND_ID_HOOK(OnActorInit, ACTOR_OBJ_KIBAKO2, shouldRegister, ObjKibako2_RandomizerInit); diff --git a/soh/soh/Enhancements/randomizer/ShuffleFairies.cpp b/soh/soh/Enhancements/randomizer/ShuffleFairies.cpp index d4a58ee5508..4b6498e33ce 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleFairies.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleFairies.cpp @@ -1,3 +1,4 @@ +#include "soh/Enhancements/randomizer/randomizerTypes.h" #include "soh/OTRGlobals.h" #include "randomizer_grotto.h" #include "draw.h" @@ -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); diff --git a/soh/soh/Enhancements/randomizer/ShuffleFreestanding.cpp b/soh/soh/Enhancements/randomizer/ShuffleFreestanding.cpp index dac2911964d..1079300af13 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleFreestanding.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleFreestanding.cpp @@ -1,3 +1,4 @@ +#include "soh/Enhancements/randomizer/randomizerTypes.h" #include extern "C" { @@ -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, { diff --git a/soh/soh/Enhancements/randomizer/ShuffleFrogs.cpp b/soh/soh/Enhancements/randomizer/ShuffleFrogs.cpp new file mode 100644 index 00000000000..7aa3619b8fd --- /dev/null +++ b/soh/soh/Enhancements/randomizer/ShuffleFrogs.cpp @@ -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" }); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp b/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp index d82c3b39320..1dbac6a69c3 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleGrass.cpp @@ -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); diff --git a/soh/soh/Enhancements/randomizer/ShuffleMasterSword.cpp b/soh/soh/Enhancements/randomizer/ShuffleMasterSword.cpp new file mode 100644 index 00000000000..5b520805316 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/ShuffleMasterSword.cpp @@ -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" }); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/ShufflePots.cpp b/soh/soh/Enhancements/randomizer/ShufflePots.cpp index 815562578ab..c2fc2d1252f 100644 --- a/soh/soh/Enhancements/randomizer/ShufflePots.cpp +++ b/soh/soh/Enhancements/randomizer/ShufflePots.cpp @@ -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) { diff --git a/soh/soh/Enhancements/randomizer/ShuffleScrubs.cpp b/soh/soh/Enhancements/randomizer/ShuffleScrubs.cpp new file mode 100644 index 00000000000..790122648e9 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/ShuffleScrubs.cpp @@ -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: + break; + default: + *should = false; + break; + } + } + } + }); +} + +static RegisterShipInitFunc registerShuffleScrubs(RegisterShuffleScrubs, { "IS_RANDO" }); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/ShuffleSkulltulaRewards.cpp b/soh/soh/Enhancements/randomizer/ShuffleSkulltulaRewards.cpp new file mode 100644 index 00000000000..a2e08354ddc --- /dev/null +++ b/soh/soh/Enhancements/randomizer/ShuffleSkulltulaRewards.cpp @@ -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" }); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/ShuffleTradeItems.c b/soh/soh/Enhancements/randomizer/ShuffleTradeItems.cpp similarity index 54% rename from soh/soh/Enhancements/randomizer/ShuffleTradeItems.c rename to soh/soh/Enhancements/randomizer/ShuffleTradeItems.cpp index 8b43884e4b0..e62646a75b4 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleTradeItems.c +++ b/soh/soh/Enhancements/randomizer/ShuffleTradeItems.cpp @@ -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(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(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(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(tradeIndex + RAND_INF_CHILD_TRADES_HAS_WEIRD_EGG))) { return ITEM_POCKET_EGG + tradeIndex; } } diff --git a/soh/soh/Enhancements/randomizer/ShuffleTradeItems.h b/soh/soh/Enhancements/randomizer/ShuffleTradeItems.h index a43f7de5274..fcd128ec4c5 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleTradeItems.h +++ b/soh/soh/Enhancements/randomizer/ShuffleTradeItems.h @@ -3,9 +3,15 @@ #include +#ifdef __cplusplus +extern "C" { +#endif u8 Randomizer_GetNextChildTradeItem(); u8 Randomizer_GetPrevChildTradeItem(); u8 Randomizer_GetNextAdultTradeItem(); u8 Randomizer_GetPrevAdultTradeItem(); +#ifdef __cplusplus +} +#endif #endif diff --git a/soh/soh/Enhancements/randomizer/ShuffleTrees.cpp b/soh/soh/Enhancements/randomizer/ShuffleTrees.cpp index 14cb9c7b1d2..86e4bb1ebe4 100644 --- a/soh/soh/Enhancements/randomizer/ShuffleTrees.cpp +++ b/soh/soh/Enhancements/randomizer/ShuffleTrees.cpp @@ -160,6 +160,19 @@ void EnWood02_RandomizerInit(void* actorRef) { } void RegisterShuffleTrees() { + SHOULD_SHUFFLE_LOCATION({ + if (location->GetRCType() == RCTYPE_TREE) { + if (RAND_GET_OPTION(RSK_SHUFFLE_TREES) == RO_GENERIC_OFF) { + *should = false; + } + } + if (location->GetRCType() == RCTYPE_NLTREE) { + if (RAND_GET_OPTION(RSK_SHUFFLE_TREES) == RO_GENERIC_OFF || + RAND_GET_OPTION(RSK_LOGIC_RULES) != RO_LOGIC_NO_LOGIC) { + *should = false; + } + } + }) bool shouldRegister = IS_RANDO && Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_TREES).Get(); COND_ID_HOOK(OnActorInit, ACTOR_EN_WOOD02, shouldRegister, EnWood02_RandomizerInit); diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp index ef680862556..3ca7248f158 100644 --- a/soh/soh/Enhancements/randomizer/context.cpp +++ b/soh/soh/Enhancements/randomizer/context.cpp @@ -161,92 +161,40 @@ bool Context::IsQuestOfLocationActive(RandomizerCheck rc) { loc->GetQuest() == RCQUEST_VANILLA && mDungeons->GetDungeonFromScene(loc->GetScene())->IsVanilla(); } +bool Context::ShouldAddLocationToPool(Location* location, bool result) { + bool boolResult = static_cast(result); + // A few things that need to return false regardless of any settings + if (location->GetRandomizerCheck() == RC_UNKNOWN_CHECK || location->GetRandomizerCheck() == RC_TRIFORCE_COMPLETED || + location->GetRCType() == RCTYPE_CHEST_GAME || // not supported yet + location->GetRCType() == RCTYPE_STATIC_HINT || // can't have items + location->GetRCType() == RCTYPE_GOSSIP_STONE || // can't have items + (location->IsDungeon() && location->GetQuest() != RCQUEST_BOTH && + (location->GetQuest() == RCQUEST_MQ) != GetDungeon(location->GetArea() - RCAREA_DEKU_TREE)->IsMQ())) { + return false; + } + GameInteractor::Instance->ExecuteHooks(location, &boolResult); + return boolResult; +} + void Context::GenerateLocationPool() { allLocations.clear(); overworldLocations.clear(); for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) { dungeon->locations.clear(); } + for (Location& location : StaticData::GetLocationTable()) { - // skip RCs that shouldn't be in the pool for any reason (i.e. settings, unsupported check type, etc.) - // TODO: Exclude checks for some of the older shuffles from the pool too i.e. Frog Songs, Scrubs, etc.) - if (location.GetRandomizerCheck() == RC_UNKNOWN_CHECK || - location.GetRandomizerCheck() == RC_TRIFORCE_COMPLETED || // already in pool - (location.GetRandomizerCheck() == RC_TOT_MASTER_SWORD && - mOptions[RSK_SHUFFLE_MASTER_SWORD].Is(RO_GENERIC_OFF)) || - (location.GetRandomizerCheck() == RC_KAK_100_GOLD_SKULLTULA_REWARD && - mOptions[RSK_SHUFFLE_100_GS_REWARD].Is(RO_GENERIC_OFF)) || - location.GetRCType() == RCTYPE_CHEST_GAME || // not supported yet - location.GetRCType() == RCTYPE_STATIC_HINT || // can't have items - location.GetRCType() == RCTYPE_GOSSIP_STONE || // can't have items - (location.GetRCType() == RCTYPE_FROG_SONG && mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES].Is(RO_GENERIC_OFF)) || - (location.GetRCType() == RCTYPE_SCRUB && mOptions[RSK_SHUFFLE_SCRUBS].Is(RO_SCRUBS_OFF)) || - (location.GetRCType() == RCTYPE_SCRUB && mOptions[RSK_SHUFFLE_SCRUBS].Is(RO_SCRUBS_ONE_TIME_ONLY) && - !(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_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 && - mOptions[RSK_FISHSANITY].IsNot(RO_FISHSANITY_HYRULE_LOACH)) || - (location.GetRCType() == RCTYPE_FISH && !mFishsanity->GetFishLocationIncluded(&location)) || - (location.GetRCType() == RCTYPE_POT && mOptions[RSK_SHUFFLE_POTS].Is(RO_SHUFFLE_POTS_OFF)) || - (location.GetRCType() == RCTYPE_GRASS && mOptions[RSK_SHUFFLE_GRASS].Is(RO_SHUFFLE_GRASS_OFF)) || - (location.GetRCType() == RCTYPE_CRATE && mOptions[RSK_SHUFFLE_CRATES].Is(RO_SHUFFLE_CRATES_OFF)) || - (location.GetRCType() == RCTYPE_NLCRATE && (mOptions[RSK_SHUFFLE_CRATES].Is(RO_SHUFFLE_CRATES_OFF) || - mOptions[RSK_LOGIC_RULES].IsNot(RO_LOGIC_NO_LOGIC))) || - (location.GetRCType() == RCTYPE_SMALL_CRATE && mOptions[RSK_SHUFFLE_CRATES].Is(RO_SHUFFLE_CRATES_OFF)) || - (location.GetRCType() == RCTYPE_FOUNTAIN_FAIRY && !mOptions[RSK_SHUFFLE_FOUNTAIN_FAIRIES]) || - (location.GetRCType() == RCTYPE_STONE_FAIRY && !mOptions[RSK_SHUFFLE_STONE_FAIRIES]) || - (location.GetRCType() == RCTYPE_BEAN_FAIRY && !mOptions[RSK_SHUFFLE_BEAN_FAIRIES]) || - (location.GetRCType() == RCTYPE_SONG_FAIRY && !mOptions[RSK_SHUFFLE_SONG_FAIRIES]) || - (location.GetRCType() == RCTYPE_TREE && !mOptions[RSK_SHUFFLE_TREES]) || - (location.GetRCType() == RCTYPE_NLTREE && - (!mOptions[RSK_SHUFFLE_TREES] || mOptions[RSK_LOGIC_RULES].IsNot(RO_LOGIC_NO_LOGIC))) || - (location.GetRCType() == RCTYPE_FREESTANDING && - mOptions[RSK_SHUFFLE_FREESTANDING].Is(RO_SHUFFLE_FREESTANDING_OFF)) || - (location.GetRCType() == RCTYPE_BEEHIVE && !mOptions[RSK_SHUFFLE_BEEHIVES])) { - continue; - } - if (location.IsOverworld()) { - // Skip stuff that is shuffled to dungeon only, i.e. tokens, pots, etc., or other checks that - // should not have a shuffled item. - if ((location.GetRCType() == RCTYPE_FREESTANDING && - mOptions[RSK_SHUFFLE_FREESTANDING].Is(RO_SHUFFLE_FREESTANDING_DUNGEONS)) || - (location.GetRCType() == RCTYPE_POT && mOptions[RSK_SHUFFLE_POTS].Is(RO_SHUFFLE_POTS_DUNGEONS)) || - (location.GetRCType() == RCTYPE_GRASS && mOptions[RSK_SHUFFLE_GRASS].Is(RO_SHUFFLE_GRASS_DUNGEONS)) || - (location.GetRCType() == RCTYPE_CRATE && mOptions[RSK_SHUFFLE_CRATES].Is(RO_SHUFFLE_CRATES_DUNGEONS)) || - (location.GetRCType() == RCTYPE_NLCRATE && - mOptions[RSK_SHUFFLE_CRATES].Is(RO_SHUFFLE_CRATES_DUNGEONS) && - mOptions[RSK_LOGIC_RULES].Is(RO_LOGIC_NO_LOGIC)) || - (location.GetRCType() == RCTYPE_SMALL_CRATE && - mOptions[RSK_SHUFFLE_CRATES].Is(RO_SHUFFLE_CRATES_DUNGEONS))) { - continue; - } - // If we've gotten past all the conditions where an overworld location should not be - // shuffled, add it to the pool. - AddLocation(location.GetRandomizerCheck(), &overworldLocations); + if (ShouldAddLocationToPool(&location, true)) { + // If we've gotten here, we are definitely adding the location to the pool, + // determine if we are adding to to overworldLocations or a dungeon's location + // list. AddLocation(location.GetRandomizerCheck()); - } else { // is a dungeon check - auto* dungeon = GetDungeon(location.GetArea() - RCAREA_DEKU_TREE); - if (location.GetQuest() == RCQUEST_BOTH || (location.GetQuest() == RCQUEST_MQ) == dungeon->IsMQ()) { - if ((location.GetRCType() == RCTYPE_FREESTANDING && - mOptions[RSK_SHUFFLE_FREESTANDING].Is(RO_SHUFFLE_FREESTANDING_OVERWORLD)) || - (location.GetRCType() == RCTYPE_POT && mOptions[RSK_SHUFFLE_POTS].Is(RO_SHUFFLE_POTS_OVERWORLD)) || - (location.GetRCType() == RCTYPE_GRASS && - mOptions[RSK_SHUFFLE_GRASS].Is(RO_SHUFFLE_GRASS_OVERWORLD)) || - (location.GetRCType() == RCTYPE_CRATE && - mOptions[RSK_SHUFFLE_CRATES].Is(RO_SHUFFLE_CRATES_OVERWORLD)) || - (location.GetRCType() == RCTYPE_NLCRATE && - mOptions[RSK_SHUFFLE_CRATES].Is(RO_SHUFFLE_CRATES_OVERWORLD) && - mOptions[RSK_LOGIC_RULES].Is(RO_LOGIC_NO_LOGIC)) || - (location.GetRCType() == RCTYPE_SMALL_CRATE && - mOptions[RSK_SHUFFLE_CRATES].Is(RO_SHUFFLE_CRATES_OVERWORLD))) { - continue; - } + if (location.IsOverworld()) { + AddLocation(location.GetRandomizerCheck(), &overworldLocations); + } else { // Is a Dungeon check + auto* dungeon = GetDungeon(location.GetArea() - RCAREA_DEKU_TREE); // also add to that dungeon's location list. AddLocation(location.GetRandomizerCheck(), &dungeon->locations); - AddLocation(location.GetRandomizerCheck()); } } } diff --git a/soh/soh/Enhancements/randomizer/context.h b/soh/soh/Enhancements/randomizer/context.h index 96894775680..50209c7e110 100644 --- a/soh/soh/Enhancements/randomizer/context.h +++ b/soh/soh/Enhancements/randomizer/context.h @@ -54,6 +54,7 @@ class Context { template void AddLocations(const Container& locations, std::vector* destination = nullptr); bool IsQuestOfLocationActive(RandomizerCheck rc); + bool ShouldAddLocationToPool(Location* location, bool result); void GenerateLocationPool(); static std::vector GetLocations(const std::vector& locationPool, const RandomizerCheckType checkType); diff --git a/soh/soh/Enhancements/randomizer/fishsanity.cpp b/soh/soh/Enhancements/randomizer/fishsanity.cpp index 83d326384b3..e4506dd632f 100644 --- a/soh/soh/Enhancements/randomizer/fishsanity.cpp +++ b/soh/soh/Enhancements/randomizer/fishsanity.cpp @@ -634,4 +634,22 @@ void Rando::StaticData::RegisterFishLocations() { // clang-format on } +// RANDOTODO: Convert fishsanity to "Shuffle Fish" and use hooks like +// the newer shuffles. +void RegisterShuffleFish() { + SHOULD_SHUFFLE_LOCATION({ + if (location->GetRCType() == RCTYPE_FISH) { + if (!OTRGlobals::Instance->gRandoContext->GetFishsanity()->GetFishLocationIncluded(location)) { + *should = false; + } + } + if (location->GetRandomizerCheck() == RC_LH_HYRULE_LOACH) { + if (RAND_GET_OPTION(RSK_FISHSANITY) != RO_FISHSANITY_HYRULE_LOACH) { + *should = false; + } + } + }); +} + +static RegisterShipInitFunc registerShuffleFish(RegisterShuffleFish, { "IS_RANDO" }); static RegisterShipInitFunc initFunc(Rando::StaticData::RegisterFishLocations);