From a68a987573c70db074b377e2124fe69984b88403 Mon Sep 17 00:00:00 2001 From: Tim Xie Date: Wed, 20 May 2026 01:12:30 +0800 Subject: [PATCH 1/3] Add equipment deselection toggle for swords, shields, and clothes --- include/dusk/settings.h | 4 ++ src/d/actor/d_a_alink.cpp | 7 ++ src/d/d_menu_collect.cpp | 134 +++++++++++++++++++++++++++++++++++++- src/dusk/settings.cpp | 6 ++ src/dusk/ui/settings.cpp | 5 ++ 5 files changed, 154 insertions(+), 2 deletions(-) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index bd6f30683b..273898853e 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -133,6 +133,10 @@ struct UserSettings { ConfigVar instantText; ConfigVar sunsSong; ConfigVar autoSave; + ConfigVar enableDeselectSwords; + ConfigVar enableDeselectShields; + ConfigVar enableDeselectClothes; + // Preferences ConfigVar enableMirrorMode; diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index e2fe7a890c..da1ce5d918 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -4912,9 +4912,16 @@ int daAlink_c::create() { } else #endif // Event Flag: Finished Sewers +#if TARGET_PC + if (checkCasualWearFlg() && dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[47]) + && !dusk::getSettings().game.enableDeselectClothes) { + dComIfGs_setSelectEquipClothes(dItemNo_WEAR_KOKIRI_e); + } +#else if (checkCasualWearFlg() && dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[47])) { dComIfGs_setSelectEquipClothes(dItemNo_WEAR_KOKIRI_e); } +#endif if (isEnteringLV7 && checkMagicArmorHeavy()) { dComIfGs_setSelectEquipClothes(dItemNo_WEAR_KOKIRI_e); diff --git a/src/d/d_menu_collect.cpp b/src/d/d_menu_collect.cpp index 612806d372..90049d26d1 100644 --- a/src/d/d_menu_collect.cpp +++ b/src/d/d_menu_collect.cpp @@ -36,6 +36,10 @@ #include "d/d_menu_window.h" #include "JSystem/J3DGraphBase/J3DMaterial.h" +#if TARGET_PC +#include "dusk/settings.h" +#endif + typedef void (dMenu_Collect2D_c::*initFunc)(); static initFunc init[] = { &dMenu_Collect2D_c::wait_init, &dMenu_Collect2D_c::save_open_init, @@ -497,6 +501,18 @@ void dMenu_Collect2D_c::screenSet() { field_0x22d[0][2] = 0; field_0x22d[1][2] = 0; field_0x22d[2][2] = 0; +#if TARGET_PC + if (dComIfGs_getSelectEquipClothes() == dItemNo_WEAR_CASUAL_e + && !dusk::getSettings().game.enableDeselectClothes) { + field_0x22d[3][2] = 0; + field_0x22d[4][2] = 0; + field_0x22d[5][2] = 0; + } else { + field_0x22d[3][2] = dComIfGs_isItemFirstBit(0x2F); + field_0x22d[4][2] = dComIfGs_isItemFirstBit(0x31); + field_0x22d[5][2] = dComIfGs_isItemFirstBit(0x30); + } +#else if (dComIfGs_getSelectEquipClothes() == dItemNo_WEAR_CASUAL_e) { field_0x22d[3][2] = 0; field_0x22d[4][2] = 0; @@ -506,6 +522,7 @@ void dMenu_Collect2D_c::screenSet() { field_0x22d[4][2] = dComIfGs_isItemFirstBit(0x31); field_0x22d[5][2] = dComIfGs_isItemFirstBit(0x30); } +#endif field_0x22d[6][2] = 0; field_0x22d[0][3] = 1; if (checkItemGet(dItemNo_BOW_e, 1)) { @@ -1129,15 +1146,32 @@ void dMenu_Collect2D_c::changeSword() { mDoAud_seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0); dMeter2Info_set2DVibration(); } +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectSwords) { + dMeter2Info_setSword(dItemNo_NONE_e, false); + setEquipItemFrameColorSword(-1); + mDoAud_seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0); + dMeter2Info_set2DVibration(); + } +#endif } else if (dComIfGs_getSelectEquipSword() != dItemNo_WOOD_STICK_e) { dMeter2Info_setSword(dItemNo_WOOD_STICK_e, false); setEquipItemFrameColorSword(0); Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); dMeter2Info_set2DVibration(); } +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectSwords) { + dMeter2Info_setSword(dItemNo_NONE_e, false); + setEquipItemFrameColorSword(0); + Z2GetAudioMgr()->seStart( + Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + dMeter2Info_set2DVibration(); + } +#endif break; case 4: - if (dComIfGs_isItemFirstBit(dItemNo_LIGHT_SWORD_e)) { + if (dComIfGs_isItemFirstBit(dItemNo_LIGHT_SWORD_e)) { if (dComIfGs_getSelectEquipSword() != dItemNo_LIGHT_SWORD_e) { dMeter2Info_setSword(dItemNo_LIGHT_SWORD_e, false); setEquipItemFrameColorSword(1); @@ -1145,12 +1179,29 @@ void dMenu_Collect2D_c::changeSword() { 0); dMeter2Info_set2DVibration(); } - } else if (dComIfGs_getSelectEquipSword() != dItemNo_MASTER_SWORD_e) { +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectSwords) { + dMeter2Info_setSword(dItemNo_NONE_e, false); + setEquipItemFrameColorSword(-1); + mDoAud_seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0); + dMeter2Info_set2DVibration(); + } +#endif + } + else if (dComIfGs_getSelectEquipSword() != dItemNo_MASTER_SWORD_e) { dMeter2Info_setSword(dItemNo_MASTER_SWORD_e, false); setEquipItemFrameColorSword(1); Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); dMeter2Info_set2DVibration(); } +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectSwords) { + dMeter2Info_setSword(dItemNo_NONE_e, false); + setEquipItemFrameColorSword(-1); + mDoAud_seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0); + dMeter2Info_set2DVibration(); + } +#endif break; case 5: if (dComIfGs_getSelectEquipSword() != dItemNo_LIGHT_SWORD_e) { @@ -1159,6 +1210,14 @@ void dMenu_Collect2D_c::changeSword() { Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); dMeter2Info_set2DVibration(); } +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectSwords) { + dMeter2Info_setSword(dItemNo_NONE_e, false); + setEquipItemFrameColorSword(-1); + mDoAud_seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0); + dMeter2Info_set2DVibration(); + } +#endif break; } } @@ -1175,6 +1234,16 @@ void dMenu_Collect2D_c::changeShield() { 0); dMeter2Info_set2DVibration(); } +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectShields) { + dMeter2Info_setShield(dItemNo_NONE_e, false); + setEquipItemFrameColorShield(-1); + daAlink_getAlinkActorClass()->setShieldChange(); + Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, + 0); + dMeter2Info_set2DVibration(); + } +#endif } else if (dComIfGs_isItemFirstBit(dItemNo_WOOD_SHIELD_e)) { if (dComIfGs_getSelectEquipShield() != dItemNo_WOOD_SHIELD_e) { dMeter2Info_setShield(dItemNo_WOOD_SHIELD_e, false); @@ -1184,6 +1253,16 @@ void dMenu_Collect2D_c::changeShield() { 0); dMeter2Info_set2DVibration(); } +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectShields) { + dMeter2Info_setShield(dItemNo_NONE_e, false); + setEquipItemFrameColorShield(-1); + daAlink_getAlinkActorClass()->setShieldChange(); + Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, + 0); + dMeter2Info_set2DVibration(); + } +#endif } break; case 4: @@ -1194,6 +1273,15 @@ void dMenu_Collect2D_c::changeShield() { Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); dMeter2Info_set2DVibration(); } +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectShields) { + dMeter2Info_setShield(dItemNo_NONE_e, false); + setEquipItemFrameColorShield(-1); + daAlink_getAlinkActorClass()->setShieldChange(); + Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + dMeter2Info_set2DVibration(); + } +#endif break; } } @@ -1208,6 +1296,15 @@ void dMenu_Collect2D_c::changeClothe() { Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); dMeter2Info_set2DVibration(); } +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectClothes) { + dMeter2Info_setCloth(dItemNo_WEAR_CASUAL_e, false); + setEquipItemFrameColorClothes(-1); + daPy_getPlayerActorClass()->setClothesChange(0); + Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + dMeter2Info_set2DVibration(); + } +#endif break; case 4: if (dComIfGs_getSelectEquipClothes() != dItemNo_WEAR_ZORA_e) { @@ -1217,6 +1314,15 @@ void dMenu_Collect2D_c::changeClothe() { Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); dMeter2Info_set2DVibration(); } +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectClothes) { + dMeter2Info_setCloth(dItemNo_WEAR_CASUAL_e, false); + setEquipItemFrameColorClothes(-1); + daPy_getPlayerActorClass()->setClothesChange(0); + Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + dMeter2Info_set2DVibration(); + } +#endif break; case 5: if (dComIfGs_getSelectEquipClothes() != dItemNo_ARMOR_e) { @@ -1226,6 +1332,15 @@ void dMenu_Collect2D_c::changeClothe() { Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); dMeter2Info_set2DVibration(); } +#if TARGET_PC + else if (dusk::getSettings().game.enableDeselectClothes) { + dMeter2Info_setCloth(dItemNo_WEAR_CASUAL_e, false); + setEquipItemFrameColorClothes(-1); + daPy_getPlayerActorClass()->setClothesChange(0); + Z2GetAudioMgr()->seStart(Z2SE_SY_ITEM_SET_X, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + dMeter2Info_set2DVibration(); + } +#endif break; } } @@ -1426,6 +1541,11 @@ void dMenu_Collect2D_c::setEquipItemFrameColorSword(int i_frame) { } } } else { +#if TARGET_PC + if (dusk::getSettings().game.enableDeselectSwords) { + mEquippedSword = dComIfGs_getSelectEquipSword(); + } +#endif for (int i = 0; i < 2; i++) { if (i == i_frame && field_0x22d[i + 3][0] != 0) { static_cast(mpScreen->search(tag[i])) @@ -1474,6 +1594,11 @@ void dMenu_Collect2D_c::setEquipItemFrameColorShield(int i_frame) { } } } else { +#if TARGET_PC + if (dusk::getSettings().game.enableDeselectShields) { + mEquippedShield = dComIfGs_getSelectEquipShield(); + } +#endif for (int i = 0; i < 2; i++) { if (i == i_frame && field_0x22d[i + 3][1] != 0) { static_cast(mpScreen->search(tag[i])) @@ -1526,6 +1651,11 @@ void dMenu_Collect2D_c::setEquipItemFrameColorClothes(int i_frame) { } } } else { +#if TARGET_PC + if (dusk::getSettings().game.enableDeselectClothes) { + mEquippedClothes = dComIfGs_getSelectEquipClothes(); + } +#endif for (int i = 0; i < 3; i++) { if (i == i_frame && field_0x22d[i + 3][2] != 0) { static_cast(mpScreen->search(tag[i])) diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 5861241fe3..afb5c38df7 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -45,6 +45,9 @@ UserSettings g_userSettings = { .instantText {"game.instantText", false}, .sunsSong {"game.sunsSong", false}, .autoSave {"game.autoSave", false}, + .enableDeselectSwords {"game.enableDeselectSwords", false}, + .enableDeselectShields {"game.enableDeselectShields", false}, + .enableDeselectClothes {"game.enableDeselectClothes", false}, // Preferences .enableMirrorMode {"game.enableMirrorMode", false}, @@ -210,6 +213,9 @@ void registerSettings() { Register(g_userSettings.game.instantText); Register(g_userSettings.game.sunsSong); Register(g_userSettings.game.autoSave); + Register(g_userSettings.game.enableDeselectSwords); + Register(g_userSettings.game.enableDeselectShields); + Register(g_userSettings.game.enableDeselectClothes); Register(g_userSettings.game.enableMirrorMode); Register(g_userSettings.game.invertCameraXAxis); Register(g_userSettings.game.invertCameraYAxis); diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 9cf8a2f5d2..fdfbbf67d3 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -1164,6 +1164,11 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { addOption("Quick Transform (R+Y)", getSettings().game.enableQuickTransform, "Transform instantly by pressing R and Y simultaneously."); + leftPane.add_section("Equipments"); + addOption("Enable Deselect Swords", getSettings().game.enableDeselectSwords, "Allows Link to deselect swords. Link will be unable to attack with a sword."); + addOption("Enable Deselect Shields", getSettings().game.enableDeselectShields, "Allows Link to deselect shields. Link will be unable to defend with a shield."); + addOption("Enable Deselect Clothes", getSettings().game.enableDeselectClothes, "Allows Link to deselect clothes. Link will wear Ordon Clothes."); + leftPane.add_section("Speedrunning"); config_bool_select(leftPane, rightPane, getSettings().game.speedrunMode, { From 403f96042d98a40f00f56551e97dcdc92bcb6736 Mon Sep 17 00:00:00 2001 From: Tim Xie Date: Wed, 20 May 2026 19:03:44 +0800 Subject: [PATCH 2/3] Group deselection settings under one select button in Equipment section --- src/dusk/ui/settings.cpp | 42 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index fdfbbf67d3..30f48fe06c 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -1165,9 +1165,45 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { "Transform instantly by pressing R and Y simultaneously."); leftPane.add_section("Equipments"); - addOption("Enable Deselect Swords", getSettings().game.enableDeselectSwords, "Allows Link to deselect swords. Link will be unable to attack with a sword."); - addOption("Enable Deselect Shields", getSettings().game.enableDeselectShields, "Allows Link to deselect shields. Link will be unable to defend with a shield."); - addOption("Enable Deselect Clothes", getSettings().game.enableDeselectClothes, "Allows Link to deselect clothes. Link will wear Ordon Clothes."); + leftPane.register_control( + leftPane.add_select_button({ + .key = "Equipment Deselection", + .getValue = [] { + int count = 0; + if (getSettings().game.enableDeselectSwords.getValue()) count++; + if (getSettings().game.enableDeselectShields.getValue()) count++; + if (getSettings().game.enableDeselectClothes.getValue()) count++; + return Rml::String{fmt::format("{} / 3", count)}; + }, + .isModified = [] { + return getSettings().game.enableDeselectSwords.getValue() != + getSettings().game.enableDeselectSwords.getDefaultValue() + || getSettings().game.enableDeselectShields.getValue() != + getSettings().game.enableDeselectShields.getDefaultValue() + || getSettings().game.enableDeselectClothes.getValue() != + getSettings().game.enableDeselectClothes.getDefaultValue(); + }, + }), + rightPane, [](Pane& pane) { + pane.clear(); + pane.add_rml( + "Allows deselection of equipped items from the Collections menu."); + + auto addSubToggle = [&pane](const Rml::String& text, ConfigVar& var) { + pane.add_button({ + .text = text, + .isSelected = [&var] { return var.getValue(); }, + }).on_pressed([&var] { + mDoAud_seStartMenu(kSoundItemChange); + var.setValue(!var.getValue()); + config::Save(); + }); + }; + + addSubToggle("Deselect Swords", getSettings().game.enableDeselectSwords); + addSubToggle("Deselect Shields", getSettings().game.enableDeselectShields); + addSubToggle("Deselect Clothes", getSettings().game.enableDeselectClothes); + }); leftPane.add_section("Speedrunning"); config_bool_select(leftPane, rightPane, getSettings().game.speedrunMode, From 282a8526ccf0ffedd147e779625838747f252f14 Mon Sep 17 00:00:00 2001 From: Tim Xie Date: Wed, 20 May 2026 19:12:21 +0800 Subject: [PATCH 3/3] Auto-switch to Hero's Clothes when deselect is disabled and wearing Ordon Clothes --- src/d/d_menu_collect.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/d/d_menu_collect.cpp b/src/d/d_menu_collect.cpp index 90049d26d1..412eadc38f 100644 --- a/src/d/d_menu_collect.cpp +++ b/src/d/d_menu_collect.cpp @@ -502,6 +502,12 @@ void dMenu_Collect2D_c::screenSet() { field_0x22d[1][2] = 0; field_0x22d[2][2] = 0; #if TARGET_PC + if (dComIfGs_getSelectEquipClothes() == dItemNo_WEAR_CASUAL_e + && !dusk::getSettings().game.enableDeselectClothes + && dComIfGs_isItemFirstBit(dItemNo_WEAR_KOKIRI_e)) { + dMeter2Info_setCloth(dItemNo_WEAR_KOKIRI_e, false); + daPy_getPlayerActorClass()->setClothesChange(0); + } if (dComIfGs_getSelectEquipClothes() == dItemNo_WEAR_CASUAL_e && !dusk::getSettings().game.enableDeselectClothes) { field_0x22d[3][2] = 0;