Zora's River waterfall always open, take two (#4459)

* Zora's River waterfall always open, take two

* Remove improper, redundant checks in hook

* Move all checks into update hook

* Add Randomizer setting for keeping Sleeping Waterfall open

* Change header exports to extern exports

* Remove "closed as child" option for rando setting

* Oops, missed a spot

* A bit more cleanup: simplify a redundant condition

* Unify hook handlers

* Oopsie, fix build error

* Add "play only once" option

* Force Sleeping Waterfall enhancement in rando mode

* Force enhancement only if waterfall is Open in rando

* Restore forced-open waterfall in rando

* Fix rando condition in hook

* Fix? rando entrance logic for OI

* Fix build errors
This commit is contained in:
Jordan Longstaff 2024-11-30 20:59:38 -05:00 committed by GitHub
parent ee628059d8
commit 9b74a09955
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 124 additions and 6 deletions

View File

@ -304,6 +304,7 @@ const std::vector<const char*> enhancementsCvars = {
CVAR_ENHANCEMENT("TimeSavers.SkipChildStealth"), CVAR_ENHANCEMENT("TimeSavers.SkipChildStealth"),
CVAR_ENHANCEMENT("TimeSavers.SkipTowerEscape"), CVAR_ENHANCEMENT("TimeSavers.SkipTowerEscape"),
CVAR_ENHANCEMENT("TimeSavers.SkipForcedDialog"), CVAR_ENHANCEMENT("TimeSavers.SkipForcedDialog"),
CVAR_ENHANCEMENT("TimeSavers.SleepingWaterfall"),
CVAR_ENHANCEMENT("SlowTextSpeed"), CVAR_ENHANCEMENT("SlowTextSpeed"),
}; };
@ -549,6 +550,7 @@ const std::vector<const char*> randomizerCvars = {
CVAR_RANDOMIZER_SETTING("SkipChildZelda"), CVAR_RANDOMIZER_SETTING("SkipChildZelda"),
CVAR_RANDOMIZER_SETTING("SkipEponaRace"), CVAR_RANDOMIZER_SETTING("SkipEponaRace"),
CVAR_RANDOMIZER_SETTING("SkipScarecrowsSong"), CVAR_RANDOMIZER_SETTING("SkipScarecrowsSong"),
CVAR_RANDOMIZER_SETTING("SleepingWaterfall"),
CVAR_RANDOMIZER_SETTING("StartingAge"), CVAR_RANDOMIZER_SETTING("StartingAge"),
CVAR_RANDOMIZER_SETTING("StartingBoleroOfFire"), CVAR_RANDOMIZER_SETTING("StartingBoleroOfFire"),
CVAR_RANDOMIZER_SETTING("StartingConsumables"), CVAR_RANDOMIZER_SETTING("StartingConsumables"),
@ -1175,12 +1177,13 @@ const std::vector<PresetEntry> s6PresetEntries = {
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipChildZelda"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipChildZelda"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipEponaRace"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipEponaRace"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipTowerEscape"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipTowerEscape"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SleepingWaterfall"), RO_WATERFALL_CLOSED),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingAge"), RO_AGE_RANDOM), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingAge"), RO_AGE_RANDOM),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingConsumables"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingConsumables"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingDekuShield"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingDekuShield"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingMapsCompasses"), RO_DUNGEON_ITEM_LOC_STARTWITH), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingMapsCompasses"), RO_DUNGEON_ITEM_LOC_STARTWITH),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingOcarina"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingOcarina"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), 0), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), RO_ZF_CLOSED),
}; };
const std::vector<PresetEntry> hellModePresetEntries = { const std::vector<PresetEntry> hellModePresetEntries = {
@ -1235,16 +1238,18 @@ const std::vector<PresetEntry> hellModePresetEntries = {
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipEponaRace"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipEponaRace"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipScarecrowsSong"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipScarecrowsSong"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipTowerEscape"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipTowerEscape"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SleepingWaterfall"), RO_WATERFALL_OPEN),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingAge"), RO_AGE_RANDOM), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingAge"), RO_AGE_RANDOM),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingMapsCompasses"), RO_DUNGEON_ITEM_LOC_ANYWHERE), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("StartingMapsCompasses"), RO_DUNGEON_ITEM_LOC_ANYWHERE),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SunlightArrows"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SunlightArrows"), 1),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), 2), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), RO_ZF_OPEN),
}; };
const std::vector<PresetEntry> BenchmarkPresetEntries = { const std::vector<PresetEntry> BenchmarkPresetEntries = {
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("Forest"), RO_FOREST_CLOSED_DEKU), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("Forest"), RO_FOREST_CLOSED_DEKU),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("KakarikoGate"), RO_KAK_GATE_OPEN), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("KakarikoGate"), RO_KAK_GATE_OPEN),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("DoorOfTime"), RO_DOOROFTIME_SONGONLY), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("DoorOfTime"), RO_DOOROFTIME_SONGONLY),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SleepingWaterfall"), RO_WATERFALL_CLOSED),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), RO_ZF_CLOSED), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ZorasFountain"), RO_ZF_CLOSED),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("GerudoFortress"), RO_GF_NORMAL), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("GerudoFortress"), RO_GF_NORMAL),
PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("RainbowBridge"), RO_BRIDGE_DUNGEON_REWARDS), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("RainbowBridge"), RO_BRIDGE_DUNGEON_REWARDS),

