1 #include "spellresistance.hpp" 2 3 #include <components/misc/rng.hpp> 4 5 #include "../mwbase/environment.hpp" 6 #include "../mwbase/world.hpp" 7 8 #include "../mwworld/class.hpp" 9 #include "../mwworld/esmstore.hpp" 10 11 #include "creaturestats.hpp" 12 #include "spellutil.hpp" 13 14 namespace MWMechanics 15 { 16 getEffectMultiplier(short effectId,const MWWorld::Ptr & actor,const MWWorld::Ptr & caster,const ESM::Spell * spell,const MagicEffects * effects)17 float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, 18 const ESM::Spell* spell, const MagicEffects* effects) 19 { 20 if (!actor.getClass().isActor()) 21 return 1; 22 23 float resistance = getEffectResistance(effectId, actor, caster, spell, effects); 24 return 1 - resistance / 100.f; 25 } 26 getEffectResistance(short effectId,const MWWorld::Ptr & actor,const MWWorld::Ptr & caster,const ESM::Spell * spell,const MagicEffects * effects)27 float getEffectResistance (short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, 28 const ESM::Spell* spell, const MagicEffects* effects) 29 { 30 // Effects with no resistance attribute belonging to them can not be resisted 31 if (ESM::MagicEffect::getResistanceEffect(effectId) == -1) 32 return 0.f; 33 34 const auto magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectId); 35 36 const MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); 37 const MWMechanics::MagicEffects* magicEffects = &stats.getMagicEffects(); 38 if (effects) 39 magicEffects = effects; 40 41 float resistance = getEffectResistanceAttribute(effectId, magicEffects); 42 43 float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); 44 float luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); 45 float x = (willpower + 0.1f * luck) * stats.getFatigueTerm(); 46 47 // This makes spells that are easy to cast harder to resist and vice versa 48 float castChance = 100.f; 49 if (spell != nullptr && !caster.isEmpty() && caster.getClass().isActor()) 50 castChance = getSpellSuccessChance(spell, caster, nullptr, false, false); // Uncapped casting chance 51 if (castChance > 0) 52 x *= 50 / castChance; 53 54 float roll = Misc::Rng::rollClosedProbability() * 100; 55 if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) 56 roll -= resistance; 57 58 if (x <= roll) 59 x = 0; 60 else 61 { 62 if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) 63 x = 100; 64 else 65 x = roll / std::min(x, 100.f); 66 } 67 68 x = std::min(x + resistance, 100.f); 69 return x; 70 } 71 getEffectResistanceAttribute(short effectId,const MagicEffects * actorEffects)72 float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects) 73 { 74 short resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId); 75 short weaknessEffect = ESM::MagicEffect::getWeaknessEffect(effectId); 76 77 float resistance = 0; 78 if (resistanceEffect != -1) 79 resistance += actorEffects->get(resistanceEffect).getMagnitude(); 80 if (weaknessEffect != -1) 81 resistance -= actorEffects->get(weaknessEffect).getMagnitude(); 82 83 if (effectId == ESM::MagicEffect::FireDamage) 84 resistance += actorEffects->get(ESM::MagicEffect::FireShield).getMagnitude(); 85 if (effectId == ESM::MagicEffect::ShockDamage) 86 resistance += actorEffects->get(ESM::MagicEffect::LightningShield).getMagnitude(); 87 if (effectId == ESM::MagicEffect::FrostDamage) 88 resistance += actorEffects->get(ESM::MagicEffect::FrostShield).getMagnitude(); 89 90 return resistance; 91 } 92 93 } 94