diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 30138b0042..7bdb97370e 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -57,6 +57,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 { @@ -105,6 +113,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 @@ -234,7 +248,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 34690accab..2852076334 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -12734,7 +12734,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 @@ -18707,7 +18719,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 46d599daa5..51b67c47d0 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 aed43089c4..e61a7a0923 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -197,6 +197,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 7a34264f48..0a58dfd1ec 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -127,7 +127,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 @@ -257,7 +257,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 d65cab3370..c0f1dc235a 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -75,6 +75,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; @@ -211,7 +219,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); @@ -1272,8 +1280,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."); });