From 68e7481ef000d7813249a5f30b10061c2e470ee4 Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Wed, 13 May 2026 17:36:14 -0400 Subject: [PATCH 1/4] More Magic Armor Options - Add a 3rd option to lose rupees only on damage --- include/dusk/settings.h | 14 ++++++++++- src/d/actor/d_a_alink.cpp | 4 ++-- src/d/actor/d_a_alink_damage.inc | 2 +- src/d/actor/d_a_alink_wolf.inc | 4 ++-- src/dusk/config.cpp | 1 + src/dusk/settings.cpp | 4 ++-- src/dusk/speedrun.cpp | 2 +- src/dusk/ui/settings.cpp | 41 +++++++++++++++++++++++++++++--- 8 files changed, 60 insertions(+), 12 deletions(-) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 43e565ed5e..be8d6e18d0 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -34,6 +34,12 @@ enum class GyroMode : u8 { Mouse = 1, }; +enum class MagicArmorMode : u8 { + NORMAL = 0, + ON_DAMAGE = 1, + NEVER = 2, +}; + namespace config { template <> struct ConfigEnumRange { @@ -58,6 +64,12 @@ struct ConfigEnumRange { static constexpr auto min = GyroMode::Sensor; static constexpr auto max = GyroMode::Mouse; }; + +template <> +struct ConfigEnumRange { + static constexpr auto min = MagicArmorMode::NORMAL; + static constexpr auto max = MagicArmorMode::NEVER; +}; } // Persistent user settings @@ -171,7 +183,7 @@ struct UserSettings { ConfigVar canTransformAnywhere; ConfigVar fastRoll; ConfigVar fastSpinner; - ConfigVar freeMagicArmor; + ConfigVar armorRupeeDrain; ConfigVar invincibleEnemies; // Technical diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index 498d3de173..f9b4304d80 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -12738,7 +12738,7 @@ void daAlink_c::setMagicArmorBrk(int i_status) { BOOL daAlink_c::checkMagicArmorHeavy() const { #if TARGET_PC - return checkMagicArmorWearAbility() && (dComIfGs_getRupee() == 0 && !dusk::getSettings().game.freeMagicArmor); + return checkMagicArmorWearAbility() && (dComIfGs_getRupee() == 0 && dusk::getSettings().game.armorRupeeDrain.getValue() == dusk::MagicArmorMode::NORMAL); #else return checkMagicArmorWearAbility() && dComIfGs_getRupee() == 0; #endif @@ -18711,7 +18711,7 @@ int daAlink_c::execute() { #if TARGET_PC // This handles rupee drain and transitions between rupees/no rupees // We can skip all of that if the magic armor doesn't use rupees - if (!dusk::getSettings().game.freeMagicArmor && checkMagicArmorWearAbility() && mClothesChangeWaitTimer == 0) { + if (dusk::getSettings().game.armorRupeeDrain.getValue() == dusk::MagicArmorMode::NORMAL && checkMagicArmorWearAbility() && mClothesChangeWaitTimer == 0) { #else if (checkMagicArmorWearAbility() && mClothesChangeWaitTimer == 0) { #endif diff --git a/src/d/actor/d_a_alink_damage.inc b/src/d/actor/d_a_alink_damage.inc index bccdbf7381..d4e96b0ff0 100644 --- a/src/d/actor/d_a_alink_damage.inc +++ b/src/d/actor/d_a_alink_damage.inc @@ -192,7 +192,7 @@ int daAlink_c::setDamagePoint(int i_dmgAmount, BOOL i_checkZoraMag, BOOL i_setDm if (checkMagicArmorNoDamage()) { #if TARGET_PC - if(dusk::getSettings().game.freeMagicArmor) { + if(dusk::getSettings().game.armorRupeeDrain.getValue() == dusk::MagicArmorMode::NEVER) { i_dmgAmount = 0; } #endif diff --git a/src/d/actor/d_a_alink_wolf.inc b/src/d/actor/d_a_alink_wolf.inc index b2e60aea01..d3708368f9 100644 --- a/src/d/actor/d_a_alink_wolf.inc +++ b/src/d/actor/d_a_alink_wolf.inc @@ -348,7 +348,7 @@ void daAlink_c::changeLink(int param_0) { initModel(static_cast(dComIfG_getObjectRes(l_mArcName, "al_hands.bmd")), 0); #if TARGET_PC - if (dComIfGs_getRupee() != 0 || dusk::getSettings().game.freeMagicArmor) + if (dComIfGs_getRupee() != 0 || dusk::getSettings().game.armorRupeeDrain.getValue() != dusk::MagicArmorMode::NORMAL) #else if (dComIfGs_getRupee() != 0) #endif @@ -458,7 +458,7 @@ void daAlink_c::changeLink(int param_0) { field_0x06f0 = field_0x064C->getMaterialNodePointer(2)->getShape(); #if TARGET_PC - if (dComIfGs_getRupee() != 0 || dusk::getSettings().game.freeMagicArmor) { + if (dComIfGs_getRupee() != 0 || dusk::getSettings().game.armorRupeeDrain.getValue() != dusk::MagicArmorMode::NORMAL) { #else if (dComIfGs_getRupee() != 0) { #endif diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index de4cc227a3..69f36bc414 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -158,6 +158,7 @@ namespace dusk::config { template class ConfigImpl; template class ConfigImpl; template class ConfigImpl; + template class ConfigImpl; } void dusk::config::Register(ConfigVarBase& configVar) { diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 5e3f73a366..f43f1d0773 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -106,7 +106,7 @@ UserSettings g_userSettings = { .canTransformAnywhere {"game.canTransformAnywhere", false}, .fastRoll {"game.fastRoll", false}, .fastSpinner {"game.fastSpinner", false}, - .freeMagicArmor {"game.freeMagicArmor", false}, + .armorRupeeDrain {"game.armorRupeeDrain", MagicArmorMode::NORMAL}, .invincibleEnemies {"game.invincibleEnemies", false}, // Technical @@ -226,7 +226,7 @@ void registerSettings() { Register(g_userSettings.game.enableFastIronBoots); Register(g_userSettings.game.canTransformAnywhere); Register(g_userSettings.game.fastRoll); - Register(g_userSettings.game.freeMagicArmor); + Register(g_userSettings.game.armorRupeeDrain); Register(g_userSettings.game.restoreWiiGlitches); Register(g_userSettings.game.enableLinkDollRotation); Register(g_userSettings.game.enableAchievementToasts); diff --git a/src/dusk/speedrun.cpp b/src/dusk/speedrun.cpp index feb2178c41..38488600b1 100644 --- a/src/dusk/speedrun.cpp +++ b/src/dusk/speedrun.cpp @@ -33,7 +33,7 @@ void resetForSpeedrunMode() { getSettings().game.canTransformAnywhere.setSpeedrunValue(false); getSettings().game.fastRoll.setSpeedrunValue(false); getSettings().game.fastSpinner.setSpeedrunValue(false); - getSettings().game.freeMagicArmor.setSpeedrunValue(false); + getSettings().game.armorRupeeDrain.setSpeedrunValue(MagicArmorMode::NORMAL); getSettings().game.pauseOnFocusLost.setSpeedrunValue(false); aurora_set_pause_on_focus_lost(false); diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 2ee51029ab..157cef73d3 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -61,6 +61,12 @@ constexpr std::array kGyroInputModeLabels = { "Mouse", }; +constexpr std::array kMagicArmorModes = { + "Normal", + "On Damage", + "Never", +}; + bool try_parse_backend(std::string_view backend, AuroraBackend& outBackend) { if (backend == "auto") { outBackend = BACKEND_AUTO; @@ -197,7 +203,7 @@ void reset_for_speedrun_mode() { getSettings().game.canTransformAnywhere.setSpeedrunValue(false); getSettings().game.fastRoll.setSpeedrunValue(false); getSettings().game.fastSpinner.setSpeedrunValue(false); - getSettings().game.freeMagicArmor.setSpeedrunValue(false); + getSettings().game.armorRupeeDrain.setSpeedrunValue(MagicArmorMode::NORMAL); getSettings().game.invincibleEnemies.setSpeedrunValue(false); getSettings().game.pauseOnFocusLost.setSpeedrunValue(false); @@ -1134,8 +1140,37 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { "Makes Link's roll animation and movement twice as fast."); addCheat("Fast Spinner", getSettings().game.fastSpinner, "Speeds up Spinner movement while holding R."); - addCheat("Free Magic Armor", getSettings().game.freeMagicArmor, - "Lets the magic armor work without consuming rupees."); + leftPane.register_control( + leftPane.add_select_button({ + .key = "Magic Armor Rupee Drain", + .getValue = + [] { + return kMagicArmorModes[static_cast(getSettings().game.armorRupeeDrain.getValue())]; + }, + .isDisabled = [] { return getSettings().game.speedrunMode; }, + .isModified = + [] { + return getSettings().game.armorRupeeDrain.getValue() != + getSettings().game.armorRupeeDrain.getDefaultValue(); + }, + }), + rightPane, [](Pane& pane) { + for (int i = 0; i < kMagicArmorModes.size(); i++) { + pane.add_button({ + .text = kMagicArmorModes[i], + .isSelected = + [i] { + return getSettings().game.armorRupeeDrain.getValue() == static_cast(i); + }, + }) + .on_pressed([i] { + mDoAud_seStartMenu(kSoundItemChange); + getSettings().game.armorRupeeDrain.setValue(static_cast(i)); + config::Save(); + }); + } + pane.add_rml("Control when the Magic Armor uses rupees."); + }); addCheat("Invincible Enemies", getSettings().game.invincibleEnemies, "Prevents enemies from taking damage."); }); From 899ae155700ad056bae5445b21355920d3f963aa Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Thu, 14 May 2026 17:32:48 -0400 Subject: [PATCH 2/4] More Choices - Add cosmetic and double defense options These both have been requested a couple times --- include/dusk/settings.h | 6 ++++-- src/d/actor/d_a_alink.cpp | 14 +++++++++++++- src/d/actor/d_a_alink_damage.inc | 26 +++++++++++++++++++++++++- src/dusk/ui/settings.cpp | 14 +++++++++++--- 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index be8d6e18d0..874ad08f0b 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -37,7 +37,9 @@ enum class GyroMode : u8 { enum class MagicArmorMode : u8 { NORMAL = 0, ON_DAMAGE = 1, - NEVER = 2, + DOUBLE_DEFENSE = 2, + INVINCIBLE = 3, + COSMETIC = 4, }; namespace config { @@ -68,7 +70,7 @@ struct ConfigEnumRange { template <> struct ConfigEnumRange { static constexpr auto min = MagicArmorMode::NORMAL; - static constexpr auto max = MagicArmorMode::NEVER; + static constexpr auto max = MagicArmorMode::COSMETIC; }; } diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index f9b4304d80..b1206dffe3 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -12738,7 +12738,19 @@ void daAlink_c::setMagicArmorBrk(int i_status) { BOOL daAlink_c::checkMagicArmorHeavy() const { #if TARGET_PC - return checkMagicArmorWearAbility() && (dComIfGs_getRupee() == 0 && dusk::getSettings().game.armorRupeeDrain.getValue() == dusk::MagicArmorMode::NORMAL); + if(!checkMagicArmorWearAbility()) { + return false; + } + + switch(dusk::getSettings().game.armorRupeeDrain) { + case dusk::MagicArmorMode::NORMAL: + return dComIfGs_getRupee() == 0; + case dusk::MagicArmorMode::ON_DAMAGE: + case dusk::MagicArmorMode::DOUBLE_DEFENSE: + case dusk::MagicArmorMode::INVINCIBLE: + case dusk::MagicArmorMode::COSMETIC: + return false; + } #else return checkMagicArmorWearAbility() && dComIfGs_getRupee() == 0; #endif diff --git a/src/d/actor/d_a_alink_damage.inc b/src/d/actor/d_a_alink_damage.inc index d4e96b0ff0..a57e71bcee 100644 --- a/src/d/actor/d_a_alink_damage.inc +++ b/src/d/actor/d_a_alink_damage.inc @@ -192,7 +192,7 @@ int daAlink_c::setDamagePoint(int i_dmgAmount, BOOL i_checkZoraMag, BOOL i_setDm if (checkMagicArmorNoDamage()) { #if TARGET_PC - if(dusk::getSettings().game.armorRupeeDrain.getValue() == dusk::MagicArmorMode::NEVER) { + if(dusk::getSettings().game.armorRupeeDrain.getValue() == dusk::MagicArmorMode::INVINCIBLE) { i_dmgAmount = 0; } #endif @@ -202,6 +202,11 @@ int daAlink_c::setDamagePoint(int i_dmgAmount, BOOL i_checkZoraMag, BOOL i_setDm if (!mpHIO->mDamage.m.mInvincible && g_debugHpMode == 0) #endif { +#if TARGET_PC + if(checkMagicArmorWearAbility() && dusk::getSettings().game.armorRupeeDrain.getValue() == dusk::MagicArmorMode::DOUBLE_DEFENSE) { + i_dmgAmount /= 2; + } +#endif dComIfGp_setItemLifeCount(-i_dmgAmount, 0); } @@ -281,7 +286,26 @@ BOOL daAlink_c::checkIcePolygonDamage(cBgS_PolyInfo* i_poly) { } BOOL daAlink_c::checkMagicArmorNoDamage() { +#ifdef TARGET_PC + if (!checkMagicArmorWearAbility()) { + return false; + } + + switch(dusk::getSettings().game.armorRupeeDrain) { + case dusk::MagicArmorMode::NORMAL: + return !checkMagicArmorHeavy(); + case dusk::MagicArmorMode::ON_DAMAGE: + return dComIfGs_getRupee() != 0; + case dusk::MagicArmorMode::DOUBLE_DEFENSE: + return false; + case dusk::MagicArmorMode::INVINCIBLE: + return true; + case dusk::MagicArmorMode::COSMETIC: + return false; + } +#else return checkMagicArmorWearAbility() && !checkMagicArmorHeavy(); +#endif } int daAlink_c::checkPolyDamage() { diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 157cef73d3..1de757628f 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -64,7 +64,9 @@ constexpr std::array kGyroInputModeLabels = { constexpr std::array kMagicArmorModes = { "Normal", "On Damage", - "Never", + "Double Defense", + "Invincible", + "Cosmetic", }; bool try_parse_backend(std::string_view backend, AuroraBackend& outBackend) { @@ -1142,7 +1144,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { "Speeds up Spinner movement while holding R."); leftPane.register_control( leftPane.add_select_button({ - .key = "Magic Armor Rupee Drain", + .key = "Magic Armor Behavior", .getValue = [] { return kMagicArmorModes[static_cast(getSettings().game.armorRupeeDrain.getValue())]; @@ -1169,7 +1171,13 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { config::Save(); }); } - pane.add_rml("Control when the Magic Armor uses rupees."); + pane.add_rml( + "
Control the behavior of the Magic Armor." + "
Normal is its original behavior." + "
On Damage only uses rupees when damaged. You will not become heavy when you run out." + "
Double Defense never uses rupees and halves damage taken." + "
Invincible never uses rupees and is immune to damage." + "
Cosmetic uses no rupees and provides no other benefits."); }); addCheat("Invincible Enemies", getSettings().game.invincibleEnemies, "Prevents enemies from taking damage."); From 5231e60903ad3fc0d7b267df6a21f8fa84f078ed Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Thu, 14 May 2026 17:48:13 -0400 Subject: [PATCH 3/4] Shorten Description The description was very, very long before --- src/dusk/ui/settings.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 1de757628f..d3c737bfb8 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -1172,12 +1172,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { }); } pane.add_rml( - "
Control the behavior of the Magic Armor." - "
Normal is its original behavior." - "
On Damage only uses rupees when damaged. You will not become heavy when you run out." - "
Double Defense never uses rupees and halves damage taken." - "
Invincible never uses rupees and is immune to damage." - "
Cosmetic uses no rupees and provides no other benefits."); + "
Control the behavior of the Magic Armor."); }); addCheat("Invincible Enemies", getSettings().game.invincibleEnemies, "Prevents enemies from taking damage."); From a9fcc2f52a94ffe002d2bc88ac03d4708ee09a07 Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Wed, 20 May 2026 17:51:13 -0400 Subject: [PATCH 4/4] Web Editor Got Me Fix my syntax --- include/dusk/settings.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 53717e052e..8954c84574 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -57,7 +57,7 @@ enum class MagicArmorMode : u8 { DOUBLE_DEFENSE = 2, INVINCIBLE = 3, COSMETIC = 4, -} +}; namespace config { template <> @@ -102,6 +102,7 @@ struct ConfigEnumRange { static constexpr auto max = MenuScaling::Dusklight; }; +template <> struct ConfigEnumRange { static constexpr auto min = MagicArmorMode::NORMAL; static constexpr auto max = MagicArmorMode::COSMETIC;