toc/
toc/account/a/
toc/area/backup/
toc/area/imc/
toc/caste/
toc/caste/backup/
toc/clans/
toc/classes/
toc/crash/
toc/gods/
toc/guilds/
toc/lname/s/
toc/maps/backup/
toc/player/a/
toc/src/
toc/system/backup/
toc/tableprog/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 *			 Tracking/hunting module			    *
 ****************************************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"


#define BFS_ERROR	   -1
#define BFS_ALREADY_THERE  -2
#define BFS_NO_PATH	   -3

#define TRACK_THROUGH_DOORS

extern sh_int top_room;

/* You can define or not define TRACK_THOUGH_DOORS, above, depending on
   whether or not you want track to find paths which lead through closed
   or hidden doors.
*/

typedef struct bfs_queue_struct BFS_DATA;
struct bfs_queue_struct
{
   ROOM_INDEX_DATA *room;
   char dir;
   BFS_DATA *next;
};

static BFS_DATA *queue_head = NULL, *queue_tail = NULL, *room_queue = NULL;

/* Utility macros */
#define MARK(room)	(xSET_BIT(	(room)->room_flags, ROOM_MARK) )
#define UNMARK(room)	(xREMOVE_BIT(	(room)->room_flags, ROOM_MARK) )
#define IS_MARKED(room)	(xIS_SET(	(room)->room_flags, ROOM_MARK) )

bool valid_edge(EXIT_DATA * pexit)
{
   if (pexit->to_room
#ifndef TRACK_THROUGH_DOORS
      && !IS_SET(pexit->exit_info, EX_CLOSED)
#endif
      && !IS_MARKED(pexit->to_room))
      return TRUE;
   else
      return FALSE;
}

void bfs_enqueue(ROOM_INDEX_DATA * room, char dir)
{
   BFS_DATA *curr;

   curr = malloc(sizeof(BFS_DATA));
   curr->room = room;
   curr->dir = dir;
   curr->next = NULL;

   if (queue_tail)
   {
      queue_tail->next = curr;
      queue_tail = curr;
   }
   else
      queue_head = queue_tail = curr;
}


void bfs_dequeue(void)
{
   BFS_DATA *curr;

   curr = queue_head;

   if (!(queue_head = queue_head->next))
      queue_tail = NULL;
   free(curr);
}


void bfs_clear_queue(void)
{
   while (queue_head)
      bfs_dequeue();
}

void room_enqueue(ROOM_INDEX_DATA * room)
{
   BFS_DATA *curr;

   curr = malloc(sizeof(BFS_DATA));
   curr->room = room;
   curr->next = room_queue;

   room_queue = curr;
}

void clean_room_queue(void)
{
   BFS_DATA *curr, *curr_next;

   for (curr = room_queue; curr; curr = curr_next)
   {
      UNMARK(curr->room);
      curr_next = curr->next;
      free(curr);
   }
   room_queue = NULL;
}


int find_first_step(ROOM_INDEX_DATA * src, ROOM_INDEX_DATA * target, int maxdist, int *steps)
{
   int curr_dir, count;
   EXIT_DATA *pexit;

   if (!src || !target)
   {
      bug("Illegal value passed to find_first_step (track.c)", 0);
      return BFS_ERROR;
   }

   if (src == target)
      return BFS_ALREADY_THERE;

   if (src->area != target->area)
      return BFS_NO_PATH;

   room_enqueue(src);
   MARK(src);

   /* first, enqueue the first steps, saving which direction we're going. */
   for (pexit = src->first_exit; pexit; pexit = pexit->next)
      if (valid_edge(pexit))
      {
         curr_dir = pexit->vdir;
         MARK(pexit->to_room);
         room_enqueue(pexit->to_room);
         bfs_enqueue(pexit->to_room, curr_dir);
      }

   count = 0;
   while (queue_head)
   {
      if (++count > maxdist)
      {
         bfs_clear_queue();
         clean_room_queue();
         return BFS_NO_PATH;
      }
      if (queue_head->room == target)
      {
         curr_dir = queue_head->dir;
         bfs_clear_queue();
         clean_room_queue();
         if (steps)
            *steps = count;
         return curr_dir;
      }
      else
      {
         for (pexit = queue_head->room->first_exit; pexit; pexit = pexit->next)
            if (valid_edge(pexit))
            {
               curr_dir = pexit->vdir;
               MARK(pexit->to_room);
               room_enqueue(pexit->to_room);
               bfs_enqueue(pexit->to_room, queue_head->dir);
            }
         bfs_dequeue();
      }
   }
   clean_room_queue();

   return BFS_NO_PATH;
}

