Shuffle Zelda's Letter (#6938)

Removes RSK_SKIP_CHILD_ZELDA & RSK_KAK_GATE,
these are managed by RSK_SHUFFLE_ZELDAS_LETTER & RSK_STARTING_ZELDAS_LETTER & RSK_SHUFFLE_WEIRD_EGG
This commit is contained in:
Philip Dubé
2026-07-19 22:37:45 +00:00
committed by GitHub
parent cb974d123f
commit 1ea7206073
31 changed files with 180 additions and 117 deletions
@@ -22,7 +22,6 @@
"GregHint": 1,
"HBAHint": 1,
"IncludeTycoonWallet": 1,
"KakarikoGate": 1,
"Keysanity": 5,
"GbkRewardCount": 8,
"MalonHint": 1,
@@ -55,11 +54,12 @@
"ShuffleSongs": 2,
"ShuffleSwim": 1,
"ShuffleTokens": 3,
"SkipChildZelda": 1,
"ShuffleWeirdEgg": 2,
"SkipEponaRace": 1,
"SkipScarecrowsSong": 1,
"StartingAge": 2,
"StartingMapsCompasses": 0,
"StartingZeldasLetter": 1,
"SunlightArrows": 1
}
}
@@ -25,7 +25,6 @@
"GregHint": 1,
"HBAHint": 1,
"IncludeTycoonWallet": 1,
"KakarikoGate": 1,
"Keysanity": 2,
"GbkRewardCount": 6,
"MalonHint": 1,
@@ -35,12 +34,13 @@
"SheikLAHint": 0,
"ShuffleGanonBossKey": 8,
"ShuffleOcarinas": 1,
"SkipChildZelda": 1,
"ShuffleWeirdEgg": 2,
"SkipEponaRace": 1,
"SkipScarecrowsSong": 1,
"StartingKokiriSword": 1,
"StartingMapsCompasses": 0,
"StartingOcarina": 1,
"StartingZeldasLetter": 1,
"SunlightArrows": 1,
"ZorasFountain": 1
}
@@ -16,7 +16,6 @@
"FishsanityPondCount": 17,
"GerudoKeys": 3,
"IncludeTycoonWallet": 1,
"KakarikoGate": 1,
"Keysanity": 5,
"GbkRewardCount": 10,
"GbkRewardOptions": 1,
@@ -83,6 +82,7 @@
"ShuffleTokens": 3,
"ShuffleWarpSongs": 1,
"ShuffleWeirdEgg": 1,
"ShuffleZeldasLetter": 1,
"StartingAge": 2,
"StartingHearts": 0,
"StartingMapsCompasses": 5,
@@ -25,7 +25,6 @@
"GregHint": 1,
"HBAHint": 1,
"IncludeTycoonWallet": 1,
"KakarikoGate": 1,
"Keysanity": 5,
"GbkRewardCount": 7,
"MalonHint": 1,
@@ -48,11 +47,12 @@
"ShuffleScrubs": 2,
"ShuffleSongs": 2,
"ShuffleTokens": 3,
"SkipChildZelda": 1,
"ShuffleWeirdEgg": 2,
"SkipEponaRace": 1,
"SkipScarecrowsSong": 1,
"StartingMapsCompasses": 0,
"StartingOcarina": 1,
"StartingZeldasLetter": 1,
"SunlightArrows": 1,
"ZorasFountain": 1
}
@@ -638,7 +638,7 @@ void CreateStoneHints() {
std::vector<HintDistributionSetting> distTable = hintSetting.distTable;
// Apply impa's song exclusions when zelda is skipped
if (ctx->GetOption(RSK_SKIP_CHILD_ZELDA)) {
if (ctx->GetOption(RSK_STARTING_ZELDAS_LETTER) && !ctx->GetOption(RSK_SHUFFLE_ZELDAS_LETTER)) {
ctx->GetItemLocation(RC_SONG_FROM_IMPA)->SetHintAccesible();
}
if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT) || !ctx->GetOption(RSK_SHUFFLE_MASTER_SWORD)) {
@@ -331,7 +331,9 @@ void GenerateItemPool() {
}
// Fixed item locations
ctx->PlaceItemInLocation(RC_HC_ZELDAS_LETTER, RG_ZELDAS_LETTER);
if (!ctx->GetOption(RSK_SHUFFLE_ZELDAS_LETTER)) {
ctx->PlaceItemInLocation(RC_HC_ZELDAS_LETTER, RG_ZELDAS_LETTER);
}
ctx->PlaceItemInLocation(RC_GANONS_BOSS_KEY, RG_BLUE_RUPEE); // placeholder, filled by setting
ctx->PlaceItemInLocation(RC_GANON_SOUL, RG_BLUE_RUPEE); // placeholder, filled by setting
ctx->PlaceItemInLocation(RC_WINCON, RG_BLUE_RUPEE); // placeholder, filled by setting
@@ -364,7 +366,7 @@ void GenerateItemPool() {
}
}
if (ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG)) {
if (ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG).Is(RO_WEIRD_EGG_SHUFFLED)) {
if (!ctx->GetOption(RSK_STARTING_WEIRD_EGG)) {
AddItemToPool(RG_WEIRD_EGG, 2, 1, 1, 1);
}
@@ -372,6 +374,10 @@ void GenerateItemPool() {
ctx->PlaceItemInLocation(RC_HC_MALON_EGG, RG_WEIRD_EGG, false, true);
}
if (ctx->GetOption(RSK_SHUFFLE_ZELDAS_LETTER) && !ctx->GetOption(RSK_STARTING_ZELDAS_LETTER)) {
AddItemToPool(RG_ZELDAS_LETTER, 2, 1, 1, 1);
}
if (ctx->GetOption(RSK_SHUFFLE_OCARINA)) {
if (ctx->GetOption(RSK_STARTING_OCARINA).IsNot(RO_STARTING_OCARINA_TIME)) {
int baseOcarinas = ctx->GetOption(RSK_STARTING_OCARINA).Is(RO_STARTING_OCARINA_OFF) ? 2 : 1;
@@ -109,9 +109,13 @@ void GenerateStartingInventory() {
}
}
// The weird egg only exists as an item when it's shuffled; vanilla gives it through the cutscene.
if (ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG)) {
if (ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG).Is(RO_WEIRD_EGG_SHUFFLED)) {
AddItemToInventory(RG_WEIRD_EGG, ctx->GetOption(RSK_STARTING_WEIRD_EGG) ? 1 : 0);
}
// Same for Zelda's Letter.
if (ctx->GetOption(RSK_SHUFFLE_ZELDAS_LETTER)) {
AddItemToInventory(RG_ZELDAS_LETTER, ctx->GetOption(RSK_STARTING_ZELDAS_LETTER) ? 1 : 0);
}
AddItemToInventory(RG_BUNNY_HOOD, ctx->GetOption(RSK_STARTING_BUNNY_HOOD) ? 1 : 0);
AddItemToInventory(RG_CLAIM_CHECK, ctx->GetOption(RSK_STARTING_CLAIM_CHECK) ? 1 : 0);
AddItemToInventory(RG_PROGRESSIVE_OCARINA, ctx->GetOption(RSK_STARTING_OCARINA).Get());
@@ -1,3 +1,4 @@
#include "ShuffleTradeItems.h"
#include "functions.h"
#include "variables.h"
#include "macros.h"
@@ -294,11 +294,11 @@ void RandomizerOnFlagSetHandler(int16_t flagType, int16_t flag) {
}
if (flagType == FLAG_EVENT_CHECK_INF && flag == EVENTCHKINF_TALON_WOKEN_IN_CASTLE) {
// remove chicken as this is the only use for it
Flags_UnsetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_CHICKEN);
}
if (flagType == FLAG_EVENT_CHECK_INF && flag == EVENTCHKINF_OBTAINED_ZELDAS_LETTER) {
if (flagType == FLAG_EVENT_CHECK_INF && flag == EVENTCHKINF_OBTAINED_ZELDAS_LETTER &&
!RAND_GET_OPTION(RSK_SHUFFLE_ZELDAS_LETTER)) {
Flags_SetRandomizerInf(RAND_INF_ZELDAS_LETTER);
}
@@ -46,8 +46,8 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_DOUBLE_DEFENSE] = Item(RG_DOUBLE_DEFENSE, Text{ "Double Defense", "Double Défense", "Doppelte Verteidigung" }, ITEMTYPE_ITEM, RG_DOUBLE_DEFENSE, true, LOGIC_DOUBLE_DEFENSE, RHT_DOUBLE_DEFENSE, RG_DOUBLE_DEFENSE, OBJECT_GI_HEARTS, GID_HEART_CONTAINER, 0xE9, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_HEALTH, MOD_RANDOMIZER, {"", "la ", ""});
itemTable[RG_DOUBLE_DEFENSE].SetCustomDrawFunc(Randomizer_DrawDoubleDefense);
// Trade Quest Items
itemTable[RG_WEIRD_EGG] = Item(RG_WEIRD_EGG, Text{ "Weird Egg", "Oeuf Curieux", "Seltsames Ei" }, ITEMTYPE_ITEM, GI_WEIRD_EGG, true, LOGIC_WEIRD_EGG, RHT_WEIRD_EGG, ITEM_WEIRD_EGG, OBJECT_GI_EGG, GID_EGG, 0x9A, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE, {"the ", "l'", "das "});
itemTable[RG_ZELDAS_LETTER] = Item(RG_ZELDAS_LETTER, Text{ "Zelda's Letter", "Lettre de Zelda", "Zeldas Brief" }, ITEMTYPE_ITEM, GI_LETTER_ZELDA, true, LOGIC_ZELDAS_LETTER, RHT_ZELDAS_LETTER, ITEM_LETTER_ZELDA, OBJECT_GI_LETTER, GID_LETTER_ZELDA, 0x69, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE, {"", "la ", ""});
itemTable[RG_WEIRD_EGG] = Item(RG_WEIRD_EGG, Text{ "Weird Egg", "Oeuf Curieux", "Seltsames Ei" }, ITEMTYPE_ITEM, GI_WEIRD_EGG, true, LOGIC_WEIRD_EGG, RHT_WEIRD_EGG, ITEM_WEIRD_EGG, OBJECT_GI_EGG, GID_EGG, 0x9A, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"the ", "l'", "das "});
itemTable[RG_ZELDAS_LETTER] = Item(RG_ZELDAS_LETTER, Text{ "Zelda's Letter", "Lettre de Zelda", "Zeldas Brief" }, ITEMTYPE_ITEM, GI_LETTER_ZELDA, true, LOGIC_ZELDAS_LETTER, RHT_ZELDAS_LETTER, ITEM_LETTER_ZELDA, OBJECT_GI_LETTER, GID_LETTER_ZELDA, 0x69, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "la ", ""});
itemTable[RG_POCKET_EGG] = Item(RG_POCKET_EGG, Text{ "Pocket Egg", "Oeuf de poche", "Ei" }, ITEMTYPE_ITEM, GI_POCKET_EGG, true, LOGIC_POCKET_EGG, RHT_POCKET_EGG, ITEM_POCKET_EGG, OBJECT_GI_EGG, GID_EGG, 0x01, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE, {"the ", "l'", "das "});
itemTable[RG_COJIRO] = Item(RG_COJIRO, Text{ "Cojiro", "P'tit Poulet", "Henni" }, ITEMTYPE_ITEM, GI_COJIRO, true, LOGIC_COJIRO, RHT_COJIRO, ITEM_COJIRO, OBJECT_GI_NIWATORI, GID_COJIRO, 0x02, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE);
itemTable[RG_ODD_MUSHROOM] = Item(RG_ODD_MUSHROOM, Text{ "Odd Mushroom", "Champigon Suspect", "Schimmelpilz" }, ITEMTYPE_ITEM, GI_ODD_MUSHROOM, true, LOGIC_ODD_MUSHROOM, RHT_ODD_MUSHROOM, ITEM_ODD_MUSHROOM, OBJECT_GI_MUSHROOM, GID_ODD_MUSHROOM, 0x03, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE, {"the ", "le ", "den "});
@@ -25,6 +25,7 @@ void RegionTable_Init_CastleGrounds() {
//Events
EVENT_ACCESS(LOGIC_FAIRY_ACCESS, logic->CallGossipFairy() || logic->CanUse(RG_STICKS)),
EVENT_ACCESS(LOGIC_BUG_ACCESS, logic->HasItem(RG_POWER_BRACELET)),
EVENT_ACCESS(LOGIC_MALON_RETURNED_FROM_CASTLE, logic->Get(LOGIC_TALON_RETURNED_FROM_CASTLE) && logic->HasItem(RG_SPEAK_HYLIAN)),
}, {
//Locations
LOCATION(RC_HC_MALON_EGG, logic->HasItem(RG_SPEAK_HYLIAN)),
@@ -95,7 +96,10 @@ void RegionTable_Init_CastleGrounds() {
ENTRANCE(RR_HC_MOAT, true),
});
areaTable[RR_HC_MOAT] = Region("Hyrule Castle Moat", SCENE_HYRULE_CASTLE, {}, {
areaTable[RR_HC_MOAT] = Region("Hyrule Castle Moat", SCENE_HYRULE_CASTLE, {
//Events
EVENT_ACCESS(LOGIC_TALON_RETURNED_FROM_CASTLE, logic->CanUse(RG_WEIRD_EGG) && logic->HasItem(RG_SPEAK_HYLIAN)),
}, {
//Locations
LOCATION(RC_HC_GRASS_1, logic->CanCutShrubs()),
LOCATION(RC_HC_GRASS_2, logic->CanCutShrubs()),
@@ -116,7 +120,7 @@ void RegionTable_Init_CastleGrounds() {
//Exits
ENTRANCE(RR_HC_GATE, true),
ENTRANCE(RR_HC_STORMS_GROTTO, logic->CanOpenStormsGrotto()),
ENTRANCE(RR_HC_DRAIN_LEDGE, (logic->CanUse(RG_WEIRD_EGG) && logic->HasItem(RG_POWER_BRACELET) && logic->HasItem(RG_SPEAK_HYLIAN)) ||
ENTRANCE(RR_HC_DRAIN_LEDGE, (logic->Get(LOGIC_TALON_RETURNED_FROM_CASTLE) && logic->HasItem(RG_POWER_BRACELET)) ||
(ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->TakeDamage() && logic->HasExplosives() && logic->CanJumpslash())),
});
@@ -126,10 +130,13 @@ void RegionTable_Init_CastleGrounds() {
ENTRANCE(RR_HC_GARDEN, logic->CanUse(RG_CRAWL)),
});
areaTable[RR_HC_GARDEN] = Region("HC Garden", SCENE_CASTLE_COURTYARD_ZELDA, {}, {
areaTable[RR_HC_GARDEN] = Region("HC Garden", SCENE_CASTLE_COURTYARD_ZELDA, {
//Events
EVENT_ACCESS(LOGIC_MET_ZELDA, logic->HasItem(RG_SPEAK_HYLIAN)),
}, {
//Locations
LOCATION(RC_HC_ZELDAS_LETTER, logic->HasItem(RG_SPEAK_HYLIAN)),
LOCATION(RC_SONG_FROM_IMPA, logic->HasItem(RG_SPEAK_HYLIAN)),
LOCATION(RC_HC_ZELDAS_LETTER, logic->Get(LOGIC_MET_ZELDA)),
LOCATION(RC_SONG_FROM_IMPA, logic->Get(LOGIC_MET_ZELDA)),
LOCATION(RC_HC_WONDER_COURTYARD_RIGHT_WINDOW, logic->CanUse(RG_FAIRY_SLINGSHOT)),
LOCATION(RC_HC_WONDER_COURTYARD_LEFT_WINDOW, logic->CanUse(RG_FAIRY_SLINGSHOT)),
}, {
@@ -11,7 +11,7 @@ void RegionTable_Init_LonLonRanch() {
EVENT_ACCESS(LOGIC_LINKS_COW, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->CanUse(RG_EPONAS_SONG) && logic->IsAdult && logic->AtDay),
}, {
//Locations
LOCATION(RC_SONG_FROM_MALON, logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->HasItem(RG_FAIRY_OCARINA) && logic->AtDay),
LOCATION(RC_SONG_FROM_MALON, logic->IsChild && logic->Get(LOGIC_MALON_RETURNED_FROM_CASTLE) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->HasItem(RG_FAIRY_OCARINA) && logic->AtDay),
LOCATION(RC_LLR_GS_TREE, logic->IsChild && logic->CanBonkTrees() && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_LLR_GS_RAIN_SHED, logic->IsChild && logic->CanGetNightTimeGS() && (logic->HasItem(RG_POWER_BRACELET) || logic->CanKillEnemy(RE_GOLD_SKULLTULA))),
LOCATION(RC_LLR_GS_HOUSE_WINDOW, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()),
@@ -38,7 +38,7 @@ void RegionTable_Init_LonLonRanch() {
areaTable[RR_LLR_TALONS_HOUSE] = Region("LLR Talons House", SCENE_LON_LON_BUILDINGS, {}, {
//Locations
LOCATION(RC_LLR_TALONS_CHICKENS, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->IsChild && logic->AtDay && logic->HasItem(RG_ZELDAS_LETTER) && logic->HasItem(RG_POWER_BRACELET)),
LOCATION(RC_LLR_TALONS_CHICKENS, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->IsChild && logic->AtDay && logic->Get(LOGIC_TALON_RETURNED_FROM_CASTLE) && logic->HasItem(RG_POWER_BRACELET)),
LOCATION(RC_LLR_TALONS_HOUSE_POT_1, logic->CanBreakPots()),
LOCATION(RC_LLR_TALONS_HOUSE_POT_2, logic->CanBreakPots()),
LOCATION(RC_LLR_TALONS_HOUSE_POT_3, logic->CanBreakPots()),
@@ -152,7 +152,7 @@ void RegionTable_Init_Market() {
//Currently, mask swap in menu doesn't need access to the mask shop
//If it is forced on/a setting, a copy of these events should be added to root
//it also doesn't need you to open kak gate, but that might be best treated as a bug
EVENT_ACCESS(LOGIC_CAN_BORROW_MASKS, logic->HasItem(RG_ZELDAS_LETTER) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->Get(LOGIC_KAKARIKO_GATE_OPEN)),
EVENT_ACCESS(LOGIC_CAN_BORROW_MASKS, logic->HasItem(RG_SPEAK_HYLIAN) && logic->Get(LOGIC_KAKARIKO_GATE_OPEN)),
EVENT_ACCESS(LOGIC_BORROW_SKULL_MASK, ctx->GetOption(RSK_MASK_QUEST).Is(RO_MASK_QUEST_COMPLETED) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->Get(LOGIC_CAN_BORROW_MASKS)),
EVENT_ACCESS(LOGIC_BORROW_SPOOKY_MASK, ctx->GetOption(RSK_MASK_QUEST).Is(RO_MASK_QUEST_COMPLETED) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->Get(LOGIC_CAN_BORROW_MASKS)),
EVENT_ACCESS(LOGIC_BORROW_BUNNY_HOOD, ctx->GetOption(RSK_MASK_QUEST).Is(RO_MASK_QUEST_COMPLETED) && logic->HasItem(RG_SPEAK_HYLIAN) && logic->Get(LOGIC_CAN_BORROW_MASKS)),
@@ -42,7 +42,7 @@ void RegionTable_Init_SacredForestMeadow() {
EVENT_ACCESS(LOGIC_FAIRY_ACCESS, logic->CallGossipFairyExceptSuns()),
}, {
//Locations
LOCATION(RC_SONG_FROM_SARIA, logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER)),
LOCATION(RC_SONG_FROM_SARIA, logic->IsChild && logic->Get(LOGIC_MET_ZELDA)),
LOCATION(RC_SHEIK_IN_FOREST, logic->IsAdult),
LOCATION(RC_SFM_SARIA_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()),
LOCATION(RC_SFM_SARIA_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)),
@@ -7,7 +7,7 @@ void RegionTable_Init_Root() {
// clang-format off
areaTable[RR_ROOT] = Region("Root", SCENE_ID_MAX, TIME_DOESNT_PASS, {RA_LINKS_POCKET}, {
//Events
EVENT_ACCESS(LOGIC_KAKARIKO_GATE_OPEN, ctx->GetOption(RSK_KAK_GATE).Is(RO_KAK_GATE_OPEN)),
EVENT_ACCESS(LOGIC_KAKARIKO_GATE_OPEN, (bool)ctx->GetOption(RSK_STARTING_ZELDAS_LETTER)),
EVENT_ACCESS(LOGIC_TH_COULD_FREE_1_TORCH_CARPENTER, ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE)),
EVENT_ACCESS(LOGIC_TH_COULD_FREE_DOUBLE_CELL_CARPENTER, ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST)),
EVENT_ACCESS(LOGIC_TH_COULD_FREE_DEAD_END_CARPENTER, ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST)),
@@ -15,6 +15,9 @@ void RegionTable_Init_Root() {
EVENT_ACCESS(LOGIC_TH_RESCUED_ALL_CARPENTERS, ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE)),
EVENT_ACCESS(LOGIC_FREED_EPONA, (bool)ctx->GetOption(RSK_SKIP_EPONA_RACE)),
EVENT_ACCESS(LOGIC_SHOWED_MIDO_SWORD_AND_SHIELD, ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_OFF)),
EVENT_ACCESS(LOGIC_MET_ZELDA, ctx->GetOption(RSK_STARTING_ZELDAS_LETTER) && !ctx->GetOption(RSK_SHUFFLE_ZELDAS_LETTER)),
EVENT_ACCESS(LOGIC_MALON_RETURNED_FROM_CASTLE, ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG).Is(RO_WEIRD_EGG_SKIP_TALON)),
EVENT_ACCESS(LOGIC_TALON_RETURNED_FROM_CASTLE, ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG).Is(RO_WEIRD_EGG_SKIP_TALON)),
}, {
//Locations
LOCATION(RC_LINKS_POCKET, true),
@@ -22,9 +25,9 @@ void RegionTable_Init_Root() {
LOCATION(RC_GANON_SOUL, logic->CanTriggerGanonsSoul()),
LOCATION(RC_WINCON, logic->CanTriggerWincon()),
LOCATION(RC_SARIA_SONG_HINT, logic->CanUse(RG_SARIAS_SONG)),
LOCATION(RC_SONG_FROM_IMPA, (bool)ctx->GetOption(RSK_SKIP_CHILD_ZELDA)),
LOCATION(RC_HC_MALON_EGG, (bool)ctx->GetOption(RSK_SKIP_CHILD_ZELDA)),
LOCATION(RC_HC_ZELDAS_LETTER, (bool)ctx->GetOption(RSK_SKIP_CHILD_ZELDA)),
LOCATION(RC_SONG_FROM_IMPA, ctx->GetOption(RSK_STARTING_ZELDAS_LETTER) && !ctx->GetOption(RSK_SHUFFLE_ZELDAS_LETTER)),
LOCATION(RC_HC_MALON_EGG, ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG).Is(RO_WEIRD_EGG_SKIP_TALON)),
LOCATION(RC_HC_ZELDAS_LETTER, ctx->GetOption(RSK_STARTING_ZELDAS_LETTER) && !ctx->GetOption(RSK_SHUFFLE_ZELDAS_LETTER)),
LOCATION(RC_TOT_MASTER_SWORD, (bool)ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT)),
}, {
//Exits
+2 -2
View File
@@ -122,7 +122,7 @@ bool Logic::HasItem(RandomizerGet itemName) {
case RO_MASK_QUEST_VANILLA:
return Get(LOGIC_BORROW_SKULL_MASK);
case RO_MASK_QUEST_COMPLETED:
return HasItem(RG_ZELDAS_LETTER) && Get(LOGIC_KAKARIKO_GATE_OPEN);
return Get(LOGIC_KAKARIKO_GATE_OPEN);
case RO_MASK_QUEST_SHUFFLE:
return CheckRandoInf(RAND_INF_CHILD_TRADES_HAS_MASK_SKULL);
default:
@@ -134,7 +134,7 @@ bool Logic::HasItem(RandomizerGet itemName) {
case RO_MASK_QUEST_VANILLA:
return Get(LOGIC_BORROW_RIGHT_MASKS);
case RO_MASK_QUEST_COMPLETED:
return HasItem(RG_ZELDAS_LETTER) && Get(LOGIC_KAKARIKO_GATE_OPEN);
return Get(LOGIC_KAKARIKO_GATE_OPEN);
case RO_MASK_QUEST_SHUFFLE:
return CheckRandoInf(RAND_INF_CHILD_TRADES_HAS_MASK_TRUTH);
default:
@@ -15,11 +15,6 @@ void Settings::CreateOptionDescriptions() {
"\n"
"Off - Mido no longer blocks the path to the Deku Tree. Kokiri "
"boy no longer blocks the path out of the forest.";
mOptionDescriptions[RSK_KAK_GATE] = "Closed - The gate will remain closed until Zelda's Letter "
"is shown to the guard.\n"
"\n"
"Open - The gate is always open. The Happy Mask Shop "
"will open immediately after obtaining Zelda's Letter.";
mOptionDescriptions[RSK_DOOR_OF_TIME] = "Closed - The Ocarina of Time, the Song of Time and all "
"three Spiritual Stones are required to open the Door of Time.\n"
"\n"
@@ -274,15 +269,20 @@ void Settings::CreateOptionDescriptions() {
"Shuffle ability to speak to NPCs. 6 jabbernuts will be shuffled:\nDeku, Gerudo, Goron, Hylian, Kokiri, "
"Zora\nKaepora Gaebora speaks any language.";
mOptionDescriptions[RSK_SHUFFLE_OPEN_CHEST] = "Shuffles the ability to open chests into the item pool.";
mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG] = "Shuffles the Weird Egg from Malon in to the item pool. Enabling "
"\"Skip Child Zelda\" disables this feature.\n"
"\n"
"The Weird Egg is required to unlock several events:\n"
" - Zelda's Lullaby from Impa\n"
" - Saria's Song in Sacred Forest Meadow\n"
" - Epona's Song and chicken minigame at Lon Lon Ranch\n"
" - Zelda's Letter for Kakariko gate (if set to closed)\n"
" - Happy Mask Shop sidequest\n";
mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG] =
"Vanilla: Malon gives the Weird Egg at Hyrule Castle.\n"
"\n"
"Shuffled: shuffles Weird Egg into item pool.\n"
"\n"
"Skip Waking Talon: Talon already woken and back at Lon Lon Ranch with Malon.";
mOptionDescriptions[RSK_SHUFFLE_ZELDAS_LETTER] =
"Shuffles Zelda's Letter into the item pool, meeting Zelda gives a random item instead.\n"
"\n"
"Required to open Kakariko gate and Happy Mask Shop. Starting with letter starts with gate opened.\n"
"\n"
"Meeting Zelda still triggers Saria at Sacred Forest Meadow.\n"
"\n"
"When disabled, \"Start with Zelda's Letter\" skips child Zelda: you also get item Impa would give.";
mOptionDescriptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD] =
"Shuffles the Gerudo Membership Card into the item pool.\n"
"\n"
@@ -685,9 +685,6 @@ void Settings::CreateOptionDescriptions() {
mOptionDescriptions[RSK_BIG_POE_COUNT] = "The Poe collector will give a reward for turning in this many Big Poes.";
mOptionDescriptions[RSK_SKIP_CHILD_STEALTH] =
"The crawlspace into Hyrule Castle goes straight to Zelda, skipping the guards.";
mOptionDescriptions[RSK_SKIP_CHILD_ZELDA] =
"Start with Zelda's Letter and the item Impa would normally give you and skip the sequence up "
"until after meeting Zelda. Disables the ability to shuffle Weird Egg.";
mOptionDescriptions[RSK_SKIP_EPONA_RACE] = "Epona can be summoned with Epona's Song without needing to race Ingo.";
mOptionDescriptions[RSK_MASK_QUEST] =
"How masks are acquired.\n"
+25 -1
View File
@@ -1094,6 +1094,10 @@ void Randomizer_GameplayStats_SetTimestamp(uint16_t item) {
timestampItem = ITEM_DOUBLE_DEFENSE;
} else if (item >= RG_KEATON_MASK && item <= RG_MASK_OF_TRUTH) {
timestampItem = ITEM_MASK_KEATON + (item - RG_KEATON_MASK);
} else if (item == RG_WEIRD_EGG) {
timestampItem = ITEM_WEIRD_EGG;
} else if (item == RG_ZELDAS_LETTER) {
timestampItem = ITEM_LETTER_ZELDA;
} else if (randomizerGetToStatsTimeStamp.contains((RandomizerGet)item)) {
timestampItem = randomizerGetToStatsTimeStamp[(RandomizerGet)item];
}
@@ -1105,6 +1109,16 @@ void Randomizer_GameplayStats_SetTimestamp(uint16_t item) {
extern "C" u8 Return_Item_Entry(GetItemEntry itemEntry, u8 returnItem);
// The child trade slot can be displaced (e.g. chicken consumed waking Talon,
// letter shown to the guard), leaving an item there the player no longer owns.
static bool ChildTradeSlotOccupied() {
u8 slotItem = INV_CONTENT(ITEM_TRADE_CHILD);
if (slotItem < ITEM_WEIRD_EGG || slotItem > ITEM_MASK_TRUTH) {
return false;
}
return Flags_GetRandomizerInf((RandomizerInf)(slotItem - ITEM_WEIRD_EGG + RAND_INF_CHILD_TRADES_HAS_WEIRD_EGG));
}
extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
if (giEntry.modIndex != MOD_RANDOMIZER) {
LUSLOG_WARN(
@@ -1136,9 +1150,19 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
gSaveContext.inventory.dungeonKeys[SCENE_THIEVES_HIDEOUT] = GERUDO_FORTRESS_SMALL_KEY_MAX;
gSaveContext.inventory.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX;
} else if (item >= RG_KEATON_MASK && item <= RG_MASK_OF_TRUTH) {
if (INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_NONE) {
if (!ChildTradeSlotOccupied()) {
INV_CONTENT(ITEM_TRADE_CHILD) = (int)ITEM_MASK_KEATON + (item - RG_KEATON_MASK);
}
} else if (item == RG_WEIRD_EGG) {
Flags_SetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_WEIRD_EGG);
if (!ChildTradeSlotOccupied()) {
INV_CONTENT(ITEM_TRADE_CHILD) = ITEM_WEIRD_EGG;
}
} else if (item == RG_ZELDAS_LETTER) {
Flags_SetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_LETTER_ZELDA);
if (!ChildTradeSlotOccupied()) {
INV_CONTENT(ITEM_TRADE_CHILD) = ITEM_LETTER_ZELDA;
}
} else if (item == RG_CHILD_WALLET &&
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FULL_WALLETS)) {
Rupees_ChangeBy(99);
@@ -312,6 +312,9 @@ RANDO_ENUM_ITEM(LOGIC_SHADOW_MQ_SWITCH_ACROSS_CHASM)
RANDO_ENUM_ITEM(LOGIC_SHADOW_MQ_EYE_SWITCH_ACROSS_CHASM)
RANDO_ENUM_ITEM(LOGIC_WAKE_UP_ADULT_TALON)
RANDO_ENUM_ITEM(LOGIC_KAKARIKO_GATE_OPEN)
RANDO_ENUM_ITEM(LOGIC_MET_ZELDA)
RANDO_ENUM_ITEM(LOGIC_MALON_RETURNED_FROM_CASTLE)
RANDO_ENUM_ITEM(LOGIC_TALON_RETURNED_FROM_CASTLE)
RANDO_ENUM_ITEM(LOGIC_DELIVER_RUTOS_LETTER)
RANDO_ENUM_ITEM(LOGIC_KING_ZORA_THAWED)
RANDO_ENUM_ITEM(LOGIC_LINKS_COW)
@@ -77,12 +77,6 @@ RANDO_ENUM_ITEM(RO_GF_CARPENTERS_FAST)
RANDO_ENUM_ITEM(RO_GF_CARPENTERS_FREE)
RANDO_ENUM_END(RandoOptionGerudoFortress)
// Kakariko Gate settings (closed/open)
RANDO_ENUM_BEGIN(RandoOptionKakarikoGate)
RANDO_ENUM_ITEM(RO_KAK_GATE_CLOSED)
RANDO_ENUM_ITEM(RO_KAK_GATE_OPEN)
RANDO_ENUM_END(RandoOptionKakarikoGate)
// Rainbow Bridge settings (vanilla, always open, stones, medallions, dungeon rewards, dungeons, tokens)
RANDO_ENUM_BEGIN(RandoOptionRainbowBridge)
RANDO_ENUM_ITEM(RO_BRIDGE_VANILLA)
@@ -313,6 +307,13 @@ RANDO_ENUM_ITEM(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS)
RANDO_ENUM_ITEM(RO_SHUFFLE_MERCHANTS_ALL)
RANDO_ENUM_END(RandoOptionShuffleMerchants)
// Shuffle Weird Egg Settings (vanilla, shuffled, skip waking talon)
RANDO_ENUM_BEGIN(RandoOptionShuffleWeirdEgg)
RANDO_ENUM_ITEM(RO_WEIRD_EGG_VANILLA)
RANDO_ENUM_ITEM(RO_WEIRD_EGG_SHUFFLED)
RANDO_ENUM_ITEM(RO_WEIRD_EGG_SKIP_TALON)
RANDO_ENUM_END(RandoOptionShuffleWeirdEgg)
// Starting Ocarina Settings (off, fairy, oot)
RANDO_ENUM_BEGIN(RandoOptionStartingOcarina)
RANDO_ENUM_ITEM(RO_STARTING_OCARINA_OFF)
@@ -15,7 +15,6 @@ RANDO_ENUM_BEGIN(RandomizerSettingKey)
RANDO_ENUM_ITEM(RSK_NONE)
RANDO_ENUM_ITEM(RSK_LOGIC_RULES)
RANDO_ENUM_ITEM(RSK_FOREST)
RANDO_ENUM_ITEM(RSK_KAK_GATE)
RANDO_ENUM_ITEM(RSK_DOOR_OF_TIME)
RANDO_ENUM_ITEM(RSK_ZORAS_FOUNTAIN)
RANDO_ENUM_ITEM(RSK_SLEEPING_WATERFALL)
@@ -93,6 +92,7 @@ RANDO_ENUM_ITEM(RSK_SCRUBS_PRICES_AFFORDABLE)
RANDO_ENUM_ITEM(RSK_SHUFFLE_BEEHIVES)
RANDO_ENUM_ITEM(RSK_SHUFFLE_COWS)
RANDO_ENUM_ITEM(RSK_SHUFFLE_WEIRD_EGG)
RANDO_ENUM_ITEM(RSK_SHUFFLE_ZELDAS_LETTER)
RANDO_ENUM_ITEM(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)
RANDO_ENUM_ITEM(RSK_SHUFFLE_POTS)
RANDO_ENUM_ITEM(RSK_SHUFFLE_CRATES)
@@ -142,7 +142,6 @@ RANDO_ENUM_ITEM(RSK_BOSS_KEYSANITY)
RANDO_ENUM_ITEM(RSK_GANONS_BOSS_KEY)
RANDO_ENUM_ITEM(RSK_GANONS_SOUL)
RANDO_ENUM_ITEM(RSK_SKIP_CHILD_STEALTH)
RANDO_ENUM_ITEM(RSK_SKIP_CHILD_ZELDA)
RANDO_ENUM_ITEM(RSK_STARTING_STICKS)
RANDO_ENUM_ITEM(RSK_STARTING_NUTS)
RANDO_ENUM_ITEM(RSK_STARTING_BEANS)
@@ -176,6 +175,7 @@ RANDO_ENUM_ITEM(RSK_STARTING_BOTTLE_2)
RANDO_ENUM_ITEM(RSK_STARTING_BOTTLE_3)
RANDO_ENUM_ITEM(RSK_STARTING_BOTTLE_4)
RANDO_ENUM_ITEM(RSK_STARTING_WEIRD_EGG)
RANDO_ENUM_ITEM(RSK_STARTING_ZELDAS_LETTER)
RANDO_ENUM_ITEM(RSK_STARTING_CLAIM_CHECK)
RANDO_ENUM_ITEM(RSK_STARTING_GERUDO_CARD)
RANDO_ENUM_ITEM(RSK_STARTING_BIGGORON_SWORD)
@@ -154,7 +154,8 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() {
RO_DUNGEON_REWARDS_END_OF_DUNGEON) && // dungeon rewards end of dungeons
(location.GetRCType() != RCTYPE_OCARINA ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleOcarinas"), RO_GENERIC_NO)) && // ocarina locations
(location.GetRandomizerCheck() != RC_HC_ZELDAS_LETTER) && // don't show until we support shuffling letter
(location.GetRandomizerCheck() != RC_HC_ZELDAS_LETTER ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleZeldasLetter"), RO_GENERIC_NO)) &&
(location.GetRCType() !=
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
@@ -215,7 +216,8 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() {
(location.GetRandomizerCheck() != RC_ZR_MAGIC_BEAN_SALESMAN ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), RO_SHUFFLE_MERCHANTS_OFF) % 2) &&
(location.GetRandomizerCheck() != RC_HC_MALON_EGG ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), RO_GENERIC_NO)) &&
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), RO_WEIRD_EGG_VANILLA) ==
RO_WEIRD_EGG_SHUFFLED) &&
(location.GetRCType() != RCTYPE_FROG_SONG ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleFrogSongRupees"), RO_GENERIC_NO)) &&
(location.GetRCType() != RCTYPE_FOUNTAIN_FAIRY ||
@@ -71,6 +71,7 @@ bool showKokiriSword;
bool showMasterSword;
bool showHyruleLoach;
bool showWeirdEgg;
bool showZeldasLetter;
bool showGerudoCard;
bool showOverworldPots;
bool showDungeonPots;
@@ -1373,8 +1374,11 @@ void LoadSettings() {
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_GENERIC_YES
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
@@ -1665,8 +1669,7 @@ bool IsCheckShuffled(RandomizerCheck rc) {
(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
(rc != RC_HC_ZELDAS_LETTER) && // don't show zeldas letter until we support shuffling it
(rc != RC_LINKS_POCKET || showLinksPocket) &&
(rc != RC_HC_ZELDAS_LETTER || showZeldasLetter) && (rc != RC_LINKS_POCKET || showLinksPocket) &&
OTRGlobals::Instance->gRandoContext->IsQuestOfLocationActive(rc) &&
(loc->GetRCType() != RCTYPE_SHOP ||
(showShops &&
+25 -21
View File
@@ -336,9 +336,14 @@ void SetStartingItems() {
Item_Give(NULL, ITEM_BOTTLE);
}
if (Randomizer_GetSettingValue(RSK_STARTING_WEIRD_EGG) && Randomizer_GetSettingValue(RSK_SHUFFLE_WEIRD_EGG)) {
if (Randomizer_GetSettingValue(RSK_STARTING_WEIRD_EGG) &&
Randomizer_GetSettingValue(RSK_SHUFFLE_WEIRD_EGG) == RO_WEIRD_EGG_SHUFFLED) {
Item_Give(NULL, ITEM_WEIRD_EGG);
}
if (Randomizer_GetSettingValue(RSK_STARTING_ZELDAS_LETTER) &&
Randomizer_GetSettingValue(RSK_SHUFFLE_ZELDAS_LETTER)) {
Item_Give(NULL, ITEM_LETTER_ZELDA);
}
if (Randomizer_GetSettingValue(RSK_STARTING_CLAIM_CHECK)) {
Item_Give(NULL, ITEM_CLAIM_CHECK);
}
@@ -571,33 +576,37 @@ extern "C" void Randomizer_InitSaveFile() {
}
}
if (Randomizer_GetSettingValue(RSK_SKIP_CHILD_ZELDA)) {
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_SONG_FROM_IMPA, (GetItemID)RG_ZELDAS_LULLABY);
StartingItemGive(getItemEntry, RC_SONG_FROM_IMPA);
getItemEntry = Randomizer_GetItemFromKnownCheck(RC_HC_MALON_EGG, (GetItemID)RG_WEIRD_EGG);
StartingItemGive(getItemEntry, RC_HC_MALON_EGG);
getItemEntry = Randomizer_GetItemFromKnownCheck(RC_HC_ZELDAS_LETTER, (GetItemID)RG_ZELDAS_LETTER);
StartingItemGive(getItemEntry, RC_HC_ZELDAS_LETTER);
// Skip Waking Talon: the egg already hatched and woke him, Malon/Talon start back at the ranch.
if (Randomizer_GetSettingValue(RSK_SHUFFLE_WEIRD_EGG) == RO_WEIRD_EGG_SKIP_TALON) {
OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_HC_MALON_EGG)->SetCheckStatus(RCSHOW_SAVED);
// Malon/Talon back at ranch.
Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_POCKET_EGG);
Flags_SetRandomizerInf(RAND_INF_WEIRD_EGG);
Flags_SetEventChkInf(EVENTCHKINF_TALON_WOKEN_IN_CASTLE);
Flags_SetEventChkInf(EVENTCHKINF_TALON_RETURNED_FROM_CASTLE);
}
// Set "Got Zelda's Letter" flag. Also ensures Saria is back at SFM.
// Starting with an unshuffled letter skips child Zelda.
if (Randomizer_GetSettingValue(RSK_STARTING_ZELDAS_LETTER) &&
!Randomizer_GetSettingValue(RSK_SHUFFLE_ZELDAS_LETTER)) {
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_SONG_FROM_IMPA, (GetItemID)RG_ZELDAS_LULLABY);
StartingItemGive(getItemEntry, RC_SONG_FROM_IMPA);
getItemEntry = Randomizer_GetItemFromKnownCheck(RC_HC_ZELDAS_LETTER, (GetItemID)RG_ZELDAS_LETTER);
StartingItemGive(getItemEntry, RC_HC_ZELDAS_LETTER);
// Set "Met Zelda" flag. Also ensures Saria is back at SFM.
Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER);
Flags_SetRandomizerInf(RAND_INF_ZELDAS_LETTER);
Flags_SetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_LETTER_ZELDA);
// Got item from Impa.
Flags_SetEventChkInf(EVENTCHKINF_LEARNED_ZELDAS_LULLABY);
}
gSaveContext.sceneFlags[SCENE_HYRULE_CASTLE].swch |= (1 << 0x4); // Move milk crates in Hyrule Castle to moat.
// Set this at the end to ensure we always start with the letter.
// This is for the off chance, we got the Weird Egg from Impa (which should never happen).
INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA;
// Starting with the letter opens the Kakariko gate, shuffled or not.
// The letter then has no use, so drop it from the trade cycle.
if (Randomizer_GetSettingValue(RSK_STARTING_ZELDAS_LETTER)) {
Flags_SetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD);
Flags_UnsetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_LETTER_ZELDA);
}
if (Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && startingAge == RO_AGE_ADULT) {
@@ -631,11 +640,6 @@ extern "C" void Randomizer_InitSaveFile() {
break;
}
if (Randomizer_GetSettingValue(RSK_KAK_GATE) == RO_KAK_GATE_OPEN) {
Flags_SetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD);
Flags_UnsetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_LETTER_ZELDA);
}
if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_CARPENTERS_FAST ||
Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_CARPENTERS_FREE) {
Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(1));
+9 -25
View File
@@ -165,7 +165,6 @@ void Settings::CreateOptions() {
OPT_CALLBACK(RSK_FOREST, {
HandleStartingAgeUI();
});
OPT_U8(RSK_KAK_GATE, "Kakariko Gate", {"Closed", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("KakarikoGate"), mOptionDescriptions[RSK_KAK_GATE]);
OPT_U8(RSK_DOOR_OF_TIME, "Door of Time", {"Closed", "Song only", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("DoorOfTime"), mOptionDescriptions[RSK_DOOR_OF_TIME], WIDGET_CVAR_COMBOBOX);
OPT_CALLBACK(RSK_DOOR_OF_TIME, {
HandleStartingAgeUI();
@@ -853,7 +852,8 @@ void Settings::CreateOptions() {
});
OPT_BOOL(RSK_SHUFFLE_SPEAK, "Shuffle Jabber Nuts", CVAR_RANDOMIZER_SETTING("ShuffleSpeak"), mOptionDescriptions[RSK_SHUFFLE_SPEAK]);
OPT_BOOL(RSK_SHUFFLE_OPEN_CHEST, "Shuffle Open Chest", CVAR_RANDOMIZER_SETTING("ShuffleOpenChest"), mOptionDescriptions[RSK_SHUFFLE_OPEN_CHEST]);
OPT_BOOL(RSK_SHUFFLE_WEIRD_EGG, "Shuffle Weird Egg", CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG]);
OPT_U8(RSK_SHUFFLE_WEIRD_EGG, "Shuffle Weird Egg", {"Vanilla", "Shuffled", "Skip Waking Talon"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG], WIDGET_CVAR_COMBOBOX, RO_WEIRD_EGG_VANILLA);
OPT_BOOL(RSK_SHUFFLE_ZELDAS_LETTER, "Shuffle Zelda's Letter", CVAR_RANDOMIZER_SETTING("ShuffleZeldasLetter"), mOptionDescriptions[RSK_SHUFFLE_ZELDAS_LETTER]);
OPT_BOOL(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD, "Shuffle Gerudo Membership Card", CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"), mOptionDescriptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD]);
OPT_U8(RSK_SHUFFLE_POTS, "Shuffle Pots", {"Off", "Dungeons", "Overworld", "All Pots"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShufflePots"), mOptionDescriptions[RSK_SHUFFLE_POTS], WIDGET_CVAR_COMBOBOX, RO_SHUFFLE_POTS_OFF);
OPT_U8(RSK_SHUFFLE_GRASS, "Shuffle Grass", {"Off", "Dungeons", "Overworld", "All Grass"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleGrass"), mOptionDescriptions[RSK_SHUFFLE_GRASS], WIDGET_CVAR_COMBOBOX, RO_SHUFFLE_GRASS_OFF);
@@ -1345,17 +1345,6 @@ void Settings::CreateOptions() {
//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);
OPT_BOOL(RSK_SKIP_CHILD_ZELDA, "Skip Child Zelda", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipChildZelda"), mOptionDescriptions[RSK_SKIP_CHILD_ZELDA], WIDGET_CVAR_CHECKBOX, RO_GENERIC_DONT_SKIP);
OPT_CALLBACK(RSK_SKIP_CHILD_ZELDA, {
// Shuffle Weird Egg - Disabled when Skip Child Zelda is active
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("SkipChildZelda"), RO_GENERIC_DONT_SKIP)) {
mOptions[RSK_SHUFFLE_WEIRD_EGG].Disable("This option is disabled because \"Skip Child Zelda\" is enabled.");
mOptions[RSK_SKIP_CHILD_STEALTH].Disable("This option is disabled because \"Skip Child Zelda\" is enabled.");
} else {
mOptions[RSK_SHUFFLE_WEIRD_EGG].Enable();
mOptions[RSK_SKIP_CHILD_STEALTH].Enable();
}
});
OPT_BOOL(RSK_EARLY_GRANNYS_SHOP, "Early Granny's Potion Shop", CVAR_RANDOMIZER_SETTING("EarlyGrannysShop"), mOptionDescriptions[RSK_EARLY_GRANNYS_SHOP]);
OPT_BOOL(RSK_SKIP_EPONA_RACE, "Skip Epona Race", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipEponaRace"), mOptionDescriptions[RSK_SKIP_EPONA_RACE], WIDGET_CVAR_CHECKBOX, RO_GENERIC_DONT_SKIP);
OPT_BOOL(RSK_SKIP_SCARECROWS_SONG, "Skip Scarecrow's Song", CVAR_RANDOMIZER_SETTING("SkipScarecrowsSong"), mOptionDescriptions[RSK_SKIP_SCARECROWS_SONG]);
@@ -1458,6 +1447,7 @@ void Settings::CreateOptions() {
OPT_U8(RSK_STARTING_BOTTLE_3, "Starting Bottle 3", {"Off", "Empty Bottle", "Bottle with Big Poe"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingBottle3"), "", WIDGET_CVAR_COMBOBOX, 0);
OPT_U8(RSK_STARTING_BOTTLE_4, "Starting Bottle 4", {"Off", "Empty Bottle", "Bottle with Big Poe"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingBottle4"), "", WIDGET_CVAR_COMBOBOX, 0);
OPT_BOOL(RSK_STARTING_WEIRD_EGG, "Start with Weird Egg", CVAR_RANDOMIZER_SETTING("StartingWeirdEgg"));
OPT_BOOL(RSK_STARTING_ZELDAS_LETTER, "Start with Zelda's Letter", CVAR_RANDOMIZER_SETTING("StartingZeldasLetter"));
OPT_BOOL(RSK_STARTING_CLAIM_CHECK, "Start with Claim Check", CVAR_RANDOMIZER_SETTING("StartingClaimCheck"));
OPT_BOOL(RSK_STARTING_GERUDO_CARD, "Start with Gerudo Card", CVAR_RANDOMIZER_SETTING("StartingGerudoCard"));
OPT_BOOL(RSK_STARTING_BUNNY_HOOD, "Start with Bunny Hood", CVAR_RANDOMIZER_SETTING("StartingBunnyHood"));
@@ -1887,7 +1877,6 @@ void Settings::CreateOptions() {
&mOptions[RSK_FULL_WALLETS],
&mOptions[RSK_SLINGBOW_BREAK_BEEHIVES],
&mOptions[RSK_SWORDLESS_EPONA_ITEMS],
&mOptions[RSK_SKIP_CHILD_ZELDA],
&mOptions[RSK_MASK_QUEST],
&mOptions[RSK_SKIP_CHILD_STEALTH],
&mOptions[RSK_EARLY_GRANNYS_SHOP],
@@ -1935,7 +1924,6 @@ void Settings::CreateOptions() {
OptionGroup::SubGroup("Area Access",
{
&mOptions[RSK_FOREST],
&mOptions[RSK_KAK_GATE],
&mOptions[RSK_DOOR_OF_TIME],
&mOptions[RSK_ZORAS_FOUNTAIN],
&mOptions[RSK_SLEEPING_WATERFALL],
@@ -2035,6 +2023,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_MASTER_SWORD],
&mOptions[RSK_SHUFFLE_OCARINA],
&mOptions[RSK_SHUFFLE_WEIRD_EGG],
&mOptions[RSK_SHUFFLE_ZELDAS_LETTER],
&mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD],
&mOptions[RSK_FISHSANITY],
&mOptions[RSK_FISHSANITY_POND_COUNT],
@@ -2186,7 +2175,6 @@ void Settings::CreateOptions() {
WidgetContainerType::TABLE);
mOptionGroups[RSG_OPEN] = OptionGroup("Open Settings", {
&mOptions[RSK_FOREST],
&mOptions[RSK_KAK_GATE],
&mOptions[RSK_DOOR_OF_TIME],
&mOptions[RSK_ZORAS_FOUNTAIN],
&mOptions[RSK_SLEEPING_WATERFALL],
@@ -2296,6 +2284,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_SPEAK],
&mOptions[RSK_SHUFFLE_OPEN_CHEST],
&mOptions[RSK_SHUFFLE_WEIRD_EGG],
&mOptions[RSK_SHUFFLE_ZELDAS_LETTER],
&mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD],
&mOptions[RSK_SHUFFLE_MERCHANTS],
&mOptions[RSK_MERCHANT_PRICES],
@@ -2386,8 +2375,9 @@ void Settings::CreateOptions() {
&mOptions[RSK_STARTING_BOMBCHU_BAG], &mOptions[RSK_STARTING_BOTTLE_1],
&mOptions[RSK_STARTING_BOTTLE_2], &mOptions[RSK_STARTING_BOTTLE_3],
&mOptions[RSK_STARTING_BOTTLE_4], &mOptions[RSK_STARTING_WEIRD_EGG],
&mOptions[RSK_STARTING_CLAIM_CHECK], &mOptions[RSK_STARTING_GERUDO_CARD],
&mOptions[RSK_STARTING_BIGGORON_SWORD], &mOptions[RSK_STARTING_BUNNY_HOOD] });
&mOptions[RSK_STARTING_ZELDAS_LETTER], &mOptions[RSK_STARTING_CLAIM_CHECK],
&mOptions[RSK_STARTING_GERUDO_CARD], &mOptions[RSK_STARTING_BIGGORON_SWORD],
&mOptions[RSK_STARTING_BUNNY_HOOD] });
mOptionGroups[RSG_STARTING_SONGS] =
OptionGroup::SubGroup("Ocarina Songs", {
&mOptions[RSK_STARTING_ZELDAS_LULLABY],
@@ -2419,7 +2409,6 @@ void Settings::CreateOptions() {
},
OptionGroupType::DEFAULT);
mOptionGroups[RSG_TIMESAVERS] = OptionGroup("Timesaver Settings", {
&mOptions[RSK_SKIP_CHILD_ZELDA],
&mOptions[RSK_SKIP_EPONA_RACE],
&mOptions[RSK_SKIP_SCARECROWS_SONG],
&mOptions[RSK_SKIP_PLANTING_BEANS],
@@ -2629,12 +2618,6 @@ void Settings::UpdateAllOptions() {
void Context::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocations,
const std::set<RandomizerTrick>& enabledTricks) {
// if we skip child zelda, we start with zelda's letter, and malon starts
// at the ranch, so we should *not* shuffle the weird egg
if (mOptions[RSK_SKIP_CHILD_ZELDA]) {
mOptions[RSK_SHUFFLE_WEIRD_EGG].Set(RO_GENERIC_OFF);
}
// With certain access settings, the seed is only beatable if Starting Age is set to Child.
if (mOptions[RSK_LOGIC_RULES].IsNot(RO_LOGIC_NO_LOGIC) &&
((mOptions[RSK_DOOR_OF_TIME].Is(RO_DOOROFTIME_CLOSED) && !mOptions[RSK_SHUFFLE_OCARINA]) ||
@@ -3164,6 +3147,7 @@ void Settings::RandomizeAllSettings() {
case RSK_STARTING_BOTTLE_3:
case RSK_STARTING_BOTTLE_4:
case RSK_STARTING_WEIRD_EGG:
case RSK_STARTING_ZELDAS_LETTER:
case RSK_STARTING_CLAIM_CHECK:
case RSK_STARTING_GERUDO_CARD:
case RSK_STARTING_BIGGORON_SWORD:
+18 -1
View File
@@ -290,7 +290,8 @@ void DrawStartingItemsMenu(WidgetInfo& info) {
StartingItemToggle(RSK_STARTING_CLAIM_CHECK, ITEM_CLAIM_CHECK);
ImGui::SameLine();
bool weirdEggShuffled =
CVarGetInteger(Rando::Settings::GetInstance()->GetOption(RSK_SHUFFLE_WEIRD_EGG).GetCVarName().c_str(), 0) != 0;
CVarGetInteger(Rando::Settings::GetInstance()->GetOption(RSK_SHUFFLE_WEIRD_EGG).GetCVarName().c_str(),
RO_WEIRD_EGG_VANILLA) == RO_WEIRD_EGG_SHUFFLED;
ImGui::BeginDisabled(!weirdEggShuffled);
StartingItemToggle(RSK_STARTING_WEIRD_EGG, ITEM_WEIRD_EGG, !weirdEggShuffled);
ImGui::EndDisabled();
@@ -298,6 +299,22 @@ void DrawStartingItemsMenu(WidgetInfo& info) {
ImGui::SetTooltip("Enable Shuffle Weird Egg to start with the Weird Egg.");
}
ImGui::SameLine();
bool zeldasLetterShuffled =
CVarGetInteger(Rando::Settings::GetInstance()->GetOption(RSK_SHUFFLE_ZELDAS_LETTER).GetCVarName().c_str(), 0) !=
0;
StartingItemToggle(RSK_STARTING_ZELDAS_LETTER, ITEM_LETTER_ZELDA);
if (ImGui::IsItemHovered()) {
if (zeldasLetterShuffled) {
ImGui::SetTooltip("Start with Zelda's Letter\n\n"
"The Kakariko gate starts open.");
} else {
ImGui::SetTooltip("Start with Zelda's Letter\n\n"
"The Kakariko gate starts open.\n"
"While the letter isn't shuffled this also skips child Zelda:\n"
"you get the item Impa would give and skip everything up to meeting Zelda.");
}
}
ImGui::SameLine();
StartingItemToggle(RSK_STARTING_BUNNY_HOOD, ITEM_MASK_BUNNY);
ImGui::SeparatorText("Songs");
+10
View File
@@ -1659,5 +1659,15 @@ void ConfigVersion7Updater::Update(Ship::Config* conf) {
CVarSetInteger("gRandoSettings.ShuffleBossSouls", RO_BOSS_SOULS_ON);
CVarSetInteger("gRandoSettings.ShuffleGanonsSoul", RO_GANONS_SOUL_ANYWHERE);
}
// Skip Child Zelda split into starting with unshuffled Zelda's Letter & Skip Waking Talon
if (CVarGetInteger("gRandoSettings.SkipChildZelda", 0)) {
CVarSetInteger("gRandoSettings.StartingZeldasLetter", 1);
CVarSetInteger("gRandoSettings.ShuffleWeirdEgg", RO_WEIRD_EGG_SKIP_TALON);
}
CVarClear("gRandoSettings.SkipChildZelda");
// Kakariko Gate setting removed; the gate opens when starting with an unshuffled letter
CVarClear("gRandoSettings.KakarikoGate");
}
} // namespace SOH
+1
View File
@@ -2410,6 +2410,7 @@ u8 Item_Give(PlayState* play, u8 item) {
if (item >= ITEM_POCKET_EGG) {
Flags_SetRandomizerInf(item - ITEM_POCKET_EGG + RAND_INF_ADULT_TRADES_HAS_POCKET_EGG);
} else if (item == ITEM_LETTER_ZELDA) {
Flags_SetRandomizerInf(RAND_INF_ZELDAS_LETTER);
// don't care about zelda's letter if it's already been shown to the guard
if (!Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD)) {
Flags_SetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_LETTER_ZELDA);
@@ -46,8 +46,7 @@ void BgGateShutter_Init(Actor* thisx, PlayState* play) {
this->somePos.y = thisx->world.pos.y;
this->somePos.z = thisx->world.pos.z;
if (((Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD)) ||
(!IS_RANDO && (Flags_GetEventChkInf(EVENTCHKINF_PULLED_MASTER_SWORD_FROM_PEDESTAL))) ||
(IS_RANDO && (Randomizer_GetSettingValue(RSK_KAK_GATE) == RO_KAK_GATE_OPEN))) &&
(!IS_RANDO && (Flags_GetEventChkInf(EVENTCHKINF_PULLED_MASTER_SWORD_FROM_PEDESTAL)))) &&
(play->sceneNum == SCENE_KAKARIKO_VILLAGE)) {
thisx->world.pos.x = -89.0f;
thisx->world.pos.z = -1375.0f;
@@ -606,10 +606,7 @@ void EnOssan_Init(Actor* thisx, PlayState* play) {
}
// If you haven't given Zelda's Letter to the Kakariko Guard
// or are rando'd and haven't gotten gotten the letter from zelda yet
if (this->actor.params == OSSAN_TYPE_MASK &&
(!Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD) ||
(IS_RANDO && !Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER)))) {
if (this->actor.params == OSSAN_TYPE_MASK && !Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD)) {
Actor_Kill(&this->actor);
return;
}
@@ -344,7 +344,7 @@ bool CanMaskSelect() {
void KaleidoScope_HandleItemCycles(PlayState* play) {
// handle the mask select
KaleidoScope_HandleItemCycleExtras(
play, SLOT_TRADE_CHILD, CanMaskSelect(),
play, SLOT_TRADE_CHILD, IS_RANDO || CanMaskSelect(),
IS_RANDO ? Randomizer_GetPrevChildTradeItem()
: (INV_CONTENT(ITEM_TRADE_CHILD) <= ITEM_MASK_KEATON || INV_CONTENT(ITEM_TRADE_CHILD) > ITEM_MASK_TRUTH
? ITEM_MASK_TRUTH
@@ -385,7 +385,7 @@ void KaleidoScope_HandleItemCycles(PlayState* play) {
void KaleidoScope_DrawItemCycles(PlayState* play) {
// draw the mask select
KaleidoScope_DrawItemCycleExtras(
play, SLOT_TRADE_CHILD, CanMaskSelect(),
play, SLOT_TRADE_CHILD, IS_RANDO || CanMaskSelect(),
IS_RANDO ? Randomizer_GetPrevChildTradeItem()
: (INV_CONTENT(ITEM_TRADE_CHILD) <= ITEM_MASK_KEATON || INV_CONTENT(ITEM_TRADE_CHILD) > ITEM_MASK_TRUTH
? ITEM_MASK_TRUTH