Ganon's Boss Soul Instead

This commit is contained in:
Demur Rumed 2025-06-29 04:05:01 +00:00
commit 7b998d1f8b
12 changed files with 74 additions and 36 deletions

View file

@ -9,7 +9,6 @@
#include "hints.hpp" #include "hints.hpp"
#include "shops.hpp" #include "shops.hpp"
#include "pool_functions.hpp" #include "pool_functions.hpp"
//#include "debug.hpp"
#include "soh/Enhancements/randomizer/static_data.h" #include "soh/Enhancements/randomizer/static_data.h"
#include "soh/Enhancements/debugger/performanceTimer.h" #include "soh/Enhancements/debugger/performanceTimer.h"
@ -1058,10 +1057,9 @@ static void RandomizeOwnDungeon(const Rando::DungeonInfo* dungeon) {
AddElementsToPool(dungeonItems, dungeonSmallKeys); AddElementsToPool(dungeonItems, dungeonSmallKeys);
} }
if ((ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON) && if (ctx->GetOption(RSK_GANONS_SOUL) || dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY
dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY) || ? ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON)
(ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OWN_DUNGEON) && : ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OWN_DUNGEON)) {
dungeon->GetBossKey() == RG_GANONS_CASTLE_BOSS_KEY)) {
auto dungeonBossKey = auto dungeonBossKey =
FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i) { return i == dungeon->GetBossKey(); }); FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i) { return i == dungeon->GetBossKey(); });
AddElementsToPool(dungeonItems, dungeonBossKey); AddElementsToPool(dungeonItems, dungeonBossKey);
@ -1112,17 +1110,18 @@ static void RandomizeDungeonItems() {
} }
if (ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON) && if (ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON) &&
dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY) { (ctx->GetOption(RSK_GANONS_SOUL) || dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY)) {
auto bossKey = FilterAndEraseFromPool( auto bossKey = FilterAndEraseFromPool(
ItemPool, [dungeon](const RandomizerGet i) { return i == dungeon->GetBossKey(); }); ItemPool, [dungeon](const RandomizerGet i) { return i == dungeon->GetBossKey(); });
AddElementsToPool(anyDungeonItems, bossKey); AddElementsToPool(anyDungeonItems, bossKey);
} else if (ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD) && } else if (ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD) &&
dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY) { (ctx->GetOption(RSK_GANONS_SOUL) || dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY)) {
auto bossKey = FilterAndEraseFromPool( auto bossKey = FilterAndEraseFromPool(
ItemPool, [dungeon](const RandomizerGet i) { return i == dungeon->GetBossKey(); }); ItemPool, [dungeon](const RandomizerGet i) { return i == dungeon->GetBossKey(); });
AddElementsToPool(overworldItems, bossKey); AddElementsToPool(overworldItems, bossKey);
} }
if (!ctx->GetOption(RSK_GANONS_SOUL)) {
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_ANY_DUNGEON)) { if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_ANY_DUNGEON)) {
auto ganonBossKey = auto ganonBossKey =
FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == RG_GANONS_CASTLE_BOSS_KEY; }); FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == RG_GANONS_CASTLE_BOSS_KEY; });
@ -1133,6 +1132,7 @@ static void RandomizeDungeonItems() {
AddElementsToPool(overworldItems, ganonBossKey); AddElementsToPool(overworldItems, ganonBossKey);
} }
} }
}
if (ctx->GetOption(RSK_GERUDO_KEYS).Is(RO_GERUDO_KEYS_ANY_DUNGEON)) { if (ctx->GetOption(RSK_GERUDO_KEYS).Is(RO_GERUDO_KEYS_ANY_DUNGEON)) {
auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) {

View file

@ -1199,14 +1199,15 @@ void GenerateItemPool() {
} }
if (!ctx->GetOption(RSK_TRIFORCE_HUNT)) { // Don't add GBK to the pool at all for Triforce Hunt. if (!ctx->GetOption(RSK_TRIFORCE_HUNT)) { // Don't add GBK to the pool at all for Triforce Hunt.
auto rg = ctx->GetOption(RSK_GANONS_SOUL) ? RG_GANON_SOUL : RG_GANONS_CASTLE_BOSS_KEY;
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_KAK_TOKENS)) { if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_KAK_TOKENS)) {
ctx->PlaceItemInLocation(RC_KAK_100_GOLD_SKULLTULA_REWARD, RG_GANONS_CASTLE_BOSS_KEY); ctx->PlaceItemInLocation(RC_KAK_100_GOLD_SKULLTULA_REWARD, rg);
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Get() >= RO_GANON_BOSS_KEY_LACS_VANILLA) { } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Get() >= RO_GANON_BOSS_KEY_LACS_VANILLA) {
ctx->PlaceItemInLocation(RC_TOT_LIGHT_ARROWS_CUTSCENE, RG_GANONS_CASTLE_BOSS_KEY); ctx->PlaceItemInLocation(RC_TOT_LIGHT_ARROWS_CUTSCENE, rg);
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA)) { } else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA)) {
ctx->PlaceItemInLocation(RC_GANONS_TOWER_BOSS_KEY_CHEST, RG_GANONS_CASTLE_BOSS_KEY); ctx->PlaceItemInLocation(RC_GANONS_TOWER_BOSS_KEY_CHEST, rg);
} else { } else {
AddItemToMainPool(RG_GANONS_CASTLE_BOSS_KEY); AddItemToMainPool(rg);
} }
} }

View file

@ -57,7 +57,7 @@ void GenerateStartingInventory() {
// Add Ganon's Boss key with Triforce Hunt so the game thinks it's obtainable from the start. // Add Ganon's Boss key with Triforce Hunt so the game thinks it's obtainable from the start.
// During save init, the boss key isn't actually given and it's instead given when completing the triforce. // During save init, the boss key isn't actually given and it's instead given when completing the triforce.
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_STARTWITH) || ctx->GetOption(RSK_TRIFORCE_HUNT)) { if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_STARTWITH) || ctx->GetOption(RSK_TRIFORCE_HUNT)) {
AddItemToInventory(RG_GANONS_CASTLE_BOSS_KEY); AddItemToInventory(ctx->GetOption(RSK_GANONS_SOUL) ? RG_GANON_SOUL : RG_GANONS_CASTLE_BOSS_KEY);
} }
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) && if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) &&

View file

@ -544,6 +544,9 @@ void SetAllEntrancesData() {
{ { EntranceType::AdultBoss, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, RR_SHADOW_TEMPLE_BOSS_ROOM, ENTR_SHADOW_TEMPLE_BOSS_ENTRANCE }, { { EntranceType::AdultBoss, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, RR_SHADOW_TEMPLE_BOSS_ROOM, ENTR_SHADOW_TEMPLE_BOSS_ENTRANCE },
{ EntranceType::AdultBoss, RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, ENTR_SHADOW_TEMPLE_BOSS_DOOR } }, { EntranceType::AdultBoss, RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, ENTR_SHADOW_TEMPLE_BOSS_DOOR } },
{ { EntranceType::GanonBoss, RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR, RR_GANONS_TOWER_GANONDORF_LAIR, ENTR_GANONDORF_BOSS_0 },
{ EntranceType::GanonBoss, RR_GANONS_TOWER_GANONDORF_LAIR, RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR, ENTR_GANONS_TOWER_2 } },
{ { EntranceType::BlueWarp, RR_DEKU_TREE_BOSS_ROOM, RR_KF_OUTSIDE_DEKU_TREE, ENTR_KOKIRI_FOREST_DEKU_TREE_BLUE_WARP }, { { EntranceType::BlueWarp, RR_DEKU_TREE_BOSS_ROOM, RR_KF_OUTSIDE_DEKU_TREE, ENTR_KOKIRI_FOREST_DEKU_TREE_BLUE_WARP },
NO_RETURN_ENTRANCE }, NO_RETURN_ENTRANCE },
{ { EntranceType::BlueWarp, RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DEATH_MOUNTAIN_TRAIL, ENTR_DEATH_MOUNTAIN_TRAIL_DODONGO_BLUE_WARP }, { { EntranceType::BlueWarp, RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DEATH_MOUNTAIN_TRAIL, ENTR_DEATH_MOUNTAIN_TRAIL_DODONGO_BLUE_WARP },
@ -560,6 +563,8 @@ void SetAllEntrancesData() {
NO_RETURN_ENTRANCE }, NO_RETURN_ENTRANCE },
{ { EntranceType::BlueWarp, RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION, ENTR_GRAVEYARD_SHADOW_TEMPLE_BLUE_WARP }, { { EntranceType::BlueWarp, RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION, ENTR_GRAVEYARD_SHADOW_TEMPLE_BLUE_WARP },
NO_RETURN_ENTRANCE }, NO_RETURN_ENTRANCE },
{ { EntranceType::BlueWarp, RR_GANONS_TOWER_GANONDORF_LAIR, RR_GANONS_TOWER_FLOOR_1, ENTR_GANONS_TOWER_0 },
NO_RETURN_ENTRANCE },
// clang-format on // clang-format on
}; };
@ -760,7 +765,7 @@ static bool EntranceUnreachableAs(Entrance* entrance, uint8_t age, std::vector<E
static bool ValidateWorld(Entrance* entrancePlaced) { static bool ValidateWorld(Entrance* entrancePlaced) {
auto ctx = Rando::Context::GetInstance(); auto ctx = Rando::Context::GetInstance();
SPDLOG_DEBUG("Validating world\n"); SPDLOG_DEBUG("Validating world");
// check certain conditions when certain types of ER are enabled // check certain conditions when certain types of ER are enabled
EntranceType type = EntranceType::None; EntranceType type = EntranceType::None;
@ -1214,6 +1219,9 @@ int EntranceShuffler::ShuffleAllEntrances() {
if (ctx->GetOption(RSK_SHUFFLE_BOSS_ENTRANCES).Is(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_FULL)) { if (ctx->GetOption(RSK_SHUFFLE_BOSS_ENTRANCES).Is(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_FULL)) {
entrancePools[EntranceType::Boss] = GetShuffleableEntrances(EntranceType::ChildBoss); entrancePools[EntranceType::Boss] = GetShuffleableEntrances(EntranceType::ChildBoss);
AddElementsToPool(entrancePools[EntranceType::Boss], GetShuffleableEntrances(EntranceType::AdultBoss)); AddElementsToPool(entrancePools[EntranceType::Boss], GetShuffleableEntrances(EntranceType::AdultBoss));
if (ctx->GetOption(RSK_GANONS_SOUL)) {
AddElementsToPool(entrancePools[EntranceType::Boss], GetShuffleableEntrances(EntranceType::GanonBoss));
}
// If forest is closed, ensure Ghoma is inside the Deku tree // If forest is closed, ensure Ghoma is inside the Deku tree
// Deku tree being in its vanilla location is handled below // Deku tree being in its vanilla location is handled below
if (ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_ON) && if (ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_ON) &&
@ -1231,6 +1239,10 @@ int EntranceShuffler::ShuffleAllEntrances() {
} else { } else {
entrancePools[EntranceType::ChildBoss] = GetShuffleableEntrances(EntranceType::ChildBoss); entrancePools[EntranceType::ChildBoss] = GetShuffleableEntrances(EntranceType::ChildBoss);
entrancePools[EntranceType::AdultBoss] = GetShuffleableEntrances(EntranceType::AdultBoss); entrancePools[EntranceType::AdultBoss] = GetShuffleableEntrances(EntranceType::AdultBoss);
if (ctx->GetOption(RSK_GANONS_SOUL)) {
AddElementsToPool(entrancePools[EntranceType::AdultBoss],
GetShuffleableEntrances(EntranceType::GanonBoss));
}
// If forest is closed, ensure Ghoma is inside the Deku tree // If forest is closed, ensure Ghoma is inside the Deku tree
if (ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_ON) && if (ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_ON) &&
!(ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) || ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES))) { !(ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) || ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES))) {
@ -1506,6 +1518,8 @@ int EntranceShuffler::ShuffleAllEntrances() {
GetEntrance(RR_SPIRIT_TEMPLE_ENTRYWAY, RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE) }, GetEntrance(RR_SPIRIT_TEMPLE_ENTRYWAY, RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE) },
{ EntranceNameByRegions(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY), { EntranceNameByRegions(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY),
GetEntrance(RR_SHADOW_TEMPLE_ENTRYWAY, RR_GRAVEYARD_WARP_PAD_REGION) }, GetEntrance(RR_SHADOW_TEMPLE_ENTRYWAY, RR_GRAVEYARD_WARP_PAD_REGION) },
{ EntranceNameByRegions(RR_GANONS_TOWER_GANONDORF_LAIR, RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR),
GetEntrance(RR_GANONS_TOWER_ENTRYWAY, RR_GANONS_TOWER_FLOOR_1) },
}; };
// If a boss room is inside a dungeon entrance (or inside a dungeon which is inside a dungeon entrance), make // If a boss room is inside a dungeon entrance (or inside a dungeon which is inside a dungeon entrance), make
@ -1527,6 +1541,8 @@ int EntranceShuffler::ShuffleAllEntrances() {
GetEntrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_DESERT_COLOSSUS) }, GetEntrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_DESERT_COLOSSUS) },
{ EntranceNameByRegions(RR_SHADOW_TEMPLE_ENTRYWAY, RR_GRAVEYARD_WARP_PAD_REGION), { EntranceNameByRegions(RR_SHADOW_TEMPLE_ENTRYWAY, RR_GRAVEYARD_WARP_PAD_REGION),
GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION) }, GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION) },
{ EntranceNameByRegions(RR_GANONS_TOWER_ENTRYWAY, RR_GANONS_TOWER_FLOOR_1),
GetEntrance(RR_GANONS_TOWER_GANONDORF_LAIR, RR_GANONS_TOWER_FLOOR_1) },
}; };
// Pair <BlueWarp exit, BossRoom reverse exit> // Pair <BlueWarp exit, BossRoom reverse exit>
@ -1547,6 +1563,8 @@ int EntranceShuffler::ShuffleAllEntrances() {
GetEntrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY) }, GetEntrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY) },
{ GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION), { GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION),
GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY) }, GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY) },
{ GetEntrance(RR_GANONS_TOWER_GANONDORF_LAIR, RR_GANONS_TOWER_FLOOR_1),
GetEntrance(RR_GANONS_TOWER_GANONDORF_LAIR, RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR) },
}; };
for (EntrancePair pair : bossRoomExitPairs) { for (EntrancePair pair : bossRoomExitPairs) {
@ -1587,7 +1605,6 @@ void EntranceShuffler::CreateEntranceOverrides() {
int i = 0; int i = 0;
for (Entrance* entrance : allShuffleableEntrances) { for (Entrance* entrance : allShuffleableEntrances) {
// Include blue warps when dungeons or bosses are shuffled // Include blue warps when dungeons or bosses are shuffled
bool includeBluewarps = bool includeBluewarps =
entrance->GetType() == Rando::EntranceType::BlueWarp && entrance->GetType() == Rando::EntranceType::BlueWarp &&

View file

@ -25,6 +25,7 @@ enum class EntranceType {
ChildBossReverse, ChildBossReverse,
AdultBoss, AdultBoss,
AdultBossReverse, AdultBossReverse,
GanonBoss,
Interior, Interior,
InteriorReverse, InteriorReverse,
SpecialInterior, SpecialInterior,

View file

@ -2008,7 +2008,9 @@ void RandomizerOnActorInitHandler(void* actorRef) {
Actor_Kill(actor); Actor_Kill(actor);
} }
if (RAND_GET_OPTION(RSK_SHUFFLE_BOSS_SOULS)) { if (RAND_GET_OPTION(RSK_SHUFFLE_BOSS_SOULS) ||
(RAND_GET_OPTION(RSK_GANONS_SOUL) && gPlayState->sceneNum == SCENE_GANONDORF_BOSS ||
gPlayState->sceneNum == SCENE_GANON_BOSS)) {
// Boss souls require an additional item (represented by a RAND_INF) to spawn a boss in a particular lair // Boss souls require an additional item (represented by a RAND_INF) to spawn a boss in a particular lair
RandomizerInf currentBossSoulRandInf = RAND_INF_MAX; RandomizerInf currentBossSoulRandInf = RAND_INF_MAX;
switch (gPlayState->sceneNum) { switch (gPlayState->sceneNum) {
@ -2038,7 +2040,8 @@ void RandomizerOnActorInitHandler(void* actorRef) {
break; break;
case SCENE_GANONDORF_BOSS: case SCENE_GANONDORF_BOSS:
case SCENE_GANON_BOSS: case SCENE_GANON_BOSS:
if (RAND_GET_OPTION(RSK_SHUFFLE_BOSS_SOULS) == RO_BOSS_SOULS_ON_PLUS_GANON) { if (RAND_GET_OPTION(RSK_GANONS_SOUL) ||
RAND_GET_OPTION(RSK_SHUFFLE_BOSS_SOULS) == RO_BOSS_SOULS_ON_PLUS_GANON) {
currentBossSoulRandInf = RAND_INF_GANON_SOUL; currentBossSoulRandInf = RAND_INF_GANON_SOUL;
} }
break; break;
@ -2218,8 +2221,8 @@ void RandomizerOnPlayerUpdateHandler() {
if (!GameInteractor::IsGameplayPaused() && Flags_GetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY) && if (!GameInteractor::IsGameplayPaused() && Flags_GetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY) &&
gPlayState->transitionTrigger != TRANS_TRIGGER_START && gPlayState->transitionTrigger != TRANS_TRIGGER_START &&
(1 << 0 & gSaveContext.inventory.dungeonItems[SCENE_GANONS_TOWER]) == 0) { (1 << 0 & gSaveContext.inventory.dungeonItems[SCENE_GANONS_TOWER]) == 0) {
GiveItemEntryWithoutActor(gPlayState, auto rg = RAND_GET_OPTION(RSK_GANONS_SOUL) ? RG_GANON_SOUL : RG_GANONS_CASTLE_BOSS_KEY;
*Rando::StaticData::GetItemTable().at(RG_GANONS_CASTLE_BOSS_KEY).GetGIEntry()); GiveItemEntryWithoutActor(gPlayState, *Rando::StaticData::GetItemTable().at(rg).GetGIEntry());
} }
if (!GameInteractor::IsGameplayPaused() && RAND_GET_OPTION(RSK_TRIFORCE_HUNT)) { if (!GameInteractor::IsGameplayPaused() && RAND_GET_OPTION(RSK_TRIFORCE_HUNT)) {

View file

@ -430,16 +430,20 @@ bool Item::IsMajorItem() const {
return false; return false;
} }
if (type == ITEMTYPE_BOSSKEY && getItemId != 0xAD && if (type == ITEMTYPE_BOSSKEY) {
(ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_VANILLA) || if (getItemId == 0xAD && !ctx->GetOption(RSK_GANONS_SOUL)) {
ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON))) { // Ganons Castle Boss Key handled specially unless Ganon's Soul is wincon reward
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA) ||
ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OWN_DUNGEON)) {
return false; return false;
} }
// Ganons Castle Boss Key } else {
if (getItemId == 0xAD && (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA) || if (ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_VANILLA) ||
ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OWN_DUNGEON))) { ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON)) {
return false; return false;
} }
}
}
if (randomizerGet == RG_GREG_RUPEE) { if (randomizerGet == RG_GREG_RUPEE) {
return ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_GREG); return ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_GREG);

View file

@ -487,6 +487,8 @@ void RegionTable_Init_GanonsCastle() {
}, { }, {
//Exits //Exits
Entrance(RR_GANONS_CASTLE_ESCAPE, []{return logic->CanKillEnemy(RE_GANONDORF);}), Entrance(RR_GANONS_CASTLE_ESCAPE, []{return logic->CanKillEnemy(RE_GANONDORF);}),
Entrance(RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR, []{return false;}),
Entrance(RR_GANONS_TOWER_FLOOR_1, []{return false;}),
}); });
areaTable[RR_GANONS_CASTLE_ESCAPE] = Region("Ganon's Castle Escape", SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR, {}, { areaTable[RR_GANONS_CASTLE_ESCAPE] = Region("Ganon's Castle Escape", SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR, {}, {

View file

@ -595,6 +595,9 @@ void Settings::CreateOptionDescriptions() {
"\n" "\n"
"Greg as Wildcard - Greg does not change logic, Greg helps obtain GBK, max number of " "Greg as Wildcard - Greg does not change logic, Greg helps obtain GBK, max number of "
"rewards on slider does not change."; "rewards on slider does not change.";
mOptionDescriptions[RSK_GANONS_SOUL] = "Ganon's Boss Key reward replaced with Ganon's Soul.\n"
"GBK will be shuffled like a regular boss key.\n"
"Ganon's Tower's boss entrance may be shuffled.";
mOptionDescriptions[RSK_BIG_POE_COUNT] = "The Poe collector will give a reward for turning in this many Big Poes."; mOptionDescriptions[RSK_BIG_POE_COUNT] = "The Poe collector will give a reward for turning in this many Big Poes.";
mOptionDescriptions[RSK_SKIP_CHILD_STEALTH] = mOptionDescriptions[RSK_SKIP_CHILD_STEALTH] =
"The crawlspace into Hyrule Castle goes straight to Zelda, skipping the guards."; "The crawlspace into Hyrule Castle goes straight to Zelda, skipping the guards.";

View file

@ -5851,6 +5851,7 @@ typedef enum {
RSK_GERUDO_KEYS, RSK_GERUDO_KEYS,
RSK_BOSS_KEYSANITY, RSK_BOSS_KEYSANITY,
RSK_GANONS_BOSS_KEY, RSK_GANONS_BOSS_KEY,
RSK_GANONS_SOUL,
RSK_SKIP_CHILD_STEALTH, RSK_SKIP_CHILD_STEALTH,
RSK_SKIP_CHILD_ZELDA, RSK_SKIP_CHILD_ZELDA,
RSK_STARTING_STICKS, RSK_STARTING_STICKS,

View file

@ -380,7 +380,10 @@ const EntranceData entranceData[] = {
{ ENTR_GREAT_FAIRYS_FOUNTAIN_MAGIC_OGC_DD, ENTR_POTION_SHOP_KAKARIKO_1, SINGLE_SCENE_INFO(SCENE_OUTSIDE_GANONS_CASTLE), "OGC Behind Pillar", "OGC Great Fairy Fountain", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_INTERIOR, "outside ganon's castle", 1}, { ENTR_GREAT_FAIRYS_FOUNTAIN_MAGIC_OGC_DD, ENTR_POTION_SHOP_KAKARIKO_1, SINGLE_SCENE_INFO(SCENE_OUTSIDE_GANONS_CASTLE), "OGC Behind Pillar", "OGC Great Fairy Fountain", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_INTERIOR, "outside ganon's castle", 1},
{ ENTR_INSIDE_GANONS_CASTLE_ENTRANCE, ENTR_CASTLE_GROUNDS_RAINBOW_BRIDGE_EXIT, SINGLE_SCENE_INFO(SCENE_OUTSIDE_GANONS_CASTLE), "OGC Rainbow Bridge Exit", "Inside Ganon's Castle Entrance", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_DUNGEON, "outside ganon's castle,gc", 1}, { ENTR_INSIDE_GANONS_CASTLE_ENTRANCE, ENTR_CASTLE_GROUNDS_RAINBOW_BRIDGE_EXIT, SINGLE_SCENE_INFO(SCENE_OUTSIDE_GANONS_CASTLE), "OGC Rainbow Bridge Exit", "Inside Ganon's Castle Entrance", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_DUNGEON, "outside ganon's castle,gc", 1},
{ ENTR_POTION_SHOP_KAKARIKO_1, ENTR_GREAT_FAIRYS_FOUNTAIN_MAGIC_OGC_DD, {{ SCENE_GREAT_FAIRYS_FOUNTAIN_MAGIC, 0x02 }}, "OGC Great Fairy Fountain", "OGC Behind Pillar", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_INTERIOR, "outside ganon's castle"}, { ENTR_POTION_SHOP_KAKARIKO_1, ENTR_GREAT_FAIRYS_FOUNTAIN_MAGIC_OGC_DD, {{ SCENE_GREAT_FAIRYS_FOUNTAIN_MAGIC, 0x02 }}, "OGC Great Fairy Fountain", "OGC Behind Pillar", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_INTERIOR, "outside ganon's castle"},
{ ENTR_CASTLE_GROUNDS_RAINBOW_BRIDGE_EXIT, ENTR_INSIDE_GANONS_CASTLE_ENTRANCE, SINGLE_SCENE_INFO(SCENE_INSIDE_GANONS_CASTLE), "Inside Ganon's Castle Entrance", "OGC Rainbow Bridge Exit", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_DUNGEON, "outside ganon's castle,gc"} { ENTR_CASTLE_GROUNDS_RAINBOW_BRIDGE_EXIT, ENTR_INSIDE_GANONS_CASTLE_ENTRANCE, SINGLE_SCENE_INFO(SCENE_INSIDE_GANONS_CASTLE), "Inside Ganon's Castle Entrance", "OGC Rainbow Bridge Exit", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_DUNGEON, "outside ganon's castle,gc"},
{ ENTR_GANONDORF_BOSS_0, ENTR_GANONS_TOWER_2, SINGLE_SCENE_INFO(SCENE_GANONS_TOWER), "Ganon's Tower Boss Door", "Ganondorf", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_DUNGEON, "", 1},
{ ENTR_GANONS_TOWER_2, ENTR_GANONDORF_BOSS_0, SINGLE_SCENE_INFO(SCENE_GANONDORF_BOSS), "Ganondorf", "Ganon's Tower Boss Door", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_DUNGEON, "", 1},
{ ENTR_GANONS_TOWER_0, -1, SINGLE_SCENE_INFO(SCENE_GANONDORF_BOSS), "Ganondorf Blue Warp", "Ganon's Tower Blue Warp", ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_GROUP_HYRULE_CASTLE, ENTRANCE_TYPE_ONE_WAY, "bw", 1},
// clang-format on // clang-format on
}; };

View file

@ -251,6 +251,7 @@ void Settings::CreateOptions() {
OPT_U8(RSK_LACS_DUNGEON_COUNT, "GCBK Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsDungeonCount"), "", WidgetType::Slider, 8, true); OPT_U8(RSK_LACS_DUNGEON_COUNT, "GCBK Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsDungeonCount"), "", WidgetType::Slider, 8, true);
OPT_U8(RSK_LACS_TOKEN_COUNT, "GCBK Token Count", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsTokenCount"), "", WidgetType::Slider, 100, true); OPT_U8(RSK_LACS_TOKEN_COUNT, "GCBK Token Count", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsTokenCount"), "", WidgetType::Slider, 100, true);
OPT_U8(RSK_LACS_OPTIONS, "GCBK LACS Reward Options", {"Standard Reward", "Greg as Reward", "Greg as Wildcard"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardOptions"), mOptionDescriptions[RSK_LACS_OPTIONS], WidgetType::Combobox, RO_LACS_STANDARD_REWARD); OPT_U8(RSK_LACS_OPTIONS, "GCBK LACS Reward Options", {"Standard Reward", "Greg as Reward", "Greg as Wildcard"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardOptions"), mOptionDescriptions[RSK_LACS_OPTIONS], WidgetType::Combobox, RO_LACS_STANDARD_REWARD);
OPT_BOOL(RSK_GANONS_SOUL, "Ganon's Soul Instead", CVAR_RANDOMIZER_SETTING("ShuffleGanonSoul"), mOptionDescriptions[RSK_GANONS_SOUL]);
OPT_U8(RSK_KEYRINGS, "Key Rings", {"Off", "Random", "Count", "Selection"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRings"), mOptionDescriptions[RSK_KEYRINGS], WidgetType::Combobox, RO_KEYRINGS_OFF); OPT_U8(RSK_KEYRINGS, "Key Rings", {"Off", "Random", "Count", "Selection"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRings"), mOptionDescriptions[RSK_KEYRINGS], WidgetType::Combobox, RO_KEYRINGS_OFF);
OPT_U8(RSK_KEYRINGS_RANDOM_COUNT, "Keyring Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsRandomCount"), "", WidgetType::Slider, 8); OPT_U8(RSK_KEYRINGS_RANDOM_COUNT, "Keyring Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsRandomCount"), "", WidgetType::Slider, 8);
OPT_U8(RSK_KEYRINGS_GERUDO_FORTRESS, "Gerudo Fortress Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGerudoFortress"), "", WidgetType::Combobox, 0); OPT_U8(RSK_KEYRINGS_GERUDO_FORTRESS, "Gerudo Fortress Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGerudoFortress"), "", WidgetType::Combobox, 0);
@ -1305,6 +1306,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_GERUDO_KEYS], &mOptions[RSK_GERUDO_KEYS],
&mOptions[RSK_BOSS_KEYSANITY], &mOptions[RSK_BOSS_KEYSANITY],
&mOptions[RSK_GANONS_BOSS_KEY], &mOptions[RSK_GANONS_BOSS_KEY],
&mOptions[RSK_GANONS_SOUL],
&mOptions[RSK_LACS_STONE_COUNT], &mOptions[RSK_LACS_STONE_COUNT],
&mOptions[RSK_LACS_MEDALLION_COUNT], &mOptions[RSK_LACS_MEDALLION_COUNT],
&mOptions[RSK_LACS_DUNGEON_COUNT], &mOptions[RSK_LACS_DUNGEON_COUNT],
@ -1543,6 +1545,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_GERUDO_KEYS], &mOptions[RSK_GERUDO_KEYS],
&mOptions[RSK_BOSS_KEYSANITY], &mOptions[RSK_BOSS_KEYSANITY],
&mOptions[RSK_GANONS_BOSS_KEY], &mOptions[RSK_GANONS_BOSS_KEY],
&mOptions[RSK_GANONS_SOUL],
&mOptions[RSK_LACS_STONE_COUNT], &mOptions[RSK_LACS_STONE_COUNT],
&mOptions[RSK_LACS_MEDALLION_COUNT], &mOptions[RSK_LACS_MEDALLION_COUNT],
&mOptions[RSK_LACS_DUNGEON_COUNT], &mOptions[RSK_LACS_DUNGEON_COUNT],