From 43de13fa993a36edfd37c7c4d3aa4389713a9835 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Nov 2015 19:22:31 +0100 Subject: [PATCH] Do not allow resting on lava --- apps/openmw/mwphysics/physicssystem.cpp | 42 +++++++++++++++++++++++++ apps/openmw/mwphysics/physicssystem.hpp | 6 ++++ apps/openmw/mwworld/worldimp.cpp | 9 ++++-- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 9eda6cb06..17014e162 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -515,6 +515,7 @@ namespace MWPhysics public: Object(const MWWorld::Ptr& ptr, osg::ref_ptr shapeInstance) : mShapeInstance(shapeInstance) + , mSolid(true) { mPtr = ptr; @@ -549,6 +550,17 @@ namespace MWPhysics return mCollisionObject.get(); } + /// Return solid flag. Not used by the object itself, true by default. + bool isSolid() const + { + return mSolid; + } + + void setSolid(bool solid) + { + mSolid = solid; + } + bool isAnimated() const { return !mShapeInstance->mAnimatedShapes.empty(); @@ -618,6 +630,7 @@ namespace MWPhysics private: std::auto_ptr mCollisionObject; osg::ref_ptr mShapeInstance; + bool mSolid; }; // --------------------------------------------------------------- @@ -684,6 +697,35 @@ namespace MWPhysics return mDebugDrawEnabled; } + void PhysicsSystem::markAsNonSolid(const MWWorld::Ptr &ptr) + { + ObjectMap::iterator found = mObjects.find(ptr); + if (found == mObjects.end()) + return; + + found->second->setSolid(false); + } + + bool PhysicsSystem::isOnSolidGround (const MWWorld::Ptr& actor) const + { + const Actor* physactor = getActor(actor); + if (!physactor->getOnGround()) + return false; + + CollisionMap::const_iterator found = mStandingCollisions.find(actor); + if (found == mStandingCollisions.end()) + return true; // assume standing on terrain (which is a non-object, so not collision tracked) + + ObjectMap::const_iterator foundObj = mObjects.find(found->second); + if (foundObj == mObjects.end()) + return false; + + if (!foundObj->second->isSolid()) + return false; + + return true; + } + class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback { const btCollisionObject* mMe; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 83729d7ae..de644e0f3 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -153,6 +153,12 @@ namespace MWPhysics bool toggleDebugRendering(); + /// Mark the given object as a 'non-solid' object. A non-solid object means that + /// \a isOnSolidGround will return false for actors standing on that object. + void markAsNonSolid (const MWWorld::Ptr& ptr); + + bool isOnSolidGround (const MWWorld::Ptr& actor) const; + private: void updateWater(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 57a20a993..b1234c8a4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2059,11 +2059,10 @@ namespace MWWorld if (!actor) throw std::runtime_error("can't find player"); - if((!actor->getOnGround()&&actor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) + if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos)) return 2; - if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || - player.getClass().getNpcStats(player).isWerewolf()) + if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) return 1; return 0; @@ -2155,6 +2154,8 @@ namespace MWWorld health.setCurrent(health.getCurrent()-healthPerSecond*MWBase::Environment::get().getFrameDuration()); stats.setHealth(health); + mPhysics->markAsNonSolid (object); + if (healthPerSecond > 0.0f) { if (actor == getPlayerPtr()) @@ -2183,6 +2184,8 @@ namespace MWWorld health.setCurrent(health.getCurrent()-healthPerSecond*MWBase::Environment::get().getFrameDuration()); stats.setHealth(health); + mPhysics->markAsNonSolid (object); + if (healthPerSecond > 0.0f) { if (actor == getPlayerPtr())