From 72625182a41b7a1ec4784d449c5483a90f4b4928 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sun, 19 May 2024 22:07:54 -0500 Subject: [PATCH] Add a few initial cutscene skips (#399) --- mm/2s2h/BenGui/BenMenuBar.cpp | 3 + mm/2s2h/Enhancements/Cutscenes/Cutscenes.cpp | 15 ++++ mm/2s2h/Enhancements/Cutscenes/Cutscenes.h | 18 ++++ .../Enhancements/Cutscenes/HideTitleCards.h | 6 -- .../MiscInteractions/SkipDekuSalesman.cpp | 17 ++++ .../MiscInteractions/SkipScarecrowDance.cpp | 37 ++++++++ .../MiscInteractions/SkipTatlInterrupts.cpp | 89 +++++++++++++++++++ .../Cutscenes/SkipEntranceCutscenes.h | 6 -- .../Cutscenes/SkipIntroSequence.cpp | 28 ++++++ .../StoryCutscenes/SkipClockTowerOpen.cpp | 24 +++++ mm/2s2h/Enhancements/Enhancements.cpp | 3 +- mm/2s2h/Enhancements/Enhancements.h | 3 +- .../GameInteractor/GameInteractor.h | 4 + mm/src/code/z_demo.c | 8 ++ .../overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c | 5 +- .../overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c | 5 +- .../actors/ovl_En_Kakasi/z_en_kakasi.h | 5 ++ 17 files changed, 256 insertions(+), 20 deletions(-) create mode 100644 mm/2s2h/Enhancements/Cutscenes/Cutscenes.cpp create mode 100644 mm/2s2h/Enhancements/Cutscenes/Cutscenes.h delete mode 100644 mm/2s2h/Enhancements/Cutscenes/HideTitleCards.h create mode 100644 mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipDekuSalesman.cpp create mode 100644 mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipScarecrowDance.cpp create mode 100644 mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp delete mode 100644 mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.h create mode 100644 mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp create mode 100644 mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp diff --git a/mm/2s2h/BenGui/BenMenuBar.cpp b/mm/2s2h/BenGui/BenMenuBar.cpp index 2a83a35fe..a160e2334 100644 --- a/mm/2s2h/BenGui/BenMenuBar.cpp +++ b/mm/2s2h/BenGui/BenMenuBar.cpp @@ -361,6 +361,9 @@ void DrawEnhancementsMenu() { UIWidgets::CVarCheckbox( "Skip to File Select", "gEnhancements.Cutscenes.SkipToFileSelect", { .tooltip = "Skip the opening title sequence and go straight to the file select menu after boot" }); + UIWidgets::CVarCheckbox("Skip Intro Sequence", "gEnhancements.Cutscenes.SkipIntroSequence"); + UIWidgets::CVarCheckbox("Skip Story Cutscenes", "gEnhancements.Cutscenes.SkipStoryCutscenes"); + UIWidgets::CVarCheckbox("Skip Misc Interactions", "gEnhancements.Cutscenes.SkipMiscInteractions"); ImGui::EndMenu(); } diff --git a/mm/2s2h/Enhancements/Cutscenes/Cutscenes.cpp b/mm/2s2h/Enhancements/Cutscenes/Cutscenes.cpp new file mode 100644 index 000000000..d3e0bc20e --- /dev/null +++ b/mm/2s2h/Enhancements/Cutscenes/Cutscenes.cpp @@ -0,0 +1,15 @@ +#include "Cutscenes.h" + +void RegisterCutscenes() { + // MiscInteractions + RegisterSkipDekuSalesman(); + RegisterSkipScarecrowDance(); + RegisterSkipTatlInterrupts(); + + // StoryCutscenes + RegisterSkipClockTowerOpen(); + + RegisterHideTitleCards(); + RegisterSkipEntranceCutscenes(); + RegisterSkipIntroSequence(); +} diff --git a/mm/2s2h/Enhancements/Cutscenes/Cutscenes.h b/mm/2s2h/Enhancements/Cutscenes/Cutscenes.h new file mode 100644 index 000000000..8449439e1 --- /dev/null +++ b/mm/2s2h/Enhancements/Cutscenes/Cutscenes.h @@ -0,0 +1,18 @@ +#ifndef CUTSCENES_H +#define CUTSCENES_H + +void RegisterCutscenes(); + +// MiscInteractions + void RegisterSkipDekuSalesman(); + void RegisterSkipScarecrowDance(); + void RegisterSkipTatlInterrupts(); + +// StoryCutscenes + void RegisterSkipClockTowerOpen(); + +void RegisterHideTitleCards(); +void RegisterSkipEntranceCutscenes(); +void RegisterSkipIntroSequence(); + +#endif // CUTSCENES_H diff --git a/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.h b/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.h deleted file mode 100644 index b537ae8cf..000000000 --- a/mm/2s2h/Enhancements/Cutscenes/HideTitleCards.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CUTSCENES_HIDE_TITLE_CARDS_H -#define CUTSCENES_HIDE_TITLE_CARDS_H - -void RegisterHideTitleCards(); - -#endif // CUTSCENES_HIDE_TITLE_CARDS_H diff --git a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipDekuSalesman.cpp b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipDekuSalesman.cpp new file mode 100644 index 000000000..439f4e934 --- /dev/null +++ b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipDekuSalesman.cpp @@ -0,0 +1,17 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { + #include "z64.h" + extern SaveContext gSaveContext; + void Flags_SetWeekEventReg(s32 flag); +} + +void RegisterSkipDekuSalesman() { + // prevents him from doing his "fly in" animation + GameInteractor::Instance->RegisterGameHookForID(ACTOR_EN_SELLNUTS, [](Actor* actor, bool* should) { + if (CVarGetInteger("gEnhancements.Cutscenes.SkipMiscInteractions", 0) && !CHECK_WEEKEVENTREG(WEEKEVENTREG_73_04)) { + SET_WEEKEVENTREG(WEEKEVENTREG_73_04); + } + }); +} diff --git a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipScarecrowDance.cpp b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipScarecrowDance.cpp new file mode 100644 index 000000000..f44d9def0 --- /dev/null +++ b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipScarecrowDance.cpp @@ -0,0 +1,37 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { + #include "z64.h" + #include "src/overlays/actors/ovl_En_Kakasi/z_en_kakasi.h" +} + +void RegisterSkipScarecrowDance() { + // Skips to end of "passing time" dance with the scarecrow + GameInteractor::Instance->RegisterGameHookForID(ACTOR_EN_KAKASI, [](Actor* outerActor) { + static uint32_t enKakasiUpdateHook = 0; + static uint32_t enKakasiKillHook = 0; + GameInteractor::Instance->UnregisterGameHookForPtr(enKakasiUpdateHook); + GameInteractor::Instance->UnregisterGameHook(enKakasiKillHook); + enKakasiUpdateHook = 0; + enKakasiKillHook = 0; + + enKakasiUpdateHook = GameInteractor::Instance->RegisterGameHookForPtr((uintptr_t)outerActor, [](Actor* actor) { + EnKakasi* enKakasi = (EnKakasi*)actor; + if ( + CVarGetInteger("gEnhancements.Cutscenes.SkipMiscInteractions", 0) && + enKakasi->actionFunc == EnKakasi_DancingNightAway && + enKakasi->unk190 == 0 + ) { + enKakasi->unk190 = 13; + enKakasi->unk204 = 0; + } + }); + enKakasiKillHook = GameInteractor::Instance->RegisterGameHook([](s8 sceneId, s8 spawnNum) { + GameInteractor::Instance->UnregisterGameHook(enKakasiUpdateHook); + GameInteractor::Instance->UnregisterGameHook(enKakasiKillHook); + enKakasiUpdateHook = 0; + enKakasiKillHook = 0; + }); + }); +} diff --git a/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp new file mode 100644 index 000000000..5f3281ffa --- /dev/null +++ b/mm/2s2h/Enhancements/Cutscenes/MiscInteractions/SkipTatlInterrupts.cpp @@ -0,0 +1,89 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +#define ELFMSG3_GET_SWITCH_FLAG(thisx) (((thisx)->params & 0x7F00) >> 8) + +extern "C" { + #include "z64.h" + extern PlayState* gPlayState; + extern SaveContext gSaveContext; + extern u32 gBitFlags[]; + void Flags_SetWeekEventReg(s32 flag); + void Flags_SetSwitch(PlayState* play, s32 flag); + void Actor_Kill(Actor* actor); +} + +void RegisterSkipTatlInterrupts() { + // First time entering Clock Town Interupt + REGISTER_VB_SHOULD(GI_VB_PLAY_TRANSITION_CS, { + if ( + gSaveContext.save.entrance == ENTRANCE(SOUTH_CLOCK_TOWN, 0) && + gSaveContext.save.cutsceneIndex == 0 && + !CHECK_WEEKEVENTREG(WEEKEVENTREG_59_04) && + CVarGetInteger("gEnhancements.Cutscenes.SkipMiscInteractions", 0) + ) { + Flags_SetWeekEventReg(WEEKEVENTREG_59_04); + } + }); + + // General interupt + REGISTER_VB_SHOULD(GI_VB_TATL_INTERUPT_MSG3, { + if (CVarGetInteger("gEnhancements.Cutscenes.SkipMiscInteractions", 0) && *should) { + Actor* actor = static_cast(opt); + *should = false; + if (ELFMSG3_GET_SWITCH_FLAG(actor) != 0x7F) { + Flags_SetSwitch(gPlayState, ELFMSG3_GET_SWITCH_FLAG(actor)); + } + Actor_Kill(actor); + } + }); + + // General interupt 2 (the flags were directly copied from the original code) + REGISTER_VB_SHOULD(GI_VB_TATL_INTERUPT_MSG6, { + if (CVarGetInteger("gEnhancements.Cutscenes.SkipMiscInteractions", 0) && *should) { + Actor* actor = static_cast(opt); + *should = false; + switch (actor->textId) { + case 0x224: + SET_WEEKEVENTREG(WEEKEVENTREG_79_10); + break; + + case 0x25B: + SET_WEEKEVENTREG(WEEKEVENTREG_88_20); + break; + + case 0x216: + SET_WEEKEVENTREG(WEEKEVENTREG_31_04); + break; + + case 0x231: + SET_WEEKEVENTREG(WEEKEVENTREG_31_01); + break; + + case 0x232: + SET_WEEKEVENTREG(WEEKEVENTREG_31_02); + break; + + case 0x233: + SET_WEEKEVENTREG(WEEKEVENTREG_80_04); + break; + } + if (CHECK_QUEST_ITEM(QUEST_REMAINS_ODOLWA)) { + SET_WEEKEVENTREG(WEEKEVENTREG_87_10); + } + + if (CHECK_QUEST_ITEM(QUEST_REMAINS_GOHT)) { + SET_WEEKEVENTREG(WEEKEVENTREG_87_20); + } + + if (CHECK_QUEST_ITEM(QUEST_REMAINS_GYORG)) { + SET_WEEKEVENTREG(WEEKEVENTREG_87_40); + } + + if (CHECK_QUEST_ITEM(QUEST_REMAINS_TWINMOLD)) { + SET_WEEKEVENTREG(WEEKEVENTREG_87_80); + } + Actor_Kill(actor); + } + }); +} diff --git a/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.h b/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.h deleted file mode 100644 index d2f9cd673..000000000 --- a/mm/2s2h/Enhancements/Cutscenes/SkipEntranceCutscenes.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CUTSCENES_SKIP_ENTRANCE_CUTSCENES_H -#define CUTSCENES_SKIP_ENTRANCE_CUTSCENES_H - -void RegisterSkipEntranceCutscenes(); - -#endif // CUTSCENES_SKIP_ENTRANCE_CUTSCENES_H \ No newline at end of file diff --git a/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp b/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp new file mode 100644 index 000000000..34b51ac57 --- /dev/null +++ b/mm/2s2h/Enhancements/Cutscenes/SkipIntroSequence.cpp @@ -0,0 +1,28 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { + #include "z64.h" + extern PlayState* gPlayState; + extern SaveContext gSaveContext; +} + +void RegisterSkipIntroSequence() { + REGISTER_VB_SHOULD(GI_VB_PLAY_TRANSITION_CS, { + // Intro cutscene + if (!(gSaveContext.save.entrance == ENTRANCE(CUTSCENE, 0) && gSaveContext.save.cutsceneIndex == 0)) return; + + if (CVarGetInteger("gEnhancements.Cutscenes.SkipIntroSequence", 0)) { + gSaveContext.save.entrance = ENTRANCE(SOUTH_CLOCK_TOWN, 0); + gSaveContext.save.hasTatl = true; + gSaveContext.cycleSceneFlags[SCENE_INSIDETOWER].switch0 |= (1 << 0); + gSaveContext.cycleSceneFlags[SCENE_OPENINGDAN].switch0 |= (1 << 2); + gSaveContext.cycleSceneFlags[SCENE_OPENINGDAN].switch0 |= (1 << 0); + gSaveContext.save.playerForm = PLAYER_FORM_DEKU; + + // Mark chest as opened and give the player the Deku Nuts + gSaveContext.cycleSceneFlags[SCENE_OPENINGDAN].chest |= (1 << 0); + Item_Give(gPlayState, ITEM_DEKU_NUTS_10); + } + }); +} diff --git a/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp b/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp new file mode 100644 index 000000000..d33b9683a --- /dev/null +++ b/mm/2s2h/Enhancements/Cutscenes/StoryCutscenes/SkipClockTowerOpen.cpp @@ -0,0 +1,24 @@ +#include +#include "Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { + #include "z64.h" + void Flags_SetWeekEventReg(s32 flag); + extern SaveContext gSaveContext; +} + +void RegisterSkipClockTowerOpen() { + REGISTER_VB_SHOULD(GI_VB_PLAY_TRANSITION_CS, { + // Cutscene where clock tower opens. Will only show if the player is in Clock Town + if ( + ENTRANCE(SOUTH_CLOCK_TOWN, 0) && + gSaveContext.save.cutsceneIndex == 0xFFF1 && + CVarGetInteger("gEnhancements.Cutscenes.SkipStoryCutscenes", 0) + ) { + // Setting the respawn flag to 2 will respawn the player where they were before the cutscene, consistent with the normal behavior + gSaveContext.respawnFlag = 2; + gSaveContext.save.cutsceneIndex = 0; + SET_WEEKEVENTREG(WEEKEVENTREG_CLOCK_TOWER_OPENED); + } + }); +} diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 740869ae9..d1f4118a8 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -33,8 +33,7 @@ void InitEnhancements() { RegisterTatlISG(); // Cutscenes - RegisterSkipEntranceCutscenes(); - RegisterHideTitleCards(); + RegisterCutscenes(); // Modes RegisterPlayAsKafei(); diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 3675d2070..5c54ee250 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -12,8 +12,7 @@ #include "Masks/NoBlastMaskCooldown.h" #include "Masks/FastTransformation.h" #include "Minigames/AlwaysWinDoggyRace.h" -#include "Cutscenes/SkipEntranceCutscenes.h" -#include "Cutscenes/HideTitleCards.h" +#include "Cutscenes/Cutscenes.h" #include "Restorations/PowerCrouchStab.h" #include "Restorations/SideRoll.h" #include "Restorations/TatlISG.h" diff --git a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h index 8a6f61a5b..09ea7c88d 100644 --- a/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h +++ b/mm/2s2h/Enhancements/GameInteractor/GameInteractor.h @@ -44,6 +44,10 @@ typedef enum { GI_VB_PREVENT_CLOCK_DISPLAY, GI_VB_SONG_AVAILABLE_TO_PLAY, GI_VB_USE_CUSTOM_CAMERA, + + GI_VB_PLAY_TRANSITION_CS, + GI_VB_TATL_INTERUPT_MSG3, + GI_VB_TATL_INTERUPT_MSG6 } GIVanillaBehavior; #ifdef __cplusplus diff --git a/mm/src/code/z_demo.c b/mm/src/code/z_demo.c index 769b9498c..e15b2f021 100644 --- a/mm/src/code/z_demo.c +++ b/mm/src/code/z_demo.c @@ -1573,7 +1573,15 @@ void Cutscene_HandleEntranceTriggers(PlayState* play) { } } +// 2S2H [Enhancements] This is equivalent to Cutscene_HandleConditionalTriggers in OoT. It's unused normally, but we +// use it for VB. In VB changing *should to false has no effect, but you instead modify the entrance & cutsceneIndex to +// override the behavior. void func_800EDDB0(PlayState* play) { + LUSLOG_INFO("Cutscene_HandleConditionalTriggers: entrance: %d, cutsceneIndex: 0x%X", gSaveContext.save.entrance, gSaveContext.save.cutsceneIndex); + + if (!GameInteractor_Should(GI_VB_PLAY_TRANSITION_CS, true, NULL)) { + return; + } } void func_800EDDBC(UNK_TYPE arg0, UNK_TYPE arg1) { diff --git a/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c b/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c index 57cbaada3..6be333215 100644 --- a/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c +++ b/mm/src/overlays/actors/ovl_Elf_Msg3/z_elf_msg3.c @@ -6,6 +6,7 @@ #include "z_elf_msg3.h" #include "overlays/actors/ovl_En_Elf/z_en_elf.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_10) @@ -104,11 +105,11 @@ void func_80A2CF7C(ElfMsg3* this, PlayState* play) { Player* player = GET_PLAYER(play); EnElf* tatl = (EnElf*)player->tatlActor; - if (((((player->tatlActor != NULL) && + if (GameInteractor_Should(GI_VB_TATL_INTERUPT_MSG3, (((((player->tatlActor != NULL) && (fabsf(player->actor.world.pos.x - this->actor.world.pos.x) < (100.0f * this->actor.scale.x))) && (this->actor.world.pos.y <= player->actor.world.pos.y)) && ((player->actor.world.pos.y - this->actor.world.pos.y) < (100.0f * this->actor.scale.y))) && - (fabsf(player->actor.world.pos.z - this->actor.world.pos.z) < (100.0f * this->actor.scale.z))) { + (fabsf(player->actor.world.pos.z - this->actor.world.pos.z) < (100.0f * this->actor.scale.z))), this)) { player->tatlTextId = func_80A2CF50(this); CutsceneManager_Queue(CS_ID_GLOBAL_TALK); tatl->elfMsg = &this->actor; diff --git a/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c b/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c index 7f144ad53..f5f36eeab 100644 --- a/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c +++ b/mm/src/overlays/actors/ovl_Elf_Msg6/z_elf_msg6.c @@ -6,6 +6,7 @@ #include "z_elf_msg6.h" #include "overlays/actors/ovl_En_Elf/z_en_elf.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_10) @@ -236,8 +237,8 @@ void ElfMsg6_Destroy(Actor* thisx, PlayState* play) { } s32 func_80BA1C00(ElfMsg6* this) { - return (this->actor.xzDistToPlayer < (100.0f * this->actor.scale.x)) && - ((this->actor.playerHeightRel >= 0.0f) && (this->actor.playerHeightRel < (100.0f * this->actor.scale.y))); + return GameInteractor_Should(GI_VB_TATL_INTERUPT_MSG6, ((this->actor.xzDistToPlayer < (100.0f * this->actor.scale.x)) && + ((this->actor.playerHeightRel >= 0.0f) && (this->actor.playerHeightRel < (100.0f * this->actor.scale.y)))), this); } void func_80BA1C88(ElfMsg6* this, PlayState* play, s16 arg2) { diff --git a/mm/src/overlays/actors/ovl_En_Kakasi/z_en_kakasi.h b/mm/src/overlays/actors/ovl_En_Kakasi/z_en_kakasi.h index 689e475b2..bb65a8c86 100644 --- a/mm/src/overlays/actors/ovl_En_Kakasi/z_en_kakasi.h +++ b/mm/src/overlays/actors/ovl_En_Kakasi/z_en_kakasi.h @@ -1,7 +1,9 @@ #ifndef Z_EN_KAKASI_H #define Z_EN_KAKASI_H +#ifndef __cplusplus #include "global.h" +#endif #include "z64snap.h" struct EnKakasi; @@ -46,4 +48,7 @@ typedef struct EnKakasi { #define KAKASI_GET_ABOVE_GROUND(thisx) ((thisx)->params & 0x1) #define KAKASI_GET_TARGETMODE(thisx) ((thisx)->world.rot.x - 1) +// 2S2H [Enhancements] Externed for time savers +void EnKakasi_DancingNightAway(EnKakasi* thisx, PlayState* play); + #endif // Z_EN_KAKASI_H