Early Granny's Potion Shop (#6693)

ZFG thinks it makes more sense not requiring Claim Check, so add option
This commit is contained in:
Philip Dubé
2026-06-12 05:05:37 +00:00
committed by GitHub
parent 8499286899
commit 7b01a7bf2e
9 changed files with 32 additions and 92 deletions
@@ -34,36 +34,6 @@ Context::Context() {
mLogic = std::make_shared<Logic>();
mTrials = std::make_shared<Trials>();
mFishsanity = std::make_shared<Fishsanity>();
VanillaLogicDefaults = {
// RANDOTODO check what this does
&mOptions[RSK_LINKS_POCKET],
&mOptions[RSK_SHUFFLE_DUNGEON_REWARDS],
&mOptions[RSK_SHUFFLE_SONGS],
&mOptions[RSK_SHOPSANITY],
&mOptions[RSK_SHOPSANITY_COUNT],
&mOptions[RSK_SHOPSANITY_PRICES],
&mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE],
&mOptions[RSK_FISHSANITY],
&mOptions[RSK_FISHSANITY_POND_COUNT],
&mOptions[RSK_FISHSANITY_AGE_SPLIT],
&mOptions[RSK_SHUFFLE_SCRUBS],
&mOptions[RSK_SHUFFLE_BEEHIVES],
&mOptions[RSK_SHUFFLE_COWS],
&mOptions[RSK_SHUFFLE_POTS],
&mOptions[RSK_SHUFFLE_CRATES],
&mOptions[RSK_SHUFFLE_ROCKS],
&mOptions[RSK_SHUFFLE_BOULDERS],
&mOptions[RSK_SHUFFLE_FREESTANDING],
&mOptions[RSK_SHUFFLE_MERCHANTS],
&mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES],
&mOptions[RSK_SHUFFLE_ADULT_TRADE],
&mOptions[RSK_SHUFFLE_100_GS_REWARD],
&mOptions[RSK_SHUFFLE_FOUNTAIN_FAIRIES],
&mOptions[RSK_SHUFFLE_STONE_FAIRIES],
&mOptions[RSK_SHUFFLE_BEAN_FAIRIES],
&mOptions[RSK_SHUFFLE_SONG_FAIRIES],
&mOptions[RSK_GOSSIP_STONE_HINTS],
};
}
RandomizerArea Context::GetAreaFromString(std::string str) {
@@ -128,7 +128,6 @@ class Context {
std::vector<RandomizerCheck> everyPossibleLocation = {};
std::set<RandomizerGet> possibleIceTrapModels = {};
std::unordered_map<RandomizerCheck, RandomizerGet> iceTrapModels = {};
std::vector<OptionValue*> VanillaLogicDefaults = {};
std::array<uint8_t, 5> hashIconIndexes = {};
bool playthroughBeatable = false;
bool allLocationsReachable = false;
@@ -688,8 +688,8 @@ u8 EnDs_RandoCanGetGrannyItem() {
!Flags_GetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP) &&
// Traded odd mushroom when adult trade is on
((RAND_GET_OPTION(RSK_SHUFFLE_ADULT_TRADE) && Flags_GetItemGetInf(ITEMGETINF_30)) ||
// Found claim check when adult trade is off
(!RAND_GET_OPTION(RSK_SHUFFLE_ADULT_TRADE) && INV_CONTENT(ITEM_CLAIM_CHECK) == ITEM_CLAIM_CHECK));
(!RAND_GET_OPTION(RSK_SHUFFLE_ADULT_TRADE) &&
(RAND_GET_OPTION(RSK_EARLY_GRANNYS_SHOP) || INV_CONTENT(ITEM_CLAIM_CHECK) == ITEM_CLAIM_CHECK)));
}
u8 EnJs_RandoCanGetCarpetMerchantItem() {
@@ -257,8 +257,10 @@ void RegionTable_Init_Kakariko() {
}, {
//Locations
LOCATION(RC_KAK_TRADE_ODD_MUSHROOM, logic->IsAdult && logic->CanUse(RG_ODD_MUSHROOM)),
LOCATION(RC_KAK_GRANNYS_SHOP, logic->IsAdult && logic->HasItem(RG_SPEAK_HYLIAN) &&
(logic->CanUse(RG_ODD_MUSHROOM) || logic->TradeQuestStep(RG_ODD_MUSHROOM)) && GetCheckPrice() <= GetWalletCapacity()),
LOCATION(RC_KAK_GRANNYS_SHOP, logic->IsAdult && logic->HasItem(RG_SPEAK_HYLIAN) &&
(logic->CanUse(RG_ODD_MUSHROOM) || (ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE).Is(RO_GENERIC_OFF) &&
(logic->HasItem(RG_CLAIM_CHECK) || ctx->GetOption(RSK_EARLY_GRANNYS_SHOP))) &&
GetCheckPrice() <= GetWalletCapacity())),
}, {
// Exits
ENTRANCE(RR_KAK_BACKYARD, true),
-44
View File
@@ -1498,50 +1498,6 @@ bool Logic::SunlightArrows() {
return ctx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS);
}
// Is this best off signaling what you have already traded, or what step you are currently on?
bool Logic::TradeQuestStep(RandomizerGet rg) {
if (ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE)) {
return false; // This does not apply when we are shuffling trade items
}
bool hasState = false;
// Falling through each case to test each possibility
switch (rg) {
case RG_POCKET_EGG:
hasState = hasState || HasItem(RG_POCKET_EGG);
[[fallthrough]];
case RG_COJIRO:
hasState = hasState || HasItem(RG_COJIRO);
[[fallthrough]];
case RG_ODD_MUSHROOM:
hasState = hasState || HasItem(RG_ODD_MUSHROOM);
[[fallthrough]];
case RG_ODD_POTION:
hasState = hasState || HasItem(RG_ODD_POTION);
[[fallthrough]];
case RG_POACHERS_SAW:
hasState = hasState || HasItem(RG_POACHERS_SAW);
[[fallthrough]];
case RG_BROKEN_SWORD:
hasState = hasState || HasItem(RG_BROKEN_SWORD);
[[fallthrough]];
case RG_PRESCRIPTION:
hasState = hasState || HasItem(RG_PRESCRIPTION);
[[fallthrough]];
case RG_EYEDROPS:
hasState = hasState || HasItem(RG_EYEDROPS);
[[fallthrough]];
case RG_CLAIM_CHECK:
hasState = hasState || HasItem(RG_CLAIM_CHECK);
break;
default:
SPDLOG_ERROR("TradeQuestStep reached `return false;`. Missing case for RandomizerGet of {}",
static_cast<uint32_t>(rg));
assert(false);
return false;
}
return hasState;
}
bool Logic::CanStandingShield() {
return CanUse(RG_MIRROR_SHIELD) || (IsAdult && HasItem(RG_HYLIAN_SHIELD)) || CanUse(RG_DEKU_SHIELD);
}
-1
View File
@@ -113,7 +113,6 @@ class Logic {
bool HasFireSource();
bool HasFireSourceWithTorch();
bool SunlightArrows();
bool TradeQuestStep(RandomizerGet rg);
bool CanStandingShield();
bool CanShield();
bool CanUseProjectile();
@@ -50,18 +50,17 @@ void Settings::CreateOptionDescriptions() {
"Choose which age Link will start as.\n\n"
"Starting as adult means you start with the Master Sword in your inventory.\n"
"The child option is forcefully set if it would conflict with other options.";
mOptionDescriptions[RSK_GERUDO_FORTRESS] =
"Sets the state of the carpenters captured by Gerudo "
"in Gerudo Fortress, and with it the number of guards that spawn.\n"
"\n"
"Normal - All 4 carpenters are required to be saved.\n"
"\n"
"Fast - Only the bottom left carpenter requires rescuing.\n"
"\n"
"Free - The bridge is repaired from the 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.";
mOptionDescriptions[RSK_GERUDO_FORTRESS] = "Sets the state of the carpenters captured by Gerudo "
"in Gerudo Fortress, and with it the number of guards that spawn.\n"
"\n"
"Normal - All 4 carpenters are required to be saved.\n"
"\n"
"Fast - Only the bottom left carpenter requires rescuing.\n"
"\n"
"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.";
mOptionDescriptions[RSK_RAINBOW_BRIDGE] =
"Alters the requirements to open the bridge to Ganon's Castle.\n"
"\n"
@@ -521,6 +520,11 @@ void Settings::CreateOptionDescriptions() {
"D-pad.\n"
"\n"
"If disabled, only the Claim Check will be found in the pool.";
mOptionDescriptions[RSK_EARLY_GRANNYS_SHOP] =
"Makes Granny's Potion Shop available from start, rather than requiring Claim Check to be found first.\n"
"\n"
"This only applies when Shuffle Adult Trade is disabled. With Shuffle Adult "
"Trade enabled, Granny still requires trading the Odd Mushroom as usual.";
mOptionDescriptions[RSK_SHUFFLE_100_GS_REWARD] =
"Shuffle the item the cursed rich man in the House of Skulltula gives when you "
"have collected all 100 Gold Skulltula Tokens.\n"
@@ -151,6 +151,7 @@ RANDO_ENUM_ITEM(RSK_MASK_QUEST)
RANDO_ENUM_ITEM(RSK_SKIP_SCARECROWS_SONG)
RANDO_ENUM_ITEM(RSK_SKIP_PLANTING_BEANS)
RANDO_ENUM_ITEM(RSK_SKULLS_SUNS_SONG)
RANDO_ENUM_ITEM(RSK_EARLY_GRANNYS_SHOP)
RANDO_ENUM_ITEM(RSK_SHUFFLE_ADULT_TRADE)
RANDO_ENUM_ITEM(RSK_SHUFFLE_MERCHANTS)
RANDO_ENUM_ITEM(RSK_MERCHANT_PRICES)
@@ -1027,6 +1027,13 @@ void Settings::CreateOptions() {
OPT_BOOL(RSK_SHUFFLE_BEGGAR, "Shuffle Beggar", CVAR_RANDOMIZER_SETTING("ShuffleBeggar"), mOptionDescriptions[RSK_SHUFFLE_BEGGAR]);
OPT_BOOL(RSK_SHUFFLE_FROG_SONG_RUPEES, "Shuffle Frog Song Rupees", CVAR_RANDOMIZER_SETTING("ShuffleFrogSongRupees"), mOptionDescriptions[RSK_SHUFFLE_FROG_SONG_RUPEES]);
OPT_BOOL(RSK_SHUFFLE_ADULT_TRADE, "Shuffle Adult Trade", CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), mOptionDescriptions[RSK_SHUFFLE_ADULT_TRADE]);
OPT_CALLBACK(RSK_SHUFFLE_ADULT_TRADE, {
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), RO_GENERIC_OFF)) {
mOptions[RSK_EARLY_GRANNYS_SHOP].Disable("This has no effect when Shuffle Adult Trade is on.");
} else {
mOptions[RSK_EARLY_GRANNYS_SHOP].Enable();
}
});
OPT_U8(RSK_SHUFFLE_CHEST_MINIGAME, "Shuffle Chest Minigame", {"Off", "On (Separate)", "On (Pack)"});
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, {
@@ -1250,6 +1257,7 @@ void Settings::CreateOptions() {
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]);
OPT_BOOL(RSK_SKIP_PLANTING_BEANS, "Skip Planting Beans", CVAR_RANDOMIZER_SETTING("SkipPlantingBeans"), mOptionDescriptions[RSK_SKIP_PLANTING_BEANS]);
@@ -1747,6 +1755,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SKIP_CHILD_ZELDA],
&mOptions[RSK_MASK_QUEST],
&mOptions[RSK_SKIP_CHILD_STEALTH],
&mOptions[RSK_EARLY_GRANNYS_SHOP],
&mOptions[RSK_SKIP_PLANTING_BEANS],
&mOptions[RSK_SKIP_EPONA_RACE],
&mOptions[RSK_SKIP_SCARECROWS_SONG],