From db13984db00e9096fdc48817757856ee2100c3a4 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 4 Apr 2020 18:28:53 +0300 Subject: [PATCH] Separate spell resistance --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/combat.cpp | 1 + apps/openmw/mwmechanics/spellcasting.cpp | 78 +----------------- apps/openmw/mwmechanics/spellcasting.hpp | 22 +---- apps/openmw/mwmechanics/spellpriority.cpp | 1 + apps/openmw/mwmechanics/spellresistance.cpp | 90 +++++++++++++++++++++ apps/openmw/mwmechanics/spellresistance.hpp | 37 +++++++++ apps/openmw/mwworld/inventorystore.cpp | 1 + 8 files changed, 134 insertions(+), 98 deletions(-) create mode 100644 apps/openmw/mwmechanics/spellresistance.cpp create mode 100644 apps/openmw/mwmechanics/spellresistance.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 57262f9646..3395b5fc88 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -83,7 +83,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat creaturestats magiceffects movement actorutil drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe - aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellsuccess spellcasting + aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellcasting spellresistance disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning character actors objects aistate coordinateconverter trading weaponpriority spellpriority weapontype ) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 9f5446c11e..9698892e4a 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -18,6 +18,7 @@ #include "npcstats.hpp" #include "movement.hpp" #include "spellcasting.hpp" +#include "spellresistance.hpp" #include "difficultyscaling.hpp" #include "actorutil.hpp" #include "pathfinding.hpp" diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index d7c3bcdb11..d5ddd9a55a 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -28,6 +28,7 @@ #include "aifollow.hpp" #include "weapontype.hpp" #include "summoning.hpp" +#include "spellresistance.hpp" namespace MWMechanics { @@ -168,83 +169,6 @@ namespace MWMechanics return spell && spellIncreasesSkill(spell); } - float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects) - { - short resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId); - short weaknessEffect = ESM::MagicEffect::getWeaknessEffect(effectId); - - float resistance = 0; - if (resistanceEffect != -1) - resistance += actorEffects->get(resistanceEffect).getMagnitude(); - if (weaknessEffect != -1) - resistance -= actorEffects->get(weaknessEffect).getMagnitude(); - - if (effectId == ESM::MagicEffect::FireDamage) - resistance += actorEffects->get(ESM::MagicEffect::FireShield).getMagnitude(); - if (effectId == ESM::MagicEffect::ShockDamage) - resistance += actorEffects->get(ESM::MagicEffect::LightningShield).getMagnitude(); - if (effectId == ESM::MagicEffect::FrostDamage) - resistance += actorEffects->get(ESM::MagicEffect::FrostShield).getMagnitude(); - - return resistance; - } - - float getEffectResistance (short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, - const ESM::Spell* spell, const MagicEffects* effects) - { - const ESM::MagicEffect *magicEffect = - MWBase::Environment::get().getWorld()->getStore().get().find ( - effectId); - - const MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); - const MWMechanics::MagicEffects* magicEffects = &stats.getMagicEffects(); - if (effects) - magicEffects = effects; - - // Effects with no resistance attribute belonging to them can not be resisted - if (ESM::MagicEffect::getResistanceEffect(effectId) == -1) - return 0.f; - - float resistance = getEffectResistanceAttribute(effectId, magicEffects); - - int willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); - float luck = static_cast(stats.getAttribute(ESM::Attribute::Luck).getModified()); - float x = (willpower + 0.1f * luck) * stats.getFatigueTerm(); - - // This makes spells that are easy to cast harder to resist and vice versa - float castChance = 100.f; - if (spell != nullptr && !caster.isEmpty() && caster.getClass().isActor()) - { - castChance = getSpellSuccessChance(spell, caster, nullptr, false, false); // Uncapped casting chance - } - if (castChance > 0) - x *= 50 / castChance; - - float roll = Misc::Rng::rollClosedProbability() * 100; - if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) - roll -= resistance; - - if (x <= roll) - x = 0; - else - { - if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) - x = 100; - else - x = roll / std::min(x, 100.f); - } - - x = std::min(x + resistance, 100.f); - return x; - } - - float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, - const ESM::Spell* spell, const MagicEffects* effects) - { - float resistance = getEffectResistance(effectId, actor, caster, spell, effects); - return 1 - resistance / 100.f; - } - /// Check if the given effect can be applied to the target. If \a castByPlayer, emits a message box on failure. bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer) { diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 804b4bca9d..91cf372729 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -1,5 +1,5 @@ -#ifndef MWMECHANICS_SPELLSUCCESS_H -#define MWMECHANICS_SPELLSUCCESS_H +#ifndef MWMECHANICS_SPELLCASTING_H +#define MWMECHANICS_SPELLCASTING_H #include #include @@ -46,24 +46,6 @@ namespace MWMechanics bool spellIncreasesSkill(const ESM::Spell* spell); bool spellIncreasesSkill(const std::string& spellId); - /// Get the resistance attribute against an effect for a given actor. This will add together - /// ResistX and Weakness to X effects relevant against the given effect. - float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects); - - /// Get the effective resistance against an effect casted by the given actor in the given spell (optional). - /// @return >=100 for fully resisted. can also return negative value for damage amplification. - /// @param effects Override the actor's current magicEffects. Useful if there are effects currently - /// being applied (but not applied yet) that should also be considered. - float getEffectResistance (short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, - const ESM::Spell* spell = nullptr, const MagicEffects* effects = nullptr); - - /// Get an effect multiplier for applying an effect cast by the given actor in the given spell (optional). - /// @return effect multiplier from 0 to 2. (100% net resistance to 100% net weakness) - /// @param effects Override the actor's current magicEffects. Useful if there are effects currently - /// being applied (but not applied yet) that should also be considered. - float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, - const ESM::Spell* spell = nullptr, const MagicEffects* effects = nullptr); - bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer); int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index f90e59971a..a529781cbe 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -16,6 +16,7 @@ #include "creaturestats.hpp" #include "spellcasting.hpp" +#include "spellresistance.hpp" #include "weapontype.hpp" #include "combat.hpp" #include "summoning.hpp" diff --git a/apps/openmw/mwmechanics/spellresistance.cpp b/apps/openmw/mwmechanics/spellresistance.cpp new file mode 100644 index 0000000000..bbb4b56a5c --- /dev/null +++ b/apps/openmw/mwmechanics/spellresistance.cpp @@ -0,0 +1,90 @@ +#include "spellresistance.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" + +#include "creaturestats.hpp" +#include "spellcasting.hpp" + +namespace MWMechanics +{ + + float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, + const ESM::Spell* spell, const MagicEffects* effects) + { + float resistance = getEffectResistance(effectId, actor, caster, spell, effects); + return 1 - resistance / 100.f; + } + + float getEffectResistance (short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, + const ESM::Spell* spell, const MagicEffects* effects) + { + // Effects with no resistance attribute belonging to them can not be resisted + if (ESM::MagicEffect::getResistanceEffect(effectId) == -1) + return 0.f; + + const auto magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectId); + + const MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); + const MWMechanics::MagicEffects* magicEffects = &stats.getMagicEffects(); + if (effects) + magicEffects = effects; + + float resistance = getEffectResistanceAttribute(effectId, magicEffects); + + int willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); + float luck = static_cast(stats.getAttribute(ESM::Attribute::Luck).getModified()); + float x = (willpower + 0.1f * luck) * stats.getFatigueTerm(); + + // This makes spells that are easy to cast harder to resist and vice versa + float castChance = 100.f; + if (spell != nullptr && !caster.isEmpty() && caster.getClass().isActor()) + castChance = getSpellSuccessChance(spell, caster, nullptr, false, false); // Uncapped casting chance + if (castChance > 0) + x *= 50 / castChance; + + float roll = Misc::Rng::rollClosedProbability() * 100; + if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) + roll -= resistance; + + if (x <= roll) + x = 0; + else + { + if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) + x = 100; + else + x = roll / std::min(x, 100.f); + } + + x = std::min(x + resistance, 100.f); + return x; + } + + float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects) + { + short resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId); + short weaknessEffect = ESM::MagicEffect::getWeaknessEffect(effectId); + + float resistance = 0; + if (resistanceEffect != -1) + resistance += actorEffects->get(resistanceEffect).getMagnitude(); + if (weaknessEffect != -1) + resistance -= actorEffects->get(weaknessEffect).getMagnitude(); + + if (effectId == ESM::MagicEffect::FireDamage) + resistance += actorEffects->get(ESM::MagicEffect::FireShield).getMagnitude(); + if (effectId == ESM::MagicEffect::ShockDamage) + resistance += actorEffects->get(ESM::MagicEffect::LightningShield).getMagnitude(); + if (effectId == ESM::MagicEffect::FrostDamage) + resistance += actorEffects->get(ESM::MagicEffect::FrostShield).getMagnitude(); + + return resistance; + } + +} diff --git a/apps/openmw/mwmechanics/spellresistance.hpp b/apps/openmw/mwmechanics/spellresistance.hpp new file mode 100644 index 0000000000..8e74c22601 --- /dev/null +++ b/apps/openmw/mwmechanics/spellresistance.hpp @@ -0,0 +1,37 @@ +#ifndef MWMECHANICS_SPELLRESISTANCE_H +#define MWMECHANICS_SPELLRESISTANCE_H + +namespace ESM +{ + struct Spell; +} + +namespace MWWorld +{ + class Ptr; +} + +namespace MWMechanics +{ + class MagicEffects; + + /// Get an effect multiplier for applying an effect cast by the given actor in the given spell (optional). + /// @return effect multiplier from 0 to 2. (100% net resistance to 100% net weakness) + /// @param effects Override the actor's current magicEffects. Useful if there are effects currently + /// being applied (but not applied yet) that should also be considered. + float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, + const ESM::Spell* spell = nullptr, const MagicEffects* effects = nullptr); + + /// Get the effective resistance against an effect casted by the given actor in the given spell (optional). + /// @return >=100 for fully resisted. can also return negative value for damage amplification. + /// @param effects Override the actor's current magicEffects. Useful if there are effects currently + /// being applied (but not applied yet) that should also be considered. + float getEffectResistance (short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, + const ESM::Spell* spell = nullptr, const MagicEffects* effects = nullptr); + + /// Get the resistance attribute against an effect for a given actor. This will add together + /// ResistX and Weakness to X effects relevant against the given effect. + float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects); +} + +#endif diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 1c80620117..1de97d068d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -14,6 +14,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/spellresistance.hpp" #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/weapontype.hpp"