Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement] Fast Song Playback #550

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions mm/2s2h/BenGui/BenMenuBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,8 @@ void DrawEnhancementsMenu() {
{ .tooltip = "Enables using the Dpad for Ocarina playback." });
UIWidgets::CVarCheckbox("Prevent Dropped Ocarina Inputs", "gEnhancements.Playback.NoDropOcarinaInput",
{ .tooltip = "Prevent dropping inputs when playing the ocarina quickly" });
UIWidgets::CVarCheckbox("Faster song playbacks", "gEnhancements.Playback.FastSongPlayback",
{ .tooltip = "Makes song playback faster" });

ImGui::EndMenu();
}
Expand Down
20 changes: 17 additions & 3 deletions mm/src/code/z_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -4025,7 +4025,13 @@ void Message_SpawnSongEffect(PlayState* play) {
(msgCtx->songPlayed != OCARINA_SONG_GORON_LULLABY_INTRO) &&
!((msgCtx->ocarinaAction >= OCARINA_ACTION_PROMPT_WIND_FISH_HUMAN) &&
(msgCtx->ocarinaAction <= OCARINA_ACTION_PROMPT_WIND_FISH_DEKU))) {
msgCtx->ocarinaSongEffectActive = true;
if (CVarGetInteger(
"gEnhancements.Playback.FastSongPlayback",
0)) { // Set to false to allow subsequent ocarina actions without considering this effect as active
msgCtx->ocarinaSongEffectActive = false;
} else {
msgCtx->ocarinaSongEffectActive = true;
}
if (msgCtx->songPlayed != OCARINA_SONG_SCARECROW_SPAWN) {
Actor_Spawn(&play->actorCtx, play, sOcarinaEffectActorIds[msgCtx->songPlayed], player->actor.world.pos.x,
player->actor.world.pos.y, player->actor.world.pos.z, 0, 0, 0,
Expand Down Expand Up @@ -4765,7 +4771,10 @@ void Message_DrawMain(PlayState* play, Gfx** gfxP) {
AudioOcarina_SetPlaybackSong(msgCtx->ocarinaAction - OCARINA_ACTION_SCARECROW_LONG_RECORDING, 1);
} else {
AudioOcarina_SetInstrument(sPlayerFormOcarinaInstruments[CUR_FORM]);
AudioOcarina_SetPlaybackSong((u8)msgCtx->songPlayed + 1, 1);
if (!CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0)) { // Skips the visual note playback after playing a song
AudioOcarina_SetPlaybackSong((u8)msgCtx->songPlayed + 1, 1);
}
if (msgCtx->songPlayed != OCARINA_SONG_SCARECROW_SPAWN) {
Audio_PlayFanfareWithPlayerIOPort7((u16)sOcarinaSongFanfares[msgCtx->songPlayed],
(u8)sOcarinaSongFanfareIoData[CUR_FORM]);
Expand All @@ -4791,7 +4800,12 @@ void Message_DrawMain(PlayState* play, Gfx** gfxP) {
}
Message_Decode(play);
msgCtx->msgMode = MSGMODE_16;
msgCtx->stateTimer = 20;
if (CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0)) { // Speeds up the time it shows the song name after playback
msgCtx->stateTimer = 1;
} else {
msgCtx->stateTimer = 20;
}
Message_DrawText(play, &gfx);
break;

Expand Down
18 changes: 12 additions & 6 deletions mm/src/overlays/actors/ovl_Eff_Change/z_eff_change.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ void EffChange_Init(Actor* thisx, PlayState* play) {
Keyframe_FlexPlayOnce(&this->skeletonInfo, gGameplayKeepKFAnim_281DC);
this->step = 0;
this->actor.shape.rot.y = 0;
this->skeletonInfo.frameCtrl.speed = (2.0f / 3.0f);
this->skeletonInfo.frameCtrl.speed =
(2.0f / 3.0f) + (CVarGetInteger("gEnhancements.Playback.FastSongPlayback", 0)
? 1.0f
: 0.0f); // Speeds up the spawning of the statue to ensure it keeps the switch pressed down
CutsceneManager_Queue(CS_ID_GLOBAL_ELEGY);
}

Expand Down Expand Up @@ -110,11 +113,14 @@ void func_80A4C5CC(EffChange* this, PlayState* play) {
phi_fv0 = 0.0f;
}
Environment_AdjustLights(play, phi_fv0, 850.0f, 0.2f, 0.0f);
if (CutsceneManager_GetCurrentCsId() != CS_ID_GLOBAL_ELEGY) {
if (CutsceneManager_IsNext(CS_ID_GLOBAL_ELEGY)) {
CutsceneManager_Start(CS_ID_GLOBAL_ELEGY, &this->actor);
} else {
CutsceneManager_Queue(CS_ID_GLOBAL_ELEGY);
if (!CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0)) { // skips the elegy cutscene, allowing you to instanly move away from the statue
if (CutsceneManager_GetCurrentCsId() != CS_ID_GLOBAL_ELEGY) {
if (CutsceneManager_IsNext(CS_ID_GLOBAL_ELEGY)) {
CutsceneManager_Start(CS_ID_GLOBAL_ELEGY, &this->actor);
} else {
CutsceneManager_Queue(CS_ID_GLOBAL_ELEGY);
}
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions mm/src/overlays/actors/ovl_En_Test6/z_en_test6.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,12 @@ void EnTest6_InvertedSoTCutscene(EnTest6* this, PlayState* play) {
subCam = Play_GetCamera(play, this->subCamId);
mainCam = Play_GetCamera(play, CAM_ID_MAIN);

// Check if fast song playback is enabled and skip the cutscene if true
if (CVarGetInteger("gEnhancements.Playback.FastSongPlayback", 0)) {
EnTest6_StopInvertedSoTCutscene(this, play);
return;
}

// Update cutscene effects
switch (this->cueId) {
case SOTCS_CUEID_INV_INIT:
Expand Down Expand Up @@ -727,6 +733,12 @@ void EnTest6_DoubleSoTCutscene(EnTest6* this, PlayState* play) {
s16 subCamId;
s16 pad2;

// Check if fast song playback is enabled and skip the cutscene if true
if (CVarGetInteger("gEnhancements.Playback.FastSongPlayback", 0)) {
EnTest6_StopDoubleSoTCutscene(this, play);
return;
}

if (this->timer > 115) {
this->doubleSoTEnvLerp += 0.2f;
EnTest6_EnableWhiteFillScreen(play, this->doubleSoTEnvLerp);
Expand Down
18 changes: 16 additions & 2 deletions mm/src/overlays/actors/ovl_En_Test7/z_en_test7.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,12 @@ void EnTest7_Init(Actor* thisx, PlayState* play2) {
if (ENTEST7_GET(&this->actor) == ENTEST7_MINUS1) {
func_80AF082C(this, func_80AF2938);
EnTest7_SetupAction(this, NULL);
} else if (CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0)) { // Skips the wings cutscene for song of soaring. Must be below previous lines or
// warping to entrance of temples will warp to Mayors Residence instead
func_80AF082C(this, func_80AF2350);
EnTest7_SetupAction(this, NULL);
Audio_PlayBgm_StorePrevBgm(NA_BGM_SONG_OF_SOARING);
} else {
func_80AF082C(this, func_80AF19A8);
EnTest7_SetupAction(this, func_80AF2854);
Expand Down Expand Up @@ -766,7 +772,10 @@ void func_80AF2938(EnTest7* this, PlayState* play) {
player->stateFlags2 |= PLAYER_STATE2_20000000;
this->unk_144 |= 2;
this->unk_148.unk_04 = 30.0f;
if (play->roomCtx.curRoom.behaviorType1 != ROOM_BEHAVIOR_TYPE1_1) {
if ((play->roomCtx.curRoom.behaviorType1 != ROOM_BEHAVIOR_TYPE1_1) &&
(!CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0))) { // When CVar is true, it will play the temple entrance spawning cutscene instead of the
// longer overworld one
func_80AF082C(this, func_80AF2AE8);
} else {
func_80AF082C(this, func_80AF2EC8);
Expand Down Expand Up @@ -884,7 +893,12 @@ void func_80AF2EC8(EnTest7* this, PlayState* play) {
subCam = Play_GetCamera(play, CutsceneManager_GetCurrentSubCamId(play->playerCsIds[PLAYER_CS_ID_SONG_WARP]));
this->subCamEye = subCam->eye;
this->subCamAt = subCam->at;
this->unk_1E54 = 40;
if (CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0)) { // Skips part of the feather animation when you spawn in
this->unk_1E54 = 60;
} else {
this->unk_1E54 = 40;
}

func_80AF2DB4(this, play);
}
Expand Down
6 changes: 5 additions & 1 deletion mm/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,11 @@ void EnTorch2_Update(Actor* thisx, PlayState* play) {
CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base);
targetAlpha = 255;
}
Math_StepToS(&this->alpha, targetAlpha, 8);
Math_StepToS(&this->alpha, targetAlpha,
8 + (CVarGetInteger("gEnhancements.Playback.FastSongPlayback", 0)
? 56
: 0)); // speeds up the speed of which the elegy statue becomes solid. Also needed to
// ensure it keeps the switches pushed down.
}
}

Expand Down
34 changes: 19 additions & 15 deletions mm/src/overlays/actors/ovl_Oceff_Storm/z_oceff_storm.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,26 +205,30 @@ void OceffStorm_Draw(Actor* thisx, PlayState* play) {
Vtx* vtxPtr = ResourceMgr_LoadVtxByName(sSongOfStormsCylinderVtx);
// #endregion

OPEN_DISPS(play->state.gfxCtx);

Gfx_SetupDL25_Xlu(play->state.gfxCtx);
if (!CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0)) { // Prevents the beam of light around Link from drawing, as it will awkwardly stay in place
// when the player moves.
OPEN_DISPS(play->state.gfxCtx);

gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 255, 200, 255);
gDPSetEnvColor(POLY_XLU_DISP++, 150, 150, 0, 128);
gDPSetAlphaDither(POLY_XLU_DISP++, G_AD_NOISE);
gDPSetColorDither(POLY_XLU_DISP++, G_CD_NOISE);
Gfx_SetupDL25_Xlu(play->state.gfxCtx);

vtxPtr[0].v.cn[3] = vtxPtr[6].v.cn[3] = vtxPtr[16].v.cn[3] = vtxPtr[25].v.cn[3] = this->vtxAlpha >> 1;
vtxPtr[10].v.cn[3] = vtxPtr[22].v.cn[3] = this->vtxAlpha;
gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 255, 255, 200, 255);
gDPSetEnvColor(POLY_XLU_DISP++, 150, 150, 0, 128);
gDPSetAlphaDither(POLY_XLU_DISP++, G_AD_NOISE);
gDPSetColorDither(POLY_XLU_DISP++, G_CD_NOISE);

gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
vtxPtr[0].v.cn[3] = vtxPtr[6].v.cn[3] = vtxPtr[16].v.cn[3] = vtxPtr[25].v.cn[3] = this->vtxAlpha >> 1;
vtxPtr[10].v.cn[3] = vtxPtr[22].v.cn[3] = this->vtxAlpha;

gSPDisplayList(POLY_XLU_DISP++, &sSongOfStormsCylinderMaterialDL);
gSPDisplayList(POLY_XLU_DISP++, Gfx_TwoTexScroll(play->state.gfxCtx, G_TX_RENDERTILE, scroll * 4, (0 - scroll) * 8,
32, 32, 1, scroll * 8, (0 - scroll) * 12, 32, 32));
gSPDisplayList(POLY_XLU_DISP++, &sSongOfStormsCylinderModelDL);
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);

CLOSE_DISPS(play->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, &sSongOfStormsCylinderMaterialDL);
gSPDisplayList(POLY_XLU_DISP++,
Gfx_TwoTexScroll(play->state.gfxCtx, G_TX_RENDERTILE, scroll * 4, (0 - scroll) * 8, 32, 32, 1,
scroll * 8, (0 - scroll) * 12, 32, 32));
gSPDisplayList(POLY_XLU_DISP++, &sSongOfStormsCylinderModelDL);

CLOSE_DISPS(play->state.gfxCtx);
}
OceffStorm_Draw2(&this->actor, play);
}
3 changes: 2 additions & 1 deletion mm/src/overlays/actors/ovl_Oceff_Wipe5/z_oceff_wipe5.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ void OceffWipe5_Destroy(Actor* thisx, PlayState* play) {

void OceffWipe5_Update(Actor* thisx, PlayState* play) {
OceffWipe5* this = THIS;
s32 fastPlayback = CVarGetInteger("gEnhancements.Playback.FastSongPlayback", 0);

this->actor.world.pos = GET_ACTIVE_CAM(play)->eye;
if (this->counter < 100) {
this->counter++;
this->counter += fastPlayback ? 2 : 1; // Speeds up the ocarina effect
} else {
Actor_Kill(&this->actor);
}
Expand Down
36 changes: 32 additions & 4 deletions mm/src/overlays/actors/ovl_player_actor/z_player.c
Original file line number Diff line number Diff line change
Expand Up @@ -13468,7 +13468,12 @@ void func_80848640(PlayState* play, Player* this) {
Math_Vec3f_Copy(&torch2->actor.home.pos, &this->actor.world.pos);
torch2->actor.home.rot.y = this->actor.shape.rot.y;
torch2->state = 0;
torch2->framesUntilNextState = 20;
if (CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0)) { // Speeds up the spawning of the elegy statue
torch2->framesUntilNextState = 1;
} else {
torch2->framesUntilNextState = 20;
}
} else {
torch2 = (EnTorch2*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_TORCH2, this->actor.world.pos.x,
this->actor.world.pos.y, this->actor.world.pos.z, 0, this->actor.shape.rot.y, 0,
Expand Down Expand Up @@ -17107,13 +17112,28 @@ void Player_Action_63(Player* this, PlayState* play) {
(play->msgCtx.ocarinaMode == OCARINA_MODE_APPLY_INV_SOT_SLOW)) {
if (play->msgCtx.ocarinaMode == OCARINA_MODE_APPLY_SOT) {
if (!func_8082DA90(play)) {
if (gSaveContext.save.saveInfo.playerData.threeDayResetCount == 1) {
if (CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0)) { // Ensures proper time reset whenever fast playback is active. Probably
// a better way to do this.
play->nextEntrance = ENTRANCE(SOUTH_CLOCK_TOWN, 0);
gSaveContext.save.timeSpeedOffset = 0;
gSaveContext.save.eventDayCount = 0;
gSaveContext.save.day = 0;
gSaveContext.save.time = CLOCK_TIME(6, 0) - 1;

} else if (gSaveContext.save.saveInfo.playerData.threeDayResetCount == 1) {
play->nextEntrance = ENTRANCE(CUTSCENE, 1);
} else {
play->nextEntrance = ENTRANCE(CUTSCENE, 0);
}

gSaveContext.nextCutsceneIndex = 0xFFF7;
if (CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0)) { // Ensures the player spawns back at the door of the clock tower when
// fast playback is active.
gSaveContext.nextCutsceneIndex = 0;
} else {
gSaveContext.nextCutsceneIndex = 0xFFF7;
}
play->transitionTrigger = TRANS_TRIGGER_START;
}
} else {
Expand Down Expand Up @@ -18395,7 +18415,15 @@ void Player_Action_87(Player* this, PlayState* play) {
}

void Player_Action_88(Player* this, PlayState* play) {
if (this->av2.actionVar2++ > 90) {
if (CVarGetInteger("gEnhancements.Playback.FastSongPlayback",
0)) { // Speeds up the ocarina waiting timer, allowing the player to move sooner
if (this->av2.actionVar2++ > 1) {
play->msgCtx.ocarinaMode = OCARINA_MODE_END;
func_8085B384(this, play);
} else if (this->av2.actionVar2 == 1) {
func_80848640(play, this);
}
} else if (this->av2.actionVar2++ > 90) {
play->msgCtx.ocarinaMode = OCARINA_MODE_END;
func_8085B384(this, play);
} else if (this->av2.actionVar2 == 10) {
Expand Down
Loading