diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp
index cdfdfc358..7432db734 100644
--- a/apps/openmw/mwbase/world.hpp
+++ b/apps/openmw/mwbase/world.hpp
@@ -392,6 +392,7 @@ namespace MWBase
             virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0;
             virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0;
             virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
+            virtual bool isWading(const MWWorld::Ptr &object) const = 0;
             ///Is the head of the creature underwater?
             virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0;
             virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp
index 2146fdfde..e21676f10 100644
--- a/apps/openmw/mwclass/creature.cpp
+++ b/apps/openmw/mwclass/creature.cpp
@@ -348,9 +348,9 @@ namespace MWClass
 
         // Self defense
         bool setOnPcHitMe = true; // Note OnPcHitMe is not set for friendly hits.
-        if ((canWalk(ptr) || canFly(ptr) || canSwim(ptr)) // No retaliation for totally static creatures
-                                                              // (they have no movement or attacks anyway)
-            && !attacker.isEmpty())
+        
+        // No retaliation for totally static creatures (they have no movement or attacks anyway)
+        if (isMobile(ptr) && !attacker.isEmpty())
         {
             setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
         }
diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp
index c0fc80692..0a25ddd42 100644
--- a/apps/openmw/mwmechanics/actors.cpp
+++ b/apps/openmw/mwmechanics/actors.cpp
@@ -309,8 +309,8 @@ namespace MWMechanics
         // pure water creatures won't try to fight with the target on the ground
         // except that creature is already hostile
         if ((againstPlayer || !creatureStats.getAiSequence().isInCombat())
-                && ((actor1.getClass().canSwim(actor1) && !actor1.getClass().canWalk(actor1) // pure water creature
-                && !MWBase::Environment::get().getWorld()->isSwimming(actor2))
+                && ((actor1.getClass().isPureWaterCreature(actor1)
+                && !MWBase::Environment::get().getWorld()->isWading(actor2))
                 || (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target
             return;
 
diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp
index 5d0470554..ce5963a91 100644
--- a/apps/openmw/mwmechanics/aicombat.cpp
+++ b/apps/openmw/mwmechanics/aicombat.cpp
@@ -209,7 +209,7 @@ namespace MWMechanics
         if (!actorClass.isNpc() &&
             // 1. pure water creature and Player moved out of water
             ((target == world->getPlayerPtr() &&
-            actorClass.canSwim(actor) && !actor.getClass().canWalk(actor) && !world->isSwimming(target))
+            actorClass.isPureWaterCreature(actor) && !world->isWading(target))
             // 2. creature can't swim to target
             || (!actorClass.canSwim(actor) && world->isSwimming(target))))
         {
diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp
index 61c597517..939b72ddb 100644
--- a/apps/openmw/mwworld/class.cpp
+++ b/apps/openmw/mwworld/class.cpp
@@ -383,6 +383,16 @@ namespace MWWorld
         return false;
     }
 
+    bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const
+    {
+        return canSwim(ptr) && !canWalk(ptr);
+    }
+
+    bool Class::isMobile(const MWWorld::Ptr& ptr) const
+    {
+        return canSwim(ptr) || canWalk(ptr) || canFly(ptr);
+    }
+
     int Class::getSkill(const MWWorld::Ptr& ptr, int skill) const
     {
         throw std::runtime_error("class does not support skills");
diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp
index cc18d830c..b738cdd44 100644
--- a/apps/openmw/mwworld/class.hpp
+++ b/apps/openmw/mwworld/class.hpp
@@ -308,6 +308,8 @@ namespace MWWorld
             virtual bool canFly(const MWWorld::Ptr& ptr) const;
             virtual bool canSwim(const MWWorld::Ptr& ptr) const;
             virtual bool canWalk(const MWWorld::Ptr& ptr) const;
+            bool isPureWaterCreature(const MWWorld::Ptr& ptr) const;
+            bool isMobile(const MWWorld::Ptr& ptr) const;
 
             virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
 
diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp
index 3a7aa0490..5b712648c 100644
--- a/apps/openmw/mwworld/physicssystem.cpp
+++ b/apps/openmw/mwworld/physicssystem.cpp
@@ -281,7 +281,7 @@ namespace MWWorld
 
             // Early-out for totally static creatures
             // (Not sure if gravity should still apply?)
-            if (!ptr.getClass().canWalk(ptr) && !ptr.getClass().canFly(ptr) && !ptr.getClass().canSwim(ptr))
+            if (!ptr.getClass().isMobile(ptr))
                 return position;
 
             OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
@@ -434,7 +434,7 @@ namespace MWWorld
                 if(result)
                 {
                     // don't let pure water creatures move out of water after stepMove
-                    if((ptr.getClass().canSwim(ptr) && !ptr.getClass().canWalk(ptr)) 
+                    if (ptr.getClass().isPureWaterCreature(ptr)
                             && newPosition.z > (waterlevel - halfExtents.z * 0.5))
                         newPosition = oldPosition;
                 }
diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp
index a939a6db9..f9642226b 100644
--- a/apps/openmw/mwworld/worldimp.cpp
+++ b/apps/openmw/mwworld/worldimp.cpp
@@ -1978,25 +1978,36 @@ namespace MWWorld
 
     bool World::isSubmerged(const MWWorld::Ptr &object) const
     {
-        const float *fpos = object.getRefData().getPosition().pos;
-        Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]);
-
-        const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle());
-        if(actor) pos.z += 1.85*actor->getHalfExtents().z;
-
-        return isUnderwater(object.getCell(), pos);
+        const float neckDeep = 1.85f;
+        return isUnderwater(object, neckDeep);
     }
 
     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);
+    }
+
+    bool
+    World::isWading(const MWWorld::Ptr &object) const
+    {
+        const float kneeDeep = 0.5f;
+        return isUnderwater(object, kneeDeep);
+    }
+
+    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]);
 
-        /// \fixme 3/4ths submerged?
         const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle());
-        if(actor) pos.z += actor->getHalfExtents().z * 1.5;
+        if (actor)
+        {
+            pos.z += heightRatio*actor->getHalfExtents().z;
+        }
 
         return isUnderwater(object.getCell(), pos);
     }
diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp
index 5810fe42f..dfaa9f789 100644
--- a/apps/openmw/mwworld/worldimp.hpp
+++ b/apps/openmw/mwworld/worldimp.hpp
@@ -139,6 +139,9 @@ namespace MWWorld
             void loadContentFiles(const Files::Collections& fileCollections,
                 const std::vector<std::string>& content, ContentLoader& contentLoader);
 
+            bool isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const;
+            ///< helper function for implementing isSwimming(), isSubmerged(), isWading()
+
             bool mTeleportEnabled;
             bool mLevitationEnabled;
             bool mGoToJail;
@@ -454,6 +457,7 @@ namespace MWWorld
             virtual bool isSubmerged(const MWWorld::Ptr &object) const;
             virtual bool isSwimming(const MWWorld::Ptr &object) const;
             virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const;
+            virtual bool isWading(const MWWorld::Ptr &object) const;
             virtual bool isOnGround(const MWWorld::Ptr &ptr) const;
 
             virtual void togglePOV() {