diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 0090ca010..bea99029a 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -303,26 +303,15 @@ namespace MWWorld Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); position.z += halfExtents.z; - waterlevel -= halfExtents.z * 0.5; - /* - * A 3/4 submerged example - * - * +---+ - * | | - * | | <- (original waterlevel) - * | | - * | | <- position <- waterlevel - * | | - * | | - * | | - * +---+ <- (original position) - */ + static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() + .find("fSwimHeightScale")->getFloat(); + float swimlevel = waterlevel + halfExtents.z - (halfExtents.z * 2 * fSwimHeightScale); OEngine::Physic::ActorTracer tracer; Ogre::Vector3 inertia = physicActor->getInertialForce(); Ogre::Vector3 velocity; - if(position.z < waterlevel || isFlying) + if(position.z < swimlevel || isFlying) { velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)* Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement; @@ -364,12 +353,10 @@ namespace MWWorld Ogre::Vector3 nextpos = newPosition + velocity * remainingTime; // If not able to fly, don't allow to swim up into the air - // TODO: this if condition may not work for large creatures or situations - // where the creature gets above the waterline for some reason - if(newPosition.z < waterlevel && // started 3/4 under water + if(newPosition.z < swimlevel && !isFlying && // can't fly - nextpos.z > waterlevel && // but about to go above water - newPosition.z <= waterlevel) + nextpos.z > swimlevel && // but about to go above water + newPosition.z <= swimlevel) { const Ogre::Vector3 down(0,0,-1); Ogre::Real movelen = velocity.normalise(); @@ -423,7 +410,7 @@ namespace MWWorld { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z > (waterlevel - halfExtents.z * 0.5)) + && newPosition.z + halfExtents.z > waterlevel) newPosition = oldPosition; } else @@ -444,13 +431,13 @@ namespace MWWorld // Do not allow sliding upward if there is gravity. Stepping will have taken // care of that. - if(!(newPosition.z < waterlevel || isFlying)) + if(!(newPosition.z < swimlevel || isFlying)) velocity.z = std::min(velocity.z, 0.0f); } } bool isOnGround = false; - if (!(inertia.z > 0.f) && !(newPosition.z < waterlevel)) + if (!(inertia.z > 0.f) && !(newPosition.z < swimlevel)) { Ogre::Vector3 from = newPosition; Ogre::Vector3 to = newPosition - (physicActor->getOnGround() ? @@ -494,7 +481,7 @@ namespace MWWorld } } - if(isOnGround || newPosition.z < waterlevel || isFlying) + if(isOnGround || newPosition.z < swimlevel || isFlying) physicActor->setInertialForce(Ogre::Vector3(0.0f)); else { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1015f31f6..1036d8ce6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -187,6 +187,8 @@ namespace MWWorld mStore.setUp(); mStore.movePlayerRecord(); + mSwimHeightScale = mStore.get().find("fSwimHeightScale")->getFloat(); + mGlobalVariables.fill (mStore); mWorldScene = new Scene(*mRendering, mPhysics); @@ -1952,8 +1954,7 @@ namespace MWWorld mRendering->getTriangleBatchCount(triangles, batches); } - bool - World::isFlying(const MWWorld::Ptr &ptr) const + bool World::isFlying(const MWWorld::Ptr &ptr) const { const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); bool isParalyzed = (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0); @@ -1978,8 +1979,7 @@ namespace MWWorld return false; } - bool - World::isSlowFalling(const MWWorld::Ptr &ptr) const + bool World::isSlowFalling(const MWWorld::Ptr &ptr) const { if(!ptr.getClass().isActor()) return false; @@ -1993,27 +1993,21 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - const float neckDeep = 1.85f; - return isUnderwater(object, neckDeep); + return isUnderwater(object, 1.0/mSwimHeightScale); } - bool - World::isSwimming(const MWWorld::Ptr &object) const + bool World::isSwimming(const MWWorld::Ptr &object) const { - /// \todo add check ifActor() - only actors can swim - /// \fixme 3/4ths submerged? - return isUnderwater(object, 1.5f); + return isUnderwater(object, mSwimHeightScale); } - bool - World::isWading(const MWWorld::Ptr &object) const + bool World::isWading(const MWWorld::Ptr &object) const { - const float kneeDeep = 0.5f; + const float kneeDeep = 0.25f; return isUnderwater(object, kneeDeep); } - bool - World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const + bool World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const { const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); @@ -2021,14 +2015,13 @@ namespace MWWorld const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); if (actor) { - pos.z += heightRatio*actor->getHalfExtents().z; + pos.z += heightRatio*2*actor->getHalfExtents().z; } return isUnderwater(object.getCell(), pos); } - bool - World::isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const + bool World::isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const { if (!(cell->getCell()->mData.mFlags & ESM::Cell::HasWater)) { return false; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 18fb354bc..1d103c6a9 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -139,6 +139,7 @@ namespace MWWorld void loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader); + float mSwimHeightScale; bool isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const; ///< helper function for implementing isSwimming(), isSubmerged(), isWading()