From 992634ad468944f04a8f972e34e975568afc5a3c Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Mon, 25 Nov 2024 09:41:59 -0600 Subject: [PATCH] Add better song of double time enhancement --- mm/2s2h/BenGui/SearchableMenuItems.h | 4 + mm/2s2h/Enhancements/Enhancements.cpp | 1 + mm/2s2h/Enhancements/Graphics/3DSClock.cpp | 2 +- .../Songs/BetterSongOfDoubleTime.cpp | 111 ++++++++++++++++++ mm/2s2h/Enhancements/Songs/Songs.h | 1 + mm/2s2h/GameInteractor/GameInteractor.h | 1 + mm/src/code/z_message.c | 12 +- 7 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 mm/2s2h/Enhancements/Songs/BetterSongOfDoubleTime.cpp diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index de72461f2..43ee67fc8 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1287,6 +1287,10 @@ void AddEnhancements() { "Eliminates the Cooldown between Blast Mask usage.", WIDGET_CVAR_CHECKBOX } }, // Song Enhancements { { .widgetName = "Ocarina", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Better Song of Double Time", "gEnhancements.Songs.BetterSongOfDoubleTime", + "When playing the Song of Double Time, you can now choose the exact time you want to go to, similar to " + "the 3DS version.", + WIDGET_CVAR_CHECKBOX }, { "Enable Sun's Song", "gEnhancements.Songs.EnableSunsSong", "Enables the partially implemented Sun's Song. RIGHT-DOWN-UP-RIGHT-DOWN-UP to play it. " "This song will make time move very fast until either Link moves to a different scene, " diff --git a/mm/2s2h/Enhancements/Enhancements.cpp b/mm/2s2h/Enhancements/Enhancements.cpp index 52ce348ea..21691df74 100644 --- a/mm/2s2h/Enhancements/Enhancements.cpp +++ b/mm/2s2h/Enhancements/Enhancements.cpp @@ -61,6 +61,7 @@ void InitEnhancements() { RegisterFierceDeityPutaway(); // Songs + RegisterBetterSongOfDoubleTime(); RegisterEnableSunsSong(); RegisterFasterSongPlayback(); RegisterPauseOwlWarp(); diff --git a/mm/2s2h/Enhancements/Graphics/3DSClock.cpp b/mm/2s2h/Enhancements/Graphics/3DSClock.cpp index ba5abb48e..86a79a626 100644 --- a/mm/2s2h/Enhancements/Graphics/3DSClock.cpp +++ b/mm/2s2h/Enhancements/Graphics/3DSClock.cpp @@ -77,7 +77,7 @@ void Register3DSClock() { static s32 sFinalHoursIntro = 0; - sThreeDayClockAlpha = gPlayState->interfaceCtx.aAlpha; + sThreeDayClockAlpha = gPlayState->interfaceCtx.bAlpha; OPEN_DISPS(gPlayState->state.gfxCtx); s16 posX = 160; diff --git a/mm/2s2h/Enhancements/Songs/BetterSongOfDoubleTime.cpp b/mm/2s2h/Enhancements/Songs/BetterSongOfDoubleTime.cpp new file mode 100644 index 000000000..84bada991 --- /dev/null +++ b/mm/2s2h/Enhancements/Songs/BetterSongOfDoubleTime.cpp @@ -0,0 +1,111 @@ +#include +#include "2s2h/GameInteractor/GameInteractor.h" +#include "spdlog/spdlog.h" + +extern "C" { +#include "macros.h" +#include "assets/interface/week_static/week_static.h" +extern PlayState* gPlayState; +extern SaveContext gSaveContext; +} + +static bool activelyChangingTime = false; +static u32 originalTime = CLOCK_TIME(0, 0); +static u32 originalDay = 0; + +extern void UpdateGameTime(u16 gameTime); + +const u32 INTERVAL = (CLOCK_TIME_MINUTE * 30); + +static const char* sDoWeekTableCopy[] = { + gClockDay1stTex, + gClockDay2ndTex, + gClockDayFinalTex, +}; + +static HOOK_ID onPlayerUpdateHookId = 0; + +void OnPlayerUpdate(Actor* actor) { + if (!activelyChangingTime) { + GameInteractor::Instance->UnregisterGameHookForID(onPlayerUpdateHookId); + return; + } + + gPlayState->interfaceCtx.bAlpha = 255; + + Input* input = &gPlayState->state.input[0]; + + // Pressing B should cancel the song + if (CHECK_BTN_ALL(input->press.button, BTN_B)) { + Audio_PlaySfx_MessageCancel(); + gPlayState->msgCtx.ocarinaMode = OCARINA_MODE_END; + activelyChangingTime = false; + + gSaveContext.save.day = originalDay; + UpdateGameTime(originalTime); + Interface_NewDay(gPlayState, CURRENT_DAY); + // This may have happened in the UpdateGameTime function, if there was a day/night difference, but + // we need to ensure it happens regardless because the day may have changed even if the time is the same + gPlayState->numSetupActors = ABS(gPlayState->numSetupActors); + // Load environment values for new day + func_800FEAF4(&gPlayState->envCtx); + } + + // Pressing A should confirm the song + if (CHECK_BTN_ALL(input->press.button, BTN_A)) { + Audio_PlaySfx_MessageDecide(); + gPlayState->msgCtx.ocarinaMode = OCARINA_MODE_END; + activelyChangingTime = false; + + gSaveContext.save.eventDayCount = CURRENT_DAY; + } + + // Analog stick should change the time + if (input->cur.stick_x > 0) { // Advance time + u16 newTime = CLAMP(gSaveContext.save.time + INTERVAL, 0, + (gSaveContext.save.day == 3 && gSaveContext.save.time < CLOCK_TIME(6, 0)) + ? (CLOCK_TIME(6, 0) - CLOCK_TIME_HOUR) + : INFINITY); + if (newTime > CLOCK_TIME(6, 0) && gSaveContext.save.time < CLOCK_TIME(6, 0)) { + gSaveContext.save.day = CLAMP(gSaveContext.save.day + 1, originalDay, 3); + Interface_NewDay(gPlayState, CURRENT_DAY); + func_800FEAF4(&gPlayState->envCtx); + } + UpdateGameTime(newTime); + } else if (input->cur.stick_x < 0) { // Reverse time + u16 newTime = CLAMP(gSaveContext.save.time - INTERVAL, + (gSaveContext.save.day == originalDay && + ((gSaveContext.save.time > CLOCK_TIME(6, 0) && originalTime > CLOCK_TIME(6, 0)) || + (gSaveContext.save.time < CLOCK_TIME(6, 0) && originalTime < CLOCK_TIME(6, 0)))) + ? originalTime + : 0, + INFINITY); + if (newTime < CLOCK_TIME(6, 0) && gSaveContext.save.time > CLOCK_TIME(6, 0)) { + gSaveContext.save.day = CLAMP(gSaveContext.save.day - 1, originalDay, 3); + Interface_NewDay(gPlayState, CURRENT_DAY); + func_800FEAF4(&gPlayState->envCtx); + } + UpdateGameTime(newTime); + } +} + +void RegisterBetterSongOfDoubleTime() { + GameInteractor::Instance->RegisterGameHook([](s8 sceneId, s8 spawnNum) { + // In case we didn't properly reset this variable + activelyChangingTime = false; + originalTime = CLOCK_TIME(0, 0); + originalDay = 0; + }); + + REGISTER_VB_SHOULD(VB_DISPLAY_SONG_OF_DOUBLE_TIME_PROMPT, { + if (CVarGetInteger("gEnhancements.Songs.BetterSongOfDoubleTime", 0)) { + *should = false; + gPlayState->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_DOUBLE_TIME; + activelyChangingTime = true; + originalTime = gSaveContext.save.time; + originalDay = gSaveContext.save.day; + + onPlayerUpdateHookId = GameInteractor::Instance->RegisterGameHookForID(ACTOR_PLAYER, OnPlayerUpdate); + } + }); +} diff --git a/mm/2s2h/Enhancements/Songs/Songs.h b/mm/2s2h/Enhancements/Songs/Songs.h index d4df3cc88..24e49496c 100644 --- a/mm/2s2h/Enhancements/Songs/Songs.h +++ b/mm/2s2h/Enhancements/Songs/Songs.h @@ -1,6 +1,7 @@ #ifndef SONGS_H #define SONGS_H +void RegisterBetterSongOfDoubleTime(); void RegisterEnableSunsSong(); void RegisterFasterSongPlayback(); void RegisterZoraEggCount(); diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index d097a625d..9a60374a3 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -74,6 +74,7 @@ typedef enum { VB_TRANSFORM_THUNDER_MATRIX, VB_PLAY_HEART_CONTAINER_GET_FANFARE, VB_BE_HOOKSHOT_SURFACE, + VB_DISPLAY_SONG_OF_DOUBLE_TIME_PROMPT, } GIVanillaBehavior; typedef enum { diff --git a/mm/src/code/z_message.c b/mm/src/code/z_message.c index 68d1fa5e7..0081bb5e7 100644 --- a/mm/src/code/z_message.c +++ b/mm/src/code/z_message.c @@ -6025,12 +6025,14 @@ void Message_Update(PlayState* play) { } else if (sLastPlayedSong == OCARINA_SONG_DOUBLE_TIME) { if (interfaceCtx->restrictions.songOfDoubleTime == 0) { if ((CURRENT_DAY != 3) || (gSaveContext.save.isNight == 0)) { - if (gSaveContext.save.isNight) { - Message_StartTextbox(play, D_801D0464[CURRENT_DAY - 1], NULL); - } else { - Message_StartTextbox(play, D_801D045C[CURRENT_DAY - 1], NULL); + if (GameInteractor_Should(VB_DISPLAY_SONG_OF_DOUBLE_TIME_PROMPT, true)) { + if (gSaveContext.save.isNight) { + Message_StartTextbox(play, D_801D0464[CURRENT_DAY - 1], NULL); + } else { + Message_StartTextbox(play, D_801D045C[CURRENT_DAY - 1], NULL); + } + play->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_DOUBLE_TIME; } - play->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_DOUBLE_TIME; } else { Message_StartTextbox(play, 0x1B94, NULL); play->msgCtx.ocarinaMode = OCARINA_MODE_END;