/* borg_goals.c  main goal routines */
#include "angband.h"

#ifdef AUTO_PLAY

/* this is not the main routine */
#define EXTERN extern
#include "borg.h"
#undef EXTERN
#define EXTERN /* normal */





/*
 * Prepare to think -- "dungeon screen"
 */
EXTERN bool borg_prepare_start(void)
{
    int i, x, y, lev;
    
    auto_grid *ag;
    auto_room *ar;

    byte t_a;

    cptr s;
    
    char buf[128];

#ifdef FRITSDEBUG
   borg_note("In routine borg_prepare_start()");
#endif /* FRITSDEBUG */

    /* Increase the "time" */
    c_t++;
    

    /* Clear all the "state flags" */
    do_heal = do_food = do_lite = do_torch = do_flask = FALSE;
    do_blind = do_confused = do_afraid = do_poisoned = FALSE;
#ifdef FRITS
    do_study = do_chest = FALSE;
/*    do_watch_breeders = 0L;  */  
/* keep the breeders */
#endif /* FRITS */

#ifdef FRITS
    /* Extract pclass */
    if (0==Term_what_text(0,2,-10,&t_a,buf)) {
       if (!strncmp(buf,"Warrior",7))
       {
          pclass=PCLASS_WARRIOR;
          sclass=SCLASS_NONE;
       } else if (!strncmp(buf,"Mage",4))
       {
          pclass=PCLASS_MAGE;
          sclass=SCLASS_MAGE;
       } else if (!strncmp(buf,"Priest",6))
       {
          pclass=PCLASS_PRIEST;
          sclass=SCLASS_PRIEST;
       } else if (!strncmp(buf,"Rogue",5))
       {
          pclass=PCLASS_ROGUE;
          sclass=SCLASS_MAGE;
       } else if (!strncmp(buf,"Ranger",6))
       {
          pclass=PCLASS_RANGER;
          sclass=SCLASS_MAGE;
       } else if (!strncmp(buf,"Paladin",7))
       {
          pclass=PCLASS_PALADIN;
          sclass=SCLASS_PRIEST;
       } 
    }


    /* Extract stats (see if drained) */
    for (i=0;i<6;i++) {
       if (((drained_stat & (1<<i))==0) && 
          (0 == Term_what(6, ROW_STAT + i, &t_a, &buf[0])) ) {
          if (t_a==11) /* TERM_YELLOW attribute? 13 is normal */
          {
             borg_note(format("FUCK! Stat drain...(%s) :-(",statstring[i]));
             drained_stat = (drained_stat | (1<<i));
          }
          Term_what_text(6,ROW_STAT+i,-6,&t_a,buf);
	  auto_stat[i]=stat2int(buf);
       }
    }
#endif /* FRITS */


    /* Extract current hitpoints */
    if (0 == Term_what_text(6, ROW_LEVEL, -6, &t_a, buf)) {
	auto_level = atoi(buf);
    }

#ifdef FRITS
    /* Check experience drain */
    if ((0 == Term_what(COL_EXP, ROW_EXP, &t_a, &buf[0])) &&
       ((drained_stat & (1<<6))==0) ) {
	if (t_a==11) {
             borg_note(format("FUCK! Experience drain... :-(",i));
             drained_stat = (drained_stat | (1<<6));
        }
    }
#endif /* FRITS */

    /* Extract current hitpoints */
    if (0 == Term_what_text(6, ROW_CURHP, -6, &t_a, buf)) {
	auto_curhp = atoi(buf);
    }

    /* Extract maximum hitpoints */
    if (0 == Term_what_text(6, ROW_MAXHP, -6, &t_a, buf)) {
	auto_maxhp = atoi(buf);
    }

#ifdef FRITS
    /* Extract current manapoints */
    if (0 == Term_what_text(6, ROW_MANA, -6, &t_a, buf)) {
	auto_curmana = atoi(buf);
        if (t_a==13) auto_maxmana=auto_curmana;
    }
#endif /* FRITS */

    /* Extract current gold */
    if (0 == Term_what_text(COL_GOLD, ROW_GOLD, -9, &t_a, buf)) {
	auto_gold = atol(buf);
    }



    /* Check for hunger */
    if (0 == Term_what_text(COL_HUNGRY, ROW_HUNGRY, 6, &t_a, buf)) {
        if (streq(buf, "Hungry")) do_food = TRUE;
        if (streq(buf, "Weak  ")) {do_food = TRUE;do_starve=TRUE;}
    }

    /* Check for blind */
    if (0 == Term_what_text(COL_BLIND, ROW_HUNGRY, 5, &t_a, buf)) {
        if (streq(buf, "Blind")) do_blind = TRUE;
    }

    /* Check for confused */
    if (0 == Term_what_text(COL_CONFUSED, ROW_HUNGRY, 8, &t_a, buf)) {
        if (streq(buf, "Confused")) do_confused = TRUE;
    }

    /* Check for afraid */
    if (0 == Term_what_text(COL_AFRAID, ROW_HUNGRY, 6, &t_a, buf)) {
        if (streq(buf, "Afraid")) do_afraid = TRUE;
    }

    /* Check for poisoned */
    if (0 == Term_what_text(COL_POISONED, ROW_HUNGRY, 8, &t_a, buf)) {
        if (streq(buf, "Poisoned")) do_poisoned = TRUE;
    }

#ifdef FRITS
    /* Gain some spells */
    if (0 == Term_what_text(COL_STUDY, ROW_HUNGRY, 5, &t_a, buf)) {
       /* DANGEROUS */
       /*
        if (streq(buf, "Study")) do_study = TRUE;
       */
    }
#endif /* FRITS */


    /* Determine if we are about to die */
    if (auto_curhp < auto_maxhp / 4) do_heal = TRUE;
    


    /* Extract the "current level" */
    if (Term_what_text(70, 23, -7, &t_a, buf)) strcpy(buf, "");
    for (s = buf; *s && !isdigit(*s); s++);
    lev = atoi(s);


    /* Notice changes in the level */
    if (auto_depth != lev) {

	/* Restart the clock */
	c_t = 10000L;

	/* Start a new level */
	auto_began = c_t;

	/* Shocking */
	auto_shock = c_t;

	/* No word of recall yet */
	auto_recall = 0L;
	
	/* No stairs yet */
	goal_level = 0;
	
	/* No "real" rooms yet */
	auto_room_max = 0;


	
	/* Clean up the rooms */
	for (i = 0; i < AUTO_ROOMS; i++) {

	    /* Access the room */
	    ar = &auto_rooms[i];

	    /* Never seen it */
	    ar->when = 0L;

	    /* Paranoia -- No location yet */
	    ar->x1 = ar->x2 = ar->y1 = ar->y2 = 0;
	    
	    /* Not in the queue */
	    ar->next = ar->prev = NULL;
	    
	    /* No flow */
	    ar->flow = 0;
	    
	    /* Paranoia -- Visit the corner */
	    ar->x = ar->y = 0;

	    /* Hack -- Prepare the "free list" index */
	    ar->free = i + 1;
	}

	/* Hack -- note when we run out of free rooms */
	auto_rooms[AUTO_ROOMS-1].free = 0;
	
	/* Clean up the grids */
	for (y = 0; y < AUTO_MAX_Y; y++) {
	    for (x = 0; x < AUTO_MAX_X; x++) {

		/* Access the grid */
		ag = grid(x, y);

		/* No room yet */
		ag->room = 0;

		/* Black means unknown (?) */
		ag->o_a = 0;

		/* Space means unseen */
		ag->o_c = ' ';
	    }
	}


	/* Hack -- mark the edge of the map as walls */
	for (y = 0; y < AUTO_MAX_Y; y++) {

	    /* West edge */
	    ag = grid(0, y);
	    ag->o_a = TERM_WHITE;
	    ag->o_c = '#';
	    
	    /* East edge */
	    ag = grid(AUTO_MAX_X - 1, y);
	    ag->o_a = TERM_WHITE;
	    ag->o_c = '#';
	}	    
    
	/* Hack -- mark the edge of the map as walls */
	for (x = 0; x < AUTO_MAX_X; x++) {

	    /* West edge */
	    ag = grid(x, 0);
	    ag->o_a = TERM_WHITE;
	    ag->o_c = '#';
	    
	    /* East edge */
	    ag = grid(x, AUTO_MAX_Y - 1);
	    ag->o_a = TERM_WHITE;
	    ag->o_c = '#';
	}	    
    

	/* No goal yet */
	goal = 0;
	
	/* Save the new level */
	auto_depth = lev;
    }


    /* Forget the old player grid */
    pg = NULL;

    /* Cheat -- assume that we know the current "map sector" */

    /* Analyze the current (66x22 grid) map sector */
    for (y = panel_row_min; y <= panel_row_max; y++) {
        for (x = panel_col_min; x <= panel_col_max; x++) {

	    /* White means dark */
	    byte a = TERM_WHITE;

	    /* Space means unseen */
	    char c = ' ';
	
	    /* Examine the "screen" (correctly adjusted) */
	    Term_what(x - panel_col_prt, y - panel_row_prt, &a, &c);

	    /* Notice the player */
	    if (c == '@') {

		/* Extract the player grid */
		c_x = x; c_y = y;
		
		/* Get the player's grid */
		pg = grid(c_x, c_y);

		/* Treat the grid as "unseen" */
		c = ' ';
	    }
	
	    /* Hack -- Ignore "blank" information */
	    if (!a || (c == ' ')) continue;

	    /* Hack -- Assume all floors and walls are white */
	    if (strchr("#%.", c)) a = TERM_WHITE;
	
	    /* Get the auto_grid */
	    ag = grid(x, y);

	    /* Notice exciting things */
	    if (ag->o_c == ' ') {

		/* We are shocked */
		auto_shock = c_t;

		/* Cancel stair request */
		goal_level = 0;
	    }
	    
	    /* Save the "screen info" */
	    ag->o_a = a; ag->o_c = c;
	}
    }
    
    /* Paranoia -- make sure we exist */
    if (!pg) {
	borg_oops("Player missing!");
	return (TRUE);
    }    


    /* Make sure every visited grid has a room */
    if (!pg->room) {

	/* Acquire a "free" room */
	i = auto_rooms[0].free;
	auto_rooms[0].free = auto_rooms[i].free;
	auto_rooms[i].free = 0;

	/* Paranoia */
	if (!i) core("Borg ran out of free rooms");
	
	/* Take note of new "maximums" */
	if (i + 1 > auto_room_max) auto_room_max = i + 1;
	
	/* Access the new room */
	ar = &auto_rooms[i];
	
	/* Initialize the room */
	ar->flow = 0;	
	ar->x1 = ar->x2 = ar->x = c_x;
	ar->y1 = ar->y2 = ar->y = c_y;

	/* Saw this room */
	ar->when = c_t;

	/* Save the room */
	pg->room = i;
    }
    
    
    /* Occasionally, try to build better rooms */
    if (borg_build_room(c_x, c_y)) {

	/* Note that the room builder can kill "flow" goals */
	if (goal == GOAL_FLOW) goal = 0;
    }
    
    
    /* Mark all the "containing rooms" as visited. */
    for (ar = room(1,c_x,c_y); ar; ar = room(0,0,0)) ar->when = c_t;


    /* Hack -- build the "near" array */
    near_n = 0;
    
    /* Check all of the grids on the current screen */
    for (y = panel_row_min; y <= panel_row_max; y++) {
        for (x = panel_col_min; x <= panel_col_max; x++) {

	    /* Cheat -- use the underlying "los()" macro */
	    /* Hack -- Add "viewable" ones to the array */
	    if (player_has_los_bold(y, x)) {

		/* Save the grid */
		if (near_n < NEAR_MAX) {
		    near_x[near_n] = x;
		    near_y[near_n] = y;
		    near_n++;
		}
	    }
	}
    }

#ifdef FRITS
    if (do_study) {
       /* attempt to study */
    }
#endif /* FRITS */

    
    /* XXX XXX XXX Hack -- must cheat */
    cheat_inven = cheat_equip = TRUE;


    /* Send the "inventory" command */
    if (!cheat_inven) borg_keypress('i');
    
    /* Enter next state */
    state = STATE_INVEN;

    /* All done */
    return (TRUE);
}



