From 7fbc696d44e60c4caf24ba25c635cb86f3d5dd8e Mon Sep 17 00:00:00 2001
From: elsid <elsid.mail@gmail.com>
Date: Sun, 25 Aug 2019 17:21:14 +0200
Subject: [PATCH] Change angle direction by rolling dice to avoid rotating door

---
 apps/openmw/mwmechanics/aiavoiddoor.cpp | 42 +++++++++++++++----------
 apps/openmw/mwmechanics/aiavoiddoor.hpp | 10 ++++--
 2 files changed, 34 insertions(+), 18 deletions(-)

diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp
index 793bd89ea..c476c9b57 100644
--- a/apps/openmw/mwmechanics/aiavoiddoor.cpp
+++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp
@@ -1,5 +1,7 @@
 #include "aiavoiddoor.hpp"
 
+#include <components/misc/rng.hpp>
+
 #include "../mwbase/world.hpp"
 #include "../mwbase/environment.hpp"
 #include "../mwbase/mechanicsmanager.hpp"
@@ -11,8 +13,10 @@
 #include "actorutil.hpp"
 #include "steering.hpp"
 
+static const int MAX_DIRECTIONS = 4;
+
 MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr)
-: AiPackage(), mDuration(1), mDoorPtr(doorPtr), mLastPos(ESM::Position()), mAdjAngle(0)
+: AiPackage(), mDuration(1), mDoorPtr(doorPtr), mDirection(0)
 {
 
 }
@@ -22,25 +26,18 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
 
     ESM::Position pos = actor.getRefData().getPosition();
     if(mDuration == 1) //If it just started, get the actor position as the stuck detection thing
-        mLastPos = pos;
+        mLastPos = pos.asVec3();
 
     mDuration -= duration; //Update timer
 
-    if(mDuration < 0) {
-        float x = pos.pos[0] - mLastPos.pos[0];
-        float y = pos.pos[1] - mLastPos.pos[1];
-        float z = pos.pos[2] - mLastPos.pos[2];
-        float distance = x * x + y * y + z * z;
-        if(distance < 10 * 10) { //Got stuck, didn't move
-            if(mAdjAngle == 0) //Try going in various directions
-                mAdjAngle = osg::PI / 2;
-            else if (mAdjAngle == osg::PI / 2)
-                mAdjAngle = -osg::PI / 2;
-            else
-                mAdjAngle = 0;
+    if (mDuration < 0)
+    {
+        if (isStuck(pos.asVec3()))
+        {
+            adjustDirection();
             mDuration = 1; //reset timer
         }
-        else //Not stuck
+        else
             return true; // We have tried backing up for more than one second, we've probably cleared it
     }
 
@@ -54,7 +51,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
     actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
 
     // Turn away from the door and move when turn completed
-    if (zTurn(actor, std::atan2(x,y) + mAdjAngle, osg::DegreesToRadians(5.f)))
+    if (zTurn(actor, std::atan2(x,y) + getAdjustedAngle(), osg::DegreesToRadians(5.f)))
         actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
     else
         actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
@@ -90,4 +87,17 @@ unsigned int MWMechanics::AiAvoidDoor::getPriority() const
  return 2;
 }
 
+bool MWMechanics::AiAvoidDoor::isStuck(const osg::Vec3f& actorPos) const
+{
+    return (actorPos - mLastPos).length2() < 10 * 10;
+}
 
+void MWMechanics::AiAvoidDoor::adjustDirection()
+{
+    mDirection = Misc::Rng::rollDice(MAX_DIRECTIONS);
+}
+
+float MWMechanics::AiAvoidDoor::getAdjustedAngle() const
+{
+    return 2 * osg::PI / MAX_DIRECTIONS * mDirection;
+}
diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp
index 7344a1797..4c8be29eb 100644
--- a/apps/openmw/mwmechanics/aiavoiddoor.hpp
+++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp
@@ -36,8 +36,14 @@ namespace MWMechanics
         private:
             float mDuration;
             MWWorld::ConstPtr mDoorPtr;
-            ESM::Position mLastPos;
-            float mAdjAngle;
+            osg::Vec3f mLastPos;
+            int mDirection;
+
+            bool isStuck(const osg::Vec3f& actorPos) const;
+
+            void adjustDirection();
+
+            float getAdjustedAngle() const;
     };
 }
 #endif