char *get_wtrack_dir(CHAR_DATA *ch, CHAR_DATA *victim)
{
   int diffx, diffy;
   int distx, disty, total;
   
   diffx = victim->coord->x - ch->coord->x;
   diffy = victim->coord->y - ch->coord->y;
   distx = abs(ch->coord->x - victim->coord->x);
   disty = abs(ch->coord->y - victim->coord->y);
   total = distx+disty;
   
   if (total == 1)
   {
      if (diffy > 0)
         return "south";
      else if (diffy < 0)
         return "north";
      else if (diffx > 0)
         return "east";
      else
         return "west";
   }
   if (diffy >= total/2) //S
   {
      if (diffx >= total/2) //se
         return "southeast";
      else if (diffx <= total/-2) //sw
         return "southwest";
      else
         return "south";
   }
   if (diffy <= total/-2) //N
   {
      if (diffx >= total/2) //ne
         return "northeast";
      else if (diffx <= total/-2) //nw
         return "northwest";
      else
         return "north";
   }   
   if (diffx >= total/2) //E
   {
      if (diffy >= total/2) //se
         return "southeast";
      else if (diffy <= total/-2) //ne
         return "northeast";
      else
         return "east";
   }
   if (diffx <= total/-2) //W
   {
      if (diffy >= total/2) //we
         return "southwest";
      else if (diffy <= total/-2) //we
         return "northwest";
      else
         return "west";
   }    
   return "unknown";
}
   

void do_track(CHAR_DATA * ch, char *argument)
{
   CHAR_DATA *vict;
   char arg[MIL];
   char buf[MSL];
   char name[MSL];
   int dir, maxdist;
   sh_int level;
   sh_int percent;
   int steps;
   int fnd = 0;
   int cnt = 0;

   level = POINT_LEVEL(LEARNED(ch, gsn_track), MASTERED(ch, gsn_track));

   if (!IS_NPC(ch) && (ch->pcdata->learned[gsn_track] <= 0 || ch->pcdata->ranking[gsn_track] <= 0))
   {
      send_to_char("You do not know of this skill yet.\n\r", ch);
      return;
   }
   
   one_argument(argument, arg);
   
   if (argument[0] == '\0')
   {
      send_to_char("Syntax:  track <victim>\n\r", ch);
      send_to_char("Syntax:  track area [color] [color..]\n\r", ch);
      send_to_char("Color being: red pink yellow cyan white green\n\r", ch);
      return;
   }

   WAIT_STATE(ch, skill_table[gsn_track]->beats);
   
   if (!str_cmp(arg, "area"))
   {
      int red, pink, yellow, white, green, cyan;
      red=pink=yellow=white=green=cyan=1;
      
      argument = one_argument(argument, arg);
      
      if (argument[0] != '\0')
      {
         red=pink=yellow=white=green=cyan=0;
         for (;;)
         {
            argument = one_argument(argument, arg);
            if (arg[0] == '\0')
               break;
            else
            {
               if (!str_cmp(arg, "red"))
                  red = 1;
               if (!str_cmp(arg, "pink"))
                  pink = 1;
               if (!str_cmp(arg, "yellow"))
                  yellow = 1;
               if (!str_cmp(arg, "cyan"))
                  cyan = 1;
               if (!str_cmp(arg, "white"))
                  white = 1;
               if (!str_cmp(arg, "green"))
                  green = 1;
            }
         }
      }             
      for (vict = first_char; vict; vict = vict->next)
      {
         if (vict->in_room && vict->in_room->area == ch->in_room->area)
         {
            if (xIS_SET(vict->act, ACT_NOTRACK))
               continue;   
            if (!can_see_map(ch, vict))
               continue;
            if (IN_WILDERNESS(ch))
            {
               percent = UMIN(5+level/2, 45);
               if (abs(ch->coord->x - vict->coord->x) > percent || abs(ch->coord->y - vict->coord->y) > percent)
                  continue;       
               steps = UMAX(abs(ch->coord->x - vict->coord->x), abs(ch->coord->y - vict->coord->y));
               steps = steps * 5;
            }
            else
            {
               maxdist = 250;
               if (!IS_NPC(ch))
                  maxdist = (maxdist * level / 60);
               steps = 0;
               dir = find_first_step(ch->in_room, vict->in_room, maxdist, &steps);
               if (dir == BFS_NO_PATH || dir == BFS_ERROR)
                  continue;
            }
            percent = 50 + level;
            if (number_range(1, 100) > percent)
               continue;
            fnd++;
            sprintf(name, "%.20s", PERS_MAP_NAME(vict, ch));
            sprintf(buf, MXPFTAG("Command 'track \"%s\"' desc='Click here to track the target'", "%s", "/Command") "%s", 
              PERS_MAP_NAME(vict, ch), name, add_space(strlen(name), 20));
            if (steps <= 15 && red)
            {
               ch_printf(ch, "   &w&R%s", buf);
               cnt++;
            }
            else if (steps >= 16 && steps <= 35 && pink)
            {
               ch_printf(ch, "   &w&P%s", buf);
               cnt++;
            }
            else if (steps >= 36 && steps <= 60 && yellow)
            {
               ch_printf(ch, "   &w&Y%s", buf);
               cnt++;
            }
            else if (steps >= 61 && steps <= 100 && cyan)
            {
               ch_printf(ch, "   &w&c%s", buf);
               cnt++;
            }
            else if (steps >= 101 && steps <= 150 && white)
            {
               ch_printf(ch, "   &w&W%s", buf);
               cnt++;
            }
            else if (steps > 150 && green)
            {
               ch_printf(ch, "   &w&G%s", buf);
               cnt++;
            }
            else
               continue;
            if (cnt % 4 == 0)
               send_to_char("\n\r", ch);
         } 
      }
      if (fnd > 0)
         learn_from_success(ch, gsn_track, vict);
      if (cnt > 0)
         send_to_char("\n\r", ch);
      return;
   }
   if (!(vict = get_char_world(ch, arg)))
   {
      send_to_char("You can't find a trail of anyone like that.\n\r", ch);
      return;
   }

   if (xIS_SET(vict->act, ACT_NOTRACK))
   {
      send_to_char("You can't find a trail of anyone like that.\n\r", ch);
      return;
   }
   if (IN_WILDERNESS(ch) || IN_WILDERNESS(vict))
   {
      if (IN_WILDERNESS(ch) && IN_WILDERNESS(vict))
      {
         percent = UMIN(10+level, 90);
         if (abs(ch->coord->x - vict->coord->x) > percent || abs(ch->coord->y - vict->coord->y) > percent)
         {
            send_to_char("You cannot pickup a trail from here.\n\r", ch);
            learn_from_failure(ch, gsn_track, vict);
            return;
         }
         else
         {
            percent = 10 + level*3/2;
            if (number_range(1, 100) <= percent)
            {
               ch_printf(ch, "You sense %s is located to the %s\n\r", PERS_MAP_NAME(vict, ch), get_wtrack_dir(ch, vict));
               learn_from_success(ch, gsn_track, vict);
               return;
            }
            else
            {
               send_to_char("You cannot sense a trail from here.\n\r", ch);
               learn_from_failure(ch, gsn_track, vict);
               return;
            }
         }
      }
      else
      {
         send_to_char("You can't find a trail of anyone like that.\n\r", ch);
         return;
      }
   }

   maxdist = 500;
   if (!IS_NPC(ch))
      maxdist = (maxdist * level / 60);

   percent = 10 + level*3/2;
   if (number_range(1, 100) > percent)
   {
      send_to_char("You can't sense a trail from here.\n\r", ch);
      learn_from_failure(ch, gsn_track, vict);
      return;
   }   

   dir = find_first_step(ch->in_room, vict->in_room, maxdist, NULL);

   switch (dir)
   {
      case BFS_ERROR:
         send_to_char("Hmm... something seems to be wrong.\n\r", ch);
         break;
      case BFS_ALREADY_THERE:
         send_to_char("You're already in the same room!\n\r", ch);
         break;
      case BFS_NO_PATH:
         send_to_char("You can't sense a trail from here.\n\r", ch);
         learn_from_failure(ch, gsn_track, vict);
         break;
      default:
         ch_printf(ch, "You sense a trail %s from here...\n\r", dir_name[dir]);
         learn_from_success(ch, gsn_track, vict);
         break;
   }
}


