diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/CutsceneTime.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/CutsceneTime.cpp new file mode 100644 index 0000000000..2f69c93827 --- /dev/null +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/CutsceneTime.cpp @@ -0,0 +1,284 @@ +#include "CutsceneTime.h" + +#include +#include +#include + +#include +#include + +#include "soh/ResourceManagerHelpers.h" +#include "soh/resource/type/Scene.h" +#include "soh/resource/type/scenecommand/SetAlternateHeaders.h" +#include "soh/resource/type/scenecommand/SetCutscenes.h" +#include "soh/resource/type/scenecommand/SetRoomList.h" +#include "soh/resource/type/scenecommand/SetTimeSettings.h" + +extern "C" { +#include "z64.h" +#include "macros.h" +#include "variables.h" +} + +// Misc cutscene command types +enum { + CS_MISC_STOP_CUTSCENE = 12, + CS_MISC_STOP_STORM_AND_ADVANCE_TO_DAY = 18, + CS_MISC_TIME_ADVANCE_TO_NIGHT = 25, + CS_MISC_SUNSSONG_START = 33, + CS_MISC_FREEZE_TIME = 34, +}; + +// Textbox entries with this id show no text +static constexpr uint16_t CS_TEXT_ID_NONE = 0xFFFF; +// Room time settings use this for "not set" +static constexpr uint8_t TIME_SETTING_UNSET = 0xFF; +static constexpr uint16_t SUNS_SONG_TIME_SPEED = 400; + +// Command entry sizes, in 4 byte words +static constexpr int32_t CAMERA_POINT_WORDS = sizeof(CutsceneCameraPoint) / sizeof(CutsceneData); +// CS_CMD_09 and set time entries are the same size as textboxes +static constexpr int32_t TEXTBOX_WORDS = sizeof(CsCmdTextbox) / sizeof(CutsceneData); +static constexpr int32_t ACTOR_CUE_WORDS = sizeof(CsCmdActorCue) / sizeof(CutsceneData); + +static SOH::Scene* LoadScene(const std::string& path) { + return (SOH::Scene*)Ship::Context::GetRawInstance()->GetResourceManager()->LoadResource(path).get(); +} + +template static T* FindCommand(SOH::Scene* scene, SOH::SceneCommandID id) { + for (auto& cmd : scene->commands) { + if (cmd->cmdId == id) { + return (T*)cmd.get(); + } + } + return nullptr; +} + +// Same header pick as Scene_CommandAlternateHeaderList +static SOH::Scene* LayerHeader(SOH::Scene* scene, int32_t sceneLayer) { + auto headers = FindCommand(scene, SOH::SceneCommandID::SetAlternateHeaders); + if (headers == nullptr || sceneLayer - 1 >= (int32_t)headers->headers.size()) { + return nullptr; + } + return headers->headers[sceneLayer - 1].get(); +} + +// Same path as OTRPlay_SpawnScene +static std::string ScenePath(int32_t sceneNum) { + std::string version = "shared"; + if ((sceneNum >= SCENE_DEKU_TREE && sceneNum <= SCENE_ICE_CAVERN) || sceneNum == SCENE_GERUDO_TRAINING_GROUND || + sceneNum == SCENE_INSIDE_GANONS_CASTLE) { + version = ResourceMgr_IsGameMasterQuest() ? "mq" : "nonmq"; + } + const char* file = gSceneTable[sceneNum].sceneFile.fileName; + return "scenes/" + version + "/" + file + "/" + file; +} + +static bool IsNight(uint16_t time) { + return time > CLOCK_TIME(18, 0) || time < CLOCK_TIME(6, 30); +} + +// Sun's Song speeds time up to the next of these +static bool IsSunsSongDay(uint16_t time) { + return time >= CLOCK_TIME(6, 30) && time <= CLOCK_TIME(18, 0) + 1; +} + +struct CutsceneTimeScript { + std::vector misc; + std::vector textboxes; + std::vector setTimes; + int32_t lastFrame = 0; +}; + +// Walks the command list the same way as Cutscene_ProcessCommands, keeping only what touches the clock +static CutsceneTimeScript ReadScript(const uint32_t* data) { + CutsceneTimeScript script; + int32_t totalEntries = data[0]; + script.lastFrame = data[1]; + const uint32_t* ptr = data + 2; + + for (int32_t i = 0; i < totalEntries; i++) { + int32_t cmdType = *ptr++; + if (cmdType == CS_CMD_STOP) { + break; + } + + switch (cmdType) { + case CS_CMD_CAM_EYE: + case CS_CMD_CAM_EYE_REL_TO_PLAYER: + case CS_CMD_CAM_AT: + case CS_CMD_CAM_AT_REL_TO_PLAYER: { + ptr += 2; + bool more = true; + while (more) { + more = ((CutsceneCameraPoint*)ptr)->continueFlag != CS_CMD_STOP; + ptr += CAMERA_POINT_WORDS; + } + break; + } + case CS_CMD_07: + case CS_CMD_08: + ptr += 6; + break; + case CS_CMD_TERMINATOR: + script.lastFrame = ((CsCmdBase*)(ptr + 1))->startFrame; + ptr += 3; + break; + case CS_CMD_SCENE_TRANS_FX: + ptr += 3; + break; + case CS_CMD_TEXTBOX: + case CS_CMD_09: + case CS_CMD_SETTIME: { + int32_t entries = *ptr++; + for (int32_t j = 0; j < entries; j++, ptr += TEXTBOX_WORDS) { + if (cmdType == CS_CMD_TEXTBOX && ((CsCmdBase*)ptr)->base != CS_TEXT_ID_NONE) { + script.textboxes.push_back(*(CsCmdBase*)ptr); + } else if (cmdType == CS_CMD_SETTIME) { + script.setTimes.push_back(*(CsCmdDayTime*)ptr); + } + } + break; + } + default: { + int32_t entries = *ptr++; + for (int32_t j = 0; j < entries; j++, ptr += ACTOR_CUE_WORDS) { + if (cmdType == CS_CMD_MISC) { + CsCmdBase* cmd = (CsCmdBase*)ptr; + script.misc.push_back(*cmd); + if (cmd->base == CS_MISC_STOP_CUTSCENE) { + script.lastFrame = std::min(script.lastFrame, (int32_t)cmd->startFrame); + } + } + } + break; + } + } + } + + return script; +} + +// Runs the cutscene frame by frame, starting from the given time and time speed +static uint16_t RunScript(const uint32_t* data, uint16_t dayTime, uint16_t timeSpeed, int32_t fadeInFrames, + const CutsceneTimeActorUpdate& actorUpdate) { + uint16_t roomTimeSpeed = timeSpeed; + CutsceneTimeScript script = ReadScript(data); + bool night = IsNight(dayTime); + bool sunsSongStarted = false; + bool sunsSongSpeeding = false; + bool sunsSongToDusk = false; + uint16_t sunsSongPrevSpeed = 0; + + // csCtx->frames starts at 0xFFFF and ticks before commands run, so commands start on frame 0. + // Frame 0 is counted as paused by the fade in check. + for (int32_t frame = 0; frame <= script.lastFrame; frame++) { + if (actorUpdate) { + actorUpdate(dayTime, timeSpeed); + } + + // func_80064824, only the cases that touch the clock + for (auto& cmd : script.misc) { + if (frame < cmd.startFrame || (frame >= cmd.endFrame && cmd.endFrame != cmd.startFrame)) { + continue; + } + switch (cmd.base) { + case CS_MISC_STOP_STORM_AND_ADVANCE_TO_DAY: + if (dayTime < CLOCK_TIME(7, 0)) { + dayTime += 30; + } + break; + case CS_MISC_TIME_ADVANCE_TO_NIGHT: + dayTime += 30; + if (dayTime > CLOCK_TIME(19, 0) - 1) { + dayTime = CLOCK_TIME(19, 0) - 1; + } + break; + case CS_MISC_SUNSSONG_START: + sunsSongStarted = true; + break; + case CS_MISC_FREEZE_TIME: + dayTime -= night ? timeSpeed * 2 : timeSpeed; + break; + } + } + + // func_80065134 + for (auto& cmd : script.setTimes) { + if (frame == cmd.startFrame) { + s16 hours = (s16)((cmd.hour * 60.0f) / (360.0f / 0x4000)); + s16 minutes = (s16)((cmd.minute + 1) / (360.0f / 0x4000)); + dayTime = hours + minutes; + } + } + + // Sun's Song handling in Interface_Update + if (sunsSongStarted && roomTimeSpeed != 0) { + if (!sunsSongSpeeding) { + sunsSongToDusk = IsSunsSongDay(dayTime); + sunsSongSpeeding = true; + sunsSongPrevSpeed = timeSpeed; + timeSpeed = SUNS_SONG_TIME_SPEED; + } else if (sunsSongToDusk ? dayTime > CLOCK_TIME(18, 0) + 1 : IsSunsSongDay(dayTime)) { + sunsSongStarted = sunsSongSpeeding = false; + timeSpeed = sunsSongPrevSpeed; + } + } + + // Environment_Update pauses time during the fade in and while a textbox is up. + // A textbox is up after its start frame, and the cutscene stalls on its end frame until it closes. + bool paused = frame <= fadeInFrames; + for (auto& cmd : script.textboxes) { + paused |= frame > cmd.startFrame && frame < cmd.endFrame; + } + if (!paused) { + dayTime += night && timeSpeed < SUNS_SONG_TIME_SPEED ? timeSpeed * 2 : timeSpeed; + } + night = IsNight(dayTime); + } + + return dayTime; +} + +uint16_t CutsceneTime_Simulate(int32_t sceneNum, uint16_t cutsceneIndex, uint16_t dayTime, int32_t fadeInFrames, + const CutsceneTimeActorUpdate& actorUpdate) { + int32_t sceneLayer = SCENE_LAYER_CUTSCENE_FIRST + (cutsceneIndex & 0xF); + SOH::Scene* scene = LoadScene(ScenePath(sceneNum)); + SOH::Scene* layer = scene != nullptr ? LayerHeader(scene, sceneLayer) : nullptr; + auto cutscene = + layer != nullptr ? FindCommand(layer, SOH::SceneCommandID::SetCutscenes) : nullptr; + auto rooms = FindCommand(scene, SOH::SceneCommandID::SetRoomList); + if (cutscene == nullptr || rooms == nullptr || rooms->fileNames.empty()) { + return dayTime; + } + + // Room time settings, as in Scene_CommandTimeSettings. Assumes the cutscene starts in the first room. + uint16_t timeSpeed = 0; + SOH::Scene* room = LoadScene(rooms->fileNames[0]); + SOH::Scene* roomLayer = room != nullptr ? LayerHeader(room, sceneLayer) : nullptr; + auto timeSettings = roomLayer != nullptr + ? FindCommand(roomLayer, SOH::SceneCommandID::SetTimeSettings) + : nullptr; + if (timeSettings != nullptr) { + auto& settings = timeSettings->settings; + if (settings.hour != TIME_SETTING_UNSET && settings.minute != TIME_SETTING_UNSET) { + dayTime = (uint16_t)(((settings.hour + (settings.minute / 60.0f)) * 60.0f) / ((f32)(24 * 60) / 0x10000)); + } + timeSpeed = settings.timeIncrement != TIME_SETTING_UNSET ? settings.timeIncrement : 0; + } + + return RunScript(cutscene->cutscene->commands.data(), dayTime, timeSpeed, fadeInFrames, actorUpdate); +} + +uint16_t CutsceneTime_SimulateScript(const void* cutscene, uint16_t dayTime, uint16_t timeSpeed, int32_t fadeInFrames, + const CutsceneTimeActorUpdate& actorUpdate) { + // Same lookup as Cutscene_ProcessCommands + char* data = (char*)cutscene; + if (ResourceMgr_OTRSigCheck(data)) { + data = (char*)ResourceMgr_LoadCSByName(data); + } + if (data == nullptr) { + return dayTime; + } + return RunScript((const uint32_t*)data, dayTime, timeSpeed, fadeInFrames, actorUpdate); +} diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/CutsceneTime.h b/soh/soh/Enhancements/TimeSavers/SkipCutscene/CutsceneTime.h new file mode 100644 index 0000000000..a76e6a42f3 --- /dev/null +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/CutsceneTime.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +// Stands in for actors that change the time during a cutscene. Runs each frame before the cutscene commands. +using CutsceneTimeActorUpdate = std::function; + +// Simulate cutscene's time of day, returning dayTime at end. +// fadeInFrames is how many frames time stays paused while the scene fades in. +uint16_t CutsceneTime_Simulate(int32_t sceneNum, uint16_t cutsceneIndex, uint16_t dayTime, int32_t fadeInFrames, + const CutsceneTimeActorUpdate& actorUpdate = nullptr); + +// Same for a cutscene an actor starts in the current scene, which keeps the scene's time speed. +// cutscene is the csCtx.segment the actor would have set. +uint16_t CutsceneTime_SimulateScript(const void* cutscene, uint16_t dayTime, uint16_t timeSpeed, + int32_t fadeInFrames = 0, const CutsceneTimeActorUpdate& actorUpdate = nullptr); diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipOwlTravel.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipOwlTravel.cpp index ff6b150679..90086ca6e0 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipOwlTravel.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipOwlTravel.cpp @@ -2,6 +2,7 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/randomizer/randomizer_entrance.h" +#include "soh/Enhancements/TimeSavers/SkipCutscene/CutsceneTime.h" #include "soh/ShipInit.hpp" #include @@ -9,8 +10,11 @@ extern "C" { #include "z64.h" #include "z64save.h" #include "z64scene.h" +#include "scenes/overworld/spot06/spot06_scene.h" +#include "scenes/overworld/spot16/spot16_scene.h" extern PlayState* gPlayState; extern SaveContext gSaveContext; +extern u16 gTimeSpeed; u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); } @@ -42,6 +46,11 @@ static s16 GetEntranceIndex(s32 owlType) { } static void SkipOwlTravel(s32 owlType) { + // Time keeps running during the flight + const char* cutscene = owlType == 7 ? gLakeHyliaOwlCs : gDMTOwlCs; + gSaveContext.dayTime = gSaveContext.skyboxTime = + CutsceneTime_SimulateScript(cutscene, gSaveContext.dayTime, gTimeSpeed); + gPlayState->nextEntranceIndex = GetEntranceIndex(owlType); gPlayState->transitionTrigger = TRANS_TRIGGER_START; gPlayState->transitionType = TRANS_TYPE_FADE_BLACK; diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipZeldaFleeingCastle.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipZeldaFleeingCastle.cpp index 9f4d17bf8a..6c2f4a4b73 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipZeldaFleeingCastle.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/Story/SkipZeldaFleeingCastle.cpp @@ -1,6 +1,7 @@ #include #include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/TimeSavers/SkipCutscene/CutsceneTime.h" #include "soh/ShipInit.hpp" extern "C" { @@ -48,6 +49,18 @@ void SkipZeldaFleeingCastle_OnActorInit(void* actorPtr) { } } +// BgSpot00Hanebasi_Update swaps the room's time speed for one that reaches dawn by the end, then stops time at dawn. +// Walking in late at night picks a speed too low to reach morning, and time can end up barely moving at all. +static void HanebasiTime(uint16_t& dayTime, uint16_t& timeSpeed) { + if (timeSpeed == 50) { + int32_t dawn = dayTime >= 0xD557 ? 0x1D556 : 0xD556; + timeSpeed = static_cast((dawn - dayTime) * (1.0f / 350.0f)); + } + if (dayTime >= 0x2AAC && dayTime < 0x3000) { + timeSpeed = 0; + } +} + void RegisterSkipZeldaFleeingCastle() { COND_ID_HOOK(OnActorInit, ACTOR_ITEM_OCARINA, CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO), @@ -55,7 +68,8 @@ void RegisterSkipZeldaFleeingCastle() { 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.dayTime = gSaveContext.skyboxTime = + CutsceneTime_Simulate(SCENE_HYRULE_FIELD, 0xFFF1, gSaveContext.dayTime, 7, HanebasiTime); gSaveContext.cutsceneIndex = 0; *should = false; diff --git a/soh/soh/Enhancements/TimeSavers/timesaver_hook_handlers.cpp b/soh/soh/Enhancements/TimeSavers/timesaver_hook_handlers.cpp index bd6efb6db6..6167206bcd 100644 --- a/soh/soh/Enhancements/TimeSavers/timesaver_hook_handlers.cpp +++ b/soh/soh/Enhancements/TimeSavers/timesaver_hook_handlers.cpp @@ -2,6 +2,7 @@ #include #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/Enhancements/TimeSavers/SkipCutscene/CutsceneTime.h" #include "soh/Enhancements/enhancementTypes.h" #include "soh/Enhancements/randomizer/SeedContext.h" #include "soh/Enhancements/randomizer/randomizer_entrance.h" @@ -35,8 +36,10 @@ extern "C" { #include "src/overlays/actors/ovl_Obj_Lightswitch/z_obj_lightswitch.h" #include "src/overlays/actors/ovl_Bg_Jya_Bombchuiwa/z_bg_jya_bombchuiwa.h" #include +#include "scenes/overworld/spot06/spot06_scene.h" extern SaveContext gSaveContext; extern PlayState* gPlayState; +extern u16 gTimeSpeed; extern int32_t D_8011D3AC; extern void BgSpot03Taki_HandleWaterfallState(BgSpot03Taki* bgSpot03Taki, PlayState* play); @@ -222,6 +225,7 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li case VB_PLAY_ENTRANCE_CS: { s32 entranceFlag = va_arg(args, s32); s32 entranceIndex = va_arg(args, s32); + void* cutscene = va_arg(args, void*); // Epona LLR fence jump cutscenes not skipped to allow the player and epona to load in the world correctly // Nabooru fight cutscene is handled by boss intro skip instead (which deals with other flags needing to be @@ -229,6 +233,12 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Entrances"), IS_RANDO) && (entranceFlag != EVENTCHKINF_EPONA_OBTAINED) && entranceIndex != ENTR_SPIRIT_TEMPLE_BOSS_ENTRANCE) { *should = false; + // Time keeps running during the cutscene in fields. + // Left alone elsewhere, as the scene has already snapped skyboxTime. + uint16_t dayTime = CutsceneTime_SimulateScript(cutscene, gSaveContext.dayTime, gTimeSpeed); + if (dayTime != gSaveContext.dayTime) { + gSaveContext.dayTime = gSaveContext.skyboxTime = dayTime; + } // Check for dispulsion of Ganon's Tower barrier switch (entranceIndex) { @@ -633,7 +643,10 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li } else { gPlayState->nextEntranceIndex = ENTR_HYRULE_FIELD_17; } - gSaveContext.dayTime = gSaveContext.skyboxTime = 0x8000; + // Normally set in Impa's escort cutscene, which keeps the time and lets it run. + // Its fade in is a slow circle, 50 frames. + gSaveContext.dayTime = gSaveContext.skyboxTime = + CutsceneTime_Simulate(SCENE_HYRULE_FIELD, 0xFFF8, gSaveContext.dayTime, 50); gPlayState->transitionType = TRANS_TYPE_FADE_WHITE; gPlayState->transitionTrigger = TRANS_TRIGGER_START; gSaveContext.nextTransitionType = 2; @@ -680,9 +693,8 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.LearnSong"), IS_RANDO) || IS_RANDO) { *should = false; Flags_SetEventChkInf(EVENTCHKINF_LEARNED_SUNS_SONG); - // SoH [Randomizer] TODO: Increment time X amount (find out X) - // When time is 0, it's changed to 0x46A7 - // When it's 0x8000, it's changed to 0xC090 + gSaveContext.dayTime = gSaveContext.skyboxTime = + CutsceneTime_Simulate(SCENE_GRAVEYARD, 0xFFF1, gSaveContext.dayTime, 11); } break; case VB_PLAY_ROYAL_FAMILY_TOMB_CS: { @@ -733,6 +745,9 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li case VB_PLAY_FIRE_ARROW_CS: { if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { *should = false; + // Cutscene sets the time to 7:00 + gSaveContext.dayTime = gSaveContext.skyboxTime = + CutsceneTime_SimulateScript(gLakeHyliaFireArrowsCS, gSaveContext.dayTime, gTimeSpeed); } break; } diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 41e82e5853..81e6edddc5 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -2160,9 +2160,11 @@ typedef enum { // ##### In `z_demo.c`: // - `int32_t` (entranceCutscene->flag) (promoted from `uint8_t` by va_arg) // - `int32_t` (entranceCutscene->entrance) (promoted from `uint16_t` by va_arg) + // - `void*` (entranceCutscene->segAddr) // ##### In `z_bg_breakwall.c` and `z_bg_toki_swd.c`: // - `int32_t` (EVENTCHKINF) // - `int32_t` (gSaveContext.entranceIndex) + // - `void*` (cutscene) VB_PLAY_ENTRANCE_CS, // #### `result` diff --git a/soh/src/code/z_demo.c b/soh/src/code/z_demo.c index 0ca8f6a3e7..9e990c2227 100644 --- a/soh/src/code/z_demo.c +++ b/soh/src/code/z_demo.c @@ -2203,7 +2203,8 @@ void Cutscene_HandleEntranceTriggers(PlayState* play) { (gSaveContext.cutsceneIndex < 0xFFF0) && ((u8)gSaveContext.linkAge == requiredAge) && (gSaveContext.respawnFlag <= 0)) { Flags_SetEventChkInf(entranceCutscene->flag); - if (GameInteractor_Should(VB_PLAY_ENTRANCE_CS, true, entranceCutscene->flag, entranceCutscene->entrance)) { + if (GameInteractor_Should(VB_PLAY_ENTRANCE_CS, true, entranceCutscene->flag, entranceCutscene->entrance, + entranceCutscene->segAddr)) { Cutscene_SetSegment(play, entranceCutscene->segAddr); gSaveContext.cutsceneTrigger = 2; gSaveContext.showTitleCard = false; diff --git a/soh/src/overlays/actors/ovl_Bg_Breakwall/z_bg_breakwall.c b/soh/src/overlays/actors/ovl_Bg_Breakwall/z_bg_breakwall.c index 1942f5d5aa..50983de98b 100644 --- a/soh/src/overlays/actors/ovl_Bg_Breakwall/z_bg_breakwall.c +++ b/soh/src/overlays/actors/ovl_Bg_Breakwall/z_bg_breakwall.c @@ -254,7 +254,7 @@ void BgBreakwall_Wait(BgBreakwall* this, PlayState* play) { if ((wallType == BWALL_DC_ENTRANCE) && (!Flags_GetEventChkInf(EVENTCHKINF_ENTERED_DODONGOS_CAVERN))) { Flags_SetEventChkInf(EVENTCHKINF_ENTERED_DODONGOS_CAVERN); if (GameInteractor_Should(VB_PLAY_ENTRANCE_CS, true, EVENTCHKINF_ENTERED_DODONGOS_CAVERN, - gSaveContext.entranceIndex)) { + gSaveContext.entranceIndex, gDcOpeningCs)) { Cutscene_SetSegment(play, gDcOpeningCs); gSaveContext.cutsceneTrigger = 1; Player_SetCsActionWithHaltedActors(play, NULL, 0x31); diff --git a/soh/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd.c b/soh/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd.c index 28104539e9..e0175e9103 100644 --- a/soh/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd.c +++ b/soh/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd.c @@ -118,7 +118,7 @@ void func_808BAF40(BgTokiSwd* this, PlayState* play) { Actor_IsFacingAndNearPlayer(&this->actor, 800.0f, 0x7530) && !Play_InCsMode(play)) { Flags_SetEventChkInf(EVENTCHKINF_ENTERED_MASTER_SWORD_CHAMBER); if (GameInteractor_Should(VB_PLAY_ENTRANCE_CS, true, EVENTCHKINF_ENTERED_MASTER_SWORD_CHAMBER, - gSaveContext.entranceIndex)) { + gSaveContext.entranceIndex, D_808BBD90)) { play->csCtx.segment = D_808BBD90; gSaveContext.cutsceneTrigger = 1; }