diff --git a/CHANGELOG.md b/CHANGELOG.md index c6013ce55..f51650473 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 41f546af4..68fe235ce 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 962a5bab5..94f75dfc6 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 2255203ec..1fe7eec4e 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 41e2485ce..3f87363a3 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 e5b6b5dd8..6be783219 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 55fb2eaf0..1948db7fa 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 6af0118de..2497b9e2f 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 a6616ecc1..db3d7e75b 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 0793345c8..23c860f89 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 + + +