From 31c5397ae348502a2e1d02d13a5834f0faa277ab Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Wed, 15 Apr 2026 14:36:20 -0400 Subject: [PATCH 01/24] Gamepad Color Implementation --- include/d/actor/d_a_alink.h | 1 + src/d/actor/d_a_alink_dusk.cpp | 107 +++++++++++++++++++++++++++++++++ src/f_ap/f_ap_game.cpp | 4 ++ 3 files changed, 112 insertions(+) diff --git a/include/d/actor/d_a_alink.h b/include/d/actor/d_a_alink.h index 53228af84b..786c0a4555 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 handleGamepadColor(); void handleWolfHowl(); void handleQuickTransform(); bool checkGyroAimItemContext(); diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index 9b937d3678..b081ff1ce8 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -4,6 +4,113 @@ #include "d/d_meter2_draw.h" #include "d/d_meter2_info.h" +cXyz currentGamepadColor = {0, 0, 0}; +cXyz finalGamepadColor = {0, 0, 0}; +float lerpSpeed = 0.0f; +const cXyz duskColor = {30, 30, -30}; + +const cXyz heartColor1 = {255, 0, 0}; +const cXyz heartColor2 = {155, 5, 5}; +const cXyz heartColor3 = {55, 5, 5}; + +float lerp(float a, float b, float t) { + return a + t * (b - a); +} + +cXyz LerpColor(cXyz a, cXyz b, float t) { + return {lerp(a.x, b.x, t), lerp(a.y, b.y, t), lerp(a.z, b.z, t)}; +} + +void FadeLED(cXyz newColor, float speed) { + finalGamepadColor = newColor; + lerpSpeed = speed / 30.0f; +} + +void SetLED(cXyz newColor) { + currentGamepadColor = newColor; + finalGamepadColor = newColor; +} + +void AddGamepadCurrentColor(cXyz addColor) { + finalGamepadColor.x += addColor.x; + finalGamepadColor.y += addColor.y; + finalGamepadColor.z += addColor.z; +} + +void daAlink_c::handleGamepadColor() { + bool setColor = false; + + fopAc_ac_c* zhint = dComIfGp_att_getZHint(); + if (zhint != NULL) { + FadeLED({50, 50, 175}, 2.0f); + setColor = true; + } + + u8 linkHp = Z2GetLink()->getLinkHp(); + if (linkHp <= 2) { + FadeLED(heartColor1, 2.0f); + setColor = true; + } else if (linkHp <= 4) { + FadeLED(heartColor2, 2.0f); + setColor = true; + } else if (linkHp <= 6) { + FadeLED(heartColor3, 2.0f); + setColor = true; + } + + if (!setColor) { + if (checkWolf()) { + FadeLED({115, 115, 75}, 5.0f); + setColor = true; + } else { + switch (dComIfGs_getSelectEquipClothes()) { + case dItemNo_WEAR_KOKIRI_e: + FadeLED({0, 100, 0}, 5.0f); + setColor = true; + break; + case dItemNo_WEAR_ZORA_e: + FadeLED({0, 0, 100}, 5.0f); + setColor = true; + break; + case dItemNo_ARMOR_e: + if (checkMagicArmorHeavy()) { + FadeLED({5, 100, 100}, 5.0f); + } else { + FadeLED({100, 0, 5}, 5.0f); + } + setColor = true; + break; + default: + FadeLED({235, 230, 115}, 5.0f); + setColor = true; + break; + } + } + } + + if (dKy_darkworld_check()) { + AddGamepadCurrentColor(duskColor); + } + + if (finalGamepadColor.x > 255) + finalGamepadColor.x = 255; + if (finalGamepadColor.x < 0) + finalGamepadColor.x = 0; + + if (finalGamepadColor.y > 255) + finalGamepadColor.y = 255; + if (finalGamepadColor.y < 0) + finalGamepadColor.y = 0; + + if (finalGamepadColor.z > 255) + finalGamepadColor.z = 255; + if (finalGamepadColor.z < 0) + finalGamepadColor.z = 0; + + currentGamepadColor = LerpColor(currentGamepadColor, finalGamepadColor, lerpSpeed); + PADSetColor(PAD_1, (u8)currentGamepadColor.x, (u8)currentGamepadColor.y, (u8)currentGamepadColor.z); +} + void daAlink_c::handleWolfHowl() { if (checkWolf()) { if (!dusk::getSettings().game.sunsSong) { diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 84d2ab8e97..9150d764c7 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -748,6 +748,10 @@ void fapGm_Execute() { #endif #if TARGET_PC + if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { + dynamic_cast(link)->handleGamepadColor(); + } + 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(); From 4466bf4e123569685b7c110306b4db89af645829 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Wed, 22 Apr 2026 13:00:35 -0400 Subject: [PATCH 02/24] wip --- src/d/actor/d_a_alink_dusk.cpp | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index b081ff1ce8..b35daf445f 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -5,9 +5,10 @@ #include "d/d_meter2_info.h" cXyz currentGamepadColor = {0, 0, 0}; +cXyz currentGamepadFlashColor = {0, 0, 0}; cXyz finalGamepadColor = {0, 0, 0}; float lerpSpeed = 0.0f; -const cXyz duskColor = {30, 30, -30}; +const cXyz duskColor = {45, 45, -45}; const cXyz heartColor1 = {255, 0, 0}; const cXyz heartColor2 = {155, 5, 5}; @@ -46,18 +47,21 @@ void daAlink_c::handleGamepadColor() { setColor = true; } - u8 linkHp = Z2GetLink()->getLinkHp(); - if (linkHp <= 2) { - FadeLED(heartColor1, 2.0f); - setColor = true; - } else if (linkHp <= 4) { - FadeLED(heartColor2, 2.0f); - setColor = true; - } else if (linkHp <= 6) { - FadeLED(heartColor3, 2.0f); - setColor = true; + if (!checkEventRun()) { + u8 linkHp = Z2GetLink()->getLinkHp(); + if (linkHp <= 2) { + FadeLED(heartColor1, 2.0f); + setColor = true; + } else if (linkHp <= 4) { + FadeLED(heartColor2, 2.0f); + setColor = true; + } else if (linkHp <= 6) { + FadeLED(heartColor3, 2.0f); + setColor = true; + } } + if (!setColor) { if (checkWolf()) { FadeLED({115, 115, 75}, 5.0f); @@ -92,6 +96,8 @@ void daAlink_c::handleGamepadColor() { AddGamepadCurrentColor(duskColor); } + AddGamepadCurrentColor(currentGamepadFlashColor); + if (finalGamepadColor.x > 255) finalGamepadColor.x = 255; if (finalGamepadColor.x < 0) @@ -108,7 +114,8 @@ void daAlink_c::handleGamepadColor() { finalGamepadColor.z = 0; currentGamepadColor = LerpColor(currentGamepadColor, finalGamepadColor, lerpSpeed); - PADSetColor(PAD_1, (u8)currentGamepadColor.x, (u8)currentGamepadColor.y, (u8)currentGamepadColor.z); + PADSetColor(PAD_CHAN0, (u8)currentGamepadColor.x, (u8)currentGamepadColor.y, + (u8)currentGamepadColor.z); } void daAlink_c::handleWolfHowl() { From f916a48db0d2d143daa3f55183856bb7950609d3 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Wed, 22 Apr 2026 13:36:06 -0400 Subject: [PATCH 03/24] optimized code and removed bugs --- include/d/actor/d_a_alink.h | 1 - src/d/actor/d_a_alink_dusk.cpp | 114 --------------------------------- src/f_ap/f_ap_game.cpp | 108 ++++++++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 118 deletions(-) diff --git a/include/d/actor/d_a_alink.h b/include/d/actor/d_a_alink.h index ed4f7f59bc..9980ab776f 100644 --- a/include/d/actor/d_a_alink.h +++ b/include/d/actor/d_a_alink.h @@ -4549,7 +4549,6 @@ public: /* 0x03850 */ daAlink_procFunc mpProcFunc; #if TARGET_PC - void handleGamepadColor(); void handleWolfHowl(); void handleQuickTransform(); bool checkGyroAimContext(); diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index 85bc12b21c..0f442aff94 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -4,120 +4,6 @@ #include "d/d_meter2_draw.h" #include "d/d_meter2_info.h" -cXyz currentGamepadColor = {0, 0, 0}; -cXyz currentGamepadFlashColor = {0, 0, 0}; -cXyz finalGamepadColor = {0, 0, 0}; -float lerpSpeed = 0.0f; -const cXyz duskColor = {45, 45, -45}; - -const cXyz heartColor1 = {255, 0, 0}; -const cXyz heartColor2 = {155, 5, 5}; -const cXyz heartColor3 = {55, 5, 5}; - -float lerp(float a, float b, float t) { - return a + t * (b - a); -} - -cXyz LerpColor(cXyz a, cXyz b, float t) { - return {lerp(a.x, b.x, t), lerp(a.y, b.y, t), lerp(a.z, b.z, t)}; -} - -void FadeLED(cXyz newColor, float speed) { - finalGamepadColor = newColor; - lerpSpeed = speed / 30.0f; -} - -void SetLED(cXyz newColor) { - currentGamepadColor = newColor; - finalGamepadColor = newColor; -} - -void AddGamepadCurrentColor(cXyz addColor) { - finalGamepadColor.x += addColor.x; - finalGamepadColor.y += addColor.y; - finalGamepadColor.z += addColor.z; -} - -void daAlink_c::handleGamepadColor() { - bool setColor = false; - - fopAc_ac_c* zhint = dComIfGp_att_getZHint(); - if (zhint != NULL) { - FadeLED({50, 50, 175}, 2.0f); - setColor = true; - } - - if (!checkEventRun()) { - u8 linkHp = Z2GetLink()->getLinkHp(); - if (linkHp <= 2) { - FadeLED(heartColor1, 2.0f); - setColor = true; - } else if (linkHp <= 4) { - FadeLED(heartColor2, 2.0f); - setColor = true; - } else if (linkHp <= 6) { - FadeLED(heartColor3, 2.0f); - setColor = true; - } - } - - - if (!setColor) { - if (checkWolf()) { - FadeLED({115, 115, 75}, 5.0f); - setColor = true; - } else { - switch (dComIfGs_getSelectEquipClothes()) { - case dItemNo_WEAR_KOKIRI_e: - FadeLED({0, 100, 0}, 5.0f); - setColor = true; - break; - case dItemNo_WEAR_ZORA_e: - FadeLED({0, 0, 100}, 5.0f); - setColor = true; - break; - case dItemNo_ARMOR_e: - if (checkMagicArmorHeavy()) { - FadeLED({5, 100, 100}, 5.0f); - } else { - FadeLED({100, 0, 5}, 5.0f); - } - setColor = true; - break; - default: - FadeLED({235, 230, 115}, 5.0f); - setColor = true; - break; - } - } - } - - if (dKy_darkworld_check()) { - AddGamepadCurrentColor(duskColor); - } - - AddGamepadCurrentColor(currentGamepadFlashColor); - - if (finalGamepadColor.x > 255) - finalGamepadColor.x = 255; - if (finalGamepadColor.x < 0) - finalGamepadColor.x = 0; - - if (finalGamepadColor.y > 255) - finalGamepadColor.y = 255; - if (finalGamepadColor.y < 0) - finalGamepadColor.y = 0; - - if (finalGamepadColor.z > 255) - finalGamepadColor.z = 255; - if (finalGamepadColor.z < 0) - finalGamepadColor.z = 0; - - currentGamepadColor = LerpColor(currentGamepadColor, finalGamepadColor, lerpSpeed); - PADSetColor(PAD_CHAN0, (u8)currentGamepadColor.x, (u8)currentGamepadColor.y, - (u8)currentGamepadColor.z); -} - void daAlink_c::handleWolfHowl() { if (checkWolf()) { if (!dusk::getSettings().game.sunsSong) { diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 3610f270a3..9550cee06e 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -733,10 +733,112 @@ static void fapGm_AfterRecord() { fapGm_After(); } -static void duskExecute() { - if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { - dynamic_cast(link)->handleGamepadColor(); +cXyz currentGamepadColor = {0, 0, 0}; +cXyz finalGamepadColor = {0, 0, 0}; +cXyz additionalGamepadColor = {0, 0, 0}; + +float lerpSpeed = 0.0f; + +const cXyz duskColor = {50, 50, -50}; +const cXyz noColor = {0, 0, 0}; + +float lerp(float a, float b, float t) { + return a + t * (b - a); +} + +cXyz LerpColor(cXyz a, cXyz b, float t) { + return {lerp(a.x, b.x, t), lerp(a.y, b.y, t), lerp(a.z, b.z, t)}; +} + +void FadeLED(cXyz newColor, float speed) { + finalGamepadColor = newColor; + lerpSpeed = speed / 30.0f; +} + +void SetLED(cXyz newColor) { + currentGamepadColor = newColor; + finalGamepadColor = newColor; +} + +void SetGamepadAdditionalColor(cXyz addColor) { + additionalGamepadColor.x = addColor.x; + additionalGamepadColor.y = addColor.y; + additionalGamepadColor.z = addColor.z; +} + +void handleGamepadColor() { + bool setColor = false; + + fopAc_ac_c* zhint = dComIfGp_att_getZHint(); + if (zhint != NULL) { + FadeLED({50, 50, 175}, 2.0f); + setColor = true; } + + daPy_py_c* player = daPy_getPlayerActorClass(); + daAlink_c* link = daAlink_getAlinkActorClass(); + + if (link != nullptr && !setColor) { + if (link->checkWolf()) { + FadeLED({115, 115, 75}, 5.0f); + setColor = true; + } else { + switch (dComIfGs_getSelectEquipClothes()) { + case dItemNo_WEAR_KOKIRI_e: + FadeLED({0, 100, 0}, 5.0f); + setColor = true; + break; + case dItemNo_WEAR_ZORA_e: + FadeLED({0, 0, 100}, 5.0f); + setColor = true; + break; + case dItemNo_ARMOR_e: + if (link->checkMagicArmorHeavy()) { + FadeLED({5, 100, 100}, 5.0f); + } else { + FadeLED({100, 0, 5}, 5.0f); + } + setColor = true; + break; + case dItemNo_WEAR_CASUAL_e: + FadeLED({235, 230, 115}, 5.0f); + setColor = true; + break; + } + } + } + + if (dKy_darkworld_check()) { + SetGamepadAdditionalColor(duskColor); + } else { + SetGamepadAdditionalColor(noColor); + } + + f32 finalRed = finalGamepadColor.x + additionalGamepadColor.x; + f32 finalGreen = finalGamepadColor.y + additionalGamepadColor.y; + f32 finalBlue = finalGamepadColor.z + additionalGamepadColor.z; + + if (finalRed > 255) + finalRed = 255; + if (finalRed < 0) + finalRed = 0; + + if (finalGreen > 255) + finalGreen = 255; + if (finalGreen < 0) + finalGreen = 0; + + if (finalBlue > 255) + finalBlue = 255; + if (finalBlue < 0) + finalBlue = 0; + + currentGamepadColor = LerpColor(currentGamepadColor, cXyz{finalRed, finalGreen, finalBlue}, lerpSpeed); + PADSetColor(PAD_CHAN0, (u8)currentGamepadColor.x, (u8)currentGamepadColor.y, (u8)currentGamepadColor.z); +} + +static void duskExecute() { + handleGamepadColor(); if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) { if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { From c350b7b8ed4eb7f8abee044d3d23a857bf64b462 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Wed, 22 Apr 2026 13:52:14 -0400 Subject: [PATCH 04/24] fix building on linux --- src/f_ap/f_ap_game.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 9550cee06e..9e87acccc7 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -742,12 +742,8 @@ float lerpSpeed = 0.0f; const cXyz duskColor = {50, 50, -50}; const cXyz noColor = {0, 0, 0}; -float lerp(float a, float b, float t) { - return a + t * (b - a); -} - cXyz LerpColor(cXyz a, cXyz b, float t) { - return {lerp(a.x, b.x, t), lerp(a.y, b.y, t), lerp(a.z, b.z, t)}; + return {std::lerp(a.x, b.x, t), std::lerp(a.y, b.y, t), std::lerp(a.z, b.z, t)}; } void FadeLED(cXyz newColor, float speed) { From 53e8662335d91730ce913aab328d1a3b4932ac5c Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Wed, 22 Apr 2026 21:57:36 -0600 Subject: [PATCH 05/24] frame interp: dselect_cursor_c in d_menu_ring --- include/d/d_menu_ring.h | 5 +++++ include/d/d_select_cursor.h | 3 +++ src/d/d_menu_ring.cpp | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/include/d/d_menu_ring.h b/include/d/d_menu_ring.h index 39d29a35e8..acb7747b88 100644 --- a/include/d/d_menu_ring.h +++ b/include/d/d_menu_ring.h @@ -206,6 +206,11 @@ private: /* 0x6D3 */ u8 field_0x6d3; #if TARGET_PC f32 mSelectItemSlideElapsed[4]; + f32 mCursorInterpPrevX; + f32 mCursorInterpPrevY; + f32 mCursorInterpCurrX; + f32 mCursorInterpCurrY; + bool mCursorInterpInit; #endif }; diff --git a/include/d/d_select_cursor.h b/include/d/d_select_cursor.h index 1bd5991d16..1ca226611b 100644 --- a/include/d/d_select_cursor.h +++ b/include/d/d_select_cursor.h @@ -48,6 +48,9 @@ public: } #ifdef TARGET_PC + f32 getPositionX() const { return mPositionX; } + f32 getPositionY() const { return mPositionY; } + void refreshAspectScale(); #endif diff --git a/src/d/d_menu_ring.cpp b/src/d/d_menu_ring.cpp index 529597248a..dff9c79091 100644 --- a/src/d/d_menu_ring.cpp +++ b/src/d/d_menu_ring.cpp @@ -185,6 +185,13 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i field_0x682 = 0xc000; break; } +#if TARGET_PC + mCursorInterpPrevX = 0.0f; + mCursorInterpPrevY = 0.0f; + mCursorInterpCurrX = 0.0f; + mCursorInterpCurrY = 0.0f; + mCursorInterpInit = false; +#endif for (int i = 0; i < 4; i++) { field_0x674[i] = 0; #if TARGET_PC @@ -631,6 +638,34 @@ void dMenu_Ring_c::_draw() { } else { drawSelectItem(); drawItem2(); +#if TARGET_PC + if (dusk::frame_interp::is_enabled() && mAlphaRate >= 1.0f) { + f32 cursorX = mpDrawCursor->getPositionX(); + f32 cursorY = mpDrawCursor->getPositionY(); + + if (dusk::frame_interp::get_ui_tick_pending()) { + mCursorInterpPrevX = mCursorInterpCurrX; + mCursorInterpPrevY = mCursorInterpCurrY; + mCursorInterpCurrX = cursorX; + mCursorInterpCurrY = cursorY; + + if (!mCursorInterpInit) { + mCursorInterpPrevX = mCursorInterpCurrX; + mCursorInterpPrevY = mCursorInterpCurrY; + mCursorInterpInit = true; + } + } + if (mCursorInterpInit) { + const f32 step = dusk::frame_interp::get_interpolation_step(); + mpDrawCursor->setPos( + mCursorInterpPrevX + (mCursorInterpCurrX - mCursorInterpPrevX) * step, + mCursorInterpPrevY + (mCursorInterpCurrY - mCursorInterpPrevY) * step + ); + } + } else { + mCursorInterpInit = false; + } +#endif mpDrawCursor->draw(); mpItemExplain->trans(mCenterPosX, mCenterPosY); mpItemExplain->draw((J2DOrthoGraph*)grafPort); From cccddee106c7e7f72b93c50a3f77278699c9ada4 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Wed, 22 Apr 2026 22:58:38 -0700 Subject: [PATCH 06/24] Add ability to rotate link on the collection screen --- include/dusk/settings.h | 2 ++ src/d/d_menu_collect.cpp | 7 +++++++ src/dusk/imgui/ImGuiMenuGame.cpp | 5 +++++ src/dusk/settings.cpp | 2 ++ 4 files changed, 16 insertions(+) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 4dbfaa73ef..1b16b00ea8 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -69,6 +69,8 @@ struct UserSettings { ConfigVar invertCameraXAxis; ConfigVar disableMainHUD; ConfigVar pauseOnFocusLost; + ConfigVar enableLinkDollRotation; + // Graphics ConfigVar bloomMode; diff --git a/src/d/d_menu_collect.cpp b/src/d/d_menu_collect.cpp index 46c9c1a9d9..612806d372 100644 --- a/src/d/d_menu_collect.cpp +++ b/src/d/d_menu_collect.cpp @@ -2399,6 +2399,13 @@ void dMenu_Collect3D_c::_move(u8 param_0, u8 param_1) { posZ = 550.0f; } toItem3Dpos(linkPos.x, posY, posZ, &itemPos); + +#if TARGET_PC + if (dusk::getSettings().game.enableLinkDollRotation) { + const f32 angle = mDoCPd_c::getSubStickX3D(PAD_1) * 2048; + ANGLE_ADD(mLinkAngle, angle); + } else +#endif if (param_0 == 0 && param_1 == 0) { f32 temp = 450.0f; ANGLE_ADD(mLinkAngle, temp); diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index c55836c68d..84de7f6575 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -191,6 +191,11 @@ namespace dusk { ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0,\n" "the first released version."); } + + config::ImGuiCheckbox("Enable Rotating Link Doll", getSettings().game.enableLinkDollRotation); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Enables Rotating Link in the collection menu"); + } ImGui::SeparatorText("Difficulty"); diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 28397f80f2..bdaa654cc0 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -43,6 +43,7 @@ UserSettings g_userSettings = { .invertCameraXAxis {"game.invertCameraXAxis", false}, .disableMainHUD {"game.disableMainHUD", false}, .pauseOnFocusLost {"game.pauseOnFocusLost", false}, + .enableLinkDollRotation = {"game.enableLinkDollRotation", false }, // Graphics .bloomMode {"game.bloomMode", BloomMode::Classic}, @@ -150,6 +151,7 @@ void registerSettings() { Register(g_userSettings.game.canTransformAnywhere); Register(g_userSettings.game.freeMagicArmor); Register(g_userSettings.game.restoreWiiGlitches); + Register(g_userSettings.game.enableLinkDollRotation); Register(g_userSettings.game.noMissClimbing); Register(g_userSettings.game.noLowHpSound); Register(g_userSettings.game.midnasLamentNonStop); From d8a792760260e46e277b9dcee8b765107921f9f7 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Wed, 22 Apr 2026 22:59:56 -0700 Subject: [PATCH 07/24] Clarify tooltip --- src/dusk/imgui/ImGuiMenuGame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 84de7f6575..1f29039d60 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -194,7 +194,7 @@ namespace dusk { config::ImGuiCheckbox("Enable Rotating Link Doll", getSettings().game.enableLinkDollRotation); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Enables Rotating Link in the collection menu"); + ImGui::SetTooltip("Enables Rotating Link in the collection menu with the C-Stick"); } ImGui::SeparatorText("Difficulty"); From 5a109313cbefc7b683706b4c3efd2c6d3c8f9efd Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Wed, 22 Apr 2026 23:02:11 -0700 Subject: [PATCH 08/24] Minor tooltip cleanup --- src/dusk/imgui/ImGuiMenuGame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 1f29039d60..7e54f2ffa3 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -194,7 +194,7 @@ namespace dusk { config::ImGuiCheckbox("Enable Rotating Link Doll", getSettings().game.enableLinkDollRotation); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Enables Rotating Link in the collection menu with the C-Stick"); + ImGui::SetTooltip("Enables rotating Link in the collection menu with the C-Stick"); } ImGui::SeparatorText("Difficulty"); From a83b4186af5a2e8b4c74dfcc3ce0d9334ddf4977 Mon Sep 17 00:00:00 2001 From: gymnast86 Date: Thu, 23 Apr 2026 03:25:19 -0700 Subject: [PATCH 09/24] fix holding B in the middle of text --- src/d/d_msg_class.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/d/d_msg_class.cpp b/src/d/d_msg_class.cpp index 37085a6bb9..7af18f0732 100644 --- a/src/d/d_msg_class.cpp +++ b/src/d/d_msg_class.cpp @@ -1987,6 +1987,13 @@ bool jmessage_tSequenceProcessor::do_isReady() { } #endif +#if TARGET_PC + if (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) { + field_0xb2 = 1; + pReference->setSendTimer(0); + } +#endif + if (dComIfGp_checkMesgBgm()) { bool isItemMusicPlaying = true; if (mDoAud_checkPlayingSubBgmFlag() != Z2BGM_ITEM_GET && From 06e6b0d47ef1f224f84e8c81597d27d5e222d3b6 Mon Sep 17 00:00:00 2001 From: madeline Date: Thu, 23 Apr 2026 03:58:35 -0700 Subject: [PATCH 10/24] fix safety bit on interp fixes #507 --- libs/JSystem/include/JSystem/JUtility/JUTGamePad.h | 3 +++ libs/JSystem/src/JUtility/JUTGamePad.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/libs/JSystem/include/JSystem/JUtility/JUTGamePad.h b/libs/JSystem/include/JSystem/JUtility/JUTGamePad.h index 30bf685700..45e7227fe3 100644 --- a/libs/JSystem/include/JSystem/JUtility/JUTGamePad.h +++ b/libs/JSystem/include/JSystem/JUtility/JUTGamePad.h @@ -263,6 +263,9 @@ public: /* 0x9C */ u8 field_0x9c[4]; /* 0xA0 */ OSTime mResetHoldStartTime; /* 0xA8 */ u8 field_0xa8; +#if TARGET_PC + u32 mResetHoldFrameCount; +#endif }; /** diff --git a/libs/JSystem/src/JUtility/JUTGamePad.cpp b/libs/JSystem/src/JUtility/JUTGamePad.cpp index 091cc382d1..2ddf4397dc 100644 --- a/libs/JSystem/src/JUtility/JUTGamePad.cpp +++ b/libs/JSystem/src/JUtility/JUTGamePad.cpp @@ -64,6 +64,9 @@ BOOL JUTGamePad::init() { void JUTGamePad::clear() { mButtonReset.mReset = false; field_0xa8 = 1; +#if TARGET_PC + mResetHoldFrameCount = 0; +#endif } PADStatus JUTGamePad::mPadStatus[4]; @@ -219,11 +222,19 @@ void JUTGamePad::update() { mButtonReset.mReset = false; } else if (!JUTGamePad::C3ButtonReset::sResetOccurred) { if (mButtonReset.mReset == true) { +#if TARGET_PC + checkResetCallback(++mResetHoldFrameCount * (OS_TIMER_CLOCK / 30)); +#else OSTime hold_time = OSGetTime() - mResetHoldStartTime; checkResetCallback(hold_time); +#endif } else { mButtonReset.mReset = true; +#if TARGET_PC + mResetHoldFrameCount = 0; +#else mResetHoldStartTime = OSGetTime(); +#endif } } From 251c6e7aecb26433a19b49ab87e56f2f0e9b352f Mon Sep 17 00:00:00 2001 From: madeline Date: Thu, 23 Apr 2026 06:01:28 -0700 Subject: [PATCH 11/24] more precise link debug info --- src/dusk/imgui/ImGuiMenuTools.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 97f5b5a8d3..00a03e635b 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -210,7 +210,7 @@ namespace dusk { ImGui::Text("Link"); ImGuiStringViewText( player != nullptr - ? fmt::format("Position: {: .2f}, {: .2f}, {: .2f}\n", player->current.pos.x, player->current.pos.y, player->current.pos.z) + ? fmt::format("Position: {: .4f}, {: .4f}, {: .4f}\n", player->current.pos.x, player->current.pos.y, player->current.pos.z) : "Position: ?, ?, ?\n" ); @@ -222,7 +222,7 @@ namespace dusk { ImGuiStringViewText( player != nullptr - ? fmt::format("Speed: {0}\n", player->speedF) + ? fmt::format("Speed: {: .4f}\n", player->speedF) : "Speed: ?\n" ); @@ -230,7 +230,7 @@ namespace dusk { ImGui::Text("Epona"); ImGuiStringViewText( horse != nullptr - ? fmt::format("Position: {: .2f}, {: .2f}, {: .2f}\n", horse->current.pos.x, horse->current.pos.y, horse->current.pos.z) + ? fmt::format("Position: {: .4f}, {: .4f}, {: .4f}\n", horse->current.pos.x, horse->current.pos.y, horse->current.pos.z) : "Position: ?, ?, ?\n" ); @@ -242,7 +242,7 @@ namespace dusk { ImGuiStringViewText( horse != nullptr - ? fmt::format("Speed: {0}\n", horse->speedF) + ? fmt::format("Speed: {: .4f}\n", horse->speedF) : "Speed: ?\n" ); From c991c7c407ff5b443624b7ba4960c91695a53eaf Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 23 Apr 2026 09:42:02 -0400 Subject: [PATCH 12/24] Fixes sun songing underwater --- src/d/actor/d_a_alink_dusk.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index 0f442aff94..d53476aa91 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -41,7 +41,7 @@ void daAlink_c::handleWolfHowl() { return; } - bool canTransform = false; + bool canHowl = false; if (mLinkAcch.ChkGroundHit() && !checkModeFlg(MODE_PLAYER_FLY) && !checkMagneBootsOn()) { if (!checkForestOldCentury()) { @@ -52,12 +52,17 @@ void daAlink_c::handleWolfHowl() { (checkEventRun() || getMidnaActor()->checkMetamorphoseEnable()) && (checkModeFlg(4) || dComIfGp_checkPlayerStatus0(0, 0x10)))) { - canTransform = true; + canHowl = true; } } } } + if (!canHowl) { + Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + return; + } + getWolfHowlMgrP()->setCorrectCurve(9); procWolfHowlDemoInit(); } From 14aeefb8137d2d6ebd42a29493f5e35a1e1a34ae Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Thu, 23 Apr 2026 08:38:47 -0600 Subject: [PATCH 13/24] Frame interp: interpolate ring menu cursor along arc --- include/d/d_menu_ring.h | 4 +++ src/d/d_menu_ring.cpp | 58 ++++++++++++++++++++++++++++++++++------- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/include/d/d_menu_ring.h b/include/d/d_menu_ring.h index acb7747b88..74624eac80 100644 --- a/include/d/d_menu_ring.h +++ b/include/d/d_menu_ring.h @@ -210,6 +210,10 @@ private: f32 mCursorInterpPrevY; f32 mCursorInterpCurrX; f32 mCursorInterpCurrY; + s16 mCursorInterpPrevAngle; + s16 mCursorInterpCurrAngle; + bool mCursorInterpPrevAngular; + bool mCursorInterpCurrAngular; bool mCursorInterpInit; #endif }; diff --git a/src/d/d_menu_ring.cpp b/src/d/d_menu_ring.cpp index dff9c79091..ba2b86b760 100644 --- a/src/d/d_menu_ring.cpp +++ b/src/d/d_menu_ring.cpp @@ -190,6 +190,10 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i mCursorInterpPrevY = 0.0f; mCursorInterpCurrX = 0.0f; mCursorInterpCurrY = 0.0f; + mCursorInterpPrevAngle = 0; + mCursorInterpCurrAngle = 0; + mCursorInterpPrevAngular = false; + mCursorInterpCurrAngular = false; mCursorInterpInit = false; #endif for (int i = 0; i < 4; i++) { @@ -639,34 +643,70 @@ void dMenu_Ring_c::_draw() { drawSelectItem(); drawItem2(); #if TARGET_PC + f32 simX = 0.0f; + f32 simY = 0.0f; + bool restoreSimPos = false; if (dusk::frame_interp::is_enabled() && mAlphaRate >= 1.0f) { - f32 cursorX = mpDrawCursor->getPositionX(); - f32 cursorY = mpDrawCursor->getPositionY(); + simX = mpDrawCursor->getPositionX(); + simY = mpDrawCursor->getPositionY(); + + const bool isAngular = (mStatus == STATUS_MOVE) && !mDirectSelectActive; if (dusk::frame_interp::get_ui_tick_pending()) { mCursorInterpPrevX = mCursorInterpCurrX; mCursorInterpPrevY = mCursorInterpCurrY; - mCursorInterpCurrX = cursorX; - mCursorInterpCurrY = cursorY; + mCursorInterpPrevAngle = mCursorInterpCurrAngle; + mCursorInterpPrevAngular = mCursorInterpCurrAngular; - if (!mCursorInterpInit) { + mCursorInterpCurrX = simX; + mCursorInterpCurrY = simY; + mCursorInterpCurrAngle = field_0x66e; + mCursorInterpCurrAngular = isAngular; + + // reset prev = curr for first render pass or + // when angle modes prev/curr differ + // to prevent arrival jitter + if (!mCursorInterpInit || + mCursorInterpPrevAngular != mCursorInterpCurrAngular) { mCursorInterpPrevX = mCursorInterpCurrX; mCursorInterpPrevY = mCursorInterpCurrY; + mCursorInterpPrevAngle = mCursorInterpCurrAngle; + mCursorInterpPrevAngular = mCursorInterpCurrAngular; mCursorInterpInit = true; } } if (mCursorInterpInit) { const f32 step = dusk::frame_interp::get_interpolation_step(); - mpDrawCursor->setPos( - mCursorInterpPrevX + (mCursorInterpCurrX - mCursorInterpPrevX) * step, - mCursorInterpPrevY + (mCursorInterpCurrY - mCursorInterpPrevY) * step - ); + if (mCursorInterpPrevAngular && mCursorInterpCurrAngular) { + const s16 delta = mCursorInterpCurrAngle - mCursorInterpPrevAngle; + const s16 lerpedAngle = mCursorInterpPrevAngle + (s16)(delta * step); + + // yoinked from stick_move_proc() + const f32 x = g_ringHIO.mItemRingPosX + FB_WIDTH_BASE / 2 + + mRingRadiusH * cM_ssin(lerpedAngle); + const f32 y = g_ringHIO.mItemRingPosY + FB_HEIGHT_BASE / 2 + + mRingRadiusV * cM_scos(lerpedAngle); + mpDrawCursor->setPos(x, y); + } else { + mpDrawCursor->setPos( + mCursorInterpPrevX + (mCursorInterpCurrX - mCursorInterpPrevX) * step, + mCursorInterpPrevY + (mCursorInterpCurrY - mCursorInterpPrevY) * step + ); + } + restoreSimPos = true; } } else { mCursorInterpInit = false; } #endif mpDrawCursor->draw(); +#if TARGET_PC + // prevents offsetting at destination on the next frame + // since stick_wait_proc doesn't call setPos and we clobbered mPositionX/Y + if (restoreSimPos) { + mpDrawCursor->setPos(simX, simY); + } +#endif mpItemExplain->trans(mCenterPosX, mCenterPosY); mpItemExplain->draw((J2DOrthoGraph*)grafPort); drawFlag0(); From 4453316bb036423f772cf11491fb3fd277a7068d Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 23 Apr 2026 14:25:50 -0400 Subject: [PATCH 14/24] Separated gamepad color into its own files --- files.cmake | 1 + include/dusk/gamepad_color.h | 8 +++ src/dusk/gamepad_color.cpp | 106 +++++++++++++++++++++++++++++++++++ src/f_ap/f_ap_game.cpp | 101 +-------------------------------- 4 files changed, 116 insertions(+), 100 deletions(-) create mode 100644 include/dusk/gamepad_color.h create mode 100644 src/dusk/gamepad_color.cpp diff --git a/files.cmake b/files.cmake index c50cac2d8c..32a0996227 100644 --- a/files.cmake +++ b/files.cmake @@ -1348,6 +1348,7 @@ set(DUSK_FILES src/dusk/game_clock.cpp src/dusk/globals.cpp src/dusk/gyro.cpp + src/dusk/gamepad_color.cpp src/dusk/io.cpp src/dusk/layout.cpp src/dusk/logging.cpp diff --git a/include/dusk/gamepad_color.h b/include/dusk/gamepad_color.h new file mode 100644 index 0000000000..c7cfc1e716 --- /dev/null +++ b/include/dusk/gamepad_color.h @@ -0,0 +1,8 @@ +#pragma once + +#ifndef GAMEPAD_COLOR_H +#define GAMEPAD_COLOR_H + +void handleGamepadColor(); + +#endif \ No newline at end of file diff --git a/src/dusk/gamepad_color.cpp b/src/dusk/gamepad_color.cpp new file mode 100644 index 0000000000..cba32da632 --- /dev/null +++ b/src/dusk/gamepad_color.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include + +cXyz currentGamepadColor = {0, 0, 0}; +cXyz finalGamepadColor = {0, 0, 0}; +cXyz additionalGamepadColor = {0, 0, 0}; + +float lerpSpeed = 0.0f; + +const cXyz duskColor = {50, 50, -50}; +const cXyz noColor = {0, 0, 0}; + +cXyz LerpColor(cXyz a, cXyz b, float t) { + return {std::lerp(a.x, b.x, t), std::lerp(a.y, b.y, t), std::lerp(a.z, b.z, t)}; +} + +void FadeLED(cXyz newColor, float speed) { + finalGamepadColor = newColor; + lerpSpeed = speed / 30.0f; +} + +void SetLED(cXyz newColor) { + currentGamepadColor = newColor; + finalGamepadColor = newColor; +} + +void SetGamepadAdditionalColor(cXyz addColor) { + additionalGamepadColor.x = addColor.x; + additionalGamepadColor.y = addColor.y; + additionalGamepadColor.z = addColor.z; +} + +void handleGamepadColor() { + bool setColor = false; + + fopAc_ac_c* zhint = dComIfGp_att_getZHint(); + if (zhint != NULL) { + FadeLED({50, 50, 175}, 2.0f); + setColor = true; + } + + daPy_py_c* player = daPy_getPlayerActorClass(); + daAlink_c* link = daAlink_getAlinkActorClass(); + + if (link != nullptr && !setColor) { + if (link->checkWolf()) { + FadeLED({115, 115, 75}, 5.0f); + setColor = true; + } else { + switch (dComIfGs_getSelectEquipClothes()) { + case dItemNo_WEAR_KOKIRI_e: + FadeLED({0, 100, 0}, 5.0f); + setColor = true; + break; + case dItemNo_WEAR_ZORA_e: + FadeLED({0, 0, 100}, 5.0f); + setColor = true; + break; + case dItemNo_ARMOR_e: + if (link->checkMagicArmorHeavy()) { + FadeLED({5, 100, 100}, 5.0f); + } else { + FadeLED({100, 0, 5}, 5.0f); + } + setColor = true; + break; + case dItemNo_WEAR_CASUAL_e: + FadeLED({235, 230, 115}, 5.0f); + setColor = true; + break; + } + } + } + + if (dKy_darkworld_check()) { + SetGamepadAdditionalColor(duskColor); + } else { + SetGamepadAdditionalColor(noColor); + } + + f32 finalRed = finalGamepadColor.x + additionalGamepadColor.x; + f32 finalGreen = finalGamepadColor.y + additionalGamepadColor.y; + f32 finalBlue = finalGamepadColor.z + additionalGamepadColor.z; + + if (finalRed > 255) + finalRed = 255; + if (finalRed < 0) + finalRed = 0; + + if (finalGreen > 255) + finalGreen = 255; + if (finalGreen < 0) + finalGreen = 0; + + if (finalBlue > 255) + finalBlue = 255; + if (finalBlue < 0) + finalBlue = 0; + + currentGamepadColor = LerpColor(currentGamepadColor, cXyz{finalRed, finalGreen, finalBlue}, lerpSpeed); + PADSetColor(PAD_CHAN0, (u8)currentGamepadColor.x, (u8)currentGamepadColor.y, (u8)currentGamepadColor.z); +} \ No newline at end of file diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 9e87acccc7..78fc240db4 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -23,6 +23,7 @@ #include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_main.h" #include "tracy/Tracy.hpp" +#include fapGm_HIO_c::fapGm_HIO_c() { mUsingHostIO = true; @@ -733,106 +734,6 @@ static void fapGm_AfterRecord() { fapGm_After(); } -cXyz currentGamepadColor = {0, 0, 0}; -cXyz finalGamepadColor = {0, 0, 0}; -cXyz additionalGamepadColor = {0, 0, 0}; - -float lerpSpeed = 0.0f; - -const cXyz duskColor = {50, 50, -50}; -const cXyz noColor = {0, 0, 0}; - -cXyz LerpColor(cXyz a, cXyz b, float t) { - return {std::lerp(a.x, b.x, t), std::lerp(a.y, b.y, t), std::lerp(a.z, b.z, t)}; -} - -void FadeLED(cXyz newColor, float speed) { - finalGamepadColor = newColor; - lerpSpeed = speed / 30.0f; -} - -void SetLED(cXyz newColor) { - currentGamepadColor = newColor; - finalGamepadColor = newColor; -} - -void SetGamepadAdditionalColor(cXyz addColor) { - additionalGamepadColor.x = addColor.x; - additionalGamepadColor.y = addColor.y; - additionalGamepadColor.z = addColor.z; -} - -void handleGamepadColor() { - bool setColor = false; - - fopAc_ac_c* zhint = dComIfGp_att_getZHint(); - if (zhint != NULL) { - FadeLED({50, 50, 175}, 2.0f); - setColor = true; - } - - daPy_py_c* player = daPy_getPlayerActorClass(); - daAlink_c* link = daAlink_getAlinkActorClass(); - - if (link != nullptr && !setColor) { - if (link->checkWolf()) { - FadeLED({115, 115, 75}, 5.0f); - setColor = true; - } else { - switch (dComIfGs_getSelectEquipClothes()) { - case dItemNo_WEAR_KOKIRI_e: - FadeLED({0, 100, 0}, 5.0f); - setColor = true; - break; - case dItemNo_WEAR_ZORA_e: - FadeLED({0, 0, 100}, 5.0f); - setColor = true; - break; - case dItemNo_ARMOR_e: - if (link->checkMagicArmorHeavy()) { - FadeLED({5, 100, 100}, 5.0f); - } else { - FadeLED({100, 0, 5}, 5.0f); - } - setColor = true; - break; - case dItemNo_WEAR_CASUAL_e: - FadeLED({235, 230, 115}, 5.0f); - setColor = true; - break; - } - } - } - - if (dKy_darkworld_check()) { - SetGamepadAdditionalColor(duskColor); - } else { - SetGamepadAdditionalColor(noColor); - } - - f32 finalRed = finalGamepadColor.x + additionalGamepadColor.x; - f32 finalGreen = finalGamepadColor.y + additionalGamepadColor.y; - f32 finalBlue = finalGamepadColor.z + additionalGamepadColor.z; - - if (finalRed > 255) - finalRed = 255; - if (finalRed < 0) - finalRed = 0; - - if (finalGreen > 255) - finalGreen = 255; - if (finalGreen < 0) - finalGreen = 0; - - if (finalBlue > 255) - finalBlue = 255; - if (finalBlue < 0) - finalBlue = 0; - - currentGamepadColor = LerpColor(currentGamepadColor, cXyz{finalRed, finalGreen, finalBlue}, lerpSpeed); - PADSetColor(PAD_CHAN0, (u8)currentGamepadColor.x, (u8)currentGamepadColor.y, (u8)currentGamepadColor.z); -} - static void duskExecute() { handleGamepadColor(); From 1e6e1976e343124fbe85b34c6c2602aacc760d31 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 23 Apr 2026 13:07:42 -0600 Subject: [PATCH 15/24] Clamp max LOD for Wolf Link and Midna eyes --- src/d/actor/d_a_alink_wolf.inc | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/d/actor/d_a_alink_wolf.inc b/src/d/actor/d_a_alink_wolf.inc index 0a6da841c5..063c5253f1 100644 --- a/src/d/actor/d_a_alink_wolf.inc +++ b/src/d/actor/d_a_alink_wolf.inc @@ -149,6 +149,23 @@ void daAlink_c::changeWolf() { mpLinkModel = initModel(static_cast(dComIfG_getObjectRes(l_wArcName, 14)), 0x20200); +#ifdef TARGET_PC + // Update Wolf Link's eye maxLOD to prevent the eyes from disappearing + { + J3DTexture* tex = mpLinkModel->getModelData()->getTexture(); + JUTNameTab* nametable = mpLinkModel->getModelData()->getTextureName(); + if (tex != nullptr && nametable != nullptr) { + for (u16 i = 0; i < tex->getNum(); i++) { + const char* tex_name = nametable->getName(i); + if (tex_name != NULL && strcmp(tex_name, "wl_eyeball") == 0) { + ResTIMG* timg = tex->getResTIMG(i); + timg->maxLOD = 0; + } + } + } + } +#endif + J3DModelData* chainModelData = static_cast(dComIfG_getObjectRes(l_wArcName, 15)); for (u16 i = 0; i < 4; i++) { mpWlChainModels[i] = initModel(chainModelData, 0); @@ -162,6 +179,23 @@ void daAlink_c::changeWolf() { mpWlMidnaHairModel = initModelEnv(static_cast(dComIfG_getObjectRes(l_wArcName, 11)), 0x1000000); +#ifdef TARGET_PC + // Update Midna's eye maxLOD to prevent the eyes from disappearing + { + J3DTexture* tex = mpWlMidnaModel->getModelData()->getTexture(); + JUTNameTab* nametable = mpWlMidnaModel->getModelData()->getTextureName(); + if (tex != nullptr && nametable != nullptr) { + for (u16 i = 0; i < tex->getNum(); i++) { + const char* tex_name = nametable->getName(i); + if (tex_name != NULL && strcmp(tex_name, "midona_eyeball") == 0) { + ResTIMG* timg = tex->getResTIMG(i); + timg->maxLOD = 0; + } + } + } + } +#endif + mpDMidnaBrk = static_cast(dComIfG_getObjectRes(l_wArcName, 18)); mpDMidnaBrk->searchUpdateMaterialID(mpWlMidnaModel->getModelData()); mpWlMidnaModel->getModelData()->entryTevRegAnimator(mpDMidnaBrk); From 23130d5a57fd6dc2f792927bd7539d0d0cb9d01c Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 23 Apr 2026 15:08:34 -0400 Subject: [PATCH 16/24] Thinner map lines at higher resolution Affects both the Map Menu and the Mini-Map. --- src/d/d_map_path.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/d/d_map_path.cpp b/src/d/d_map_path.cpp index 916bd2c223..8288a2ef9f 100644 --- a/src/d/d_map_path.cpp +++ b/src/d/d_map_path.cpp @@ -237,6 +237,13 @@ void dDrawPath_c::rendering(dDrawPath_c::line_class const* p_line) { if (isDrawType(p_line->field_0x0)) { int width = getLineWidth(p_line->field_0x1); + #if TARGET_PC + f32 height = JUTVideo::getManager()->getRenderHeight() / 448.0f; + if (height > 1.0f) { + width /= 2; + } + #endif + if (width > 0 && p_line->mDataNum >= 2) { GXSetLineWidth(width, GX_TO_ZERO); GXSetTevColor(GX_TEVREG0, *getLineColor(p_line->field_0x0 & 0x3F, p_line->field_0x1)); From dfdac1c1cd2ba4fde1fde47ec373edfebf4dd693 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Thu, 23 Apr 2026 15:11:51 -0700 Subject: [PATCH 17/24] update setup instructions --- README.md | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 7322441b74..c2fe53576d 100644 --- a/README.md +++ b/README.md @@ -10,28 +10,19 @@ First make sure your dump of the game is clean and supported by Dusk. You can do this by checking the sha1 hash of your dump against this list of supported versions. | Version | sha1 hash | -| ------------ | ---------------------------------------- | +|--------------| ---------------------------------------- | | GameCube USA | 75edd3ddff41f125d1b4ce1a40378f1b565519e7 | +| GameCube PAL | 2601822a488eeb86fb89db16ca8f29c2c953e1ca | ### 2. Download [Dusk](https://github.com/TwilitRealm/dusk/releases) ### 3. Setup the game -#### Windows - Extract the zip folder -- Place your dump of the game into the same folder where you extracted to -- Launch `dusk.exe` +- Launch Dusk +- Select Options, then set the ISO Path to your supported game dump +- Press Start Game to play! -#### macOS -- TODO - -#### Linux -- TODO - -#### iOS -- TODO - -#### android -- TODO +![DuskOptions](assets/dusk_options.png) # Building If you'd like to build Dusk from source, please read the [build instructions](docs/building.md). From f04a0ffcf1293e57f87398ee201adaa76c252d07 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Thu, 23 Apr 2026 15:12:40 -0700 Subject: [PATCH 18/24] forgot pic oops --- assets/dusk_options.png | Bin 0 -> 83757 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/dusk_options.png diff --git a/assets/dusk_options.png b/assets/dusk_options.png new file mode 100644 index 0000000000000000000000000000000000000000..4ed4ad7563d0325f41ab82dd605f9236d546f320 GIT binary patch literal 83757 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

