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