void found_prey(CHAR_DATA * ch, CHAR_DATA * victim)
{
   char buf[MSL];
   char victname[MSL];

   if (victim == NULL)
   {
      bug("Found_prey: null victim", 0);
      return;
   }

   if (victim->in_room == NULL)
   {
      bug("Found_prey: null victim->in_room", 0);
      return;
   }
   if (!IS_AWAKE(ch) || IS_AFFECTED(ch, AFF_WEB))
      return;
   sprintf(victname, IS_NPC(victim) ? victim->short_descr : victim->name);

   if (!can_see(ch, victim))
   {
      if (number_percent() < 90)
         return;
      switch (number_bits(3))
      {
         case 0:
            sprintf(buf, "Don't make me find you, %s!", victname);
            do_say(ch, buf);
            break;
         case 1:
         case 2:
            act(AT_ACTION, "$n sniffs around the room for $N.", ch, NULL, victim, TO_NOTVICT);
            act(AT_ACTION, "You sniff around the room for $N.", ch, NULL, victim, TO_CHAR);
            act(AT_ACTION, "$n sniffs around the room for you.", ch, NULL, victim, TO_VICT);
            sprintf(buf, "I can smell your blood!");
            do_say(ch, buf);
            break;
         case 3:
            sprintf(buf, "I'm going to tear %s apart!", victname);
            do_yell(ch, buf);
            break;
         case 4:
         case 5:
            do_say(ch, "Just wait until I find you...");
            break;
         case 6:
         case 7:
            do_say(ch, "To hell with you...");
            stop_hunting(ch);
            stop_hating(ch);
            if (IN_WILDERNESS(ch))
               find_next_hunt(ch, 0);
            break;
      }
      return;
   }

   if (is_room_safe(ch))
   {
      if (number_percent() < 90)
         return;
      switch (number_bits(2))
      {
         case 0:
            do_say(ch, "C'mon out, you coward!");
            sprintf(buf, "%s is a bloody coward!", victname);
            do_yell(ch, buf);
            break;
         case 1:
            sprintf(buf, "Let's take this outside, %s", victname);
            do_say(ch, buf);
            break;
         case 2:
            sprintf(buf, "%s is a yellow-bellied wimp!", victname);
            do_yell(ch, buf);
            break;
         case 3:
            act(AT_ACTION, "$n takes a few swipes at $N.", ch, NULL, victim, TO_NOTVICT);
            act(AT_ACTION, "You try to take a few swipes $N.", ch, NULL, victim, TO_CHAR);
            act(AT_ACTION, "$n takes a few swipes at you.", ch, NULL, victim, TO_VICT);
            break;
      }
      return;
   }

   switch (number_bits(2))
   {
      case 0:
         sprintf(buf, "%s Your blood is mine!", victname);
         do_tell(ch, buf);
         break;
      case 1:
         sprintf(buf, "%s Alas, we meet again!", victname);
         do_tell(ch, buf);
         break;
      case 2:
         sprintf(buf, "%s What do you want on your tombstone?", victname);
         do_tell(ch, buf);
         break;
      case 3:
         act(AT_ACTION, "$n lunges at $N from out of nowhere!", ch, NULL, victim, TO_NOTVICT);
         act(AT_ACTION, "You lunge at $N catching $M off guard!", ch, NULL, victim, TO_CHAR);
         act(AT_ACTION, "$n lunges at you from out of nowhere!", ch, NULL, victim, TO_VICT);
   }
   //stop_hunting(ch);
   set_fighting(ch, victim);
   one_hit(ch, victim, TYPE_UNDEFINED, LM_BODY);
   return;
}

