Skip to content

Commit

Permalink
Add better song of double time enhancement (#876)
Browse files Browse the repository at this point in the history
  • Loading branch information
garrettjoecox authored Dec 6, 2024
1 parent 7d3b897 commit 1d2a945
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 6 deletions.
4 changes: 4 additions & 0 deletions mm/2s2h/BenGui/SearchableMenuItems.h
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,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, "
Expand Down
1 change: 1 addition & 0 deletions mm/2s2h/Enhancements/Enhancements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ void InitEnhancements() {
RegisterFierceDeityPutaway();

// Songs
RegisterBetterSongOfDoubleTime();
RegisterEnableSunsSong();
RegisterFasterSongPlayback();
RegisterPauseOwlWarp();
Expand Down
2 changes: 1 addition & 1 deletion mm/2s2h/Enhancements/Graphics/3DSClock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
165 changes: 165 additions & 0 deletions mm/2s2h/Enhancements/Songs/BetterSongOfDoubleTime.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#include <libultraship/bridge.h>
#include "2s2h/GameInteractor/GameInteractor.h"
#include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h"

extern "C" {
#include "variables.h"
#include "functions.h"
#include "assets/interface/week_static/week_static.h"
#include "objects/gameplay_keep/gameplay_keep.h"
extern PlayState* gPlayState;
extern SaveContext gSaveContext;

Gfx* Gfx_DrawTexRect4b(Gfx* gfx, TexturePtr texture, s32 fmt, s16 textureWidth, s16 textureHeight, s16 rectLeft,
s16 rectTop, s16 rectWidth, s16 rectHeight, s32 cms, s32 masks, s32 rects, u16 dsdx, u16 dtdy);
}

static bool activelyChangingTime = false;
static u16 originalTime = CLOCK_TIME(0, 0);
static s32 originalDay = 0;

extern void UpdateGameTime(u16 gameTime);

static const char* sDoWeekTableCopy[] = {
gClockDay1stTex,
gClockDay2ndTex,
gClockDayFinalTex,
};

static HOOK_ID onPlayerUpdateHookId = 0;

void OnPlayerUpdate(Actor* actor) {
if (!activelyChangingTime) {
GameInteractor::Instance->UnregisterGameHookForID<GameInteractor::OnActorUpdate>(onPlayerUpdateHookId);
onPlayerUpdateHookId = 0;
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;
}

u16 INTERVAL = (CLOCK_TIME_MINUTE * 30);
if (CHECK_BTN_ALL(input->cur.button, BTN_Z)) {
INTERVAL = (CLOCK_TIME_MINUTE * 5);
}

// Analog stick should change the time
if (input->cur.stick_x > 0) { // Advance time
u16 newTime = CLAMP(gSaveContext.save.time + INTERVAL, -INT_MAX,
(gSaveContext.save.day == 3 && gSaveContext.save.time < CLOCK_TIME(6, 0))
? (CLOCK_TIME(6, 0) - CLOCK_TIME_HOUR)
: INT_MAX);
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
: -INT_MAX,
INT_MAX);
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 DrawTextRec(f32 x, f32 y, f32 z, s32 s, s32 t, f32 dx, f32 dy) {
OPEN_DISPS(gPlayState->state.gfxCtx);

gDPPipeSync(OVERLAY_DISP++);
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, 255);

f32 w = 8.0f * z;
s32 ulx = (x - w) * 4.0f;
s32 lrx = (x + w) * 4.0f;

f32 h = 12.0f * z;
s32 uly = (y - h) * 4.0f;
s32 lry = (y + h) * 4.0f;

f32 unk = 1024 * (1.0f / z);
s32 dsdx = unk * dx;
s32 dtdy = dy * unk;

gSPTextureRectangle(OVERLAY_DISP++, ulx, uly, lrx, lry, G_TX_RENDERTILE, s, t, dsdx, dtdy);

CLOSE_DISPS(gPlayState->state.gfxCtx);
}

void RegisterBetterSongOfDoubleTime() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](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<GameInteractor::OnActorUpdate>(
ACTOR_PLAYER, OnPlayerUpdate);
}
});

REGISTER_VB_SHOULD(VB_PREVENT_CLOCK_DISPLAY, {
if (!activelyChangingTime) {
return;
}

OPEN_DISPS(gPlayState->state.gfxCtx);
Gfx_SetupDL39_Overlay(gPlayState->state.gfxCtx);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPLoadTextureBlock(OVERLAY_DISP++, gArrowCursorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 24, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
DrawTextRec(53.0f, 191.0f, 1.0f, 0, 0, -1.0f, 1.0f);
DrawTextRec(270.0f, 191.0f, 1.0f, 0, 0, 1.0f, 1.0f);
gDPLoadTextureBlock(OVERLAY_DISP++, gControlStickTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
DrawTextRec(69.0f, 195.0f, 1.0f, 0, 0, -1.0f, 1.0f);
DrawTextRec(254.0f, 195.0f, 1.0f, 0, 0, 1.0f, 1.0f);
CLOSE_DISPS(gPlayState->state.gfxCtx);
});
}
1 change: 1 addition & 0 deletions mm/2s2h/Enhancements/Songs/Songs.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef SONGS_H
#define SONGS_H

void RegisterBetterSongOfDoubleTime();
void RegisterEnableSunsSong();
void RegisterFasterSongPlayback();
void RegisterZoraEggCount();
Expand Down
1 change: 1 addition & 0 deletions mm/2s2h/GameInteractor/GameInteractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ typedef enum {
VB_PLAY_HEART_CONTAINER_GET_FANFARE,
VB_BE_HOOKSHOT_SURFACE,
VB_DEKU_GUARD_SHOW_SEARCH_BALLS,
VB_DISPLAY_SONG_OF_DOUBLE_TIME_PROMPT,
} GIVanillaBehavior;

typedef enum {
Expand Down
12 changes: 7 additions & 5 deletions mm/src/code/z_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -6028,12 +6028,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;
Expand Down

0 comments on commit 1d2a945

Please sign in to comment.