summaryrefslogtreecommitdiff
path: root/soh
diff options
context:
space:
mode:
Diffstat (limited to 'soh')
-rw-r--r--soh/assets/custom/lang/en_US.json18
-rw-r--r--soh/assets/custom/presets/Rando Seed Settings - Advanced.json2
-rw-r--r--soh/assets/custom/presets/Rando Seed Settings - Beginner.json2
-rw-r--r--soh/assets/custom/presets/Rando Seed Settings - Standard.json2
-rw-r--r--soh/soh/Enhancements/TimeSavers/timesaver_hook_handlers.cpp3
-rw-r--r--soh/soh/Enhancements/debugger/debugSaveEditor.cpp3
-rw-r--r--soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h8
-rw-r--r--soh/soh/Enhancements/gameplaystats.cpp1
-rw-r--r--soh/soh/Enhancements/gameplaystats.h3
-rw-r--r--soh/soh/Enhancements/kaleido.cpp5
-rw-r--r--soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp4
-rw-r--r--soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp6
-rw-r--r--soh/soh/Enhancements/randomizer/3drando/item_pool.cpp4
-rw-r--r--soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp1
-rw-r--r--soh/soh/Enhancements/randomizer/Plandomizer.cpp6
-rw-r--r--soh/soh/Enhancements/randomizer/RCToRandInf.cpp1
-rw-r--r--soh/soh/Enhancements/randomizer/SeedContext.cpp2
-rw-r--r--soh/soh/Enhancements/randomizer/Traps.cpp5
-rw-r--r--soh/soh/Enhancements/randomizer/draw.cpp20
-rw-r--r--soh/soh/Enhancements/randomizer/draw.h1
-rw-r--r--soh/soh/Enhancements/randomizer/hook_handlers.cpp13
-rw-r--r--soh/soh/Enhancements/randomizer/item_list.cpp2
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp1
-rw-r--r--soh/soh/Enhancements/randomizer/location_list.cpp1
-rw-r--r--soh/soh/Enhancements/randomizer/logic.cpp7
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer.cpp4
-rw-r--r--soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerCheck.h1
-rw-r--r--soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerGet.h1
-rw-r--r--soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerHintTextKey.h2
-rw-r--r--soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h3
-rw-r--r--soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h3
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp2
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp4
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp10
-rw-r--r--soh/soh/Enhancements/randomizer/savefile.cpp3
-rw-r--r--soh/soh/Enhancements/randomizer/settings.cpp63
-rw-r--r--soh/soh/SohGui/ImGuiUtils.cpp6
-rw-r--r--soh/soh/SohGui/SohMenuEnhancements.cpp10
-rw-r--r--soh/soh/SohGui/SohMenuStartingItems.cpp14
-rw-r--r--soh/soh/config/ConfigUpdaters.cpp1
-rw-r--r--soh/src/code/code_800EC960.c3
-rw-r--r--soh/src/overlays/actors/ovl_En_Kakasi3/z_en_kakasi3.c4
42 files changed, 207 insertions, 48 deletions
diff --git a/soh/assets/custom/lang/en_US.json b/soh/assets/custom/lang/en_US.json
index f018fda10..4e9bf0c42 100644
--- a/soh/assets/custom/lang/en_US.json
+++ b/soh/assets/custom/lang/en_US.json
@@ -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"
},
diff --git a/soh/assets/custom/presets/Rando Seed Settings - Advanced.json b/soh/assets/custom/presets/Rando Seed Settings - Advanced.json
index 88cad1fe5..2ce182484 100644
--- a/soh/assets/custom/presets/Rando Seed Settings - Advanced.json
+++ b/soh/assets/custom/presets/Rando Seed Settings - Advanced.json
@@ -56,9 +56,9 @@
"ShuffleTokens": 3,
"ShuffleWeirdEgg": 2,
"SkipEponaRace": 1,
- "SkipScarecrowsSong": 1,
"StartingAge": 2,
"StartingMapsCompasses": 0,
+ "StartingScarecrowsSong": 1,
"StartingZeldasLetter": 1,
"SunlightArrows": 1
}
diff --git a/soh/assets/custom/presets/Rando Seed Settings - Beginner.json b/soh/assets/custom/presets/Rando Seed Settings - Beginner.json
index 945ce0f80..22e0eaaf9 100644
--- a/soh/assets/custom/presets/Rando Seed Settings - Beginner.json
+++ b/soh/assets/custom/presets/Rando Seed Settings - Beginner.json
@@ -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
diff --git a/soh/assets/custom/presets/Rando Seed Settings - Standard.json b/soh/assets/custom/presets/Rando Seed Settings - Standard.json
index 2ebfe4f95..d97aaeac9 100644
--- a/soh/assets/custom/presets/Rando Seed Settings - Standard.json
+++ b/soh/assets/custom/presets/Rando Seed Settings - Standard.json
@@ -49,9 +49,9 @@
"ShuffleTokens": 3,
"ShuffleWeirdEgg": 2,
"SkipEponaRace": 1,
- "SkipScarecrowsSong": 1,
"StartingMapsCompasses": 0,
"StartingOcarina": 1,
+ "StartingScarecrowsSong": 1,
"StartingZeldasLetter": 1,
"SunlightArrows": 1,
"ZorasFountain": 1
diff --git a/soh/soh/Enhancements/TimeSavers/timesaver_hook_handlers.cpp b/soh/soh/Enhancements/TimeSavers/timesaver_hook_handlers.cpp
index 7b3f150df..5ad585885 100644
--- a/soh/soh/Enhancements/TimeSavers/timesaver_hook_handlers.cpp
+++ b/soh/soh/Enhancements/TimeSavers/timesaver_hook_handlers.cpp
@@ -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;
diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp
index 35d8e5d92..36da8b07e 100644
--- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp
+++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp
@@ -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))
diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
index 19f9bfb9e..478045108 100644
--- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
+++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
@@ -1265,6 +1265,14 @@ typedef enum {
// #### `result`
// ```c
+ // !Flags_GetEventChkInf(EVENTCHKINF_PLAYED_SONG_FOR_SCARECROW_AS_ADULT)
+ // ```
+ // #### `args`
+ // - None
+ VB_GIVE_ITEM_FROM_SCARECROW,
+
+ // #### `result`
+ // ```c
// true
// ```
// #### `args`
diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp
index 8824dfa2a..d814025b0 100644
--- a/soh/soh/Enhancements/gameplaystats.cpp
+++ b/soh/soh/Enhancements/gameplaystats.cpp
@@ -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
}
diff --git a/soh/soh/Enhancements/gameplaystats.h b/soh/soh/Enhancements/gameplaystats.h
index 414ffe689..bf9d651a6 100644
--- a/soh/soh/Enhancements/gameplaystats.h
+++ b/soh/soh/Enhancements/gameplaystats.h
@@ -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 {
diff --git a/soh/soh/Enhancements/kaleido.cpp b/soh/soh/Enhancements/kaleido.cpp
index affeca7f5..ee66375f8 100644
--- a/soh/soh/Enhancements/kaleido.cpp
+++ b/soh/soh/Enhancements/kaleido.cpp
@@ -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",
diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp
index e9d5a567a..d837e9e5a 100644
--- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp
@@ -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}));
diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp
index 371163634..2a1df3385 100644
--- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp
@@ -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
{
diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp
index f7f56b9ef..53059dd80 100644
--- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp
@@ -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;
diff --git a/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp b/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp
index a873834a2..11e3527ad 100644
--- a/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp
@@ -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);
diff --git a/soh/soh/Enhancements/randomizer/Plandomizer.cpp b/soh/soh/Enhancements/randomizer/Plandomizer.cpp
index 73631e8a2..ebc5a8638 100644
--- a/soh/soh/Enhancements/randomizer/Plandomizer.cpp
+++ b/soh/soh/Enhancements/randomizer/Plandomizer.cpp
@@ -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);
}
diff --git a/soh/soh/Enhancements/randomizer/RCToRandInf.cpp b/soh/soh/Enhancements/randomizer/RCToRandInf.cpp
index 2e9077ba0..a579d6eb8 100644
--- a/soh/soh/Enhancements/randomizer/RCToRandInf.cpp
+++ b/soh/soh/Enhancements/randomizer/RCToRandInf.cpp
@@ -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 },
diff --git a/soh/soh/Enhancements/randomizer/SeedContext.cpp b/soh/soh/Enhancements/randomizer/SeedContext.cpp
index 2cd7837ef..9d3013509 100644
--- a/soh/soh/Enhancements/randomizer/SeedContext.cpp
+++ b/soh/soh/Enhancements/randomizer/SeedContext.cpp
@@ -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
diff --git a/soh/soh/Enhancements/randomizer/Traps.cpp b/soh/soh/Enhancements/randomizer/Traps.cpp
index 9ab724d81..0654479db 100644
--- a/soh/soh/Enhancements/randomizer/Traps.cpp
+++ b/soh/soh/Enhancements/randomizer/Traps.cpp
@@ -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 " } },
diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp
index b65aab0c5..334f84e8e 100644
--- a/soh/soh/Enhancements/randomizer/draw.cpp
+++ b/soh/soh/Enhancements/randomizer/draw.cpp
@@ -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);
diff --git a/soh/soh/Enhancements/randomizer/draw.h b/soh/soh/Enhancements/randomizer/draw.h
index 05958dc8f..739971098 100644
--- a/soh/soh/Enhancements/randomizer/draw.h
+++ b/soh/soh/Enhancements/randomizer/draw.h
@@ -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);
diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp
index e21bf5583..e14498097 100644
--- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp
+++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp
@@ -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;
}
diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp
index 34cac3e19..83b4c36ef 100644
--- a/soh/soh/Enhancements/randomizer/item_list.cpp
+++ b/soh/soh/Enhancements/randomizer/item_list.cpp
@@ -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);
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp
index 29d102aca..db854e734 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp
@@ -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)),
diff --git a/soh/soh/Enhancements/randomizer/location_list.cpp b/soh/soh/Enhancements/randomizer/location_list.cpp
index 0f6665067..94073a11a 100644
--- a/soh/soh/Enhancements/randomizer/location_list.cpp
+++ b/soh/soh/Enhancements/randomizer/location_list.cpp
@@ -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);
diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp
index e4d429710..a9caab725 100644
--- a/soh/soh/Enhancements/randomizer/logic.cpp
+++ b/soh/soh/Enhancements/randomizer/logic.cpp
@@ -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:
diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp
index 7ebe0b141..d6669cbe7 100644
--- a/soh/soh/Enhancements/randomizer/randomizer.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer.cpp
@@ -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
diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerCheck.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerCheck.h
index 674e3004c..884f8c68a 100644
--- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerCheck.h
+++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerCheck.h
@@ -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)
diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerGet.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerGet.h
index 4b31a2824..7d58a950e 100644
--- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerGet.h
+++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerGet.h
@@ -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)
diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerHintTextKey.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerHintTextKey.h
index b2de108d7..a17a71818 100644
--- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerHintTextKey.h
+++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerHintTextKey.h
@@ -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)
diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h
index c2994616d..76dadee6f 100644
--- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h
+++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h
@@ -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)
diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h
index 155ad6c64..7f13f4b49 100644
--- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h
+++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h
@@ -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)
diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp
index e41c74c24..c6b9920d2 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp
@@ -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
diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
index 7368c6309..67ba9cc99 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
@@ -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) ||
diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
index e0f2412b7..3962fe3c5 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
@@ -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,
diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp
index 2fb9f3060..130cbc1c0 100644
--- a/soh/soh/Enhancements/randomizer/savefile.cpp
+++ b/soh/soh/Enhancements/randomizer/savefile.cpp
@@ -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);
}
diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp
index 23c6814ee..118bf10bc 100644
--- a/soh/soh/Enhancements/randomizer/settings.cpp
+++ b/soh/soh/Enhancements/randomizer/settings.cpp
@@ -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:
diff --git a/soh/soh/SohGui/ImGuiUtils.cpp b/soh/soh/SohGui/ImGuiUtils.cpp
index a75b65c01..968f5eac8 100644
--- a/soh/soh/SohGui/ImGuiUtils.cpp
+++ b/soh/soh/SohGui/ImGuiUtils.cpp
@@ -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));
diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp
index 7d0579981..27c7f9f47 100644
--- a/soh/soh/SohGui/SohMenuEnhancements.cpp
+++ b/soh/soh/SohGui/SohMenuEnhancements.cpp
@@ -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"))
diff --git a/soh/soh/SohGui/SohMenuStartingItems.cpp b/soh/soh/SohGui/SohMenuStartingItems.cpp
index 6a6101509..fcd1015ef 100644
--- a/soh/soh/SohGui/SohMenuStartingItems.cpp
+++ b/soh/soh/SohGui/SohMenuStartingItems.cpp
@@ -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);
diff --git a/soh/soh/config/ConfigUpdaters.cpp b/soh/soh/config/ConfigUpdaters.cpp
index 2dbdfd764..4df227ab2 100644
--- a/soh/soh/config/ConfigUpdaters.cpp
+++ b/soh/soh/config/ConfigUpdaters.cpp
@@ -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 },
};
diff --git a/soh/src/code/code_800EC960.c b/soh/src/code/code_800EC960.c
index b8aa5c8bf..31fc49de4 100644
--- a/soh/src/code/code_800EC960.c
+++ b/soh/src/code/code_800EC960.c
@@ -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
diff --git a/soh/src/overlays/actors/ovl_En_Kakasi3/z_en_kakasi3.c b/soh/src/overlays/actors/ovl_En_Kakasi3/z_en_kakasi3.c
index 2f088e5f6..c1e692851 100644
--- a/soh/src/overlays/actors/ovl_En_Kakasi3/z_en_kakasi3.c
+++ b/soh/src/overlays/actors/ovl_En_Kakasi3/z_en_kakasi3.c
@@ -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);
}
}