forked from mirror/openmw-tes3mp
Merge pull request #1044 from Allofich/magic
Changes to multi-effect spells
This commit is contained in:
commit
8677a6f803
8 changed files with 203 additions and 167 deletions
|
@ -486,8 +486,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId,
|
virtual void launchMagicBolt (const std::string& spellId, bool stack, const ESM::EffectList& effects,
|
||||||
float speed, bool stack, const ESM::EffectList& effects,
|
|
||||||
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0;
|
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0;
|
||||||
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
||||||
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0;
|
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0;
|
||||||
|
|
|
@ -1236,19 +1236,27 @@ bool CharacterController::updateWeaponState()
|
||||||
cast.playSpellCastingEffects(spellid);
|
cast.playSpellCastingEffects(spellid);
|
||||||
|
|
||||||
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
||||||
const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0);
|
|
||||||
|
const ESM::ENAMstruct &lastEffect = spell->mEffects.mList.at(spell->mEffects.mList.size() - 1);
|
||||||
|
|
||||||
const ESM::MagicEffect *effect;
|
const ESM::MagicEffect *effect;
|
||||||
effect = store.get<ESM::MagicEffect>().find(effectentry.mEffectID);
|
|
||||||
|
effect = store.get<ESM::MagicEffect>().find(lastEffect.mEffectID); // use last effect of list for color of VFX_Hands
|
||||||
|
|
||||||
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Hands");
|
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Hands");
|
||||||
|
|
||||||
|
for (size_t iter = 0; iter < spell->mEffects.mList.size(); ++iter) // play hands vfx for each effect
|
||||||
|
{
|
||||||
if (mAnimation->getNode("Bip01 L Hand"))
|
if (mAnimation->getNode("Bip01 L Hand"))
|
||||||
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle);
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle);
|
||||||
|
|
||||||
if (mAnimation->getNode("Bip01 R Hand"))
|
if (mAnimation->getNode("Bip01 R Hand"))
|
||||||
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle);
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle);
|
||||||
|
}
|
||||||
|
|
||||||
switch(effectentry.mRange)
|
const ESM::ENAMstruct &firstEffect = spell->mEffects.mList.at(0); // first effect used for casting animation
|
||||||
|
|
||||||
|
switch(firstEffect.mRange)
|
||||||
{
|
{
|
||||||
case 0: mAttackType = "self"; break;
|
case 0: mAttackType = "self"; break;
|
||||||
case 1: mAttackType = "touch"; break;
|
case 1: mAttackType = "touch"; break;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
|
@ -27,41 +28,6 @@
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
/// Get projectile properties (model, sound and speed) for a spell with the given effects
|
|
||||||
/// If \a model is empty, the spell has no ranged effects and should not spawn a projectile.
|
|
||||||
void getProjectileInfo (const ESM::EffectList& effects, std::string& model, std::string& sound, float& speed)
|
|
||||||
{
|
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
|
|
||||||
iter!=effects.mList.end(); ++iter)
|
|
||||||
{
|
|
||||||
if (iter->mRange != ESM::RT_Target)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
|
||||||
iter->mEffectID);
|
|
||||||
|
|
||||||
model = magicEffect->mBolt;
|
|
||||||
if (model.empty())
|
|
||||||
model = "VFX_DefaultBolt";
|
|
||||||
|
|
||||||
static const std::string schools[] = {
|
|
||||||
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
|
||||||
};
|
|
||||||
if (!magicEffect->mBoltSound.empty())
|
|
||||||
sound = magicEffect->mBoltSound;
|
|
||||||
else
|
|
||||||
sound = schools[magicEffect->mData.mSchool] + " bolt";
|
|
||||||
|
|
||||||
speed = magicEffect->mData.mSpeed;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -317,6 +283,23 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get projectile properties (model, sound and speed) for a spell with the given effects and launch.
|
||||||
|
/// If \a model is empty, the spell has no ranged effects and should not spawn a projectile.
|
||||||
|
void CastSpell::launchMagicBolt (const ESM::EffectList& effects)
|
||||||
|
{
|
||||||
|
osg::Vec3f fallbackDirection (0,1,0);
|
||||||
|
|
||||||
|
// Fall back to a "caster to target" direction if we have no other means of determining it
|
||||||
|
// (e.g. when cast by a non-actor)
|
||||||
|
if (!mTarget.isEmpty())
|
||||||
|
fallbackDirection =
|
||||||
|
osg::Vec3f(mTarget.getRefData().getPosition().asVec3())-
|
||||||
|
osg::Vec3f(mCaster.getRefData().getPosition().asVec3());
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, effects,
|
||||||
|
mCaster, mSourceName, fallbackDirection);
|
||||||
|
}
|
||||||
|
|
||||||
void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster,
|
void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster,
|
||||||
const ESM::EffectList &effects, ESM::RangeType range, bool reflected, bool exploded)
|
const ESM::EffectList &effects, ESM::RangeType range, bool reflected, bool exploded)
|
||||||
{
|
{
|
||||||
|
@ -356,7 +339,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
ESM::EffectList reflectedEffects;
|
ESM::EffectList reflectedEffects;
|
||||||
std::vector<ActiveSpells::ActiveEffect> appliedLastingEffects;
|
std::vector<ActiveSpells::ActiveEffect> appliedLastingEffects;
|
||||||
bool firstAppliedEffect = true;
|
|
||||||
bool anyHarmfulEffect = false;
|
bool anyHarmfulEffect = false;
|
||||||
|
|
||||||
// HACK: cache target's magic effects here, and add any applied effects to it. Use the cached effects for determining resistance.
|
// HACK: cache target's magic effects here, and add any applied effects to it. Use the cached effects for determining resistance.
|
||||||
|
@ -544,9 +526,6 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)
|
if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)
|
||||||
{
|
|
||||||
// Play sound, only for the first effect
|
|
||||||
if (firstAppliedEffect)
|
|
||||||
{
|
{
|
||||||
static const std::string schools[] = {
|
static const std::string schools[] = {
|
||||||
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||||
|
@ -557,8 +536,6 @@ namespace MWMechanics
|
||||||
sndMgr->playSound3D(target, magicEffect->mHitSound, 1.0f, 1.0f);
|
sndMgr->playSound3D(target, magicEffect->mHitSound, 1.0f, 1.0f);
|
||||||
else
|
else
|
||||||
sndMgr->playSound3D(target, schools[magicEffect->mData.mSchool]+" hit", 1.0f, 1.0f);
|
sndMgr->playSound3D(target, schools[magicEffect->mData.mSchool]+" hit", 1.0f, 1.0f);
|
||||||
firstAppliedEffect = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add VFX
|
// Add VFX
|
||||||
const ESM::Static* castStatic;
|
const ESM::Static* castStatic;
|
||||||
|
@ -791,17 +768,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
if (launchProjectile)
|
if (launchProjectile)
|
||||||
{
|
launchMagicBolt(enchantment->mEffects);
|
||||||
std::string projectileModel;
|
|
||||||
std::string sound;
|
|
||||||
float speed = 0;
|
|
||||||
getProjectileInfo(enchantment->mEffects, projectileModel, sound, speed);
|
|
||||||
if (!projectileModel.empty())
|
|
||||||
MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed,
|
|
||||||
false, enchantment->mEffects, mCaster, mSourceName,
|
|
||||||
// Not needed, enchantments can only be cast by actors
|
|
||||||
osg::Vec3f(1,0,0));
|
|
||||||
}
|
|
||||||
else if (!mTarget.isEmpty())
|
else if (!mTarget.isEmpty())
|
||||||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Target);
|
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Target);
|
||||||
|
|
||||||
|
@ -882,28 +849,9 @@ namespace MWMechanics
|
||||||
inflict(mCaster, mCaster, spell->mEffects, ESM::RT_Self);
|
inflict(mCaster, mCaster, spell->mEffects, ESM::RT_Self);
|
||||||
|
|
||||||
if (!mTarget.isEmpty())
|
if (!mTarget.isEmpty())
|
||||||
{
|
|
||||||
inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch);
|
inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch);
|
||||||
}
|
|
||||||
|
|
||||||
|
launchMagicBolt(spell->mEffects);
|
||||||
std::string projectileModel;
|
|
||||||
std::string sound;
|
|
||||||
float speed = 0;
|
|
||||||
getProjectileInfo(spell->mEffects, projectileModel, sound, speed);
|
|
||||||
if (!projectileModel.empty())
|
|
||||||
{
|
|
||||||
osg::Vec3f fallbackDirection (0,1,0);
|
|
||||||
// Fall back to a "caster to target" direction if we have no other means of determining it
|
|
||||||
// (e.g. when cast by a non-actor)
|
|
||||||
if (!mTarget.isEmpty())
|
|
||||||
fallbackDirection =
|
|
||||||
osg::Vec3f(mTarget.getRefData().getPosition().asVec3())-
|
|
||||||
osg::Vec3f(mCaster.getRefData().getPosition().asVec3());
|
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed,
|
|
||||||
false, spell->mEffects, mCaster, mSourceName, fallbackDirection);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -976,10 +924,12 @@ namespace MWMechanics
|
||||||
|
|
||||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
||||||
const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0);
|
|
||||||
|
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->mEffects.mList.begin();
|
||||||
|
iter != spell->mEffects.mList.end(); ++iter)
|
||||||
|
{
|
||||||
const ESM::MagicEffect *effect;
|
const ESM::MagicEffect *effect;
|
||||||
effect = store.get<ESM::MagicEffect>().find(effectentry.mEffectID);
|
effect = store.get<ESM::MagicEffect>().find(iter->mEffectID);
|
||||||
|
|
||||||
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
|
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
|
||||||
|
|
||||||
|
@ -1007,6 +957,7 @@ namespace MWMechanics
|
||||||
else
|
else
|
||||||
sndMgr->playSound3D(mCaster, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f);
|
sndMgr->playSound3D(mCaster, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int getEffectiveEnchantmentCastCost(float castCost, const MWWorld::Ptr &actor)
|
int getEffectiveEnchantmentCastCost(float castCost, const MWWorld::Ptr &actor)
|
||||||
{
|
{
|
||||||
|
|
|
@ -94,6 +94,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
void playSpellCastingEffects(const std::string &spellid);
|
void playSpellCastingEffects(const std::string &spellid);
|
||||||
|
|
||||||
|
/// Launch a bolt with the given effects.
|
||||||
|
void launchMagicBolt (const ESM::EffectList& effects);
|
||||||
|
|
||||||
/// @note \a target can be any type of object, not just actors.
|
/// @note \a target can be any type of object, not just actors.
|
||||||
/// @note \a caster can be any type of object, or even an empty object.
|
/// @note \a caster can be any type of object, or even an empty object.
|
||||||
void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
|
void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "projectilemanager.hpp"
|
#include "projectilemanager.hpp"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include <osg/PositionAttitudeTransform>
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
@ -33,6 +35,55 @@
|
||||||
|
|
||||||
#include "../mwphysics/physicssystem.hpp"
|
#include "../mwphysics/physicssystem.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
ESM::EffectList getMagicBoltData(std::vector<std::string>& projectileIDs, std::vector<std::string>& sounds, float& speed, const ESM::EffectList& effects)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
ESM::EffectList projectileEffects;
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
|
||||||
|
iter!=effects.mList.end(); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
||||||
|
iter->mEffectID);
|
||||||
|
|
||||||
|
// All the projectiles should use the same speed. From observations in the
|
||||||
|
// original engine, this seems to be the average of the constituent effects.
|
||||||
|
speed += magicEffect->mData.mSpeed;
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (iter->mRange != ESM::RT_Target)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (magicEffect->mBolt.empty())
|
||||||
|
projectileIDs.push_back("VFX_DefaultBolt");
|
||||||
|
else
|
||||||
|
projectileIDs.push_back(magicEffect->mBolt);
|
||||||
|
|
||||||
|
static const std::string schools[] = {
|
||||||
|
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||||
|
};
|
||||||
|
if (!magicEffect->mBoltSound.empty())
|
||||||
|
sounds.push_back(magicEffect->mBoltSound);
|
||||||
|
else
|
||||||
|
sounds.push_back(schools[magicEffect->mData.mSchool] + " bolt");
|
||||||
|
projectileEffects.mList.push_back(*iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count != 0)
|
||||||
|
speed /= count;
|
||||||
|
|
||||||
|
if (projectileEffects.mList.size() > 1) // insert a VFX_Multiple projectile if there are multiple projectile effects
|
||||||
|
{
|
||||||
|
std::ostringstream ID;
|
||||||
|
ID << "VFX_Multiple" << effects.mList.size();
|
||||||
|
std::vector<std::string>::iterator it;
|
||||||
|
it = projectileIDs.begin();
|
||||||
|
it = projectileIDs.insert(it, ID.str());
|
||||||
|
}
|
||||||
|
return projectileEffects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
@ -92,7 +143,19 @@ namespace MWWorld
|
||||||
attachTo = rotateNode;
|
attachTo = rotateNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
mResourceSystem->getSceneManager()->getInstance(model, attachTo);
|
osg::ref_ptr<osg::Node> ptr = mResourceSystem->getSceneManager()->getInstance(model, attachTo);
|
||||||
|
|
||||||
|
if (state.mIdMagic.size() > 1)
|
||||||
|
for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter)
|
||||||
|
{
|
||||||
|
std::ostringstream nodeName;
|
||||||
|
nodeName << "Dummy" << std::setw(2) << std::setfill('0') << iter;
|
||||||
|
const ESM::Weapon* weapon = MWBase::Environment::get().getWorld()->getStore().get<ESM::Weapon>().find (state.mIdMagic.at(iter));
|
||||||
|
SceneUtil::FindByNameVisitor findVisitor(nodeName.str());
|
||||||
|
attachTo->accept(findVisitor);
|
||||||
|
if (findVisitor.mFoundNode)
|
||||||
|
mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode);
|
||||||
|
}
|
||||||
|
|
||||||
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
|
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
|
||||||
state.mNode->accept(disableFreezeOnCullVisitor);
|
state.mNode->accept(disableFreezeOnCullVisitor);
|
||||||
|
@ -112,10 +175,8 @@ namespace MWWorld
|
||||||
state.mEffectAnimationTime->addTime(duration);
|
state.mEffectAnimationTime->addTime(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectileManager::launchMagicBolt(const std::string &model, const std::string &sound,
|
void ProjectileManager::launchMagicBolt(const std::string &spellId, bool stack, const ESM::EffectList &effects, const Ptr &caster,
|
||||||
const std::string &spellId, float speed, bool stack,
|
const std::string &sourceName, const osg::Vec3f& fallbackDirection)
|
||||||
const ESM::EffectList &effects, const Ptr &caster, const std::string &sourceName,
|
|
||||||
const osg::Vec3f& fallbackDirection)
|
|
||||||
{
|
{
|
||||||
osg::Vec3f pos = caster.getRefData().getPosition().asVec3();
|
osg::Vec3f pos = caster.getRefData().getPosition().asVec3();
|
||||||
if (caster.getClass().isActor())
|
if (caster.getClass().isActor())
|
||||||
|
@ -137,32 +198,30 @@ namespace MWWorld
|
||||||
|
|
||||||
MagicBoltState state;
|
MagicBoltState state;
|
||||||
state.mSourceName = sourceName;
|
state.mSourceName = sourceName;
|
||||||
state.mId = model;
|
|
||||||
state.mSpellId = spellId;
|
state.mSpellId = spellId;
|
||||||
state.mCasterHandle = caster;
|
state.mCasterHandle = caster;
|
||||||
if (caster.getClass().isActor())
|
if (caster.getClass().isActor())
|
||||||
state.mActorId = caster.getClass().getCreatureStats(caster).getActorId();
|
state.mActorId = caster.getClass().getCreatureStats(caster).getActorId();
|
||||||
else
|
else
|
||||||
state.mActorId = -1;
|
state.mActorId = -1;
|
||||||
state.mSpeed = speed;
|
|
||||||
state.mStack = stack;
|
state.mStack = stack;
|
||||||
state.mSoundId = sound;
|
|
||||||
|
|
||||||
// Only interested in "on target" effects
|
state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, effects);
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
|
|
||||||
iter!=effects.mList.end(); ++iter)
|
|
||||||
{
|
|
||||||
if (iter->mRange == ESM::RT_Target)
|
|
||||||
state.mEffects.mList.push_back(*iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), model);
|
// Non-projectile should have been removed by getMagicBoltData
|
||||||
|
if (state.mEffects.mList.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0));
|
||||||
MWWorld::Ptr ptr = ref.getPtr();
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
|
||||||
createModel(state, ptr.getClass().getModel(ptr), pos, orient, true);
|
createModel(state, ptr.getClass().getModel(ptr), pos, orient, true);
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
state.mSound = sndMgr->playSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
for (size_t it = 0; it != state.mSoundIds.size(); it++)
|
||||||
|
{
|
||||||
|
state.mSounds.push_back(sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop));
|
||||||
|
}
|
||||||
|
|
||||||
mMagicBolts.push_back(state);
|
mMagicBolts.push_back(state);
|
||||||
}
|
}
|
||||||
|
@ -173,7 +232,7 @@ namespace MWWorld
|
||||||
state.mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
state.mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||||
state.mBowId = bow.getCellRef().getRefId();
|
state.mBowId = bow.getCellRef().getRefId();
|
||||||
state.mVelocity = orient * osg::Vec3f(0,1,0) * speed;
|
state.mVelocity = orient * osg::Vec3f(0,1,0) * speed;
|
||||||
state.mId = projectile.getCellRef().getRefId();
|
state.mIdArrow = projectile.getCellRef().getRefId();
|
||||||
state.mCasterHandle = actor;
|
state.mCasterHandle = actor;
|
||||||
state.mAttackStrength = attackStrength;
|
state.mAttackStrength = attackStrength;
|
||||||
|
|
||||||
|
@ -205,8 +264,10 @@ namespace MWWorld
|
||||||
osg::Vec3f pos(it->mNode->getPosition());
|
osg::Vec3f pos(it->mNode->getPosition());
|
||||||
osg::Vec3f newPos = pos + direction * duration * speed;
|
osg::Vec3f newPos = pos + direction * duration * speed;
|
||||||
|
|
||||||
if (it->mSound.get())
|
for (size_t soundIter = 0; soundIter != it->mSounds.size(); soundIter++)
|
||||||
it->mSound->setPosition(newPos);
|
{
|
||||||
|
it->mSounds.at(soundIter)->setPosition(newPos);
|
||||||
|
}
|
||||||
|
|
||||||
it->mNode->setPosition(newPos);
|
it->mNode->setPosition(newPos);
|
||||||
|
|
||||||
|
@ -246,7 +307,11 @@ namespace MWWorld
|
||||||
MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, result.mHitObject,
|
MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, result.mHitObject,
|
||||||
ESM::RT_Target, it->mSpellId, it->mSourceName);
|
ESM::RT_Target, it->mSpellId, it->mSourceName);
|
||||||
|
|
||||||
MWBase::Environment::get().getSoundManager()->stopSound(it->mSound);
|
for (size_t soundIter = 0; soundIter != it->mSounds.size(); soundIter++)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getSoundManager()->stopSound(it->mSounds.at(soundIter));
|
||||||
|
}
|
||||||
|
|
||||||
mParent->removeChild(it->mNode);
|
mParent->removeChild(it->mNode);
|
||||||
|
|
||||||
it = mMagicBolts.erase(it);
|
it = mMagicBolts.erase(it);
|
||||||
|
@ -286,7 +351,7 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
if (result.mHit)
|
if (result.mHit)
|
||||||
{
|
{
|
||||||
MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId);
|
MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mIdArrow);
|
||||||
|
|
||||||
// Try to get a Ptr to the bow that was used. It might no longer exist.
|
// Try to get a Ptr to the bow that was used. It might no longer exist.
|
||||||
MWWorld::Ptr bow = projectileRef.getPtr();
|
MWWorld::Ptr bow = projectileRef.getPtr();
|
||||||
|
@ -326,7 +391,10 @@ namespace MWWorld
|
||||||
for (std::vector<MagicBoltState>::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it)
|
for (std::vector<MagicBoltState>::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it)
|
||||||
{
|
{
|
||||||
mParent->removeChild(it->mNode);
|
mParent->removeChild(it->mNode);
|
||||||
MWBase::Environment::get().getSoundManager()->stopSound(it->mSound);
|
for (size_t soundIter = 0; soundIter != it->mSounds.size(); soundIter++)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getSoundManager()->stopSound(it->mSounds.at(soundIter));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mMagicBolts.clear();
|
mMagicBolts.clear();
|
||||||
}
|
}
|
||||||
|
@ -338,7 +406,7 @@ namespace MWWorld
|
||||||
writer.startRecord(ESM::REC_PROJ);
|
writer.startRecord(ESM::REC_PROJ);
|
||||||
|
|
||||||
ESM::ProjectileState state;
|
ESM::ProjectileState state;
|
||||||
state.mId = it->mId;
|
state.mId = it->mIdArrow;
|
||||||
state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition()));
|
state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition()));
|
||||||
state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude()));
|
state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude()));
|
||||||
state.mActorId = it->mActorId;
|
state.mActorId = it->mActorId;
|
||||||
|
@ -357,14 +425,14 @@ namespace MWWorld
|
||||||
writer.startRecord(ESM::REC_MPRJ);
|
writer.startRecord(ESM::REC_MPRJ);
|
||||||
|
|
||||||
ESM::MagicBoltState state;
|
ESM::MagicBoltState state;
|
||||||
state.mId = it->mId;
|
state.mId = it->mIdMagic.at(0);
|
||||||
state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition()));
|
state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition()));
|
||||||
state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude()));
|
state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude()));
|
||||||
state.mActorId = it->mActorId;
|
state.mActorId = it->mActorId;
|
||||||
|
|
||||||
state.mSpellId = it->mSpellId;
|
state.mSpellId = it->mSpellId;
|
||||||
state.mEffects = it->mEffects;
|
state.mEffects = it->mEffects;
|
||||||
state.mSound = it->mSoundId;
|
state.mSound = it->mSoundIds.at(0);
|
||||||
state.mSourceName = it->mSourceName;
|
state.mSourceName = it->mSourceName;
|
||||||
state.mSpeed = it->mSpeed;
|
state.mSpeed = it->mSpeed;
|
||||||
state.mStack = it->mStack;
|
state.mStack = it->mStack;
|
||||||
|
@ -386,7 +454,7 @@ namespace MWWorld
|
||||||
state.mActorId = esm.mActorId;
|
state.mActorId = esm.mActorId;
|
||||||
state.mBowId = esm.mBowId;
|
state.mBowId = esm.mBowId;
|
||||||
state.mVelocity = esm.mVelocity;
|
state.mVelocity = esm.mVelocity;
|
||||||
state.mId = esm.mId;
|
state.mIdArrow = esm.mId;
|
||||||
state.mAttackStrength = esm.mAttackStrength;
|
state.mAttackStrength = esm.mAttackStrength;
|
||||||
|
|
||||||
std::string model;
|
std::string model;
|
||||||
|
@ -413,17 +481,20 @@ namespace MWWorld
|
||||||
|
|
||||||
MagicBoltState state;
|
MagicBoltState state;
|
||||||
state.mSourceName = esm.mSourceName;
|
state.mSourceName = esm.mSourceName;
|
||||||
state.mId = esm.mId;
|
state.mIdMagic.push_back(esm.mId);
|
||||||
state.mSpellId = esm.mSpellId;
|
state.mSpellId = esm.mSpellId;
|
||||||
state.mActorId = esm.mActorId;
|
state.mActorId = esm.mActorId;
|
||||||
state.mSpeed = esm.mSpeed;
|
|
||||||
state.mStack = esm.mStack;
|
state.mStack = esm.mStack;
|
||||||
state.mEffects = esm.mEffects;
|
state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, esm.mEffects);
|
||||||
|
state.mSpeed = esm.mSpeed; // speed is derived from non-projectile effects as well as
|
||||||
|
// projectile effects, so we can't calculate it from the save
|
||||||
|
// file's effect list, which is already trimmed of non-projectile
|
||||||
|
// effects. We need to use the stored value.
|
||||||
|
|
||||||
std::string model;
|
std::string model;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId);
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0));
|
||||||
MWWorld::Ptr ptr = ref.getPtr();
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
model = ptr.getClass().getModel(ptr);
|
model = ptr.getClass().getModel(ptr);
|
||||||
}
|
}
|
||||||
|
@ -435,9 +506,12 @@ namespace MWWorld
|
||||||
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true);
|
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true);
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
state.mSound = sndMgr->playSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f,
|
|
||||||
MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
for (size_t soundIter = 0; soundIter != state.mSoundIds.size(); soundIter++)
|
||||||
state.mSoundId = esm.mSound;
|
{
|
||||||
|
state.mSounds.push_back(sndMgr->playSound3D(esm.mPosition, state.mSoundIds.at(soundIter), 1.0f, 1.0f,
|
||||||
|
MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop));
|
||||||
|
}
|
||||||
|
|
||||||
mMagicBolts.push_back(state);
|
mMagicBolts.push_back(state);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -49,8 +49,7 @@ namespace MWWorld
|
||||||
MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics);
|
MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics);
|
||||||
|
|
||||||
/// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used.
|
/// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used.
|
||||||
void launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId,
|
void launchMagicBolt (const std::string &spellId, bool stack, const ESM::EffectList& effects,
|
||||||
float speed, bool stack, const ESM::EffectList& effects,
|
|
||||||
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection);
|
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection);
|
||||||
|
|
||||||
void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
||||||
|
@ -84,8 +83,11 @@ namespace MWWorld
|
||||||
|
|
||||||
MWWorld::Ptr getCaster();
|
MWWorld::Ptr getCaster();
|
||||||
|
|
||||||
// MW-id of this projectile
|
// MW-ids of a magic projectile
|
||||||
std::string mId;
|
std::vector<std::string> mIdMagic;
|
||||||
|
|
||||||
|
// MW-id of an arrow projectile
|
||||||
|
std::string mIdArrow;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MagicBoltState : public State
|
struct MagicBoltState : public State
|
||||||
|
@ -101,8 +103,8 @@ namespace MWWorld
|
||||||
|
|
||||||
bool mStack;
|
bool mStack;
|
||||||
|
|
||||||
MWBase::SoundPtr mSound;
|
std::vector<MWBase::SoundPtr> mSounds;
|
||||||
std::string mSoundId;
|
std::vector<std::string> mSoundIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProjectileState : public State
|
struct ProjectileState : public State
|
||||||
|
|
|
@ -2705,11 +2705,10 @@ namespace MWWorld
|
||||||
mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength);
|
mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId,
|
void World::launchMagicBolt (const std::string &spellId, bool stack, const ESM::EffectList& effects,
|
||||||
float speed, bool stack, const ESM::EffectList& effects,
|
|
||||||
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection)
|
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection)
|
||||||
{
|
{
|
||||||
mProjectileManager->launchMagicBolt(model, sound, spellId, speed, stack, effects, caster, sourceName, fallbackDirection);
|
mProjectileManager->launchMagicBolt(spellId, stack, effects, caster, sourceName, fallbackDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& World::getContentFiles() const
|
const std::vector<std::string>& World::getContentFiles() const
|
||||||
|
@ -3163,8 +3162,9 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
const ESM::MagicEffect* effect = getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
const ESM::MagicEffect* effect = getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
||||||
|
|
||||||
if (effectIt->mArea <= 0)
|
if (effectIt->mArea <= 0 || effectIt->mRange != rangeType)
|
||||||
continue; // Not an area effect
|
continue; // Not an area effect or not right range type
|
||||||
|
|
||||||
|
|
||||||
// Spawn the explosion orb effect
|
// Spawn the explosion orb effect
|
||||||
const ESM::Static* areaStatic;
|
const ESM::Static* areaStatic;
|
||||||
|
|
|
@ -594,8 +594,7 @@ namespace MWWorld
|
||||||
*/
|
*/
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor);
|
virtual void castSpell (const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId,
|
virtual void launchMagicBolt (const std::string& spellId, bool stack, const ESM::EffectList& effects,
|
||||||
float speed, bool stack, const ESM::EffectList& effects,
|
|
||||||
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection);
|
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection);
|
||||||
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
||||||
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength);
|
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength);
|
||||||
|
|
Loading…
Reference in a new issue