Make spell absorption multiplicative (bug #4684)

pull/1984/head
Andrei Kortunov 6 years ago
parent 0fad2449f3
commit bf9e8c4556

@ -143,6 +143,7 @@
Bug #4674: Journal can be opened when settings window is open
Bug #4677: Crash in ESM reader when NPC record has DNAM record without DODT one
Bug #4678: Crash in ESP parser when SCVR has no variable names
Bug #4684: Spell Absorption is additive
Bug #4685: Missing sound causes an exception inside Say command
Bug #4689: Default creature soundgen entries are not used
Feature #912: Editor: Add missing icons to UniversalId tables

@ -324,6 +324,34 @@ namespace MWMechanics
return true;
}
class GetAbsorptionProbability : public MWMechanics::EffectSourceVisitor
{
public:
float mProbability;
GetAbsorptionProbability(const MWWorld::Ptr& actor)
: mProbability(0.f){}
virtual void visit (MWMechanics::EffectKey key,
const std::string& sourceName, const std::string& sourceId, int casterActorId,
float magnitude, float remainingTime = -1, float totalTime = -1)
{
if (key.mId == ESM::MagicEffect::SpellAbsorption)
{
if (mProbability == 0.f)
mProbability = magnitude / 100;
else
{
// If there are different sources of SpellAbsorption effect, multiply failing probability for all effects.
// Real absorption probability will be the (1 - total fail chance) in this case.
float failProbability = 1.f - mProbability;
failProbability *= 1.f - magnitude / 100;
mProbability = 1.f - failProbability;
}
}
}
};
CastSpell::CastSpell(const MWWorld::Ptr &caster, const MWWorld::Ptr &target, const bool fromProjectile, const bool manualSpell)
: mCaster(caster)
, mTarget(target)
@ -444,12 +472,18 @@ namespace MWMechanics
MWBase::Environment::get().getWindowManager()->setEnemy(target);
// Try absorbing if it's a spell
// NOTE: Vanilla does this once per spell absorption effect source instead of adding the % from all sources together, not sure
// if that is worth replicating.
// NOTE: Vanilla does this once per spell absorption effect source instead of adding the % from all sources together, so use the same approach here
bool absorbed = false;
if (spell && caster != target && target.getClass().isActor())
{
float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude();
GetAbsorptionProbability check(target);
MWMechanics::CreatureStats& stats = target.getClass().getCreatureStats(target);
stats.getActiveSpells().visitEffectSources(check);
stats.getSpells().visitEffectSources(check);
if (target.getClass().hasInventoryStore(target))
target.getClass().getInventoryStore(target).visitEffectSources(check);
int absorb = check.mProbability * 100;
absorbed = (Misc::Rng::roll0to99() < absorb);
if (absorbed)
{

Loading…
Cancel
Save