From fbd0ffe86ff00da9bac3ae24670d1cbca32c1860 Mon Sep 17 00:00:00 2001
From: mrcheko <cheko@sevas.ua>
Date: Tue, 22 Apr 2014 22:59:39 +0400
Subject: [PATCH] enable z-moving for flying/water combatants

---
 apps/openmw/mwmechanics/aicombat.cpp  | 32 +++++++++++++++++++--------
 apps/openmw/mwmechanics/character.cpp | 10 +++++----
 2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp
index 84798ca028..807e08c1db 100644
--- a/apps/openmw/mwmechanics/aicombat.cpp
+++ b/apps/openmw/mwmechanics/aicombat.cpp
@@ -38,7 +38,7 @@ namespace
         return Ogre::Radian( Ogre::Math::ACos(dir.y / len) * sgn(Ogre::Math::ASin(dir.x / len)) ).valueDegrees();
     }
 
-	const float PATHFIND_Z_REACH = 50.0f;
+    const float PATHFIND_Z_REACH = 50.0f;
     // distance at which actor pays more attention to decide whether to shortcut or stick to pathgrid
     const float PATHFIND_CAUTION_DIST = 500.0f;
     // distance after which actor (failed previously to shortcut) will try again
@@ -115,6 +115,7 @@ namespace MWMechanics
         }
 
 
+
         mTimerAttack -= duration;
         actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mStrike);
 
@@ -229,6 +230,17 @@ namespace MWMechanics
 
         mLastPos = pos;
 
+        // check if can move along z-axis
+        bool canMoveByZ;
+        if(canMoveByZ = ((actor.getClass().isNpc() || actor.getClass().canSwim(actor)) && MWBase::Environment::get().getWorld()->isSwimming(actor))
+            || (actor.getClass().canFly(actor) && MWBase::Environment::get().getWorld()->isFlying(actor)))
+        {
+            float zToTarget = vTargetPos.z - pos.pos[2];
+
+            mMovement.mPosition[1] = sqrt(distToTarget*distToTarget - zToTarget*zToTarget); // XY-plane vec length
+            mMovement.mPosition[2] = zToTarget;
+        }
+
         if(distToTarget < rangeMelee || (distToTarget <= rangeCloseUp && mFollowTarget && !isStuck) )
         {
             //Melee and Close-up combat
@@ -238,12 +250,13 @@ namespace MWMechanics
             if (mFollowTarget && distToTarget > rangeMelee)
             {
                 //Close-up combat: just run up on target
-                mMovement.mPosition[1] = 1;
+                if(!canMoveByZ) mMovement.mPosition[1] = 1;
             }
             else
             {
                 //Melee: stop running and attack
                 mMovement.mPosition[1] = 0;
+                if(canMoveByZ) mMovement.mPosition[2] = 0;
 
                 // When attacking with a weapon, choose between slash, thrust or chop
                 if (actor.getClass().hasInventoryStore(actor))
@@ -295,15 +308,16 @@ namespace MWMechanics
 				preferShortcut = checkWayIsClear(vActorPos, vTargetPos, distToTarget > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2);
             }
 
-			if(preferShortcut)
-			{
+            if(canMoveByZ) preferShortcut = true;
+
+            if(preferShortcut)
+            {
                 mTargetAngle = getZAngleToDir(vDirToTarget, distToTarget);
                 mForceNoShortcut = false;
                 mShortcutFailPos.pos[0] = mShortcutFailPos.pos[1] = mShortcutFailPos.pos[2] = 0;
-                if(mPathFinder.isPathConstructed())
-                    mPathFinder.clearPath();
-			}
-			else // if shortcut failed stick to path grid
+                mPathFinder.clearPath();
+            }
+            else // if shortcut failed stick to path grid
             {
                 if(!isStuck && mShortcutFailPos.pos[0] == 0.0f && mShortcutFailPos.pos[1] == 0.0f && mShortcutFailPos.pos[2] == 0.0f)
                 {
@@ -344,7 +358,7 @@ namespace MWMechanics
                 }
             }
 
-            mMovement.mPosition[1] = 1;
+            if(!canMoveByZ) mMovement.mPosition[1] = 1;
             mReadyToAttack = false;
         }
 
diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp
index 93c789af1a..2c63d5a142 100644
--- a/apps/openmw/mwmechanics/character.cpp
+++ b/apps/openmw/mwmechanics/character.cpp
@@ -1018,6 +1018,7 @@ void CharacterController::update(float duration)
 
         vec.x *= mMovementSpeed;
         vec.y *= mMovementSpeed;
+        if(inwater || flying) vec.z *= mMovementSpeed;
 
         CharacterState movestate = CharState_None;
         CharacterState idlestate = CharState_SpecialIdle;
@@ -1084,7 +1085,8 @@ void CharacterController::update(float duration)
         fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss, fatigue.getCurrent() < 0);
         cls.getCreatureStats(mPtr).setFatigue(fatigue);
 
-        if(sneak || inwater || flying)
+        // kind of hack, reason - creatures can move along z when in water/flying
+        if(sneak || ((inwater || flying) && mPtr.getRefData().getHandle() == "player"))
             vec.z = 0.0f;
 
         if (inwater || flying)
@@ -1119,7 +1121,7 @@ void CharacterController::update(float duration)
             vec.y *= mult;
             vec.z  = 0.0f;
         }
-        else if(vec.z > 0.0f && mJumpState == JumpState_None)
+        else if(!inwater && !flying && vec.z > 0.0f && mJumpState == JumpState_None)
         {
             // Started a jump.
             float z = cls.getJump(mPtr);
@@ -1179,9 +1181,9 @@ void CharacterController::update(float duration)
         }
         else
         {
-           if(!(vec.z > 0.0f))
+            if(!(vec.z > 0.0f))
                 mJumpState = JumpState_None;
-            vec.z = 0.0f;
+            if(!inwater && !flying) vec.z = 0.0f;
 
             if(std::abs(vec.x/2.0f) > std::abs(vec.y))
             {