1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-22 21:40:42 +00:00

Fix crash for on target spells cast by non-actors (Fixes #1529)

This commit is contained in:
scrawl 2014-06-18 01:41:07 +02:00
parent fe1e6a2719
commit e95483c40f
7 changed files with 57 additions and 21 deletions

View File

@ -470,7 +470,7 @@ namespace MWBase
virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId,
float speed, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) = 0;
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0;

View File

@ -340,7 +340,7 @@ namespace MWMechanics
}
// Try reflecting
if (!reflected && magnitudeMult > 0 && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable))
if (!reflected && magnitudeMult > 0 && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable))
{
int reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).mMagnitude;
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
@ -465,14 +465,14 @@ namespace MWMechanics
if (!appliedLastingEffects.empty())
{
int casterActorId = -1;
if (caster.getClass().isActor())
if (!caster.isEmpty() && caster.getClass().isActor())
casterActorId = caster.getClass().getCreatureStats(caster).getActorId();
target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects,
mSourceName, casterActorId);
}
// Notify the target actor they've been hit
if (anyHarmfulEffect && target.getClass().isActor() && target != caster && caster.getClass().isActor())
if (anyHarmfulEffect && target.getClass().isActor() && target != caster && !caster.isEmpty() && caster.getClass().isActor())
target.getClass().onHit(target, 0.f, true, MWWorld::Ptr(), caster, true);
}
@ -657,7 +657,9 @@ namespace MWMechanics
getProjectileInfo(enchantment->mEffects, projectileModel, sound, speed);
if (!projectileModel.empty())
MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed,
false, enchantment->mEffects, mCaster, mSourceName);
false, enchantment->mEffects, mCaster, mSourceName,
// Not needed, enchantments can only be cast by actors
Ogre::Vector3(1,0,0));
return true;
}
@ -742,8 +744,18 @@ namespace MWMechanics
float speed = 0;
getProjectileInfo(spell->mEffects, projectileModel, sound, speed);
if (!projectileModel.empty())
{
Ogre::Vector3 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 =
Ogre::Vector3(mTarget.getRefData().getPosition().pos)-
Ogre::Vector3(mCaster.getRefData().getPosition().pos);
MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed,
false, spell->mEffects, mCaster, mSourceName);
false, spell->mEffects, mCaster, mSourceName, fallbackDirection);
}
return true;
}

View File

@ -47,8 +47,8 @@ namespace MWMechanics
class CastSpell
{
private:
MWWorld::Ptr mCaster;
MWWorld::Ptr mTarget;
MWWorld::Ptr mCaster; // May be empty
MWWorld::Ptr mTarget; // May be empty
public:
bool mStack;
std::string mId; // ID of spell, potion, item etc
@ -59,8 +59,13 @@ namespace MWMechanics
CastSpell(const MWWorld::Ptr& caster, const MWWorld::Ptr& target);
bool cast (const ESM::Spell* spell);
/// @note mCaster must be an actor
bool cast (const MWWorld::Ptr& item);
/// @note mCaster must be an NPC
bool cast (const ESM::Ingredient* ingredient);
bool cast (const ESM::Potion* potion);
/// @note Auto detects if spell, ingredient or potion

View File

@ -57,22 +57,32 @@ namespace MWWorld
void ProjectileManager::launchMagicBolt(const std::string &model, const std::string &sound,
const std::string &spellId, float speed, bool stack,
const ESM::EffectList &effects, const Ptr &actor, const std::string &sourceName)
const ESM::EffectList &effects, const Ptr &caster, const std::string &sourceName,
const Ogre::Vector3& fallbackDirection)
{
// Spawn at 0.75 * ActorHeight
float height = mPhysEngine.getCharacter(actor.getRefData().getHandle())->getHalfExtents().z * 2 * 0.75;
float height = 0;
if (OEngine::Physic::PhysicActor* actor = mPhysEngine.getCharacter(caster.getRefData().getHandle()))
height = actor->getHalfExtents().z * 2 * 0.75; // Spawn at 0.75 * ActorHeight
Ogre::Vector3 pos(actor.getRefData().getPosition().pos);
Ogre::Vector3 pos(caster.getRefData().getPosition().pos);
pos.z += height;
Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
Ogre::Quaternion orient;
if (caster.getClass().isActor())
orient = Ogre::Quaternion(Ogre::Radian(caster.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
Ogre::Quaternion(Ogre::Radian(caster.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
else
orient = Ogre::Vector3::UNIT_Y.getRotationTo(fallbackDirection);
MagicBoltState state;
state.mSourceName = sourceName;
state.mId = model;
state.mSpellId = spellId;
state.mActorId = actor.getClass().getCreatureStats(actor).getActorId();
state.mCaster = caster;
if (caster.getClass().isActor())
state.mActorId = caster.getClass().getCreatureStats(caster).getActorId();
else
state.mActorId = -1;
state.mSpeed = speed;
state.mStack = stack;
state.mSoundId = sound;
@ -152,7 +162,9 @@ namespace MWWorld
{
MWWorld::Ptr obstacle = MWBase::Environment::get().getWorld()->searchPtrViaHandle(cIt->second);
MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId);
MWWorld::Ptr caster = it->mCaster;
if (caster.isEmpty())
caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId);
if (!obstacle.isEmpty() && obstacle == caster)
continue;

View File

@ -39,9 +39,10 @@ namespace MWWorld
ProjectileManager (Ogre::SceneManager* sceneMgr,
OEngine::Physic::PhysicEngine& engine);
/// 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,
float speed, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName);
const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection);
void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
const Ogre::Vector3& pos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed);
@ -64,9 +65,15 @@ namespace MWWorld
NifOgre::ObjectScenePtr mObject;
Ogre::SceneNode* mNode;
// Actor who shot this projectile
int mActorId;
// actorId doesn't work for non-actors, so we also keep track of the Ptr.
// For non-actors, the caster ptr is mainly needed to prevent the projectile
// from colliding with its caster.
// TODO: this will break when the game is saved and reloaded, since there is currently
// no way to write identifiers for non-actors to a savegame.
MWWorld::Ptr mCaster;
// MW-id of this projectile
std::string mId;
};

View File

@ -2329,9 +2329,9 @@ namespace MWWorld
void World::launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId,
float speed, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName)
const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection)
{
mProjectileManager->launchMagicBolt(model, sound, spellId, speed, stack, effects, actor, sourceName);
mProjectileManager->launchMagicBolt(model, sound, spellId, speed, stack, effects, caster, sourceName, fallbackDirection);
}
const std::vector<std::string>& World::getContentFiles() const

View File

@ -546,7 +546,7 @@ namespace MWWorld
virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId,
float speed, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName);
const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection);
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed);