forked from teamnwah/openmw-tes3coop
ESS-Importer: Convert magic projectiles (Closes #2320)
This commit is contained in:
parent
5ebb43a422
commit
f15de6d3ca
16 changed files with 238 additions and 63 deletions
|
@ -17,6 +17,7 @@ set(ESSIMPORTER_FILES
|
||||||
importscri.cpp
|
importscri.cpp
|
||||||
importscpt.cpp
|
importscpt.cpp
|
||||||
importproj.cpp
|
importproj.cpp
|
||||||
|
importsplm.cpp
|
||||||
importercontext.cpp
|
importercontext.cpp
|
||||||
converter.cpp
|
converter.cpp
|
||||||
convertacdt.cpp
|
convertacdt.cpp
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#include "converter.hpp"
|
#include "converter.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <osgDB/WriteFile>
|
#include <osgDB/WriteFile>
|
||||||
|
|
||||||
#include <components/esm/creaturestate.hpp>
|
#include <components/esm/creaturestate.hpp>
|
||||||
#include <components/esm/containerstate.hpp>
|
#include <components/esm/containerstate.hpp>
|
||||||
#include <components/esm/projectilestate.hpp>
|
|
||||||
|
|
||||||
#include "convertcrec.hpp"
|
#include "convertcrec.hpp"
|
||||||
#include "convertcntc.hpp"
|
#include "convertcntc.hpp"
|
||||||
|
@ -461,11 +461,7 @@ namespace ESSImport
|
||||||
if (!pnam.isMagic())
|
if (!pnam.isMagic())
|
||||||
{
|
{
|
||||||
ESM::ProjectileState out;
|
ESM::ProjectileState out;
|
||||||
out.mId = pnam.mArrowId.toString();
|
convertBaseState(out, pnam);
|
||||||
out.mPosition = pnam.mPosition;
|
|
||||||
out.mOrientation.mValues[0] = out.mOrientation.mValues[1] = out.mOrientation.mValues[2] = 0.0f;
|
|
||||||
out.mOrientation.mValues[3] = 1.0f;
|
|
||||||
out.mActorId = convertActorId(pnam.mActorId.toString(), *mContext);
|
|
||||||
|
|
||||||
out.mBowId = pnam.mBowId.toString();
|
out.mBowId = pnam.mBowId.toString();
|
||||||
out.mVelocity = pnam.mVelocity;
|
out.mVelocity = pnam.mVelocity;
|
||||||
|
@ -477,16 +473,49 @@ namespace ESSImport
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Implement magic projectile conversion.
|
ESM::MagicBoltState out;
|
||||||
|
convertBaseState(out, pnam);
|
||||||
|
|
||||||
/*esm.startRecord(ESM::REC_MPRJ);
|
auto it = std::find_if(mContext->mActiveSpells.begin(), mContext->mActiveSpells.end(),
|
||||||
out.save(esm);
|
[&pnam](const SPLM::ActiveSpell& spell) -> bool { return spell.mIndex == pnam.mSplmIndex; });
|
||||||
esm.endRecord(ESM::REC_MPRJ);*/
|
|
||||||
|
|
||||||
std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (not implemented)" << std::endl;
|
if (it == mContext->mActiveSpells.end())
|
||||||
|
{
|
||||||
|
std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (invalid spell link)" << std::endl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out.mSpellId = it->mSPDT.mId.toString();
|
||||||
|
out.mSpeed = pnam.mSpeed * 0.001f; // not sure where this factor comes from
|
||||||
|
|
||||||
|
esm.startRecord(ESM::REC_MPRJ);
|
||||||
|
out.save(esm);
|
||||||
|
esm.endRecord(ESM::REC_MPRJ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertPROJ::convertBaseState(ESM::BaseProjectileState& base, const PROJ::PNAM& pnam)
|
||||||
|
{
|
||||||
|
base.mId = pnam.mArrowId.toString();
|
||||||
|
base.mPosition = pnam.mPosition;
|
||||||
|
|
||||||
|
osg::Quat orient;
|
||||||
|
orient.makeRotate(osg::Vec3f(0,1,0), pnam.mVelocity);
|
||||||
|
base.mOrientation = orient;
|
||||||
|
|
||||||
|
base.mActorId = convertActorId(pnam.mActorId.toString(), *mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertSPLM::read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
mSPLM.load(esm);
|
||||||
|
mContext->mActiveSpells = mSPLM.mActiveSpells;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertSPLM::write(ESM::ESMWriter& esm)
|
||||||
|
{
|
||||||
|
std::cerr << "Warning: Skipped active spell conversion (not implemented)" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <components/esm/globalscript.hpp>
|
#include <components/esm/globalscript.hpp>
|
||||||
#include <components/esm/queststate.hpp>
|
#include <components/esm/queststate.hpp>
|
||||||
#include <components/esm/stolenitems.hpp>
|
#include <components/esm/stolenitems.hpp>
|
||||||
|
#include <components/esm/projectilestate.hpp>
|
||||||
|
|
||||||
#include "importcrec.hpp"
|
#include "importcrec.hpp"
|
||||||
#include "importcntc.hpp"
|
#include "importcntc.hpp"
|
||||||
|
@ -36,6 +37,7 @@
|
||||||
#include "importjour.hpp"
|
#include "importjour.hpp"
|
||||||
#include "importscpt.hpp"
|
#include "importscpt.hpp"
|
||||||
#include "importproj.h"
|
#include "importproj.h"
|
||||||
|
#include "importsplm.h"
|
||||||
|
|
||||||
#include "convertacdt.hpp"
|
#include "convertacdt.hpp"
|
||||||
#include "convertnpcc.hpp"
|
#include "convertnpcc.hpp"
|
||||||
|
@ -602,9 +604,19 @@ public:
|
||||||
virtual void read(ESM::ESMReader& esm) override;
|
virtual void read(ESM::ESMReader& esm) override;
|
||||||
virtual void write(ESM::ESMWriter& esm) override;
|
virtual void write(ESM::ESMWriter& esm) override;
|
||||||
private:
|
private:
|
||||||
|
void convertBaseState(ESM::BaseProjectileState& base, const PROJ::PNAM& pnam);
|
||||||
PROJ mProj;
|
PROJ mProj;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ConvertSPLM : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader& esm) override;
|
||||||
|
virtual void write(ESM::ESMWriter& esm) override;
|
||||||
|
private:
|
||||||
|
SPLM mSPLM;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -271,6 +271,7 @@ namespace ESSImport
|
||||||
const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value;
|
const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value;
|
||||||
const unsigned int recGAME = ESM::FourCC<'G','A','M','E'>::value;
|
const unsigned int recGAME = ESM::FourCC<'G','A','M','E'>::value;
|
||||||
const unsigned int recJOUR = ESM::FourCC<'J','O','U','R'>::value;
|
const unsigned int recJOUR = ESM::FourCC<'J','O','U','R'>::value;
|
||||||
|
const unsigned int recSPLM = ESM::FourCC<'S','P','L','M'>::value;
|
||||||
|
|
||||||
std::map<unsigned int, std::shared_ptr<Converter> > converters;
|
std::map<unsigned int, std::shared_ptr<Converter> > converters;
|
||||||
converters[ESM::REC_GLOB] = std::shared_ptr<Converter>(new ConvertGlobal());
|
converters[ESM::REC_GLOB] = std::shared_ptr<Converter>(new ConvertGlobal());
|
||||||
|
@ -304,12 +305,12 @@ namespace ESSImport
|
||||||
converters[recJOUR ] = std::shared_ptr<Converter>(new ConvertJOUR());
|
converters[recJOUR ] = std::shared_ptr<Converter>(new ConvertJOUR());
|
||||||
converters[ESM::REC_SCPT] = std::shared_ptr<Converter>(new ConvertSCPT());
|
converters[ESM::REC_SCPT] = std::shared_ptr<Converter>(new ConvertSCPT());
|
||||||
converters[ESM::REC_PROJ] = std::shared_ptr<Converter>(new ConvertPROJ());
|
converters[ESM::REC_PROJ] = std::shared_ptr<Converter>(new ConvertPROJ());
|
||||||
|
converters[recSPLM] = std::shared_ptr<Converter>(new ConvertSPLM());
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - REGN (weather in certain regions?)
|
// - REGN (weather in certain regions?)
|
||||||
// - VFXM
|
// - VFXM
|
||||||
// - SPLM (active spell effects)
|
// - SPLM (active spell effects)
|
||||||
// - PROJ (magic projectiles in air)
|
|
||||||
|
|
||||||
std::set<unsigned int> unknownRecords;
|
std::set<unsigned int> unknownRecords;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include "importcrec.hpp"
|
#include "importcrec.hpp"
|
||||||
#include "importcntc.hpp"
|
#include "importcntc.hpp"
|
||||||
#include "importplayer.hpp"
|
#include "importplayer.hpp"
|
||||||
|
#include "importsplm.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ namespace ESSImport
|
||||||
std::map<std::string, ESM::Creature> mCreatures;
|
std::map<std::string, ESM::Creature> mCreatures;
|
||||||
std::map<std::string, ESM::NPC> mNpcs;
|
std::map<std::string, ESM::NPC> mNpcs;
|
||||||
|
|
||||||
|
std::vector<SPLM::ActiveSpell> mActiveSpells;
|
||||||
|
|
||||||
Context()
|
Context()
|
||||||
: mDay(0)
|
: mDay(0)
|
||||||
, mMonth(0)
|
, mMonth(0)
|
||||||
|
|
43
apps/essimporter/importsplm.cpp
Normal file
43
apps/essimporter/importsplm.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include "importsplm.h"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void SPLM::load(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
while (esm.isNextSub("NAME"))
|
||||||
|
{
|
||||||
|
ActiveSpell spell;
|
||||||
|
esm.getHT(spell.mIndex);
|
||||||
|
esm.getHNT(spell.mSPDT, "SPDT");
|
||||||
|
spell.mTarget = esm.getHNOString("TNAM");
|
||||||
|
|
||||||
|
while (esm.isNextSub("NPDT"))
|
||||||
|
{
|
||||||
|
ActiveEffect effect;
|
||||||
|
esm.getHT(effect.mNPDT);
|
||||||
|
|
||||||
|
// Effect-specific subrecords can follow:
|
||||||
|
// - INAM for disintegration and bound effects
|
||||||
|
// - CNAM for summoning and command effects
|
||||||
|
// - VNAM for vampirism
|
||||||
|
// NOTE: There can be multiple INAMs per effect.
|
||||||
|
// TODO: Needs more research.
|
||||||
|
|
||||||
|
esm.skipHSubUntil("NAM0"); // sentinel
|
||||||
|
esm.getSubName();
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
spell.mActiveEffects.push_back(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char xnam; // sentinel
|
||||||
|
esm.getHNT(xnam, "XNAM");
|
||||||
|
|
||||||
|
mActiveSpells.push_back(spell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
81
apps/essimporter/importsplm.h
Normal file
81
apps/essimporter/importsplm.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTSPLM_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTSPLM_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <components/esm/esmcommon.hpp>
|
||||||
|
#include <components/esm/util.hpp>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
struct SPLM
|
||||||
|
{
|
||||||
|
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
struct SPDT // 160 bytes
|
||||||
|
{
|
||||||
|
int mType; // 1 = spell, 2 = enchantment, 3 = potion
|
||||||
|
ESM::NAME32 mId; // base ID of a spell/enchantment/potion
|
||||||
|
unsigned char mUnknown[4*4];
|
||||||
|
ESM::NAME32 mCasterId;
|
||||||
|
ESM::NAME32 mSourceId; // empty for spells
|
||||||
|
unsigned char mUnknown2[4*11];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NPDT // 56 bytes
|
||||||
|
{
|
||||||
|
ESM::NAME32 mAffectedActorId;
|
||||||
|
unsigned char mUnknown[4*2];
|
||||||
|
int mMagnitude;
|
||||||
|
float mSecondsActive;
|
||||||
|
unsigned char mUnknown2[4*2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct INAM // 40 bytes
|
||||||
|
{
|
||||||
|
int mUnknown;
|
||||||
|
unsigned char mUnknown2;
|
||||||
|
ESM::FIXED_STRING<35> mItemId; // disintegrated item / bound item / item to re-equip after expiration
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CNAM // 36 bytes
|
||||||
|
{
|
||||||
|
int mUnknown; // seems to always be 0
|
||||||
|
ESM::NAME32 mSummonedOrCommandedActor[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VNAM // 4 bytes
|
||||||
|
{
|
||||||
|
int mUnknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
struct ActiveEffect
|
||||||
|
{
|
||||||
|
NPDT mNPDT;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ActiveSpell
|
||||||
|
{
|
||||||
|
int mIndex;
|
||||||
|
SPDT mSPDT;
|
||||||
|
std::string mTarget;
|
||||||
|
std::vector<ActiveEffect> mActiveEffects;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<ActiveSpell> mActiveSpells;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -487,8 +487,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& spellId, bool stack, const ESM::EffectList& effects,
|
virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, 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;
|
||||||
|
|
||||||
|
|
|
@ -329,7 +329,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CastSpell::launchMagicBolt (const ESM::EffectList& effects)
|
void CastSpell::launchMagicBolt ()
|
||||||
{
|
{
|
||||||
osg::Vec3f fallbackDirection (0,1,0);
|
osg::Vec3f fallbackDirection (0,1,0);
|
||||||
|
|
||||||
|
@ -340,8 +340,7 @@ namespace MWMechanics
|
||||||
osg::Vec3f(mTarget.getRefData().getPosition().asVec3())-
|
osg::Vec3f(mTarget.getRefData().getPosition().asVec3())-
|
||||||
osg::Vec3f(mCaster.getRefData().getPosition().asVec3());
|
osg::Vec3f(mCaster.getRefData().getPosition().asVec3());
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, effects,
|
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, mCaster, fallbackDirection);
|
||||||
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,
|
||||||
|
@ -823,7 +822,7 @@ namespace MWMechanics
|
||||||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
||||||
|
|
||||||
if (launchProjectile)
|
if (launchProjectile)
|
||||||
launchMagicBolt(enchantment->mEffects);
|
launchMagicBolt();
|
||||||
else if (isProjectile || !mTarget.isEmpty())
|
else if (isProjectile || !mTarget.isEmpty())
|
||||||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Target);
|
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Target);
|
||||||
|
|
||||||
|
@ -915,7 +914,7 @@ namespace MWMechanics
|
||||||
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);
|
launchMagicBolt();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ namespace MWMechanics
|
||||||
void playSpellCastingEffects(const std::string &spellid);
|
void playSpellCastingEffects(const std::string &spellid);
|
||||||
|
|
||||||
/// Launch a bolt with the given effects.
|
/// Launch a bolt with the given effects.
|
||||||
void launchMagicBolt (const ESM::EffectList& effects);
|
void launchMagicBolt ();
|
||||||
|
|
||||||
/// @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.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "projectilemanager.hpp"
|
#include "projectilemanager.hpp"
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <osg/PositionAttitudeTransform>
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
|
||||||
|
@ -41,13 +42,29 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
ESM::EffectList getMagicBoltData(std::vector<std::string>& projectileIDs, std::vector<std::string>& sounds, float& speed, std::string& texture, const ESM::EffectList& effects)
|
ESM::EffectList getMagicBoltData(std::vector<std::string>& projectileIDs, std::vector<std::string>& sounds, float& speed, std::string& texture, std::string& sourceName, const std::string& id)
|
||||||
{
|
{
|
||||||
|
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
const ESM::EffectList* effects;
|
||||||
|
if (const ESM::Spell* spell = esmStore.get<ESM::Spell>().search(id)) // check if it's a spell
|
||||||
|
{
|
||||||
|
sourceName = spell->mName;
|
||||||
|
effects = &spell->mEffects;
|
||||||
|
}
|
||||||
|
else // check if it's an enchanted item
|
||||||
|
{
|
||||||
|
MWWorld::ManualRef ref(esmStore, id);
|
||||||
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
const ESM::Enchantment* ench = esmStore.get<ESM::Enchantment>().find(ptr.getClass().getEnchantment(ptr));
|
||||||
|
sourceName = ptr.getClass().getName(ptr);
|
||||||
|
effects = &ench->mEffects;
|
||||||
|
}
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
speed = 0.0f;
|
speed = 0.0f;
|
||||||
ESM::EffectList projectileEffects;
|
ESM::EffectList projectileEffects;
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects->mList.begin());
|
||||||
iter!=effects.mList.end(); ++iter)
|
iter!=effects->mList.end(); ++iter)
|
||||||
{
|
{
|
||||||
const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
||||||
iter->mEffectID);
|
iter->mEffectID);
|
||||||
|
@ -82,14 +99,14 @@ namespace
|
||||||
if (projectileEffects.mList.size() == 1)
|
if (projectileEffects.mList.size() == 1)
|
||||||
{
|
{
|
||||||
const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
||||||
effects.mList.begin()->mEffectID);
|
effects->mList.begin()->mEffectID);
|
||||||
texture = magicEffect->mParticle;
|
texture = magicEffect->mParticle;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectileEffects.mList.size() > 1) // insert a VFX_Multiple projectile if there are multiple projectile effects
|
if (projectileEffects.mList.size() > 1) // insert a VFX_Multiple projectile if there are multiple projectile effects
|
||||||
{
|
{
|
||||||
std::ostringstream ID;
|
std::ostringstream ID;
|
||||||
ID << "VFX_Multiple" << effects.mList.size();
|
ID << "VFX_Multiple" << effects->mList.size();
|
||||||
std::vector<std::string>::iterator it;
|
std::vector<std::string>::iterator it;
|
||||||
it = projectileIDs.begin();
|
it = projectileIDs.begin();
|
||||||
it = projectileIDs.insert(it, ID.str());
|
it = projectileIDs.insert(it, ID.str());
|
||||||
|
@ -235,8 +252,7 @@ namespace MWWorld
|
||||||
state.mEffectAnimationTime->addTime(duration);
|
state.mEffectAnimationTime->addTime(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectileManager::launchMagicBolt(const std::string &spellId, bool stack, const ESM::EffectList &effects, const Ptr &caster,
|
void ProjectileManager::launchMagicBolt(const std::string &spellId, const Ptr &caster, const osg::Vec3f& fallbackDirection)
|
||||||
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())
|
||||||
|
@ -257,18 +273,16 @@ namespace MWWorld
|
||||||
orient.makeRotate(osg::Vec3f(0,1,0), osg::Vec3f(fallbackDirection));
|
orient.makeRotate(osg::Vec3f(0,1,0), osg::Vec3f(fallbackDirection));
|
||||||
|
|
||||||
MagicBoltState state;
|
MagicBoltState state;
|
||||||
state.mSourceName = sourceName;
|
|
||||||
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.mStack = stack;
|
|
||||||
|
|
||||||
std::string texture = "";
|
std::string texture = "";
|
||||||
|
|
||||||
state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, effects);
|
state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, state.mSourceName, state.mSpellId);
|
||||||
|
|
||||||
// Non-projectile should have been removed by getMagicBoltData
|
// Non-projectile should have been removed by getMagicBoltData
|
||||||
if (state.mEffects.mList.empty())
|
if (state.mEffects.mList.empty())
|
||||||
|
@ -277,7 +291,7 @@ namespace MWWorld
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0));
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0));
|
||||||
MWWorld::Ptr ptr = ref.getPtr();
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
|
||||||
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(effects);
|
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects);
|
||||||
createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, lightDiffuseColor, texture);
|
createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, lightDiffuseColor, texture);
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
@ -364,7 +378,7 @@ namespace MWWorld
|
||||||
cast.mHitPosition = pos;
|
cast.mHitPosition = pos;
|
||||||
cast.mId = it->mSpellId;
|
cast.mId = it->mSpellId;
|
||||||
cast.mSourceName = it->mSourceName;
|
cast.mSourceName = it->mSourceName;
|
||||||
cast.mStack = it->mStack;
|
cast.mStack = false;
|
||||||
cast.inflict(result.mHitObject, caster, it->mEffects, ESM::RT_Target, false, true);
|
cast.inflict(result.mHitObject, caster, it->mEffects, ESM::RT_Target, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -504,11 +518,7 @@ namespace MWWorld
|
||||||
state.mActorId = it->mActorId;
|
state.mActorId = it->mActorId;
|
||||||
|
|
||||||
state.mSpellId = it->mSpellId;
|
state.mSpellId = it->mSpellId;
|
||||||
state.mEffects = it->mEffects;
|
|
||||||
state.mSound = it->mSoundIds.at(0);
|
|
||||||
state.mSourceName = it->mSourceName;
|
|
||||||
state.mSpeed = it->mSpeed;
|
state.mSpeed = it->mSpeed;
|
||||||
state.mStack = it->mStack;
|
|
||||||
|
|
||||||
state.save(writer);
|
state.save(writer);
|
||||||
|
|
||||||
|
@ -553,13 +563,21 @@ namespace MWWorld
|
||||||
esm.load(reader);
|
esm.load(reader);
|
||||||
|
|
||||||
MagicBoltState state;
|
MagicBoltState state;
|
||||||
state.mSourceName = esm.mSourceName;
|
|
||||||
state.mIdMagic.push_back(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.mStack = esm.mStack;
|
|
||||||
std::string texture = "";
|
std::string texture = "";
|
||||||
state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, esm.mEffects);
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, state.mSourceName, state.mSpellId);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
std::cerr << "Warning: Failed to recreate magic projectile from saved data (id \"" << state.mSpellId << "\" no longer exists?)" << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
state.mSpeed = esm.mSpeed; // speed is derived from non-projectile effects as well as
|
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
|
// projectile effects, so we can't calculate it from the save
|
||||||
// file's effect list, which is already trimmed of non-projectile
|
// file's effect list, which is already trimmed of non-projectile
|
||||||
|
@ -577,7 +595,7 @@ namespace MWWorld
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(esm.mEffects);
|
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects);
|
||||||
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture);
|
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture);
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
|
|
@ -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 &spellId, bool stack, const ESM::EffectList& effects,
|
void launchMagicBolt (const std::string &spellId, const MWWorld::Ptr& caster, 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,
|
||||||
const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength);
|
const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength);
|
||||||
|
@ -101,8 +100,6 @@ namespace MWWorld
|
||||||
|
|
||||||
float mSpeed;
|
float mSpeed;
|
||||||
|
|
||||||
bool mStack;
|
|
||||||
|
|
||||||
std::vector<MWBase::Sound*> mSounds;
|
std::vector<MWBase::Sound*> mSounds;
|
||||||
std::vector<std::string> mSoundIds;
|
std::vector<std::string> mSoundIds;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2816,10 +2816,9 @@ 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 &spellId, bool stack, const ESM::EffectList& effects,
|
void World::launchMagicBolt (const std::string &spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection)
|
||||||
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection)
|
|
||||||
{
|
{
|
||||||
mProjectileManager->launchMagicBolt(spellId, stack, effects, caster, sourceName, fallbackDirection);
|
mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& World::getContentFiles() const
|
const std::vector<std::string>& World::getContentFiles() const
|
||||||
|
|
|
@ -601,8 +601,7 @@ namespace MWWorld
|
||||||
*/
|
*/
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor);
|
virtual void castSpell (const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
virtual void launchMagicBolt (const std::string& spellId, bool stack, const ESM::EffectList& effects,
|
virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override;
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,7 @@ namespace ESM
|
||||||
BaseProjectileState::save(esm);
|
BaseProjectileState::save(esm);
|
||||||
|
|
||||||
esm.writeHNString ("SPEL", mSpellId);
|
esm.writeHNString ("SPEL", mSpellId);
|
||||||
esm.writeHNString ("SRCN", mSourceName);
|
|
||||||
mEffects.save(esm);
|
|
||||||
esm.writeHNT ("SPED", mSpeed);
|
esm.writeHNT ("SPED", mSpeed);
|
||||||
esm.writeHNT ("STCK", mStack);
|
|
||||||
esm.writeHNString ("SOUN", mSound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagicBoltState::load(ESMReader &esm)
|
void MagicBoltState::load(ESMReader &esm)
|
||||||
|
@ -39,11 +35,14 @@ namespace ESM
|
||||||
BaseProjectileState::load(esm);
|
BaseProjectileState::load(esm);
|
||||||
|
|
||||||
mSpellId = esm.getHNString("SPEL");
|
mSpellId = esm.getHNString("SPEL");
|
||||||
mSourceName = esm.getHNString ("SRCN");
|
if (esm.isNextSub("SRCN")) // for backwards compatibility
|
||||||
mEffects.load(esm);
|
esm.skipHSub();
|
||||||
|
ESM::EffectList().load(esm); // for backwards compatibility
|
||||||
esm.getHNT (mSpeed, "SPED");
|
esm.getHNT (mSpeed, "SPED");
|
||||||
esm.getHNT (mStack, "STCK");
|
if (esm.isNextSub("STCK")) // for backwards compatibility
|
||||||
mSound = esm.getHNString ("SOUN");
|
esm.skipHSub();
|
||||||
|
if (esm.isNextSub("SOUN")) // for backwards compatibility
|
||||||
|
esm.skipHSub();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectileState::save(ESMWriter &esm) const
|
void ProjectileState::save(ESMWriter &esm) const
|
||||||
|
|
|
@ -31,11 +31,7 @@ namespace ESM
|
||||||
struct MagicBoltState : public BaseProjectileState
|
struct MagicBoltState : public BaseProjectileState
|
||||||
{
|
{
|
||||||
std::string mSpellId;
|
std::string mSpellId;
|
||||||
std::string mSourceName;
|
|
||||||
ESM::EffectList mEffects;
|
|
||||||
float mSpeed;
|
float mSpeed;
|
||||||
bool mStack;
|
|
||||||
std::string mSound;
|
|
||||||
|
|
||||||
void load (ESMReader &esm);
|
void load (ESMReader &esm);
|
||||||
void save (ESMWriter &esm) const;
|
void save (ESMWriter &esm) const;
|
||||||
|
|
Loading…
Reference in a new issue