void hunt_victim(CHAR_DATA * ch)
{
   bool found;
   CHAR_DATA *tmp;
   EXIT_DATA *pexit;
   sh_int ret;
   int chance;

   if (!ch || !ch->hunting)
      return;
      
   if (ch->fight_timer > 0)
      return;
      
   /* make sure the char still exists */
   for (found = FALSE, tmp = first_char; tmp && !found; tmp = tmp->next)
      if (ch->hunting->who == tmp)
         found = TRUE;

   if (!found)
   {
      do_say(ch, "Damn!  My prey is gone!!");
      stop_hunting(ch);
      return;
   }

   if (ch->in_room == ch->hunting->who->in_room)
   {
      if (ch->fighting)
         return;
      found_prey(ch, ch->hunting->who);
      return;
   }

   ret = find_first_step(ch->in_room, ch->hunting->who->in_room, 500, NULL);
   if (ret < 0)
   {
      do_say(ch, "Damn!  Lost my prey!");
      stop_hunting(ch);
      return;
   }
   else
   {
      if ((pexit = get_exit(ch->in_room, ret)) == NULL)
      {
         bug("Hunt_victim: lost exit?", 0);
         return;
      }
      chance = get_hunt_cost(pexit->to_room);
      if (chance <= 1 || number_range(1, chance) == 1)
      {
         if (!xIS_SET(ch->act, ACT_MILITARY) || (xIS_SET(ch->act, ACT_MILITARY) && !xIS_SET(ch->miflags, KM_SENTINEL)))
            move_char(ch, pexit, FALSE);
      }
      if (!ch->hunting)
      {
         if (!ch->in_room)
         {
            bug("Hunt_victim: no ch->in_room!  Mob #%d, name: %s.  Placing mob in limbo.", ch->pIndexData->vnum, ch->name);
            char_to_room(ch, get_room_index(ROOM_VNUM_LIMBO));
            return;
         }
         do_say(ch, "Damn!  Lost my prey!");
         return;
      }
      if (ch->in_room == ch->hunting->who->in_room)
         found_prey(ch, ch->hunting->who);
      else
      {
         CHAR_DATA *vch;

         /* perform a ranged attack if possible */
         /* Changed who to name as scan_for_victim expects the name and
            * Not the char struct. --Shaddai
          */
         if ((vch = scan_for_victim(ch, pexit, ch->hunting->name)) != NULL)
         {
            if (!mob_fire(ch, ch->hunting->who->name, pexit->vdir))
            {
               /* ranged spell attacks go here */
            }
         }
      }
      return;
   }
}

/* Below is used to hunt/track on Wilderness Map */
int find_dir(int cx, int cy, int vx, int vy)
{
   if (cx > vx && cy > vy)
      return 7;
   if (cx < vx && cy > vy)
      return 6;
   if (cx > vx && cy < vy)
      return 9;
   if (cx < vx && cy < vy)
      return 8;
   if (cx == vx && cy > vy)
      return 0;
   if (cx == vx && cy < vy)
      return 2;
   if (cx > vx && cy == vy)
      return 3;
   if (cx < vx && cy == vy)
      return 1;

   return -1;
}
int get_x(int currx, int dir)
{
   if (dir == 6 || dir == 1 || dir == 8)
      return currx + 1;
   if (dir == 7 || dir == 3 || dir == 9)
      return currx - 1;

   return currx;
}
int get_y(int curry, int dir)
{
   if (dir == 7 || dir == 0 || dir == 6)
      return curry - 1;
   if (dir == 9 || dir == 2 || dir == 8)
      return curry + 1;

   return curry;
}

