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/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/dusk/settings.h b/include/dusk/settings.h index 8e57b9db99..7381ccafe5 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -61,6 +61,7 @@ struct UserSettings { ConfigVar noMissClimbing; ConfigVar fastTears; ConfigVar instantSaves; + ConfigVar sunsSong; // Preferences ConfigVar enableMirrorMode; diff --git a/src/Z2AudioLib/Z2WolfHowlMgr.cpp b/src/Z2AudioLib/Z2WolfHowlMgr.cpp index 4b546fc54a..cb4f387a21 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_MID, 20}, {HOWL_LINE_LOW, 20}, {HOWL_LINE_HIGH, 40}, + {HOWL_LINE_MID, 20}, {HOWL_LINE_LOW, 20}, {HOWL_LINE_HIGH, 40}, +}; +#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,13 @@ void Z2WolfHowlMgr::setCorrectData(s8 curveID, Z2WolfHowlData* data) { cPitchCenter = 0.94387f; cPitchDown = 0.74915f; break; + #if TARGET_PC + case Z2WOLFHOWL_TIMESONG: + cPitchUp = 1.259906f; + cPitchCenter = 0.94387f; + cPitchDown = 0.840885f; + break; + #endif default: cPitchUp = 1.1892f; cPitchCenter = 1.0f; @@ -400,7 +417,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 +427,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 +442,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 +457,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_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 2e38298090..0a6da841c5 100644 --- a/src/d/actor/d_a_alink_wolf.inc +++ b/src/d/actor/d_a_alink_wolf.inc @@ -3954,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; @@ -4095,6 +4101,19 @@ int daAlink_c::procWolfHowlDemo() { 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/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")) diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index 99c77dac70..c218185c92 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -39,6 +39,7 @@ static void ApplyPresetDusk() { s.game.instantSaves.setValue(true); s.game.midnasLamentNonStop.setValue(true); s.game.enableFrameInterpolation.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 a50ec1ee4c..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()) { diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 4a4f6186f0..0c2f02c129 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}, + .sunsSong {"game.sunsSong", false}, // Preferences .enableMirrorMode {"game.enableMirrorMode", false}, @@ -113,6 +114,7 @@ void registerSettings() { Register(g_userSettings.game.fastClimbing); Register(g_userSettings.game.fastTears); Register(g_userSettings.game.instantSaves); + 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();