=== DOOM - id Tech 1 - p_enemy.c @ 363 ==========================================================
rf: https://github.com/id-Software/DOOM/blob/master/linuxdoom-1.10/p_enemy.c

void P_NewChaseDir (mobj_t*   actor)
{
    fixed_t deltax;
    fixed_t deltay;
    
    dirtype_t  d[3];
    
    int     tdir;
    dirtype_t  olddir;
    
    dirtype_t  turnaround;

    if (!actor->target)
       I_Error ("P_NewChaseDir: called with no target");
      
    olddir = actor->movedir;
    turnaround=opposite[olddir];

    deltax = actor->target->x - actor->x;
    deltay = actor->target->y - actor->y;

    if (deltax>10*FRACUNIT)
       d[1]= DI_EAST;
    else if (deltax<-10*FRACUNIT)
       d[1]= DI_WEST;
    else
       d[1]=DI_NODIR;

    if (deltay<-10*FRACUNIT)
       d[2]= DI_SOUTH;
    else if (deltay>10*FRACUNIT)
       d[2]= DI_NORTH;
    else
       d[2]=DI_NODIR;

    // try direct route
    if (d[1] != DI_NODIR
       && d[2] != DI_NODIR)
    {
       actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
       if (actor->movedir != turnaround && P_TryWalk(actor))
           return;
    }

    // try other directions
    if (P_Random() > 200
       ||  abs(deltay)>abs(deltax))
    {
       tdir=d[1];
       d[1]=d[2];
       d[2]=tdir;
    }

    if (d[1]==turnaround)
       d[1]=DI_NODIR;
    if (d[2]==turnaround)
       d[2]=DI_NODIR;
   
    if (d[1]!=DI_NODIR)
    {
       actor->movedir = d[1];
       if (P_TryWalk(actor))
       {
           // either moved forward or attacked
           return;
       }
    }

    if (d[2]!=DI_NODIR)
    {
       actor->movedir =d[2];

       if (P_TryWalk(actor))
           return;
    }

    // there is no direct path to the player,
    // so pick another direction.
    if (olddir!=DI_NODIR)
    {
       actor->movedir =olddir;

       if (P_TryWalk(actor))
           return;
    }

    // randomly determine direction of search
    if (P_Random()&1)   
    {
       for ( tdir=DI_EAST;
             tdir<=DI_SOUTHEAST;
             tdir++ )
       {
           if (tdir!=turnaround)
           {
              actor->movedir =tdir;
      
              if ( P_TryWalk(actor) )
                  return;
           }
       }
    }
    else
    {
       for ( tdir=DI_SOUTHEAST;
             tdir != (DI_EAST-1);
             tdir-- )
       {
           if (tdir!=turnaround)
           {
              actor->movedir =tdir;
      
              if ( P_TryWalk(actor) )
                  return;
           }
       }
    }

    if (turnaround !=  DI_NODIR)
    {
       actor->movedir =turnaround;
       if ( P_TryWalk(actor) )
           return;
    }

    actor->movedir = DI_NODIR;   // can not move
}



=== QUAKE - id Tech 2 - sv_move.c @ 284 =========================================================
rf: https://github.com/id-Software/Quake/blob/master/WinQuake/sv_move.c

/*
================
SV_NewChaseDir

================
*/
#define  DI_NODIR -1
void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
{
   float    deltax,deltay;
   float       d[3];
   float    tdir, olddir, turnaround;

   olddir = anglemod( (int)(actor->v.ideal_yaw/45)*45 );
   turnaround = anglemod(olddir - 180);

   deltax = enemy->v.origin[0] - actor->v.origin[0];
   deltay = enemy->v.origin[1] - actor->v.origin[1];
   if (deltax>10)
      d[1]= 0;
   else if (deltax<-10)
      d[1]= 180;
   else
      d[1]= DI_NODIR;
   if (deltay<-10)
      d[2]= 270;
   else if (deltay>10)
      d[2]= 90;
   else
      d[2]= DI_NODIR;

// try direct route
   if (d[1] != DI_NODIR && d[2] != DI_NODIR)
   {
      if (d[1] == 0)
         tdir = d[2] == 90 ? 45 : 315;
      else
         tdir = d[2] == 90 ? 135 : 215;
         
      if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
         return;
   }

// try other directions
   if ( ((rand()&3) & 1) ||  abs(deltay)>abs(deltax))
   {
      tdir=d[1];
      d[1]=d[2];
      d[2]=tdir;
   }

   if (d[1]!=DI_NODIR && d[1]!=turnaround 
   && SV_StepDirection(actor, d[1], dist))
         return;

   if (d[2]!=DI_NODIR && d[2]!=turnaround
   && SV_StepDirection(actor, d[2], dist))
         return;

/* there is no direct path to the player, so pick another direction */

   if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
         return;

   if (rand()&1)  /*randomly determine direction of search*/
   {
      for (tdir=0 ; tdir<=315 ; tdir += 45)
         if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
               return;
   }
   else
   {
      for (tdir=315 ; tdir >=0 ; tdir -= 45)
         if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
               return;
   }

   if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
         return;

   actor->v.ideal_yaw = olddir;     // can't move

// if a bridge was pulled out from underneath a monster, it may not have
// a valid standing position at all

   if (!SV_CheckBottom (actor))
      SV_FixCheckBottom (actor);

}