int find_slot(dir)
{
   if (dir == 0)
      return 1;
   if (dir == 6)
      return 2;
   if (dir == 1)
      return 3;
   if (dir == 8)
      return 4;
   if (dir == 2)
      return 5;
   if (dir == 9)
      return 6;
   if (dir == 3)
      return 7;
   if (dir == 7)
      return 8;

   return 0;
}

int alt_dir(CHAR_DATA * ch, int x, int y, int dir)
{
   int gox;
   int goy;
   int godir;
   int newdir;
   int addto;
   int tries;

   const int spin[25] = {
      0, 0, 6, 1, 8, 2, 9, 3, 7, 0, 6, 1, 8, 2, 9, 3, 7, 0, 6, 1, 8, 2, 9, 3, 7
   };

   for (tries = 1; tries < 9; tries++)
   {
      addto = find_slot(dir);
      if (tries % 2 == 1)
         godir = ((tries + 1) / 2);
      else
         godir = (tries / 2);

      if (tries != 9)
         if (tries % 2 == 1)
            newdir = spin[8 + addto + godir];
         else
            newdir = spin[8 + addto - godir];
      else
         newdir = spin[8 + addto - 4];

      gox = get_x(x, newdir);
      goy = get_y(y, newdir);

      if (sect_show[(int)map_sector[ch->map][gox][goy]].canpass == FALSE
      || is_set_wilderness(ch, ROOM_NO_MOB, gox, goy, ch->map))
         continue;
      else
         return newdir;
   }
   return -1;
}

// 0 - Wilderness 1 -Battle
int go_find_victim(CHAR_DATA * ch, CHAR_DATA * victim, int type)
{
   sh_int dir;
   sh_int count;
   sh_int numcount;
   sh_int times;
   sh_int locount[10];
   sh_int lo = 1000;
   sh_int lonum = -1;
   sh_int initdir[10];
   sh_int currx, curry, gox, goy;

   if (ch->coord->x == victim->coord->x && ch->coord->y == victim->coord->y && ch->map == victim->map)
      return -2;
   if (ch->in_room->area != victim->in_room->area)
   {
      return -1;
   }

   numcount = 15;
   if (xIS_SET(ch->act, ACT_MILITARY))
      numcount = ch->m6 + 2;

   for (times = 0; times < 5; times++)
   {
      currx = ch->coord->x;
      curry = ch->coord->y;
      for (count = 1; count <= numcount; count++)
      {
         dir = find_dir(currx, curry, victim->coord->x, victim->coord->y);
         gox = get_x(currx, dir);
         goy = get_y(curry, dir);
         if (sect_show[(int)map_sector[ch->map][gox][goy]].canpass == FALSE || map_sector[ch->map][gox][goy] == SECT_EXIT
         || is_set_wilderness(ch, ROOM_NO_MOB, gox, goy, ch->map))
         {
            dir = alt_dir(ch, currx, curry, dir);
            gox = get_x(currx, dir);
            goy = get_y(curry, dir);
         }
         if (count == 1)
            initdir[times] = dir;
         currx = gox;
         curry = goy;
         if (currx == victim->coord->x && curry == victim->coord->y)
            break;

         if (count == numcount)
            count = 1000;
      }
      locount[times] = count;
   }
   for (times = 0; times < 5; times++)
   {
      if (locount[times] < lo)
      {
         lo = locount[times];
         lonum = times;
      }
   }
   if (lo >= 1000 || lonum == -1)
      return -1;
   else
      return initdir[lonum];
}