View File

@ -43,7 +43,12 @@ void RegionTable_Init_ZorasDomain() {
Entrance(RR_ZR_FAIRY_GROTTO, {[]{return Here(RR_ZORAS_RIVER, []{return logic->BlastOrSmash();});}}), Entrance(RR_ZR_FAIRY_GROTTO, {[]{return Here(RR_ZORAS_RIVER, []{return logic->BlastOrSmash();});}}),
Entrance(RR_THE_LOST_WOODS, {[]{return logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS);}}), Entrance(RR_THE_LOST_WOODS, {[]{return logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS);}}),
Entrance(RR_ZR_STORMS_GROTTO, {[]{return logic->CanOpenStormsGrotto();}}), Entrance(RR_ZR_STORMS_GROTTO, {[]{return logic->CanOpenStormsGrotto();}}),
Entrance(RR_ZR_BEHIND_WATERFALL, {[]{return logic->CanUse(RG_ZELDAS_LULLABY) || (logic->IsChild && ctx->GetTrickOption(RT_ZR_CUCCO)) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_ZR_HOVERS));}}), Entrance(RR_ZR_BEHIND_WATERFALL, {[]{
return ctx->GetOption(RSK_SLEEPING_WATERFALL).Is(RO_WATERFALL_OPEN) ||
Here(RR_ZORAS_RIVER, []{return logic->CanUse(RG_ZELDAS_LULLABY);}) ||
(logic->IsChild && ctx->GetTrickOption(RT_ZR_CUCCO)) ||
(logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_ZR_HOVERS));
}}),
}); });
areaTable[RR_ZR_BEHIND_WATERFALL] = Region("ZR Behind Waterfall", "Zora River", {RA_ZORAS_RIVER}, DAY_NIGHT_CYCLE, {}, {}, { areaTable[RR_ZR_BEHIND_WATERFALL] = Region("ZR Behind Waterfall", "Zora River", {RA_ZORAS_RIVER}, DAY_NIGHT_CYCLE, {}, {}, {

View File

@ -33,6 +33,12 @@ void Settings::CreateOptionDescriptions() {
"\n" "\n"
"Open - King Zora has already mweeped out of the way in both " "Open - King Zora has already mweeped out of the way in both "
"time periods. Ruto's Letter is removed from the item pool."; "time periods. Ruto's Letter is removed from the item pool.";
mOptionDescriptions[RSK_SLEEPING_WATERFALL] = "Closed - Sleeping Waterfall obstructs the entrance to Zora's "
"Domain. Zelda's Lullaby must be played in order to open it "
"(but only once; then it stays open in both time periods).\n"
"\n"
"Open - Sleeping Waterfall is always open. "
"Link may always enter Zora's Domain.";
mOptionDescriptions[RSK_STARTING_AGE] = mOptionDescriptions[RSK_STARTING_AGE] =
"Choose which age Link will start as.\n\n" "Choose which age Link will start as.\n\n"
"Starting as adult means you start with the Master Sword in your inventory.\n" "Starting as adult means you start with the Master Sword in your inventory.\n"

View File

@ -3947,6 +3947,7 @@ typedef enum {
RSK_KAK_GATE, RSK_KAK_GATE,
RSK_DOOR_OF_TIME, RSK_DOOR_OF_TIME,
RSK_ZORAS_FOUNTAIN, RSK_ZORAS_FOUNTAIN,
RSK_SLEEPING_WATERFALL,
RSK_STARTING_AGE, RSK_STARTING_AGE,
RSK_GERUDO_FORTRESS, RSK_GERUDO_FORTRESS,
RSK_RAINBOW_BRIDGE, RSK_RAINBOW_BRIDGE,
@ -4184,6 +4185,12 @@ typedef enum {
RO_ZF_OPEN, RO_ZF_OPEN,
} RandoOptionZorasFountain; } RandoOptionZorasFountain;
//Sleeping Waterfall settings (closed, open)
typedef enum {
RO_WATERFALL_CLOSED,
RO_WATERFALL_OPEN,
} RandoOptionSleepingWaterfall;
//Starting Age settings (child, adult, random) //Starting Age settings (child, adult, random)
typedef enum { typedef enum {
RO_AGE_CHILD, RO_AGE_CHILD,

View File

@ -109,6 +109,7 @@ void Settings::CreateOptions() {
mOptions[RSK_KAK_GATE] = Option::U8("Kakariko Gate", {"Closed", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("KakarikoGate"), mOptionDescriptions[RSK_KAK_GATE]); mOptions[RSK_KAK_GATE] = Option::U8("Kakariko Gate", {"Closed", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("KakarikoGate"), mOptionDescriptions[RSK_KAK_GATE]);
mOptions[RSK_DOOR_OF_TIME] = Option::U8("Door of Time", {"Closed", "Song only", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("DoorOfTime"), mOptionDescriptions[RSK_DOOR_OF_TIME], WidgetType::Combobox); mOptions[RSK_DOOR_OF_TIME] = Option::U8("Door of Time", {"Closed", "Song only", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("DoorOfTime"), mOptionDescriptions[RSK_DOOR_OF_TIME], WidgetType::Combobox);
mOptions[RSK_ZORAS_FOUNTAIN] = Option::U8("Zora's Fountain", {"Closed", "Closed as child", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ZorasFountain"), mOptionDescriptions[RSK_ZORAS_FOUNTAIN]); mOptions[RSK_ZORAS_FOUNTAIN] = Option::U8("Zora's Fountain", {"Closed", "Closed as child", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ZorasFountain"), mOptionDescriptions[RSK_ZORAS_FOUNTAIN]);
mOptions[RSK_SLEEPING_WATERFALL] = Option::U8("Sleeping Waterfall", {"Closed", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SleepingWaterfall"), mOptionDescriptions[RSK_SLEEPING_WATERFALL]);
mOptions[RSK_GERUDO_FORTRESS] = Option::U8("Gerudo Fortress", {"Normal", "Fast", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GerudoFortress"), mOptionDescriptions[RSK_GERUDO_FORTRESS]); mOptions[RSK_GERUDO_FORTRESS] = Option::U8("Gerudo Fortress", {"Normal", "Fast", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GerudoFortress"), mOptionDescriptions[RSK_GERUDO_FORTRESS]);
mOptions[RSK_RAINBOW_BRIDGE] = Option::U8("Rainbow Bridge", {"Vanilla", "Always open", "Stones", "Medallions", "Dungeon rewards", "Dungeons", "Tokens", "Greg"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("RainbowBridge"), mOptionDescriptions[RSK_RAINBOW_BRIDGE], WidgetType::Combobox, RO_BRIDGE_VANILLA, false, IMFLAG_NONE); mOptions[RSK_RAINBOW_BRIDGE] = Option::U8("Rainbow Bridge", {"Vanilla", "Always open", "Stones", "Medallions", "Dungeon rewards", "Dungeons", "Tokens", "Greg"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("RainbowBridge"), mOptionDescriptions[RSK_RAINBOW_BRIDGE], WidgetType::Combobox, RO_BRIDGE_VANILLA, false, IMFLAG_NONE);
mOptions[RSK_RAINBOW_BRIDGE_STONE_COUNT] = Option::U8("Stone Count", {NumOpts(0, 4)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StoneCount"), "", WidgetType::Slider, 3, true); mOptions[RSK_RAINBOW_BRIDGE_STONE_COUNT] = Option::U8("Stone Count", {NumOpts(0, 4)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StoneCount"), "", WidgetType::Slider, 3, true);
@ -696,6 +697,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_KAK_GATE], &mOptions[RSK_KAK_GATE],
&mOptions[RSK_DOOR_OF_TIME], &mOptions[RSK_DOOR_OF_TIME],
&mOptions[RSK_ZORAS_FOUNTAIN], &mOptions[RSK_ZORAS_FOUNTAIN],
&mOptions[RSK_SLEEPING_WATERFALL],
}, false, WidgetContainerType::COLUMN); }, false, WidgetContainerType::COLUMN);
mOptionGroups[RSG_WORLD_IMGUI] = OptionGroup::SubGroup("World Settings", { mOptionGroups[RSG_WORLD_IMGUI] = OptionGroup::SubGroup("World Settings", {
&mOptions[RSK_STARTING_AGE], &mOptions[RSK_STARTING_AGE],
@ -945,6 +947,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_KAK_GATE], &mOptions[RSK_KAK_GATE],
&mOptions[RSK_DOOR_OF_TIME], &mOptions[RSK_DOOR_OF_TIME],
&mOptions[RSK_ZORAS_FOUNTAIN], &mOptions[RSK_ZORAS_FOUNTAIN],
&mOptions[RSK_SLEEPING_WATERFALL],
&mOptions[RSK_GERUDO_FORTRESS], &mOptions[RSK_GERUDO_FORTRESS],
&mOptions[RSK_RAINBOW_BRIDGE], &mOptions[RSK_RAINBOW_BRIDGE],
&mOptions[RSK_RAINBOW_BRIDGE_STONE_COUNT], &mOptions[RSK_RAINBOW_BRIDGE_STONE_COUNT],
@ -1262,6 +1265,7 @@ void Settings::CreateOptions() {
{ "Open Settings:Kakariko Gate", RSK_KAK_GATE }, { "Open Settings:Kakariko Gate", RSK_KAK_GATE },
{ "Open Settings:Door of Time", RSK_DOOR_OF_TIME }, { "Open Settings:Door of Time", RSK_DOOR_OF_TIME },
{ "Open Settings:Zora's Fountain", RSK_ZORAS_FOUNTAIN }, { "Open Settings:Zora's Fountain", RSK_ZORAS_FOUNTAIN },
{ "Open Settings:Sleeping Waterfall", RSK_SLEEPING_WATERFALL },
{ "World Settings:Starting Age", RSK_STARTING_AGE }, { "World Settings:Starting Age", RSK_STARTING_AGE },
{ "Open Settings:Gerudo Fortress", RSK_GERUDO_FORTRESS }, { "Open Settings:Gerudo Fortress", RSK_GERUDO_FORTRESS },
{ "Open Settings:Rainbow Bridge", RSK_RAINBOW_BRIDGE }, { "Open Settings:Rainbow Bridge", RSK_RAINBOW_BRIDGE },
@ -2625,6 +2629,13 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) {
mOptions[index].SetContextIndex(RO_ZF_OPEN); mOptions[index].SetContextIndex(RO_ZF_OPEN);
} }
break; break;
case RSK_SLEEPING_WATERFALL:
if (it.value() == "Closed") {
mOptions[index].SetContextIndex(RO_WATERFALL_CLOSED);
} else if (it.value() == "Open") {
mOptions[index].SetContextIndex(RO_WATERFALL_OPEN);
}
break;
case RSK_STARTING_AGE: case RSK_STARTING_AGE:
if (it.value() == "Child") { if (it.value() == "Child") {
mOptions[index].SetContextIndex(RO_AGE_CHILD); mOptions[index].SetContextIndex(RO_AGE_CHILD);

View File

@ -35,6 +35,9 @@ extern SaveContext gSaveContext;
extern PlayState* gPlayState; extern PlayState* gPlayState;
extern int32_t D_8011D3AC; extern int32_t D_8011D3AC;
extern void func_808ADEF0(BgSpot03Taki* bgSpot03Taki, PlayState* play);
extern void BgSpot03Taki_ApplyOpeningAlpha(BgSpot03Taki* bgSpot03Taki, s32 bufferIndex);
extern void func_80AF36EC(EnRu2* enRu2, PlayState* play); extern void func_80AF36EC(EnRu2* enRu2, PlayState* play);
} }
@ -96,6 +99,9 @@ void EnDntDemo_JudgeSkipToReward(EnDntDemo* enDntDemo, PlayState* play) {
} }
} }
void BgSpot03Taki_KeepOpen(BgSpot03Taki* bgSpot03Taki, PlayState* play) {
}
static int successChimeCooldown = 0; static int successChimeCooldown = 0;
void RateLimitedSuccessChime() { void RateLimitedSuccessChime() {
if (successChimeCooldown == 0) { if (successChimeCooldown == 0) {
@ -692,6 +698,8 @@ static uint32_t enFuUpdateHook = 0;
static uint32_t enFuKillHook = 0; static uint32_t enFuKillHook = 0;
static uint32_t bgSpot02UpdateHook = 0; static uint32_t bgSpot02UpdateHook = 0;
static uint32_t bgSpot02KillHook = 0; static uint32_t bgSpot02KillHook = 0;
static uint32_t bgSpot03UpdateHook = 0;
static uint32_t bgSpot03KillHook = 0;
static uint32_t enPoSistersUpdateHook = 0; static uint32_t enPoSistersUpdateHook = 0;
static uint32_t enPoSistersKillHook = 0; static uint32_t enPoSistersKillHook = 0;
void TimeSaverOnActorInitHandler(void* actorRef) { void TimeSaverOnActorInitHandler(void* actorRef) {
@ -747,6 +755,10 @@ void TimeSaverOnActorInitHandler(void* actorRef) {
}); });
} }
if (actor->id == ACTOR_EN_OWL && gPlayState->sceneNum == SCENE_ZORAS_RIVER && CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SleepingWaterfall"), 0) == 2) {
Actor_Kill(actor);
}
if (actor->id == ACTOR_BG_SPOT02_OBJECTS && actor->params == 2) { if (actor->id == ACTOR_BG_SPOT02_OBJECTS && actor->params == 2) {
bgSpot02UpdateHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>([](void* innerActorRef) mutable { bgSpot02UpdateHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>([](void* innerActorRef) mutable {
Actor* innerActor = static_cast<Actor*>(innerActorRef); Actor* innerActor = static_cast<Actor*>(innerActorRef);
@ -769,6 +781,61 @@ void TimeSaverOnActorInitHandler(void* actorRef) {
}); });
} }
if (actor->id == ACTOR_BG_SPOT03_TAKI) {
bgSpot03UpdateHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>([](void* innerActorRef) mutable {
Actor* innerActor = static_cast<Actor*>(innerActorRef);
if (innerActor->id != ACTOR_BG_SPOT03_TAKI) {
return;
}
bool shouldKeepOpen;
switch (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SleepingWaterfall"), 0)) {
case 1:
shouldKeepOpen = Flags_GetEventChkInf(EVENTCHKINF_OPENED_ZORAS_DOMAIN);
break;
case 2:
if (IS_RANDO && RAND_GET_OPTION(RSK_SLEEPING_WATERFALL) == RO_WATERFALL_OPEN) {
shouldKeepOpen = true;
} else {
shouldKeepOpen = CHECK_QUEST_ITEM(QUEST_SONG_LULLABY) &&
(INV_CONTENT(ITEM_OCARINA_TIME) == ITEM_OCARINA_TIME ||
INV_CONTENT(ITEM_OCARINA_FAIRY) == ITEM_OCARINA_FAIRY);
}
break;
default:
shouldKeepOpen = false;
break;
}
if (!shouldKeepOpen) {
return;
}
BgSpot03Taki* bgSpot03 = static_cast<BgSpot03Taki*>(innerActorRef);
if (bgSpot03->actionFunc == func_808ADEF0) {
bgSpot03->actionFunc = BgSpot03Taki_KeepOpen;
bgSpot03->state = WATERFALL_OPENED;
bgSpot03->openingAlpha = 0.0f;
Flags_SetSwitch(gPlayState, bgSpot03->switchFlag);
func_8003EBF8(gPlayState, &gPlayState->colCtx.dyna, bgSpot03->dyna.bgId);
BgSpot03Taki_ApplyOpeningAlpha(bgSpot03, 0);
BgSpot03Taki_ApplyOpeningAlpha(bgSpot03, 1);
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorUpdate>(bgSpot03UpdateHook);
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnSceneInit>(bgSpot03KillHook);
bgSpot03UpdateHook = 0;
bgSpot03KillHook = 0;
}
});
bgSpot03KillHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int16_t sceneNum) mutable {
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorUpdate>(bgSpot03UpdateHook);
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnSceneInit>(bgSpot03KillHook);
bgSpot03UpdateHook = 0;
bgSpot03KillHook = 0;
});
}
if (actor->id == ACTOR_EN_DNT_DEMO && (IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO))) { if (actor->id == ACTOR_EN_DNT_DEMO && (IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO))) {
EnDntDemo* enDntDemo = static_cast<EnDntDemo*>(actorRef); EnDntDemo* enDntDemo = static_cast<EnDntDemo*>(actorRef);
enDntDemo->actionFunc = EnDntDemo_JudgeSkipToReward; enDntDemo->actionFunc = EnDntDemo_JudgeSkipToReward;

View File

@ -83,6 +83,7 @@ static const char* imguiScaleOptions[4] = { "Small", "Normal", "Large", "X-Large
static const char* chestStyleMatchesContentsOptions[4] = { "Disabled", "Both", "Texture Only", "Size Only" }; static const char* chestStyleMatchesContentsOptions[4] = { "Disabled", "Both", "Texture Only", "Size Only" };
static const char* skipGetItemAnimationOptions[3] = { "Disabled", "Junk Items", "All Items" }; static const char* skipGetItemAnimationOptions[3] = { "Disabled", "Junk Items", "All Items" };
static const char* skipForcedDialogOptions[4] = { "None", "Navi Only", "NPCs Only", "All" }; static const char* skipForcedDialogOptions[4] = { "None", "Navi Only", "NPCs Only", "All" };
static const char* sleepingWaterfallOptions[3] = { "Always", "Once", "Never" };
static const char* bunnyHoodOptions[3] = { "Disabled", "Faster Run & Longer Jump", "Faster Run" }; static const char* bunnyHoodOptions[3] = { "Disabled", "Faster Run & Longer Jump", "Faster Run" };
static const char* mirroredWorldModes[9] = { static const char* mirroredWorldModes[9] = {
"Disabled", "Always", "Random", "Random (Seeded)", "Dungeons", "Disabled", "Always", "Random", "Random (Seeded)", "Dungeons",
@ -123,7 +124,7 @@ static const char* imguiScaleOptions[4] = { "Small", "Normal", "Large", "X-Large
CVAR_ENHANCEMENT("InjectItemCounts.HeartPiece"), CVAR_ENHANCEMENT("InjectItemCounts.HeartPiece"),
CVAR_ENHANCEMENT("InjectItemCounts.HeartContainer"), CVAR_ENHANCEMENT("InjectItemCounts.HeartContainer"),
}; };
static const char* itemCountMessageOptions[sizeof(itemCountMessageCVars) / sizeof(const char*)] = { static const char* itemCountMessageOptions[ARRAY_COUNT(itemCountMessageCVars)] = {
"Gold Skulltula Tokens", "Gold Skulltula Tokens",
"Pieces of Heart", "Pieces of Heart",
"Heart Containers", "Heart Containers",
@ -796,7 +797,23 @@ void DrawEnhancementsMenu() {
UIWidgets::PaddedEnhancementCheckbox("Skip Scarecrow Song", CVAR_ENHANCEMENT("InstantScarecrow"), true, false, UIWidgets::PaddedEnhancementCheckbox("Skip Scarecrow Song", CVAR_ENHANCEMENT("InstantScarecrow"), true, false,
forceSkipScarecrow, forceSkipScarecrowText, UIWidgets::CheckboxGraphics::Checkmark); forceSkipScarecrow, forceSkipScarecrowText, UIWidgets::CheckboxGraphics::Checkmark);
UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song."); UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song.");
bool forceSleepingWaterfallEnhancement =
IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SLEEPING_WATERFALL) == RO_WATERFALL_OPEN;
uint8_t forceSleepingWaterfallValue = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SLEEPING_WATERFALL) + 1;
static const char* forceSleepingWaterfallText =
"This setting is forcefully enabled because a randomizer savefile with \"Sleeping Waterfall: Open\" is loaded.";
UIWidgets::PaddedText("Play Zelda's Lullaby to open Sleeping Waterfall", true, false);
UIWidgets::EnhancementCombobox(CVAR_ENHANCEMENT("TimeSavers.SleepingWaterfall"),
sleepingWaterfallOptions, 0, forceSleepingWaterfallEnhancement,
forceSleepingWaterfallText, forceSleepingWaterfallValue);
UIWidgets::Tooltip(
"Always: Link must always play Zelda's Lullaby to open "
"the waterfall entrance to Zora's Domain.\n"
"Once: Link only needs to play Zelda's Lullaby once to "
"open the waterfall; after that, it stays open permanently.\n"
"Never: Link never needs to play Zelda's Lullaby to open the "
"waterfall; he only needs to have learned it and have an ocarina."
);
ImGui::EndTable(); ImGui::EndTable();
ImGui::EndMenu(); ImGui::EndMenu();
@ -867,7 +884,7 @@ void DrawEnhancementsMenu() {
UIWidgets::Spacer(0); UIWidgets::Spacer(0);
if (ImGui::BeginMenu("Item Count Messages")) { if (ImGui::BeginMenu("Item Count Messages")) {
int numOptions = sizeof(itemCountMessageCVars) / sizeof(const char*); int numOptions = ARRAY_COUNT(itemCountMessageCVars);
bool allItemCountsChecked = std::all_of(itemCountMessageCVars, itemCountMessageCVars + numOptions, bool allItemCountsChecked = std::all_of(itemCountMessageCVars, itemCountMessageCVars + numOptions,
[](const char* cvar) { return CVarGetInteger(cvar, 0); }); [](const char* cvar) { return CVarGetInteger(cvar, 0); });
bool someItemCountsChecked = std::any_of(itemCountMessageCVars, itemCountMessageCVars + numOptions, bool someItemCountsChecked = std::any_of(itemCountMessageCVars, itemCountMessageCVars + numOptions,