From 48bdaaa3dd5e6a114874b581d5db666ab9e41251 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 13 Apr 2026 10:46:09 -0400 Subject: [PATCH 1/4] Time Stones Feature --- include/d/actor/d_a_obj_wind_stone.h | 3 +++ include/dusk/settings.h | 1 + src/d/actor/d_a_alink_wolf.inc | 29 +++++++++++++++++++----- src/d/actor/d_a_obj_wind_stone.cpp | 13 +++++++++++ src/dusk/imgui/ImGuiFirstRunPreset.cpp | 1 + src/dusk/imgui/ImGuiMenuEnhancements.cpp | 5 ++++ src/dusk/settings.cpp | 2 ++ 7 files changed, 48 insertions(+), 6 deletions(-) diff --git a/include/d/actor/d_a_obj_wind_stone.h b/include/d/actor/d_a_obj_wind_stone.h index f5e52dfc94..7e44cb7108 100644 --- a/include/d/actor/d_a_obj_wind_stone.h +++ b/include/d/actor/d_a_obj_wind_stone.h @@ -27,6 +27,9 @@ public: bool chkEveOccur(); void exeModeHowl(); void exeModeMapDisp(); + #if TARGET_PC + void exeModeSetTime(); + #endif bool chkMapDispMode(); u8 getGoldWolfIdx(); diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 68ea49c752..168c5ca31b 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -47,6 +47,7 @@ struct UserSettings { ConfigVar noMissClimbing; ConfigVar fastTears; ConfigVar instantSaves; + ConfigVar timeStones; // Preferences ConfigVar enableMirrorMode; diff --git a/src/d/actor/d_a_alink_wolf.inc b/src/d/actor/d_a_alink_wolf.inc index 2e38298090..7f4bef7e42 100644 --- a/src/d/actor/d_a_alink_wolf.inc +++ b/src/d/actor/d_a_alink_wolf.inc @@ -3868,12 +3868,7 @@ void daAlink_c::setWolfHowlNotHappen(int param_0) { } int daAlink_c::procWolfHowlDemoInit() { - if (!dComIfGp_event_compulsory(this, NULL, 0xFFFF)) { - return 0; - } - - mDemo.setSpecialDemoType(); - + #if TARGET_PC s16 name; if (field_0x27f4 != NULL) { name = fopAcM_GetName(field_0x27f4); @@ -3881,6 +3876,28 @@ int daAlink_c::procWolfHowlDemoInit() { name = fpcNm_ALINK_e; } + if (name == fpcNm_Obj_WindStone_e && !static_cast(field_0x27f4)->chkEveOccur() && dusk::getSettings().game.timeStones) { + Z2GetSeMgr()->seStart(Z2SE_READ_RIDDLE_B, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + dKy_instant_timechg(0.0f); + return 0; + } + #endif + + if (!dComIfGp_event_compulsory(this, NULL, 0xFFFF)) { + return 0; + } + + mDemo.setSpecialDemoType(); + + #if !TARGET_PC + s16 name; + if (field_0x27f4 != NULL) { + name = fopAcM_GetName(field_0x27f4); + } else { + name = fpcNm_ALINK_e; + } + #endif + if (name == fpcNm_Tag_WaraHowl_e) { shape_angle.y = field_0x27f4->shape_angle.y; current.angle.y = shape_angle.y; diff --git a/src/d/actor/d_a_obj_wind_stone.cpp b/src/d/actor/d_a_obj_wind_stone.cpp index 3158b93848..861b402d06 100644 --- a/src/d/actor/d_a_obj_wind_stone.cpp +++ b/src/d/actor/d_a_obj_wind_stone.cpp @@ -87,6 +87,9 @@ int daWindStone_c::execute() { exeModeMapDisp(); break; case 2: + #if TARGET_PC + exeModeSetTime(); + #endif break; } setModelMtx(); @@ -180,6 +183,16 @@ void daWindStone_c::exeModeMapDisp() { } } +#if TARGET_PC +void daWindStone_c::exeModeSetTime() { + attention_info.flags = 0; + if (!chkEveOccur() && chkWlfInRange() && dusk::getSettings().game.timeStones) { + attention_info.flags |= fopAc_AttnFlag_ETC_e; + attention_info.distances[fopAc_attn_ETC_e] = 65; + } +} +#endif + bool daWindStone_c::chkMapDispMode() { if (fopAcM_isSwitch(this, getSwBit2())) { return false; diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index b73eaff6e6..f42b444ec7 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -37,6 +37,7 @@ static void ApplyPresetDusk() { s.game.instantSaves.setValue(true); s.game.midnasLamentNonStop.setValue(true); s.game.enableFrameInterpolation.setValue(true); + s.game.timeStones.setValue(true); } // ========================================================================= diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index a50ec1ee4c..7827781400 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -63,6 +63,11 @@ namespace dusk { ImGui::SetTooltip("Skip the delay when writing to the Memory Card."); } + config::ImGuiCheckbox("Time Stones", getSettings().game.timeStones); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Allows Wolf Link to use Howling Stones to set the time to midnight."); + } + ImGui::EndMenu(); } diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 9d3d873acc..a1773b1346 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -35,6 +35,7 @@ UserSettings g_userSettings = { .noMissClimbing {"game.noMissClimbing", false}, .fastTears {"game.fastTears", false}, .instantSaves {"game.instantSaves", false}, + .timeStones {"game.timeStones", false}, // Preferences .enableMirrorMode {"game.enableMirrorMode", false}, @@ -111,6 +112,7 @@ void registerSettings() { Register(g_userSettings.game.fastClimbing); Register(g_userSettings.game.fastTears); Register(g_userSettings.game.instantSaves); + Register(g_userSettings.game.timeStones); Register(g_userSettings.game.enableMirrorMode); Register(g_userSettings.game.invertCameraXAxis); Register(g_userSettings.game.enableBloom); From e1844d55da5957c59ebaaa4e7e4107fe403cc128 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 13 Apr 2026 13:03:28 -0400 Subject: [PATCH 2/4] Time Stones now with Song of Time --- include/Z2AudioLib/Z2WolfHowlMgr.h | 4 ++++ src/Z2AudioLib/Z2WolfHowlMgr.cpp | 32 +++++++++++++++++++++++++---- src/d/actor/d_a_alink_wolf.inc | 33 +++++++++++++++--------------- src/d/d_kankyo.cpp | 13 ++++++++++++ 4 files changed, 61 insertions(+), 21 deletions(-) diff --git a/include/Z2AudioLib/Z2WolfHowlMgr.h b/include/Z2AudioLib/Z2WolfHowlMgr.h index 2b2595d1ea..10b746a4c1 100644 --- a/include/Z2AudioLib/Z2WolfHowlMgr.h +++ b/include/Z2AudioLib/Z2WolfHowlMgr.h @@ -39,6 +39,10 @@ enum Z2WolfHowlCurveID { Z2WOLFHOWL_NEWSONG2, Z2WOLFHOWL_NEWSONG3, + #if TARGET_PC + Z2WOLFHOWL_TIMESONG, + #endif + Z2WOLFHOWL_MAX }; diff --git a/src/Z2AudioLib/Z2WolfHowlMgr.cpp b/src/Z2AudioLib/Z2WolfHowlMgr.cpp index 4b546fc54a..5f86b237b6 100644 --- a/src/Z2AudioLib/Z2WolfHowlMgr.cpp +++ b/src/Z2AudioLib/Z2WolfHowlMgr.cpp @@ -115,7 +115,14 @@ static Z2WolfHowlLine sNewSong3[9] = { {HOWL_LINE_MID, 45}, }; -static Z2WolfHowlData sGuideData[9] = { +#if TARGET_PC +static Z2WolfHowlLine sHowlTimeSong[6] = { + {HOWL_LINE_HIGH, 30}, {HOWL_LINE_LOW, 40}, {HOWL_LINE_MID, 30}, + {HOWL_LINE_HIGH, 30}, {HOWL_LINE_LOW, 40}, {HOWL_LINE_MID, 30}, +}; +#endif + +static Z2WolfHowlData sGuideData[9 IF_DUSK(+1)] = { {ARRAY_SIZE(sHowlTobikusa), sHowlTobikusa}, {ARRAY_SIZE(sHowlUmakusa), sHowlUmakusa}, {ARRAY_SIZE(sHowlZeldaSong), sHowlZeldaSong}, @@ -125,6 +132,9 @@ static Z2WolfHowlData sGuideData[9] = { {ARRAY_SIZE(sNewSong1), sNewSong1}, {ARRAY_SIZE(sNewSong2), sNewSong2}, {ARRAY_SIZE(sNewSong3), sNewSong3}, + #if TARGET_PC + {ARRAY_SIZE(sHowlTimeSong), sHowlTimeSong}, + #endif }; Z2WolfHowlMgr::Z2WolfHowlMgr() : JASGlobalInstance(true) { @@ -356,6 +366,11 @@ void Z2WolfHowlMgr::setCorrectData(s8 curveID, Z2WolfHowlData* data) { cPitchCenter = 0.94387f; cPitchDown = 0.74915f; break; + case Z2WOLFHOWL_TIMESONG: + cPitchUp = 1.12246f; + cPitchCenter = 0.94387f; + cPitchDown = 0.74915f; + break; default: cPitchUp = 1.1892f; cPitchCenter = 1.0f; @@ -400,7 +415,7 @@ u8 Z2WolfHowlMgr::getCorrectLineNum() { return 0; } -static JAISoundID sCorrectPhrase[9] = { +static JAISoundID sCorrectPhrase[9 IF_DUSK(+1)] = { Z2BGM_HOWL_TOBIKUSA, Z2BGM_HOWL_UMAKUSA, Z2BGM_HOWL_ZELDASONG, @@ -410,9 +425,12 @@ static JAISoundID sCorrectPhrase[9] = { Z2BGM_NEW_01_HOWL, Z2BGM_NEW_02_HOWL, Z2BGM_NEW_03_HOWL, + #if TARGET_PC + 0xFFFFFFFF, + #endif }; -static JAISoundID sWindStoneSound[9] = { +static JAISoundID sWindStoneSound[9 IF_DUSK(+1)] = { 0xFFFFFFFF, 0xFFFFFFFF, Z2BGM_STONE_ZELDASONG, @@ -422,9 +440,12 @@ static JAISoundID sWindStoneSound[9] = { Z2BGM_NEW_01_STONE, Z2BGM_NEW_02_STONE, Z2BGM_NEW_03_STONE, + #if TARGET_PC + 0xFFFFFFFF, + #endif }; -static JAISoundID sCorrectDuo[9] = { +static JAISoundID sCorrectDuo[9 IF_DUSK(+1)] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, @@ -434,6 +455,9 @@ static JAISoundID sCorrectDuo[9] = { Z2BGM_NEW_01_DUO, Z2BGM_NEW_02_DUO, Z2BGM_NEW_03_DUO, + #if TARGET_PC + 0xFFFFFFFF, + #endif }; s8 Z2WolfHowlMgr::checkLine() { diff --git a/src/d/actor/d_a_alink_wolf.inc b/src/d/actor/d_a_alink_wolf.inc index 7f4bef7e42..ff0755648e 100644 --- a/src/d/actor/d_a_alink_wolf.inc +++ b/src/d/actor/d_a_alink_wolf.inc @@ -3868,35 +3868,18 @@ void daAlink_c::setWolfHowlNotHappen(int param_0) { } int daAlink_c::procWolfHowlDemoInit() { - #if TARGET_PC - s16 name; - if (field_0x27f4 != NULL) { - name = fopAcM_GetName(field_0x27f4); - } else { - name = fpcNm_ALINK_e; - } - - if (name == fpcNm_Obj_WindStone_e && !static_cast(field_0x27f4)->chkEveOccur() && dusk::getSettings().game.timeStones) { - Z2GetSeMgr()->seStart(Z2SE_READ_RIDDLE_B, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); - dKy_instant_timechg(0.0f); - return 0; - } - #endif - if (!dComIfGp_event_compulsory(this, NULL, 0xFFFF)) { return 0; } mDemo.setSpecialDemoType(); - #if !TARGET_PC s16 name; if (field_0x27f4 != NULL) { name = fopAcM_GetName(field_0x27f4); } else { name = fpcNm_ALINK_e; } - #endif if (name == fpcNm_Tag_WaraHowl_e) { shape_angle.y = field_0x27f4->shape_angle.y; @@ -3959,7 +3942,15 @@ int daAlink_c::procWolfHowlDemoInit() { } else if (name == fpcNm_TAG_HOWL_e) { mZ2WolfHowlMgr.setCorrectCurve(static_cast(field_0x27f4)->getCurveID()); } else if (name == fpcNm_Obj_WindStone_e) { + #if TARGET_PC + if (!static_cast(field_0x27f4)->chkEveOccur() && dusk::getSettings().game.timeStones) { + mZ2WolfHowlMgr.setCorrectCurve(9); + } else { + mZ2WolfHowlMgr.setCorrectCurve(static_cast(field_0x27f4)->getTuneId()); + } + #else mZ2WolfHowlMgr.setCorrectCurve(static_cast(field_0x27f4)->getTuneId()); + #endif mProcVar0.field_0x3008 = static_cast(field_0x27f4)->getNextSceneId(); mProcVar4.field_0x3010 = 1; } else if (name == fpcNm_Obj_SmWStone_e) { @@ -4109,6 +4100,14 @@ int daAlink_c::procWolfHowlDemo() { if (checkUnderMove0BckNoArcWolf(WANM_HOWL_END) || isSkipEdge) { if (checkAnmEnd(frameCtrl_p) || isSkipEdge) { if (mProcVar0.mHowlExitID >= 0) { + #if TARGET_PC + if (daAlink_getAlinkActorClass()->getCorrectCurveID() == 9) { + g_env_light.time_change_rate = 1.0f; + dComIfGp_event_reset(); + dCam_getBody()->EndEventCamera(fopAcM_GetID(this)); + return 1; + } + #endif dStage_changeScene(mProcVar0.mHowlExitID, 0.0f, 0, fopAcM_GetRoomNo(this), shape_angle.y, -1); } else { diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index 0bd3db8e2a..60e4d619a4 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -1540,8 +1540,21 @@ void dScnKy_env_light_c::setDaytime() { } if (dComIfGp_roomControl_getTimePass() && !field_0x130a && temp_r29) { + #if TARGET_PC + f32 prev = daytime; + #endif + daytime += time_change_rate; + #if TARGET_PC + if (time_change_rate == 1.0f && + (std::fmod(daytime - 90.0f + 360.0f, 360.0f) < std::fmod(prev - 90.0f + 360.0f, 360.0f) || + std::fmod(daytime - 285.0f + 360.0f, 360.0f) < std::fmod(prev - 285.0f + 360.0f, 360.0f))) + { + g_env_light.time_change_rate = 0.012f; + } + #endif + // Stage is Fishing Pond or Hena's Hut if (!strcmp(dComIfGp_getStartStageName(), "F_SP127") || !strcmp(dComIfGp_getStartStageName(), "R_SP127")) From 71e03f635878952f97a737b363b9c922d2eb7f1e Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 13 Apr 2026 13:05:11 -0400 Subject: [PATCH 3/4] oops forgot a define somewhere --- src/Z2AudioLib/Z2WolfHowlMgr.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Z2AudioLib/Z2WolfHowlMgr.cpp b/src/Z2AudioLib/Z2WolfHowlMgr.cpp index 5f86b237b6..320b861fa8 100644 --- a/src/Z2AudioLib/Z2WolfHowlMgr.cpp +++ b/src/Z2AudioLib/Z2WolfHowlMgr.cpp @@ -366,11 +366,13 @@ void Z2WolfHowlMgr::setCorrectData(s8 curveID, Z2WolfHowlData* data) { cPitchCenter = 0.94387f; cPitchDown = 0.74915f; break; + #if TARGET_PC case Z2WOLFHOWL_TIMESONG: cPitchUp = 1.12246f; cPitchCenter = 0.94387f; cPitchDown = 0.74915f; break; + #endif default: cPitchUp = 1.1892f; cPitchCenter = 1.0f; From 6e542c21cd165664991eb217b84a261de6b6b997 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 13 Apr 2026 18:08:05 -0400 Subject: [PATCH 4/4] Added howling anywhere (R+X) --- include/d/actor/d_a_alink.h | 1 + include/d/actor/d_a_obj_wind_stone.h | 3 -- include/dusk/settings.h | 2 +- src/Z2AudioLib/Z2WolfHowlMgr.cpp | 8 ++-- src/d/actor/d_a_alink_dusk.cpp | 59 ++++++++++++++++++++++++ src/d/actor/d_a_alink_wolf.inc | 35 +++++++------- src/d/actor/d_a_obj_wind_stone.cpp | 13 ------ src/dusk/imgui/ImGuiFirstRunPreset.cpp | 2 +- src/dusk/imgui/ImGuiMenuEnhancements.cpp | 14 ++++-- src/dusk/settings.cpp | 4 +- src/f_ap/f_ap_game.cpp | 6 +++ 11 files changed, 102 insertions(+), 45 deletions(-) diff --git a/include/d/actor/d_a_alink.h b/include/d/actor/d_a_alink.h index b68a4de5a9..53228af84b 100644 --- a/include/d/actor/d_a_alink.h +++ b/include/d/actor/d_a_alink.h @@ -4549,6 +4549,7 @@ public: /* 0x03850 */ daAlink_procFunc mpProcFunc; #if TARGET_PC + void handleWolfHowl(); void handleQuickTransform(); bool checkGyroAimItemContext(); #endif diff --git a/include/d/actor/d_a_obj_wind_stone.h b/include/d/actor/d_a_obj_wind_stone.h index 7e44cb7108..f5e52dfc94 100644 --- a/include/d/actor/d_a_obj_wind_stone.h +++ b/include/d/actor/d_a_obj_wind_stone.h @@ -27,9 +27,6 @@ public: bool chkEveOccur(); void exeModeHowl(); void exeModeMapDisp(); - #if TARGET_PC - void exeModeSetTime(); - #endif bool chkMapDispMode(); u8 getGoldWolfIdx(); diff --git a/include/dusk/settings.h b/include/dusk/settings.h index b6a54d3115..4cda8654b6 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -61,7 +61,7 @@ struct UserSettings { ConfigVar noMissClimbing; ConfigVar fastTears; ConfigVar instantSaves; - ConfigVar timeStones; + ConfigVar sunsSong; // Preferences ConfigVar enableMirrorMode; diff --git a/src/Z2AudioLib/Z2WolfHowlMgr.cpp b/src/Z2AudioLib/Z2WolfHowlMgr.cpp index 320b861fa8..cb4f387a21 100644 --- a/src/Z2AudioLib/Z2WolfHowlMgr.cpp +++ b/src/Z2AudioLib/Z2WolfHowlMgr.cpp @@ -117,8 +117,8 @@ static Z2WolfHowlLine sNewSong3[9] = { #if TARGET_PC static Z2WolfHowlLine sHowlTimeSong[6] = { - {HOWL_LINE_HIGH, 30}, {HOWL_LINE_LOW, 40}, {HOWL_LINE_MID, 30}, - {HOWL_LINE_HIGH, 30}, {HOWL_LINE_LOW, 40}, {HOWL_LINE_MID, 30}, + {HOWL_LINE_MID, 20}, {HOWL_LINE_LOW, 20}, {HOWL_LINE_HIGH, 40}, + {HOWL_LINE_MID, 20}, {HOWL_LINE_LOW, 20}, {HOWL_LINE_HIGH, 40}, }; #endif @@ -368,9 +368,9 @@ void Z2WolfHowlMgr::setCorrectData(s8 curveID, Z2WolfHowlData* data) { break; #if TARGET_PC case Z2WOLFHOWL_TIMESONG: - cPitchUp = 1.12246f; + cPitchUp = 1.259906f; cPitchCenter = 0.94387f; - cPitchDown = 0.74915f; + cPitchDown = 0.840885f; break; #endif default: diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index dbff923a2e..9b937d3678 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -4,6 +4,65 @@ #include "d/d_meter2_draw.h" #include "d/d_meter2_info.h" +void daAlink_c::handleWolfHowl() { + if (checkWolf()) { + if (!dusk::getSettings().game.sunsSong) { + return; + } + + // Check to see if Link has the ability to transform. + if (!dComIfGs_isEventBit(dSv_event_flag_c::M_077)) { + return; + } + + // Ensure there is a proper pointer to the mMeterClass and mpMeterDraw structs in + // g_meter2_info. + const auto meterClassPtr = g_meter2_info.getMeterClass(); + if (!meterClassPtr) { + return; + } + + const auto meterDrawPtr = meterClassPtr->getMeterDrawPtr(); + if (!meterDrawPtr) { + return; + } + + // Ensure that link is not in a cutscene. + if (checkEventRun()) { + Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + return; + } + + mDoCPd_c::getCpadInfo(PAD_1).mPressedButtonFlags = 0; + + // Ensure that the Z Button is not dimmed + if (meterDrawPtr->getButtonZAlpha() != 1.f) { + Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + return; + } + + bool canTransform = false; + + if (mLinkAcch.ChkGroundHit() && !checkModeFlg(MODE_PLAYER_FLY) && !checkMagneBootsOn()) { + if (!checkForestOldCentury()) { + if (checkMidnaRide()) { + if ((checkWolf() && + (checkModeFlg(MODE_UNK_1000) || dComIfGp_checkPlayerStatus0(0, 0x10))) || + (!checkWolf() && + (checkEventRun() || getMidnaActor()->checkMetamorphoseEnable()) && + (checkModeFlg(4) || dComIfGp_checkPlayerStatus0(0, 0x10)))) + { + canTransform = true; + } + } + } + } + + getWolfHowlMgrP()->setCorrectCurve(9); + procWolfHowlDemoInit(); + } +} + void daAlink_c::handleQuickTransform() { if (!dusk::getSettings().game.enableQuickTransform) { return; diff --git a/src/d/actor/d_a_alink_wolf.inc b/src/d/actor/d_a_alink_wolf.inc index ff0755648e..0a6da841c5 100644 --- a/src/d/actor/d_a_alink_wolf.inc +++ b/src/d/actor/d_a_alink_wolf.inc @@ -3942,15 +3942,7 @@ int daAlink_c::procWolfHowlDemoInit() { } else if (name == fpcNm_TAG_HOWL_e) { mZ2WolfHowlMgr.setCorrectCurve(static_cast(field_0x27f4)->getCurveID()); } else if (name == fpcNm_Obj_WindStone_e) { - #if TARGET_PC - if (!static_cast(field_0x27f4)->chkEveOccur() && dusk::getSettings().game.timeStones) { - mZ2WolfHowlMgr.setCorrectCurve(9); - } else { - mZ2WolfHowlMgr.setCorrectCurve(static_cast(field_0x27f4)->getTuneId()); - } - #else mZ2WolfHowlMgr.setCorrectCurve(static_cast(field_0x27f4)->getTuneId()); - #endif mProcVar0.field_0x3008 = static_cast(field_0x27f4)->getNextSceneId(); mProcVar4.field_0x3010 = 1; } else if (name == fpcNm_Obj_SmWStone_e) { @@ -3962,7 +3954,13 @@ int daAlink_c::procWolfHowlDemoInit() { mZ2WolfHowlMgr.setCorrectCurve(-1); } } else { + #if TARGET_PC + if (mZ2WolfHowlMgr.getCorrectCurveID() != 9) { + mZ2WolfHowlMgr.setCorrectCurve(-1); + } + #else mZ2WolfHowlMgr.setCorrectCurve(-1); + #endif } mNormalSpeed = 0.0f; @@ -4100,17 +4098,22 @@ int daAlink_c::procWolfHowlDemo() { if (checkUnderMove0BckNoArcWolf(WANM_HOWL_END) || isSkipEdge) { if (checkAnmEnd(frameCtrl_p) || isSkipEdge) { if (mProcVar0.mHowlExitID >= 0) { - #if TARGET_PC - if (daAlink_getAlinkActorClass()->getCorrectCurveID() == 9) { - g_env_light.time_change_rate = 1.0f; - dComIfGp_event_reset(); - dCam_getBody()->EndEventCamera(fopAcM_GetID(this)); - return 1; - } - #endif dStage_changeScene(mProcVar0.mHowlExitID, 0.0f, 0, fopAcM_GetRoomNo(this), shape_angle.y, -1); } else { + #if TARGET_PC + if (daAlink_getAlinkActorClass()->getCorrectCurveID() == 9) { + if (dComIfGp_roomControl_getTimePass()) { + g_env_light.time_change_rate = 1.0f; + dComIfGp_event_reset(); + dCam_getBody()->EndEventCamera(fopAcM_GetID(this)); + } else { + setWolfHowlNotHappen(isSkipEdge); + } + return 1; + } + #endif + fopAc_ac_c* actor_p = NULL; if (gwolf_p == NULL) { fopAcIt_Executor((fopAcIt_ExecutorFunc)daAlink_searchWolfHowl, diff --git a/src/d/actor/d_a_obj_wind_stone.cpp b/src/d/actor/d_a_obj_wind_stone.cpp index 861b402d06..3158b93848 100644 --- a/src/d/actor/d_a_obj_wind_stone.cpp +++ b/src/d/actor/d_a_obj_wind_stone.cpp @@ -87,9 +87,6 @@ int daWindStone_c::execute() { exeModeMapDisp(); break; case 2: - #if TARGET_PC - exeModeSetTime(); - #endif break; } setModelMtx(); @@ -183,16 +180,6 @@ void daWindStone_c::exeModeMapDisp() { } } -#if TARGET_PC -void daWindStone_c::exeModeSetTime() { - attention_info.flags = 0; - if (!chkEveOccur() && chkWlfInRange() && dusk::getSettings().game.timeStones) { - attention_info.flags |= fopAc_AttnFlag_ETC_e; - attention_info.distances[fopAc_attn_ETC_e] = 65; - } -} -#endif - bool daWindStone_c::chkMapDispMode() { if (fopAcM_isSwitch(this, getSwBit2())) { return false; diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index ec11511c3c..c218185c92 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -39,7 +39,7 @@ static void ApplyPresetDusk() { s.game.instantSaves.setValue(true); s.game.midnasLamentNonStop.setValue(true); s.game.enableFrameInterpolation.setValue(true); - s.game.timeStones.setValue(true); + s.game.sunsSong.setValue(true); s.game.bloomMode.setValue(BloomMode::Dusk); } diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index 7827781400..8c65c97912 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -11,6 +11,15 @@ namespace dusk { if (ImGui::BeginMenu("Enhancements")) { if (ImGui::BeginMenu("Quality of Life")) { config::ImGuiCheckbox("Quick Transform (R+Y)", getSettings().game.enableQuickTransform); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Allows you to quickly transform between forms\n" + "without having to talk to Midna."); + } + + config::ImGuiCheckbox("Sun's Song (R+X)", getSettings().game.sunsSong); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Allows Wolf Link to howl and change the time of day."); + } config::ImGuiCheckbox("Bigger Wallets", getSettings().game.biggerWallets); if (ImGui::IsItemHovered()) { @@ -63,11 +72,6 @@ namespace dusk { ImGui::SetTooltip("Skip the delay when writing to the Memory Card."); } - config::ImGuiCheckbox("Time Stones", getSettings().game.timeStones); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Allows Wolf Link to use Howling Stones to set the time to midnight."); - } - ImGui::EndMenu(); } diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index a6d5037db7..f25825da90 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -35,7 +35,7 @@ UserSettings g_userSettings = { .noMissClimbing {"game.noMissClimbing", false}, .fastTears {"game.fastTears", false}, .instantSaves {"game.instantSaves", false}, - .timeStones {"game.timeStones", false}, + .sunsSong {"game.sunsSong", false}, // Preferences .enableMirrorMode {"game.enableMirrorMode", false}, @@ -112,7 +112,7 @@ void registerSettings() { Register(g_userSettings.game.fastClimbing); Register(g_userSettings.game.fastTears); Register(g_userSettings.game.instantSaves); - Register(g_userSettings.game.timeStones); + Register(g_userSettings.game.sunsSong); Register(g_userSettings.game.enableMirrorMode); Register(g_userSettings.game.invertCameraXAxis); Register(g_userSettings.game.bloomMode); diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index f54ca1edad..84d2ab8e97 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -748,6 +748,12 @@ void fapGm_Execute() { #endif #if TARGET_PC + if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) { + if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { + dynamic_cast(link)->handleWolfHowl(); + } + } + if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigY(PAD_1)) { if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { dynamic_cast(link)->handleQuickTransform();