mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-21 16:09:41 +00:00
First try at handling target magic
This commit is contained in:
parent
e7ad503e30
commit
076cc9230b
5 changed files with 111 additions and 17 deletions
|
@ -417,7 +417,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual void launchProjectile (const std::string& id, const ESM::EffectList& effects,
|
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||||
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
|
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -329,7 +329,7 @@ namespace MWMechanics
|
||||||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->launchProjectile(mId, enchantment->mEffects, mCaster, mSourceName);
|
MWBase::Environment::get().getWorld()->launchProjectile(mId, false, enchantment->mEffects, mCaster, mSourceName);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -434,7 +434,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->launchProjectile(mId, spell->mEffects, mCaster, mSourceName);
|
MWBase::Environment::get().getWorld()->launchProjectile(mId, false, spell->mEffects, mCaster, mSourceName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,7 @@ namespace MWMechanics
|
||||||
private:
|
private:
|
||||||
MWWorld::Ptr mCaster;
|
MWWorld::Ptr mCaster;
|
||||||
MWWorld::Ptr mTarget;
|
MWWorld::Ptr mTarget;
|
||||||
|
public:
|
||||||
bool mStack;
|
bool mStack;
|
||||||
std::string mId; // ID of spell, potion, item etc
|
std::string mId; // ID of spell, potion, item etc
|
||||||
std::string mSourceName; // Display name for spell, potion, etc
|
std::string mSourceName; // Display name for spell, potion, etc
|
||||||
|
|
|
@ -804,6 +804,8 @@ namespace MWWorld
|
||||||
return MWWorld::Ptr ();
|
return MWWorld::Ptr ();
|
||||||
|
|
||||||
MWWorld::Ptr object = searchPtrViaHandle (result.second);
|
MWWorld::Ptr object = searchPtrViaHandle (result.second);
|
||||||
|
if (object.isEmpty())
|
||||||
|
return object;
|
||||||
float ActivationDistance;
|
float ActivationDistance;
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||||
|
@ -895,15 +897,16 @@ namespace MWWorld
|
||||||
copyObjectToCell(ptr, newCell, pos);
|
copyObjectToCell(ptr, newCell, pos);
|
||||||
else if (!mWorldScene->isCellActive(newCell))
|
else if (!mWorldScene->isCellActive(newCell))
|
||||||
{
|
{
|
||||||
MWWorld::Class::get(ptr)
|
|
||||||
.copyToCell(ptr, newCell)
|
|
||||||
.getRefData()
|
|
||||||
.setBaseNode(0);
|
|
||||||
|
|
||||||
mWorldScene->removeObjectFromScene(ptr);
|
mWorldScene->removeObjectFromScene(ptr);
|
||||||
mLocalScripts.remove(ptr);
|
mLocalScripts.remove(ptr);
|
||||||
removeContainerScripts (ptr);
|
removeContainerScripts (ptr);
|
||||||
haveToMove = false;
|
haveToMove = false;
|
||||||
|
|
||||||
|
MWWorld::Ptr newPtr = MWWorld::Class::get(ptr)
|
||||||
|
.copyToCell(ptr, newCell);
|
||||||
|
newPtr.getRefData().setBaseNode(0);
|
||||||
|
|
||||||
|
objectLeftActiveCell(ptr, newPtr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1292,7 +1295,8 @@ namespace MWWorld
|
||||||
|
|
||||||
mWorldScene->update (duration, paused);
|
mWorldScene->update (duration, paused);
|
||||||
|
|
||||||
doPhysics (duration);
|
if (!paused)
|
||||||
|
doPhysics (duration);
|
||||||
|
|
||||||
performUpdateSceneQueries ();
|
performUpdateSceneQueries ();
|
||||||
|
|
||||||
|
@ -2066,11 +2070,12 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::launchProjectile (const std::string& id, const ESM::EffectList& effects,
|
void World::launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||||
const MWWorld::Ptr& actor, const std::string& sourceName)
|
const MWWorld::Ptr& actor, const std::string& sourceName)
|
||||||
{
|
{
|
||||||
std::string projectileModel;
|
std::string projectileModel;
|
||||||
std::string sound;
|
std::string sound;
|
||||||
|
float speed = 0;
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -2091,18 +2096,20 @@ namespace MWWorld
|
||||||
else
|
else
|
||||||
sound = schools[magicEffect->mData.mSchool] + " bolt";
|
sound = schools[magicEffect->mData.mSchool] + " bolt";
|
||||||
|
|
||||||
|
speed = magicEffect->mData.mSpeed;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (projectileModel.empty())
|
if (projectileModel.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
return;
|
// Spawn at 0.75 * ActorHeight
|
||||||
|
float height = mPhysEngine->getCharacter(actor.getRefData().getHandle())->getHalfExtents().z * 2 * 0.75;
|
||||||
|
|
||||||
MWWorld::ManualRef ref(getStore(), projectileModel);
|
MWWorld::ManualRef ref(getStore(), projectileModel);
|
||||||
ESM::Position pos;
|
ESM::Position pos;
|
||||||
pos.pos[0] = actor.getRefData().getPosition().pos[0];
|
pos.pos[0] = actor.getRefData().getPosition().pos[0];
|
||||||
pos.pos[1] = actor.getRefData().getPosition().pos[1];
|
pos.pos[1] = actor.getRefData().getPosition().pos[1];
|
||||||
pos.pos[2] = actor.getRefData().getPosition().pos[2];
|
pos.pos[2] = actor.getRefData().getPosition().pos[2] + height;
|
||||||
pos.rot[0] = actor.getRefData().getPosition().rot[0];
|
pos.rot[0] = actor.getRefData().getPosition().rot[0];
|
||||||
pos.rot[1] = actor.getRefData().getPosition().rot[1];
|
pos.rot[1] = actor.getRefData().getPosition().rot[1];
|
||||||
pos.rot[2] = actor.getRefData().getPosition().rot[2];
|
pos.rot[2] = actor.getRefData().getPosition().rot[2];
|
||||||
|
@ -2113,6 +2120,9 @@ namespace MWWorld
|
||||||
state.mSourceName = sourceName;
|
state.mSourceName = sourceName;
|
||||||
state.mId = id;
|
state.mId = id;
|
||||||
state.mActorHandle = actor.getRefData().getHandle();
|
state.mActorHandle = actor.getRefData().getHandle();
|
||||||
|
state.mSpeed = speed;
|
||||||
|
state.mEffects = effects;
|
||||||
|
state.mStack = stack;
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
sndMgr->playSound3D(ptr, sound, 1.0f, 1.0f);
|
sndMgr->playSound3D(ptr, sound, 1.0f, 1.0f);
|
||||||
|
@ -2122,6 +2132,7 @@ namespace MWWorld
|
||||||
|
|
||||||
void World::moveProjectiles(float duration)
|
void World::moveProjectiles(float duration)
|
||||||
{
|
{
|
||||||
|
std::map<std::string, ProjectileState> moved;
|
||||||
for (std::map<MWWorld::Ptr, ProjectileState>::iterator it = mProjectiles.begin(); it != mProjectiles.end();)
|
for (std::map<MWWorld::Ptr, ProjectileState>::iterator it = mProjectiles.begin(); it != mProjectiles.end();)
|
||||||
{
|
{
|
||||||
if (!mWorldScene->isCellActive(*it->first.getCell()))
|
if (!mWorldScene->isCellActive(*it->first.getCell()))
|
||||||
|
@ -2129,9 +2140,83 @@ namespace MWWorld
|
||||||
mProjectiles.erase(it++);
|
mProjectiles.erase(it++);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// TODO: Move
|
|
||||||
//moveObject(it->first, newPos.x, newPos.y, newPos.z);
|
MWWorld::Ptr ptr = it->first;
|
||||||
++it;
|
|
||||||
|
Ogre::Vector3 rot(ptr.getRefData().getPosition().rot);
|
||||||
|
|
||||||
|
// TODO: Why -rot.z, but not -rot.x?
|
||||||
|
Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z);
|
||||||
|
orient = orient * Ogre::Quaternion(Ogre::Radian(rot.x), Ogre::Vector3::UNIT_X);
|
||||||
|
|
||||||
|
// This is just a guess, probably wrong
|
||||||
|
static float fProjectileMinSpeed = getStore().get<ESM::GameSetting>().find("fProjectileMinSpeed")->getFloat();
|
||||||
|
static float fProjectileMaxSpeed = getStore().get<ESM::GameSetting>().find("fProjectileMaxSpeed")->getFloat();
|
||||||
|
float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * it->second.mSpeed;
|
||||||
|
|
||||||
|
Ogre::Vector3 direction = orient.yAxis();
|
||||||
|
direction.normalise();
|
||||||
|
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
||||||
|
Ogre::Vector3 newPos = pos + direction * duration * speed;
|
||||||
|
|
||||||
|
// Check for impact
|
||||||
|
btVector3 from(pos.x, pos.y, pos.z);
|
||||||
|
btVector3 to(newPos.x, newPos.y, newPos.z);
|
||||||
|
std::vector<std::pair<float, std::string> > collisions = mPhysEngine->rayTest2(from, to);
|
||||||
|
for (std::vector<std::pair<float, std::string> >::iterator cIt = collisions.begin(); cIt != collisions.end(); ++cIt)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr obstacle = searchPtrViaHandle(cIt->second);
|
||||||
|
if (obstacle.isEmpty())
|
||||||
|
{
|
||||||
|
// Terrain. TODO: Explode
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (obstacle == ptr)
|
||||||
|
continue;
|
||||||
|
MWWorld::Ptr caster = searchPtrViaHandle(it->second.mActorHandle);
|
||||||
|
if (caster.isEmpty())
|
||||||
|
caster = obstacle;
|
||||||
|
MWMechanics::CastSpell cast(caster, obstacle);
|
||||||
|
cast.mStack = it->second.mStack;
|
||||||
|
cast.mId = it->second.mId;
|
||||||
|
cast.mSourceName = it->second.mSourceName;
|
||||||
|
cast.inflict(obstacle, caster, it->second.mEffects, ESM::RT_Target, false);
|
||||||
|
|
||||||
|
deleteObject(ptr);
|
||||||
|
mProjectiles.erase(it++);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string handle = ptr.getRefData().getHandle();
|
||||||
|
|
||||||
|
moveObject(ptr, newPos.x, newPos.y, newPos.z);
|
||||||
|
|
||||||
|
// HACK: Re-fetch Ptrs if necessary, since the cell might have changed
|
||||||
|
if (!ptr.getRefData().getCount())
|
||||||
|
{
|
||||||
|
moved[handle] = it->second;
|
||||||
|
mProjectiles.erase(it++);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK: Re-fetch Ptrs if necessary, since the cell might have changed
|
||||||
|
for (std::map<std::string, ProjectileState>::iterator it = moved.begin(); it != moved.end(); ++it)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr newPtr = searchPtrViaHandle(it->first);
|
||||||
|
if (newPtr.isEmpty()) // The projectile went into an inactive cell and was deleted
|
||||||
|
continue;
|
||||||
|
mProjectiles[getPtrViaHandle(it->first)] = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::objectLeftActiveCell(Ptr object, Ptr movedPtr)
|
||||||
|
{
|
||||||
|
// For now, projectiles moved to an inactive cell are just deleted, because there's no reliable way to hold on to the meta information
|
||||||
|
if (mProjectiles.find(object) != mProjectiles.end())
|
||||||
|
{
|
||||||
|
deleteObject(movedPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,12 @@ namespace MWWorld
|
||||||
|
|
||||||
// Name of item to display as effect source in magic menu (in case we casted an enchantment)
|
// Name of item to display as effect source in magic menu (in case we casted an enchantment)
|
||||||
std::string mSourceName;
|
std::string mSourceName;
|
||||||
|
|
||||||
|
ESM::EffectList mEffects;
|
||||||
|
|
||||||
|
float mSpeed;
|
||||||
|
|
||||||
|
bool mStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<MWWorld::Ptr, ProjectileState> mProjectiles;
|
std::map<MWWorld::Ptr, ProjectileState> mProjectiles;
|
||||||
|
@ -147,6 +153,9 @@ namespace MWWorld
|
||||||
bool mTeleportEnabled;
|
bool mTeleportEnabled;
|
||||||
bool mLevitationEnabled;
|
bool mLevitationEnabled;
|
||||||
|
|
||||||
|
/// Called when \a object is moved to an inactive cell
|
||||||
|
void objectLeftActiveCell (MWWorld::Ptr object, MWWorld::Ptr movedPtr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
World (OEngine::Render::OgreRenderer& renderer,
|
World (OEngine::Render::OgreRenderer& renderer,
|
||||||
|
@ -493,7 +502,7 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor);
|
virtual void castSpell (const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
virtual void launchProjectile (const std::string& id, const ESM::EffectList& effects,
|
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||||
const MWWorld::Ptr& actor, const std::string& sourceName);
|
const MWWorld::Ptr& actor, const std::string& sourceName);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue