Shuffle Scarecrow Song (#7205)

This commit is contained in:
Philip Dubé
2026-09-18 14:54:24 +00:00
committed by GitHub
parent 02c7632a33
commit a353b6e7ce
42 changed files with 207 additions and 48 deletions
+10 -8
View File
@@ -472,6 +472,13 @@
"When disabled, \"Start with Zelda's Letter\" skips child Zelda: you also get the item Impa would give."
]
},
"shuffle_scarecrows_song": {
"name": "Shuffle Scarecrow's Song",
"description": [
"Shuffles Scarecrow's Song into the item pool. Teaching Bonooru a song as child, then playing it ",
"back to him as adult, gives a random item instead."
]
},
"shuffle_gerudo_membership_card": {
"name": "Shuffle Gerudo Membership Card",
"description": [
@@ -1168,14 +1175,6 @@
"name": "Shuffle Masks",
"description": "The Happy Mask Shop never opens, masks are shuffled with the rest of the items."
},
"skip_scarecrows_song": {
"name": "Skip Scarecrow's Song",
"description": [
"Start with the ability to summon Pierre the Scarecrow. Pulling out an Ocarina in the usual locations will ",
"automatically summon him.\n",
"With \"Shuffle Ocarina Buttons\" enabled, you'll need at least two Ocarina buttons to summon him."
]
},
"skip_planting_beans": {
"name": "Skip Planting Beans",
"description": [
@@ -1826,6 +1825,9 @@
"starting_zeldas_letter": {
"name": "Start with Zelda's Letter"
},
"starting_scarecrows_song": {
"name": "Start with Scarecrow's Song"
},
"starting_claim_check": {
"name": "Start with Claim Check"
},
@@ -56,9 +56,9 @@
"ShuffleTokens": 3,
"ShuffleWeirdEgg": 2,
"SkipEponaRace": 1,
"SkipScarecrowsSong": 1,
"StartingAge": 2,
"StartingMapsCompasses": 0,
"StartingScarecrowsSong": 1,
"StartingZeldasLetter": 1,
"SunlightArrows": 1
}
@@ -36,11 +36,11 @@
"ShuffleOcarinas": 1,
"ShuffleWeirdEgg": 2,
"SkipEponaRace": 1,
"SkipScarecrowsSong": 1,
"StartingKokiriSword": 1,
"StartingBunnyHood": 1,
"StartingMapsCompasses": 0,
"StartingOcarina": 1,
"StartingScarecrowsSong": 1,
"StartingZeldasLetter": 1,
"SunlightArrows": 1,
"ZorasFountain": 1
@@ -49,9 +49,9 @@
"ShuffleTokens": 3,
"ShuffleWeirdEgg": 2,
"SkipEponaRace": 1,
"SkipScarecrowsSong": 1,
"StartingMapsCompasses": 0,
"StartingOcarina": 1,
"StartingScarecrowsSong": 1,
"StartingZeldasLetter": 1,
"SunlightArrows": 1,
"ZorasFountain": 1
@@ -896,6 +896,9 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
break;
}
case VB_SKIP_SCARECROWS_SONG: {
if (IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_SCARECROWS_SONG)) {
break;
}
if (gPlayState->msgCtx.msgMode == MSGMODE_OCARINA_PLAYING &&
CVarGetInteger(CVAR_ENHANCEMENT("InstantScarecrow"), 0) && gSaveContext.scarecrowSpawnSongSet) {
*should = true;
@@ -2132,6 +2132,7 @@ void DrawEquipmentTab() {
randomizer.GetRandoSettingValue(RSK_SHUFFLE_OPEN_CHEST) ||
randomizer.GetRandoSettingValue(RSK_SHUFFLE_SPEAK) ||
randomizer.GetRandoSettingValue(RSK_SHUFFLE_OCARINA_BUTTONS) ||
randomizer.GetRandoSettingValue(RSK_SHUFFLE_SCARECROWS_SONG) ||
randomizer.GetRandoSettingValue(RSK_ROCS_FEATHER);
if (bombchuProgressive || triforceHunt || anyAbilityShuffle) {
@@ -2216,6 +2217,8 @@ void DrawEquipmentTab() {
static_cast<RandomizerInf>(RAND_INF_HAS_OCARINA_A + i));
}
}
if (randomizer.GetRandoSettingValue(RSK_SHUFFLE_SCARECROWS_SONG))
add(RG_SCARECROWS_SONG, RAND_INF_HAS_SCARECROWS_SONG);
if (randomizer.GetRandoSettingValue(RSK_ROCS_FEATHER))
add(RG_ROCS_FEATHER, RAND_INF_OBTAINED_ROCS_FEATHER);
if (randomizer.GetRandoSettingValue(RSK_SHUFFLE_FISHING_POLE))
@@ -1263,6 +1263,14 @@ typedef enum {
// - `*EnGb`
VB_GIVE_ITEM_FROM_POE_COLLECTOR,
// #### `result`
// ```c
// !Flags_GetEventChkInf(EVENTCHKINF_PLAYED_SONG_FOR_SCARECROW_AS_ADULT)
// ```
// #### `args`
// - None
VB_GIVE_ITEM_FROM_SCARECROW,
// #### `result`
// ```c
// true
+1
View File
@@ -905,6 +905,7 @@ void SetupDisplayNames() {
strcpy(itemTimestampDisplayName[TIMESTAMP_FOUND_ZR_BEAN_SOUL], "ZR Bean Soul: ");
strcpy(itemTimestampDisplayName[TIMESTAMP_FOUND_SKELETON_KEY], "Skeleton Key: ");
strcpy(itemTimestampDisplayName[TIMESTAMP_FOUND_ROCS_FEATHER], "Roc's Feather: ");
strcpy(itemTimestampDisplayName[TIMESTAMP_FOUND_SCARECROWS_SONG], "Scarecrow's Song: ");
// clang-format on
}
+2 -1
View File
@@ -121,7 +121,8 @@ typedef enum {
/* 0xED */ TIMESTAMP_FOUND_SKELETON_KEY,
/* 0xEE */ TIMESTAMP_FOUND_ROCS_FEATHER,
/* 0xEF */ TIMESTAMP_TIMESPLITS_COMPLETED,
/* 0xF0 */ TIMESTAMP_MAX
/* 0xF0 */ TIMESTAMP_FOUND_SCARECROWS_SONG,
/* 0xF1 */ TIMESTAMP_MAX
} GameplayStatTimestamp;
typedef enum {
+5
View File
@@ -154,6 +154,11 @@ Kaleido::Kaleido() {
if (ctx->GetOption(RSK_SHUFFLE_OCARINA_BUTTONS)) {
mEntries.push_back(std::make_shared<KaleidoEntryOcarinaButtons>());
}
if (ctx->GetOption(RSK_SHUFFLE_SCARECROWS_SONG)) {
mEntries.push_back(std::make_shared<KaleidoEntryIconFlag>(
gSongNoteTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 24, Color_RGBA8{ 40, 160, 40, 255 },
FlagType::FLAG_RANDOMIZER_INF, RAND_INF_HAS_SCARECROWS_SONG, "Scarecrow's Song"));
}
if (ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS).IsNot(RO_BOSS_SOULS_OFF)) {
static const char* bossSoulNames[] = {
"Gohma's Soul", "King Dodongo's Soul", "Barinade's Soul", "Phantom Ganon's Soul",
@@ -512,6 +512,10 @@ void StaticData::HintTable_Init_Exclude_Overworld() {
/*french*/ "Selon moi, le #trésor au fond du lac# est #[[1]]#.", {QM_RED, QM_GREEN}));
// /*spanish*/ Según dicen, el #tesoro hundido del lago# se trata de #[[1]]#.
hintTextTable[RHT_LH_SCARECROWS_SONG] = HintText(CustomMessage("They say that #teaching a scarecrow a tune# is rewarded with #[[1]]#.",
/*german*/ TODO_TRANSLATE,
/*french*/ TODO_TRANSLATE, {QM_RED, QM_GREEN}));
hintTextTable[RHT_TH_FREED_CARPENTERS] = HintText(CustomMessage("They say that #rescuing captured carpenters# is rewarded with #[[1]]#.",
/*german*/ "Man erzählt sich, daß das #Retten gefangener Zimmerleute# #[[1]]# einbrächte.",
/*french*/ "Selon moi, #secourir les charpentiers capturés# assure #[[1]]#.", {QM_RED, QM_GREEN}));
@@ -2090,6 +2090,12 @@ void StaticData::HintTable_Init_Item() {
hintTextTable[RHT_MASK_GERUDO] = HintText(CustomMessage("a gerudo mask", /*german*/"!!!", /*french*/"le Masque de Gerudo"), {CustomMessage("a mask", /*german*/"!!!", /*french*/"un masque")});
hintTextTable[RHT_MASK_TRUTH] = HintText(CustomMessage("a mask of truth", /*german*/"!!!", /*french*/"le Masque de Vérité"), {CustomMessage("a mask", /*german*/"!!!", /*french*/"un masque")});
hintTextTable[RHT_SCARECROWS_SONG] = HintText(CustomMessage("Scarecrow's Song", /*german*/"das Vogelscheuchenlied", /*french*/"le chant de l'épouvantail"),
{
CustomMessage("a song", /*german*/"ein Lied", /*french*/"un chant")
}, {
CustomMessage("a scarecrow's memory", /*german*/"eine Vogelscheuchen-Erinnerung", /*french*/"un souvenir d'épouvantail")});
hintTextTable[RHT_FISHING_POLE] = HintText(CustomMessage("a fishing pole", /*german*/"eine Angelrute", /*french*/"une canne à pêche"),
// /*spanish*/caña de pescar
{
@@ -387,6 +387,10 @@ void GenerateItemPool() {
AddItemToPool(RG_ZELDAS_LETTER, 2, 1, 1, 1);
}
if (ctx->GetOption(RSK_SHUFFLE_SCARECROWS_SONG) && !ctx->GetOption(RSK_STARTING_SCARECROWS_SONG)) {
AddItemToPool(RG_SCARECROWS_SONG, 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;
@@ -120,6 +120,7 @@ void GenerateStartingInventory() {
if (ctx->GetOption(RSK_SHUFFLE_ZELDAS_LETTER)) {
AddItemToInventory(RG_ZELDAS_LETTER, ctx->GetOption(RSK_STARTING_ZELDAS_LETTER) ? 1 : 0);
}
AddItemToInventory(RG_SCARECROWS_SONG, ctx->GetOption(RSK_STARTING_SCARECROWS_SONG) ? 1 : 0);
AddItemToInventory(RG_KEATON_MASK, ctx->GetOption(RSK_STARTING_KEATON_MASK) ? 1 : 0);
AddItemToInventory(RG_SKULL_MASK, ctx->GetOption(RSK_STARTING_SKULL_MASK) ? 1 : 0);
AddItemToInventory(RG_SPOOKY_MASK, ctx->GetOption(RSK_STARTING_SPOOKY_MASK) ? 1 : 0);
@@ -415,6 +415,12 @@ void PlandomizerItemImageCorrection(Rando::Item randoItem) {
textureID = gui->GetTextureByName("ITEM_OCARINA_TIME");
}
if (randoItem.GetRandomizerGet() == RG_SCARECROWS_SONG) {
textureID = gui->GetTextureByName("RG_SCARECROWS_SONG");
imageSize = ImVec2(24.0f, 32.0f);
imagePadding = 6.0f;
}
if (textureID == 0) {
textureID = gui->GetTextureByName(itemMapping[randoItem.GetGIEntry()->itemId].name);
}
@@ -159,6 +159,7 @@ std::map<RandomizerCheck, RandomizerInf> rcToRandomizerInf = {
{ RC_LH_ADULT_FISHING, RAND_INF_ADULT_FISHING },
{ RC_MARKET_10_BIG_POES, RAND_INF_10_BIG_POES },
{ RC_KAK_100_GOLD_SKULLTULA_REWARD, RAND_INF_KAK_100_GOLD_SKULLTULA_REWARD },
{ RC_LH_SCARECROWS_SONG, RAND_INF_LH_SCARECROWS_SONG },
{ RC_KF_STORMS_GROTTO_BEEHIVE_LEFT, RAND_INF_BEEHIVE_KF_STORMS_GROTTO_LEFT },
{ RC_KF_STORMS_GROTTO_BEEHIVE_RIGHT, RAND_INF_BEEHIVE_KF_STORMS_GROTTO_RIGHT },
{ RC_LW_NEAR_SHORTCUTS_GROTTO_BEEHIVE_LEFT, RAND_INF_BEEHIVE_LW_NEAR_SHORTCUTS_GROTTO_LEFT },
@@ -172,6 +172,8 @@ 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.GetRandomizerCheck() == RC_LH_SCARECROWS_SONG &&
mOptions[RSK_SHUFFLE_SCARECROWS_SONG].Is(RO_GENERIC_OFF)) ||
(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
@@ -982,6 +982,11 @@ static void InitTrickNames() {
{ Text{ "Floating Lure", "Floating Lure", "Schwimmer" }, Text{ "a ", "un ", "einen " } },
{ Text{ "Fishing Reel", "Fishing Reel", "Angelschnur" }, Text{ "a ", "un ", "eine " } },
};
trickNameTable[RG_SCARECROWS_SONG] = {
{ Text{ "Pierre's Polka", "Polka de Pierre", "Pierres Polka" }, Text{ "", "la ", "" } },
{ Text{ "Crow's Song", "Chant du corbeau", "Krähenlied" }, Text{ "the ", "le ", "das " } },
{ Text{ "Bonooru's Ballad", "Ballade de Bonooru", "Bonoorus Ballade" }, Text{ "", "la ", "" } },
};
trickNameTable[RG_SKELETON_KEY] = {
// TODO_TRANSLATE
{ Text{ "Stalfos Key" }, Text{ "the " } }, { Text{ "Nightmare Key" }, Text{ "the " } },
+20
View File
@@ -14,6 +14,7 @@ extern "C" {
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/object_gi_compass/object_gi_compass.h"
#include "objects/object_gi_map/object_gi_map.h"
#include "objects/object_gi_melody/object_gi_melody.h"
#include "objects/object_gi_hearts/object_gi_hearts.h"
#include "objects/object_gi_rupy/object_gi_rupy.h"
#include "objects/object_gi_scale/object_gi_scale.h"
@@ -1221,6 +1222,25 @@ extern "C" void Randomizer_DrawFishingPoleGI(PlayState* play, GetItemEntry* getI
CLOSE_DISPS(play->state.gfxCtx);
}
extern "C" void Randomizer_DrawScarecrowsSong(PlayState* play, GetItemEntry* getItemEntry) {
OPEN_DISPS(play->state.gfxCtx);
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
G_MTX_MODELVIEW | G_MTX_LOAD);
// dark green note, distinct from the lighter Saria and Minuet greens
gDPSetGrayscaleColor(POLY_XLU_DISP++, 40, 160, 40, 255);
gSPGrayscale(POLY_XLU_DISP++, true);
gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gGiSongNoteDL);
gSPGrayscale(POLY_XLU_DISP++, false);
CLOSE_DISPS(play->state.gfxCtx);
}
extern "C" void Randomizer_DrawSkeletonKey(PlayState* play, GetItemEntry* getItemEntry) {
OPEN_DISPS(play->state.gfxCtx);
+1
View File
@@ -27,6 +27,7 @@ void Randomizer_DrawJabberNut(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawOpenChest(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawSilverRupee(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawFishingPoleGI(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawScarecrowsSong(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawSkeletonKey(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawMysteryItem(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawBombchuBag(PlayState* play, GetItemEntry* getItemEntry);
@@ -1932,9 +1932,18 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
break;
}
if (gPlayState->msgCtx.msgMode == MSGMODE_OCARINA_PLAYING && RAND_GET_OPTION(RSK_SKIP_SCARECROWS_SONG)) {
if (Flags_GetRandomizerInf(RAND_INF_HAS_SCARECROWS_SONG) &&
gPlayState->msgCtx.msgMode == MSGMODE_OCARINA_PLAYING) {
*should = true;
break;
} else if (RAND_GET_OPTION(RSK_SHUFFLE_SCARECROWS_SONG)) {
*should = false;
}
break;
}
case VB_GIVE_ITEM_FROM_SCARECROW: {
if (RAND_GET_OPTION(RSK_SHUFFLE_SCARECROWS_SONG)) {
Flags_SetRandomizerInf(RAND_INF_LH_SCARECROWS_SONG);
*should = false;
}
break;
}
@@ -402,6 +402,8 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_GANON_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
itemTable[RG_FISHING_POLE] = Item(RG_FISHING_POLE, Text{ "Fishing Pole", "Canne à Pêche", "Angelrute" }, ITEMTYPE_ITEM, RG_FISHING_POLE, true, LOGIC_FISHING_POLE, RHT_FISHING_POLE, RG_FISHING_POLE, OBJECT_GI_FISH, GID_FISHING_POLE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"the ", "la ", "das "});
itemTable[RG_FISHING_POLE].SetCustomDrawFunc(Randomizer_DrawFishingPoleGI);
itemTable[RG_SCARECROWS_SONG] = Item(RG_SCARECROWS_SONG, Text{ "Scarecrow's Song", "Chant de l'Épouvantail", "Vogelscheuchenlied" }, ITEMTYPE_ITEM, RG_SCARECROWS_SONG, true, LOGIC_NONE, RHT_SCARECROWS_SONG, RG_SCARECROWS_SONG, OBJECT_GI_MELODY, GID_SONG_GENERIC, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"the ", "le ", "das "});
itemTable[RG_SCARECROWS_SONG].SetCustomDrawFunc(Randomizer_DrawScarecrowsSong);
itemTable[RG_OCARINA_A_BUTTON] = Item(RG_OCARINA_A_BUTTON, Text{ "Ocarina A Button", "Touche A de l'Ocarina", "Taste A der Okarina" }, ITEMTYPE_ITEM, GI_MAP, true, LOGIC_OCARINA_A_BUTTON, RHT_OCARINA_A_BUTTON, RG_OCARINA_A_BUTTON, OBJECT_GI_MAP, GID_STONE_OF_AGONY, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"the ", "la ", "den "});
itemTable[RG_OCARINA_A_BUTTON].SetCustomDrawFunc(Randomizer_DrawOcarinaButton);
@@ -15,6 +15,7 @@ void RegionTable_Init_LakeHylia() {
}, {
//Locations
LOCATION(RC_LH_UNDERWATER_ITEM, logic->IsChild && logic->HasItem(RG_SILVER_SCALE)),
LOCATION(RC_LH_SCARECROWS_SONG, logic->Get(LOGIC_CHILD_SCARECROW) && logic->Get(LOGIC_ADULT_SCARECROW)),
LOCATION(RC_LH_SUN, logic->IsAdult && ((logic->Get(LOGIC_WATER_TEMPLE_CLEAR) && logic->HasItem(RG_BRONZE_SCALE)) || logic->ReachDistantScarecrow()) && logic->CanUse(RG_FAIRY_BOW)),
LOCATION(RC_LH_FREESTANDING_POH, logic->IsAdult && (logic->ReachScarecrow() || logic->BeanPlanted(LOGIC_PLANT_LAKE_HYLIA_BEAN)) && logic->CanAvoidEnemy(RE_GUAY, ED_CLOSE, false) && logic->HasItem(RG_CLIMB)),
LOCATION(RC_LH_GS_BEAN_PATCH, logic->CanSpawnSoilSkull(RG_LAKE_HYLIA_BEAN_SOUL) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)),
@@ -187,6 +187,7 @@ void Rando::StaticData::InitLocationTable() {
locationTable[RC_LH_LAB_DIVE] = Location::Base(RC_LH_LAB_DIVE, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_LAKESIDE_LABORATORY, 0x00, "Lab Dive", RHT_LH_LAB_DIVE, RG_PIECE_OF_HEART, SpoilerCollectionCheck::ItemGetInf(16), true);
locationTable[RC_LH_TRADE_FROG] = Location::Base(RC_LH_TRADE_FROG, RCQUEST_BOTH, RCTYPE_ADULT_TRADE, ACTOR_ID_MAX, SCENE_LAKESIDE_LABORATORY, 0x00, "Lab Trade Eyeball Frog", RHT_LH_TRADE_FROG, RG_EYEDROPS, SpoilerCollectionCheck::RandomizerInf(RAND_INF_ADULT_TRADES_LH_TRADE_FROG), true);
locationTable[RC_LH_UNDERWATER_ITEM] = Location::Base(RC_LH_UNDERWATER_ITEM, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_LAKE_HYLIA, 0x00, "Underwater Item", RHT_LH_UNDERWATER_ITEM, RG_RUTOS_LETTER, SpoilerCollectionCheck::EventChkInf(EVENTCHKINF_OBTAINED_RUTOS_LETTER), true);
locationTable[RC_LH_SCARECROWS_SONG] = Location::Base(RC_LH_SCARECROWS_SONG, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_LAKE_HYLIA, 0x00, "Scarecrow's Song", RHT_LH_SCARECROWS_SONG, RG_SCARECROWS_SONG, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LH_SCARECROWS_SONG));
locationTable[RC_LH_SUN] = Location::Base(RC_LH_SUN, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_LAKE_HYLIA, 0x00, "Sun", RHT_LH_SUN, RG_FIRE_ARROWS, SpoilerCollectionCheck::Chest(0x57, 0x1F), true);
locationTable[RC_LH_FREESTANDING_POH] = Location::Collectable(RC_LH_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_LAKE_HYLIA, 7686, 0x1E, "Freestanding PoH", RHT_LH_FREESTANDING_POH, RG_PIECE_OF_HEART, true);
locationTable[RC_LH_DEKU_SCRUB_GROTTO_LEFT] = Location::Base(RC_LH_DEKU_SCRUB_GROTTO_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LAKE_HYLIA, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x00, 0xEF), "Deku Scrub Grotto Left", RHT_LH_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_LEFT), false, 20);
+5 -2
View File
@@ -144,6 +144,7 @@ bool Logic::HasItem(RandomizerGet itemName) {
case RG_POWER_BRACELET:
case RG_CHILD_WALLET:
case RG_FISHING_POLE:
case RG_SCARECROWS_SONG:
case RG_BRONZE_SCALE:
case RG_CLIMB:
case RG_CRAWL:
@@ -1605,8 +1606,8 @@ bool Logic::HookshotOrBoomerang() {
}
bool Logic::ScarecrowsSong() {
return (ctx->GetOption(RSK_SKIP_SCARECROWS_SONG) && HasItem(RG_FAIRY_OCARINA) && OcarinaButtons() >= 2) ||
(Get(LOGIC_CHILD_SCARECROW) && Get(LOGIC_ADULT_SCARECROW));
return (HasItem(RG_SCARECROWS_SONG) && HasItem(RG_FAIRY_OCARINA) && OcarinaButtons() >= 2) ||
(!ctx->GetOption(RSK_SHUFFLE_SCARECROWS_SONG) && Get(LOGIC_CHILD_SCARECROW) && Get(LOGIC_ADULT_SCARECROW));
}
bool Logic::BlueFire() {
@@ -2029,6 +2030,7 @@ std::map<RandomizerGet, uint32_t> StaticData::RandoGetToRandInf = {
{ RG_SPEAK_KOKIRI, RAND_INF_CAN_SPEAK_KOKIRI },
{ RG_SPEAK_ZORA, RAND_INF_CAN_SPEAK_ZORA },
{ RG_FISHING_POLE, RAND_INF_FISHING_POLE_FOUND },
{ RG_SCARECROWS_SONG, RAND_INF_HAS_SCARECROWS_SONG },
{ RG_ROCS_FEATHER, RAND_INF_OBTAINED_ROCS_FEATHER },
{ RG_GUARD_HOUSE_KEY, RAND_INF_GUARD_HOUSE_KEY_OBTAINED },
{ RG_MARKET_BAZAAR_KEY, RAND_INF_MARKET_BAZAAR_KEY_OBTAINED },
@@ -2501,6 +2503,7 @@ void Logic::ApplyItemEffect(Item& item, bool state) {
case RG_SPEAK_KOKIRI:
case RG_SPEAK_ZORA:
case RG_FISHING_POLE:
case RG_SCARECROWS_SONG:
case RG_GUARD_HOUSE_KEY:
case RG_MARKET_BAZAAR_KEY:
case RG_MARKET_POTION_SHOP_KEY:
@@ -512,6 +512,8 @@ ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGe
: (gSaveContext.magicLevel < 2 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE);
case RG_FISHING_POLE:
return !Flags_GetRandomizerInf(RAND_INF_FISHING_POLE_FOUND) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE;
case RG_SCARECROWS_SONG:
return !Flags_GetRandomizerInf(RAND_INF_HAS_SCARECROWS_SONG) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE;
// Songs
case RG_ZELDAS_LULLABY:
@@ -1091,6 +1093,8 @@ static std::unordered_map<RandomizerGet, GameplayStatTimestamp> randomizerGetToS
{ RG_SKELETON_KEY, TIMESTAMP_FOUND_SKELETON_KEY },
{ RG_ROCS_FEATHER, TIMESTAMP_FOUND_ROCS_FEATHER },
{ RG_SCARECROWS_SONG, TIMESTAMP_FOUND_SCARECROWS_SONG },
};
// Gameplay stat tracking: Update time the item was acquired
@@ -277,6 +277,7 @@ RANDO_ENUM_ITEM(RC_ZF_GS_ABOVE_THE_LOG)
RANDO_ENUM_ITEM(RC_ZF_GS_TREE)
RANDO_ENUM_ITEM(RC_ZF_GS_HIDDEN_CAVE)
RANDO_ENUM_ITEM(RC_LH_UNDERWATER_ITEM)
RANDO_ENUM_ITEM(RC_LH_SCARECROWS_SONG)
RANDO_ENUM_ITEM(RC_LH_CHILD_FISHING)
RANDO_ENUM_ITEM(RC_LH_CHILD_FISH_1)
RANDO_ENUM_ITEM(RC_LH_CHILD_FISH_2)
@@ -255,6 +255,7 @@ RANDO_ENUM_ITEM(RG_OCARINA_C_LEFT_BUTTON)
RANDO_ENUM_ITEM(RG_OCARINA_C_RIGHT_BUTTON)
RANDO_ENUM_ITEM(RG_SKELETON_KEY)
RANDO_ENUM_ITEM(RG_FISHING_POLE)
RANDO_ENUM_ITEM(RG_SCARECROWS_SONG)
RANDO_ENUM_ITEM(RG_DEKU_STICK_BAG)
RANDO_ENUM_ITEM(RG_DEKU_NUT_BAG)
RANDO_ENUM_ITEM(RG_HINT)
@@ -362,6 +362,7 @@ RANDO_ENUM_ITEM(RHT_ZF_GS_ABOVE_THE_LOG)
RANDO_ENUM_ITEM(RHT_ZF_GS_TREE)
RANDO_ENUM_ITEM(RHT_ZF_GS_HIDDEN_CAVE)
RANDO_ENUM_ITEM(RHT_LH_UNDERWATER_ITEM)
RANDO_ENUM_ITEM(RHT_LH_SCARECROWS_SONG)
RANDO_ENUM_ITEM(RHT_LH_CHILD_FISHING)
RANDO_ENUM_ITEM(RHT_LH_ADULT_FISHING)
RANDO_ENUM_ITEM(RHT_LH_POND_FISH)
@@ -1079,6 +1080,7 @@ RANDO_ENUM_ITEM(RHT_CRAWL)
RANDO_ENUM_ITEM(RHT_SPEAK)
RANDO_ENUM_ITEM(RHT_OPEN_CHEST)
RANDO_ENUM_ITEM(RHT_FISHING_POLE)
RANDO_ENUM_ITEM(RHT_SCARECROWS_SONG)
RANDO_ENUM_ITEM(RHT_SKELETON_KEY)
RANDO_ENUM_ITEM(RHT_SILVER_RUPEE_DODONGOS_CAVERN)
RANDO_ENUM_ITEM(RHT_SILVER_RUPEE_SHADOW_TEMPLE)
@@ -155,6 +155,8 @@ RANDO_ENUM_ITEM(RAND_INF_ADULT_TRADES_DMT_TRADE_CLAIM_CHECK)
RANDO_ENUM_ITEM(RAND_INF_KAK_100_GOLD_SKULLTULA_REWARD)
RANDO_ENUM_ITEM(RAND_INF_LH_SCARECROWS_SONG)
RANDO_ENUM_ITEM(RAND_INF_GREG_FOUND)
RANDO_ENUM_ITEM(RAND_INF_TOT_MASTER_SWORD)
@@ -1499,6 +1501,7 @@ RANDO_ENUM_ITEM(RAND_INF_GROTTO_FISH_LW_NEAR_SHORTCUTS_GROTTO)
RANDO_ENUM_ITEM(RAND_INF_GROTTO_FISH_KF_STORMS_GROTTO)
RANDO_ENUM_ITEM(RAND_INF_FISHING_POLE_FOUND)
RANDO_ENUM_ITEM(RAND_INF_HAS_SCARECROWS_SONG)
RANDO_ENUM_ITEM(RAND_INF_ZD_FISH_1)
RANDO_ENUM_ITEM(RAND_INF_ZD_FISH_2)
@@ -93,6 +93,7 @@ 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_SCARECROWS_SONG)
RANDO_ENUM_ITEM(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)
RANDO_ENUM_ITEM(RSK_SHUFFLE_POTS)
RANDO_ENUM_ITEM(RSK_SHUFFLE_CRATES)
@@ -177,6 +178,7 @@ 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_SCARECROWS_SONG)
RANDO_ENUM_ITEM(RSK_STARTING_CLAIM_CHECK)
RANDO_ENUM_ITEM(RSK_STARTING_GERUDO_CARD)
RANDO_ENUM_ITEM(RSK_STARTING_BIGGORON_SWORD)
@@ -185,7 +187,6 @@ RANDO_ENUM_ITEM(RSK_SHUFFLE_CHEST_MINIGAME)
RANDO_ENUM_ITEM(RSK_BIG_POE_COUNT)
RANDO_ENUM_ITEM(RSK_SKIP_EPONA_RACE)
RANDO_ENUM_ITEM(RSK_SHUFFLE_MASKS)
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)
@@ -157,6 +157,8 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() {
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleOcarinas"), RO_GENERIC_NO)) && // ocarina locations
(location.GetRandomizerCheck() != RC_HC_ZELDAS_LETTER ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleZeldasLetter"), RO_GENERIC_NO)) &&
(location.GetRandomizerCheck() != RC_LH_SCARECROWS_SONG ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleScarecrowsSong"), 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
@@ -112,6 +112,7 @@ bool showBossKeysanity;
bool showGanonBossKey;
bool showOcarinas;
bool show100SkullReward;
bool showScarecrowsSong;
bool showLinksPocket;
bool showChestMinigame;
bool fortressFast;
@@ -1653,6 +1654,8 @@ void LoadSettings() {
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;
showScarecrowsSong = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(
RSK_SHUFFLE_SCARECROWS_SONG) == 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;
@@ -1970,6 +1973,7 @@ bool IsCheckShuffled(RandomizerCheck rc) {
(loc->GetRCType() != RCTYPE_BOSS_KEY || showBossKeysanity) &&
(loc->GetRCType() != RCTYPE_GANON_BOSS_KEY || showGanonBossKey) &&
(rc != RC_KAK_100_GOLD_SKULLTULA_REWARD || show100SkullReward) &&
(rc != RC_LH_SCARECROWS_SONG || showScarecrowsSong) &&
(loc->GetRCType() != RCTYPE_GF_KEY && rc != RC_TH_FREED_CARPENTERS ||
(showGerudoCard && rc == RC_TH_FREED_CARPENTERS) ||
(fortressNormal && showGerudoFortressKeys && loc->GetRCType() == RCTYPE_GF_KEY) ||
@@ -176,6 +176,10 @@ std::vector<ItemTrackerItem> openChestItems = {
ITEM_TRACKER_RG(RG_OPEN_CHEST, "", 0, DrawItem),
};
std::vector<ItemTrackerItem> scarecrowsSongItems = {
ITEM_TRACKER_RG(RG_SCARECROWS_SONG, "", 0, DrawItem),
};
std::vector<ItemTrackerItem> beanSoulItems = {
ITEM_TRACKER_RG_CUSTOM(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, "DMC", ITEM_BEAN, 0, DrawItem),
ITEM_TRACKER_RG_CUSTOM(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, "DMT", ITEM_BEAN, 0, DrawItem),
@@ -1198,6 +1202,9 @@ void DrawItem(ItemTrackerItem item) {
case RG_OPEN_CHEST:
itemName = "Open";
break;
case RG_SCARECROWS_SONG:
itemName = "Scarecrow's Song";
break;
}
} else if (item.kind == ITEM_KIND_DUMMY) {
if (item.id == ITEMTYPE_SILVER) {
@@ -1622,6 +1629,9 @@ void UpdateVectors() {
if (IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_OPEN_CHEST)) {
mainWindowItems.insert(mainWindowItems.end(), openChestItems.begin(), openChestItems.end());
}
if (IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_SCARECROWS_SONG)) {
mainWindowItems.insert(mainWindowItems.end(), scarecrowsSongItems.begin(), scarecrowsSongItems.end());
}
// if we're adding greg to the misc window,
// and misc isn't on the main window,
@@ -344,6 +344,9 @@ void SetStartingItems() {
Randomizer_GetSettingValue(RSK_SHUFFLE_ZELDAS_LETTER)) {
Item_Give(NULL, ITEM_LETTER_ZELDA);
}
if (Randomizer_GetSettingValue(RSK_STARTING_SCARECROWS_SONG)) {
Flags_SetRandomizerInf(RAND_INF_HAS_SCARECROWS_SONG);
}
if (Randomizer_GetSettingValue(RSK_STARTING_CLAIM_CHECK)) {
Item_Give(NULL, ITEM_CLAIM_CHECK);
}
+42 -21
View File
@@ -858,6 +858,7 @@ void Settings::CreateOptions() {
OPT_U8(RSK_SHUFFLE_OPEN_CHEST, {"Off", "On", "Progressive"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleOpenChest"), WIDGET_CVAR_COMBOBOX, RO_OPEN_CHEST_OFF);
OPT_U8(RSK_SHUFFLE_WEIRD_EGG, {"Vanilla", "Shuffled", "Skip Waking Talon"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), WIDGET_CVAR_COMBOBOX, RO_WEIRD_EGG_VANILLA);
OPT_BOOL(RSK_SHUFFLE_ZELDAS_LETTER, CVAR_RANDOMIZER_SETTING("ShuffleZeldasLetter"));
OPT_BOOL(RSK_SHUFFLE_SCARECROWS_SONG, CVAR_RANDOMIZER_SETTING("ShuffleScarecrowsSong"));
OPT_BOOL(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD, CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"));
OPT_U8(RSK_SHUFFLE_POTS, {"Off", "Dungeons", "Overworld", "All Pots"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShufflePots"), WIDGET_CVAR_COMBOBOX, RO_SHUFFLE_POTS_OFF);
OPT_U8(RSK_SHUFFLE_GRASS, {"Off", "Dungeons", "Overworld", "All Grass"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleGrass"), WIDGET_CVAR_COMBOBOX, RO_SHUFFLE_GRASS_OFF);
@@ -1341,7 +1342,6 @@ void Settings::CreateOptions() {
OPT_BOOL(RSK_SKIP_CHILD_STEALTH, {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipChildStealth"), WIDGET_CVAR_CHECKBOX, RO_GENERIC_DONT_SKIP);
OPT_BOOL(RSK_EARLY_GRANNYS_SHOP, CVAR_RANDOMIZER_SETTING("EarlyGrannysShop"));
OPT_BOOL(RSK_SKIP_EPONA_RACE, {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipEponaRace"), WIDGET_CVAR_CHECKBOX, RO_GENERIC_DONT_SKIP);
OPT_BOOL(RSK_SKIP_SCARECROWS_SONG, CVAR_RANDOMIZER_SETTING("SkipScarecrowsSong"));
OPT_BOOL(RSK_SKIP_PLANTING_BEANS, CVAR_RANDOMIZER_SETTING("SkipPlantingBeans"));
OPT_U8(RSK_BIG_POE_COUNT, {NumOpts(0, 10)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("BigPoeTargetCount"), WIDGET_CVAR_SLIDER_INT, 10);
OPT_CALLBACK(RSK_BIG_POE_COUNT, {
@@ -1446,6 +1446,7 @@ void Settings::CreateOptions() {
OPT_U8(RSK_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, CVAR_RANDOMIZER_SETTING("StartingWeirdEgg"));
OPT_BOOL(RSK_STARTING_ZELDAS_LETTER, CVAR_RANDOMIZER_SETTING("StartingZeldasLetter"));
OPT_BOOL(RSK_STARTING_SCARECROWS_SONG, CVAR_RANDOMIZER_SETTING("StartingScarecrowsSong"));
OPT_BOOL(RSK_STARTING_CLAIM_CHECK, CVAR_RANDOMIZER_SETTING("StartingClaimCheck"));
OPT_BOOL(RSK_STARTING_GERUDO_CARD, CVAR_RANDOMIZER_SETTING("StartingGerudoCard"));
OPT_BOOL(RSK_STARTING_KEATON_MASK, CVAR_RANDOMIZER_SETTING("StartingKeatonMask"));
@@ -1886,7 +1887,6 @@ void Settings::CreateOptions() {
&mOptions[RSK_EARLY_GRANNYS_SHOP],
&mOptions[RSK_SKIP_PLANTING_BEANS],
&mOptions[RSK_SKIP_EPONA_RACE],
&mOptions[RSK_SKIP_SCARECROWS_SONG],
},
WidgetContainerType::SECTION);
mOptionGroups[RSG_MENU_SECTION_WINCON] = OptionGroup::SubGroup("Win Condition",
@@ -2022,24 +2022,43 @@ void Settings::CreateOptions() {
mOptionGroups[RSG_MENU_SECTION_BASIC_SHUFFLES] =
OptionGroup::SubGroup("Shuffle Items",
{
&mOptions[RSK_SHUFFLE_SONGS], &mOptions[RSK_SHUFFLE_TOKENS],
&mOptions[RSK_SHUFFLE_KOKIRI_SWORD], &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_SHUFFLE_MASKS], &mOptions[RSK_FISHSANITY],
&mOptions[RSK_FISHSANITY_POND_COUNT], &mOptions[RSK_FISHSANITY_AGE_SPLIT],
&mOptions[RSK_SHUFFLE_FREESTANDING], &mOptions[RSK_SHUFFLE_WONDER_ITEMS],
&mOptions[RSK_SHUFFLE_SILVER], &mOptions[RSK_SHUFFLE_BEEHIVES],
&mOptions[RSK_SHUFFLE_COWS], &mOptions[RSK_SHUFFLE_POTS],
&mOptions[RSK_SHUFFLE_GRASS], &mOptions[RSK_SHUFFLE_CRATES],
&mOptions[RSK_SHUFFLE_BOULDERS], &mOptions[RSK_SHUFFLE_ROCKS],
&mOptions[RSK_SHUFFLE_TREES], &mOptions[RSK_SHUFFLE_BUSHES],
&mOptions[RSK_SHUFFLE_ICICLES], &mOptions[RSK_SHUFFLE_RED_ICE],
&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], &mOptions[RSK_SHUFFLE_BEAN_FAIRIES],
&mOptions[RSK_SHUFFLE_SONG_FAIRIES], &mOptions[RSK_SHUFFLE_BUTTERFLY_FAIRIES],
&mOptions[RSK_SHUFFLE_SONGS],
&mOptions[RSK_SHUFFLE_TOKENS],
&mOptions[RSK_SHUFFLE_KOKIRI_SWORD],
&mOptions[RSK_SHUFFLE_MASTER_SWORD],
&mOptions[RSK_SHUFFLE_OCARINA],
&mOptions[RSK_SHUFFLE_WEIRD_EGG],
&mOptions[RSK_SHUFFLE_ZELDAS_LETTER],
&mOptions[RSK_SHUFFLE_SCARECROWS_SONG],
&mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD],
&mOptions[RSK_SHUFFLE_MASKS],
&mOptions[RSK_FISHSANITY],
&mOptions[RSK_FISHSANITY_POND_COUNT],
&mOptions[RSK_FISHSANITY_AGE_SPLIT],
&mOptions[RSK_SHUFFLE_FREESTANDING],
&mOptions[RSK_SHUFFLE_WONDER_ITEMS],
&mOptions[RSK_SHUFFLE_SILVER],
&mOptions[RSK_SHUFFLE_BEEHIVES],
&mOptions[RSK_SHUFFLE_COWS],
&mOptions[RSK_SHUFFLE_POTS],
&mOptions[RSK_SHUFFLE_GRASS],
&mOptions[RSK_SHUFFLE_CRATES],
&mOptions[RSK_SHUFFLE_BOULDERS],
&mOptions[RSK_SHUFFLE_ROCKS],
&mOptions[RSK_SHUFFLE_TREES],
&mOptions[RSK_SHUFFLE_BUSHES],
&mOptions[RSK_SHUFFLE_ICICLES],
&mOptions[RSK_SHUFFLE_RED_ICE],
&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],
&mOptions[RSK_SHUFFLE_BEAN_FAIRIES],
&mOptions[RSK_SHUFFLE_SONG_FAIRIES],
&mOptions[RSK_SHUFFLE_BUTTERFLY_FAIRIES],
},
WidgetContainerType::SECTION);
mOptionGroups[RSG_MENU_COLUMN_BASIC_SHUFFLES] =
@@ -2277,6 +2296,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_OPEN_CHEST],
&mOptions[RSK_SHUFFLE_WEIRD_EGG],
&mOptions[RSK_SHUFFLE_ZELDAS_LETTER],
&mOptions[RSK_SHUFFLE_SCARECROWS_SONG],
&mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD],
&mOptions[RSK_SHUFFLE_MASKS],
&mOptions[RSK_SHUFFLE_MERCHANTS],
@@ -2391,6 +2411,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_STARTING_REQUIEM_OF_SPIRIT],
&mOptions[RSK_STARTING_NOCTURNE_OF_SHADOW],
&mOptions[RSK_STARTING_PRELUDE_OF_LIGHT],
&mOptions[RSK_STARTING_SCARECROWS_SONG],
});
mOptionGroups[RSG_STARTING_OTHER] = OptionGroup::SubGroup("Other", {
&mOptions[RSK_STARTING_STICKS],
@@ -2409,7 +2430,6 @@ void Settings::CreateOptions() {
OptionGroupType::DEFAULT);
mOptionGroups[RSG_TIMESAVERS] = OptionGroup("Timesaver Settings", {
&mOptions[RSK_SKIP_EPONA_RACE],
&mOptions[RSK_SKIP_SCARECROWS_SONG],
&mOptions[RSK_SKIP_PLANTING_BEANS],
&mOptions[RSK_BIG_POE_COUNT],
});
@@ -3159,6 +3179,7 @@ void Settings::RandomizeAllSettings() {
case RSK_STARTING_BOTTLE_4:
case RSK_STARTING_WEIRD_EGG:
case RSK_STARTING_ZELDAS_LETTER:
case RSK_STARTING_SCARECROWS_SONG:
case RSK_STARTING_CLAIM_CHECK:
case RSK_STARTING_GERUDO_CARD:
case RSK_STARTING_BIGGORON_SWORD:
+6
View File
@@ -250,6 +250,12 @@ void RegisterImGuiItemIcons() {
gui->LoadGuiTexture("ITEM_RUPEE_SILVER", gRupeeCounterIconTex, "", silver);
gui->LoadGuiTexture("ITEM_RUPEE_SILVER_Faded", gRupeeCounterIconTex, "", silverFaded);
ImVec4 scarecrow = ImVec4(40.0f / 255.0f, 160.0f / 255.0f, 40.0f / 255.0f, 1.0f);
ImVec4 scarecrowFaded = scarecrow;
scarecrowFaded.w = 0.3f;
gui->LoadGuiTexture("RG_SCARECROWS_SONG", gSongNoteTex, "", scarecrow);
gui->LoadGuiTexture("RG_SCARECROWS_SONG_Faded", gSongNoteTex, "", scarecrowFaded);
for (const auto& entry : questMapping) {
gui->LoadGuiTexture(entry.second.name, entry.second.texturePath, "", ImVec4(1, 1, 1, 1));
gui->LoadGuiTexture(entry.second.nameFaded, entry.second.texturePath, "", ImVec4(1, 1, 1, 0.3f));
+6 -4
View File
@@ -601,13 +601,15 @@ void SohMenu::AddMenuEnhancements() {
.CVar(CVAR_ENHANCEMENT("InstantScarecrow"))
.PreFunc([](WidgetInfo& info) {
info.options->disabled =
IS_RANDO && OTRGlobals::Instance->gRandoContext->GetOption(RSK_SKIP_SCARECROWS_SONG);
info.options->disabledTooltip = "This setting is forcefully enabled because a randomized save "
"file with the option \"Skip Scarecrow's Song\" is currently loaded.";
IS_RANDO && (OTRGlobals::Instance->gRandoContext->GetOption(RSK_STARTING_SCARECROWS_SONG) ||
OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_SCARECROWS_SONG));
info.options->disabledTooltip =
"This setting is controlled by the randomizer because a randomized save file with the option "
"\"Start with Scarecrow's Song\" or \"Shuffle Scarecrow's Song\" is currently loaded.";
})
.Options(CheckboxOptions().Tooltip(
"Pierre appears when an Ocarina is pulled out. Requires learning the Scarecrow's Song first.\n"
"Without the randomizer option \"Skip Scarecrow's Song\" enabled for a seed, this still requires you "
"Without the randomizer option \"Start with Scarecrow's Song\" enabled for a seed, this still requires you "
"to teach the scarecrow the song as both ages before summoning."));
AddWidget(path, "Faster Rupee Accumulator", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("FasterRupeeAccumulator"))
+10 -4
View File
@@ -93,16 +93,15 @@ static void StartingItemTiered(RandomizerSettingKey rsk, const std::vector<uint3
}
// Toggleable 32x48 song icon, mirroring the songMapping loop in DrawQuestStatusTab.
static void StartingSongToggle(RandomizerSettingKey rsk, QuestItem song) {
static void StartingSongToggle(RandomizerSettingKey rsk, const std::string& name, const std::string& nameFaded) {
Rando::Option& option = Rando::Settings::GetInstance()->GetOption(rsk);
const char* cvar = option.GetCVarName().c_str();
const SongMapEntry& entry = songMapping[song];
bool on = CVarGetInteger(cvar, 0) != 0;
ImGui::PushID(static_cast<int32_t>(rsk));
PushStyleButton(Colors::DarkGray);
if (ImGui::ImageButton(entry.name.c_str(), GetFast3dGui()->GetTextureByName(on ? entry.name : entry.nameFaded),
kSongSize, ImVec2(0, 0), ImVec2(1, 1))) {
if (ImGui::ImageButton(name.c_str(), GetFast3dGui()->GetTextureByName(on ? name : nameFaded), kSongSize,
ImVec2(0, 0), ImVec2(1, 1))) {
CVarSetInteger(cvar, on ? 0 : 1);
SaveStartingItemCVars();
}
@@ -111,6 +110,11 @@ static void StartingSongToggle(RandomizerSettingKey rsk, QuestItem song) {
ImGui::PopID();
}
static void StartingSongToggle(RandomizerSettingKey rsk, QuestItem song) {
const SongMapEntry& entry = songMapping[song];
StartingSongToggle(rsk, entry.name, entry.nameFaded);
}
// Item icon followed by a count slider, like the ammo rows in DrawInventoryTab. The slider
// mirrors the Option's own semantics: the CVar stores the option index and the displayed
// number comes from the option text (matching how WIDGET_CVAR_SLIDER_INT renders these).
@@ -352,6 +356,8 @@ void DrawStartingItemsMenu(WidgetInfo& info) {
StartingSongToggle(RSK_STARTING_NOCTURNE_OF_SHADOW, QUEST_SONG_NOCTURNE);
ImGui::SameLine();
StartingSongToggle(RSK_STARTING_PRELUDE_OF_LIGHT, QUEST_SONG_PRELUDE);
ImGui::SameLine();
StartingSongToggle(RSK_STARTING_SCARECROWS_SONG, "RG_SCARECROWS_SONG", "RG_SCARECROWS_SONG_Faded");
ImGui::SeparatorText("Other");
StartingItemCombobox(RSK_LINKS_POCKET);
+1
View File
@@ -1459,6 +1459,7 @@ static const Migration version7Migrations[] = {
{ "gRandoEnhancements.CustomKeyModels", nullptr },
{ "gRandoSettings.LogicRules", "gRandoSettings.NoLogic" },
{ "gRandoSettings.AllLocationsReachable", "gRandoSettings.AllChecksReachable" },
{ "gRandoSettings.SkipScarecrowsSong", "gRandoSettings.StartingScarecrowsSong" },
{ nullptr, nullptr },
};
+2 -1
View File
@@ -2090,7 +2090,8 @@ void AudioOcarina_PlaybackSong(void) {
}
return;
} else {
sPlaybackNoteTimer -= nextNoteTimerStep;
// SoH [Fix] several audio tasks can run between updates, don't wrap below zero
sPlaybackNoteTimer -= MIN(nextNoteTimerStep, sPlaybackNoteTimer);
}
// Update volume
@@ -7,6 +7,7 @@
#include "z_en_kakasi3.h"
#include "vt.h"
#include "objects/object_ka/object_ka.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#define FLAGS (ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_UPDATE_DURING_OCARINA)
@@ -387,7 +388,8 @@ void func_80A91A90(EnKakasi3* this, PlayState* play) {
if (this->dialogState == Message_GetState(&play->msgCtx) && Message_ShouldAdvance(play)) {
if (this->unk_195) {
if (!Flags_GetEventChkInf(EVENTCHKINF_PLAYED_SONG_FOR_SCARECROW_AS_ADULT)) {
if (GameInteractor_Should(VB_GIVE_ITEM_FROM_SCARECROW,
!Flags_GetEventChkInf(EVENTCHKINF_PLAYED_SONG_FOR_SCARECROW_AS_ADULT))) {
Flags_SetEventChkInf(EVENTCHKINF_PLAYED_SONG_FOR_SCARECROW_AS_ADULT);
}
}