forked from teamnwah/openmw-tes3coop
Merge pull request #983 from Allofich/telekinesis
Don't allow telekinesis on actors or teleport doors
This commit is contained in:
commit
6f376bd499
14 changed files with 87 additions and 31 deletions
|
@ -250,6 +250,8 @@ namespace MWBase
|
||||||
virtual MWWorld::Ptr getFacedObject() = 0;
|
virtual MWWorld::Ptr getFacedObject() = 0;
|
||||||
///< Return pointer to the object the player is looking at, if it is within activation range
|
///< Return pointer to the object the player is looking at, if it is within activation range
|
||||||
|
|
||||||
|
virtual float getDistanceToFacedObject() = 0;
|
||||||
|
|
||||||
virtual float getMaxActivationDistance() = 0;
|
virtual float getMaxActivationDistance() = 0;
|
||||||
|
|
||||||
/// Returns a pointer to the object the provided object would hit (if within the
|
/// Returns a pointer to the object the provided object would hit (if within the
|
||||||
|
|
|
@ -81,6 +81,10 @@ namespace MWClass
|
||||||
return (ref->mBase->mName != "");
|
return (ref->mBase->mName != "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Activator::allowTelekinesis(const MWWorld::ConstPtr &ptr) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
|
const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
|
||||||
|
|
|
@ -24,6 +24,9 @@ namespace MWClass
|
||||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||||
|
|
||||||
|
virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const;
|
||||||
|
///< Return whether this class of object can be activated with telekinesis
|
||||||
|
|
||||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||||
|
|
||||||
|
|
|
@ -79,4 +79,8 @@ namespace MWClass
|
||||||
weight += effects.get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).getMagnitude();
|
weight += effects.get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).getMagnitude();
|
||||||
return (weight < 0) ? 0.0f : weight;
|
return (weight < 0) ? 0.0f : weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Actor::allowTelekinesis(const MWWorld::ConstPtr &ptr) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,9 @@ namespace MWClass
|
||||||
///< Returns total weight of objects inside this object (including modifications from magic
|
///< Returns total weight of objects inside this object (including modifications from magic
|
||||||
/// effects). Throws an exception, if the object can't hold other objects.
|
/// effects). Throws an exception, if the object can't hold other objects.
|
||||||
|
|
||||||
|
virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const;
|
||||||
|
///< Return whether this class of object can be activated with telekinesis
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
Actor(const Actor&);
|
Actor(const Actor&);
|
||||||
Actor& operator= (const Actor&);
|
Actor& operator= (const Actor&);
|
||||||
|
|
|
@ -146,11 +146,18 @@ namespace MWClass
|
||||||
|
|
||||||
if (ptr.getCellRef().getTeleport())
|
if (ptr.getCellRef().getTeleport())
|
||||||
{
|
{
|
||||||
boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ptr.getCellRef().getDestCell(), ptr.getCellRef().getDoorDest(), true));
|
if (actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() > MWBase::Environment::get().getWorld()->getMaxActivationDistance())
|
||||||
|
{
|
||||||
action->setSound(openSound);
|
// player activated teleport door with telekinesis
|
||||||
|
boost::shared_ptr<MWWorld::Action> action(new MWWorld::FailedAction);
|
||||||
return action;
|
return action;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ptr.getCellRef().getDestCell(), ptr.getCellRef().getDoorDest(), true));
|
||||||
|
action->setSound(openSound);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -213,6 +220,14 @@ namespace MWClass
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Door::allowTelekinesis(const MWWorld::ConstPtr &ptr) const
|
||||||
|
{
|
||||||
|
if (ptr.getCellRef().getTeleport() && ptr.getCellRef().getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty())
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Door::getScript (const MWWorld::ConstPtr& ptr) const
|
std::string Door::getScript (const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>();
|
const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>();
|
||||||
|
|
|
@ -45,6 +45,9 @@ namespace MWClass
|
||||||
|
|
||||||
virtual bool canLock(const MWWorld::ConstPtr &ptr) const;
|
virtual bool canLock(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
||||||
|
virtual bool allowTelekinesis(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
///< Return whether this class of object can be activated with telekinesis
|
||||||
|
|
||||||
virtual std::string getScript (const MWWorld::ConstPtr& ptr) const;
|
virtual std::string getScript (const MWWorld::ConstPtr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace MWMechanics
|
||||||
//Set the target desition from the actor
|
//Set the target desition from the actor
|
||||||
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
||||||
|
|
||||||
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 200) { //Stop when you get close
|
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < MWBase::Environment::get().getWorld()->getMaxActivationDistance()) { //Stop when you get in activation range
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
|
||||||
|
|
||||||
|
|
|
@ -661,6 +661,7 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
RenderingManager::RayResult result;
|
RenderingManager::RayResult result;
|
||||||
result.mHit = false;
|
result.mHit = false;
|
||||||
|
result.mRatio = 0;
|
||||||
if (intersector->containsIntersections())
|
if (intersector->containsIntersections())
|
||||||
{
|
{
|
||||||
result.mHit = true;
|
result.mHit = true;
|
||||||
|
@ -668,6 +669,7 @@ namespace MWRender
|
||||||
|
|
||||||
result.mHitPointWorld = intersection.getWorldIntersectPoint();
|
result.mHitPointWorld = intersection.getWorldIntersectPoint();
|
||||||
result.mHitNormalWorld = intersection.getWorldIntersectNormal();
|
result.mHitNormalWorld = intersection.getWorldIntersectNormal();
|
||||||
|
result.mRatio = intersection.ratio;
|
||||||
|
|
||||||
PtrHolder* ptrHolder = NULL;
|
PtrHolder* ptrHolder = NULL;
|
||||||
for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it)
|
for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it)
|
||||||
|
|
|
@ -120,6 +120,7 @@ namespace MWRender
|
||||||
osg::Vec3f mHitNormalWorld;
|
osg::Vec3f mHitNormalWorld;
|
||||||
osg::Vec3f mHitPointWorld;
|
osg::Vec3f mHitPointWorld;
|
||||||
MWWorld::Ptr mHitObject;
|
MWWorld::Ptr mHitObject;
|
||||||
|
float mRatio;
|
||||||
};
|
};
|
||||||
|
|
||||||
RayResult castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors=false);
|
RayResult castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors=false);
|
||||||
|
|
|
@ -1,40 +1,34 @@
|
||||||
#include "actiontrap.hpp"
|
#include "actiontrap.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
|
||||||
void ActionTrap::executeImp(const Ptr &actor)
|
void ActionTrap::executeImp(const Ptr &actor)
|
||||||
{
|
{
|
||||||
osg::Vec3f actorPosition(actor.getRefData().getPosition().asVec3());
|
osg::Vec3f actorPosition(actor.getRefData().getPosition().asVec3());
|
||||||
osg::Vec3f trapPosition(mTrapSource.getRefData().getPosition().asVec3());
|
osg::Vec3f trapPosition(mTrapSource.getRefData().getPosition().asVec3());
|
||||||
float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
|
float trapRange = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
|
||||||
|
|
||||||
// GUI calcs if object in activation distance include object and player geometry
|
// Note: can't just detonate the trap at the trapped object's location and use the blast
|
||||||
const float fudgeFactor = 1.25f;
|
|
||||||
|
|
||||||
// Hack: if actor is beyond activation range, then assume actor is using telekinesis
|
|
||||||
// to open door/container.
|
|
||||||
// Note, can't just detonate the trap at the trapped object's location and use the blast
|
|
||||||
// radius, because for most trap spells this is 1 foot, much less than the activation distance.
|
// radius, because for most trap spells this is 1 foot, much less than the activation distance.
|
||||||
if ((trapPosition - actorPosition).length() < (activationDistance * fudgeFactor))
|
// Using activation distance as the trap range.
|
||||||
|
|
||||||
|
if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() > trapRange) // player activated object outside range of trap
|
||||||
{
|
{
|
||||||
// assume actor touched trap
|
|
||||||
MWMechanics::CastSpell cast(mTrapSource, actor);
|
|
||||||
cast.mHitPosition = actorPosition;
|
|
||||||
cast.cast(mSpellId);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// assume telekinesis used
|
|
||||||
MWMechanics::CastSpell cast(mTrapSource, mTrapSource);
|
MWMechanics::CastSpell cast(mTrapSource, mTrapSource);
|
||||||
cast.mHitPosition = trapPosition;
|
cast.mHitPosition = trapPosition;
|
||||||
cast.cast(mSpellId);
|
cast.cast(mSpellId);
|
||||||
}
|
}
|
||||||
|
else // player activated object within range of trap, or NPC activated trap
|
||||||
|
{
|
||||||
|
MWMechanics::CastSpell cast(mTrapSource, actor);
|
||||||
|
cast.mHitPosition = actorPosition;
|
||||||
|
cast.cast(mSpellId);
|
||||||
|
}
|
||||||
mTrapSource.getCellRef().setTrap("");
|
mTrapSource.getCellRef().setTrap("");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,6 +280,9 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; }
|
virtual bool isGold(const MWWorld::ConstPtr& ptr) const { return false; }
|
||||||
|
|
||||||
|
virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const { return true; }
|
||||||
|
///< Return whether this class of object can be activated with telekinesis
|
||||||
|
|
||||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||||
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;
|
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,7 @@ namespace MWWorld
|
||||||
mSky (true), mCells (mStore, mEsm),
|
mSky (true), mCells (mStore, mEsm),
|
||||||
mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles),
|
mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles),
|
||||||
mActivationDistanceOverride (activationDistanceOverride), mStartupScript(startupScript),
|
mActivationDistanceOverride (activationDistanceOverride), mStartupScript(startupScript),
|
||||||
mStartCell (startCell), mTeleportEnabled(true),
|
mStartCell (startCell), mDistanceToFacedObject(-1), mTeleportEnabled(true),
|
||||||
mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0)
|
mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0)
|
||||||
{
|
{
|
||||||
mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode);
|
mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode);
|
||||||
|
@ -1027,12 +1027,20 @@ namespace MWWorld
|
||||||
|
|
||||||
float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus;
|
float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus;
|
||||||
|
|
||||||
facedObject = getFacedObject(activationDistance);
|
facedObject = getFacedObject(activationDistance, true);
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!facedObject.isEmpty() && !facedObject.getClass().allowTelekinesis(facedObject)
|
||||||
|
&& mDistanceToFacedObject > getMaxActivationDistance())
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return facedObject;
|
return facedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float World::getDistanceToFacedObject()
|
||||||
|
{
|
||||||
|
return mDistanceToFacedObject;
|
||||||
|
}
|
||||||
|
|
||||||
osg::Matrixf World::getActorHeadTransform(const MWWorld::ConstPtr& actor) const
|
osg::Matrixf World::getActorHeadTransform(const MWWorld::ConstPtr& actor) const
|
||||||
{
|
{
|
||||||
const MWRender::Animation *anim = mRendering->getAnimation(actor);
|
const MWRender::Animation *anim = mRendering->getAnimation(actor);
|
||||||
|
@ -1715,17 +1723,24 @@ namespace MWWorld
|
||||||
MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer)
|
MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer)
|
||||||
{
|
{
|
||||||
maxDistance += mRendering->getCameraDistance();
|
maxDistance += mRendering->getCameraDistance();
|
||||||
|
MWWorld::Ptr facedObject;
|
||||||
|
MWRender::RenderingManager::RayResult rayToObject;
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
{
|
{
|
||||||
float x, y;
|
float x, y;
|
||||||
MWBase::Environment::get().getWindowManager()->getMousePosition(x, y);
|
MWBase::Environment::get().getWindowManager()->getMousePosition(x, y);
|
||||||
return mRendering->castCameraToViewportRay(x, y, maxDistance, ignorePlayer).mHitObject;
|
rayToObject = mRendering->castCameraToViewportRay(x, y, maxDistance, ignorePlayer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
rayToObject = mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer);
|
||||||
return mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer).mHitObject;
|
|
||||||
}
|
facedObject = rayToObject.mHitObject;
|
||||||
|
if (rayToObject.mHit)
|
||||||
|
mDistanceToFacedObject = rayToObject.mRatio * maxDistance;
|
||||||
|
else
|
||||||
|
mDistanceToFacedObject = -1;
|
||||||
|
return facedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::isCellExterior() const
|
bool World::isCellExterior() const
|
||||||
|
|
|
@ -127,7 +127,9 @@ namespace MWWorld
|
||||||
void updateSoundListener();
|
void updateSoundListener();
|
||||||
void updateWindowManager ();
|
void updateWindowManager ();
|
||||||
void updatePlayer(bool paused);
|
void updatePlayer(bool paused);
|
||||||
|
|
||||||
MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true);
|
MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true);
|
||||||
|
|
||||||
public: // FIXME
|
public: // FIXME
|
||||||
void removeContainerScripts(const Ptr& reference);
|
void removeContainerScripts(const Ptr& reference);
|
||||||
private:
|
private:
|
||||||
|
@ -154,6 +156,9 @@ namespace MWWorld
|
||||||
const std::vector<std::string>& content, ContentLoader& contentLoader);
|
const std::vector<std::string>& content, ContentLoader& contentLoader);
|
||||||
|
|
||||||
float mSwimHeightScale;
|
float mSwimHeightScale;
|
||||||
|
|
||||||
|
float mDistanceToFacedObject;
|
||||||
|
|
||||||
bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const;
|
bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const;
|
||||||
///< helper function for implementing isSwimming(), isSubmerged(), isWading()
|
///< helper function for implementing isSwimming(), isSubmerged(), isWading()
|
||||||
|
|
||||||
|
@ -343,6 +348,8 @@ namespace MWWorld
|
||||||
virtual MWWorld::Ptr getFacedObject();
|
virtual MWWorld::Ptr getFacedObject();
|
||||||
///< Return pointer to the object the player is looking at, if it is within activation range
|
///< Return pointer to the object the player is looking at, if it is within activation range
|
||||||
|
|
||||||
|
virtual float getDistanceToFacedObject();
|
||||||
|
|
||||||
/// Returns a pointer to the object the provided object would hit (if within the
|
/// Returns a pointer to the object the provided object would hit (if within the
|
||||||
/// specified distance), and the point where the hit occurs. This will attempt to
|
/// specified distance), and the point where the hit occurs. This will attempt to
|
||||||
/// use the "Head" node as a basis.
|
/// use the "Head" node as a basis.
|
||||||
|
|
Loading…
Reference in a new issue