Shuffle Treasure Chest Game (#7020)

This commit is contained in:
Philip Dubé
2026-08-07 03:17:10 +00:00
committed by GitHub
parent 45c199b47c
commit 6706b49d1c
27 changed files with 419 additions and 261 deletions
@@ -281,8 +281,8 @@ std::map<std::string, CosmeticOption> cosmeticOptions = {
COSMETIC_OPTION("Key.FortSmallEmblem", "Fortress Small Key Emblem",COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 255, 255), false, true, false),
COSMETIC_OPTION("Key.GTGSmallBody", "GTG Small Key", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 255, 255), false, true, false),
COSMETIC_OPTION("Key.GTGSmallEmblem", "GTG Small Key Emblem", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(221, 212, 60, 255), false, true, false),
//COSMETIC_OPTION("Key.ChestGameSmallBody", "Chest Game Key", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 255, 255), false, true, false),
//COSMETIC_OPTION("Key.ChestGameEmblem", "Chest Game Key Emblem", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 0, 0, 255), false, true, false),
COSMETIC_OPTION("Key.ChestGameSmallBody", "Chest Game Key", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 255, 255), false, true, false),
COSMETIC_OPTION("Key.ChestGameEmblem", "Chest Game Key Emblem", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 0, 0, 255), false, true, false),
COSMETIC_OPTION("Key.Skeleton", "Skeleton Key", COSMETICS_GROUP_SMALL_KEYS, ColorRGBA8(255, 255, 170, 255), false, true, false),
COSMETIC_OPTION("HUD.AButton", "A Button", COSMETICS_GROUP_HUD, ColorRGBA8( 90, 90, 255, 255), false, true, false),
@@ -3639,6 +3639,51 @@ typedef enum {
// a textbox can be rendered instead. Pause screen only, Game Over version left
// intact.
VB_DRAW_SAVE_MENU,
// #### `result`
// ```c
// true
// ```
// Whether the chest game shopkeeper wipes the scene's chest flags and keys on spawn.
// #### `args`
// - `*EnTakaraMan`
VB_TAKARA_MAN_RESET_CHESTS_AND_KEYS,
// #### `result`
// ```c
// true
// ```
// Whether the chest game shopkeeper hands over a small key after being paid.
// #### `args`
// - `*EnTakaraMan`
VB_TAKARA_MAN_OFFER_GET_ITEM,
// #### `result`
// ```c
// Rand_ZeroFloat(1.99f) < 1.0f
// ```
// Whether the chest game swaps which side of the room holds the key chest.
// #### `args`
// - `*EnChanger`
VB_EN_CHANGER_SWAP_CHESTS,
// #### `result`
// ```c
// true
// ```
// Whether opening a chest sets its treasure flag.
// #### `args`
// - `*EnBox`
VB_CHEST_SET_TREASURE_FLAG,
// #### `result`
// ```c
// Flags_GetTreasure(play, this->dyna.actor.params & 0x1F)
// ```
// Whether a chest counts as already opened.
// #### `args`
// - `*EnBox`
VB_CHEST_CONSIDER_CHEST_OPEN,
} GIVanillaBehavior;
#endif
@@ -460,6 +460,14 @@ void StaticData::HintTable_Init() {
/*french*/ "Selon moi, le #neuvième ou dixième coffre à jeu# contient #[[1]]#.", {QM_RED, QM_GREEN})});
// /*spanish*/#el noveno o décimo cofre del azar# revela #[[1]]#.
hintTextTable[RHT_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER] = HintText(CustomMessage("They say that the #chest game host# is holding on to #[[1]]#.",
/*german*/ "Man erzählt sich, daß der #Truhenlotterie-Veranstalter# #[[1]]# bereithielte.",
/*french*/ "Selon moi, l'#hôte de la Chasse-aux-Trésors# détient #[[1]]#.", {QM_RED, QM_GREEN}),
{},
{CustomMessage("They say that #paying to play the chest game# grants #[[1]]#.",
/*german*/ "Man erzählt sich, daß #ein Spiel der Truhenlotterie# #[[1]]# gewähre.",
/*french*/ "Selon moi, #payer pour la Chasse-aux-Trésors# donne #[[1]]#.", {QM_RED, QM_GREEN})});
hintTextTable[RHT_GF_HBA_1500_POINTS] = HintText(CustomMessage("They say that scoring 1500 in #horseback archery# grants #[[1]]#.",
/*german*/ "Man erzählt sich, daß das Erzielen von 1.500 Punkten beim #Bogenschießen zu Pferde# #[[1]]# gewähre.",
/*french*/ "Selon moi, obtenir 1500 points dans l'#archerie équestre# donne #[[1]]#.", {QM_RED, QM_GREEN}),
@@ -1376,10 +1376,10 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("a key to the universe", /*german*/"ein Schlüssel zum Universum", /*french*/"une clé de l'univers")});
// /*spanish*/una llave al universo
hintTextTable[RHT_FOREST_TEMPLE_KEY_RING] = HintText(CustomMessage("a Forest Temple Key Ring", /*german*/"das Schlüsselbund des Waldtempels", /*french*/"un trousseau de clés du Temple de la Forêt"),
hintTextTable[RHT_FOREST_TEMPLE_KEY_RING] = HintText(CustomMessage("a Forest Temple Keyring", /*german*/"das Schlüsselbund des Waldtempels", /*french*/"un trousseau de clés du Temple de la Forêt"),
// /*spanish*/un llavero del Templo del Bosque
{
CustomMessage("a key ring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
CustomMessage("a keyring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
// /*spanish*/un llavero
}, {
CustomMessage("a sylvan toolbox for unlocking", /*german*/"eine waldige Werkzeugkiste zur Entriegelung", /*french*/"des anti-portes sylvestres"),
@@ -1391,10 +1391,10 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("a sylvan skeleton key", /*german*/"ein waldiger Skelettschlüssel", /*french*/"des crochets à porte sylvestres")});
// /*spanish*/un anillo silvestre contra cerrojos
hintTextTable[RHT_FIRE_TEMPLE_KEY_RING] = HintText(CustomMessage("a Fire Temple Key Ring", /*german*/"das Schlüsselbund des Feuertempels", /*french*/"un trousseau de clés du Temple du Feu"),
hintTextTable[RHT_FIRE_TEMPLE_KEY_RING] = HintText(CustomMessage("a Fire Temple Keyring", /*german*/"das Schlüsselbund des Feuertempels", /*french*/"un trousseau de clés du Temple du Feu"),
// /*spanish*/un llavero del Templo del Fuego
{
CustomMessage("a key ring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
CustomMessage("a keyring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
// /*spanish*/un llavero
}, {
CustomMessage("a molten toolbox for unlocking", /*german*/"eine geschmolzene Werkzeugkiste zur Entriegelung", /*french*/"des anti-portes fondus"),
@@ -1406,10 +1406,10 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("a molten skeleton key", /*german*/"ein geschmolzener Skelettschlüssel", /*french*/"des crochets à porte fondus")});
// /*spanish*/un anillo fundido contra cerrojos
hintTextTable[RHT_WATER_TEMPLE_KEY_RING] = HintText(CustomMessage("a Water Temple Key Ring", /*german*/"das Schlüsselbund des Wassertempels", /*french*/"un trousseau de clés du Temple de l'Eau"),
hintTextTable[RHT_WATER_TEMPLE_KEY_RING] = HintText(CustomMessage("a Water Temple Keyring", /*german*/"das Schlüsselbund des Wassertempels", /*french*/"un trousseau de clés du Temple de l'Eau"),
// /*spanish*/un llavero del Templo del Agua
{
CustomMessage("a key ring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
CustomMessage("a keyring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
// /*spanish*/un llavero
}, {
CustomMessage("a wet toolbox for unlocking", /*german*/"eine nasse Werkzeugkiste zur Entriegelung", /*french*/"des anti-portes humides"),
@@ -1421,10 +1421,10 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("a wet skeleton key", /*german*/"ein nasser Skelettschlüssel", /*french*/"des crochets à porte humides")});
// /*spanish*/un anillo abisal contra cerrojos
hintTextTable[RHT_SPIRIT_TEMPLE_KEY_RING] = HintText(CustomMessage("a Spirit Temple Key Ring", /*german*/"das Schlüsselbund des Geistertempels", /*french*/"un trousseau de clés du Temple de l'Esprit"),
hintTextTable[RHT_SPIRIT_TEMPLE_KEY_RING] = HintText(CustomMessage("a Spirit Temple Keyring", /*german*/"das Schlüsselbund des Geistertempels", /*french*/"un trousseau de clés du Temple de l'Esprit"),
// /*spanish*/un llavero del Templo del Espíritu
{
CustomMessage("a key ring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
CustomMessage("a keyring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
// /*spanish*/un llavero
}, {
CustomMessage("a sandy toolbox for unlocking", /*german*/"eine sandige Werkzeugkiste zur Entriegelung", /*french*/"des anti-portes sableux"),
@@ -1436,10 +1436,10 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("a sandy skeleton key", /*german*/"ein sandiger Skelettschlüssel", /*french*/"des crochets à porte sableux")});
// /*spanish*/un anillo arenoso contra cerrojos
hintTextTable[RHT_SHADOW_TEMPLE_KEY_RING] = HintText(CustomMessage("a Shadow Temple Key Ring", /*german*/"das Schlüsselbund des Schattentempels", /*french*/"un trousseau de clés du Temple de l'Ombre"),
hintTextTable[RHT_SHADOW_TEMPLE_KEY_RING] = HintText(CustomMessage("a Shadow Temple Keyring", /*german*/"das Schlüsselbund des Schattentempels", /*french*/"un trousseau de clés du Temple de l'Ombre"),
// /*spanish*/un llavero del Templo de las Sombras
{
CustomMessage("a key ring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
CustomMessage("a keyring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
// /*spanish*/un llavero
}, {
CustomMessage("a creepy toolbox for unlocking", /*german*/"eine gruselige Werkzeugkiste zur Entriegelung", /*french*/"des anti-portes sinistres"),
@@ -1451,10 +1451,10 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("a creepy skeleton key", /*german*/"ein gruseliger Skelettschlüssel", /*french*/"des crochets à porte sinistres")});
// /*spanish*/un anillo tenebroso contra cerrojos
hintTextTable[RHT_GERUDO_TRAINING_GROUND_KEY_RING] = HintText(CustomMessage("a Gerudo Training Ground Key Ring", /*german*/"das Schlüsselbund der Gerudo-Trainingsarena", /*french*/"un trousseau de clés du Gymnase Gerudo"),
hintTextTable[RHT_GERUDO_TRAINING_GROUND_KEY_RING] = HintText(CustomMessage("a Gerudo Training Ground Keyring", /*german*/"das Schlüsselbund der Gerudo-Trainingsarena", /*french*/"un trousseau de clés du Gymnase Gerudo"),
// /*spanish*/un llavero del Centro de Instrucción Gerudo
{
CustomMessage("a key ring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
CustomMessage("a keyring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
// /*spanish*/un llavero
}, {
CustomMessage("a labyrinthian toolbox for unlocking", /*german*/"eine verwirrende Werkzeugkiste zur Entriegelung", /*french*/"des anti-portes labyrinthiques"),
@@ -1466,10 +1466,10 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("a labyrinthian skeleton key", /*german*/"ein verwirrender Skelettschlüssel", /*french*/"des crochets à porte labyrinthiques")});
// /*spanish*/un anillo laberíntico contra cerrojos
hintTextTable[RHT_GERUDO_FORTRESS_KEY_RING] = HintText(CustomMessage("a Gerudo Fortress Key Ring", /*german*/"das Schlüsselbund des Diebesverstecks", /*french*/"un trousseau de clés de la Repaire des Voleurs"),
hintTextTable[RHT_GERUDO_FORTRESS_KEY_RING] = HintText(CustomMessage("a Gerudo Fortress Keyring", /*german*/"das Schlüsselbund des Diebesverstecks", /*french*/"un trousseau de clés de la Repaire des Voleurs"),
// /*spanish*/un llavero de la Fortaleza Gerudo
{
CustomMessage("a key ring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
CustomMessage("a keyring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
// /*spanish*/un llavero
}, {
CustomMessage("an imprisoned toolbox for unlocking", /*german*/"eine gefangene Werkzeugkiste zur Entriegelung", /*french*/"des anti-portes emprisonnés"),
@@ -1481,10 +1481,10 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("an imprisoned skeleton key", /*german*/"ein gefangener Skelettschlüssel", /*french*/"des crochets à porte emprisonnés")});
// /*spanish*/un anillo enjaulado contra cerrojos
hintTextTable[RHT_BOTTOM_OF_THE_WELL_KEY_RING] = HintText(CustomMessage("a Bottom of the Well Key Ring", /*german*/"das Schlüsselbund vom Grund des Brunnens", /*french*/"un trousseau de clés du fond du Puits"),
hintTextTable[RHT_BOTTOM_OF_THE_WELL_KEY_RING] = HintText(CustomMessage("a Bottom of the Well Keyring", /*german*/"das Schlüsselbund vom Grund des Brunnens", /*french*/"un trousseau de clés du fond du Puits"),
// /*spanish*/un llavero del Fondo del pozo
{
CustomMessage("a key ring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
CustomMessage("a keyring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
// /*spanish*/un llavero
}, {
CustomMessage("a moldy toolbox for unlocking", /*german*/"eine schimmelige Werkzeugkiste zur Entriegelung", /*french*/"des anti-portes moisis"),
@@ -1496,10 +1496,10 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("a moldy skeleton key", /*german*/"ein schimmeliger Skelettschlüssel", /*french*/"des crochets à porte moisis")});
// /*spanish*/un anillo subterráneo contra cerrojos
hintTextTable[RHT_GANONS_CASTLE_KEY_RING] = HintText(CustomMessage("a Ganon's Castle Key Ring", /*german*/"das Schlüsselbund von Ganons Schloß", /*french*/"un trousseau de clés du Château de Ganon"),
hintTextTable[RHT_GANONS_CASTLE_KEY_RING] = HintText(CustomMessage("a Ganon's Castle Keyring", /*german*/"das Schlüsselbund von Ganons Schloß", /*french*/"un trousseau de clés du Château de Ganon"),
// /*spanish*/un llavero del Castillo de Ganon
{
CustomMessage("a key ring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
CustomMessage("a keyring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
// /*spanish*/un llavero
}, {
CustomMessage("a final toolbox for unlocking", /*german*/"eine finale Werkzeugkiste zur Entriegelung", /*french*/"des anti-portes finaux"),
@@ -1526,9 +1526,9 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("a gambler's lockpick", /*german*/"ein Zocker-Dietrich", /*french*/"un crochet à serrure de parieur")});
// /*spanish*/una apertura portentosa del juego de azar
hintTextTable[RHT_TREASURE_GAME_KEY_RING] = HintText(CustomMessage("a Chest Game Key Ring", /*german*/ "das Schlüsselbund der Truhenlotterie", /*french*/ "TRANSLATE THIS"),
hintTextTable[RHT_TREASURE_GAME_KEY_RING] = HintText(CustomMessage("a Chest Game Keyring", /*german*/ "das Schlüsselbund der Truhenlotterie", /*french*/ "TRANSLATE THIS"),
{
CustomMessage("a key ring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
CustomMessage("a keyring", /*german*/"ein Schlüsselbund", /*french*/"un trousseau de clés")
// /*spanish*/un llavero
}, {
CustomMessage("a gambler's toolbox for unlocking", /*german*/ "eine Zocker-Werkzeugkiste zur Entriegelung", /*french*/ "TRANSLATE THIS"),
@@ -571,10 +571,12 @@ void GenerateItemPool() {
AddItemToPool(RG_CLAIM_CHECK, 2, 1, 1, 1);
}
if (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS)) {
AddItemToPool(RG_TREASURE_GAME_SMALL_KEY, 7, 6, 6, 6);
} else if (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK)) {
AddItemToPool(RG_TREASURE_GAME_KEY_RING, 2, 1, 1, 1);
if (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)) {
if (ctx->GetOption(RSK_KEYRINGS_CHEST_GAME) && ctx->GetOption(RSK_KEYRINGS)) {
AddItemToPool(RG_TREASURE_GAME_KEY_RING, 2, 1, 1, 1);
} else {
AddItemToPool(RG_TREASURE_GAME_SMALL_KEY, 7, 6, 6, 6);
}
}
int tokensToAdd = 0;
@@ -656,7 +658,7 @@ void GenerateItemPool() {
ctx->PlaceItemInLocation(RC_TH_DOUBLE_CELL_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_TH_STEEP_SLOPE_CARPENTER, RG_RECOVERY_HEART, false, true);
} else {
// Only add key ring if 4 Fortress keys necessary
// Only add keyring if 4 Fortress keys necessary
if (ctx->GetOption(RSK_KEYRINGS_GERUDO_FORTRESS) && ctx->GetOption(RSK_KEYRINGS)) {
AddItemToPool(RG_GERUDO_FORTRESS_KEY_RING, 2, 1, 1, 1);
} else {
@@ -171,7 +171,7 @@ void Context::GenerateLocationPool() {
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_CHEST_GAME && mOptions[RSK_SHUFFLE_CHEST_MINIGAME].Is(RO_GENERIC_OFF)) ||
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)) ||
@@ -273,8 +273,7 @@ void Context::AddExcludedOptions() {
for (auto& loc : StaticData::GetLocationTable()) {
// Checks of these types don't have items, skip them.
if (loc.GetRandomizerCheck() == RC_UNKNOWN_CHECK || loc.GetRandomizerCheck() == RC_WINCON ||
loc.GetRCType() == RCTYPE_CHEST_GAME || loc.GetRCType() == RCTYPE_STATIC_HINT ||
loc.GetRCType() == RCTYPE_GOSSIP_STONE) {
loc.GetRCType() == RCTYPE_STATIC_HINT || loc.GetRCType() == RCTYPE_GOSSIP_STONE) {
continue;
}
AddLocation(loc.GetRandomizerCheck(), &everyPossibleLocation);
@@ -0,0 +1,125 @@
#include <soh/OTRGlobals.h>
#include "soh/Enhancements/randomizer/randomizer.h"
extern "C" {
#include "src/overlays/actors/ovl_Door_Shutter/z_door_shutter.h"
#include "src/overlays/actors/ovl_En_Changer/z_en_changer.h"
#include "src/overlays/actors/ovl_En_Takara_Man/z_en_takara_man.h"
extern PlayState* gPlayState;
}
static bool GetChestGameRandInf(Actor* chest, RandomizerInf* randInf) {
if (gPlayState->sceneNum != SCENE_TREASURE_BOX_SHOP) {
return false;
}
s32 treasureFlag = chest->params & 0x1F;
if (treasureFlag > 9) {
return false;
}
*randInf = static_cast<RandomizerInf>(
(treasureFlag & 1 ? RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_1 : RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_1) +
treasureFlag / 2);
return true;
}
void DoorShutter_RandomizerInit(void* actorRef) {
DoorShutter* door = static_cast<DoorShutter*>(actorRef);
if (gPlayState->sceneNum != SCENE_TREASURE_BOX_SHOP || door->doorType != SHUTTER_KEY_LOCKED) {
return;
}
door->dyna.actor.params &= ~0x20;
if (Flags_GetSwitch(gPlayState, door->dyna.actor.params & 0x3F)) {
door->unlockTimer = 0;
}
}
void ItemEtcetera_RandomizerInit(void* actorRef) {
Actor* actor = static_cast<Actor*>(actorRef);
if (gPlayState->sceneNum != SCENE_TREASURE_BOX_SHOP || ((actor->params >> 8) & 0x1F) > 9) {
return;
}
// these only ever show the vanilla contents through the lens, so drop them
Actor_Kill(actor);
}
extern "C" void EnChanger_RandomizerWait(EnChanger* thisx, PlayState* play) {
}
void EnChanger_RandomizerInit(void* actorRef) {
if (gPlayState->sceneNum != SCENE_TREASURE_BOX_SHOP || gPlayState->roomCtx.curRoom.num >= 6) {
return;
}
EnChanger* changer = static_cast<EnChanger*>(actorRef);
// stop opening one chest from sealing the other and playing the reveal
changer->actionFunc = EnChanger_RandomizerWait;
}
void EnTakaraMan_RandomizerInit(void* actorRef) {
if (Flags_GetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER)) {
EnTakaraMan* takaraMan = static_cast<EnTakaraMan*>(actorRef);
// acting as if the game was already paid for stops him offering it again
takaraMan->unk_214 = 1;
}
}
void EnBox_RandomizerInit(void* actorRef) {
Actor* chest = static_cast<Actor*>(actorRef);
RandomizerInf randInf;
if (GetChestGameRandInf(chest, &randInf)) {
// the chests are see-through until the lens reveals them, but there is nothing left to reveal
chest->flags &= ~ACTOR_FLAG_REACT_TO_LENS;
}
}
void RegisterShuffleTreasureChestGame() {
bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_CHEST_MINIGAME);
// prevent wiping chest flags and key count on every visit
COND_VB_SHOULD(VB_TAKARA_MAN_RESET_CHESTS_AND_KEYS, shouldRegister, { *should = false; });
COND_VB_SHOULD(VB_TAKARA_MAN_OFFER_GET_ITEM, shouldRegister, {
Actor* takaraMan = va_arg(args, Actor*);
GetItemEntry getItemEntry =
Rando::Context::GetInstance()->GetFinalGIEntry(RC_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER, true, GI_DOOR_KEY);
Flags_SetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER);
GiveItemEntryFromActor(takaraMan, gPlayState, getItemEntry, 2000.0f, 1000.0f);
*should = false;
});
COND_VB_SHOULD(VB_EN_CHANGER_SWAP_CHESTS, shouldRegister, { *should = false; });
COND_VB_SHOULD(VB_CHEST_SET_TREASURE_FLAG, shouldRegister, {
Actor* chest = va_arg(args, Actor*);
RandomizerInf randInf;
if (GetChestGameRandInf(chest, &randInf)) {
Flags_SetRandomizerInf(randInf);
*should = false;
}
});
COND_VB_SHOULD(VB_CHEST_CONSIDER_CHEST_OPEN, shouldRegister, {
Actor* chest = va_arg(args, Actor*);
RandomizerInf randInf;
if (GetChestGameRandInf(chest, &randInf)) {
*should = Flags_GetRandomizerInf(randInf);
}
});
COND_ID_HOOK(OnActorInit, ACTOR_DOOR_SHUTTER, shouldRegister, DoorShutter_RandomizerInit);
COND_ID_HOOK(OnActorInit, ACTOR_ITEM_ETCETERA, shouldRegister, ItemEtcetera_RandomizerInit);
COND_ID_HOOK(OnActorInit, ACTOR_EN_CHANGER, shouldRegister, EnChanger_RandomizerInit);
COND_ID_HOOK(OnActorInit, ACTOR_EN_BOX, shouldRegister, EnBox_RandomizerInit);
COND_ID_HOOK(OnActorInit, ACTOR_EN_TAKARA_MAN, shouldRegister, EnTakaraMan_RandomizerInit);
}
static RegisterShipInitFunc registerShuffleTreasureChestGame(RegisterShuffleTreasureChestGame, { "IS_RANDO" });
+14
View File
@@ -885,6 +885,13 @@ static void InitTrickNames() {
Text{ "Vaati's Palace Small Key", "Vaati's Palace Small Key", "Vaati's Palace Small Key" },
};
trickNameTable[RG_TREASURE_GAME_SMALL_KEY] = {
// TODO_TRANSALTE
Text{ "Chest Game Salmon Koi", "Chest Game Salmon Koi", "Chest Game Salmon Koi" },
Text{ "Shell Game Small Key", "Shell Game Small Key", "Shell Game Small Key" },
Text{ "Treasure Hunt Small Key", "Treasure Hunt Small Key", "Treasure Hunt Small Key" },
};
trickNameTable[RG_FOREST_TEMPLE_KEY_RING] = {
// TODO_TRANSALTE
Text{ "Wind Temple Key Ring", "Wind Temple Key Ring", "Wind Temple Key Ring" },
@@ -943,6 +950,13 @@ static void InitTrickNames() {
Text{ "Vaati's Palace Key Ring", "Vaati's Palace Key Ring", "Vaati's Palace Key Ring" },
};
trickNameTable[RG_TREASURE_GAME_KEY_RING] = {
// TODO_TRANSALTE
Text{ "Chest Game Koi Ray", "Chest Game Koi Ray", "Chest Game Koi Ray" },
Text{ "Shell Game Key Ring", "Shell Game Key Ring", "Shell Game Key Ring" },
Text{ "Treasure Hunt Key Ring", "Treasure Hunt Key Ring", "Treasure Hunt Key Ring" },
};
trickNameTable[RG_FOREST_TEMPLE_BOSS_KEY] = {
// TODO_TRANSALTE
Text{ "Wind Temple Boss Key", "Wind Temple Boss Key", "Wind Temple Boss Key" },
@@ -2137,53 +2137,6 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
}
void RandomizerOnSceneInitHandler(int16_t sceneNum) {
// Treasure Chest Game
// todo: for now we're just unsetting all of them, we will
// probably need to do something different when we implement shuffle
if (sceneNum == SCENE_TREASURE_BOX_SHOP) {
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_1);
Rando::Context::GetInstance()
->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1)
->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_2);
Rando::Context::GetInstance()
->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2)
->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_3);
Rando::Context::GetInstance()
->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3)
->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_4);
Rando::Context::GetInstance()
->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4)
->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_5);
Rando::Context::GetInstance()
->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5)
->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_1);
Rando::Context::GetInstance()
->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_1)
->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_2);
Rando::Context::GetInstance()
->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_2)
->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_3);
Rando::Context::GetInstance()
->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_3)
->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_4);
Rando::Context::GetInstance()
->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_4)
->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_5);
Rando::Context::GetInstance()
->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_5)
->SetCheckStatus(RCSHOW_UNCHECKED);
CheckTracker::RecalculateAllAreaTotals();
}
// ENTRTODO: Move all entrance rando handling to a dedicated file
if (RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES)) {
// In ER, override roomNum to load based on scene and spawn during scene init
@@ -171,7 +171,8 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_GERUDO_FORTRESS_SMALL_KEY].SetCustomDrawFunc(Randomizer_DrawSmallKey);
itemTable[RG_GANONS_CASTLE_SMALL_KEY] = Item(RG_GANONS_CASTLE_SMALL_KEY, Text{ "Ganon's Castle Small Key", "Petite Clé du Château de Ganon", "Kleiner Schlüssel für Ganons Schloß" }, ITEMTYPE_SMALLKEY, 0xB7, true, LOGIC_GANONS_CASTLE_KEYS, RHT_GANONS_CASTLE_SMALL_KEY, RG_GANONS_CASTLE_SMALL_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY,MOD_RANDOMIZER, {"a ", "une ", "einen "}, "%r").CustomIcon(gQuestIconSmallKeyTex, ICON_SIZE_24);
itemTable[RG_GANONS_CASTLE_SMALL_KEY].SetCustomDrawFunc(Randomizer_DrawSmallKey);
itemTable[RG_TREASURE_GAME_SMALL_KEY] = Item(RG_TREASURE_GAME_SMALL_KEY, Text{ "Chest Game Small Key", "Petite Clé du jeu la Chasse-aux-Trésors", "Kleiner Schlüssel für das Truhenspiel" }, ITEMTYPE_SMALLKEY, GI_DOOR_KEY, true, LOGIC_TREASURE_GAME_KEYS, RHT_TREASURE_GAME_SMALL_KEY, ITEM_KEY_SMALL, OBJECT_GI_KEY, GID_KEY_SMALL, 0xF3, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY,MOD_NONE, {"a ", "une ", "einen "}).CustomIcon(gQuestIconSmallKeyTex, ICON_SIZE_24);
itemTable[RG_TREASURE_GAME_SMALL_KEY] = Item(RG_TREASURE_GAME_SMALL_KEY, Text{ "Chest Game Small Key", "Petite Clé du jeu la Chasse-aux-Trésors", "Kleiner Schlüssel für das Truhenspiel" }, ITEMTYPE_SMALLKEY, GI_DOOR_KEY, true, LOGIC_TREASURE_GAME_KEYS, RHT_TREASURE_GAME_SMALL_KEY, RG_TREASURE_GAME_SMALL_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY,MOD_RANDOMIZER, {"a ", "une ", "einen "}, "%r").CustomIcon(gQuestIconSmallKeyTex, ICON_SIZE_24);
itemTable[RG_TREASURE_GAME_SMALL_KEY].SetCustomDrawFunc(Randomizer_DrawSmallKey);
itemTable[RG_GUARD_HOUSE_KEY] = Item(RG_GUARD_HOUSE_KEY, Text{ "Guard House Key", "Clé de la Maison des Gardes", "Schlüssel für das Haus der Wachen" }, ITEMTYPE_ITEM, GI_DOOR_KEY, true, LOGIC_GUARD_HOUSE_KEY, RHT_OVERWORLD_KEY, RG_GUARD_HOUSE_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY,MOD_RANDOMIZER, {"the ", "la ", "den "}).CustomIcon(gQuestIconSmallKeyTex, ICON_SIZE_24);
itemTable[RG_GUARD_HOUSE_KEY].SetCustomDrawFunc(Randomizer_DrawOverworldKey);
itemTable[RG_MARKET_BAZAAR_KEY] = Item(RG_MARKET_BAZAAR_KEY, Text{ "Market Bazaar Key", "Clé du Bazar de la Place du Marché", "Schlüssel für den Basar des Marktes" }, ITEMTYPE_ITEM, GI_DOOR_KEY, true, LOGIC_MARKET_BAZAAR_KEY, RHT_OVERWORLD_KEY, RG_MARKET_BAZAAR_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY,MOD_RANDOMIZER, {"the ", "la ", "den "}).CustomIcon(gQuestIconSmallKeyTex, ICON_SIZE_24);
@@ -205,17 +205,18 @@ void RegionTable_Init_Market() {
areaTable[RR_MARKET_TREASURE_CHEST_GAME] = Region("Market Treasure Chest Game", SCENE_TREASURE_BOX_SHOP, {}, {
//Locations
LOCATION(RC_GREG_HINT, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN)),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_REWARD, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 6)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_1, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_2, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 2)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 2)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_3, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 3)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 3)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_4, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 4)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 4)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_5, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 5)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanOpenLargeChest() && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 5)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_1, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 1) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_2, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 2) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 2) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_3, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 3) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 3) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_4, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 4) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 4) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_5, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 5) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 5) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
LOCATION(RC_MARKET_TREASURE_CHEST_GAME_REWARD, logic->CanOpenLargeChest() && (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME) ? logic->SmallKeys(SCENE_TREASURE_BOX_SHOP, 6) : (logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_LENS_OF_TRUTH)))),
}, {
//Exits
ENTRANCE(RR_THE_MARKET, true),
@@ -233,6 +233,7 @@ void Rando::StaticData::InitLocationTable() {
locationTable[RC_MARKET_TREASURE_CHEST_GAME_KEY_3] = Location::Chest(RC_MARKET_TREASURE_CHEST_GAME_KEY_3, RCQUEST_BOTH, RCTYPE_CHEST_GAME, ACTOR_EN_BOX, SCENE_TREASURE_BOX_SHOP, 0x00, "Chest Game Third Room Key", RHT_MARKET_TREASURE_CHEST_GAME_KEY_3, RG_TREASURE_GAME_SMALL_KEY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_3));
locationTable[RC_MARKET_TREASURE_CHEST_GAME_KEY_4] = Location::Chest(RC_MARKET_TREASURE_CHEST_GAME_KEY_4, RCQUEST_BOTH, RCTYPE_CHEST_GAME, ACTOR_EN_BOX, SCENE_TREASURE_BOX_SHOP, 0x00, "Chest Game Fourth Room Key", RHT_MARKET_TREASURE_CHEST_GAME_KEY_4, RG_TREASURE_GAME_SMALL_KEY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_4));
locationTable[RC_MARKET_TREASURE_CHEST_GAME_KEY_5] = Location::Chest(RC_MARKET_TREASURE_CHEST_GAME_KEY_5, RCQUEST_BOTH, RCTYPE_CHEST_GAME, ACTOR_EN_BOX, SCENE_TREASURE_BOX_SHOP, 0x00, "Chest Game Fifth Room Key", RHT_MARKET_TREASURE_CHEST_GAME_KEY_5, RG_TREASURE_GAME_SMALL_KEY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_5));
locationTable[RC_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER] = Location::Base(RC_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER, RCQUEST_BOTH, RCTYPE_CHEST_GAME, ACTOR_EN_TAKARA_MAN, SCENE_TREASURE_BOX_SHOP, 0x00, "Chest Game Shopkeeper", RHT_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER, RG_TREASURE_GAME_SMALL_KEY, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER));
// Hyrule Castle
locationTable[RC_HC_MALON_EGG] = Location::Base(RC_HC_MALON_EGG, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_HYRULE_CASTLE, 0x00, "Malon Egg", RHT_HC_MALON_EGG, RG_WEIRD_EGG, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_OBTAINED_POCKET_EGG), true);
locationTable[RC_HC_ZELDAS_LETTER] = Location::Base(RC_HC_ZELDAS_LETTER, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_CASTLE_COURTYARD_ZELDA, 0x00, "Zeldas Letter", RHT_HC_ZELDAS_LETTER, RG_ZELDAS_LETTER, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER), true);
+3 -2
View File
@@ -1987,7 +1987,8 @@ std::map<uint32_t, SceneID> Logic::RandoGetToDungeonScene = {
{ RG_SHADOW_TEMPLE_COMPASS, SCENE_SHADOW_TEMPLE },
{ RG_BOTTOM_OF_THE_WELL_COMPASS, SCENE_BOTTOM_OF_THE_WELL },
{ RG_ICE_CAVERN_COMPASS, SCENE_ICE_CAVERN },
{ RG_TREASURE_GAME_SMALL_KEY, SCENE_TREASURE_BOX_SHOP }
{ RG_TREASURE_GAME_SMALL_KEY, SCENE_TREASURE_BOX_SHOP },
{ RG_TREASURE_GAME_KEY_RING, SCENE_TREASURE_BOX_SHOP }
};
std::map<uint32_t, uint32_t> Logic::RandoGetToQuestItem = {
@@ -2485,7 +2486,7 @@ void Logic::ApplyItemEffect(Item& item, bool state) {
case ITEMTYPE_FORTRESS_SMALLKEY:
case ITEMTYPE_SMALLKEY: {
auto randoGet = item.GetRandomizerGet();
auto keyring = randoGet >= RG_FOREST_TEMPLE_KEY_RING && randoGet <= RG_GANONS_CASTLE_KEY_RING;
auto keyring = randoGet >= RG_FOREST_TEMPLE_KEY_RING && randoGet <= RG_TREASURE_GAME_KEY_RING;
auto dungeonIndex = RandoGetToDungeonScene.find(randoGet)->second;
auto count = GetSmallKeyCount(dungeonIndex);
if (!state) {
@@ -55,7 +55,7 @@ void Settings::CreateOptionDescriptions() {
"Free - Bridge is repaired from start, and Nabooru cannot spawn.\n"
"If the Gerudo Membership Card isn't shuffled, you start with it.\n"
"\n"
"Only \"Normal\" is compatible with Gerudo Fortress Key Rings.";
"Only \"Normal\" is compatible with Gerudo Fortress Keyrings.";
mOptionDescriptions[RSK_RAINBOW_BRIDGE] =
"Alters the requirements to open the bridge to Ganon's Castle.\n"
"\n"
@@ -526,6 +526,13 @@ void Settings::CreateOptionDescriptions() {
"D-pad.\n"
"\n"
"If disabled, only the Claim Check will be found in the pool.";
mOptionDescriptions[RSK_SHUFFLE_CHEST_MINIGAME] =
"Shuffles the contents of the Market Treasure Chest Game, including the item you pay "
"the host for. Both chests in every room can be opened, and the locked doors are opened "
"with keys found elsewhere instead of keys won in the game.\n"
"\n"
"Six Chest Game Small Keys are added to the pool, or a single keyring holding all six "
"if the Chest Minigame Keyring is selected under Keyrings.";
mOptionDescriptions[RSK_EARLY_GRANNYS_SHOP] =
"Makes Granny's Potion Shop available from start, rather than requiring Claim Check to be found first.\n"
"\n"
@@ -625,18 +632,18 @@ void Settings::CreateOptionDescriptions() {
"\n"
"Off - No dungeons will have their keys replaced with keyrings.\n"
"\n"
"Random - A random amount of dungeons (0-8 or 9) will have their keys replaced with keyrings.\n"
"Random - A random amount of dungeons will have their keys replaced with keyrings.\n"
"\n"
"Count - A specified amount of randomly selected dungeons will have their keys replaced with keyrings.\n"
"\n"
"Selection - Hand select which dungeons will have their keys replaced with keyrings\n"
"(can also be left as random, in which case each one will have a 50% chance of being a keyring).\n"
"\n"
"Selecting key ring for dungeons will have no effect if Small Keys are set to Start With or Vanilla.\n"
"Selecting keyring for dungeons will have no effect if Small Keys are set to Start With or Vanilla.\n"
"\n"
"If Gerudo Fortress Carpenters is set to Normal, and Gerudo Fortress Keys is set to anything "
"other than Vanilla, then the maximum amount of Key Rings that can be selected by Random or "
"Count will be 9. Otherwise, the maximum amount of Key Rings will be 8.";
"The maximum amount of Keyrings that can be selected by Random or Count is 8, plus one if "
"Gerudo Fortress Carpenters is set to Normal and Gerudo Fortress Keys is set to anything "
"other than Vanilla, plus one if Shuffle Chest Minigame is on.";
mOptionDescriptions[RSK_GERUDO_KEYS] = "Vanilla - Thieves' Hideout Keys will appear in their vanilla locations.\n"
"\n"
"Any dungeon - Thieves' Hideout Keys can only appear inside of any dungon.\n"
+10 -5
View File
@@ -715,7 +715,7 @@ Rando::Location* Randomizer::GetCheckObjectFromActor(s16 actorId, s16 sceneNum,
specialRc = RC_MARKET_TREASURE_CHEST_GAME_REWARD;
}
// todo: handle the itemetc part of this so drawing works when we implement shuffle
// the low bits of a game chest's params are its treasure flag, odd for the key chest
if (actorId == ACTOR_EN_BOX) {
bool isAKey = (actorParams & 0x60) == 0x20;
if ((actorParams & 0xF) < 2) {
@@ -1277,8 +1277,8 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
}
// dungeon items
if ((item >= RG_FOREST_TEMPLE_SMALL_KEY && item <= RG_GANONS_CASTLE_SMALL_KEY) ||
(item >= RG_FOREST_TEMPLE_KEY_RING && item <= RG_GANONS_CASTLE_KEY_RING) ||
if ((item >= RG_FOREST_TEMPLE_SMALL_KEY && item <= RG_TREASURE_GAME_SMALL_KEY) ||
(item >= RG_FOREST_TEMPLE_KEY_RING && item <= RG_TREASURE_GAME_KEY_RING) ||
(item >= RG_FOREST_TEMPLE_BOSS_KEY && item <= RG_GANONS_CASTLE_BOSS_KEY) ||
(item >= RG_DEKU_TREE_MAP && item <= RG_ICE_CAVERN_MAP) ||
(item >= RG_DEKU_TREE_COMPASS && item <= RG_ICE_CAVERN_COMPASS)) {
@@ -1366,11 +1366,16 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
mapIndex = SCENE_INSIDE_GANONS_CASTLE;
numOfKeysOnKeyring = GANONS_CASTLE_SMALL_KEY_MAX;
break;
case RG_TREASURE_GAME_SMALL_KEY:
case RG_TREASURE_GAME_KEY_RING:
mapIndex = SCENE_TREASURE_BOX_SHOP;
numOfKeysOnKeyring = TREASURE_GAME_SMALL_KEY_MAX;
break;
default:
break;
}
if ((item >= RG_FOREST_TEMPLE_SMALL_KEY) && (item <= RG_GANONS_CASTLE_SMALL_KEY)) {
if ((item >= RG_FOREST_TEMPLE_SMALL_KEY) && (item <= RG_TREASURE_GAME_SMALL_KEY)) {
gSaveContext.ship.stats.dungeonKeys[mapIndex]++;
if (gSaveContext.inventory.dungeonKeys[mapIndex] < 0) {
gSaveContext.inventory.dungeonKeys[mapIndex] = 1;
@@ -1380,7 +1385,7 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
return Return_Item_Entry(giEntry, RG_NONE);
}
if ((item >= RG_FOREST_TEMPLE_KEY_RING) && (item <= RG_GANONS_CASTLE_KEY_RING)) {
if ((item >= RG_FOREST_TEMPLE_KEY_RING) && (item <= RG_TREASURE_GAME_KEY_RING)) {
gSaveContext.ship.stats.dungeonKeys[mapIndex] = numOfKeysOnKeyring;
gSaveContext.inventory.dungeonKeys[mapIndex] = numOfKeysOnKeyring;
return Return_Item_Entry(giEntry, RG_NONE);
@@ -102,6 +102,7 @@ RANDO_ENUM_ITEM(RC_MARKET_TREASURE_CHEST_GAME_KEY_2)
RANDO_ENUM_ITEM(RC_MARKET_TREASURE_CHEST_GAME_KEY_3)
RANDO_ENUM_ITEM(RC_MARKET_TREASURE_CHEST_GAME_KEY_4)
RANDO_ENUM_ITEM(RC_MARKET_TREASURE_CHEST_GAME_KEY_5)
RANDO_ENUM_ITEM(RC_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER)
RANDO_ENUM_ITEM(RC_MARKET_GS_GUARD_HOUSE)
RANDO_ENUM_ITEM(RC_MARKET_BAZAAR_ITEM_1)
RANDO_ENUM_ITEM(RC_MARKET_BAZAAR_ITEM_2)
@@ -182,6 +182,7 @@ RANDO_ENUM_ITEM(RHT_MARKET_TREASURE_CHEST_GAME_KEY_2)
RANDO_ENUM_ITEM(RHT_MARKET_TREASURE_CHEST_GAME_KEY_3)
RANDO_ENUM_ITEM(RHT_MARKET_TREASURE_CHEST_GAME_KEY_4)
RANDO_ENUM_ITEM(RHT_MARKET_TREASURE_CHEST_GAME_KEY_5)
RANDO_ENUM_ITEM(RHT_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER)
RANDO_ENUM_ITEM(RHT_MARKET_GS_GUARD_HOUSE)
RANDO_ENUM_ITEM(RHT_MARKET_BAZAAR_ITEM_1)
RANDO_ENUM_ITEM(RHT_MARKET_BAZAAR_ITEM_2)
@@ -1539,6 +1539,7 @@ RANDO_ENUM_ITEM(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_2)
RANDO_ENUM_ITEM(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_3)
RANDO_ENUM_ITEM(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_4)
RANDO_ENUM_ITEM(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_5)
RANDO_ENUM_ITEM(RAND_INF_MARKET_TREASURE_CHEST_GAME_SHOPKEEPER)
RANDO_ENUM_ITEM(RAND_INF_TH_ITEM_FROM_LEADER_OF_FORTRESS)
RANDO_ENUM_ITEM(RAND_INF_GF_GTG_GATE_PERMANENTLY_OPEN)
@@ -524,12 +524,6 @@ RANDO_ENUM_ITEM(RO_LOCATION_INCLUDE)
RANDO_ENUM_ITEM(RO_LOCATION_EXCLUDE)
RANDO_ENUM_END(RandoOptionLocationInclusion)
RANDO_ENUM_BEGIN(RandoOptionChestGame)
RANDO_ENUM_ITEM(RO_CHEST_GAME_OFF)
RANDO_ENUM_ITEM(RO_CHEST_GAME_SINGLE_KEYS)
RANDO_ENUM_ITEM(RO_CHEST_GAME_PACK)
RANDO_ENUM_END(RandoOptionChestGame)
RANDO_ENUM_BEGIN(RandoOptionMQSet)
RANDO_ENUM_ITEM(RO_MQ_SET_VANILLA)
RANDO_ENUM_ITEM(RO_MQ_SET_MQ)
@@ -248,6 +248,7 @@ RANDO_ENUM_ITEM(RSK_KEYRINGS_SHADOW_TEMPLE)
RANDO_ENUM_ITEM(RSK_KEYRINGS_BOTTOM_OF_THE_WELL)
RANDO_ENUM_ITEM(RSK_KEYRINGS_GTG)
RANDO_ENUM_ITEM(RSK_KEYRINGS_GANONS_CASTLE)
RANDO_ENUM_ITEM(RSK_KEYRINGS_CHEST_GAME)
RANDO_ENUM_ITEM(RSK_SHUFFLE_ENTRANCES)
RANDO_ENUM_ITEM(RSK_SHUFFLE_DUNGEON_ENTRANCES)
RANDO_ENUM_ITEM(RSK_SHUFFLE_OVERWORLD_ENTRANCES)
@@ -160,8 +160,8 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() {
RCTYPE_GOSSIP_STONE) && // don't show gossip stones (maybe gossipsanity will be a thing eventually?)
(location.GetRCType() != RCTYPE_STATIC_HINT) && // don't show static hints
(location.GetRCType() != RCTYPE_LINKS_POCKET) && // links pocket can be set to nothing if needed
(location.GetRCType() !=
RCTYPE_CHEST_GAME) && // don't show non final reward chest game checks until we support shuffling them
(location.GetRCType() != RCTYPE_CHEST_GAME ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleChestMinigame"), RO_GENERIC_OFF)) &&
(location.GetRCType() != RCTYPE_SKULL_TOKEN ||
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleTokens"), RO_TOKENSANITY_OFF) == RO_TOKENSANITY_ALL) ||
((CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleTokens"), RO_TOKENSANITY_OFF) ==
@@ -109,6 +109,7 @@ bool showGanonBossKey;
bool showOcarinas;
bool show100SkullReward;
bool showLinksPocket;
bool showChestMinigame;
bool fortressFast;
bool fortressNormal;
@@ -1588,96 +1589,71 @@ void LoadSettings() {
// If in vanilla, _try_ to show items that at least are needed for 100%
showShops =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY) != RO_SHOPSANITY_OFF : false;
showBeans = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) ==
RO_SHUFFLE_MERCHANTS_BEANS_ONLY ||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) ==
RO_SHUFFLE_MERCHANTS_ALL
: true;
IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY) != RO_SHOPSANITY_OFF;
showBeans =
!IS_RANDO ||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) ==
RO_SHUFFLE_MERCHANTS_BEANS_ONLY ||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL;
showScrubs =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) == RO_SCRUBS_ALL : false;
IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) == RO_SCRUBS_ALL;
showMajorScrubs =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) != RO_SCRUBS_OFF : false;
showMerchants = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) ==
RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS ||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) ==
RO_SHUFFLE_MERCHANTS_ALL
: true;
showSongs = IS_RANDO
? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SONGS) != RO_SONG_SHUFFLE_OFF
: false;
showBeehives = IS_RANDO
? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BEEHIVES) == RO_GENERIC_YES
: false;
showCows =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_COWS) == RO_GENERIC_YES : false;
IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) != RO_SCRUBS_OFF;
showMerchants =
!IS_RANDO ||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) ==
RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS ||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL;
showSongs =
IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SONGS) != RO_SONG_SHUFFLE_OFF;
showBeehives =
IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BEEHIVES) == RO_GENERIC_YES;
showCows = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_COWS) == RO_GENERIC_YES;
showAdultTrade =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE) == RO_GENERIC_YES
: true;
showKokiriSword =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_KOKIRI_SWORD) == RO_GENERIC_YES
: true;
showMasterSword =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MASTER_SWORD) == RO_GENERIC_YES
: true;
showHyruleLoach =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY) == RO_FISHSANITY_HYRULE_LOACH
: false;
showWeirdEgg = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_WEIRD_EGG) ==
RO_WEIRD_EGG_SHUFFLED
: true;
showZeldasLetter =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ZELDAS_LETTER) == RO_GENERIC_YES
: true;
showGerudoCard = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) == RO_GENERIC_YES
: true;
showFrogSongRupees =
IS_RANDO
? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_FROG_SONG_RUPEES) == RO_GENERIC_YES
: false;
showFountainFairies =
IS_RANDO
? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_FOUNTAIN_FAIRIES) == RO_GENERIC_YES
: false;
showStoneFairies =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_STONE_FAIRIES) == RO_GENERIC_YES
: false;
!IS_RANDO || OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE) == RO_GENERIC_YES;
showKokiriSword = !IS_RANDO || OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_KOKIRI_SWORD) ==
RO_GENERIC_YES;
showMasterSword = !IS_RANDO || OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MASTER_SWORD) ==
RO_GENERIC_YES;
showHyruleLoach = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY) ==
RO_FISHSANITY_HYRULE_LOACH;
showWeirdEgg = !IS_RANDO || OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_WEIRD_EGG) ==
RO_WEIRD_EGG_SHUFFLED;
showZeldasLetter = !IS_RANDO || OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_ZELDAS_LETTER) == RO_GENERIC_YES;
showGerudoCard = !IS_RANDO || OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) == RO_GENERIC_YES;
showFrogSongRupees = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_FROG_SONG_RUPEES) == RO_GENERIC_YES;
showFountainFairies = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_FOUNTAIN_FAIRIES) == RO_GENERIC_YES;
showStoneFairies = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_STONE_FAIRIES) ==
RO_GENERIC_YES;
showBeanFairies =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BEAN_FAIRIES) == RO_GENERIC_YES
: false;
IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BEAN_FAIRIES) == RO_GENERIC_YES;
showSongFairies =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SONG_FAIRIES) == RO_GENERIC_YES
: false;
showButterflyFairies =
IS_RANDO
? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BUTTERFLY_FAIRIES) == RO_GENERIC_YES
: false;
showStartingMapsCompasses = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_MAPANDCOMPASS) != RO_DUNGEON_ITEM_LOC_VANILLA
: false;
showKeysanity =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_KEYSANITY) != RO_DUNGEON_ITEM_LOC_VANILLA
: false;
showBossKeysanity = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BOSS_KEYSANITY) !=
RO_DUNGEON_ITEM_LOC_VANILLA
: false;
IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SONG_FAIRIES) == RO_GENERIC_YES;
showButterflyFairies = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_BUTTERFLY_FAIRIES) == RO_GENERIC_YES;
showStartingMapsCompasses = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_MAPANDCOMPASS) != RO_DUNGEON_ITEM_LOC_VANILLA;
showKeysanity = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_KEYSANITY) !=
RO_DUNGEON_ITEM_LOC_VANILLA;
showBossKeysanity = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BOSS_KEYSANITY) !=
RO_DUNGEON_ITEM_LOC_VANILLA;
showGerudoFortressKeys =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_KEYS) != RO_GERUDO_KEYS_VANILLA
: false;
showGanonBossKey = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) !=
RO_GANON_BOSS_KEY_VANILLA
: false;
showOcarinas = IS_RANDO
? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_OCARINA) == RO_GENERIC_YES
: false;
show100SkullReward =
IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_100_GS_REWARD) == RO_GENERIC_YES
: false;
showLinksPocket =
IS_RANDO ? // don't show Link's Pocket if not randomizer, or if rando and pocket is disabled
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING
: false;
IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_KEYS) != RO_GERUDO_KEYS_VANILLA;
showGanonBossKey = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) !=
RO_GANON_BOSS_KEY_VANILLA;
showOcarinas =
IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_OCARINA) == RO_GENERIC_YES;
show100SkullReward = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_100_GS_REWARD) == RO_GENERIC_YES;
// don't show Link's Pocket if not randomizer, or if rando and pocket is disabled
showLinksPocket = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) !=
RO_LINKS_POCKET_NOTHING;
showChestMinigame = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_CHEST_MINIGAME) != RO_GENERIC_OFF;
if (IS_RANDO) {
switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_TOKENS)) {
@@ -1918,8 +1894,7 @@ bool IsCheckShuffled(RandomizerCheck rc) {
return (loc->GetArea() != RCAREA_INVALID) && // don't show Invalid locations
(loc->GetRCType() != RCTYPE_GOSSIP_STONE) && // TODO: Don't show hints until tracker supports them
(loc->GetRCType() != RCTYPE_STATIC_HINT) && // TODO: Don't show hints until tracker supports them
(loc->GetRCType() != RCTYPE_CHEST_GAME) && // don't show non final reward chest game checks until we
// support shuffling them
(loc->GetRCType() != RCTYPE_CHEST_GAME || showChestMinigame) &&
(rc != RC_HC_ZELDAS_LETTER || showZeldasLetter) && (rc != RC_LINKS_POCKET || showLinksPocket) &&
OTRGlobals::Instance->gRandoContext->IsQuestOfLocationActive(rc) &&
(loc->GetRCType() != RCTYPE_SHOP ||
+62 -55
View File
@@ -137,6 +137,32 @@ void Settings::HandleMixedEntrancePoolsUI() {
}
}
void Settings::HandleKeyringUI() {
const bool fortressKeyring =
CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) ==
RO_GF_CARPENTERS_NORMAL &&
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) != RO_GERUDO_KEYS_VANILLA;
const bool chestGameKeyring =
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleChestMinigame"), RO_GENERIC_OFF) != RO_GENERIC_OFF;
const uint8_t maxKeyringCount = 8 + fortressKeyring + chestGameKeyring;
if (mOptions[RSK_KEYRINGS_RANDOM_COUNT].GetOptionCount() != maxKeyringCount + 1) {
mOptions[RSK_KEYRINGS_RANDOM_COUNT].ChangeOptions(NumOpts(0, maxKeyringCount));
}
if (fortressKeyring) {
mOptions[RSK_KEYRINGS_GERUDO_FORTRESS].Enable();
} else {
mOptions[RSK_KEYRINGS_GERUDO_FORTRESS].Disable(
"Disabled because the currently selected Gerudo Fortress Carpenters\n"
"setting and/or Gerudo Fortress Keys setting is incompatible with\n"
"having a Gerudo Fortress Keyring.");
}
if (chestGameKeyring) {
mOptions[RSK_KEYRINGS_CHEST_GAME].Enable();
} else {
mOptions[RSK_KEYRINGS_CHEST_GAME].Disable("Disabled because Shuffle Chest Minigame is off.");
}
}
void Settings::HandleStartingAgeUI() {
// Starting Age - Disabled under very specific conditions unless it's No Logic
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) != RO_LOGIC_NO_LOGIC &&
@@ -175,25 +201,7 @@ void Settings::CreateOptions() {
OPT_BOOL(RSK_LOCK_OVERWORLD_DOORS, "Lock Overworld Doors", CVAR_RANDOMIZER_SETTING("LockOverworldDoors"), mOptionDescriptions[RSK_LOCK_OVERWORLD_DOORS]);
OPT_U8(RSK_GERUDO_FORTRESS, "Fortress Carpenters", {"Normal", "Fast", "Free"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("FortressCarpenters"), mOptionDescriptions[RSK_GERUDO_FORTRESS]);
OPT_CALLBACK(RSK_GERUDO_FORTRESS, {
const uint8_t maxKeyringCount =
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) ==
RO_GF_CARPENTERS_NORMAL &&
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) != RO_GERUDO_KEYS_VANILLA)
? 9
: 8;
if (mOptions[RSK_KEYRINGS_RANDOM_COUNT].GetOptionCount() != maxKeyringCount + 1) {
mOptions[RSK_KEYRINGS_RANDOM_COUNT].ChangeOptions(NumOpts(0, maxKeyringCount));
}
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) !=
RO_GF_CARPENTERS_NORMAL ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) == RO_GERUDO_KEYS_VANILLA) {
mOptions[RSK_KEYRINGS_GERUDO_FORTRESS].Disable(
"Disabled because the currently selected Gerudo Fortress Carpenters\n"
"setting and/or Gerudo Fortress Keys setting is incompatible with\n"
"having a Gerudo Fortress Keyring.");
} else {
mOptions[RSK_KEYRINGS_GERUDO_FORTRESS].Enable();
}
HandleKeyringUI();
});
OPT_U8(RSK_RAINBOW_BRIDGE, "Rainbow Bridge", {"Vanilla", "Always open", "Stones", "Medallions", "Dungeon rewards", "Dungeons", "Tokens", "Triforce Pieces", "Greg"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("RainbowBridge"), mOptionDescriptions[RSK_RAINBOW_BRIDGE], WIDGET_CVAR_COMBOBOX, RO_BRIDGE_VANILLA, false, nullptr, IMFLAG_NONE);
OPT_CALLBACK(RSK_RAINBOW_BRIDGE, {
@@ -1042,7 +1050,10 @@ void Settings::CreateOptions() {
mOptions[RSK_EARLY_GRANNYS_SHOP].Enable();
}
});
OPT_U8(RSK_SHUFFLE_CHEST_MINIGAME, "Shuffle Chest Minigame", {"Off", "On (Separate)", "On (Pack)"});
OPT_BOOL(RSK_SHUFFLE_CHEST_MINIGAME, "Shuffle Chest Minigame", CVAR_RANDOMIZER_SETTING("ShuffleChestMinigame"), mOptionDescriptions[RSK_SHUFFLE_CHEST_MINIGAME]);
OPT_CALLBACK(RSK_SHUFFLE_CHEST_MINIGAME, {
HandleKeyringUI();
});
OPT_BOOL(RSK_SHUFFLE_100_GS_REWARD, "Shuffle 100 GS Reward", CVAR_RANDOMIZER_SETTING("Shuffle100GSReward"), mOptionDescriptions[RSK_SHUFFLE_100_GS_REWARD], IMFLAG_SEPARATOR_BOTTOM, WIDGET_CVAR_CHECKBOX, RO_GENERIC_OFF);
OPT_CALLBACK(RSK_SHUFFLE_100_GS_REWARD, {
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("Shuffle100GSReward"), RO_GENERIC_OFF)) {
@@ -1104,25 +1115,7 @@ void Settings::CreateOptions() {
OPT_U8(RSK_KEYSANITY, "Small Key Shuffle", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Keysanity"), mOptionDescriptions[RSK_KEYSANITY], WIDGET_CVAR_COMBOBOX, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON);
OPT_U8(RSK_GERUDO_KEYS, "Gerudo Fortress Keys", {"Vanilla", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GerudoKeys"), mOptionDescriptions[RSK_GERUDO_KEYS], WIDGET_CVAR_COMBOBOX, RO_GERUDO_KEYS_VANILLA);
OPT_CALLBACK(RSK_GERUDO_KEYS, {
const uint8_t maxKeyringCount =
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) ==
RO_GF_CARPENTERS_NORMAL &&
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) != RO_GERUDO_KEYS_VANILLA)
? 9
: 8;
if (mOptions[RSK_KEYRINGS_RANDOM_COUNT].GetOptionCount() != maxKeyringCount + 1) {
mOptions[RSK_KEYRINGS_RANDOM_COUNT].ChangeOptions(NumOpts(0, maxKeyringCount));
}
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("FortressCarpenters"), RO_GF_CARPENTERS_NORMAL) !=
RO_GF_CARPENTERS_NORMAL ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoKeys"), RO_GERUDO_KEYS_VANILLA) == RO_GERUDO_KEYS_VANILLA) {
mOptions[RSK_KEYRINGS_GERUDO_FORTRESS].Disable(
"Disabled because the currently selected Gerudo Fortress Carpenters\n"
"setting and/or Gerudo Fortress Keys setting is incompatible with\n"
"having a Gerudo Fortress Keyring.");
} else {
mOptions[RSK_KEYRINGS_GERUDO_FORTRESS].Enable();
}
HandleKeyringUI();
});
OPT_U8(RSK_BOSS_KEYSANITY, "Boss Key Shuffle", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("BossKeysanity"), mOptionDescriptions[RSK_BOSS_KEYSANITY], WIDGET_CVAR_COMBOBOX, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON);
OPT_U8(RSK_GANONS_BOSS_KEY, "Ganon's Boss Key", {"Vanilla", "Own Dungeon", "Start With", "Any Dungeon", "Overworld", "Anywhere", "Trigger-Stones", "Trigger-Medallions", "Trigger-Rewards", "Trigger-Dungeons", "Trigger-Tokens", "Trigger-Triforce Pieces"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), mOptionDescriptions[RSK_GANONS_BOSS_KEY], WIDGET_CVAR_COMBOBOX, RO_GANON_BOSS_KEY_VANILLA);
@@ -1290,7 +1283,7 @@ void Settings::CreateOptions() {
mOptions[RSK_WINCON_DUNGEON_COUNT].ChangeOptions(NumOpts(0, 8));
}
});
OPT_U8(RSK_KEYRINGS, "Key Rings", {"Off", "Random", "Count", "Selection"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRings"), mOptionDescriptions[RSK_KEYRINGS], WIDGET_CVAR_COMBOBOX, RO_KEYRINGS_OFF);
OPT_U8(RSK_KEYRINGS, "Keyrings", {"Off", "Random", "Count", "Selection"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRings"), mOptionDescriptions[RSK_KEYRINGS], WIDGET_CVAR_COMBOBOX, RO_KEYRINGS_OFF);
OPT_CALLBACK(RSK_KEYRINGS, {
switch (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleKeyRings"), RO_KEYRINGS_OFF)) {
case RO_KEYRINGS_COUNT:
@@ -1305,6 +1298,7 @@ void Settings::CreateOptions() {
mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Hide();
mOptions[RSK_KEYRINGS_GTG].Hide();
mOptions[RSK_KEYRINGS_GANONS_CASTLE].Hide();
mOptions[RSK_KEYRINGS_CHEST_GAME].Hide();
break;
case RO_KEYRINGS_SELECTION:
// Show checkboxes for each dungeon with keys.
@@ -1318,6 +1312,7 @@ void Settings::CreateOptions() {
mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Unhide();
mOptions[RSK_KEYRINGS_GTG].Unhide();
mOptions[RSK_KEYRINGS_GANONS_CASTLE].Unhide();
mOptions[RSK_KEYRINGS_CHEST_GAME].Unhide();
break;
default:
mOptions[RSK_KEYRINGS_RANDOM_COUNT].Hide();
@@ -1330,10 +1325,11 @@ void Settings::CreateOptions() {
mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Hide();
mOptions[RSK_KEYRINGS_GTG].Hide();
mOptions[RSK_KEYRINGS_GANONS_CASTLE].Hide();
mOptions[RSK_KEYRINGS_CHEST_GAME].Hide();
break;
}
});
OPT_U8(RSK_KEYRINGS_RANDOM_COUNT, "Keyring Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsRandomCount"), "", WIDGET_CVAR_SLIDER_INT, 8);
OPT_U8(RSK_KEYRINGS_RANDOM_COUNT, "Keyring Dungeon Count", {NumOpts(0, 10)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsRandomCount"), "", WIDGET_CVAR_SLIDER_INT, 8);
OPT_U8(RSK_KEYRINGS_GERUDO_FORTRESS, "Gerudo Fortress Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGerudoFortress"), "", WIDGET_CVAR_COMBOBOX, 0);
OPT_U8(RSK_KEYRINGS_FOREST_TEMPLE, "Forest Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsForestTemple"), "", WIDGET_CVAR_COMBOBOX, 0);
OPT_U8(RSK_KEYRINGS_FIRE_TEMPLE, "Fire Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsFireTemple"), "", WIDGET_CVAR_COMBOBOX, 0);
@@ -1343,6 +1339,7 @@ void Settings::CreateOptions() {
OPT_U8(RSK_KEYRINGS_BOTTOM_OF_THE_WELL, "Bottom of the Well Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsBottomOfTheWell"), "", WIDGET_CVAR_COMBOBOX, 0);
OPT_U8(RSK_KEYRINGS_GTG, "Gerudo Training Ground Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGTG"), "", WIDGET_CVAR_COMBOBOX, 0);
OPT_U8(RSK_KEYRINGS_GANONS_CASTLE, "Ganon's Castle Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGanonsCastle"), "", WIDGET_CVAR_COMBOBOX, 0);
OPT_U8(RSK_KEYRINGS_CHEST_GAME, "Chest Minigame Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsChestGame"), "", WIDGET_CVAR_COMBOBOX, 0);
//Dummied out due to redundancy with TimeSavers.SkipChildStealth until such a time that logic needs to consider child stealth e.g. because it's freestanding checks are added to freestanding shuffle.
//To undo this dummying, readd this setting to an OptionGroup so it appears in the UI, then edit the timesaver check hooks to look at this, and the timesaver setting to lock itself as needed.
OPT_BOOL(RSK_SKIP_CHILD_STEALTH, "Skip Child Stealth", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipChildStealth"), mOptionDescriptions[RSK_SKIP_CHILD_STEALTH], WIDGET_CVAR_CHECKBOX, RO_GENERIC_DONT_SKIP);
@@ -1998,14 +1995,15 @@ void Settings::CreateOptions() {
WidgetContainerType::SECTION);
mOptionGroups[RSG_MENU_COLUMN_MQ] =
OptionGroup::SubGroup("", { &mOptionGroups[RSG_MENU_SECTION_MQ] }, WidgetContainerType::COLUMN);
mOptionGroups[RSG_MENU_SECTION_KEYRINGS] = OptionGroup::SubGroup(
"Keyrings",
{ &mOptions[RSK_KEYRINGS], &mOptions[RSK_KEYRINGS_RANDOM_COUNT], &mOptions[RSK_KEYRINGS_FOREST_TEMPLE],
&mOptions[RSK_KEYRINGS_FIRE_TEMPLE], &mOptions[RSK_KEYRINGS_WATER_TEMPLE],
&mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE], &mOptions[RSK_KEYRINGS_SHADOW_TEMPLE],
&mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL], &mOptions[RSK_KEYRINGS_GTG],
&mOptions[RSK_KEYRINGS_GANONS_CASTLE], &mOptions[RSK_KEYRINGS_GERUDO_FORTRESS] },
WidgetContainerType::SECTION);
mOptionGroups[RSG_MENU_SECTION_KEYRINGS] =
OptionGroup::SubGroup("Keyrings",
{ &mOptions[RSK_KEYRINGS], &mOptions[RSK_KEYRINGS_RANDOM_COUNT],
&mOptions[RSK_KEYRINGS_FOREST_TEMPLE], &mOptions[RSK_KEYRINGS_FIRE_TEMPLE],
&mOptions[RSK_KEYRINGS_WATER_TEMPLE], &mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE],
&mOptions[RSK_KEYRINGS_SHADOW_TEMPLE], &mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL],
&mOptions[RSK_KEYRINGS_GTG], &mOptions[RSK_KEYRINGS_GANONS_CASTLE],
&mOptions[RSK_KEYRINGS_GERUDO_FORTRESS], &mOptions[RSK_KEYRINGS_CHEST_GAME] },
WidgetContainerType::SECTION);
mOptionGroups[RSG_MENU_COLUMN_KEYRINGS] =
OptionGroup::SubGroup("", { &mOptionGroups[RSG_MENU_SECTION_KEYRINGS] }, WidgetContainerType::COLUMN);
mOptionGroups[RSG_MENU_SIDEBAR_DUNGEONS] = OptionGroup::SubGroup("Dungeons",
@@ -2046,6 +2044,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_SIGNS],
&mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES],
&mOptions[RSK_SHUFFLE_ADULT_TRADE],
&mOptions[RSK_SHUFFLE_CHEST_MINIGAME],
&mOptions[RSK_SHUFFLE_100_GS_REWARD],
&mOptions[RSK_SHUFFLE_FOUNTAIN_FAIRIES],
&mOptions[RSK_SHUFFLE_STONE_FAIRIES],
@@ -2359,6 +2358,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL],
&mOptions[RSK_KEYRINGS_GTG],
&mOptions[RSK_KEYRINGS_GANONS_CASTLE],
&mOptions[RSK_KEYRINGS_CHEST_GAME],
});
mOptionGroups[RSG_STARTING_ITEMS] =
OptionGroup::SubGroup("Items", { &mOptions[RSK_STARTING_OCARINA], &mOptions[RSK_STARTING_KOKIRI_SWORD],
@@ -2729,10 +2729,6 @@ void Context::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocation
mOptions[RSK_STARTING_BOTTLE_4].Set(RO_STARTING_BOTTLE_OFF);
}
// RANDOTODO implement chest shuffle with keysanity
// ShuffleChestMinigame.Set(cvarSettings[RSK_SHUFFLE_CHEST_MINIGAME]);
mOptions[RSK_SHUFFLE_CHEST_MINIGAME].Set(RO_CHEST_GAME_OFF);
// TODO: RandomizeAllSettings(true) when implementing the ability to randomize the options themselves.
std::array<DungeonInfo*, 12> dungeons = this->GetDungeons()->GetDungeonList();
@@ -2853,7 +2849,7 @@ void Context::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocation
}
}
// Set key ring for each dungeon
// Set keyring for each dungeon
for (const auto dungeon : dungeons) {
dungeon->ClearKeyRing();
}
@@ -2866,7 +2862,7 @@ void Context::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocation
};
if (mOptions[RSK_KEYRINGS]) {
// Random Key Rings
// Random Keyrings
auto keyrings = keyRingOptions;
if (mOptions[RSK_GERUDO_FORTRESS].Is(RO_GF_CARPENTERS_NORMAL) &&
mOptions[RSK_GERUDO_KEYS].IsNot(RO_GERUDO_KEYS_VANILLA)) {
@@ -2874,6 +2870,11 @@ void Context::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocation
} else {
mOptions[RSK_KEYRINGS_GERUDO_FORTRESS].Set(RO_KEYRING_FOR_DUNGEON_OFF);
}
if (mOptions[RSK_SHUFFLE_CHEST_MINIGAME]) {
keyrings.push_back(&mOptions[RSK_KEYRINGS_CHEST_GAME]);
} else {
mOptions[RSK_KEYRINGS_CHEST_GAME].Set(RO_KEYRING_FOR_DUNGEON_OFF);
}
if (mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_RANDOM) || mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT)) {
const uint32_t keyRingCount = mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT)
? mOptions[RSK_KEYRINGS_RANDOM_COUNT].Get()
@@ -2918,6 +2919,12 @@ void Context::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocation
(mOptions[RSK_KEYRINGS_GANONS_CASTLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 0)) {
this->GetDungeon(GANONS_CASTLE)->SetKeyRing();
}
// Gerudo Fortress & the chest minigame have no DungeonInfo, so resolve their random rolls into the option
for (const auto keyring : { &mOptions[RSK_KEYRINGS_GERUDO_FORTRESS], &mOptions[RSK_KEYRINGS_CHEST_GAME] }) {
if (keyring->Is(RO_KEYRING_FOR_DUNGEON_RANDOM)) {
keyring->Set(Random(0, 2) == 0 ? RO_KEYRING_FOR_DUNGEON_ON : RO_KEYRING_FOR_DUNGEON_OFF);
}
}
}
auto trials = this->GetTrials()->GetTrialList();
@@ -22,6 +22,11 @@ class Settings {
*/
void HandleMixedEntrancePoolsUI();
/**
* @brief Hides or Unhides the UI of the keyring options, and updates the max keyring count.
*/
void HandleKeyringUI();
/**
* @brief UI Callback for handling UI state of Starting Age shuffle.
*/
+10 -5
View File
@@ -135,7 +135,8 @@ void EnBox_Init(Actor* thisx, PlayState* play2) {
if (play) {} // helps the compiler store play2 into s1
if (Flags_GetTreasure(play, this->dyna.actor.params & 0x1F)) {
if (GameInteractor_Should(VB_CHEST_CONSIDER_CHEST_OPEN, Flags_GetTreasure(play, this->dyna.actor.params & 0x1F),
this)) {
this->alpha = 255;
this->iceSmokeTimer = 100;
EnBox_SetupAction(this, EnBox_Open);
@@ -441,7 +442,9 @@ void EnBox_WaitOpen(EnBox* this, PlayState* play) {
}
}
osSyncPrintf("Actor_Environment_Tbox_On() %d\n", this->dyna.actor.params & 0x1F);
Flags_SetTreasure(play, this->dyna.actor.params & 0x1F);
if (GameInteractor_Should(VB_CHEST_SET_TREASURE_FLAG, true, this)) {
Flags_SetTreasure(play, this->dyna.actor.params & 0x1F);
}
} else {
player = GET_PLAYER(play);
Actor_WorldToActorCoords(&this->dyna.actor, &sp4C, &player->actor.world.pos);
@@ -449,7 +452,8 @@ void EnBox_WaitOpen(EnBox* this, PlayState* play) {
Player_IsFacingActor(&this->dyna.actor, 0x3000, play)) {
Actor_OfferGetItemNearby(&this->dyna.actor, play, -(this->dyna.actor.params >> 5 & 0x7F));
}
if (Flags_GetTreasure(play, this->dyna.actor.params & 0x1F)) {
if (GameInteractor_Should(VB_CHEST_CONSIDER_CHEST_OPEN, Flags_GetTreasure(play, this->dyna.actor.params & 0x1F),
this)) {
EnBox_SetupAction(this, EnBox_Open);
}
}
@@ -576,9 +580,10 @@ void EnBox_UpdateTexture(EnBox* this, PlayState* play) {
GetItemCategory getItemCategory;
GetItemEntry chestItem = this->getItemEntry;
// Exclude treasure game chests except for the final room, unless the chest game is shuffled
int isVanilla = !csmc || (requiresStoneAgony && !CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)) ||
(play->sceneNum == SCENE_TREASURE_BOX_SHOP &&
this->dyna.actor.room != 6); // Exclude treasure game chests except for the final room
(play->sceneNum == SCENE_TREASURE_BOX_SHOP && this->dyna.actor.room != 6 &&
!Randomizer_GetSettingValue(RSK_SHUFFLE_CHEST_MINIGAME));
if (!isVanilla) {
getItemCategory = Randomizer_AdjustItemCategory(chestItem);
@@ -8,6 +8,7 @@
#include "vt.h"
#include "overlays/actors/ovl_Item_Etcetera/z_item_etcetera.h"
#include "overlays/actors/ovl_En_Ex_Item/z_en_ex_item.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#define FLAGS 0
@@ -136,7 +137,7 @@ void EnChanger_Init(Actor* thisx, PlayState* play2) {
this->rightChestGetItemId = GI_DOOR_KEY;
rightChestItem = ITEM_ETC_KEY_SMALL_CHEST_GAME;
if (Rand_ZeroFloat(1.99f) < 1.0f) {
if (GameInteractor_Should(VB_EN_CHANGER_SWAP_CHESTS, Rand_ZeroFloat(1.99f) < 1.0f, this)) {
rightChestParams = (sLoserGetItemIds[play->roomCtx.curRoom.num] << 5) | 0x4000;
this->rightChestNum = new_var;
this->rightChestGetItemId = sLoserGetItemIds[play->roomCtx.curRoom.num];
@@ -10,6 +10,7 @@
#include "soh/OTRGlobals.h"
#include "soh/ResourceManagerHelpers.h"
#include "soh/Enhancements/savestate_serialize.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#define FLAGS \
(ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_CULLING_DISABLED | \
@@ -64,8 +65,10 @@ void EnTakaraMan_Init(Actor* thisx, PlayState* play) {
osSyncPrintf("\n\n");
// "Bun! %x" (needs a better translation)
osSyncPrintf(VT_FGCOL(PURPLE) "☆☆☆☆☆ ばぅん! ☆☆☆☆☆ %x\n" VT_RST, play->actorCtx.flags.chest);
play->actorCtx.flags.chest = 0;
gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = -1;
if (GameInteractor_Should(VB_TAKARA_MAN_RESET_CHESTS_AND_KEYS, true, this)) {
play->actorCtx.flags.chest = 0;
gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = -1;
}
SkelAnime_InitFlex(play, &this->skelAnime, &object_ts_Skel_004FE0, &object_ts_Anim_000498, this->jointTable,
this->morphTable, 10);
thisx->focus.pos = thisx->world.pos;
@@ -156,7 +159,9 @@ void func_80B17934(EnTakaraMan* this, PlayState* play) {
Rupees_ChangeBy(-10);
this->unk_214 = 1;
this->actor.parent = NULL;
Actor_OfferGetItem(&this->actor, play, GI_DOOR_KEY, 2000.0f, 1000.0f);
if (GameInteractor_Should(VB_TAKARA_MAN_OFFER_GET_ITEM, true, this)) {
Actor_OfferGetItem(&this->actor, play, GI_DOOR_KEY, 2000.0f, 1000.0f);
}
this->actionFunc = func_80B17A6C;
} else {
Message_CloseTextbox(play);
@@ -180,7 +185,7 @@ void func_80B17934(EnTakaraMan* this, PlayState* play) {
void func_80B17A6C(EnTakaraMan* this, PlayState* play) {
if (Actor_HasParent(&this->actor, play)) {
this->actionFunc = func_80B17AC4;
} else {
} else if (GameInteractor_Should(VB_TAKARA_MAN_OFFER_GET_ITEM, true, this)) {
Actor_OfferGetItem(&this->actor, play, GI_DOOR_KEY, 2000.0f, 1000.0f);
}
}