Merge pull request #983 from Allofich/telekinesis

Don't allow telekinesis on actors or teleport doors
coverity_scan^2
scrawl 9 years ago committed by GitHub
commit 6f376bd499

@ -250,6 +250,8 @@ namespace MWBase
virtual MWWorld::Ptr getFacedObject() = 0;
///< Return pointer to the object the player is looking at, if it is within activation range
virtual float getDistanceToFacedObject() = 0;
virtual float getMaxActivationDistance() = 0;
/// Returns a pointer to the object the provided object would hit (if within the

@ -81,6 +81,10 @@ namespace MWClass
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
{
const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();

@ -24,6 +24,9 @@ namespace MWClass
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
///< @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;
///< @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();
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
/// 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
Actor(const Actor&);
Actor& operator= (const Actor&);

@ -146,11 +146,18 @@ namespace MWClass
if (ptr.getCellRef().getTeleport())
{
boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ptr.getCellRef().getDestCell(), ptr.getCellRef().getDoorDest(), true));
action->setSound(openSound);
return action;
if (actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() > MWBase::Environment::get().getWorld()->getMaxActivationDistance())
{
// player activated teleport door with telekinesis
boost::shared_ptr<MWWorld::Action> action(new MWWorld::FailedAction);
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
{
@ -213,6 +220,14 @@ namespace MWClass
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
{
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 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;
///< Return name of the script attached to ptr

@ -39,7 +39,7 @@ namespace MWMechanics
//Set the target desition from the actor
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;
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);

@ -661,6 +661,7 @@ namespace MWRender
{
RenderingManager::RayResult result;
result.mHit = false;
result.mRatio = 0;
if (intersector->containsIntersections())
{
result.mHit = true;
@ -668,6 +669,7 @@ namespace MWRender
result.mHitPointWorld = intersection.getWorldIntersectPoint();
result.mHitNormalWorld = intersection.getWorldIntersectNormal();
result.mRatio = intersection.ratio;
PtrHolder* ptrHolder = NULL;
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 mHitPointWorld;
MWWorld::Ptr mHitObject;
float mRatio;
};
RayResult castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors=false);

@ -1,40 +1,34 @@
#include "actiontrap.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
namespace MWWorld
{
void ActionTrap::executeImp(const Ptr &actor)
{
osg::Vec3f actorPosition(actor.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
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
// 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.
if ((trapPosition - actorPosition).length() < (activationDistance * fudgeFactor))
{
// assume actor touched trap
MWMechanics::CastSpell cast(mTrapSource, actor);
cast.mHitPosition = actorPosition;
cast.cast(mSpellId);
}
else
// 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 telekinesis used
MWMechanics::CastSpell cast(mTrapSource, mTrapSource);
cast.mHitPosition = trapPosition;
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("");
}
}

@ -279,6 +279,9 @@ namespace MWWorld
virtual bool isKey (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)
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;

@ -150,7 +150,7 @@ namespace MWWorld
mSky (true), mCells (mStore, mEsm),
mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles),
mActivationDistanceOverride (activationDistanceOverride), mStartupScript(startupScript),
mStartCell (startCell), mTeleportEnabled(true),
mStartCell (startCell), mDistanceToFacedObject(-1), mTeleportEnabled(true),
mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0)
{
mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode);
@ -1027,12 +1027,20 @@ namespace MWWorld
float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus;
facedObject = getFacedObject(activationDistance);
}
facedObject = getFacedObject(activationDistance, true);
if (!facedObject.isEmpty() && !facedObject.getClass().allowTelekinesis(facedObject)
&& mDistanceToFacedObject > getMaxActivationDistance())
return 0;
}
return facedObject;
}
float World::getDistanceToFacedObject()
{
return mDistanceToFacedObject;
}
osg::Matrixf World::getActorHeadTransform(const MWWorld::ConstPtr& actor) const
{
const MWRender::Animation *anim = mRendering->getAnimation(actor);
@ -1715,17 +1723,24 @@ namespace MWWorld
MWWorld::Ptr World::getFacedObject(float maxDistance, bool ignorePlayer)
{
maxDistance += mRendering->getCameraDistance();
MWWorld::Ptr facedObject;
MWRender::RenderingManager::RayResult rayToObject;
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
{
float 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
{
return mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer).mHitObject;
}
rayToObject = mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer);
facedObject = rayToObject.mHitObject;
if (rayToObject.mHit)
mDistanceToFacedObject = rayToObject.mRatio * maxDistance;
else
mDistanceToFacedObject = -1;
return facedObject;
}
bool World::isCellExterior() const

@ -127,7 +127,9 @@ namespace MWWorld
void updateSoundListener();
void updateWindowManager ();
void updatePlayer(bool paused);
MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true);
public: // FIXME
void removeContainerScripts(const Ptr& reference);
private:
@ -154,6 +156,9 @@ namespace MWWorld
const std::vector<std::string>& content, ContentLoader& contentLoader);
float mSwimHeightScale;
float mDistanceToFacedObject;
bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const;
///< helper function for implementing isSwimming(), isSubmerged(), isWading()
@ -343,6 +348,8 @@ namespace MWWorld
virtual MWWorld::Ptr getFacedObject();
///< 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
/// specified distance), and the point where the hit occurs. This will attempt to
/// use the "Head" node as a basis.

Loading…
Cancel
Save