/*
 * Given a location, attempt to determine what type of monster is
 * at that location.  Use type "0" for "no known monster".
 */
EXTERN int guess_monster(int x, int y)
{
    int i;

    auto_grid *ag = grid(x, y);

#ifdef FRITSDEBUG
   borg_note("In routine borg_guess_monster()");
#endif /* FRITSDEBUG */

    /* Efficiency */
    if (ag->o_c == ' ') return (0);
    if (ag->o_c == '.') return (0);
    if (ag->o_c == '#') return (0);
    if (ag->o_c == '%') return (0);

#ifdef FRITS
    if ((ag->o_c == 'w') || (ag->o_c == 'l') || 
        (ag->o_c == ',') || (ag->o_c == 'F') || (ag->o_c == 'r') ) {
       if (do_watch_breeders == 0L) 
          borg_note("Watchout! Possible breeder monsters.");
       do_watch_breeders++;
       if ((do_watch_breeders % 50L) == 0L)
          borg_note(format("** Killed %d breeders just now **",do_watch_breeders));
    } else {
       if (do_watch_breeders != 0L)
       {
          borg_note("No more breeder monsters. Phew!");
          borg_note(format("After %d breeders, this one is a %c",do_watch_breeders,ag->o_c));
       }
       do_watch_breeders=0L;
    }
#endif /* FRITS */

    /* Special treatment of "town" monsters */
    if (auto_depth <= 0) {

	/* Find the first acceptable monster */
	for (i = 1; i < MAX_R_IDX-1; i++) {
	    
	    if (r_list[i].level) break;
	    
	    if (ag->o_c != r_list[i].r_char) continue;
	    if (ag->o_a != r_list[i].r_attr) continue;

	    return (i);
	}
    }

    /* Guess what monster it might be */
    else {

	/* Find the highest "acceptable" monster */
	for (i = MAX_R_IDX-1; i > 0; i--) {
	    
	    if (r_list[i].level > auto_depth + 5) continue;
	    
	    if (ag->o_c != r_list[i].r_char) continue;
	    if (ag->o_a != r_list[i].r_attr) continue;

	    return (i);
	}
	
    }


    /* Oops */
    return (0);
}



/*
 * Is a grid "okay" for us to run into
 *
 * This routine is ONLY called by "borg_goto_dir()".
 */
EXTERN bool borg_okay_grid(int x, int y)
{
    auto_grid *ag = grid(x, y);
    
    /* Try not to walk into walls */
    if (strchr("#%", ag->o_c)) return (FALSE);
    
    /* Try not to walk into stores */
    if (strchr("12345678", ag->o_c)) return (FALSE);
    
    /* Try to avoid monsters unless in "killing" mode */
    if ((goal != GOAL_KILL) && strchr(auto_str_kill, ag->o_c)) return (FALSE);

    /* Assume okay */
    return (TRUE);
}


/*
 * Given a "source" and "target" locations, extract a "direction",
 * which will move one step from the "source" towards the "target".
 */
