diff --git a/include/dusk/settings.h b/include/dusk/settings.h index cc8af3556a..8954c84574 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -51,6 +51,14 @@ enum class MenuScaling : u8 { Dusklight = 2, }; +enum class MagicArmorMode : u8 { + NORMAL = 0, + ON_DAMAGE = 1, + DOUBLE_DEFENSE = 2, + INVINCIBLE = 3, + COSMETIC = 4, +}; + namespace config { template <> struct ConfigEnumRange { @@ -93,6 +101,12 @@ struct ConfigEnumRange { static constexpr auto min = MenuScaling::GameCube; static constexpr auto max = MenuScaling::Dusklight; }; + +template <> +struct ConfigEnumRange { + static constexpr auto min = MagicArmorMode::NORMAL; + static constexpr auto max = MagicArmorMode::COSMETIC; +}; } // namespace config // Persistent user settings @@ -210,7 +224,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 e2fe7a890c..a5163aabca 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -12733,7 +12733,19 @@ void daAlink_c::setMagicArmorBrk(int i_status) { BOOL daAlink_c::checkMagicArmorHeavy() const { #if TARGET_PC - return checkMagicArmorWearAbility() && (dComIfGs_getRupee() == 0 && !dusk::getSettings().game.freeMagicArmor); + 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 @@ -18706,7 +18718,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..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.freeMagicArmor) { + 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/d/actor/d_a_alink_wolf.inc b/src/d/actor/d_a_alink_wolf.inc index 67fde3a7a7..49ef409e43 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 caa65bc0b4..fc22f5f1d6 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -178,6 +178,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 2ecda7df5c..462320cc05 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -110,7 +110,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 @@ -234,7 +234,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 6518ede336..36d4254b7c 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -76,6 +76,14 @@ constexpr std::array kMenuScalingModeLabels = { "Dusklight", }; +constexpr std::array kMagicArmorModes = { + "Normal", + "On Damage", + "Double Defense", + "Invincible", + "Cosmetic", +}; + bool try_parse_backend(std::string_view backend, AuroraBackend& outBackend) { if (backend == "auto") { outBackend = BACKEND_AUTO; @@ -212,7 +220,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); @@ -1257,8 +1265,38 @@ 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 Behavior", + .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 the behavior of the Magic Armor."); + }); addCheat("Invincible Enemies", getSettings().game.invincibleEnemies, "Prevents enemies from taking damage."); });