mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-13 22:39:44 +00:00
Implement Resist & Weakness effects
This commit is contained in:
parent
d49b6f19ff
commit
b1a29eb27e
10 changed files with 159 additions and 74 deletions
|
@ -69,7 +69,7 @@ add_openmw_dir (mwclass
|
||||||
add_openmw_dir (mwmechanics
|
add_openmw_dir (mwmechanics
|
||||||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||||
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
||||||
aiescort aiactivate repair enchanting pathfinding security spellsuccess
|
aiescort aiactivate repair enchanting pathfinding security spellsuccess spellcasting
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwbase
|
add_openmw_dir (mwbase
|
||||||
|
|
|
@ -468,9 +468,9 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
weapon.getCellRef().mEnchantmentCharge -= castCost;
|
weapon.getCellRef().mEnchantmentCharge -= castCost;
|
||||||
// Touch
|
// Touch
|
||||||
othercls.getCreatureStats(victim).getActiveSpells().addSpell(enchantmentName, victim, ESM::RT_Touch, weapon.getClass().getName(weapon));
|
othercls.getCreatureStats(victim).getActiveSpells().addSpell(enchantmentName, victim, ptr, ESM::RT_Touch, weapon.getClass().getName(weapon));
|
||||||
// Self
|
// Self
|
||||||
getCreatureStats(ptr).getActiveSpells().addSpell(enchantmentName, ptr, ESM::RT_Self, weapon.getClass().getName(weapon));
|
getCreatureStats(ptr).getActiveSpells().addSpell(enchantmentName, ptr, ptr, ESM::RT_Self, weapon.getClass().getName(weapon));
|
||||||
// Target
|
// Target
|
||||||
MWBase::Environment::get().getWorld()->launchProjectile(enchantmentName, enchantment->mEffects, ptr, weapon.getClass().getName(weapon));
|
MWBase::Environment::get().getWorld()->launchProjectile(enchantmentName, enchantment->mEffects, ptr, weapon.getClass().getName(weapon));
|
||||||
}
|
}
|
||||||
|
@ -936,7 +936,7 @@ namespace MWClass
|
||||||
|
|
||||||
/// \todo consider instant effects
|
/// \todo consider instant effects
|
||||||
|
|
||||||
return stats.getActiveSpells().addSpell (id, actor);
|
return stats.getActiveSpells().addSpell (id, actor, actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Npc::skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType) const
|
void Npc::skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType) const
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/actionequip.hpp"
|
#include "../mwworld/actionequip.hpp"
|
||||||
#include "../mwmechanics/spellsuccess.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
#include "../mwgui/inventorywindow.hpp"
|
#include "../mwgui/inventorywindow.hpp"
|
||||||
#include "../mwgui/bookwindow.hpp"
|
#include "../mwgui/bookwindow.hpp"
|
||||||
#include "../mwgui/scrollwindow.hpp"
|
#include "../mwgui/scrollwindow.hpp"
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/actionequip.hpp"
|
#include "../mwworld/actionequip.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/spellsuccess.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
#include "spellicons.hpp"
|
#include "spellicons.hpp"
|
||||||
#include "inventorywindow.hpp"
|
#include "inventorywindow.hpp"
|
||||||
|
|
|
@ -16,11 +16,14 @@
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
|
|
||||||
|
@ -74,7 +77,7 @@ namespace MWMechanics
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIter (effects.first.mList.begin());
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIter (effects.first.mList.begin());
|
||||||
effectIter!=effects.first.mList.end(); ++effectIter, ++i)
|
effectIter!=effects.first.mList.end(); ++effectIter, ++i)
|
||||||
{
|
{
|
||||||
float magnitude = iter->second.mRandom[i];
|
float random = iter->second.mRandom[i];
|
||||||
if (effectIter->mRange != iter->second.mRange)
|
if (effectIter->mRange != iter->second.mRange)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -83,7 +86,7 @@ namespace MWMechanics
|
||||||
int duration = effectIter->mDuration;
|
int duration = effectIter->mDuration;
|
||||||
|
|
||||||
if (effects.second.first)
|
if (effects.second.first)
|
||||||
duration *= magnitude;
|
duration *= random;
|
||||||
|
|
||||||
MWWorld::TimeStamp end = start;
|
MWWorld::TimeStamp end = start;
|
||||||
end += static_cast<double> (duration)*
|
end += static_cast<double> (duration)*
|
||||||
|
@ -102,19 +105,21 @@ namespace MWMechanics
|
||||||
if (effectIter->mDuration==0)
|
if (effectIter->mDuration==0)
|
||||||
{
|
{
|
||||||
param.mMagnitude =
|
param.mMagnitude =
|
||||||
static_cast<int> (magnitude / (0.1 * magicEffect->mData.mBaseCost));
|
static_cast<int> (random / (0.1 * magicEffect->mData.mBaseCost));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
param.mMagnitude =
|
param.mMagnitude =
|
||||||
static_cast<int> (0.05*magnitude / (0.1 * magicEffect->mData.mBaseCost));
|
static_cast<int> (0.05*random / (0.1 * magicEffect->mData.mBaseCost));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
param.mMagnitude = static_cast<int> (
|
param.mMagnitude = static_cast<int> (
|
||||||
(effectIter->mMagnMax-effectIter->mMagnMin)*magnitude + effectIter->mMagnMin);
|
(effectIter->mMagnMax-effectIter->mMagnMin)*random + effectIter->mMagnMin);
|
||||||
|
param.mMagnitude *= iter->second.mMultiplier[i];
|
||||||
|
|
||||||
mEffects.add (*effectIter, param);
|
if (param.mMagnitude)
|
||||||
|
mEffects.add (*effectIter, param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +190,7 @@ namespace MWMechanics
|
||||||
: mSpellsChanged (false), mLastUpdate (MWBase::Environment::get().getWorld()->getTimeStamp())
|
: mSpellsChanged (false), mLastUpdate (MWBase::Environment::get().getWorld()->getTimeStamp())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool ActiveSpells::addSpell (const std::string& id, const MWWorld::Ptr& actor, ESM::RangeType range, const std::string& name, int effectIndex)
|
bool ActiveSpells::addSpell (const std::string& id, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, ESM::RangeType range, const std::string& name, int effectIndex)
|
||||||
{
|
{
|
||||||
const CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor);
|
const CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor);
|
||||||
|
|
||||||
|
@ -197,6 +202,8 @@ namespace MWMechanics
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.first.mList.begin());
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.first.mList.begin());
|
||||||
iter!=effects.first.mList.end(); ++iter)
|
iter!=effects.first.mList.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
if (iter->mRange != range)
|
||||||
|
continue;
|
||||||
if (iter->mDuration)
|
if (iter->mDuration)
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -204,41 +211,37 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If none of the effects need to apply, no need to add the spell
|
||||||
if (!found)
|
if (!found)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TContainer::iterator iter = mSpells.find (id);
|
TContainer::iterator iter = mSpells.find (id);
|
||||||
|
|
||||||
float random = static_cast<float> (std::rand()) / RAND_MAX;
|
|
||||||
|
|
||||||
if (effects.second.first)
|
|
||||||
{
|
|
||||||
// ingredient -> special treatment required.
|
|
||||||
const NpcStats& npcStats = MWWorld::Class::get (actor).getNpcStats (actor);
|
|
||||||
|
|
||||||
float x =
|
|
||||||
(npcStats.getSkill (ESM::Skill::Alchemy).getModified() +
|
|
||||||
0.2 * creatureStats.getAttribute (1).getModified()
|
|
||||||
+ 0.1 * creatureStats.getAttribute (7).getModified())
|
|
||||||
* creatureStats.getFatigueTerm();
|
|
||||||
random *= 100;
|
|
||||||
random = random / std::min (x, 100.0f);
|
|
||||||
random *= 0.25 * x;
|
|
||||||
}
|
|
||||||
|
|
||||||
ActiveSpellParams params;
|
ActiveSpellParams params;
|
||||||
for (unsigned int i=0; i<effects.first.mList.size(); ++i)
|
for (unsigned int i=0; i<effects.first.mList.size(); ++i)
|
||||||
params.mRandom.push_back(static_cast<float> (std::rand()) / RAND_MAX);
|
{
|
||||||
|
float random = static_cast<float> (std::rand()) / RAND_MAX;
|
||||||
|
if (effects.second.first)
|
||||||
|
{
|
||||||
|
// ingredient -> special treatment required.
|
||||||
|
const NpcStats& npcStats = MWWorld::Class::get (actor).getNpcStats (actor);
|
||||||
|
|
||||||
|
float x =
|
||||||
|
(npcStats.getSkill (ESM::Skill::Alchemy).getModified() +
|
||||||
|
0.2 * creatureStats.getAttribute (1).getModified()
|
||||||
|
+ 0.1 * creatureStats.getAttribute (7).getModified())
|
||||||
|
* creatureStats.getFatigueTerm();
|
||||||
|
random *= 100;
|
||||||
|
random = random / std::min (x, 100.0f);
|
||||||
|
random *= 0.25 * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.mRandom.push_back(random);
|
||||||
|
}
|
||||||
params.mRange = range;
|
params.mRange = range;
|
||||||
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
|
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
params.mName = name;
|
params.mName = name;
|
||||||
|
params.mMultiplier.resize(effects.first.mList.size(), 1);
|
||||||
if (iter==mSpells.end() || stacks)
|
|
||||||
mSpells.insert (std::make_pair (id, params));
|
|
||||||
else
|
|
||||||
iter->second = params;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
for (int i=0; i<effects.first.mList.size(); ++i)
|
for (int i=0; i<effects.first.mList.size(); ++i)
|
||||||
|
@ -258,19 +261,35 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Play sounds & particles
|
|
||||||
bool first=true;
|
bool first=true;
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.first.mList.begin());
|
int i = 0;
|
||||||
iter!=effects.first.mList.end(); ++iter)
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (effects.first.mList.begin());
|
||||||
|
effectIt!=effects.first.mList.end(); ++effectIt, ++i)
|
||||||
{
|
{
|
||||||
if (iter->mRange != range)
|
if (effectIt->mRange != range)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Try resisting effect in case its harmful
|
||||||
|
const ESM::Spell *spell =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search (id);
|
||||||
|
params.mMultiplier[i] = MWMechanics::getEffectMultiplier(effectIt->mEffectID, actor, caster, spell);
|
||||||
|
if (params.mMultiplier[i] == 0)
|
||||||
|
{
|
||||||
|
if (actor.getRefData().getHandle() == "player")
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}");
|
||||||
|
else
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If fully resisted, don't play sounds or particles
|
||||||
|
if (params.mMultiplier[i] == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TODO: For Area effects, launch a growing particle effect that applies the effect to more actors as it hits them. Best managed in World.
|
// TODO: For Area effects, launch a growing particle effect that applies the effect to more actors as it hits them. Best managed in World.
|
||||||
|
|
||||||
const ESM::MagicEffect *magicEffect =
|
const ESM::MagicEffect *magicEffect =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
||||||
iter->mEffectID);
|
effectIt->mEffectID);
|
||||||
|
|
||||||
// Only the sound of the first effect plays
|
// Only the sound of the first effect plays
|
||||||
if (first)
|
if (first)
|
||||||
|
@ -296,6 +315,11 @@ namespace MWMechanics
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iter==mSpells.end() || stacks)
|
||||||
|
mSpells.insert (std::make_pair (id, params));
|
||||||
|
else
|
||||||
|
iter->second = params;
|
||||||
|
|
||||||
mSpellsChanged = true;
|
mSpellsChanged = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -415,7 +439,9 @@ namespace MWMechanics
|
||||||
magnitude = static_cast<int> (0.05*it->second.mRandom[i] / (0.1 * magicEffect->mData.mBaseCost));
|
magnitude = static_cast<int> (0.05*it->second.mRandom[i] / (0.1 * magicEffect->mData.mBaseCost));
|
||||||
}
|
}
|
||||||
|
|
||||||
visitor.visit(*effectIt, name, magnitude, remainingTime);
|
magnitude *= it->second.mMultiplier[i];
|
||||||
|
if (magnitude)
|
||||||
|
visitor.visit(*effectIt, name, magnitude, remainingTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
// Effect magnitude multiplier. Use 0 to completely disable the effect
|
// Effect magnitude multiplier. Use 0 to completely disable the effect
|
||||||
// (if it was resisted, reflected or absorbed). Use (0,1) for partially resisted.
|
// (if it was resisted, reflected or absorbed). Use (0,1) for partially resisted.
|
||||||
std::vector<bool> mMultiplier;
|
std::vector<float> mMultiplier;
|
||||||
|
|
||||||
// Display name, we need this for enchantments, which don't have a name - so you need to supply the
|
// Display name, we need this for enchantments, which don't have a name - so you need to supply the
|
||||||
// name of the item with the enchantment to addSpell
|
// name of the item with the enchantment to addSpell
|
||||||
|
@ -85,11 +85,12 @@ namespace MWMechanics
|
||||||
|
|
||||||
ActiveSpells();
|
ActiveSpells();
|
||||||
|
|
||||||
bool addSpell (const std::string& id, const MWWorld::Ptr& actor, ESM::RangeType range = ESM::RT_Self, const std::string& name = "", int effectIndex = -1);
|
bool addSpell (const std::string& id, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, ESM::RangeType range = ESM::RT_Self, const std::string& name = "", int effectIndex = -1);
|
||||||
///< Overwrites an existing spell with the same ID. If the spell does not have any
|
///< Overwrites an existing spell with the same ID. If the spell does not have any
|
||||||
/// non-instant effects, it is ignored.
|
/// non-instant effects, it is ignored.
|
||||||
/// @param id
|
/// @param id
|
||||||
/// @param actor
|
/// @param actor actor to add the spell to
|
||||||
|
/// @param caster actor who casted the spell
|
||||||
/// @param range Only effects with range type \a range will be applied
|
/// @param range Only effects with range type \a range will be applied
|
||||||
/// @param name Display name for enchantments, since they don't have a name in their record
|
/// @param name Display name for enchantments, since they don't have a name in their record
|
||||||
/// @param effectIndex Only apply one specific effect - useful for reflecting spells, since each effect is reflected individually
|
/// @param effectIndex Only apply one specific effect - useful for reflecting spells, since each effect is reflected individually
|
||||||
|
|
|
@ -114,6 +114,72 @@ namespace MWMechanics
|
||||||
return school;
|
return school;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @return >=100 for fully resisted. can also return negative value for damage amplification.
|
||||||
|
inline float getEffectResistance (short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, const ESM::Spell* spell = NULL)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect *magicEffect =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
||||||
|
effectId);
|
||||||
|
|
||||||
|
const MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
|
||||||
|
float resisted = 0;
|
||||||
|
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
|
||||||
|
{
|
||||||
|
|
||||||
|
short resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId);
|
||||||
|
short weaknessEffect = ESM::MagicEffect::getWeaknessEffect(effectId);
|
||||||
|
|
||||||
|
float resistance = 0;
|
||||||
|
if (resistanceEffect != -1)
|
||||||
|
resistance += stats.getMagicEffects().get(resistanceEffect).mMagnitude;
|
||||||
|
if (weaknessEffect != -1)
|
||||||
|
resistance -= stats.getMagicEffects().get(weaknessEffect).mMagnitude;
|
||||||
|
|
||||||
|
|
||||||
|
float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
||||||
|
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
|
float x = (willpower + 0.1 * luck) * stats.getFatigueTerm();
|
||||||
|
|
||||||
|
// This makes spells that are easy to cast harder to resist and vice versa
|
||||||
|
if (spell != NULL)
|
||||||
|
{
|
||||||
|
float castChance = getSpellSuccessChance(spell, caster);
|
||||||
|
if (castChance > 0)
|
||||||
|
x *= 50 / castChance;
|
||||||
|
}
|
||||||
|
|
||||||
|
float roll = static_cast<float>(std::rand()) / RAND_MAX * 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);
|
||||||
|
|
||||||
|
resisted = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resisted;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, const ESM::Spell* spell = NULL)
|
||||||
|
{
|
||||||
|
float resistance = getEffectResistance(effectId, actor, caster, spell);
|
||||||
|
if (resistance >= 0)
|
||||||
|
return 1 - resistance / 100.f;
|
||||||
|
else
|
||||||
|
return -(resistance-100) / 100.f;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -16,7 +16,7 @@ namespace MWWorld
|
||||||
// TODO: Apply RT_Self effects on the door / container that triggered the trap. Not terribly useful, but you could
|
// TODO: Apply RT_Self effects on the door / container that triggered the trap. Not terribly useful, but you could
|
||||||
// make it lock itself when activated for example.
|
// make it lock itself when activated for example.
|
||||||
|
|
||||||
actor.getClass().getCreatureStats(actor).getActiveSpells().addSpell(mSpellId, actor, ESM::RT_Touch);
|
actor.getClass().getCreatureStats(actor).getActiveSpells().addSpell(mSpellId, actor, actor, ESM::RT_Touch);
|
||||||
|
|
||||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(mSpellId);
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(mSpellId);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
|
|
||||||
#include "esmstore.hpp"
|
#include "esmstore.hpp"
|
||||||
#include "class.hpp"
|
#include "class.hpp"
|
||||||
|
@ -292,47 +294,37 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
||||||
if (enchantment.mData.mType != ESM::Enchantment::ConstantEffect)
|
if (enchantment.mData.mType != ESM::Enchantment::ConstantEffect)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Roll some dice, one for each effect
|
|
||||||
std::vector<EffectParams> params;
|
std::vector<EffectParams> params;
|
||||||
params.resize(enchantment.mEffects.mList.size());
|
|
||||||
for (unsigned int i=0; i<params.size();++i)
|
|
||||||
params[i].mRandom = static_cast<float> (std::rand()) / RAND_MAX;
|
|
||||||
|
|
||||||
bool existed = (mPermanentMagicEffectMagnitudes.find((**iter).getCellRef().mRefID) != mPermanentMagicEffectMagnitudes.end());
|
bool existed = (mPermanentMagicEffectMagnitudes.find((**iter).getCellRef().mRefID) != mPermanentMagicEffectMagnitudes.end());
|
||||||
if (!existed)
|
if (!existed)
|
||||||
{
|
{
|
||||||
|
// Roll some dice, one for each effect
|
||||||
|
params.resize(enchantment.mEffects.mList.size());
|
||||||
|
for (unsigned int i=0; i<params.size();++i)
|
||||||
|
params[i].mRandom = static_cast<float> (std::rand()) / RAND_MAX;
|
||||||
|
|
||||||
// Try resisting each effect
|
// Try resisting each effect
|
||||||
int i=0;
|
int i=0;
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
|
||||||
effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
|
effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
|
||||||
{
|
{
|
||||||
const ESM::MagicEffect *magicEffect =
|
params[i].mMultiplier = MWMechanics::getEffectMultiplier(effectIt->mEffectID, actor, actor);
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
|
||||||
effectIt->mEffectID);
|
|
||||||
|
|
||||||
//const MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
|
||||||
|
|
||||||
float resisted = 0;
|
|
||||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
params[i].mMultiplier = (100.f - resisted) / 100.f;
|
|
||||||
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Note that using the RefID as a key here is not entirely correct.
|
// Note that using the RefID as a key here is not entirely correct.
|
||||||
// Consider equipping the same item twice (e.g. a ring)
|
// Consider equipping the same item twice (e.g. a ring)
|
||||||
// However, permanent enchantments with a random magnitude are kind of an exploit anyway,
|
// However, permanent enchantments with a random magnitude are kind of an exploit anyway,
|
||||||
// so it doesn't really matter if both items will get the same magnitude. *Extreme* edge case.
|
// so it doesn't really matter if both items will get the same magnitude. *Extreme* edge case.
|
||||||
mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID] = params;
|
mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID] = params;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID];
|
||||||
|
|
||||||
int i=0;
|
int i=0;
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
|
||||||
effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
|
effectIt!=enchantment.mEffects.mList.end(); ++effectIt, ++i)
|
||||||
{
|
{
|
||||||
const ESM::MagicEffect *magicEffect =
|
const ESM::MagicEffect *magicEffect =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
||||||
|
@ -355,7 +347,6 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
||||||
magnitude *= params[i].mMultiplier;
|
magnitude *= params[i].mMultiplier;
|
||||||
if (magnitude)
|
if (magnitude)
|
||||||
mMagicEffects.add (*effectIt, magnitude);
|
mMagicEffects.add (*effectIt, magnitude);
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -554,8 +545,9 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
|
||||||
effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
|
effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
|
||||||
{
|
{
|
||||||
float random = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID][i].mRandom;
|
const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID][i];
|
||||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
|
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
|
||||||
|
magnitude *= params.mMultiplier;
|
||||||
visitor.visit(*effectIt, (**iter).getClass().getName(**iter), magnitude);
|
visitor.visit(*effectIt, (**iter).getClass().getName(**iter), magnitude);
|
||||||
|
|
||||||
++i;
|
++i;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/spellsuccess.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
|
|
||||||
#include "../mwrender/sky.hpp"
|
#include "../mwrender/sky.hpp"
|
||||||
|
@ -2158,7 +2158,7 @@ namespace MWWorld
|
||||||
// Now apply the spell!
|
// Now apply the spell!
|
||||||
|
|
||||||
// Apply Self portion
|
// Apply Self portion
|
||||||
actor.getClass().getCreatureStats(actor).getActiveSpells().addSpell(selectedSpell, actor, ESM::RT_Self, sourceName);
|
actor.getClass().getCreatureStats(actor).getActiveSpells().addSpell(selectedSpell, actor, actor, ESM::RT_Self, sourceName);
|
||||||
|
|
||||||
// Apply Touch portion
|
// Apply Touch portion
|
||||||
// TODO: Distance is probably incorrect, and should it be hardcoded?
|
// TODO: Distance is probably incorrect, and should it be hardcoded?
|
||||||
|
@ -2166,7 +2166,7 @@ namespace MWWorld
|
||||||
if (!contact.first.isEmpty())
|
if (!contact.first.isEmpty())
|
||||||
{
|
{
|
||||||
if (contact.first.getClass().isActor())
|
if (contact.first.getClass().isActor())
|
||||||
contact.first.getClass().getCreatureStats(contact.first).getActiveSpells().addSpell(selectedSpell, contact.first, ESM::RT_Touch, sourceName);
|
contact.first.getClass().getCreatureStats(contact.first).getActiveSpells().addSpell(selectedSpell, contact.first, actor, ESM::RT_Touch, sourceName);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We hit a non-actor, e.g. a door. Only instant effects are relevant.
|
// We hit a non-actor, e.g. a door. Only instant effects are relevant.
|
||||||
|
|
Loading…
Reference in a new issue