EXTERN int borg_extract_dir(int x1, int y1, int x2, int y2)
{
    /* Stay still */
    if ((y1 == y2) && (x1 == x2)) return (5);

    /* No x-motion */
    if (x1 == x2) return ((y1 < y2) ? 2 : 8);

    /* No y-motion */
    if (y1 == y2) return ((x1 < x2) ? 6 : 4);

    /* South */
    if (y1 < y2) return ((x1 < x2) ? 3 : 1);

    /* North */
    if (y1 > y2) return ((x1 < x2) ? 9 : 7);

    /* Oops */
    return (5);
}


/*
 * Given a "source" and "target" locations, extract a "direction",
 * which will move one step from the "source" towards the "target".
 * Attempt to avoid walls if possible.  Return "0" if none.
 */
EXTERN int borg_goto_dir(int x1, int y1, int x2, int y2)
{
    int d;
    

    /* Special case -- next to (or on) the goal */
    if ((ABS(y2-y1) <= 1) && (ABS(x2-x1) <= 1)) {
	return (borg_extract_dir(x1, y1, x2, y2));
    }

    
    /* Try to do the "horizontal" */
    if (ABS(y2 - y1) < ABS(x2 - x1)) {
	d = borg_extract_dir(x1, y1, x2, y1);
	if (borg_okay_grid(x1 + ddx[d], y1 + ddy[d])) return (d);
    }
    
    /* Try to do the "vertical" */
    if (ABS(y2 - y1) > ABS(x2 - x1)) {
	d = borg_extract_dir(x1, y1, x1, y2);
	if (borg_okay_grid(x1 + ddx[d], y1 + ddy[d])) return (d);
    }
    

    /* Try to walk "directly" there */
    d = borg_extract_dir(x1, y1, x2, y2);
    
    /* Check for walls */
    if (borg_okay_grid(x1 + ddx[d], y1 + ddy[d])) return (d);
    
    
    /* Try the "vertical" instead (includes "diagonal") */
    if (ABS(y2 - y1) <= ABS(x2 - x1)) {
	d = borg_extract_dir(x1, y1, x1, y2);
	if (borg_okay_grid(x1 + ddx[d], y1 + ddy[d])) return (d);
    }

    /* Try the "horizontal" instead (includes "diagonal") */
    if (ABS(y2 - y1) >= ABS(x2 - x1)) {
	d = borg_extract_dir(x1, y1, x2, y1);
	if (borg_okay_grid(x1 + ddx[d], y1 + ddy[d])) return (d);
    }
    
    
    /* Hack -- directly "vertical", try "shaking" */
    if (x2 == x1) {
    
	/* Shake to the east */
	d = borg_extract_dir(x1, y1, x1+1, y2);
	if (borg_okay_grid(x1 + ddx[d], y1 + ddy[d])) return (d);
    
	/* Shake to the west */
	d = borg_extract_dir(x1, y1, x1-1, y2);
	if (borg_okay_grid(x1 + ddx[d], y1 + ddy[d])) return (d);
    }
    
    /* Hack -- directly "horizontal", try "shaking" */
    if (y2 == y1) {
    
	/* Shake to the south */
	d = borg_extract_dir(x1, y1, x2, y1+1);
	if (borg_okay_grid(x1 + ddx[d], y1 + ddy[d])) return (d);
    
	/* Shake to the north */
	d = borg_extract_dir(x1, y1, x2, y1-1);
	if (borg_okay_grid(x1 + ddx[d], y1 + ddy[d])) return (d);
    }
    

    /* Hack -- Surrounded by obstacles. */
    d = borg_extract_dir(x1, y1, x2, y2);
    
    /* Let the calling routine check the result */
    return (d);
}


/*
 * Process a "goto" goal, return "TRUE" if goal is still okay.
 */
EXTERN bool borg_play_step(int x, int y)
{
    auto_grid *ag;
    
    int dir;

#ifdef FRITSDEBUG
   borg_note("In routine borg_play_step()");
#endif /* FRITSDEBUG */

    /* We have arrived */
    if ((c_x == x) && (c_y == y)) return (FALSE);
    
    /* Get a direction (may be a wall there) */
    dir = borg_goto_dir(c_x, c_y, x, y);


    /* Access the grid we are stepping on */
    ag = grid(c_x + ddx[dir], c_y + ddy[dir]);

    /* Must "disarm" traps */
    if (ag->o_c == '^') {
        borg_keypress('D');
    }

    /* Must "open" (or "bash") doors */
    else if (ag->o_c == '+') {
#ifdef FRITS
        if (rand_int(100) > 1) borg_keypress('B');
        else if (ag->o_c == '+') borg_keypress('o');
#endif /* FRITS */
        if (rand_int(100) == 0) borg_keypress('B');
        else if (ag->o_c == '+') borg_keypress('o');
    }

    /* Tunnel through rubble */
    else if (strchr(":", ag->o_c)) {
        borg_keypress('T');
    }

    /* Tunnel through walls/seams */
    /* Hack -- eventually, give up */
    else if (strchr("#%", ag->o_c)) {
	if (rand_int(5) == 0) goal = 0;
        borg_keypress('T');
    }

    /* XXX Hack -- Occasionally, tunnel for gold */
    else if (strchr("$*", ag->o_c) && (rand_int(10) == 0)) {
        borg_keypress('T');
    }
    
    /* XXX XXX XXX Hack -- Occasionally, tunnel anyway */
    else if (rand_int(1000) == 0) {
        borg_keypress('T');
    }
    
    /* Walk (or tunnel or open or bash) in that direction */
    borg_keypress('0' + dir);
    
    /* Sometimes prepare to enter a "store" */
    if (strchr("12345678", ag->o_c)) {
	state_store = (ag->o_c - '0');
        state = STATE_STORE;
    }
    

    /* Hack -- prepare to take stairs if desired */
    if ((ag->o_c == '<') && (goal_level < 0)) borg_keypress('<');
    if ((ag->o_c == '>') && (goal_level > 0) && (!auto_recall) ) borg_keypress('>');

    
    /* Did something */
    return (TRUE);
}


/*
 * Attempt to fire at the given location
 */
EXTERN bool borg_play_fire(int x2, int y2)
{
    int i, x1 = c_x, y1 = c_y;

    auto_grid *ag;
    
#ifdef FRITSDEBUG
   borg_note("In routine borg_play_fire()");
#endif /* FRITSDEBUG */

    /* Only a one in five chance */
    if (rand_int(5) != 0) return (FALSE);
    
    /* Paranoia -- Must be "on screen" */
    if (!panel_contains(y2, x2)) return (FALSE);


    /* Must not be adjacent */
    if (distance(y1, x1, y2, x2) <= 1) return (FALSE);

    /* Must not be too far away */
    if (distance(y1, x1, y2, x2) > 10) return (FALSE);

    /* Must have "missile line of sight" */
    if (!borg_projectable(y1, x1, y2, x2)) return (FALSE);


    /* XXX Hack -- do not "fire" at mushrooms/skeletons */
    ag = grid(x2, y2);
    if (ag->o_c == ',') return (FALSE);
    if (ag->o_c == 's') return (FALSE);
    
    
    /* XXX Prefer "correct" missiles */

    /* Find an arrow or something */
    for (i = 0; i < INVEN_PACK; i++) {
	if (auto_items[i].tval == TV_BOLT) break;
	if (auto_items[i].tval == TV_ARROW) break;
	if (auto_items[i].tval == TV_SHOT) break;
    }

    /* Nothing to fire */
    if (i == INVEN_PACK) return (FALSE);


    /* Fire! */
    borg_keypress('f');
    borg_keypress('a' + i);

    /* Target the location */
    borg_keypress('*');
    borg_keypress('p');
    
    /* Start at the player */
    x1 = c_x; y1 = c_y;
    
    /* Move to the location */
    for ( ; y1 < y2; y1++) borg_keypress('2');
    for ( ; y1 > y2; y1--) borg_keypress('8');
    for ( ; x1 < x2; x1++) borg_keypress('6');
    for ( ; x1 > x2; x1--) borg_keypress('4');

    /* Select the target */
    borg_keypress('t');
    
    /* Success */
    return (TRUE);
}