int get_distform args((int x, int y, int vx, int vy));
void hunt_victim_map(CHAR_DATA * ch)
{
   bool found;
   CHAR_DATA *tmp;
   CHAR_DATA *vch;
   OBJ_DATA *bow;
   sh_int ret, chance;
   sh_int maxx, maxy;
   sh_int x, y;

   if (!ch || !ch->hunting)
      return;

   x = ch->coord->x;
   y = ch->coord->y;
   maxx = MAX_X;
   maxy = MAX_Y;
   
   if (ch->fight_timer > 0)
      return;
   
   /* make sure the char still exists */
   for (found = FALSE, tmp = first_char; tmp && !found; tmp = tmp->next)
      if (ch->hunting->who == tmp)
         found = TRUE;

   if (!found)
   {
      do_say(ch, "Damn!  My prey is gone!!");
      stop_hunting(ch);
      find_next_hunt(ch, 0);
      return;
   }

    if (ch->coord->x == ch->hunting->who->coord->x && ch->coord->y == ch->hunting->who->coord->y && ch->map == ch->hunting->who->map)
    {
      if (ch->fighting)
         return;
      found_prey(ch, ch->hunting->who);
      return;
   }

   ret = go_find_victim(ch, ch->hunting->who, 0);

   if (ret < 0)
   {
      if (ret == -1)
      {
         do_say(ch, "Damn!  Lost my prey!");
         stop_hunting(ch);
         find_next_hunt(ch, 0);
         return;
      }
   }
   else
   {
      switch (ret)
      {
         case DIR_NORTH:
            y -= 1;
            break;
         case DIR_EAST:
            x += 1;
            break;
         case DIR_SOUTH:
            y += 1;
            break;
         case DIR_WEST:
            x -= 1;
            break;
         case DIR_NORTHEAST:
            x += 1;
            y -= 1;
            break;
         case DIR_NORTHWEST:
            x -= 1;
            y -= 1;
            break;
         case DIR_SOUTHEAST:
            x += 1;
            y += 1;
            break;
         case DIR_SOUTHWEST:
            x -= 1;
            y += 1;
            break;
      }
      switch (ret)
      {
         case DIR_NORTH:
            if (y == 0)
               return;
            break;

         case DIR_EAST:
            if (x == maxx + 1)
               return;
            break;

         case DIR_SOUTH:
            if (y == maxy + 1)
               return;
            break;

         case DIR_WEST:
            if (x == 0)
               return;
            break;

         case DIR_NORTHEAST:
            if (x == maxx + 1 || y == 0)
               return;
            break;

         case DIR_NORTHWEST:
            if (x == 0 || y == 0)
               return;
            break;

         case DIR_SOUTHEAST:
            if (x == maxx + 1 || y == maxy + 1)
               return;
            break;

         case DIR_SOUTHWEST:
            if (x == 0 || y == maxy + 1)
               return;
            break;
      }
      vch = ch->hunting->who;
      //Why would an archer chase down a target when it can fire at it?
      if (xIS_SET(ch->act, ACT_MILITARY)
         && (bow = get_eq_char(ch, WEAR_MISSILE_WIELD)) != NULL
         && get_distform(ch->coord->x, ch->coord->y, vch->coord->x, vch->coord->y) <= URANGE(1, bow->value[3], 10)
         && mob_fire(ch, ch->hunting->who->name, 1))
      {
         ;
      }
      else
      {
         chance = get_wilderness_hunt_cost(ch, x, y);
         if (chance <= 1 || number_range(1, chance) == 1)
         {
            if (!xIS_SET(ch->act, ACT_MILITARY) || (xIS_SET(ch->act, ACT_MILITARY) && !xIS_SET(ch->miflags, KM_SENTINEL)))
            { 
               if (IS_AWAKE(ch) && !IS_AFFECTED(ch, AFF_WEB))
               {
                  ch->coord->x = x;
                  ch->coord->y = y;
                  update_objects(ch, 0, 0, 0);
               }
            }
         }
      }
      if (!ch->hunting)
      {
         if (!ch->in_room)
         {
            bug("Hunt_victim: no ch->in_room!  Mob #%d, name: %s.  Placing mob in limbo.", ch->pIndexData->vnum, ch->name);
            char_to_room(ch, get_room_index(ROOM_VNUM_LIMBO));
            return;
         }
         do_say(ch, "Damn!  Lost my prey!");
         return;
      }
      if (ch->coord->x == ch->hunting->who->coord->x && ch->coord->y == ch->hunting->who->coord->y && ch->map == ch->hunting->who->map)
         found_prey(ch, ch->hunting->who);
      return;
   }
}