=== QUAKE 2 - id Tech 2 - m_move.c @ 403 ========================================================
rf: https://github.com/id-Software/Quake-2/blob/master/game/m_move.c

/*
================
SV_NewChaseDir

================
*/
#define  DI_NODIR -1
void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
{
   float deltax,deltay;
   float d[3];
   float tdir, olddir, turnaround;

   //FIXME: how did we get here with no enemy
   if (!enemy)
      return;

   olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
   turnaround = anglemod(olddir - 180);

   deltax = enemy->s.origin[0] - actor->s.origin[0];
   deltay = enemy->s.origin[1] - actor->s.origin[1];
   if (deltax>10)
      d[1]= 0;
   else if (deltax<-10)
      d[1]= 180;
   else
      d[1]= DI_NODIR;
   if (deltay<-10)
      d[2]= 270;
   else if (deltay>10)
      d[2]= 90;
   else
      d[2]= DI_NODIR;

// try direct route
   if (d[1] != DI_NODIR && d[2] != DI_NODIR)
   {
      if (d[1] == 0)
         tdir = d[2] == 90 ? 45 : 315;
      else
         tdir = d[2] == 90 ? 135 : 215;
         
      if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
         return;
   }

// try other directions
   if ( ((rand()&3) & 1) ||  abs(deltay)>abs(deltax))
   {
      tdir=d[1];
      d[1]=d[2];
      d[2]=tdir;
   }

   if (d[1]!=DI_NODIR && d[1]!=turnaround 
   && SV_StepDirection(actor, d[1], dist))
         return;

   if (d[2]!=DI_NODIR && d[2]!=turnaround
   && SV_StepDirection(actor, d[2], dist))
         return;

/* there is no direct path to the player, so pick another direction */

   if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
         return;

   if (rand()&1)  /*randomly determine direction of search*/
   {
      for (tdir=0 ; tdir<=315 ; tdir += 45)
         if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
               return;
   }
   else
   {
      for (tdir=315 ; tdir >=0 ; tdir -= 45)
         if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
               return;
   }

   if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
         return;

   actor->ideal_yaw = olddir;    // can't move

// if a bridge was pulled out from underneath a monster, it may not have
// a valid standing position at all

   if (!M_CheckBottom (actor))
      SV_FixCheckBottom (actor);
}


=== QUAKE 3 - id Tech 3 - NOT FOUND! ============================================================


=== DOOM 3 - id Tech 4 - AI.cpp @ 2105 ==========================================================
rf: https://github.com/id-Software/DOOM-3/blob/master/neo/game/ai/AI.cpp

/*
================
idAI::NewWanderDir
================
*/
bool idAI::NewWanderDir( const idVec3 &dest ) {
   float deltax, deltay;
   float d[ 3 ];
   float tdir, olddir, turnaround;

   move.nextWanderTime = gameLocal.time + ( gameLocal.random.RandomFloat() * 500 + 500 );

   olddir = idMath::AngleNormalize360( ( int )( current_yaw / 45 ) * 45 );
   turnaround = idMath::AngleNormalize360( olddir - 180 );

   idVec3 org = physicsObj.GetOrigin();
   deltax = dest.x - org.x;
   deltay = dest.y - org.y;
   if ( deltax > 10 ) {
      d[ 1 ]= 0;
   } else if ( deltax < -10 ) {
      d[ 1 ] = 180;
   } else {
      d[ 1 ] = DI_NODIR;
   }

   if ( deltay < -10 ) {
      d[ 2 ] = 270;
   } else if ( deltay > 10 ) {
      d[ 2 ] = 90;
   } else {
      d[ 2 ] = DI_NODIR;
   }

   // try direct route
   if ( d[ 1 ] != DI_NODIR && d[ 2 ] != DI_NODIR ) {
      if ( d[ 1 ] == 0 ) {
         tdir = d[ 2 ] == 90 ? 45 : 315;
      } else {
         tdir = d[ 2 ] == 90 ? 135 : 215;
      }

      if ( tdir != turnaround && StepDirection( tdir ) ) {
         return true;
      }
   }

   // try other directions
   if ( ( gameLocal.random.RandomInt() & 1 ) || abs( deltay ) > abs( deltax ) ) {
      tdir = d[ 1 ];
      d[ 1 ] = d[ 2 ];
      d[ 2 ] = tdir;
   }

   if ( d[ 1 ] != DI_NODIR && d[ 1 ] != turnaround && StepDirection( d[1] ) ) {
      return true;
   }

   if ( d[ 2 ] != DI_NODIR && d[ 2 ] != turnaround && StepDirection( d[ 2 ] ) ) {
      return true;
   }

   // there is no direct path to the player, so pick another direction
   if ( olddir != DI_NODIR && StepDirection( olddir ) ) {
      return true;
   }

    // randomly determine direction of search
   if ( gameLocal.random.RandomInt() & 1 ) {
      for( tdir = 0; tdir <= 315; tdir += 45 ) {
         if ( tdir != turnaround && StepDirection( tdir ) ) {
                return true;
         }
      }
   } else {
      for ( tdir = 315; tdir >= 0; tdir -= 45 ) {
         if ( tdir != turnaround && StepDirection( tdir ) ) {
            return true;
         }
      }
   }

   if ( turnaround != DI_NODIR && StepDirection( turnaround ) ) {
      return true;
   }

   // can't move
   StopMove( MOVE_STATUS_DEST_UNREACHABLE );
   return false;
}