/*
 * Process the current goal
 *
 * Note that "goto", "take", and "kill" are "identical".
 *
 * Return TRUE if this goal is still "okay".
 * Otherwise, cancel the goal and return FALSE.
 */
EXTERN bool borg_play_old_goal(void)
{
    auto_grid *ag;
    auto_room *ar;
    
#ifdef FRITSDEBUG
   borg_note("In routine borg_play_old_goal()");
#endif /* FRITSDEBUG */

    /* Process "KILL" goals */
    if (goal == GOAL_KILL) {

	/* Get the goal grid */
	ag = grid(g_x, g_y);
    
	/* Verify match, attempt a step */
	if ((ag->o_a == g_a) && (ag->o_c == g_c)) {

#ifdef FRITS
            /* Try magic */
            if (auto_curmana > auto_maxmana/2) {
               if (sclass==SCLASS_PRIEST) {
                  if(borg_cast_spell_at(SCLASS_PRIEST,'c','b',g_x,g_y)==TRUE) return(TRUE);
               } else { /* must be mage */
                  if (auto_level<10) {
                     if (rand_int(3)>0)
                     if(borg_cast_spell_at(SCLASS_MAGE,'a','a',g_x,g_y)==TRUE) return(TRUE);
                        else
                     if(borg_cast_spell_at(SCLASS_MAGE,'a','i',g_x,g_y)==TRUE) return(TRUE);
                  } else { 
                    if (auto_level < 20) {
                      switch(rand_int(10)) {
                       case 0:
                        break;
                       case 1:
                       if(borg_cast_spell_at(SCLASS_MAGE,'a','a',g_x,g_y)==TRUE) return(TRUE);
                        break;
                       case 2:
                       case 3:
                       if(borg_cast_spell_at(SCLASS_MAGE,'a','i',g_x,g_y)==TRUE) return(TRUE);
                        break;
                       case 4:
                       case 5:
                       case 6:
                       if(borg_cast_spell_at(SCLASS_MAGE,'b','b',g_x,g_y)==TRUE) return(TRUE);
                        break;
                       case 7:
                       if(borg_cast_spell_at(SCLASS_MAGE,'b','g',g_x,g_y)==TRUE) return(TRUE);
                        break;
                       default:
                       if(borg_cast_spell_at(SCLASS_MAGE,'b','h',g_x,g_y)==TRUE) return(TRUE);
                        break;
                     }
                    } else {
                       if(borg_cast_spell_at(SCLASS_MAGE,'c','g',g_x,g_y)==TRUE) return(TRUE);
                    }
                  }
               }
            }
#endif /* FRITS */

	    /* Try shooting */
	    if (borg_play_fire(g_x, g_y)) return (TRUE);
	    
	    /* Try walking */
	    if (borg_play_step(g_x, g_y)) return (TRUE);
	}
    }

    /* Process "GOTO" goals */
    else if (goal == GOAL_GOTO) {

	/* Get the goal grid */
	ag = grid(g_x, g_y);
    
	/* Verify match, attempt a step */
	if ((ag->o_a == g_a) && (ag->o_c == g_c) &&
	    borg_play_step(g_x, g_y)) return (TRUE);
    }

    /* Process "TAKE" goals */
    else if (goal == GOAL_TAKE) {

	/* Get the goal grid */
	ag = grid(g_x, g_y);
    
	/* Verify match, attempt a step */
	if ((ag->o_a == g_a) && (ag->o_c == g_c) &&
	    borg_play_step(g_x, g_y)) return (TRUE);
    }

    /* Process "FLOW" goals */
    else if (goal == GOAL_FLOW) {

	int x = c_x, y = c_y, cost = MAX_SHORT;

	/* Scan all the rooms we are in */
	for (ar = room(1,c_x,c_y); ar; ar = room(0,0,0)) {
	    if (ar->flow >= cost) continue;
	    x = ar->x; y = ar->y; cost = ar->flow;
	}
	
	/* Try to take a "step", or cancel the goal */
	if ((cost < MAX_SHORT) && (borg_play_step(x, y))) return (TRUE);
    }
    

    /* Cancel the goal */
    goal = 0;

    /* Nothing to do */
    return (FALSE);
}




/*
 * Determine if the queue is empty
 */
EXTERN bool borg_flow_empty(void)
{
    /* Semi-Hack -- Test for Empty Queue. */
    if (auto_flow_head.next == &auto_flow_tail) return (TRUE);
    if (auto_flow_tail.prev == &auto_flow_head) return (TRUE);

    /* Must have entries */
    return (FALSE);
}



/*
 * Dequeue from the "priority queue" of "auto_flow" records
 */
EXTERN auto_room *borg_flow_dequeue(void)
{
    auto_room *ar;

    /* Hack -- check for empty */
    if (borg_flow_empty()) return (NULL);
        
    /* Access the first node in the queue */
    ar = auto_flow_head.next;
    
    /* Dequeue the entry */
    ar->next->prev = ar->prev;
    ar->prev->next = ar->next;
    
    /* Forget the links */
    ar->next = ar->prev = NULL;
    
    /* Return the room */
    return (ar);
}


/*
 * Enqueue into the "priority queue" of "auto_flow" records
 */
EXTERN void borg_flow_enqueue(auto_room *ar)
{
    auto_room *node;

    /* Start at the sentinel head */
    node = &auto_flow_head;
    
    /* Hack -- Find a good location in the queue */
    while (ar->flow >= node->next->flow) node = node->next;

    /* Tell the node */
    ar->prev = node;
    ar->next = node->next;

    /* Tell the queue */
    ar->prev->next = ar;
    ar->next->prev = ar;
}

 

/*
 * Aux function -- Given a room "ar1" and a location (x,y) along the
 * edge of that room, and a "direction" of motion, find all rooms that
 * include the resulting grid, and attempt to enqueue them.
 *
 * Looks like we have to make sure that crossing rooms do not attempt
 * to recurse back on themselves or anything weird.
 *
 * Note that we assume that the "direction" is not a "diagonal".
 */
EXTERN void borg_flow_spread_aux(auto_room *ar1, int x, int y, int d)
{
    int flow;

    int x2 = x + ddx[d];
    int y2 = y + ddy[d];
        
    auto_grid *ag;
    auto_room *ar;
    
    /* Look to the given direction */
    ag = grid(x2, y2);

    /* Ignore unknown grids, walls, seams, and unroomed grids */
    if (ag->o_c == ' ') return;
    if (strchr("#%", ag->o_c)) return;
    if (!ag->room) return;
    
    /* Extract the "cost" between the two points */
    flow = ar1->flow + distance(x, y, ar1->x, ar1->y);
    flow = flow + ABS(ddx[d]) + ABS(ddy[d]);
    
    /* Now find every room containing that grid */
    for (ar = room(1,x2,y2); ar; ar = room(0,0,0)) {

	/* Paranoia -- Skip grids that contain the destination */
	/* if ((x >= ar->x1) && (x <= ar->x2) && */
	/*     (y >= ar->y1) && (y <= ar->y2)) continue; */    
	
	/* Do not "lose" previous gains */
	if (flow >= ar->flow) continue;

	/* Save the "destination" location */
	ar->x = x; ar->y = y;

	/* Save the new "cheaper" cost */
	ar->flow = flow;

	/* Hack -- Handle "upgrades" */
	if (ar->prev) {

	    /* Hack -- may not have to change anything */
	    if (ar->prev->flow <= ar->flow) continue;
	    
	    /* Dequeue the entry */
	    ar->next->prev = ar->prev;
	    ar->prev->next = ar->next;
    
	    /* Forget the links */
	    ar->next = ar->prev = NULL;
	}

	/* Enqueue the room */
	borg_flow_enqueue(ar);
    }
}