MQ6fww0xU&2G(=Sp+OSruCRGqy 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 Date: Thu, 23 Apr 2026 21:05:38 -0600 Subject: [PATCH 19/24] Fix a couple issues for Xcode projects (#513) * Link separate JSystem libraries due to control.cpp This allows the Xcode generator to work, otherwise it breaks on the duplicate control.o files within the game_debug library. * Fix __memcpy define on GCC * Try LINK_GROUP:RESCAN for GNU ld * Combine dusk/game_base/game_debug targets * Fix compile defs syntax --- CMakeLists.txt | 79 ++++++++++++++++++++++++++++------------- extern/aurora | 2 +- files.cmake | 86 +++++++++++++++++++++++++++++++++++++++++++-- include/global.h | 12 ++++++- src/dusk/extras.c | 26 +++++++++++--- src/dusk/extras.cpp | 27 -------------- 6 files changed, 170 insertions(+), 62 deletions(-) delete mode 100644 src/dusk/extras.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 77cd0b9694..19fd5d673f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +# Folder-based instead of target-based organization +# in Visual Studio and Xcode generators +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "_cmake") + if (CMAKE_SYSTEM_NAME STREQUAL Linux) set(DAWN_USE_WAYLAND ON CACHE BOOL "Enable support for Wayland surface" FORCE) endif () @@ -281,7 +286,7 @@ set(DUSK_TP_VERSION ${DUSK_GAME_NAME}${DUSK_GAME_VERSION}) message(STATUS "dusk: Game Version: ${DUSK_TP_VERSION}") -source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${JSYSTEM_FILES} ${JSYSTEM_DEBUG_FILES} ${REL_FILES}) +source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES}) source_group("dusk" FILES ${DUSK_FILES}) set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 @@ -374,41 +379,65 @@ endif () # game_debug is for game code files that we know work when compiled with DEBUG=1 # Of course, if building a release build, this distinction is irrelevant -add_library(game_debug OBJECT ${JSYSTEM_DEBUG_FILES} ${SSYSTEM_FILES} +set(GAME_DEBUG_FILES + ${SSYSTEM_FILES} src/dusk/audio/DuskAudioSystem.cpp src/dusk/audio/JASCriticalSection.cpp src/dusk/audio/DuskDsp.cpp src/dusk/audio/Adpcm.cpp src/dusk/audio/DspStub.cpp - src/dusk/imgui/ImGuiAudio.cpp) + src/dusk/imgui/ImGuiAudio.cpp +) +set_source_files_properties( + ${GAME_DEBUG_FILES} + PROPERTIES + COMPILE_DEFINITIONS "$<$:DEBUG=1>;$<$:PARTIAL_DEBUG=1>" +) # game_base is for all other game code files -add_library(game_base OBJECT ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${JSYSTEM_FILES} ${REL_FILES} ${DUSK_FILES} ${DOLPHIN_FILES}) +set(GAME_BASE_FILES + ${DOLZEL_FILES} + ${Z2AUDIOLIB_FILES} + ${REL_FILES} + ${DUSK_FILES} + ${DOLPHIN_FILES} +) +set_source_files_properties( + ${GAME_BASE_FILES} + PROPERTIES + COMPILE_DEFINITIONS "NDEBUG=1;NDEBUG_DEFINED=1;DEBUG_DEFINED=0;$<$:PARTIAL_DEBUG=1>" +) -target_compile_definitions(game_debug PRIVATE ${GAME_COMPILE_DEFS} $<$:DEBUG=1> $<$:PARTIAL_DEBUG=1>) -target_compile_definitions(game_base PRIVATE ${GAME_COMPILE_DEFS} NDEBUG=1 NDEBUG_DEFINED=1 DEBUG_DEFINED=0 $<$:PARTIAL_DEBUG=1>) +foreach(jsystem_lib IN LISTS JSYSTEM_LIBRARIES) + target_compile_definitions(${jsystem_lib} PRIVATE + ${GAME_COMPILE_DEFS} + $<$:DEBUG=1> + $<$:PARTIAL_DEBUG=1> + ) + target_include_directories(${jsystem_lib} PRIVATE ${GAME_INCLUDE_DIRS}) + target_link_libraries(${jsystem_lib} PRIVATE ${GAME_LIBS}) + set_target_properties(${jsystem_lib} PROPERTIES FOLDER "JSystem") +endforeach() -# only apply PCH to game_base since not all headers are necessarily validated with DEBUG=1 -target_precompile_headers(game_base PRIVATE "$<$:${CMAKE_SOURCE_DIR}/include/dusk_pch.hpp>") - -target_include_directories(game_debug PRIVATE ${GAME_INCLUDE_DIRS}) -target_include_directories(game_base PRIVATE ${GAME_INCLUDE_DIRS}) - -# This implicitly pulls in the library include directories even though no -# linking actually takes place for object libraries -target_link_libraries(game_debug PRIVATE ${GAME_LIBS}) -target_link_libraries(game_base PRIVATE ${GAME_LIBS}) - -if(ANDROID) - add_library(dusk SHARED src/dusk/main.cpp) - set_target_properties(dusk PROPERTIES OUTPUT_NAME main) -else () - add_executable(dusk src/dusk/main.cpp) +set(JSYSTEM_LINK_LIBRARIES ${JSYSTEM_LIBRARIES}) +if (CMAKE_CXX_LINK_GROUP_USING_RESCAN_SUPPORTED OR CMAKE_LINK_GROUP_USING_RESCAN_SUPPORTED) + # GNU ld resolves static archives in a single left-to-right pass. The split + # JSystem libraries reference each other, so they need a RESCAN group there. + set(JSYSTEM_LINK_LIBRARIES "$") endif () -target_compile_definitions(dusk PRIVATE TARGET_PC AVOID_UB=1 VERSION=0) -target_include_directories(dusk PRIVATE include) -target_link_libraries(dusk PRIVATE game_base game_debug aurora::main) +set(DUSK_FILES src/dusk/main.cpp ${GAME_BASE_FILES} ${GAME_DEBUG_FILES}) +if(ANDROID) + add_library(dusk SHARED ${DUSK_FILES}) + set_target_properties(dusk PROPERTIES OUTPUT_NAME main) +else () + add_executable(dusk ${DUSK_FILES}) +endif () + +target_compile_definitions(dusk PRIVATE ${GAME_COMPILE_DEFS}) +target_include_directories(dusk PRIVATE ${GAME_INCLUDE_DIRS}) +target_link_libraries(dusk PRIVATE aurora::main ${GAME_LIBS} ${JSYSTEM_LINK_LIBRARIES}) +target_precompile_headers(dusk PRIVATE "$<$:${CMAKE_SOURCE_DIR}/include/dusk_pch.hpp>") if (TARGET crashpad_handler) add_dependencies(dusk crashpad_handler) endif () diff --git a/extern/aurora b/extern/aurora index 63550a8375..524b683fe0 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 63550a83759974dd18bc13cd420888188be9caf9 +Subproject commit 524b683fe07710350358846fe31155bbc8b60fc5 diff --git a/files.cmake b/files.cmake index 32a0996227..af101b6c47 100644 --- a/files.cmake +++ b/files.cmake @@ -314,7 +314,7 @@ set(SSYSTEM_FILES src/SSystem/SStandard/s_basic.cpp ) -set(JSYSTEM_DEBUG_FILES +add_library(JSystem_JParticle STATIC libs/JSystem/src/JParticle/JPAResourceManager.cpp libs/JSystem/src/JParticle/JPAResource.cpp libs/JSystem/src/JParticle/JPABaseShape.cpp @@ -330,10 +330,19 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/JParticle/JPAEmitter.cpp libs/JSystem/src/JParticle/JPAParticle.cpp libs/JSystem/src/JParticle/JPAMath.cpp +) + +add_library(JSystem_JFramework STATIC libs/JSystem/src/JFramework/JFWSystem.cpp libs/JSystem/src/JFramework/JFWDisplay.cpp +) + +add_library(JSystem_J3DU STATIC libs/JSystem/src/J3DU/J3DUClipper.cpp libs/JSystem/src/J3DU/J3DUDL.cpp +) + +add_library(JSystem_JKernel STATIC libs/JSystem/src/JKernel/JKRHeap.cpp libs/JSystem/src/JKernel/JKRExpHeap.cpp libs/JSystem/src/JKernel/JKRSolidHeap.cpp @@ -359,14 +368,23 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/JKernel/JKRDvdRipper.cpp libs/JSystem/src/JKernel/JKRDvdAramRipper.cpp libs/JSystem/src/JKernel/JKRDecomp.cpp +) + +add_library(JSystem_JMath STATIC libs/JSystem/src/JMath/JMath.cpp libs/JSystem/src/JMath/random.cpp libs/JSystem/src/JMath/JMATrigonometric.cpp +) + +add_library(JSystem_JSupport STATIC libs/JSystem/src/JSupport/JSUList.cpp libs/JSystem/src/JSupport/JSUInputStream.cpp libs/JSystem/src/JSupport/JSUOutputStream.cpp libs/JSystem/src/JSupport/JSUMemoryStream.cpp libs/JSystem/src/JSupport/JSUFileStream.cpp +) + +add_library(JSystem_JUtility STATIC libs/JSystem/src/JUtility/JUTCacheFont.cpp libs/JSystem/src/JUtility/JUTResource.cpp libs/JSystem/src/JUtility/JUTTexture.cpp @@ -387,6 +405,9 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/JUtility/JUTConsole.cpp libs/JSystem/src/JUtility/JUTDirectFile.cpp libs/JSystem/src/JUtility/JUTFontData_Ascfont_fix12.cpp +) + +add_library(JSystem_JStage STATIC libs/JSystem/src/JStage/JSGActor.cpp libs/JSystem/src/JStage/JSGAmbientLight.cpp libs/JSystem/src/JStage/JSGCamera.cpp @@ -394,6 +415,9 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/JStage/JSGLight.cpp libs/JSystem/src/JStage/JSGObject.cpp libs/JSystem/src/JStage/JSGSystem.cpp +) + +add_library(JSystem_J2DGraph STATIC libs/JSystem/src/J2DGraph/J2DGrafContext.cpp libs/JSystem/src/J2DGraph/J2DOrthoGraph.cpp libs/JSystem/src/J2DGraph/J2DTevs.cpp @@ -412,6 +436,9 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/J2DGraph/J2DAnmLoader.cpp libs/JSystem/src/J2DGraph/J2DAnimation.cpp libs/JSystem/src/J2DGraph/J2DManage.cpp +) + +add_library(JSystem_J3DGraphBase STATIC libs/JSystem/src/J3DGraphBase/J3DGD.cpp libs/JSystem/src/J3DGraphBase/J3DSys.cpp libs/JSystem/src/J3DGraphBase/J3DVertex.cpp @@ -426,6 +453,9 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/J3DGraphBase/J3DTevs.cpp libs/JSystem/src/J3DGraphBase/J3DDrawBuffer.cpp libs/JSystem/src/J3DGraphBase/J3DStruct.cpp +) + +add_library(JSystem_J3DGraphAnimator STATIC libs/JSystem/src/J3DGraphAnimator/J3DShapeTable.cpp libs/JSystem/src/J3DGraphAnimator/J3DJointTree.cpp libs/JSystem/src/J3DGraphAnimator/J3DModelData.cpp @@ -437,6 +467,9 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/J3DGraphAnimator/J3DCluster.cpp libs/JSystem/src/J3DGraphAnimator/J3DJoint.cpp libs/JSystem/src/J3DGraphAnimator/J3DMaterialAttach.cpp +) + +add_library(JSystem_J3DGraphLoader STATIC libs/JSystem/src/J3DGraphLoader/J3DMaterialFactory.cpp libs/JSystem/src/J3DGraphLoader/J3DMaterialFactory_v21.cpp libs/JSystem/src/J3DGraphLoader/J3DClusterLoader.cpp @@ -445,6 +478,9 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/J3DGraphLoader/J3DJointFactory.cpp libs/JSystem/src/J3DGraphLoader/J3DShapeFactory.cpp libs/JSystem/src/J3DGraphLoader/J3DAnmLoader.cpp +) + +add_library(JSystem_JStudio STATIC libs/JSystem/src/JStudio/JStudio/ctb.cpp libs/JSystem/src/JStudio/JStudio/ctb-data.cpp libs/JSystem/src/JStudio/JStudio/functionvalue.cpp @@ -459,6 +495,9 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/JStudio/JStudio/stb.cpp libs/JSystem/src/JStudio/JStudio/stb-data-parse.cpp libs/JSystem/src/JStudio/JStudio/stb-data.cpp +) + +add_library(JSystem_JStudio_JStage STATIC libs/JSystem/src/JStudio/JStudio_JStage/control.cpp libs/JSystem/src/JStudio/JStudio_JStage/object.cpp libs/JSystem/src/JStudio/JStudio_JStage/object-actor.cpp @@ -466,10 +505,19 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/JStudio/JStudio_JStage/object-camera.cpp libs/JSystem/src/JStudio/JStudio_JStage/object-fog.cpp libs/JSystem/src/JStudio/JStudio_JStage/object-light.cpp +) + +add_library(JSystem_JStudio_JAudio2 STATIC libs/JSystem/src/JStudio/JStudio_JAudio2/control.cpp libs/JSystem/src/JStudio/JStudio_JAudio2/object-sound.cpp +) + +add_library(JSystem_JStudio_JParticle STATIC libs/JSystem/src/JStudio/JStudio_JParticle/control.cpp libs/JSystem/src/JStudio/JStudio_JParticle/object-particle.cpp +) + +add_library(JSystem_JAudio2 STATIC libs/JSystem/src/JAudio2/JASCalc.cpp libs/JSystem/src/JAudio2/JASTaskThread.cpp libs/JSystem/src/JAudio2/JASDvdThread.cpp @@ -534,22 +582,34 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/JAudio2/JAUSoundAnimator.cpp libs/JSystem/src/JAudio2/JAUSoundTable.cpp libs/JSystem/src/JAudio2/JAUStreamFileTable.cpp +) + +add_library(JSystem_JMessage STATIC libs/JSystem/src/JMessage/control.cpp libs/JSystem/src/JMessage/data.cpp libs/JSystem/src/JMessage/processor.cpp libs/JSystem/src/JMessage/resource.cpp libs/JSystem/src/JMessage/locale.cpp +) + +add_library(JSystem_JGadget STATIC libs/JSystem/src/JGadget/binary.cpp libs/JSystem/src/JGadget/define.cpp libs/JSystem/src/JGadget/linklist.cpp libs/JSystem/src/JGadget/search.cpp libs/JSystem/src/JGadget/std-vector.cpp +) + +add_library(JSystem_JAHostIO STATIC libs/JSystem/src/JAHostIO/JAHFrameNode.cpp libs/JSystem/src/JAHostIO/JAHioMessage.cpp libs/JSystem/src/JAHostIO/JAHioMgr.cpp libs/JSystem/src/JAHostIO/JAHioNode.cpp libs/JSystem/src/JAHostIO/JAHioUtil.cpp libs/JSystem/src/JAHostIO/JAHVirtualNode.cpp +) + +add_library(JSystem_JHostIO STATIC libs/JSystem/src/JHostIO/JORFile.cpp libs/JSystem/src/JHostIO/JORHostInfo.cpp libs/JSystem/src/JHostIO/JORMessageBox.cpp @@ -559,7 +619,28 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/JHostIO/JHIMccBuf.cpp ) -set(JSYSTEM_FILES +set(JSYSTEM_LIBRARIES + JSystem_JParticle + JSystem_JFramework + JSystem_J3DU + JSystem_JKernel + JSystem_JMath + JSystem_JSupport + JSystem_JUtility + JSystem_JStage + JSystem_J2DGraph + JSystem_J3DGraphBase + JSystem_J3DGraphAnimator + JSystem_J3DGraphLoader + JSystem_JStudio + JSystem_JStudio_JStage + JSystem_JStudio_JAudio2 + JSystem_JStudio_JParticle + JSystem_JAudio2 + JSystem_JMessage + JSystem_JGadget + JSystem_JAHostIO + JSystem_JHostIO ) set(REL_FILES @@ -1341,7 +1422,6 @@ set(DUSK_FILES src/dusk/crash_reporting.cpp src/dusk/endian.cpp src/dusk/extras.c - src/dusk/extras.cpp src/dusk/file_select.cpp src/dusk/file_select.hpp src/dusk/frame_interpolation.cpp diff --git a/include/global.h b/include/global.h index eda2a610ec..9301d12e11 100644 --- a/include/global.h +++ b/include/global.h @@ -73,6 +73,9 @@ #endif #ifndef __MWERKS__ +#ifdef __cplusplus +extern "C" { +#endif // Silence clangd errors about MWCC PPC intrinsics by declaring them here. extern int __cntlzw(unsigned int); extern int __rlwimi(int, int, int, int, int); @@ -80,7 +83,14 @@ extern void __dcbf(void*, int); extern void __dcbz(void*, int); extern void __sync(); extern int __abs(int); -void* __memcpy(void*, const void*, int); +#if defined(__has_builtin) && __has_builtin(__builtin_memcpy) +#define __memcpy __builtin_memcpy +#else +#define __memcpy memcpy +#endif +#ifdef __cplusplus +} +#endif #endif #ifndef M_PI diff --git a/src/dusk/extras.c b/src/dusk/extras.c index e693985479..a1fb26e998 100644 --- a/src/dusk/extras.c +++ b/src/dusk/extras.c @@ -3,6 +3,27 @@ #include #include +#ifdef _MSC_VER +#include +#endif + +void __dcbz(void* addr, int offset) { + // Gekko cache lines are 32 bytes. + // dcbz usually requires addr to be 32-byte aligned. + memset((char*)addr + offset, 0, 32); +} + +int __cntlzw(unsigned int val) { + if (val == 0) return 32; // PowerPC returns 32 if the input is 0 +#ifdef _MSC_VER + unsigned long idx; + _BitScanReverse(&idx, val); + return 31 - (int)idx; +#else + return __builtin_clz(val); +#endif +} + #ifndef _MSC_VER int stricmp(const char* str1, const char* str2) { char a_var; @@ -48,11 +69,6 @@ int strnicmp(const char* str1, const char* str2, int n) { } #endif - -void *_memcpy(void* dest, void const* src, int n) { - return memcpy(dest, src, n); -} - void DCZeroRange(void* addr, uint32_t nBytes) { #if defined(_MSC_VER) || TARGET_ANDROID memset(addr, 0, nBytes); diff --git a/src/dusk/extras.cpp b/src/dusk/extras.cpp deleted file mode 100644 index de402f028b..0000000000 --- a/src/dusk/extras.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// C++ Mangled version of extras.c -#include -#include -#ifdef _MSC_VER -#include -#endif - -void *__memcpy(void* dest, void const* src, int n) { - return memcpy(dest, src, n); -} - -void __dcbz(void* addr, int offset) { - // Gekko cache lines are 32 bytes. - // dcbz usually requires addr to be 32-byte aligned. - memset((char*)addr + offset, 0, 32); -} - -int __cntlzw(unsigned int val) { - if (val == 0) return 32; // PowerPC returns 32 if the input is 0 -#ifdef _MSC_VER - unsigned long idx; - _BitScanReverse(&idx, val); - return 31 - (int)idx; -#else - return __builtin_clz(val); -#endif -} From d625c7ab0ce686c8723241d6d902808531d2b696 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Thu, 23 Apr 2026 20:26:50 -0700 Subject: [PATCH 20/24] fix save editor clothes change crash --- src/dusk/imgui/ImGuiSaveEditor.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/dusk/imgui/ImGuiSaveEditor.cpp b/src/dusk/imgui/ImGuiSaveEditor.cpp index 5802c07b47..e91b718895 100644 --- a/src/dusk/imgui/ImGuiSaveEditor.cpp +++ b/src/dusk/imgui/ImGuiSaveEditor.cpp @@ -10,6 +10,7 @@ #include "d/d_item_data.h" #include "d/d_meter2_info.h" #include "d/d_save.h" +#include "d/actor/d_a_player.h" #include @@ -579,20 +580,21 @@ namespace dusk { if (ImGui::BeginCombo("Clothes", itemMap.find(statusA.mSelectEquip[0])->second.m_name.c_str())) { - if (ImGui::Selectable("None")) { - statusA.mSelectEquip[0] = dItemNo_NONE_e; - } if (ImGui::Selectable("Ordon Clothes")) { - statusA.mSelectEquip[0] = dItemNo_WEAR_CASUAL_e; + dMeter2Info_setCloth(dItemNo_WEAR_CASUAL_e, false); + daPy_getPlayerActorClass()->setClothesChange(0); } if (ImGui::Selectable("Hero's Clothes")) { - statusA.mSelectEquip[0] = dItemNo_WEAR_KOKIRI_e; + dMeter2Info_setCloth(dItemNo_WEAR_KOKIRI_e, false); + daPy_getPlayerActorClass()->setClothesChange(0); } if (ImGui::Selectable("Zora Armor")) { - statusA.mSelectEquip[0] = dItemNo_WEAR_ZORA_e; + dMeter2Info_setCloth(dItemNo_WEAR_ZORA_e, false); + daPy_getPlayerActorClass()->setClothesChange(0); } if (ImGui::Selectable("Magic Armor")) { - statusA.mSelectEquip[0] = dItemNo_ARMOR_e; + dMeter2Info_setCloth(dItemNo_ARMOR_e, false); + daPy_getPlayerActorClass()->setClothesChange(0); } ImGui::EndCombo(); } From 3cb5e5172b5d5c5dbf68df8b73e6327a1eb7fe23 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 23 Apr 2026 23:42:15 -0600 Subject: [PATCH 21/24] Add Adult Link eye LOD fix --- src/d/actor/d_a_alink_wolf.inc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/d/actor/d_a_alink_wolf.inc b/src/d/actor/d_a_alink_wolf.inc index 0a6da841c5..0e4e8f99c8 100644 --- a/src/d/actor/d_a_alink_wolf.inc +++ b/src/d/actor/d_a_alink_wolf.inc @@ -342,6 +342,26 @@ void daAlink_c::changeLink(int param_0) { initModel(static_cast(dComIfG_getObjectRes(mArcName, "zl_face.bmd")), 0x20200); } +#ifdef TARGET_PC + // Update Adult Link's eye maxLOD to prevent the eyes from disappearing + { + J3DTexture* tex = mpLinkFaceModel->getModelData()->getTexture(); + JUTNameTab* nametable = mpLinkFaceModel->getModelData()->getTextureName(); + if (tex != nullptr && nametable != nullptr) { + for (u16 i = 0; i < tex->getNum(); i++) { + const char* tex_name = nametable->getName(i); + if (tex_name != nullptr && + (strcmp(tex_name, "al_eyeball") == 0 || strcmp(tex_name, "highlight02") == 0 || + strcmp(tex_name, "eye_kage01") == 0)) + { + ResTIMG* timg = tex->getResTIMG(i); + timg->maxLOD = 0; + } + } + } + } +#endif + modelData = static_cast(dComIfG_getObjectRes(mArcName, "al_bootsH.bmd")); u16 i; for (i = 0; i < 2; i++) { From daf4b1dfeba637a8c6962a4f326fadfbb7bbddbc Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Thu, 23 Apr 2026 23:31:07 -0700 Subject: [PATCH 22/24] update aurora, add pre launch option to determine save file type (gci or raw) --- extern/aurora | 2 +- include/dusk/settings.h | 1 + src/dusk/imgui/ImGuiPreLaunchWindow.cpp | 28 +++++++++++++++++++++++++ src/dusk/settings.cpp | 4 +++- src/m_Do/m_Do_MemCard.cpp | 2 ++ 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/extern/aurora b/extern/aurora index 524b683fe0..be1395c134 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 524b683fe07710350358846fe31155bbc8b60fc5 +Subproject commit be1395c1343a5587cceea25754daa5cacce34f76 diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 6596adf92d..039e51af7d 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -127,6 +127,7 @@ struct UserSettings { ConfigVar wasPresetChosen; ConfigVar enableCrashReporting; ConfigVar duskMenuOpen; + ConfigVar cardFileType; } backend; }; diff --git a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp index ecbd41e158..8eff1be8d4 100644 --- a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp +++ b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp @@ -46,6 +46,17 @@ static std::string ShowIsoInvalidError(const iso::ValidationError code) { } } +static std::string_view card_type_name(CARDFileType type) { + switch (type) { + case CARD_GCIFOLDER: + return "GCI Folder"sv; + case CARD_RAWIMAGE: + return "Card Image"sv; + default: + return ""sv; + } +} + void fileDialogCallback(void* userdata, const char* path, const char* error) { auto* self = static_cast(userdata); if (error != nullptr) { @@ -216,6 +227,23 @@ void ImGuiPreLaunchWindow::drawOptions() { if (configuredBackendId != m_initialGraphicsBackend) { ImGui::TextDisabled("Restart Required"); } + auto curFileType = (CARDFileType)getSettings().backend.cardFileType.getValue(); + + if (ImGui::BeginCombo("Save File Type", card_type_name(curFileType).data())) {\ + + if (ImGui::Selectable("GCI Folder", curFileType == CARD_GCIFOLDER)) { + getSettings().backend.cardFileType.setValue(CARD_GCIFOLDER); + config::Save(); + } + + if (ImGui::Selectable("Card Image", curFileType == CARD_RAWIMAGE)) { + getSettings().backend.cardFileType.setValue(CARD_RAWIMAGE); + config::Save(); + } + + ImGui::EndCombo(); + } + ImGui::EndChild(); } diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index bdaa654cc0..3e6ee733fe 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -99,7 +99,8 @@ UserSettings g_userSettings = { .showPipelineCompilation {"backend.showPipelineCompilation", false}, .wasPresetChosen {"backend.wasPresetChosen", false}, .enableCrashReporting {"backend.enableCrashReporting", true}, - .duskMenuOpen {"backend.duskMenuOpen", false} + .duskMenuOpen {"backend.duskMenuOpen", false}, + .cardFileType {"backend.cardFileType", static_cast(CARD_GCIFOLDER)} } }; @@ -185,6 +186,7 @@ void registerSettings() { Register(g_userSettings.backend.wasPresetChosen); Register(g_userSettings.backend.enableCrashReporting); Register(g_userSettings.backend.duskMenuOpen); + Register(g_userSettings.backend.cardFileType); } // Transient settings diff --git a/src/m_Do/m_Do_MemCard.cpp b/src/m_Do/m_Do_MemCard.cpp index a0c0302b09..5cb612f128 100644 --- a/src/m_Do/m_Do_MemCard.cpp +++ b/src/m_Do/m_Do_MemCard.cpp @@ -77,6 +77,8 @@ static OSThread MemCardThread; void mDoMemCd_Ctrl_c::ThdInit() { #if !PLATFORM_SHIELD + CARDSetLoadType((CARDFileType)dusk::getSettings().backend.cardFileType.getValue()); + CARDInit(DUSK_GAME_NAME, DUSK_GAME_VERSION); #endif From 78301a8a83addfb5ac4f9771a163c7ff3533254c Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 24 Apr 2026 00:39:03 -0600 Subject: [PATCH 23/24] Restore half-size in drawDepth2 --- src/m_Do/m_Do_graphic.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index 4dc505ac03..425d1e25fe 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -1029,15 +1029,8 @@ static void drawDepth2(view_class* param_0, view_port_class* param_1, int param_ GX_FALSE, 0); } - #if TARGET_PC - // use full size for pc for higher quality background elements - u16 halfWidth = width; - u16 halfHeight = height; - #else u16 halfWidth = width >> 1; u16 halfHeight = height >> 1; - #endif - GXRenderModeObj* sp24 = JUTGetVideoManager()->getRenderMode(); GXSetCopyFilter(GX_FALSE, NULL, GX_TRUE, sp24->vfilter); GXSetTexCopySrc(x_orig, y_orig_pos, width, height); From 1c00e2cdde9e1f22db6171350482f25dc6add9fc Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Thu, 23 Apr 2026 23:40:20 -0700 Subject: [PATCH 24/24] fix unsafe cstr usage in flag editor, remove stray backslash --- src/dusk/imgui/ImGuiPreLaunchWindow.cpp | 2 +- src/dusk/imgui/ImGuiSaveEditor.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp index 8eff1be8d4..2727e78718 100644 --- a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp +++ b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp @@ -229,7 +229,7 @@ void ImGuiPreLaunchWindow::drawOptions() { } auto curFileType = (CARDFileType)getSettings().backend.cardFileType.getValue(); - if (ImGui::BeginCombo("Save File Type", card_type_name(curFileType).data())) {\ + if (ImGui::BeginCombo("Save File Type", card_type_name(curFileType).data())) { if (ImGui::Selectable("GCI Folder", curFileType == CARD_GCIFOLDER)) { getSettings().backend.cardFileType.setValue(CARD_GCIFOLDER); diff --git a/src/dusk/imgui/ImGuiSaveEditor.cpp b/src/dusk/imgui/ImGuiSaveEditor.cpp index e91b718895..eced44c7f7 100644 --- a/src/dusk/imgui/ImGuiSaveEditor.cpp +++ b/src/dusk/imgui/ImGuiSaveEditor.cpp @@ -1491,11 +1491,11 @@ namespace dusk { } ImGui::TableNextColumn(); - ImGui::Text(e.flagName.c_str()); + ImGuiStringViewText(e.flagName); ImGui::TableNextColumn(); - ImGui::Text(e.location.c_str()); + ImGuiStringViewText(e.location); ImGui::TableNextColumn(); - ImGui::Text(e.description.c_str()); + ImGuiStringViewText(e.description); } ImGui::EndTable(); }