From d05603c7fe0bf59b976b463cdca5fae05d17dc8c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Feb 2016 19:37:19 +0100 Subject: [PATCH] Directly apply On Target 'When Strikes' enchantments instead of launching a projectile (Fixes #3212) --- apps/openmw/mwclass/creature.cpp | 13 +------- apps/openmw/mwclass/npc.cpp | 13 +------- apps/openmw/mwmechanics/combat.cpp | 38 ++++++++++++------------ apps/openmw/mwmechanics/combat.hpp | 2 ++ apps/openmw/mwmechanics/spellcasting.cpp | 25 +++++++++------- apps/openmw/mwmechanics/spellcasting.hpp | 3 +- 6 files changed, 40 insertions(+), 54 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 0f021b5a2..4a7af1099 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -306,18 +306,7 @@ namespace MWClass } // Apply "On hit" enchanted weapons - std::string enchantmentName = !weapon.isEmpty() ? weapon.getClass().getEnchantment(weapon) : ""; - if (!enchantmentName.empty()) - { - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( - enchantmentName); - if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes) - { - MWMechanics::CastSpell cast(ptr, victim); - cast.mHitPosition = hitPosition; - cast.cast(weapon); - } - } + MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); } else if (isBipedal(ptr)) { diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 474985f7b..4c825f63f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -637,18 +637,7 @@ namespace MWClass damage *= store.find("fCombatKODamageMult")->getFloat(); // Apply "On hit" enchanted weapons - std::string enchantmentName = !weapon.isEmpty() ? weapon.getClass().getEnchantment(weapon) : ""; - if (!enchantmentName.empty()) - { - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( - enchantmentName); - if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes) - { - MWMechanics::CastSpell cast(ptr, victim); - cast.mHitPosition = hitPosition; - cast.cast(weapon); - } - } + MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); MWMechanics::applyElementalShields(ptr, victim); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index a01dc7079..8d9d4cb3a 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -29,28 +29,28 @@ float signedAngleRadians (const osg::Vec3f& v1, const osg::Vec3f& v2, const osg: return std::atan2((normal * (v1 ^ v2)), (v1 * v2)); } -bool applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const osg::Vec3f& hitPosition) +} + +namespace MWMechanics { - std::string enchantmentName = !object.isEmpty() ? object.getClass().getEnchantment(object) : ""; - if (!enchantmentName.empty()) + + bool applyOnStrikeEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const osg::Vec3f& hitPosition) { - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( - enchantmentName); - if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes) + std::string enchantmentName = !object.isEmpty() ? object.getClass().getEnchantment(object) : ""; + if (!enchantmentName.empty()) { - MWMechanics::CastSpell cast(attacker, victim); - cast.mHitPosition = hitPosition; - cast.cast(object); - return true; + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( + enchantmentName); + if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes) + { + MWMechanics::CastSpell cast(attacker, victim); + cast.mHitPosition = hitPosition; + cast.cast(object, false); + return true; + } } + return false; } - return false; -} - -} - -namespace MWMechanics -{ bool blockMeleeAttack(const MWWorld::Ptr &attacker, const MWWorld::Ptr &blocker, const MWWorld::Ptr &weapon, float damage, float attackStrength) { @@ -215,9 +215,9 @@ namespace MWMechanics damage *= gmst.find("fCombatKODamageMult")->getFloat(); // Apply "On hit" effect of the weapon - bool appliedEnchantment = applyEnchantment(attacker, victim, weapon, hitPosition); + bool appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, weapon, hitPosition); if (weapon != projectile) - appliedEnchantment = applyEnchantment(attacker, victim, projectile, hitPosition); + appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, projectile, hitPosition); if (damage > 0) MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index ca78d7956..7d0b3b78f 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -6,6 +6,8 @@ namespace MWMechanics { +bool applyOnStrikeEnchantment(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const osg::Vec3f& hitPosition); + /// @return can we block the attack? bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker, const MWWorld::Ptr& weapon, float damage, float attackStrength); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 736d2a616..8882d14a8 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -687,7 +687,7 @@ namespace MWMechanics throw std::runtime_error("ID type cannot be casted"); } - bool CastSpell::cast(const MWWorld::Ptr &item) + bool CastSpell::cast(const MWWorld::Ptr &item, bool launchProjectile) { std::string enchantmentName = item.getClass().getEnchantment(item); if (enchantmentName.empty()) @@ -754,15 +754,20 @@ namespace MWMechanics inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); } - std::string projectileModel; - std::string sound; - float speed = 0; - getProjectileInfo(enchantment->mEffects, projectileModel, sound, speed); - if (!projectileModel.empty()) - MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed, - false, enchantment->mEffects, mCaster, mSourceName, - // Not needed, enchantments can only be cast by actors - osg::Vec3f(1,0,0)); + if (launchProjectile) + { + std::string projectileModel; + std::string sound; + float speed = 0; + getProjectileInfo(enchantment->mEffects, projectileModel, sound, speed); + if (!projectileModel.empty()) + MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed, + false, enchantment->mEffects, mCaster, mSourceName, + // Not needed, enchantments can only be cast by actors + osg::Vec3f(1,0,0)); + } + else if (!mTarget.isEmpty()) + inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Target); return true; } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 5b48bd4a8..5bc618058 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -81,7 +81,8 @@ namespace MWMechanics bool cast (const ESM::Spell* spell); /// @note mCaster must be an actor - bool cast (const MWWorld::Ptr& item); + /// @param launchProjectile If set to false, "on target" effects are directly applied instead of being launched as projectile originating from the caster. + bool cast (const MWWorld::Ptr& item, bool launchProjectile=true); /// @note mCaster must be an NPC bool cast (const ESM::Ingredient* ingredient);