/*
 * Spread the "flow", assuming some rooms have been enqueued.
 *
 * We assume that the "flow" fields of all the rooms have been
 * initialized via "borg_flow_clear()", and that then the "flow"
 * fields of the rooms in the queue were set to "zero" (or any
 * other number) before being enqueued.
 *
 * We also assume that none of the icky grids have the "prev"
 * or "next" pointers set to anything.
 */
EXTERN void borg_flow_spread(void)
{
    int x, y;

    auto_room *ar;


    /* Keep going until the queue is empty */
    while (!borg_flow_empty()) {

	/* Dequeue the next room */	
	ar = borg_flow_dequeue();

	/* Scan the south/north edges */
	for (x = ar->x1; x <= ar->x2; x++) {
		
	    /* South edge */
	    y = ar->y2;
	
	    /* Look to the south */
	    borg_flow_spread_aux(ar, x, y, 2);

	    /* North edge */
	    y = ar->y1;
	
	    /* Look to the north */
	    borg_flow_spread_aux(ar, x, y, 8);
	}
	
	/* Scan the east/west edges */
	for (y = ar->y1; y <= ar->y2; y++) {
		
	    /* East edge */
	    x = ar->x2;
	
	    /* Look to the east */
	    borg_flow_spread_aux(ar, x, y, 6);

	    /* West edge */
	    x = ar->x1;
	
	    /* Look to the west */
	    borg_flow_spread_aux(ar, x, y, 4);
	}

	
	/* Look along the South-East corner */
	borg_flow_spread_aux(ar, ar->x2, ar->y2, 3);
	
	/* Look along the South-West corner */
	borg_flow_spread_aux(ar, ar->x1, ar->y2, 1);
	
	/* Look along the North-East corner */
	borg_flow_spread_aux(ar, ar->x2, ar->y1, 9);
	
	/* Look along the North-West corner */
	borg_flow_spread_aux(ar, ar->x1, ar->y1, 7);
    }
}


/*
 * Reset the "flow codes" of all "real" rooms to a large number
 */
EXTERN void borg_flow_clear(void)
{
    int i;
    
    /* Reset the cost of all the (real) rooms */
    for (i = 0; i < auto_room_max; i++) {

	/* Get the room */
	auto_room *ar = &auto_rooms[i];

	/* Skip "dead" rooms */	
	if (!ar->when) continue;
	
	/* Initialize the "flow" */
	ar->flow = MAX_SHORT;

	/* Paranoia -- clear the pointers */
	ar->next = ar->prev = NULL;
    }
}



/*
 * Do a "reverse" flow -- find unreachable rooms
 */
EXTERN void borg_flow_reverse()
{
    auto_room *ar;


    /* Clear the flow codes */
    borg_flow_clear();
    
    /* Enqueue the player's rooms */
    for (ar = room(1,c_x,c_y); ar; ar = room(0,0,0)) {

	/* Mark rooms as "cheap" */
	ar->flow = 0;
	
	/* Save the player's location */
	ar->x = c_x; ar->y = c_y;
		
	/* Enqueue the room */
	borg_flow_enqueue(ar);
    }
    
    /* Attempt to spread, or fail */
    borg_flow_spread();
}


/*
 * Prepare to "flow" towards "interesting" things
 */
EXTERN bool borg_flow_symbols(cptr what)
{
    int x, y, n = 0;

    auto_grid *ag;
    auto_room *ar;
        
#ifdef FRITSDEBUG
   borg_note(format("In routine borg_flow_symbols(%s)",what));
#endif /* FRITSDEBUG */

    /* Clear the flow codes */
    borg_flow_clear();


    /* Examine every legal grid */
    for (y = 1; y < AUTO_MAX_Y-1; y++) {
	for (x = 1; x < AUTO_MAX_X-1; x++) {

	    /* Get the grid */
	    ag = grid(x, y);

	    /* Skip current location */
	    if (pg == ag) continue;
	    
	    /* Ignore unknown (and unroomed) grids */
	    if ((ag->o_c == ' ') || !ag->room) continue;
	    
	    /* Require symbols from the given string */
	    if (!strchr(what, ag->o_c)) continue;

	    /* Scan all the rooms that hold it */
	    for (ar = room(1,x,y); ar; ar = room(0,0,0)) {

	    	/* Skip rooms we already added */
		if (!ar->flow) continue;
			    
		/* Mark rooms as "cheap" */
		ar->flow = 0;
	
		/* Save the location */
		ar->x = x; ar->y = y;
		
		/* Enqueue the room */
		borg_flow_enqueue(ar);

		/* Count the rooms */
		n++;
	    }
	}
    }
    
    /* Nothing to spread */
    if (!n) return (FALSE);
    
    /* Spread the flow */
    borg_flow_spread();

    /* Hmmm -- we may not be able to get to the grids */
    for (ar = room(1,c_x,c_y); ar; ar = room(0,0,0)) {

	/* See if we can flow there */
	if (ar->flow < MAX_SHORT) {
	
	    /* Note */
	    borg_note(format("Flowing toward '%s' symbols, at cost %d",
		      what, ar->flow));
    
	    /* Set the "goal" */
	    goal = GOAL_FLOW;

	    /* Success */
	    return (TRUE);
	}
    }
    
    /* Oops.  We must be stuck */
    return (FALSE);
}



/*
 * Prepare to "flow" towards "interesting" things
 */
EXTERN bool borg_flow_explore(void)
{
    int x, y, d, i, n = 0;

    auto_room *ar;
    
    auto_grid *ag, *ag1;
    

    /* Clear the flow codes */
    borg_flow_clear();


    /* Examine every known grid */
    for (y = 1; y < AUTO_MAX_Y-1; y++) {
	for (x = 1; x < AUTO_MAX_X-1; x++) {

	    /* Get the grid */
	    ag = grid(x, y);

	    /* Skip unknown/unroomed grids, plus walls/seams */			
	    if ((ag->o_c == ' ') || !ag->room) continue;			
	    if (strchr("#%", ag->o_c)) continue;
	    		    
	    /* Examine the four IMPORTANT neighbors */
	    for (i = 0; i < 4; i++) {

		/* Extract the next direction */
		d = ddd[i];
		    
		/* Get the grid */
		ag1 = grid(x+ddx[d], y+ddy[d]);

		/* Note that walls/seams are boring */
		if (strchr("#%", ag1->o_c)) continue;
		
		/* Skip "known", "roomed" grids */
		if ((ag1->o_c != ' ') && ag1->room) continue;

		/* Scan all the rooms that hold the "known" grid */
		for (ar = room(1,x,y); ar; ar = room(0,0,0)) {

		    /* Paranoia -- skip dead rooms */
		    if (!ar->when) continue;
		    
		    /* Hack -- skip rooms we already added */
		    if (ar->flow < MAX_SHORT) continue;
		    
		    /* Mark rooms as "cheap" */
		    ar->flow = 0;
		
		    /* Save the location */
		    ar->x = x; ar->y = y;
	    
		    /* Enqueue the room */
		    borg_flow_enqueue(ar);
		    
		    /* Count the rooms */
		    n++;
		}

		/* And then stop */
		break;
	    }
	}
    }
    
    /* Nothing to spread */
    if (!n) return (FALSE);
    
    /* Spread the flow */
    borg_flow_spread();

    /* Hmmm -- we may not be able to get to the grids */
    for (ar = room(1,c_x,c_y); ar; ar = room(0,0,0)) {

	/* See if we can flow there */
	if (ar->flow < MAX_SHORT) {
	
	    /* Note */
	    borg_note(format("Exploring, at cost %d", ar->flow));
        
	    /* Set the "goal" */
	    goal = GOAL_FLOW;

	    /* Success */
	    return (TRUE);
	}
    }
    
    /* Oops.  We must be stuck */
    return (FALSE);
}


