forked from teamnwah/openmw-tes3coop
Refactor ActiveSpells to track range type. Added basic self range magic.
This commit is contained in:
parent
9e2b1942fc
commit
cbe96a2170
10 changed files with 187 additions and 29 deletions
|
@ -406,6 +406,8 @@ namespace MWBase
|
||||||
virtual bool getGodModeState() = 0;
|
virtual bool getGodModeState() = 0;
|
||||||
|
|
||||||
virtual bool toggleGodMode() = 0;
|
virtual bool toggleGodMode() = 0;
|
||||||
|
|
||||||
|
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,8 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
// add lasting effect spells/potions etc
|
// add lasting effect spells/potions etc
|
||||||
|
|
||||||
|
// TODO: Move this to ActiveSpells
|
||||||
const MWMechanics::ActiveSpells::TContainer& activeSpells = stats.getActiveSpells().getActiveSpells();
|
const MWMechanics::ActiveSpells::TContainer& activeSpells = stats.getActiveSpells().getActiveSpells();
|
||||||
for (MWMechanics::ActiveSpells::TContainer::const_iterator it = activeSpells.begin();
|
for (MWMechanics::ActiveSpells::TContainer::const_iterator it = activeSpells.begin();
|
||||||
it != activeSpells.end(); ++it)
|
it != activeSpells.end(); ++it)
|
||||||
|
@ -105,31 +107,36 @@ namespace MWGui
|
||||||
|
|
||||||
float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
||||||
|
|
||||||
|
int i=0;
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = list.mList.begin();
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = list.mList.begin();
|
||||||
effectIt != list.mList.end(); ++effectIt)
|
effectIt != list.mList.end(); ++effectIt, ++i)
|
||||||
{
|
{
|
||||||
|
if (effectIt->mRange != it->second.mRange)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float randomFactor = it->second.mRandom[i];
|
||||||
|
|
||||||
const ESM::MagicEffect* magicEffect =
|
const ESM::MagicEffect* magicEffect =
|
||||||
MWBase::Environment::get().getWorld ()->getStore ().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
MWBase::Environment::get().getWorld ()->getStore ().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
||||||
|
|
||||||
MagicEffectInfo effectInfo;
|
MagicEffectInfo effectInfo;
|
||||||
effectInfo.mSource = getSpellDisplayName (it->first);
|
effectInfo.mSource = it->second.mName;
|
||||||
effectInfo.mKey = MWMechanics::EffectKey (effectIt->mEffectID);
|
effectInfo.mKey = MWMechanics::EffectKey (effectIt->mEffectID);
|
||||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
||||||
effectInfo.mKey.mArg = effectIt->mSkill;
|
effectInfo.mKey.mArg = effectIt->mSkill;
|
||||||
else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
||||||
effectInfo.mKey.mArg = effectIt->mAttribute;
|
effectInfo.mKey.mArg = effectIt->mAttribute;
|
||||||
effectInfo.mMagnitude = effectIt->mMagnMin + (effectIt->mMagnMax-effectIt->mMagnMin) * it->second.second;
|
effectInfo.mMagnitude = effectIt->mMagnMin + (effectIt->mMagnMax-effectIt->mMagnMin) * randomFactor;
|
||||||
effectInfo.mRemainingTime = effectIt->mDuration +
|
effectInfo.mRemainingTime = effectIt->mDuration +
|
||||||
(it->second.first - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale;
|
(it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale;
|
||||||
|
|
||||||
// ingredients need special casing for their magnitude / duration
|
// ingredients need special casing for their magnitude / duration
|
||||||
/// \todo duplicated from ActiveSpells, helper function?
|
|
||||||
if (MWBase::Environment::get().getWorld()->getStore().get<ESM::Ingredient>().search (it->first))
|
if (MWBase::Environment::get().getWorld()->getStore().get<ESM::Ingredient>().search (it->first))
|
||||||
{
|
{
|
||||||
effectInfo.mRemainingTime = effectIt->mDuration * it->second.second +
|
effectInfo.mRemainingTime = effectIt->mDuration * randomFactor +
|
||||||
(it->second.first - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale;
|
(it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale;
|
||||||
|
|
||||||
effectInfo.mMagnitude = static_cast<int> (0.05*it->second.second / (0.1 * magicEffect->mData.mBaseCost));
|
effectInfo.mMagnitude = static_cast<int> (0.05*randomFactor / (0.1 * magicEffect->mData.mBaseCost));
|
||||||
}
|
}
|
||||||
|
|
||||||
effects[effectIt->mEffectID].push_back (effectInfo);
|
effects[effectIt->mEffectID].push_back (effectInfo);
|
||||||
|
@ -288,6 +295,10 @@ namespace MWGui
|
||||||
|
|
||||||
ESM::EffectList SpellIcons::getSpellEffectList (const std::string& id)
|
ESM::EffectList SpellIcons::getSpellEffectList (const std::string& id)
|
||||||
{
|
{
|
||||||
|
if (const ESM::Enchantment* enchantment =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search (id))
|
||||||
|
return enchantment->mEffects;
|
||||||
|
|
||||||
if (const ESM::Spell *spell =
|
if (const ESM::Spell *spell =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search (id))
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search (id))
|
||||||
return spell->mEffects;
|
return spell->mEffects;
|
||||||
|
|
|
@ -467,7 +467,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
Widgets::MWDynamicStatPtr chargeWidget = enchantArea->createWidget<Widgets::MWDynamicStat>
|
Widgets::MWDynamicStatPtr chargeWidget = enchantArea->createWidget<Widgets::MWDynamicStat>
|
||||||
("MW_ChargeBar", chargeCoord, MyGUI::Align::Default, "ToolTipEnchantCharge");
|
("MW_ChargeBar", chargeCoord, MyGUI::Align::Default, "ToolTipEnchantCharge");
|
||||||
chargeWidget->setValue(charge, charge);
|
chargeWidget->setValue(charge, maxCharge);
|
||||||
totalSize.height += 24;
|
totalSize.height += 24;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
@ -64,15 +65,19 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
std::pair<ESM::EffectList, std::pair<bool, bool> > effects = getEffectList (iter->first);
|
std::pair<ESM::EffectList, std::pair<bool, bool> > effects = getEffectList (iter->first);
|
||||||
|
|
||||||
const MWWorld::TimeStamp& start = iter->second.first;
|
const MWWorld::TimeStamp& start = iter->second.mTimeStamp;
|
||||||
float magnitude = iter->second.second;
|
|
||||||
|
|
||||||
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 effectIter (effects.first.mList.begin());
|
||||||
|
effectIter!=effects.first.mList.end(); ++effectIter, ++i)
|
||||||
{
|
{
|
||||||
if (iter->mDuration)
|
float magnitude = iter->second.mRandom[i];
|
||||||
|
if (effectIter->mRange != iter->second.mRange)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (effectIter->mDuration)
|
||||||
{
|
{
|
||||||
int duration = iter->mDuration;
|
int duration = effectIter->mDuration;
|
||||||
|
|
||||||
if (effects.second.first)
|
if (effects.second.first)
|
||||||
duration *= magnitude;
|
duration *= magnitude;
|
||||||
|
@ -89,9 +94,9 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
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);
|
effectIter->mEffectID);
|
||||||
|
|
||||||
if (iter->mDuration==0)
|
if (effectIter->mDuration==0)
|
||||||
{
|
{
|
||||||
param.mMagnitude =
|
param.mMagnitude =
|
||||||
static_cast<int> (magnitude / (0.1 * magicEffect->mData.mBaseCost));
|
static_cast<int> (magnitude / (0.1 * magicEffect->mData.mBaseCost));
|
||||||
|
@ -104,9 +109,9 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
param.mMagnitude = static_cast<int> (
|
param.mMagnitude = static_cast<int> (
|
||||||
(iter->mMagnMax-iter->mMagnMin)*magnitude + iter->mMagnMin);
|
(effectIter->mMagnMax-effectIter->mMagnMin)*magnitude + effectIter->mMagnMin);
|
||||||
|
|
||||||
mEffects.add (*iter, param);
|
mEffects.add (*effectIter, param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,6 +120,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
std::pair<ESM::EffectList, std::pair<bool, bool> > ActiveSpells::getEffectList (const std::string& id) const
|
std::pair<ESM::EffectList, std::pair<bool, bool> > ActiveSpells::getEffectList (const std::string& id) const
|
||||||
{
|
{
|
||||||
|
if (const ESM::Enchantment* enchantment =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search (id))
|
||||||
|
return std::make_pair (enchantment->mEffects, std::make_pair(false, false));
|
||||||
|
|
||||||
if (const ESM::Spell *spell =
|
if (const ESM::Spell *spell =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search (id))
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search (id))
|
||||||
return std::make_pair (spell->mEffects, std::make_pair(false, false));
|
return std::make_pair (spell->mEffects, std::make_pair(false, false));
|
||||||
|
@ -156,7 +165,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)
|
bool ActiveSpells::addSpell (const std::string& id, const MWWorld::Ptr& actor, ESM::RangeType range, const std::string& name)
|
||||||
{
|
{
|
||||||
std::pair<ESM::EffectList, std::pair<bool, bool> > effects = getEffectList (id);
|
std::pair<ESM::EffectList, std::pair<bool, bool> > effects = getEffectList (id);
|
||||||
bool stacks = effects.second.second;
|
bool stacks = effects.second.second;
|
||||||
|
@ -196,11 +205,41 @@ namespace MWMechanics
|
||||||
random *= 0.25 * x;
|
random *= 0.25 * x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActiveSpellParams params;
|
||||||
|
for (unsigned int i=0; i<effects.first.mList.size(); ++i)
|
||||||
|
params.mRandom.push_back(static_cast<float> (std::rand()) / RAND_MAX);
|
||||||
|
params.mRange = range;
|
||||||
|
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
|
params.mName = name;
|
||||||
|
|
||||||
if (iter==mSpells.end() || stacks)
|
if (iter==mSpells.end() || stacks)
|
||||||
mSpells.insert (std::make_pair (id,
|
mSpells.insert (std::make_pair (id, params));
|
||||||
std::make_pair (MWBase::Environment::get().getWorld()->getTimeStamp(), random)));
|
|
||||||
else
|
else
|
||||||
iter->second = std::make_pair (MWBase::Environment::get().getWorld()->getTimeStamp(), random);
|
iter->second = params;
|
||||||
|
|
||||||
|
// Play sounds
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.first.mList.begin());
|
||||||
|
iter!=effects.first.mList.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (iter->mRange != range)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const ESM::MagicEffect *magicEffect =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
||||||
|
iter->mEffectID);
|
||||||
|
|
||||||
|
static const std::string schools[] = {
|
||||||
|
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||||
|
};
|
||||||
|
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
if(!magicEffect->mHitSound.empty())
|
||||||
|
sndMgr->playSound3D(actor, magicEffect->mHitSound, 1.0f, 1.0f);
|
||||||
|
else
|
||||||
|
sndMgr->playSound3D(actor, schools[magicEffect->mData.mSchool]+" hit", 1.0f, 1.0f);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
mSpellsChanged = true;
|
mSpellsChanged = true;
|
||||||
|
|
||||||
|
@ -249,13 +288,14 @@ namespace MWMechanics
|
||||||
duration = iter->mDuration;
|
duration = iter->mDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effects.second.first)
|
// Scale duration by magnitude if needed
|
||||||
duration *= iterator->second.second;
|
if (effects.second.first && iterator->second.mRandom.size())
|
||||||
|
duration *= iterator->second.mRandom.front();
|
||||||
|
|
||||||
double scaledDuration = duration *
|
double scaledDuration = duration *
|
||||||
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
||||||
|
|
||||||
double usedUp = MWBase::Environment::get().getWorld()->getTimeStamp()-iterator->second.first;
|
double usedUp = MWBase::Environment::get().getWorld()->getTimeStamp()-iterator->second.mTimeStamp;
|
||||||
|
|
||||||
if (usedUp>=scaledDuration)
|
if (usedUp>=scaledDuration)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include "magiceffects.hpp"
|
#include "magiceffects.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/defs.hpp>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct Spell;
|
struct Spell;
|
||||||
|
@ -22,6 +24,22 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
struct ActiveSpellParams
|
||||||
|
{
|
||||||
|
// Only apply effects of this range type
|
||||||
|
ESM::RangeType mRange;
|
||||||
|
|
||||||
|
// When the spell was added
|
||||||
|
MWWorld::TimeStamp mTimeStamp;
|
||||||
|
|
||||||
|
// Random factor for each effect
|
||||||
|
std::vector<float> mRandom;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
std::string mName;
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief Lasting spell effects
|
/// \brief Lasting spell effects
|
||||||
///
|
///
|
||||||
/// \note The name of this class is slightly misleading, since it also handels lasting potion
|
/// \note The name of this class is slightly misleading, since it also handels lasting potion
|
||||||
|
@ -30,7 +48,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef std::multimap<std::string, std::pair<MWWorld::TimeStamp, float> > TContainer;
|
typedef std::multimap<std::string, ActiveSpellParams > TContainer;
|
||||||
typedef TContainer::const_iterator TIterator;
|
typedef TContainer::const_iterator TIterator;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -51,9 +69,13 @@ namespace MWMechanics
|
||||||
|
|
||||||
ActiveSpells();
|
ActiveSpells();
|
||||||
|
|
||||||
bool addSpell (const std::string& id, const MWWorld::Ptr& actor);
|
bool addSpell (const std::string& id, const MWWorld::Ptr& actor, ESM::RangeType range = ESM::RT_Self, const std::string& name = "");
|
||||||
///< 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 actor
|
||||||
|
/// @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
|
||||||
///
|
///
|
||||||
/// \return Has the spell been added?
|
/// \return Has the spell been added?
|
||||||
|
|
||||||
|
|
|
@ -273,7 +273,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name)
|
||||||
|
|
||||||
newRecord.mName = name;
|
newRecord.mName = name;
|
||||||
|
|
||||||
int index = static_cast<int> (std::rand()/static_cast<double> (RAND_MAX)*6);
|
int index = static_cast<int> (std::rand()/static_cast<double> (RAND_MAX+1)*6);
|
||||||
assert (index>=0 && index<6);
|
assert (index>=0 && index<6);
|
||||||
|
|
||||||
static const char *name[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" };
|
static const char *name[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" };
|
||||||
|
|
|
@ -531,6 +531,11 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
||||||
else
|
else
|
||||||
sndMgr->playSound3D(mPtr, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f);
|
sndMgr->playSound3D(mPtr, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
if (inv.getSelectedEnchantItem() != inv.end())
|
||||||
|
{
|
||||||
|
// Enchanted items cast immediately (no animation)
|
||||||
|
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(mWeaponType == WeapType_PickProbe)
|
else if(mWeaponType == WeapType_PickProbe)
|
||||||
{
|
{
|
||||||
|
|
|
@ -653,6 +653,9 @@ void Animation::handleTextKey(AnimState &state, const std::string &groupname, co
|
||||||
MWWorld::Class::get(mPtr).hit(mPtr, MWMechanics::CreatureStats::AT_Thrust);
|
MWWorld::Class::get(mPtr).hit(mPtr, MWMechanics::CreatureStats::AT_Thrust);
|
||||||
else if(evt.compare(off, len, "hit") == 0)
|
else if(evt.compare(off, len, "hit") == 0)
|
||||||
MWWorld::Class::get(mPtr).hit(mPtr);
|
MWWorld::Class::get(mPtr).hit(mPtr);
|
||||||
|
|
||||||
|
else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release")
|
||||||
|
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#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 "../mwrender/sky.hpp"
|
#include "../mwrender/sky.hpp"
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
@ -1983,4 +1985,75 @@ namespace MWWorld
|
||||||
return mGodMode;
|
return mGodMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::castSpell(const Ptr &actor)
|
||||||
|
{
|
||||||
|
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
stats.setAttackingOrSpell(false);
|
||||||
|
|
||||||
|
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
||||||
|
if (!selectedSpell.empty())
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = getStore().get<ESM::Spell>().search(selectedSpell);
|
||||||
|
|
||||||
|
// Check mana
|
||||||
|
MWMechanics::DynamicStat<float> magicka = stats.getMagicka();
|
||||||
|
if (magicka.getCurrent() < spell->mData.mCost)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientSP}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce mana
|
||||||
|
magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost);
|
||||||
|
stats.setMagicka(magicka);
|
||||||
|
|
||||||
|
// Check success
|
||||||
|
int successChance = MWMechanics::getSpellSuccessChance(selectedSpell, actor);
|
||||||
|
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||||
|
if (roll >= successChance)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}");
|
||||||
|
// TODO sound: "Spell Failure <School>"
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
actor.getClass().getCreatureStats(actor).getActiveSpells().addSpell(selectedSpell, actor, ESM::RT_Self);
|
||||||
|
// TODO: RT_Range, RT_Touch
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
||||||
|
if (inv.getSelectedEnchantItem() != inv.end())
|
||||||
|
{
|
||||||
|
MWWorld::Ptr item = *inv.getSelectedEnchantItem();
|
||||||
|
std::string id = item.getClass().getEnchantment(item);
|
||||||
|
const ESM::Enchantment* enchantment = getStore().get<ESM::Enchantment>().search (id);
|
||||||
|
|
||||||
|
// Check if there's enough charge left
|
||||||
|
const float enchantCost = enchantment->mData.mCost;
|
||||||
|
MWMechanics::NpcStats &stats = MWWorld::Class::get(actor).getNpcStats(actor);
|
||||||
|
int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified();
|
||||||
|
const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10);
|
||||||
|
|
||||||
|
if (item.getCellRef().mEnchantmentCharge == -1)
|
||||||
|
item.getCellRef().mEnchantmentCharge = enchantment->mData.mCharge;
|
||||||
|
|
||||||
|
if (item.getCellRef().mEnchantmentCharge < castCost)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce charge
|
||||||
|
item.getCellRef().mEnchantmentCharge -= castCost;
|
||||||
|
|
||||||
|
std::string itemName = item.getClass().getName(item);
|
||||||
|
actor.getClass().getCreatureStats(actor).getActiveSpells().addSpell(id, actor, ESM::RT_Self, itemName);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: RT_Range, RT_Touch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -453,6 +453,8 @@ namespace MWWorld
|
||||||
virtual bool getGodModeState();
|
virtual bool getGodModeState();
|
||||||
|
|
||||||
virtual bool toggleGodMode();
|
virtual bool toggleGodMode();
|
||||||
|
|
||||||
|
virtual void castSpell (const MWWorld::Ptr& actor);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue