diff --git a/soh/soh/Enhancements/TimeSavers/FasterHeavyBlockLift.cpp b/soh/soh/Enhancements/TimeSavers/FasterHeavyBlockLift.cpp index 97c253073..05a98fd80 100644 --- a/soh/soh/Enhancements/TimeSavers/FasterHeavyBlockLift.cpp +++ b/soh/soh/Enhancements/TimeSavers/FasterHeavyBlockLift.cpp @@ -1,7 +1,5 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" -#include "spdlog/spdlog.h" +#include "soh/ShipInit.hpp" extern "C" { #include "z64save.h" @@ -12,29 +10,29 @@ extern PlayState* gPlayState; extern SaveContext gSaveContext; } +#define CVAR_BLOCKLIFT_NAME CVAR_ENHANCEMENT("FasterHeavyBlockLift") +#define CVAR_BLOCKLIFT_VALUE CVarGetInteger(CVAR_BLOCKLIFT_NAME, 0) + +#define CVAR_SKIP_CUTSCENE_NAME CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint") +#define CVAR_SKIP_CUTSCENE_VALUE CVarGetInteger(CVAR_SKIP_CUTSCENE_NAME, IS_RANDO) + /** * This primarily handles speeding up the heavy block lifts (OGC and in the Fire Trial) but also handles skipping * the one point cutscene since the two options are so similar in what they do. */ -void FasterHeavyBlockLift_Register() { - REGISTER_VB_SHOULD(VB_PLAY_ONEPOINT_ACTOR_CS, { +void RegisterFasterHeavyBlockLift() { + COND_VB_SHOULD(VB_PLAY_ONEPOINT_ACTOR_CS, CVAR_BLOCKLIFT_VALUE || CVAR_SKIP_CUTSCENE_VALUE, { Actor* actor = va_arg(args, Actor*); - if (actor->id == ACTOR_BG_HEAVY_BLOCK && - (CVarGetInteger(CVAR_ENHANCEMENT("FasterHeavyBlockLift"), 0) || - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint"), IS_RANDO))) { + if (actor->id == ACTOR_BG_HEAVY_BLOCK) { *should = false; } }); - REGISTER_VB_SHOULD(VB_FREEZE_LINK_FOR_BLOCK_THROW, { - if (CVarGetInteger(CVAR_ENHANCEMENT("FasterHeavyBlockLift"), 0) || - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint"), IS_RANDO)) { - *should = false; - } - }); + COND_VB_SHOULD(VB_FREEZE_LINK_FOR_BLOCK_THROW, CVAR_BLOCKLIFT_VALUE || CVAR_SKIP_CUTSCENE_VALUE, + { *should = false; }); - REGISTER_VB_SHOULD(VB_PLAY_THROW_ANIMATION, { + COND_VB_SHOULD(VB_PLAY_THROW_ANIMATION, CVAR_BLOCKLIFT_VALUE, { Player* player = GET_PLAYER(gPlayState); Actor* interactRangeActor = player->interactRangeActor; s32 interactActorId = interactRangeActor->id; @@ -42,18 +40,17 @@ void FasterHeavyBlockLift_Register() { // Same actor is used for small and large silver rocks, use actor params to identify large ones bool isLargeSilverRock = (interactActorId == ACTOR_EN_ISHI) && ((interactRangeActor->params & 1) == 1); - if (CVarGetInteger(CVAR_ENHANCEMENT("FasterHeavyBlockLift"), 0) && - (isLargeSilverRock || interactActorId == ACTOR_BG_HEAVY_BLOCK)) { + if (isLargeSilverRock || interactActorId == ACTOR_BG_HEAVY_BLOCK) { *should = false; LinkAnimation_PlayOnceSetSpeed(gPlayState, &player->skelAnime, anim, 5.0f); } }); - REGISTER_VB_SHOULD(VB_MOVE_THROWN_ACTOR, { - if (CVarGetInteger(CVAR_ENHANCEMENT("FasterHeavyBlockLift"), 0)) { - Actor* heldActor = va_arg(args, Actor*); + COND_VB_SHOULD(VB_MOVE_THROWN_ACTOR, CVAR_BLOCKLIFT_VALUE, { + Actor* heldActor = va_arg(args, Actor*); - heldActor->shape.rot.x -= 3510; - } + heldActor->shape.rot.x -= 3510; }); } + +static RegisterShipInitFunc initFunc(RegisterFasterHeavyBlockLift, { CVAR_BLOCKLIFT_NAME, CVAR_SKIP_CUTSCENE_NAME }); diff --git a/soh/soh/Enhancements/TimeSavers/FasterRupeeAccumulator.cpp b/soh/soh/Enhancements/TimeSavers/FasterRupeeAccumulator.cpp index 36a780b6a..5fcfb0d26 100644 --- a/soh/soh/Enhancements/TimeSavers/FasterRupeeAccumulator.cpp +++ b/soh/soh/Enhancements/TimeSavers/FasterRupeeAccumulator.cpp @@ -1,7 +1,5 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" -#include "spdlog/spdlog.h" +#include "soh/ShipInit.hpp" extern "C" { #include "z64save.h" @@ -12,11 +10,8 @@ extern PlayState* gPlayState; extern SaveContext gSaveContext; } -void FasterRupeeAccumulator_Register() { - GameInteractor::Instance->RegisterGameHook([]() { - if (!CVarGetInteger(CVAR_ENHANCEMENT("FasterRupeeAccumulator"), 0)) - return; - +void RegisterFasterRupeeAccumulator() { + COND_HOOK(OnInterfaceUpdate, CVarGetInteger(CVAR_ENHANCEMENT("FasterRupeeAccumulator"), 0), []() { if (gSaveContext.rupeeAccumulator == 0) { return; } @@ -46,3 +41,5 @@ void FasterRupeeAccumulator_Register() { } }); } + +static RegisterShipInitFunc initFunc(RegisterFasterRupeeAccumulator, { CVAR_ENHANCEMENT("FasterRupeeAccumulator") }); diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipIntro.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipIntro.cpp index f7db9de32..26eae8097 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipIntro.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipIntro.cpp @@ -1,6 +1,6 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" +#include "soh/Enhancements/randomizer/context.h" +#include "soh/ShipInit.hpp" extern "C" { #include "z64save.h" @@ -10,12 +10,13 @@ extern PlayState* gPlayState; extern SaveContext gSaveContext; } -void SkipIntro_Register() { - REGISTER_VB_SHOULD(VB_PLAY_TRANSITION_CS, { +void RegisterSkipIntro() { + bool shouldRegister = CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Intro"), 0) || IS_RANDO; + COND_VB_SHOULD(VB_PLAY_TRANSITION_CS, shouldRegister, { // If we're playing rando and if starting age is adult and/or overworld spawns are shuffled we need to skip // the cutscene regardless of the enhancement being on. bool adultStart = gSaveContext.linkAge == LINK_AGE_ADULT; - bool shuffleEntrances = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_ENTRANCES).Is(true); + bool shuffleEntrances = Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_ENTRANCES).Is(true); if ((CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Intro"), IS_RANDO) || (IS_RANDO && (adultStart || shuffleEntrances))) && gSaveContext.cutsceneIndex == 0xFFF1) { @@ -45,3 +46,6 @@ void SkipIntro_Register() { } }); } + +static RegisterShipInitFunc initFunc(RegisterSkipIntro, + { CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Intro"), "IS_RANDO" }); diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipBlueWarp.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipBlueWarp.cpp index e15b8abd8..cc136b14f 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipBlueWarp.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipBlueWarp.cpp @@ -1,6 +1,7 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" +#include "soh/Enhancements/randomizer/context.h" +#include "soh/ShipInit.hpp" extern "C" { #include "macros.h" @@ -12,120 +13,6 @@ extern "C" { static bool sEnteredBlueWarp = false; -/** - * This will override the transitions into the blue warp cutscenes, set any appropriate flags, and - * set the entrance index to where you would normally end up after the blue warp cutscene. This - * should also account for the difference between your first and following visits to the blue warp. - */ -void SkipBlueWarp_ShouldPlayTransitionCS(GIVanillaBehavior _, bool* should, va_list originalArgs) { - // Do nothing when in a boss rush - if (IS_BOSS_RUSH) { - return; - } - - bool overrideBlueWarpDestinations = - IS_RANDO && (RAND_GET_OPTION(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF || - RAND_GET_OPTION(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF); - - // Force blue warp skip on when ER needs to place Link somewhere else. - // This is preferred over having story cutscenes play in the overworld and then reloading Link somewhere else after. - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO) || overrideBlueWarpDestinations) { - bool isBlueWarpCutscene = false; - // Deku Tree Blue warp - if (gSaveContext.entranceIndex == ENTR_KOKIRI_FOREST_0 && gSaveContext.cutsceneIndex == 0xFFF1) { - gSaveContext.entranceIndex = ENTR_KOKIRI_FOREST_DEKU_TREE_BLUE_WARP; - isBlueWarpCutscene = true; - // Dodongo's Cavern Blue warp - } else if (gSaveContext.entranceIndex == ENTR_DEATH_MOUNTAIN_TRAIL_BOTTOM_EXIT && - gSaveContext.cutsceneIndex == 0xFFF1) { - gSaveContext.entranceIndex = ENTR_DEATH_MOUNTAIN_TRAIL_DODONGO_BLUE_WARP; - isBlueWarpCutscene = true; - // Jabu Jabu's Blue warp - } else if (gSaveContext.entranceIndex == ENTR_ZORAS_FOUNTAIN_JABU_JABU_BLUE_WARP && - gSaveContext.cutsceneIndex == 0xFFF0) { - gSaveContext.entranceIndex = ENTR_ZORAS_FOUNTAIN_JABU_JABU_BLUE_WARP; - isBlueWarpCutscene = true; - // Forest Temple Blue warp - } else if (gSaveContext.entranceIndex == ENTR_CHAMBER_OF_THE_SAGES_0 && gSaveContext.cutsceneIndex == 0x0 && - gSaveContext.chamberCutsceneNum == CHAMBER_CS_FOREST) { - // Normally set in the blue warp cutscene - Flags_SetEventChkInf(EVENTCHKINF_SPOKE_TO_DEKU_TREE_SPROUT); - - if (IS_RANDO) { - gSaveContext.entranceIndex = ENTR_SACRED_FOREST_MEADOW_FOREST_TEMPLE_BLUE_WARP; - } else { - gSaveContext.entranceIndex = ENTR_KOKIRI_FOREST_12; - } - - isBlueWarpCutscene = true; - // Fire Temple Blue warp - } else if (gSaveContext.entranceIndex == ENTR_KAKARIKO_VILLAGE_FRONT_GATE && - gSaveContext.cutsceneIndex == 0xFFF3) { - // Normally set in the blue warp cutscene - Flags_SetEventChkInf(EVENTCHKINF_DEATH_MOUNTAIN_ERUPTED); - - gSaveContext.entranceIndex = ENTR_DEATH_MOUNTAIN_CRATER_FIRE_TEMPLE_BLUE_WARP; - isBlueWarpCutscene = true; - // Water Temple Blue warp - } else if (gSaveContext.entranceIndex == ENTR_CHAMBER_OF_THE_SAGES_0 && gSaveContext.cutsceneIndex == 0x0 && - gSaveContext.chamberCutsceneNum == CHAMBER_CS_WATER) { - // Normally set in the blue warp cutscene - gSaveContext.dayTime = gSaveContext.skyboxTime = 0x4800; - Flags_SetEventChkInf(EVENTCHKINF_RAISED_LAKE_HYLIA_WATER); - - gSaveContext.entranceIndex = ENTR_LAKE_HYLIA_WATER_TEMPLE_BLUE_WARP; - isBlueWarpCutscene = true; - // Spirit Temple Blue warp - } else if (gSaveContext.entranceIndex == ENTR_CHAMBER_OF_THE_SAGES_0 && gSaveContext.cutsceneIndex == 0x0 && - gSaveContext.chamberCutsceneNum == CHAMBER_CS_SPIRIT) { - gSaveContext.entranceIndex = ENTR_DESERT_COLOSSUS_SPIRIT_TEMPLE_BLUE_WARP; - isBlueWarpCutscene = true; - // Shadow Temple Blue warp - } else if (gSaveContext.entranceIndex == ENTR_CHAMBER_OF_THE_SAGES_0 && gSaveContext.cutsceneIndex == 0x0 && - gSaveContext.chamberCutsceneNum == CHAMBER_CS_SHADOW) { - gSaveContext.entranceIndex = ENTR_GRAVEYARD_SHADOW_TEMPLE_BLUE_WARP; - isBlueWarpCutscene = true; - } - - if (isBlueWarpCutscene) { - if (gSaveContext.entranceIndex != ENTR_LAKE_HYLIA_WATER_TEMPLE_BLUE_WARP) { - // Normally set in the blue warp cutscene - gSaveContext.dayTime = gSaveContext.skyboxTime = 0x8000; - } - - *should = false; - gSaveContext.cutsceneIndex = 0; - } - - // This is outside the above condition because we want to handle both first and following visits to the blue - // warp - if (sEnteredBlueWarp && overrideBlueWarpDestinations) { - Entrance_OverrideBlueWarp(); - } - } - - sEnteredBlueWarp = false; -} - -/** - * Using this hook to simply observe that Link has entered a bluewarp - * This way we know to allow entrance rando overrides to be processed on the next tranisition hook - */ -void SkipBlueWarp_ShouldPlayBlueWarpCS(GIVanillaBehavior _, bool* should, va_list originalArgs) { - sEnteredBlueWarp = true; -} - -/** - * While we could rely on the Item_Give that's normally called, it's not very clear to the player that they - * received the item when skipping the blue warp cutscene, so we'll prevent that and queue it up to be given - * to the player instead. - */ -void SkipBlueWarp_ShouldGiveItem(GIVanillaBehavior _, bool* should, va_list originalArgs) { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { - *should = false; - } -} - // Todo: Move item queueing here /** @@ -148,35 +35,143 @@ void EnKo_MoveWhenReady(EnKo* enKo, PlayState* play) { void SkipBlueWarp_OnActorUpdate(void* actorPtr) { EnKo* enKo = static_cast(actorPtr); - if ((enKo->actor.params & 0xFF) == ENKO_TYPE_CHILD_3 && enKo->actionFunc == func_80A995CC && - CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { + if ((enKo->actor.params & 0xFF) == ENKO_TYPE_CHILD_3 && enKo->actionFunc == func_80A995CC) { enKo->actionFunc = EnKo_MoveWhenReady; } } -/** - * This will ensure that the Deku Tree Sprout considers the Forest Temple finished when you skip the blue warp cutscene. - * Typically this checks for if you have the medallion, and when skipping the cutscene at this point you don't have it - * yet. - */ -void SkipBlueWarp_ShouldDekuJrConsiderForestTempleFinished(GIVanillaBehavior _, bool* should, va_list originalArgs) { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { - if (gSaveContext.entranceIndex == ENTR_KOKIRI_FOREST_DEKU_TREE_BLUE_WARP && - gSaveContext.cutsceneIndex == 0xFFF1) { - *should = Flags_GetEventChkInf(EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP); - } - } +void RegisterSkipBlueWarp() { + COND_ID_HOOK(OnActorUpdate, ACTOR_EN_KO, + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO), + SkipBlueWarp_OnActorUpdate); + + /** + * This will ensure that the Deku Tree Sprout considers the Forest Temple finished when you skip the blue warp + * cutscene. Typically this checks for if you have the medallion, and when skipping the cutscene at this point you + * don't have it yet. + */ + COND_VB_SHOULD(VB_DEKU_JR_CONSIDER_FOREST_TEMPLE_FINISHED, + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO), { + if (gSaveContext.entranceIndex == ENTR_KOKIRI_FOREST_DEKU_TREE_BLUE_WARP && + gSaveContext.cutsceneIndex == 0xFFF1) { + *should = Flags_GetEventChkInf(EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP); + } + }); + + /** + * While we could rely on the Item_Give that's normally called, it's not very clear to the player that they + * received the item when skipping the blue warp cutscene, so we'll prevent that and queue it up to be given + * to the player instead. + */ + COND_VB_SHOULD(VB_GIVE_ITEM_FROM_BLUE_WARP, + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO), { *should = false; }); } -void SkipBlueWarp_Register() { - GameInteractor::Instance->RegisterGameHookForID(ACTOR_EN_KO, - SkipBlueWarp_OnActorUpdate); - GameInteractor::Instance->RegisterGameHookForID( - VB_PLAY_TRANSITION_CS, SkipBlueWarp_ShouldPlayTransitionCS); - GameInteractor::Instance->RegisterGameHookForID( - VB_PLAY_BLUE_WARP_CS, SkipBlueWarp_ShouldPlayBlueWarpCS); - GameInteractor::Instance->RegisterGameHookForID( - VB_DEKU_JR_CONSIDER_FOREST_TEMPLE_FINISHED, SkipBlueWarp_ShouldDekuJrConsiderForestTempleFinished); - GameInteractor::Instance->RegisterGameHookForID(VB_GIVE_ITEM_FROM_BLUE_WARP, - SkipBlueWarp_ShouldGiveItem); +void RegisterShouldPlayBlueWarp() { + /** + * This will override the transitions into the blue warp cutscenes, set any appropriate flags, and + * set the entrance index to where you would normally end up after the blue warp cutscene. This + * should also account for the difference between your first and following visits to the blue warp. + */ + REGISTER_VB_SHOULD(VB_PLAY_TRANSITION_CS, { + // Do nothing when in a boss rush + if (IS_BOSS_RUSH) { + return; + } + + bool overrideBlueWarpDestinations = + IS_RANDO && (RAND_GET_OPTION(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF || + RAND_GET_OPTION(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF); + + // Force blue warp skip on when ER needs to place Link somewhere else. + // This is preferred over having story cutscenes play in the overworld and then reloading Link somewhere else + // after. + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO) || + overrideBlueWarpDestinations) { + bool isBlueWarpCutscene = false; + // Deku Tree Blue warp + if (gSaveContext.entranceIndex == ENTR_KOKIRI_FOREST_0 && gSaveContext.cutsceneIndex == 0xFFF1) { + gSaveContext.entranceIndex = ENTR_KOKIRI_FOREST_DEKU_TREE_BLUE_WARP; + isBlueWarpCutscene = true; + // Dodongo's Cavern Blue warp + } else if (gSaveContext.entranceIndex == ENTR_DEATH_MOUNTAIN_TRAIL_BOTTOM_EXIT && + gSaveContext.cutsceneIndex == 0xFFF1) { + gSaveContext.entranceIndex = ENTR_DEATH_MOUNTAIN_TRAIL_DODONGO_BLUE_WARP; + isBlueWarpCutscene = true; + // Jabu Jabu's Blue warp + } else if (gSaveContext.entranceIndex == ENTR_ZORAS_FOUNTAIN_JABU_JABU_BLUE_WARP && + gSaveContext.cutsceneIndex == 0xFFF0) { + gSaveContext.entranceIndex = ENTR_ZORAS_FOUNTAIN_JABU_JABU_BLUE_WARP; + isBlueWarpCutscene = true; + // Forest Temple Blue warp + } else if (gSaveContext.entranceIndex == ENTR_CHAMBER_OF_THE_SAGES_0 && gSaveContext.cutsceneIndex == 0x0 && + gSaveContext.chamberCutsceneNum == CHAMBER_CS_FOREST) { + // Normally set in the blue warp cutscene + Flags_SetEventChkInf(EVENTCHKINF_SPOKE_TO_DEKU_TREE_SPROUT); + + if (IS_RANDO) { + gSaveContext.entranceIndex = ENTR_SACRED_FOREST_MEADOW_FOREST_TEMPLE_BLUE_WARP; + } else { + gSaveContext.entranceIndex = ENTR_KOKIRI_FOREST_12; + } + + isBlueWarpCutscene = true; + // Fire Temple Blue warp + } else if (gSaveContext.entranceIndex == ENTR_KAKARIKO_VILLAGE_FRONT_GATE && + gSaveContext.cutsceneIndex == 0xFFF3) { + // Normally set in the blue warp cutscene + Flags_SetEventChkInf(EVENTCHKINF_DEATH_MOUNTAIN_ERUPTED); + + gSaveContext.entranceIndex = ENTR_DEATH_MOUNTAIN_CRATER_FIRE_TEMPLE_BLUE_WARP; + isBlueWarpCutscene = true; + // Water Temple Blue warp + } else if (gSaveContext.entranceIndex == ENTR_CHAMBER_OF_THE_SAGES_0 && gSaveContext.cutsceneIndex == 0x0 && + gSaveContext.chamberCutsceneNum == CHAMBER_CS_WATER) { + // Normally set in the blue warp cutscene + gSaveContext.dayTime = gSaveContext.skyboxTime = 0x4800; + Flags_SetEventChkInf(EVENTCHKINF_RAISED_LAKE_HYLIA_WATER); + + gSaveContext.entranceIndex = ENTR_LAKE_HYLIA_WATER_TEMPLE_BLUE_WARP; + isBlueWarpCutscene = true; + // Spirit Temple Blue warp + } else if (gSaveContext.entranceIndex == ENTR_CHAMBER_OF_THE_SAGES_0 && gSaveContext.cutsceneIndex == 0x0 && + gSaveContext.chamberCutsceneNum == CHAMBER_CS_SPIRIT) { + gSaveContext.entranceIndex = ENTR_DESERT_COLOSSUS_SPIRIT_TEMPLE_BLUE_WARP; + isBlueWarpCutscene = true; + // Shadow Temple Blue warp + } else if (gSaveContext.entranceIndex == ENTR_CHAMBER_OF_THE_SAGES_0 && gSaveContext.cutsceneIndex == 0x0 && + gSaveContext.chamberCutsceneNum == CHAMBER_CS_SHADOW) { + gSaveContext.entranceIndex = ENTR_GRAVEYARD_SHADOW_TEMPLE_BLUE_WARP; + isBlueWarpCutscene = true; + } + + if (isBlueWarpCutscene) { + if (gSaveContext.entranceIndex != ENTR_LAKE_HYLIA_WATER_TEMPLE_BLUE_WARP) { + // Normally set in the blue warp cutscene + gSaveContext.dayTime = gSaveContext.skyboxTime = 0x8000; + } + + *should = false; + gSaveContext.cutsceneIndex = 0; + } + + // This is outside the above condition because we want to handle both first and following visits to the blue + // warp + if (sEnteredBlueWarp && overrideBlueWarpDestinations) { + Entrance_OverrideBlueWarp(); + } + } + + sEnteredBlueWarp = false; + }); + + /** + * Using this hook to simply observe that Link has entered a bluewarp + * This way we know to allow entrance rando overrides to be processed on the next tranisition hook + */ + REGISTER_VB_SHOULD(VB_PLAY_BLUE_WARP_CS, { sEnteredBlueWarp = true; }); } + +static RegisterShipInitFunc initHooks(RegisterSkipBlueWarp, + { CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), "IS_RANDO" }); +static RegisterShipInitFunc initUnconditionalHooks(RegisterShouldPlayBlueWarp); diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipDekuTreeIntro.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipDekuTreeIntro.cpp index 361f69d68..9faa312a1 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipDekuTreeIntro.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipDekuTreeIntro.cpp @@ -1,6 +1,5 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" +#include "soh/ShipInit.hpp" extern "C" { #include "src/overlays/actors/ovl_Bg_Treemouth/z_bg_treemouth.h" @@ -9,15 +8,17 @@ extern "C" { /** * This will skip the Deku Tree intro, and simply open the mouth as you approach it. */ -void SkipDekuTreeIntro_Register() { - REGISTER_VB_SHOULD(VB_PLAY_DEKU_TREE_INTRO_CS, { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { - BgTreemouth* treeMouth = va_arg(args, BgTreemouth*); - Flags_SetEventChkInf(EVENTCHKINF_DEKU_TREE_OPENED_MOUTH); - Audio_PlaySoundGeneral(NA_SE_EV_WOODDOOR_OPEN, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, - &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); - BgTreemouth_SetupAction(treeMouth, func_808BC6F8); - *should = false; - } - }); +void RegisterSkipDekuTreeIntro() { + COND_VB_SHOULD(VB_PLAY_DEKU_TREE_INTRO_CS, + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO), { + BgTreemouth* treeMouth = va_arg(args, BgTreemouth*); + Flags_SetEventChkInf(EVENTCHKINF_DEKU_TREE_OPENED_MOUTH); + Audio_PlaySoundGeneral(NA_SE_EV_WOODDOOR_OPEN, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + BgTreemouth_SetupAction(treeMouth, func_808BC6F8); + *should = false; + }); } + +static RegisterShipInitFunc initFunc(RegisterSkipDekuTreeIntro, + { CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), "IS_RANDO" }); diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipLostWoodsBridge.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipLostWoodsBridge.cpp index 9485bdb0f..d743bead9 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipLostWoodsBridge.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipLostWoodsBridge.cpp @@ -1,6 +1,6 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" +#include "soh/ShipInit.hpp" extern "C" { #include "z64save.h" @@ -9,21 +9,19 @@ extern PlayState* gPlayState; extern SaveContext gSaveContext; } -void SkipLostWoodsBridge_Register() { +void RegisterSkipLostWoodsBridge() { /** * This skips the cutscene where you speak to Saria on the bridge in Lost Woods, where she gives you the Fairy * Ocarina. */ - REGISTER_VB_SHOULD(VB_PLAY_TRANSITION_CS, { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { - if ((gSaveContext.entranceIndex == ENTR_LOST_WOODS_BRIDGE_EAST_EXIT) && - !Flags_GetEventChkInf(EVENTCHKINF_SPOKE_TO_SARIA_ON_BRIDGE)) { - Flags_SetEventChkInf(EVENTCHKINF_SPOKE_TO_SARIA_ON_BRIDGE); - if (GameInteractor_Should(VB_GIVE_ITEM_FAIRY_OCARINA, true)) { - Item_Give(gPlayState, ITEM_OCARINA_FAIRY); - } - *should = false; + COND_VB_SHOULD(VB_PLAY_TRANSITION_CS, CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO), { + if ((gSaveContext.entranceIndex == ENTR_LOST_WOODS_BRIDGE_EAST_EXIT) && + !Flags_GetEventChkInf(EVENTCHKINF_SPOKE_TO_SARIA_ON_BRIDGE)) { + Flags_SetEventChkInf(EVENTCHKINF_SPOKE_TO_SARIA_ON_BRIDGE); + if (GameInteractor_Should(VB_GIVE_ITEM_FAIRY_OCARINA, true)) { + Item_Give(gPlayState, ITEM_OCARINA_FAIRY); } + *should = false; } }); @@ -32,11 +30,11 @@ void SkipLostWoodsBridge_Register() { * player that they received the item when skipping the cutscene, so we'll prevent it, and queue it up to be given * instead. */ - REGISTER_VB_SHOULD(VB_GIVE_ITEM_FAIRY_OCARINA, { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { - *should = false; - } - }); + COND_VB_SHOULD(VB_GIVE_ITEM_FAIRY_OCARINA, + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO), { *should = false; }); // Todo: Move item queueing here } + +static RegisterShipInitFunc initFunc(RegisterSkipLostWoodsBridge, + { CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), "IS_RANDO" }); diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipToGivingZeldasLetter.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipToGivingZeldasLetter.cpp index c623d46d2..1acd6dabe 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipToGivingZeldasLetter.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipToGivingZeldasLetter.cpp @@ -1,6 +1,5 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" +#include "soh/ShipInit.hpp" extern "C" { #include "src/overlays/actors/ovl_En_Zl4/z_en_zl4.h" @@ -33,16 +32,17 @@ void EnZl4_SkipToGivingZeldasLetter(EnZl4* enZl4, PlayState* play) { } void SkipToGivingZeldasLetter_OnActorInit(void* actorPtr) { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { - EnZl4* enZl4 = static_cast(actorPtr); - if (enZl4->actionFunc != EnZl4_Cutscene || enZl4->csState != 0) - return; + EnZl4* enZl4 = static_cast(actorPtr); + if (enZl4->actionFunc != EnZl4_Cutscene || enZl4->csState != 0) + return; - enZl4->actionFunc = EnZl4_SkipToGivingZeldasLetter; - } + enZl4->actionFunc = EnZl4_SkipToGivingZeldasLetter; } -void SkipToGivingZeldasLetter_Register() { - GameInteractor::Instance->RegisterGameHookForID(ACTOR_EN_ZL4, - SkipToGivingZeldasLetter_OnActorInit); +void RegisterSkipToGivingZeldasLetter() { + COND_ID_HOOK(OnActorInit, ACTOR_EN_ZL4, CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO), + SkipToGivingZeldasLetter_OnActorInit); } + +static RegisterShipInitFunc initFunc(RegisterSkipToGivingZeldasLetter, + { CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), "IS_RANDO" }); diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipZeldaFleeingCastle.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipZeldaFleeingCastle.cpp index 56d26f01d..ae82ff9f0 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipZeldaFleeingCastle.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipZeldaFleeingCastle.cpp @@ -1,6 +1,5 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" +#include "soh/ShipInit.hpp" extern "C" { #include "z64save.h" @@ -8,18 +7,6 @@ extern "C" { extern SaveContext gSaveContext; } -void SkipZeldaFleeingCastle_ShouldPlayTransitionCS(GIVanillaBehavior _, bool* should, va_list originalArgs) { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { - if (gSaveContext.entranceIndex == ENTR_HYRULE_FIELD_PAST_BRIDGE_SPAWN && gSaveContext.cutsceneIndex == 0xFFF1) { - // Normally set in the cutscene - gSaveContext.dayTime = gSaveContext.skyboxTime = 0x4AAA; - - gSaveContext.cutsceneIndex = 0; - *should = false; - } - } -} - /** * When this cutscene is skipped, walking up to the bridge to castle town triggers a quick fade in/out * which can be confusing to beginners, because they need to then fetch the Ocarina of Time from the water. @@ -46,7 +33,7 @@ void SkipZeldaFleeingCastle_OnActorUpdate(void* actorPtr) { void SkipZeldaFleeingCastle_OnActorInit(void* actorPtr) { Actor* actor = static_cast(actorPtr); - if (actor->params == 3 && CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { + if (actor->params == 3) { framesSinceSpawn = 0; itemOcarinaUpdateHook = GameInteractor::Instance->RegisterGameHookForPtr( (uintptr_t)actorPtr, SkipZeldaFleeingCastle_OnActorUpdate); @@ -59,9 +46,20 @@ void SkipZeldaFleeingCastle_OnActorInit(void* actorPtr) { } } -void SkipZeldaFleeingCastle_Register() { - GameInteractor::Instance->RegisterGameHookForID(ACTOR_ITEM_OCARINA, - SkipZeldaFleeingCastle_OnActorInit); - GameInteractor::Instance->RegisterGameHookForID( - VB_PLAY_TRANSITION_CS, SkipZeldaFleeingCastle_ShouldPlayTransitionCS); +void RegisterSkipZeldaFleeingCastle() { + COND_ID_HOOK(OnActorInit, ACTOR_ITEM_OCARINA, + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO), + SkipZeldaFleeingCastle_OnActorInit); + COND_VB_SHOULD(VB_PLAY_TRANSITION_CS, CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO), { + if (gSaveContext.entranceIndex == ENTR_HYRULE_FIELD_PAST_BRIDGE_SPAWN && gSaveContext.cutsceneIndex == 0xFFF1) { + // Normally set in the cutscene + gSaveContext.dayTime = gSaveContext.skyboxTime = 0x4AAA; + + gSaveContext.cutsceneIndex = 0; + *should = false; + } + }); } + +static RegisterShipInitFunc initFunc(RegisterSkipZeldaFleeingCastle, + { CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), "IS_RANDO" }); diff --git a/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveJabuJabuElevator.cpp b/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveJabuJabuElevator.cpp index 704339424..34e2fdf61 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveJabuJabuElevator.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveJabuJabuElevator.cpp @@ -1,28 +1,28 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" +#include "soh/ShipInit.hpp" extern "C" { #include "src/overlays/actors/ovl_Bg_Bdan_Objects/z_bg_bdan_objects.h" } +void BdanInit(void* actorRef) { + Player* player = GET_PLAYER(gPlayState); + BgBdanObjects* bgBdanObjects = static_cast(actorRef); + + if (bgBdanObjects->dyna.actor.params == 1) { + if (player->actor.world.pos.y < -500.0f) { + bgBdanObjects->timer = 220; + } + } +} + /** * Adjusts the behavior of the elevator to start near the bottom if you are entering the room from the bottom */ -void MoveJabuJabuElevator_Register() { - GameInteractor::Instance->RegisterGameHookForID( - ACTOR_BG_BDAN_OBJECTS, [](void* actorRef) { - Player* player = GET_PLAYER(gPlayState); - BgBdanObjects* bgBdanObjects = static_cast(actorRef); - - if (!CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { - return; - } - - if (bgBdanObjects->dyna.actor.params == 1) { - if (player->actor.world.pos.y < -500.0f) { - bgBdanObjects->timer = 220; - } - } - }); +void RegisterMoveJabuJabuElevator() { + COND_ID_HOOK(OnActorInit, ACTOR_BG_BDAN_OBJECTS, + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO), BdanInit); } + +static RegisterShipInitFunc initFunc(RegisterMoveJabuJabuElevator, + { CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), "IS_RANDO" }); diff --git a/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveMidoInKokiriForest.cpp b/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveMidoInKokiriForest.cpp index 6e9b94b4a..1e4e77d44 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveMidoInKokiriForest.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/MoveMidoInKokiriForest.cpp @@ -1,6 +1,5 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" +#include "soh/ShipInit.hpp" extern "C" { #include "z64save.h" @@ -15,14 +14,17 @@ extern SaveContext gSaveContext; * This simply skips the Mido interaction in Kokiri Forest, once you equip the Kokiri * Sword and Deku Shield he will move out of the way without you needing to talk to him. */ -void MoveMidoInKokiriForest_Register() { - REGISTER_VB_SHOULD(VB_MOVE_MIDO_IN_KOKIRI_FOREST, { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO) && - !Flags_GetEventChkInf(EVENTCHKINF_SHOWED_MIDO_SWORD_SHIELD) && - (CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) == EQUIP_VALUE_SHIELD_DEKU) && - (CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) == EQUIP_VALUE_SWORD_KOKIRI) && gSaveContext.cutsceneIndex == 0) { - Flags_SetEventChkInf(EVENTCHKINF_SHOWED_MIDO_SWORD_SHIELD); - *should = true; - } - }); +void RegisterMoveMidoInKokiriForest() { + COND_VB_SHOULD( + VB_MOVE_MIDO_IN_KOKIRI_FOREST, CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO), { + if (!Flags_GetEventChkInf(EVENTCHKINF_SHOWED_MIDO_SWORD_SHIELD) && + (CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) == EQUIP_VALUE_SHIELD_DEKU) && + (CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) == EQUIP_VALUE_SWORD_KOKIRI) && gSaveContext.cutsceneIndex == 0) { + Flags_SetEventChkInf(EVENTCHKINF_SHOWED_MIDO_SWORD_SHIELD); + *should = true; + } + }); } + +static RegisterShipInitFunc initFunc(RegisterMoveMidoInKokiriForest, + { CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), "IS_RANDO" }); diff --git a/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/SkipChildRutoInteractions.cpp b/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/SkipChildRutoInteractions.cpp index 97b65a543..39417d5de 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/SkipChildRutoInteractions.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipMiscInteractions/SkipChildRutoInteractions.cpp @@ -1,6 +1,5 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" -#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -#include "soh/OTRGlobals.h" +#include "soh/ShipInit.hpp" extern "C" { #include "overlays/actors/ovl_En_Ru1/z_en_ru1.h" @@ -9,93 +8,87 @@ extern "C" { Actor* func_80AEB124(PlayState* play); } -void SkipChildRutoInteractions_Register() { - // Skips the Child Ruto introduction cutscene, where she drops down into the hole in Jabu-Jabu's Belly - REGISTER_VB_SHOULD(VB_PLAY_CHILD_RUTO_INTRO, { - EnRu1* enRu1 = va_arg(args, EnRu1*); +void Ru1Init(void* actorRef) { + EnRu1* enRu1 = static_cast(actorRef); - if (!CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { - return; - } - - Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_MEET_RUTO); - Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_TALK_FIRST_TIME); - Flags_SetInfTable(INFTABLE_143); + if (enRu1->action == 22) { + enRu1->action = 27; enRu1->drawConfig = 1; - enRu1->actor.world.pos.x = 127.0f; - enRu1->actor.world.pos.y = -340.0f; - enRu1->actor.world.pos.z = -3041.0f; - enRu1->actor.shape.rot.y = enRu1->actor.world.rot.y = -5098; + enRu1->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_FRIENDLY; + Animation_Change(&enRu1->skelAnime, (AnimationHeader*)&gRutoChildSittingAnim, 1.0f, 0.0f, + Animation_GetLastFrame((void*)&gRutoChildSittingAnim), ANIMMODE_LOOP, 0.0f); + } +} - if (*should) { - Animation_Change(&enRu1->skelAnime, (AnimationHeader*)&gRutoChildTurnAroundAnim, 1.0f, 0, - Animation_GetLastFrame((void*)&gRutoChildTurnAroundAnim), ANIMMODE_ONCE, -8.0f); - enRu1->action = 10; - } +void RegisterSkipChildRutoInteractions() { + // Skips the Child Ruto introduction cutscene, where she drops down into the hole in Jabu-Jabu's Belly + COND_VB_SHOULD( + VB_PLAY_CHILD_RUTO_INTRO, CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO), { + EnRu1* enRu1 = va_arg(args, EnRu1*); - *should = false; - }); + Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_MEET_RUTO); + Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_TALK_FIRST_TIME); + Flags_SetInfTable(INFTABLE_143); + enRu1->drawConfig = 1; + enRu1->actor.world.pos.x = 127.0f; + enRu1->actor.world.pos.y = -340.0f; + enRu1->actor.world.pos.z = -3041.0f; + enRu1->actor.shape.rot.y = enRu1->actor.world.rot.y = -5098; + + if (*should) { + Animation_Change(&enRu1->skelAnime, (AnimationHeader*)&gRutoChildTurnAroundAnim, 1.0f, 0, + Animation_GetLastFrame((void*)&gRutoChildTurnAroundAnim), ANIMMODE_ONCE, -8.0f); + enRu1->action = 10; + } + + *should = false; + }); // Skips a short dialogue sequence where Ruto tells you to throw her to the Sapphire - REGISTER_VB_SHOULD(VB_RUTO_WANT_TO_BE_TOSSED_TO_SAPPHIRE, { - if (!CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { - return; - } - - if (*should) { - Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE); - *should = false; - } - }); + COND_VB_SHOULD(VB_RUTO_WANT_TO_BE_TOSSED_TO_SAPPHIRE, + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO), { + if (*should) { + Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE); + *should = false; + } + }); // Prevents Ruto from running to the Sapphire when she wants to be tossed to it, instead she just stands up and // waits for link to get closer - REGISTER_VB_SHOULD(VB_RUTO_RUN_TO_SAPPHIRE, { - EnRu1* enRu1 = va_arg(args, EnRu1*); - DynaPolyActor* dynaPolyActor = va_arg(args, DynaPolyActor*); + COND_VB_SHOULD(VB_RUTO_RUN_TO_SAPPHIRE, + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO), { + EnRu1* enRu1 = va_arg(args, EnRu1*); + DynaPolyActor* dynaPolyActor = va_arg(args, DynaPolyActor*); - if (!CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { - return; - } - - if (*should) { - enRu1->unk_28C = (BgBdanObjects*)dynaPolyActor; - Flags_SetInfTable(INFTABLE_145); - Flags_SetSwitch(gPlayState, 0x02); - Flags_SetSwitch(gPlayState, 0x1F); - enRu1->action = 42; - Animation_Change(&enRu1->skelAnime, (AnimationHeader*)&gRutoChildWait2Anim, 1.0f, 0, - Animation_GetLastFrame((void*)&gRutoChildWait2Anim), ANIMMODE_LOOP, -8.0f); - // If we aren't skipping one point cutscenes and BgBdan objects has set the camera setting - // to CAM_SET_NORMAL1 (2), don't reset the camera setting to 1. This prevents the One Point - // Cutscene of Ruto getting lifted up from getting queued up twice. - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint"), IS_RANDO) || - enRu1->unk_28C->cameraSetting != 2) { - enRu1->unk_28C->cameraSetting = 1; - } - Actor* sapphire = func_80AEB124(gPlayState); - if (sapphire != NULL) { - Actor_Kill(sapphire); - } - enRu1->actor.room = gPlayState->roomCtx.curRoom.num; - *should = false; - } - }); + if (*should) { + enRu1->unk_28C = (BgBdanObjects*)dynaPolyActor; + Flags_SetInfTable(INFTABLE_145); + Flags_SetSwitch(gPlayState, 0x02); + Flags_SetSwitch(gPlayState, 0x1F); + enRu1->action = 42; + Animation_Change(&enRu1->skelAnime, (AnimationHeader*)&gRutoChildWait2Anim, 1.0f, 0, + Animation_GetLastFrame((void*)&gRutoChildWait2Anim), ANIMMODE_LOOP, -8.0f); + // If we aren't skipping one point cutscenes and BgBdan objects has set the camera setting + // to CAM_SET_NORMAL1 (2), don't reset the camera setting to 1. This prevents the One Point + // Cutscene of Ruto getting lifted up from getting queued up twice. + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.OnePoint"), IS_RANDO) || + enRu1->unk_28C->cameraSetting != 2) { + enRu1->unk_28C->cameraSetting = 1; + } + Actor* sapphire = func_80AEB124(gPlayState); + if (sapphire != NULL) { + Actor_Kill(sapphire); + } + enRu1->actor.room = gPlayState->roomCtx.curRoom.num; + *should = false; + } + }); // This overrides the behavior that causes Ruto to get upset at you before sitting back down again when // INFTABLE_RUTO_IN_JJ_TALK_FIRST_TIME is set - GameInteractor::Instance->RegisterGameHookForID(ACTOR_EN_RU1, [](void* actorRef) { - EnRu1* enRu1 = static_cast(actorRef); - if (!CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { - return; - } - - if (enRu1->action == 22) { - enRu1->action = 27; - enRu1->drawConfig = 1; - enRu1->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED | ACTOR_FLAG_FRIENDLY; - Animation_Change(&enRu1->skelAnime, (AnimationHeader*)&gRutoChildSittingAnim, 1.0f, 0.0f, - Animation_GetLastFrame((void*)&gRutoChildSittingAnim), ANIMMODE_LOOP, 0.0f); - } - }); + COND_ID_HOOK(OnActorInit, ACTOR_EN_RU1, + CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO), Ru1Init); } + +static RegisterShipInitFunc initFunc(RegisterSkipChildRutoInteractions, + { CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), "IS_RANDO" }); diff --git a/soh/soh/Enhancements/TimeSavers/TimeSavers.cpp b/soh/soh/Enhancements/TimeSavers/TimeSavers.cpp deleted file mode 100644 index a881675d6..000000000 --- a/soh/soh/Enhancements/TimeSavers/TimeSavers.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "TimeSavers.h" - -void TimeSavers_Register() { - // SkipCutscene - // Story - SkipBlueWarp_Register(); - SkipDekuTreeIntro_Register(); - SkipLostWoodsBridge_Register(); - SkipToGivingZeldasLetter_Register(); - SkipZeldaFleeingCastle_Register(); - SkipIntro_Register(); - // SkipMiscInteractions - MoveJabuJabuElevator_Register(); - MoveMidoInKokiriForest_Register(); - SkipChildRutoInteractions_Register(); - FasterHeavyBlockLift_Register(); - FasterRupeeAccumulator_Register(); -} diff --git a/soh/soh/Enhancements/TimeSavers/TimeSavers.h b/soh/soh/Enhancements/TimeSavers/TimeSavers.h deleted file mode 100644 index 9448260d6..000000000 --- a/soh/soh/Enhancements/TimeSavers/TimeSavers.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef TIME_SAVERS_H -#define TIME_SAVERS_H - -void TimeSavers_Register(); - -// SkipCutscene -// Story -void SkipBlueWarp_Register(); -void SkipDekuTreeIntro_Register(); -void SkipLostWoodsBridge_Register(); -void SkipToGivingZeldasLetter_Register(); -void SkipZeldaFleeingCastle_Register(); -void SkipIntro_Register(); -// SkipMiscInteractions -void MoveJabuJabuElevator_Register(); -void MoveMidoInKokiriForest_Register(); -void SkipChildRutoInteractions_Register(); -void FasterHeavyBlockLift_Register(); -void FasterRupeeAccumulator_Register(); - -#endif // TIME_SAVERS_H diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 05e9d3d74..6c547db08 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -13,7 +13,6 @@ #include "soh/Enhancements/cosmetics/authenticGfxPatches.h" #include #include "soh/Enhancements/timesaver_hook_handlers.h" -#include "soh/Enhancements/TimeSavers/TimeSavers.h" #include "soh/Enhancements/randomizer/hook_handlers.h" #include "src/overlays/actors/ovl_En_Bb/z_en_bb.h" @@ -961,7 +960,6 @@ void InitMods() { BossRush_RegisterHooks(); RandomizerRegisterHooks(); TimeSaverRegisterHooks(); - TimeSavers_Register(); RegisterTTS(); RegisterOcarinaTimeTravel(); RegisterPermanentHeartLoss();