/*
 * Prepare to "flow" towards "old" objects and monsters
 */
EXTERN bool borg_flow_collect(void)
{
    int x, y, n = 0;

    auto_room *ar;
    
    auto_grid *ag;
    

    /* Clear the flow codes */
    borg_flow_clear();


    /* Examine every grid */
    for (y = 1; y < AUTO_MAX_Y-1; y++) {
	for (x = 1; x < AUTO_MAX_X-1; x++) {

	    /* Get the grid */
	    ag = grid(x, y);

	    /* Hack -- skip player grid */
	    if (ag == pg) continue;
	    
	    /* Skip unknown/unroomed grids */			
	    if ((ag->o_c == ' ') || !ag->room) continue;
	    
	    /* Skip walls */			
	    if (strchr("#%", ag->o_c)) continue;
	    
	    /* Desire to approach objects and monsters */
	    if (strchr(auto_str_kill, ag->o_c) ||
	        strchr(auto_str_take, ag->o_c)) {
	    
		/* Scan all the rooms that hold the grid */
		for (ar = room(1,x,y); ar; ar = room(0,0,0)) {

		    /* Paranoia -- skip dead rooms */
		    if (!ar->when) continue;
		    
		    /* Hack -- skip rooms we already added */
		    if (ar->flow < MAX_SHORT) continue;
		    
		    /* Mark rooms as "cheap" */
		    ar->flow = 0;
		
		    /* Save the location */
		    ar->x = x; ar->y = y;
	    
		    /* Enqueue the room */
		    borg_flow_enqueue(ar);
		    
		    /* Count the rooms */
		    n++;
		}

		/* And then stop */
		break;
	    }
	}
    }
    
    /* Nothing to spread */
    if (!n) return (FALSE);
    
    /* Spread the flow */
    borg_flow_spread();

    /* Hmmm -- we may not be able to get to the grids */
    for (ar = room(1,c_x,c_y); ar; ar = room(0,0,0)) {

	/* See if we can flow there */
	if (ar->flow < MAX_SHORT) {
	
	    /* Note */
	    borg_note(format("Collecting old junk, at cost %d", ar->flow));
        
	    /* Set the "goal" */
	    goal = GOAL_FLOW;

	    /* Success */
	    return (TRUE);
	}
    }
    
    /* Oops.  We must be stuck */
    return (FALSE);
}


/*
 * Prepare to "flow" towards "old" rooms.
 */
EXTERN bool borg_flow_revisit(void)
{
    int x, y, i;

    auto_room *ar;
    
    int r_n = -1;
    u32b r_age = 0L;

    u32b age;


    /* Hack -- first find the reachable spaces */
    borg_flow_reverse();
     
    
    /* Re-visit "old" rooms */
    for (i = 0; i < auto_room_max; i++) {

	/* Access the "room" */
	ar = &auto_rooms[i];

 	/* Skip "dead" rooms */
	if (!ar->when) continue;

	/* Skip "unreachable" rooms */
	if (ar->flow == MAX_SHORT) continue;
	
	/* Reward "age" and "distance" and "luck" */
	age = (c_t - ar->when) + (ar->flow / 2);
	
	/* Skip "recent" rooms */
	if ((r_n >= 0) && (age < r_age)) continue;
	
	/* Save the index, and the age */
	r_n = i; r_age = age;
    }

    /* Clear the flow codes */
    borg_flow_clear();

    /* Hack -- No rooms to visit */
    if (r_n < 0) return (FALSE);
    
    /* Get the room */
    ar = &auto_rooms[r_n];

    /* Visit a random grid of that room */
    x = ar->x = rand_range(ar->x1, ar->x2);
    y = ar->y = rand_range(ar->y1, ar->y2);

    /* Mark the room as "cheap" */
    ar->flow = 0;

    /* Enqueue the room */
    borg_flow_enqueue(ar);
    	    
    /* Spread the flow */
    borg_flow_spread();

    /* Hmmm -- we may not be able to get to the grids */
    for (ar = room(1,c_x,c_y); ar; ar = room(0,0,0)) {

	/* See if we can flow there */
	if (ar->flow < MAX_SHORT) {
	
	    /* Note */
	    borg_note(format("Revisting (%d,%d) with age %ld, at cost %d",
			     x, y, r_age, ar->flow));
    
	    /* Set the "goal" */
	    goal = GOAL_FLOW;

	    /* Success */
	    return (TRUE);
	}
    }

    /* Success */
    return (FALSE);
}


/*
 * Act spastic, go somewhere silly
 */
EXTERN bool borg_flow_spastic(void)
{
    int i, n = 0;

    auto_room *ar;
    

    int r_n = -1;


    /* Hack -- first find the reachable spaces */
    borg_flow_reverse();
    
    /* Pick a "random" room */
    for (i = 0; i < auto_room_max; i++) {

	/* Access the "room" */
	ar = &auto_rooms[i];

 	/* Skip "dead" rooms */
	if (!ar->when) continue;

	/* Skip "unreachable" rooms */
	if (ar->flow == MAX_SHORT) continue;
	
	/* Skip annoying rooms */
	if ((ar->x1 == ar->x2) || (ar->y1 == ar->y2)) continue;
	
	/* Pick a random room */
	if (!rand_int(++n)) r_n = i;
    }

    /* Clear the flow codes */
    borg_flow_clear();

    /* Hack -- No rooms to visit */
    if (r_n < 0) return (FALSE);
    
    /* Get the room */
    ar = &auto_rooms[r_n];

    /* Visit a random grid along the wall */
    if (rand_int(2) == 0) {
	ar->x = rand_int(2) ? ar->x1 : ar->x2;
	ar->y = rand_range(ar->y1, ar->y2);
    }
    else {
	ar->x = rand_range(ar->x1, ar->x2);
	ar->y = rand_int(2) ? ar->y1 : ar->y2;
    }
    
    /* Note */
    borg_note(format("Spastic twitch towards (%d,%d)", ar->x, ar->y));
    
    /* Mark the room as "cheap" */
    ar->flow = 0;

    /* Enqueue the room */
    borg_flow_enqueue(ar);
    	    
    /* Spread the flow */
    borg_flow_spread();

    /* Set the "goal" */
    goal = GOAL_FLOW;

    /* Success */
    return (TRUE);
}



/*
 * Count the monsters touching a location
 * Assumes the location is not an outer wall
 */
EXTERN int borg_count_monsters(int x0, int y0)
{
    int i, d, x, y, n = 0;

    auto_grid *ag;

    /* Look around */
    for (i = 0; i < 8; i++) {

	/* Access the grid */
	d = ddd[i];
	x = x0 + ddx[d];
	y = y0 + ddy[d];
	ag = grid(x, y);

	/* Look for monsters */
	if (strchr(auto_str_kill, ag->o_c)) n++;
    }
    
    /* Return the count */
    return (n);
}


/*
 * Hack -- be cautious
 */
EXTERN int borg_caution(void)
{
    int x, y, i, d, k, n, g_n, g_d = -1;

    auto_grid *ag;

    /* Look around */
    g_n = n = borg_count_monsters(c_x, c_y);
    
    /* Ignore small numbers of monsters */
    if (n < 2) return (FALSE);
    
    /* Attempt to find a better grid */
    for (i = 0; i < 8; i++) {

	/* Access the grid */
	d = ddd[i];
	x = c_x + ddx[d];
	y = c_y + ddy[d];
	ag = grid(x, y);

	/* Skip unknown grids */
	if (ag->o_c == ' ') continue;

	/* Skip walls */
	if (strchr("#%", ag->o_c)) continue;

	/* Skip monsters */
	if (strchr(auto_str_kill, ag->o_c)) continue;
	
	/* Skip traps and stores */
	if (strchr("12345678^", ag->o_c)) continue;
	
	/* Count the monsters */
	k = borg_count_monsters(x, y);

	/* Require fewer monsters */
	if (k >= g_n) continue;
	
	/* Save the info */
	g_n = k; g_d = d;
    }

    /* Ignore nowhere to run */
    if (g_d < 0) return (FALSE);

    /* Take note */
    borg_note(format("Caution (%d > %d)", n, g_n));

    /* Flee! */
    borg_keypress('0' + g_d);
    
    /* Success */
    return (TRUE);
}



/*
 * Perform one "useful" action
 *
 * Return "TRUE" if successful, "FALSE" if failed.
 *
 * Strategy:
 *   Make sure we are happy with our "status" (see above)
 *   Attack and kill visible monsters, if near enough
 *   Open doors, disarm traps, tunnel through rubble
 *   Pick up (or tunnel to) gold and useful objects
 *   Explore "interesting" grids, to expand the map
 */
