diff --git a/CHANGELOG.md b/CHANGELOG.md index c6013ce552..f51650473b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Bug #3765: DisableTeleporting makes Mark/Recall/Intervention effects undetectable Bug #4329: Removed birthsign abilities are restored after reloading the save Bug #4383: Bow model obscures crosshair when arrow is drawn + Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons Bug #4411: Reloading a saved game while falling prevents damage in some cases Bug #4540: Rain delay when exiting water Bug #4701: PrisonMarker record is not hardcoded like other markers diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 41f546af46..68fe235ce3 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -80,6 +80,7 @@ bool Launcher::AdvancedPage::loadSettings() int unarmedFactorsStrengthIndex = mEngineSettings.getInt("strength influences hand to hand", "Game"); if (unarmedFactorsStrengthIndex >= 0 && unarmedFactorsStrengthIndex <= 2) unarmedFactorsStrengthComboBox->setCurrentIndex(unarmedFactorsStrengthIndex); + loadSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game"); // Input Settings loadSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input"); @@ -139,6 +140,7 @@ void Launcher::AdvancedPage::saveSettings() int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex(); if (unarmedFactorsStrengthIndex != mEngineSettings.getInt("strength influences hand to hand", "Game")) mEngineSettings.setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex); + saveSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game"); // Input Settings saveSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input"); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 962a5bab50..94f75dfc6a 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -308,6 +308,7 @@ namespace MWClass { damage = attack[0] + ((attack[1]-attack[0])*attackStrength); MWMechanics::adjustWeaponDamage(damage, weapon, ptr); + MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } @@ -382,9 +383,6 @@ namespace MWClass if (!object.isEmpty()) stats.setLastHitObject(object.getCellRef().getRefId()); - if (damage > 0.0f && !object.isEmpty()) - MWMechanics::resistNormalWeapon(ptr, attacker, object, damage); - if (damage < 0.001f) damage = 0; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 2255203ec8..1fe7eec4ee 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -619,6 +619,8 @@ namespace MWClass damage = attack[0] + ((attack[1]-attack[0])*attackStrength); } MWMechanics::adjustWeaponDamage(damage, weapon, ptr); + MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); + MWMechanics::applyWerewolfDamageMult(victim, weapon, damage); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); healthdmg = true; } diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 41e2485ce0..3f87363a32 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -148,30 +148,49 @@ namespace MWMechanics return false; } + bool isNormalWeapon(const MWWorld::Ptr &weapon) + { + if (weapon.isEmpty()) + return false; + + const int flags = weapon.get()->mBase->mData.mFlags; + bool isSilver = flags & ESM::Weapon::Silver; + bool isMagical = flags & ESM::Weapon::Magical; + bool isEnchanted = !weapon.getClass().getEnchantment(weapon).empty(); + + return !isSilver && !isMagical && (!isEnchanted || !Settings::Manager::getBool("enchanted weapons are magical", "Game")); + } + void resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) { + if (damage == 0 || weapon.isEmpty() || !isNormalWeapon(weapon)) + return; + const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); - float resistance = std::min(100.f, effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() - - effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude()); + const float resistance = effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() / 100.f; + const float weakness = effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude() / 100.f; - float multiplier = 1.f - resistance / 100.f; - - if (!(weapon.get()->mBase->mData.mFlags & ESM::Weapon::Silver - || weapon.get()->mBase->mData.mFlags & ESM::Weapon::Magical)) - { - if (weapon.getClass().getEnchantment(weapon).empty() - || !Settings::Manager::getBool("enchanted weapons are magical", "Game")) - damage *= multiplier; - } - - if ((weapon.get()->mBase->mData.mFlags & ESM::Weapon::Silver) - && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) - damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat(); + damage *= 1.f - std::min(1.f, resistance-weakness); if (damage == 0 && attacker == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); } + void applyWerewolfDamageMult(const MWWorld::Ptr &actor, const MWWorld::Ptr &weapon, float &damage) + { + if (damage == 0 || weapon.isEmpty() || !actor.getClass().isNpc()) + return; + + const int flags = weapon.get()->mBase->mData.mFlags; + bool isSilver = flags & ESM::Weapon::Silver; + + if (isSilver && actor.getClass().getNpcStats(actor).isWerewolf()) + { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + damage *= store.get().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat(); + } + } + void projectileHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, const osg::Vec3f& hitPosition, float attackStrength) { @@ -208,6 +227,9 @@ namespace MWMechanics damage += attack[0] + ((attack[1] - attack[0]) * attackStrength); adjustWeaponDamage(damage, weapon, attacker); + if (weapon == projectile || Settings::Manager::getBool("only appropriate ammunition bypasses resistance", "Game") || isNormalWeapon(weapon)) + resistNormalWeapon(victim, attacker, projectile, damage); + applyWerewolfDamageMult(victim, projectile, damage); if (attacker == getPlayer()) { diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index e5b6b5dd88..6be7832196 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -20,8 +20,13 @@ bool applyOnStrikeEnchantment(const MWWorld::Ptr& attacker, const MWWorld::Ptr& /// @return can we block the attack? bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker, const MWWorld::Ptr& weapon, float damage, float attackStrength); +/// @return does normal weapon resistance and weakness apply to the weapon? +bool isNormalWeapon (const MWWorld::Ptr& weapon); + void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage); +void applyWerewolfDamageMult (const MWWorld::Ptr& actor, const MWWorld::Ptr& weapon, float &damage); + /// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt /// @note \a victim may be empty (e.g. for a hit on terrain), a non-actor (environment objects) or an actor void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 55fb2eaf09..1948db7fa6 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -78,7 +78,10 @@ namespace MWMechanics adjustWeaponDamage(rating, item, actor); if (weapon->mData.mType != ESM::Weapon::MarksmanBow && weapon->mData.mType != ESM::Weapon::MarksmanCrossbow) + { resistNormalWeapon(enemy, actor, item, rating); + applyWerewolfDamageMult(enemy, item, rating); + } else if (weapon->mData.mType == ESM::Weapon::MarksmanBow) { if (arrowRating <= 0.f) diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 6af0118de7..2497b9e2fe 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -211,3 +211,16 @@ disposition change of merchants caused by trading will be permanent and won't be This imitates the option that Morrowind Code Patch offers. This setting can be toggled in Advanced tab of the launcher. + +only appropriate ammunition bypasses resistance +----------------------------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +If this setting is true, you will have to use the appropriate ammunition to bypass normal weapon resistance (or weakness). +An enchanted bow with chitin arrows will no longer be enough for the purpose, while a steel longbow with glass arrows will still work. +This was previously the default engine behavior that diverged from Morrowind design. + +This setting can be toggled in Advanced tab of the launcher. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index a6616ecc11..db3d7e75b1 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -242,6 +242,9 @@ strength influences hand to hand = 0 # Render holstered weapons (with quivers and scabbards), requires modded assets weapon sheathing = false +# Allow non-standard ammunition solely to bypass normal weapon resistance or weakness +only appropriate ammunition bypasses resistance = false + [General] # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 0793345c8d..23c860f897 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -96,6 +96,16 @@ + + + + <html><head/><body><p>Allow non-standard ammunition solely to bypass normal weapon resistance or weakness.</p></body></html> + + + Only appropriate ammunition bypasses normal weapon resistance + + +