From d865c82f760eecbaca9355af01f9b23bffc5de72 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 13 Apr 2026 18:08:05 -0400 Subject: [PATCH] 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();