EXTERN bool borg_prepare_think(void)
{
    int i, k, x, y, f;

    auto_grid *ag;

    /* Best "monster" data */
    int m_f = -1;

    /* Best "object" data */
    int i_f = -1;
    
    /* Best "unknown" data */
    int u_f = -1;
    
#ifdef FRITSDEBUG
   borg_note("** In routine borg_prepare_think()");
#endif /* FRITSDEBUG */

    /*** Hack -- restart every time ***/
    
    /* Assume we will go back to the start state */
    state = STATE_START;
    

    /*** Then verify the inventory ***/

    /* Examine the inventory */
    borg_notice();

    /* Use things */
    if (borg_use_things()) return (TRUE);
    
    /* Throw away junk */
    if (borg_throw_junk()) return (TRUE);
        
    /* Identify unknown things */
    if (borg_test_stuff()) return (TRUE);
        
    /* Always have a free space available */
    if (borg_free_space()) return (TRUE);
    
    /* Wear things that need to be worn */
    if (borg_wear_stuff()) return (TRUE);
    

    /*** Caution is the better part of valor ***/
    
    /* Try not to get surrounded by monsters */
    if ((rand_int(5) == 0) && borg_caution()) return (TRUE);
    
    
    /*** Reactive Scan (Monsters, Items, Doors, etc) ***/
    
    /* Remember and prefer "current" monster, if useful */
    if ((goal == GOAL_KILL) && (c_x != g_x) && (c_y != g_y)) {

	/* Calculate the distance */
	m_f = double_distance(c_y, c_x, g_y, g_x);
    }

    /* Examine the "nearby" grids */
    for (i = 0; i < near_n; i++) {

	/* Access the "view grid" */
	y = near_y[i];
	x = near_x[i];

	/* Get the auto_grid */
	ag = grid(x, y);

	/* Hack -- Skip the player */
	if (ag == pg) continue;
	
	/* Notice monsters */
	if (strchr(auto_str_kill, ag->o_c)) {

	    /* Calculate the distance */
	    f = double_distance(c_y, c_x, y, x);
	
	    /* Keep track of the "nearest" monster */
	    if ((m_f < 0) || (f < m_f)) {

		/* Memorize the distance and location */
		m_f = f; g_x = x; g_y = y;

		/* Memorize the goal contents */
		g_a = ag->o_a; g_c = ag->o_c;

		/* Reset the "origin" data */
		o_y = c_y; o_x = c_x; o_t = c_t;

		/* Kill it */
		goal = GOAL_KILL;
	    }
	}
    }

    /* Hack -- note monster type */
    if (m_f >= 0) {
	int rrr = guess_monster(g_x, g_y);
	if (rrr) {
	    borg_note(format("Chasing a '%s'", r_list[rrr].name));
	}
	else {
	    borg_note(format("Chasing an unknown monster"));
	}
    }
    
    /* Chase and Kill the "closest" monster */
#ifndef FRITS
    if (m_f >= 0) return (borg_play_old_goal());
#else
    /* BUT watch out for breeders */
    if ((m_f >= 0) && (do_watch_breeders < 250L))
       return (borg_play_old_goal());
    if ((do_watch_breeders > 250L) && (!auto_recall)) {
       borg_note("WARNING: the breeders are taking over.");
       for(i=0;i<INVEN_PACK;i++) {
          if (auto_items[i].kind == OBJ_SCROLL_RECALL) {
             borg_note("I'm getting out of here!");
             borg_keypress('r');
             borg_keypress('a'+i);
             auto_recall=c_t;
             do_watch_breeders=0L;
          }
       }
       /* TE DOEN: in case of no recall scrolls.. */

       return (borg_play_old_goal());
    }
#endif /* FRITS */


    /*** Rest until healed ***/
    
    /* Rest occasionally if damaged */
    if ((auto_curhp < 3 * auto_maxhp / 4) && (rand_int(10) == 0)) {
	borg_note("Resting...");
	borg_keypress('R');
	borg_keypress('&');
	borg_keypress('\n');
	return (TRUE);
    }
    

    /*** Then try objects ***/
    
    /* Remember and prefer "current" object, if useful */
    if ((goal == GOAL_TAKE) && (c_x != g_x) && (c_y != g_y)) {

	/* Calculate the distance */
	i_f = double_distance(c_y, c_x, g_y, g_x);
    }

    /* Examine the "nearby" grids */
    for (i = 0; i < near_n; i++) {

	/* Access the "view grid" */
	y = near_y[i];
	x = near_x[i];

	/* Get the auto_grid */
	ag = grid(x, y);

	/* Skip the player */
	if (ag == pg) continue;
	
	/* Notice objects (including doors, traps, rubble) */
	if (strchr(auto_str_take, ag->o_c)) {

	    /* Calculate the distance */
	    f = double_distance(c_y, c_x, y, x);
	
	    /* Keep track of the "nearest" object */
	    if ((i_f < 0) || (f < i_f)) {

		/* Save the distance and location */
		i_f = f; g_x = x; g_y = y;

		/* Memorize the goal contents */
		g_a = ag->o_a; g_c = ag->o_c;

		/* Reset the "origin" data */
		o_y = c_y; o_x = c_x; o_t = c_t;

		/* Take it or Open it */
		goal = GOAL_TAKE;	
	    }
	}
    }

    /* Grab the "closest" item */
    if (i_f >= 0) return (borg_play_old_goal());
        


    /*** Rest until healed ***/
    
    /* Rest occasionally */
    if ((auto_curhp < auto_maxhp) && (rand_int(10) == 0)) {
	borg_note("Resting...");
	borg_keypress('R');
	borg_keypress('&');
	borg_keypress('\n');
	return (TRUE);
    }
    

    /*** Local searching ***/

    /* Hack -- Search intersections for doors */
    if (borg_inspect(c_x, c_y)) {
	borg_note("Inspecting a wall");
	borg_keypress('0');
	borg_keypress('9');
	borg_keypress('s');
	return (TRUE);
    }

    /* Hack -- Search random locations for doors */
    if ((rand_int(100) == 0) && (auto_level!=0)) {
#ifdef FRITS
        if (sclass==SCLASS_PRIEST)
        {
           if (rand_int(100)>75) 
              borg_cast_spell(sclass,'a','f');
           else
              borg_cast_spell(sclass,'a','g');
        } else {
           if (sclass==SCLASS_MAGE)
           {
              borg_cast_spell(sclass,'a','h');
           }
        }
#endif /* FRITS */
	borg_keypress('1');
	borg_keypress('9');
	borg_keypress('s');
	return (TRUE);
    }

#ifdef FRITS
        protevil--;
        /* cast Protection from Evil */
        if ( ( auto_curmana > 20 ) && (sclass==SCLASS_PRIEST) && (protevil<=0) && (borg_can_cast(SCLASS_PRIEST,'c','e')))
        {
           if(rand_int(2)==0)
           if (borg_cast_spell(SCLASS_PRIEST,'c','e')==TRUE) 
           {
              protevil=12+auto_level*3;
              return(TRUE);
           }
        }
#endif /* FRITS */

    
    /*** And then try local exploring ***/

    /* Remember and prefer "current" destination, if useful */
    if ((goal == GOAL_GOTO) && (c_x != g_x) && (c_y != g_y)) {

	/* Calculate the distance */
	u_f = double_distance(c_y, c_x, g_y, g_x);
    }

    /* Examine the "nearby" grids */
    for (i = 0; i < near_n; i++) {

	/* Access the "view grid" */
	y = near_y[i];
	x = near_x[i];

	/* Get the auto_grid */
	ag = grid(x, y);

	/* Skip the player */
	if (ag == pg) continue;
	
	/* Notice "unknown" grids */
	if ((ag->o_c == ' ') || (!ag->room && !strchr("#%", ag->o_c))) {

	    /* Calculate the "double-distance" */
	    f = double_distance(c_y, c_x, y, x);
	
	    /* Keep track of the "nearest" one */
	    if ((u_f < 0) || (f < u_f)) {

		/* Save the distance and location */
		u_f = f; g_x = x; g_y = y;

		/* Hack -- Memorize the goal "contents" */
		g_a = ag->o_a; g_c = ag->o_c;

		/* Reset the "origin" data */
		o_y = c_y; o_x = c_x; o_t = c_t;

		/* Attempt to "go" there */
		goal = GOAL_GOTO;
	    }
	}
    }

    /* Approach "unknown" grids */
    if (u_f >= 0) return (borg_play_old_goal());
    
#ifdef FRITS
    /* try to gain new spells... dangerous! */
    /* don't do it too often since it is computer-intensive */
       if (rand_int(100*auto_level)==0) {
          return(borg_can_gain_spell());
       }
#endif /* FRITS */

    /*** Explore the Level ***/

    /* Maintain old goals (explore, symbols, spastic, revisit) */
    if (goal == GOAL_FLOW) return (borg_play_old_goal());


    /* Explore unknown grids */
    if (borg_flow_explore()) return (borg_play_old_goal());


    /* Collect old stuff */
    if (borg_flow_collect()) return (borg_play_old_goal());

    /* Get bored eventually, leave the level */
    if (c_t - auto_shock > 1000L) {

	cptr what;

	/* Assume back to town */
	goal_level = -1;

	/* Hack -- how many items are "good" */
	k = borg_count_sell();
	
	/* Not enough sellable items, go down */
	if (k < 18) goal_level = 1;

	/* Hack -- chance of random direction */
	i = rand_int(1000);

	/* Hack -- flee the level when really bored */
	if (c_t - auto_shock > 2000L) i = rand_int(10);

	/* Go for random stairs sometimes */
	if (i < 10) goal_level = (i < 5) ? -1 : 1;
	
	/* Already in town, always go down */
	if (auto_depth == 0) goal_level = 1;

	/* Determine which stairs to use */
	what = (goal_level > 0) ? ">" : "<";

#ifdef FRITS
	/* recall to dungeon */
	if ( (!auto_recall) && (auto_depth == 0) && (goal_level > 0) &&
             ( ((auto_level > 10) || (auto_maxhp > 100)) )   /* "fitness" */
        ) {
	    /* Scan the inventory for Recall scrolls */
	    for (i = 0; i < INVEN_PACK; i++) {

		if (auto_items[i].kind == OBJ_SCROLL_RECALL) {
		    auto_recall = c_t;
		    borg_keypress('r');
		    borg_keypress('a' + i);
                    borg_note("Recalling to dungeon");
		    return (TRUE);
                }
            }
        }

	/* recall to town */
	if ( (!auto_recall) && (auto_depth >= 5) && (goal_level < 0) ) {
	    /* Scan the inventory for Recall scrolls */
	    for (i = 0; i < INVEN_PACK; i++) {

		if (auto_items[i].kind == OBJ_SCROLL_RECALL) {
		    auto_recall = c_t;
		    borg_keypress('r');
		    borg_keypress('a' + i);
                    borg_note("Recalling to town");
		    return (TRUE);
                }
            }
        }
#endif FRITS

	/* Take note */
	borg_note(format("Looking for stairs (%s) with %d good items",
			 what, k));

	/* Attempt to use those stairs */
	if (borg_flow_symbols(what)) return (borg_play_old_goal());
	
	/* Hack -- try a word of recall instead */
	if ((!auto_recall) && (auto_depth) && (goal_level < 0)) /* recall back */
        {

	    /* Scan the inventory */
	    for (i = 0; i < INVEN_PACK; i++) {

		/* Eat food rations and such */
		if (auto_items[i].kind == OBJ_SCROLL_RECALL) {

		    auto_recall = c_t;
		    
		    borg_keypress('r');
		    borg_keypress('a' + i);

		    return (TRUE);
		}
	    }
	}
    }


    /* XXX XXX XXX Hack -- Occasionally, act stupid */
    if ((c_t - auto_shock > 500L) && (rand_int(3) == 0)) {
	if (borg_flow_spastic()) return (borg_play_old_goal());
    }
    
    
    /* Re-visit old rooms */
    if (borg_flow_revisit()) return (borg_play_old_goal());


    /*** Totally stuck with nothing to do ***/

    /* This is a bad thing */
    borg_note("Twitchy!");
    
    /* Try searching */
    borg_keypress('0');
    borg_keypress('9');
    borg_keypress('s');

    /* Occasional tunnel */
    if (rand_int(5) == 0) borg_keypress('T');

    /* Move (or tunnel) */
    borg_keypress('0' + randint(9));

    /* We did something */
    return (TRUE);
}





/*
 * Let the "auto player" enqueue some keypresses
 */
EXTERN void borg_play_perform(void)
{

#ifdef FRITSDEBUG
   borg_note("*** In routine borg_play_perform()");
#endif /* FRITSDEBUG */

    /* Verify options */
    borg_play_options();

    /* Loop until something has been done */
    while (state) {

	/* Handle "stores" when necessary */
	if ((state == STATE_STORE) && borg_prepare_store()) break;
#ifdef FRITS
	/* Check all my spellbooks */
        if ((state == STATE_BOOKCHECK) && borg_prepare_spells()) break;
#endif /* FRITS */

	/* And then check the dungeon */
	if ((state == STATE_START) && borg_prepare_start()) break;

	/* And then check the inventory and equipment */
	if ((state == STATE_INVEN) && borg_prepare_inven()) break;
	if ((state == STATE_EQUIP) && borg_prepare_equip()) break;
	
	/* And then actually think */
	if ((state == STATE_THINK) && borg_prepare_think()) break;
    }
}


#endif /* AUTO_PLAY */

