/* File: borg6.c */

/* Purpose: Medium level stuff for the Borg -BEN- */

#include "angband.h"

#ifdef ALLOW_BORG

#include "borg1.h"
#include "borg2.h"
#include "borg3.h"
#include "borg4.h"
#include "borg5.h"
#include "borg6.h"



/*
 * This file is responsible for the low level dungeon goals.
 *
 * This includes calculating the danger from monsters, determining
 * how and when to attack monsters, and calculating "flow" paths
 * from place to place for various reasons.
 *
 * Notes:
 *   We assume that invisible/offscreen monsters are dangerous
 *   We consider physical attacks, missile attacks, spell attacks,
 *     wand attacks, etc, as variations on a single theme.
 *   We take account of monster resistances and susceptibilities
 *   We try not to wake up sleeping monsters by throwing things
 *
 * To Do:
 *   Consider various "special" attacks like sleep and slow
 *
 * Bugs:
 *   We use missiles and bolt spells against ghosts in walls
 *   Currently the "twitchy()" function is not very smart
 *   We get "twitchy" when we are afraid of the monsters
 *   Annoyance and Danger are very different things (!)
 */





/*
 * Given a "source" and "target" locations, extract a "direction",
 * which will move one step from the "source" towards the "target".
 *
 * Note that we use "diagonal" motion whenever possible.
 *
 * We return "5" if no motion is needed.
 */
static int borg_extract_dir(int y1, int x1, int y2, int x2)
{
    /* No movement required */
    if ((y1 == y2) && (x1 == x2)) return (5);

    /* South or North */
    if (x1 == x2) return ((y1 < y2) ? 2 : 8);

    /* East or West */
    if (y1 == y2) return ((x1 < x2) ? 6 : 4);

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

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

    /* Paranoia */
    return (5);
}


/*
 * Given a "source" and "target" locations, extract a "direction",
 * which will move one step from the "source" towards the "target".
 *
 * We prefer "non-diagonal" motion, which allows us to save the
 * "diagonal" moves for avoiding pillars and other obstacles.
 *
 * If no "obvious" path is available, we use "borg_extract_dir()".
 *
 * We return "5" if no motion is needed.
 */
static int borg_goto_dir(int y1, int x1, int y2, int x2)
{
    int d, e;

    int ay = (y2 > y1) ? (y2 - y1) : (y1 - y2);
    int ax = (x2 > x1) ? (x2 - x1) : (x1 - x2);


    /* Default direction */
    e = borg_extract_dir(y1, x1, y2, x2);


    /* Adjacent location, use default */
    if ((ay <= 1) && (ay <= 1)) return (e);


    /* Try south/north (primary) */
    if (ay > ax)
    {
        d = (y1 < y2) ? 2 : 8;
        if (borg_cave_floor_bold(y1 + ddy[d], x1 + ddx[d])) return (d);
    }

    /* Try east/west (primary) */
    if (ay < ax)
    {
        d = (x1 < x2) ? 6 : 4;
        if (borg_cave_floor_bold(y1 + ddy[d], x1 + ddx[d])) return (d);
    }


    /* Try diagonal */
    d = borg_extract_dir(y1, x1, y2, x2);

    /* Check for walls */
    if (borg_cave_floor_bold(y1 + ddy[d], x1 + ddx[d])) return (d);


    /* Try south/north (secondary) */
    if (ay <= ax)
    {
        d = (y1 < y2) ? 2 : 8;
        if (borg_cave_floor_bold(y1 + ddy[d], x1 + ddx[d])) return (d);
    }

    /* Try east/west (secondary) */
    if (ay >= ax)
    {
        d = (x1 < x2) ? 6 : 4;
        if (borg_cave_floor_bold(y1 + ddy[d], x1 + ddx[d])) return (d);
    }


    /* Circle obstacles */
    if (!ay)
    {
        /* Circle to the south */
        d = (x1 < x2) ? 3 : 1;
        if (borg_cave_floor_bold(y1 + ddy[d], x1 + ddx[d])) return (d);

        /* Circle to the north */
        d = (x1 < x2) ? 9 : 7;
        if (borg_cave_floor_bold(y1 + ddy[d], x1 + ddx[d])) return (d);
    }

    /* Circle obstacles */
    if (!ax)
    {
        /* Circle to the east */
        d = (y1 < y2) ? 3 : 9;
        if (borg_cave_floor_bold(y1 + ddy[d], x1 + ddx[d])) return (d);

        /* Circle to the west */
        d = (y1 < y2) ? 1 : 7;
        if (borg_cave_floor_bold(y1 + ddy[d], x1 + ddx[d])) return (d);
    }


    /* Oops */
    return (e);
}



/*
 * Clear the "flow" information
 *
 * This function was once a major bottleneck, so we now use several
 * slightly bizarre, but highly optimized, memory copying methods.
 */
static void borg_flow_clear(void)
{
    /* Reset the "cost" fields */
    COPY(auto_data_cost, auto_data_hard, auto_data);

    /* Wipe costs and danger */
    if (auto_danger_wipe)
    {
        /* Wipe the "know" flags */
        WIPE(auto_data_know, auto_data);

        /* Wipe the "icky" flags */
        WIPE(auto_data_icky, auto_data);

        /* Wipe complete */
        auto_danger_wipe = FALSE;
    }

    /* Start over */
    flow_head = 0;
    flow_tail = 0;
}




/*
 * Spread a "flow" from the "destination" grids outwards
 *
 * We fill in the "cost" field of every grid that the player can
 * "reach" with the number of steps needed to reach that grid,
 * if the grid is "reachable", and otherwise, with "255", which
 * is the largest possible value that can be stored in a byte.
 *
 * Thus, certain grids which are actually "reachable" but only by
 * a path which is at least 255 steps in length will thus appear
 * to be "unreachable", but this is not a major concern.
 *
 * We use the "flow" array as a "circular queue", and thus we must
 * be careful not to allow the "queue" to "overflow".  This could
 * only happen with a large number of distinct destination points,
 * each several units away from every other destination point, and
 * in a dungeon with no walls and no dangerous monsters.  But this
 * is technically possible, so we must check for it just in case.
 *
 * We do not need a "priority queue" because the cost from grid to
 * grid is always "one" and we process them in order.  If we did
 * use a priority queue, this function might become unusably slow,
 * unless we reactivated the "room building" code.
 *
 * We handle both "walls" and "danger" by marking every grid which
 * is "impassible", due to either walls, or danger, as "ICKY", and
 * marking every grid which has been "checked" as "KNOW", allowing
 * us to only check the wall/danger status of any grid once.  This
 * provides some important optimization, since many "flows" can be
 * done before the "ICKY" and "KNOW" flags must be reset.
 *
 * Note that the "borg_enqueue_grid()" function should refuse to
 * enqueue "dangeous" destination grids, but does not need to set
 * the "KNOW" or "ICKY" flags, since having a "cost" field of zero
 * means that these grids will never be queued again.  In fact,
 * the "borg_enqueue_grid()" function can be used to enqueue grids
 * which are "walls", such as "doors" or "rubble".
 *
 * This function is extremely expensive, and is a major bottleneck
 * in the code, due more to internal processing than to the use of
 * the "borg_danger()" function, especially now that the use of the
 * "borg_danger()" function has been optimized several times.
 *
 * The "optimize" flag allows this function to stop as soon as it
 * finds any path which reaches the player, since in general we are
 * looking for paths to destination grids which the player can take,
 * and we can stop this function as soon as we find any usable path,
 * since it will always be as short a path as possible.
 *
 * We queue the "children" in reverse order, to allow any "diagonal"
 * neighbors to be processed first, since this may boost efficiency.
 *
 * Note that we should recalculate "danger", and reset all "flows"
 * if we notice that a wall has disappeared, and if one appears, we
 * must give it a maximal cost, and mark it as "icky", in case it
 * was currently included in any flow.
 *
 * If a "depth" is given, then the flow will only be spread to that
 * depth, note that the maximum legal value of "depth" is 250.
 */
static void borg_flow_spread(int depth, bool optimize, bool avoid)
{
    int i;
    int n, o = 0;
    int x1, y1;
    int x, y;


    /* Now process the queue */
    while (flow_head != flow_tail)
    {
        /* Extract the next entry */
        x1 = auto_flow_x[flow_tail];
        y1 = auto_flow_y[flow_tail];

        /* Circular queue -- dequeue the next entry */
        if (++flow_tail == AUTO_FLOW_MAX) flow_tail = 0;


        /* Cost (one per movement grid) */
        n = auto_data_cost->data[y1][x1] + 1;

        /* New depth */
        if (n > o)
        {
            /* Optimize (if requested) */
            if (optimize && (n > auto_data_cost->data[c_y][c_x])) break;

            /* Limit depth */
            if (n > depth) break;

            /* Save */
            o = n;
        }

        /* Queue the "children" */
        for (i = 0; i < 8; i++)
        {
            int old_head;

            auto_grid *ag;


            /* Neighbor grid */
            x = x1 + ddx_ddd[i];
            y = y1 + ddy_ddd[i];


            /* Skip "reached" grids */
            if (auto_data_cost->data[y][x] <= n) continue;


            /* Access the grid */
            ag = &auto_grids[y][x];


            /* Avoid "wall" grids (not doors) */
            if (ag->feat >= FEAT_SECRET) continue;


            /* Avoid unknown grids (if requested) */
            if (avoid && (ag->feat == FEAT_NONE)) continue;


            /* Ignore "icky" grids */
            if (auto_data_icky->data[y][x]) continue;

            /* Analyze every grid once */
            if (!auto_data_know->data[y][x])
            {
                int p;


                /* Mark as known */
                auto_data_know->data[y][x] = TRUE;


                /* Get the danger */
                p = borg_danger(y, x, 1);

                /* Dangerous grid */
                if (p > avoidance / 2)
                {
                    /* Mark as icky */
                    auto_data_icky->data[y][x] = TRUE;

                    /* Ignore this grid */
                    continue;
                }
            }


            /* Save the flow cost */
            auto_data_cost->data[y][x] = n;

            /* Enqueue that entry */
            auto_flow_x[flow_head] = x;
            auto_flow_y[flow_head] = y;


            /* Circular queue -- memorize head */
            old_head = flow_head;

            /* Circular queue -- insert with wrap */
            if (++flow_head == AUTO_FLOW_MAX) 
                flow_head = 0;

            /* Circular queue -- handle overflow (badly) */
            if (flow_head == flow_tail) 
                flow_head = old_head;
        }
    }

    /* Forget the flow info */
    flow_head = flow_tail = 0;
}



/*
 * Enqueue a fresh (legal) starting grid, if it is safe
 */
static void borg_flow_enqueue_grid(int y, int x)
{
    int old_head;


    /* Avoid icky grids */
    if (auto_data_icky->data[y][x]) return;

    /* Unknown */
    if (!auto_data_know->data[y][x])
    {
        /* Mark as known */
        auto_data_know->data[y][x] = TRUE;

        /* Mark dangerous grids as icky */
        if (borg_danger(y, x, 1) > avoidance / 2)
        {
            /* Icky */
            auto_data_icky->data[y][x] = TRUE;

            /* Avoid */
            return;
        }
    }


    /* Only enqueue a grid once */
    if (!auto_data_cost->data[y][x]) return;


    /* Save the flow cost (zero) */
    auto_data_cost->data[y][x] = 0;

    /* Enqueue that entry */
    auto_flow_y[flow_head] = y;
    auto_flow_x[flow_head] = x;


    /* Circular queue -- memorize head */
    old_head = flow_head;

    /* Circular queue -- insert with wrap */
    if (++flow_head == AUTO_FLOW_MAX) flow_head = 0;

    /* Circular queue -- handle overflow */
    if (flow_head == flow_tail) flow_head = old_head;
}



/*
 * Do a "reverse" flow from the player outwards
 */
static void borg_flow_reverse(void)
{
    /* Clear the flow codes */
    borg_flow_clear();

    /* Enqueue the player's grid */
    borg_flow_enqueue_grid(c_y, c_x);

    /* Spread, but do NOT optimize */
    borg_flow_spread(250, FALSE, FALSE);
}





/*
 * Attempt to induce "word of recall"
 */
bool borg_recall(void)
{
    /* Multiple "recall" fails */
    if (!goal_recalling)
    {
        /* Try to "recall" */
        if (borg_spell(5, 4) ||
            borg_prayer(4, 4) ||
            borg_zap_rod(SV_ROD_RECALL) ||
            borg_read_scroll(SV_SCROLL_WORD_OF_RECALL))
        {
            /* Success */
            return (TRUE);
        }
    }

    /* Nothing */
    return (FALSE);
}



/*
 * Prevent starvation by any means possible
 */
static bool borg_eat_food_any(void)
{
    int i;

    /* Scan the inventory for "normal" food */
    for (i = 0; i < INVEN_PACK; i++)
    {
        auto_item *item = &auto_items[i];

        /* Skip empty items */
        if (!item->iqty) continue;

        /* Skip unknown food */
        if (!item->kind) continue;

        /* Skip non-food */
        if (item->tval != TV_FOOD) continue;

        /* Skip "flavored" food */
        if (item->sval < SV_FOOD_MIN_FOOD) continue;

        /* Eat something of that type */
        if (borg_eat_food(item->sval)) return (TRUE);
    }

    /* Scan the inventory for "okay" food */
    for (i = 0; i < INVEN_PACK; i++)
    {
        auto_item *item = &auto_items[i];

        /* Skip empty items */
        if (!item->iqty) continue;

        /* Skip unknown food */
        if (!item->kind) continue;

        /* Skip non-food */
        if (item->tval != TV_FOOD) continue;

        /* Skip "icky" food */
        if (item->sval < SV_FOOD_MIN_OKAY) continue;

        /* Eat something of that type */
        if (borg_eat_food(item->sval)) return (TRUE);
    }

    /* Nothing */
    return (FALSE);
}


/*
 * Mega-Hack -- evaluate the "freedom" of the given location
 *
 * The theory is that often, two grids will have equal "danger",
 * but one will be "safer" than the other, perhaps because it
 * is closer to stairs, or because it is in a corridor, or has
 * some other characteristic that makes it "safer".
 *
 * Then, if the Borg is in danger, say, from a normal speed monster
 * which is standing next to him, he will know that walking away from
 * the monster is "pointless", because the monster will follow him,
 * but if the resulting location is "safer" for some reason, then
 * he will consider it.  This will allow him to flee towards stairs
 * in the town, and perhaps towards corridors in the dungeon.
 *
 * This method is used in town to chase the stairs.
 *
 * XXX XXX XXX We should attempt to walk "around" buildings.
 */
static int borg_freedom(int y, int x)
{
    int d, f = 0;

    /* Hack -- chase stairs in town */
    if (!auto_depth && track_more_num)
    {
        /* Love the stairs! */
        d = double_distance(y, x, track_more_y[0], track_more_x[0]);

        /* Proximity is good */
        f += (1000 - d);

        /* Close proximity is great */
        if (d < 4) f += (2000 - (d * 500));
    }

    /* Freedom */
    return (f);
}


/*
 * Check a floor grid for "happy" status
 *
 * These grids are floor grids which contain stairs, or which
 * are non-corners in corridors, or which are directly adjacent
 * to pillars.  Stairs are good because they can be used to leave
 * the level.  Corridors are good because you can back into them
 * to avoid groups of monsters and because they can be used for
 * escaping.  Pillars are good because while standing next to a
 * pillar, you can walk "around" it in two different directions,
 * allowing you to retreat from a single normal monster forever.
 */
static bool borg_happy_grid_bold(int y, int x)
{
    auto_grid *ag = &auto_grids[y][x];


    /* Accept stairs */
    if (ag->feat == FEAT_LESS) return (TRUE);
    if (ag->feat == FEAT_MORE) return (TRUE);


    /* Hack -- weak/dark is very unhappy */
    if (do_weak || !my_cur_lite) return (FALSE);


    /* Case 1a: north-south corridor */
    if (borg_cave_floor_bold(y-1, x) && borg_cave_floor_bold(y+1, x) &&
        !borg_cave_floor_bold(y, x-1) && !borg_cave_floor_bold(y, x+1))
    {
        /* Happy */
        return (TRUE);
    }

    /* Case 1b: east-west corridor */
    if (borg_cave_floor_bold(y, x-1) && borg_cave_floor_bold(y, x+1) &&
        !borg_cave_floor_bold(y-1, x) && !borg_cave_floor_bold(y+1, x))
    {
        /* Happy */
        return (TRUE);
    }


    /* Case 2a: north pillar */
    if (!borg_cave_floor_bold(y-1, x) &&
        borg_cave_floor_bold(y-1, x-1) &&
        borg_cave_floor_bold(y-1, x+1) &&
        borg_cave_floor_bold(y-2, x))
    {
        /* Happy */
        return (TRUE);
    }

    /* Case 2b: south pillar */
    if (!borg_cave_floor_bold(y+1, x) &&
        borg_cave_floor_bold(y+1, x-1) &&
        borg_cave_floor_bold(y+1, x+1) &&
        borg_cave_floor_bold(y+2, x))
    {
        /* Happy */
        return (TRUE);
    }

    /* Case 2c: east pillar */
    if (!borg_cave_floor_bold(y, x+1) &&
        borg_cave_floor_bold(y-1, x+1) &&
        borg_cave_floor_bold(y+1, x+1) &&
        borg_cave_floor_bold(y, x+2))
    {
        /* Happy */
        return (TRUE);
    }

    /* Case 2d: west pillar */
    if (!borg_cave_floor_bold(y, x-1) &&
        borg_cave_floor_bold(y-1, x-1) &&
        borg_cave_floor_bold(y+1, x-1) &&
        borg_cave_floor_bold(y, x-2))
    {
        /* Happy */
        return (TRUE);
    }


    /* Not happy */
    return (FALSE);
}


/* 
 * is there a unique nearby? (check auto_kills)
 * This is used to keep us in fights and make us use all
 * our 'spare' equiptment to kill uniques
 * This only works for uniques we know about.  If one of the
 * monsters around is misidentified then it may be a unique 
 * and we wouldn't know.
 */
static bool borg_near_unique(int dist)
{
    auto_kill *kill;
    monster_race *r_ptr;
    int x9, y9, ax, ay, d;
    int i;

    /* make sure there is a unique around */
    for (i = 1; i < auto_kills_nxt; i++)
    {
        kill = &auto_kills[i];
        r_ptr = &r_info[kill->r_idx];

        /* Skip dead monsters */
        if (!kill->r_idx) continue;

        x9 = kill->x;
        y9 = kill->y;

        /* Distance components */
        ax = (x9 > c_x) ? (x9 - c_x) : (c_x - x9);
        ay = (y9 > c_y) ? (y9 - c_y) : (c_y - y9);

        /* Distance */
        d = MAX(ax, ay);

        /* if the unique is too far then skip it. */
        if (d > dist) continue;

        /* found one.  Done. */
        if (r_ptr->flags1 & RF1_UNIQUE) return (TRUE);
    }

    /* no nearby uniques */
    return FALSE;
}


/*
 * Help determine if "phase door" seems like a good idea
 */
bool borg_caution_phase(bool emergency)
{
    int n, k, i, d, x, y, p;

    int dis = 10;
    int min = dis / 2;

    auto_grid *ag;

    /* Simulate 100 attempts */
    for (n = k = 0; k < 100; k++)
    {
        /* Pick a location */
        for (i = 0; i < 100; i++)
        {
            /* Pick a (possibly illegal) location */
            while (1)
            {
                y = rand_spread(c_y, dis);
                x = rand_spread(c_x, dis);
                d = distance(c_y, c_x, y, x);
                if ((d >= min) && (d <= dis)) break;
            }

            /* Ignore illegal locations */
            if ((y <= 0) || (y >= AUTO_MAX_Y - 1)) continue;
            if ((x <= 0) || (x >= AUTO_MAX_X - 1)) continue;

            /* Access */
            ag = &auto_grids[y][x];

            /* Skip unknown grids */
            if (ag->feat == FEAT_NONE) continue;

            /* Skip weird grids */
            if (ag->feat == FEAT_INVIS) continue;

            /* Skip walls */
            if (!borg_cave_floor_bold(y, x)) continue;

            /* Skip monsters */
            if (ag->kill) continue;

            /* Stop looking */
            break;
        }

        /* No location */
        /* in the real code it would keep trying but here we should */
        /* assume that there is unknown spots that you would be able */
        /* to go but may be dangerious. */
        if (i >= 100)
        {
            n++;
            continue;
        }

        /* Examine */
        p = borg_danger(y, x, 2);

        /* if *very* scary, do not allow jumps at all */
        if (p > auto_chp) n++;
    }

    /* Too much danger */
    /* in an emergency try with extra danger allowed */
    if (n > (emergency ? 20 : 5)) 
    {
        borg_note(format("# No Phase. scary squares: %d", n));
        return (FALSE);
    }
    /* note how scary it was */
    if (emergency)
        borg_note(format("# Emergency Phase. scary squares: %d", n));
    else
        borg_note(format("# Safe to Phase. scary squares: %d", n));

    /* Okay */
    return (TRUE);
}

/* 
 * Try to phase door or teleport
 * b_q is the danger of the least dangerious square around us.
 */
bool borg_escape(int b_q)
{
    /* also run if stunned or it is scary here */
    if ((b_q > avoidance) || do_heavy_stun || 
        (b_q > ((auto_mhp*2)/5) && !borg_fighting_unique))
    {
        /* only escape with spell if fail is low */
        int allow_fail = 2;

        /* if very healthy, allow extra fail */
        if ((auto_chp*100)/auto_mhp > 90)
            allow_fail = 20;

        /* very scary, do not allow fail */
        if ((b_q > avoidance) || do_heavy_stun)
            allow_fail = 0;

        /* Phase door, if useful */
        if (amt_phase && borg_caution_phase(FALSE) &&
             (borg_spell_fail(0, 2, allow_fail) ||
              borg_prayer_fail(4, 0, allow_fail) ||
              borg_read_scroll(SV_SCROLL_PHASE_DOOR)))
        {
            /* Success */
            return (TRUE);
        }

        /* Teleport via spell */
        if ( borg_spell_fail(1, 5, allow_fail) ||
             borg_prayer_fail(1, 1, allow_fail) ||
             borg_prayer_fail(4, 1, allow_fail))
        {
            /* Success */
            return (TRUE);
        }

        /* if low failure allowed, use scroll before staff */
/* !FIX: should check for % fail use of staff  AJG */
        if ( ((allow_fail > 1) && 
             (borg_use_staff(SV_STAFF_TELEPORTATION) ||
             borg_read_scroll(SV_SCROLL_TELEPORT))) ||
             ((allow_fail <= 1) && 
             (borg_read_scroll(SV_SCROLL_TELEPORT) ||
              borg_use_staff(SV_STAFF_TELEPORTATION))))
        {
            /* Success */
            return (TRUE);
        }

        /* if I fail to teleport, try phase again (better to */
        /* take a chance and phase out than stick around and die) */
        if ( amt_phase && borg_caution_phase(TRUE) &&
             (borg_spell_fail(0, 2, allow_fail)  ||
             borg_prayer_fail(4, 0, allow_fail) ||
             borg_read_scroll(SV_SCROLL_PHASE_DOOR)))
        {
            /* Success */
            return (TRUE);
        }

        /* if we got this far we tried to escape but couldn't... */
        /* time to flee */
        if (!goal_fleeing)
        {
            /* Note */
            borg_note("# Fleeing (failed to teleport)");

            /* Start fleeing */
            goal_fleeing = TRUE;
        }

        /* Flee now */
        if (!goal_leaving)
        {
            /* Flee! */
            borg_note("# Leaving (failed to teleport)");

            /* Start leaving */
            goal_leaving = TRUE;
        }

    }

    /* Attempt to teleport (usually) */
    /* do not escape from uniques so quick */
    if (((b_q > avoidance / 2) && !borg_fighting_unique ) || 
        (b_q > avoidance) || do_heavy_stun)
    {
        /* allow any fail beacuse this round is 'safe' */
        /* (next round may not be) */

        /* XXX XXX XXX Count close calls */

        /* Phase door, if useful */
        if (amt_phase && borg_caution_phase(FALSE) &&
            (borg_spell(0, 2) ||
             borg_prayer(4, 0) ||
             borg_read_scroll(SV_SCROLL_PHASE_DOOR)))
        {
            /* Success */
            return (TRUE);
        }

        /* Try teleportation */
        if ((rand_int(100) < 50) &&
            (borg_spell(1, 5) ||
             borg_prayer(4, 1) ||
             borg_prayer(1, 1) ||
             borg_use_staff(SV_STAFF_TELEPORTATION) ||
             borg_read_scroll(SV_SCROLL_TELEPORT)))
        {
            /* Success */
            return (TRUE);
        }
    }
    return (FALSE);
}

/* 
 * ** Try healing **
 * this function tries to heal the borg both before trying to flee (pre_flight)
 * and after.  Before the flight check, try to heal up enough to stay in the fight.
 * after the flight check, we are no longer in immediate danger so heal up as a 
 * precaution.
 */
static bool borg_heal( bool pre_flight, int danger )
{
    int hp_down ;
    int allow_fail = 20;
    int chance;

    hp_down = auto_mhp - auto_chp;

    /* before the fight only do sure fire cures */
    if (pre_flight) 
        allow_fail = 0;

    /* if unhurt no healing needed */
    if (hp_down == 0) 
        return FALSE;

    /* Hack -- heal when wounded (prayers) */
    /* 4/5 hp 0%                           */
    /* 3/4 hp 5%                           */
    /* 2/3 hp 20%                          */
    /* 1/2 hp 50%                          */
    /* 1/3 hp 80%                          */
    /* 1/4 hp 100%                         */
    chance = rand_int(100);

    /* BIG HACK. get max damage that can be done. */
    if (!pre_flight)
    {
        if ( danger )
        {
            s16b save_avoid;

            save_avoid = avoidance;
            avoidance = 1;
            danger = borg_danger(c_y, c_x, 1);
            avoidance = save_avoid;
        }

        /* if the next hit may make us run, heal now */
        if (((auto_chp - danger) / 2) < danger)
        {
            if (mb_ptr->spell_book == TV_PRAYER_BOOK)
                chance -= 50;
            else
                chance -= 20;
        }

        if (!(((auto_chp <= ((auto_mhp * 4) / 5)) && (chance < 0)) ||
            ((auto_chp <= ((auto_mhp * 3) / 4)) && (chance < 5)) ||
            ((auto_chp <= ((auto_mhp * 2) / 3)) && (chance < 20)) ||
            ((auto_chp <= (auto_mhp / 2)) && (chance < 50)) ||
            ((auto_chp <= (auto_mhp / 3)) && (chance < 80)) ||
             (auto_chp <= (auto_mhp / 4)) ||
             do_heavy_stun || do_stun))
            return FALSE;
    }

    /* only heal before attempting to flee if the danger is */
    /* more than the avoidance and being healed will help */
    if ( pre_flight )
    {
        if (danger < avoidance)
            return (FALSE);

        if (danger > auto_mhp)
            return (FALSE);
    }
    /* Cure light Wounds (2d10) */
    if ( hp_down < 10 &&
         (danger - (hp_down < 6 ? hp_down : 6) < avoidance) && 
         borg_prayer_fail(0, 1, allow_fail))
    {
        return (TRUE);
    } 
    /* Cure Serious Wounds (4d10) */
    if ( hp_down < 20 && 
         (danger - (hp_down < 12 ? hp_down : 12) < avoidance) && 
         borg_prayer_fail(1, 2, allow_fail))
    {
        return (TRUE);
    } 

    /* Cure Critical Wounds (6d10) */
    if ( hp_down < 50 && 
         (danger - (hp_down < 18 ? hp_down : 18) < avoidance) && 
         (borg_prayer_fail(2, 2, allow_fail) || 
          borg_prayer_fail(6, 0, allow_fail)))
    {
        return (TRUE);
    } 

    /* Cure Mortal Wounds (8d10) */
    if ( hp_down < 120 && 
         (danger - (hp_down < 24 ? hp_down : 24) < avoidance) && 
         (borg_prayer_fail(2, 7, allow_fail) || 
          borg_prayer_fail(6, 1, allow_fail)))
    {
        return (TRUE);
    } 

    /* Heal (300hp) */
    if (hp_down < 350 && 
        (danger - (hp_down < 300 ? hp_down : 300) < avoidance) && 
        borg_prayer_fail(3, 2, allow_fail) )
    {
        return (TRUE);
    }

    /* Healing (2000hp) */
    if ((danger - (hp_down < 2000 ? hp_down : 2000) < avoidance) && 
        borg_prayer_fail(6, 2, allow_fail))
    {
        return (TRUE);
    }

    /* Try a lesser prayer again, just incase we tried a  */
    /* higher spell and failed */
    /* (didn't have/not enough mana...) */
    if ( !pre_flight &&
        (borg_prayer_fail(3, 2, allow_fail) ||
        borg_prayer_fail(2, 7, allow_fail) || 
        borg_prayer_fail(2, 2, allow_fail) || 
        borg_prayer_fail(1, 2, allow_fail) || 
        borg_prayer_fail(0, 1, allow_fail)))
    {
        return (TRUE);
    }

    /* very hurt, Big heal - reusable */
    if (hp_down > 150)
    { 
        if (((danger - (hp_down < 500 ? hp_down : 500) < avoidance) ||
             !pre_flight) && borg_zap_rod(SV_ROD_HEALING)) /* 500hp */
        {
            return TRUE;
        }

        if (((danger - (hp_down < 300 ? hp_down : 300) < avoidance) ||
            !pre_flight) && borg_use_staff(SV_STAFF_HEALING)) /* 300hp */
        {
            return TRUE;
        }
    }

    /* very hurt, use big potions. */
    if ((hp_down > 300) || ((hp_down > 150) && borg_fighting_unique))
    { 
        /* use life and *healing* before healing because they are less */
        /* common and clutter inventory. */
        if (((danger - (hp_down < 1200 ? hp_down : 1200) < avoidance)  || 
             !pre_flight) && 
            (borg_quaff_potion(SV_POTION_LIFE) ||
             borg_quaff_potion(SV_POTION_STAR_HEALING)) ) 
        {
            return TRUE;
        }

        if ((((danger - (hp_down < 300 ? hp_down : 300)) < avoidance)  || 
             !pre_flight) && 
            borg_quaff_potion(SV_POTION_HEALING)) /* 300hp */
        {
            return TRUE;
        }
    }

    /* do not drink cure potions during a fight to heal. */
    if (!pre_flight) return (FALSE);

    /* use staff more librally, it will not last long. */
    if (auto_level > 25)
    {
        if (((danger - (hp_down < 300 ? hp_down : 300)) < avoidance) && 
            borg_use_staff(SV_STAFF_HEALING)) /* 300hp */
        {
            return TRUE;
        }
    }

    /* Do not use up CSW/CCW on healing if high level */
    if (auto_level > 15) return (FALSE);

    /* not so hurt, use smaller potions. */
    /* (only use up cure crits if we have lots) */
    if (amt_cure_critical > 8) 
    {
        if ((danger - (hp_down < 12 ? hp_down : 12) < avoidance) &&
             borg_quaff_potion(SV_POTION_CURE_CRITICAL))
        {
            return (TRUE);
        }
    }

    if ((danger - (hp_down < 8 ? hp_down : 8) < avoidance) && 
         borg_quaff_potion(SV_POTION_CURE_SERIOUS))
    {
        return (TRUE);
    }

    return (FALSE);
}


/*
 * Be "cautious" and attempt to prevent death or dishonor.
 *
 * Strategy:
 *
 *   (1) Caution
 *   (1a) Analyze the situation
 *   (1a1) try to heal
 *   (1a2) try a defence
 *   (1b) Teleport from danger
 *   (1c) Handle critical stuff
 *   (1d) Retreat to happy grids
 *   (1e) Back away from danger
 *   (1f) Heal various conditions
 *
 *   (2) Attack
 *   (2a) Simulate possible attacks
 *   (2b) Perform optimal attack
 *
 *   (3) Recover
 *   (3a) Recover by spells/prayers
 *   (3b) Recover by items/etc
 *   (3c) Recover by resting
 *
 * XXX XXX XXX
 * In certain situations, the "proper" course of action is to simply
 * attack a nearby monster, since often most of the danger is due to
 * a single monster which can sometimes be killed in a single blow.
 *
 * Actually, both "borg_caution()" and "borg_recover()" need to
 * be more intelligent, and should probably take into account
 * such things as nearby monsters, and/or the relative advantage
 * of simply pummeling nearby monsters instead of recovering.
 *
 * Note that invisible/offscreen monsters contribute to the danger
 * of an extended "region" surrounding the observation, so we will
 * no longer rest near invisible monsters if they are dangerous.
 *
 * We sometimes try to "rest" to restore mana near "wimpy" monsters
 * which happen to drain mana, which is counter-productive.
 *
 * XXX XXX XXX
 * We should perhaps reduce the "fear" values of each region over
 * time, to take account of obsolete invisible monsters.
 *
 * Note that walking away from a fast monster is counter-productive,
 * since the monster will often just follow us, so we use a special
 * method which allows us to factor in the speed of the monster and
 * predict the state of the world after we move one step.  Of course,
 * walking away from a spell casting monster is even worse, since the
 * monster will just get to use the spell attack multiple times.  But,
 * if we are trying to get to known safety, then fleeing in such a way
 * might make sense.  Actually, this has been done too well, note that
 * it makes sense to flee some monsters, if they "stumble", or if we
 * are trying to get to stairs.  XXX XXX XXX
 *
 * Note that the "flow" routines attempt to avoid entering into
 * situations that are dangerous, but sometimes we do not see the
 * danger coming, and then we must attempt to survive by any means.
 *
 * We will attempt to "teleport" if the danger in the current situation,
 * as well as that resulting from attempting to "back away" from danger,
 * are sufficient to kill us in one or two blows.  This allows us to
 * avoid teleportation in situations where simply backing away is the
 * proper course of action, for example, when standing next to a nasty
 * stationary monster, but also to teleport when backing away will not
 * reduce the danger sufficiently.
 *
 * But note that in "nasty" situations (when we are running out of light,
 * or when we are starving, blind, confused, or hallucinating), we will
 * ignore the possibility of "backing away" from danger, when considering
 * the possibility of using "teleport" to escape.  But if the teleport
 * fails, we will still attempt to "retreat" or "back away" if possible.
 *
 * XXX XXX XXX Note that it should be possible to do some kind of nasty
 * "flow" algorithm which would use a priority queue, or some reasonably
 * efficient normal queue stuff, to determine the path which incurs the
 * smallest "cumulative danger", and minimizes the total path length.
 * It may even be sufficient to treat each step as having a cost equal
 * to the danger of the destination grid, plus one for the actual step.
 * This would allow the Borg to prefer a ten step path passing through
 * one grid with danger 10, to a five step path, where each step has
 * danger 9.  Currently, he often chooses paths of constant danger over
 * paths with small amounts of high danger.  However, the current method
 * is very fast, which is certainly a point in its favor...
 *
 * When in danger, attempt to "flee" by "teleport" or "recall", and if
 * this is not possible, attempt to "heal" damage, if needed, and else
 * attempt to "flee" by "running".
 *
 * XXX XXX XXX Both "borg_caution()" and "borg_recover()" should only
 * perform the "healing" tasks if they will cure more "damage"/"stuff"
 * than may be re-applied in the next turn, this should prevent using
 * wimpy healing spells next to dangerous monsters, and resting to regain
 * mana near a mana-drainer.
 *
 * Whenever we are in a situation in which, even when fully healed, we
 * could die in a single round, we set the "goal_fleeing" flag, and if
 * we could die in two rounds, we set the "goal_leaving" flag.
 *
 * In town, whenever we could die in two rounds if we were to stay still,
 * we set the "goal_leaving" flag.  In combination with the "retreat" and
 * the "back away" code, this should allow us to leave town before getting
 * into situations which might be fatal.
 *
 * Flag "goal_fleeing" means get off this level right now, using recall
 * if possible when we get a chance, and otherwise, take stairs, even if
 * it is very dangerous to do so.
 *
 * Flag "goal_leaving" means get off this level when possible, using
 * stairs if possible when we get a chance.
 *
 * We will also take stairs if we happen to be standing on them, and we
 * could die in two rounds.  This is often "safer" than teleportation,
 * and allows the "retreat" code to retreat towards stairs, knowing that
 * once there, we will leave the level.
 */
bool borg_caution(void)
{
    int j, p;

    int q, b_q = -1;

    bool nasty = FALSE;

    /*** Notice "nasty" situations ***/

    /* About to run out of light is extremely nasty */
    if (!my_lite && auto_items[INVEN_LITE].pval < 250) nasty = TRUE;

    /* Starvation is nasty */
    if (do_weak) nasty = TRUE;

    /* Blind-ness is nasty */
    if (do_blind) nasty = TRUE;

    /* Confusion is nasty */
    if (do_confused) nasty = TRUE;

    /* Hallucination is nasty */
    if (do_image) nasty = TRUE;

    /* if on level 100 and not ready for Morgoth, run */
    if (auto_depth == 100)
    {
        if (borg_ready_morgoth == 0)
        {
            /* Start leaving */
            if (!goal_leaving)
            {
                /* Note */
                borg_note("# Leaving (No Morgoth Yet)");

                /* Start leaving */
                goal_leaving = TRUE;
            }
        }
    }

    /*** Evaluate local danger ***/

    /* am I fighting a unique? */
    borg_fighting_unique = borg_near_unique(6);

    /* Look around */
    p = borg_danger(c_y, c_x, 1);

    /* Unless "nasty"... */
    if (!nasty || !auto_depth)
    {
        int i;

        /* Attempt to find a better grid */
        for (i = 0; i < 8; i++)
        {
            int x = c_x + ddx_ddd[i];
            int y = c_y + ddy_ddd[i];

            /* Access the grid */
            auto_grid *ag = &auto_grids[y][x];

            /* Skip walls/doors */
            if (!borg_cave_floor_grid(ag)) continue;

            /* Skip unknown grids */
            if (ag->feat == FEAT_NONE) continue;

            /* Skip monster grids */
            if (ag->kill) continue;

            /* Mega-Hack -- skip stores XXX XXX XXX */
            if ((ag->feat >= FEAT_SHOP_HEAD) && (ag->feat <= FEAT_SHOP_TAIL)) continue;

            /* Mega-Hack -- skip traps XXX XXX XXX */
            if ((ag->feat >= FEAT_TRAP_HEAD) && (ag->feat <= FEAT_TRAP_TAIL)) continue;

            /* Extract the danger there */
            q = borg_danger(y, x, 2);

            /* Skip larger danger */
            if ((b_q >= 0) && (b_q < q)) continue;

            /* Track */
            b_q = q;
        }
    }

    /* Danger (ignore stupid "fear" danger) */
    if ((p > avoidance / 2) || (p > auto_fear_region[c_y/11][c_x/11]))
    {
        /* Describe (briefly) the current situation */
        borg_note(format("# Loc:%d,%d Dep:%d Lev:%d HP:%d/%d SP:%d/%d Danger:b_q=%d/p=%d",
                         c_x, c_y, auto_depth, auto_level,
                         auto_chp, auto_mhp, auto_csp, auto_msp,
                         b_q, p));
    } 
    else
    {
        if (borg_goi)
            borg_note(format("# Loc:%d,%d goi!", c_x, c_y));
    }

    /* No (good) retreat */
    if ((b_q < 0) || (b_q > p)) b_q = p;


    /* try healing before running away */
    if (borg_heal( TRUE, p ))
        return TRUE;

    /* do some defence before running away! */
    if (borg_defend())
        return TRUE;

    /*** Danger ***/

    /* Impending doom */
    /* don't take off in the middle of a fight */
    /* just to restock and it is useless to restock */
    /* if you have just left town. */
    if (borg_restock(auto_depth) && 
        !borg_fighting_unique && 
        (auto_time_town + (c_t - auto_began)) > 200)
    {
        /* Start leaving */
        if (!goal_leaving)
        {
            /* Note */
            borg_note(format("# Leaving (restock) %s", borg_restock(auto_depth)));

            /* Start leaving */
            goal_leaving = TRUE;
        }

        /* Start fleeing */
        if (!goal_fleeing)
        {
            /* Note */
            borg_note(format("# Fleeing (restock) %s", borg_restock(auto_depth)));

            /* Start fleeing */
            goal_fleeing = TRUE;
        }
    }

    /* Excessive danger */
    else if ((b_q > auto_mhp) && (rand_int(100) > (auto_level+20)))
    {
        /* Start fleeing */
        /* do not flee level if going after Morgoth or fighting a unique */
        if (!goal_fleeing && !borg_fighting_unique &&
            !((auto_depth == 100) && (borg_ready_morgoth == 1)))
        {
            /* Note */
            borg_note("# Fleeing (excessive danger)");

            /* Start fleeing */
            goal_fleeing = TRUE;
        }
    }
    /* Potential danger (near death) in town */
    else if (!auto_depth && (p > auto_chp))
    {
        /* Flee now */
        if (!goal_leaving)
        {
            /* Flee! */
            borg_note("# Leaving (potential danger)");

            /* Start leaving */
            goal_leaving = TRUE;
        }
    }


    /*** Stairs ***/

    /* Leaving or Fleeing, take stairs */
    if (goal_leaving || goal_fleeing)
    {
        /* Take next stairs */
        stair_less = goal_fleeing;
        if (borg_ready_morgoth == 0)
            stair_less = TRUE;

        /* Only go down if fleeing or prepared. */
        stair_more = goal_fleeing;
        if ((cptr)NULL == borg_prepared(auto_depth+1))
            stair_more = TRUE;
    }

    /* Take stairs up */
    if (stair_less || (b_q > auto_chp / 2))
    {
        /* Current grid */
        auto_grid *ag = &auto_grids[c_y][c_x];

        /* Usable stairs */
        if (ag->feat == FEAT_LESS)
        {
            /* Take the stairs */
            borg_keypress('<');

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

    /* Take stairs down */
    if ((stair_more || (b_q > auto_chp / 2)) && !goal_recalling)
    {
        /* Current grid */
        auto_grid *ag = &auto_grids[c_y][c_x];

        /* Usable stairs */
        if (ag->feat == FEAT_MORE)
        {
            /* Take the stairs */
            borg_keypress('>');

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


    /*** Escape if possible ***/

    /* Attempt to escape */
    if (borg_escape(b_q))
    {
        /* Hack -- reset the "goal" location */
        g_x = g_y = 0;

        /* Success */
        return (TRUE);
    }

    /*** Deal with critical situations ***/

    /* Hack -- require light */
    if (!my_lite)
    {
        auto_item *item = &auto_items[INVEN_LITE];

        /* Must have light -- Refuel current torch */
        if ((item->tval == TV_LITE) && (item->sval == SV_LITE_TORCH))
        {
            /* Try to refuel the torch */
            if ((item->pval < 500) && borg_refuel_torch()) return (TRUE);
        }

        /* Must have light -- Refuel current lantern */
        if ((item->tval == TV_LITE) && (item->sval == SV_LITE_LANTERN))
        {
            /* Try to refill the lantern */
            if ((item->pval < 1000) && borg_refuel_lantern()) return (TRUE);
        }

        /* Flee for fuel */
        if (auto_depth && (item->pval < 250))
        {
            /* Start leaving */
            if (!goal_leaving)
            {
                /* Flee */
                borg_note("# Leaving (need fuel)");

                /* Start leaving */
                goal_leaving = TRUE;
            }

            /* Start fleeing */
            if (!goal_fleeing)
            {
                /* Flee */
                borg_note("# Fleeing (need fuel)");

                /* Start fleeing */
                goal_fleeing = TRUE;
            }
        }
    }

    /* Hack -- prevent starvation */
    if (do_weak)
    {
        /* Attempt to satisfy hunger */
        if (borg_eat_food_any() ||
            borg_spell(2, 0) ||
            borg_prayer(1, 5))
        {
            /* Success */
            return (TRUE);
        }

        /* Flee for food */
        if (auto_depth)
        {
            /* Start leaving */
            if (!goal_leaving)
            {
                /* Flee */
                borg_note("# Leaving (need food)");

                /* Start leaving */
                goal_leaving = TRUE;
            }

            /* Start fleeing */
            if (!goal_fleeing)
            {
                /* Flee */
                borg_note("# Fleeing (need food)");

                /* Start fleeing */
                goal_fleeing = TRUE;
            }
        }
    }


    /*** Flee on foot ***/

    /* Strategic retreat */
    if (p > avoidance / 2)
    {
        int d, b_d = -1;
        int r, b_r = -1;

        int b_x = c_x;
        int b_y = c_y;


        /* Scan the useful viewable grids */
        for (j = 1; j < auto_view_n; j++)
        {
            int x1 = c_x;
            int y1 = c_y;

            int x2 = auto_view_x[j];
            int y2 = auto_view_y[j];


            /* Require "floor" grids */
            if (!borg_cave_floor_bold(y2, x2)) continue;

            /* Require "happy" grids */
            if (!borg_happy_grid_bold(y2, x2)) continue;

            /* Track "nearest" grid */
            if (b_r >= 0)
            {
                int ay = ((y2 > y1) ? (y2 - y1) : (y1 - y2));
                int ax = ((x2 > x1) ? (x2 - x1) : (x1 - x2));

                /* Ignore "distant" locations */
                if ((ax > b_r) || (ay > b_r)) continue;
            }


            /* Reset */
            r = 0;

            /* Simulate movement */
            while (1)
            {
                auto_grid *ag;

                /* Obtain direction */
                d = borg_goto_dir(y1, x1, y2, x2);

                /* Verify direction */
                if ((d == 0) || (d == 5)) break;

                /* Track distance */
                r++;

                /* Simulate the step */
                y1 += ddy[d];
                x1 += ddx[d];

                /* Obtain the grid */
                ag = &auto_grids[y1][x1];

                /* Require floor */
                if (!borg_cave_floor_grid(ag)) break;

                /* Require line of sight */
                if (!borg_los(y1, x1, y2, x2)) break;

                /* Check danger (over time) */
                if (borg_danger(y1, x1, r+1) > p) break;

                /* !FIX AJG keep dying by colossus.  Maybe this will help... */
                /* make sure it is not dangerous to take the first step. */
                if (r == 1 && borg_danger(y1, x1, 1) >= p)  break;

                /* Skip monsters */
                if (ag->kill) break;

                /* Skip traps */
                if ((ag->feat >= FEAT_TRAP_HEAD) && (ag->feat <= FEAT_TRAP_TAIL)) break;


                /* Safe arrival */
                if ((x1 == x2) && (y1 == y2))
                {
                    /* Save distance */
                    b_r = r;

                    /* Save location */
                    b_x = x2;
                    b_y = y2;

                    /* Done */
                    break;
                }
            }
        }

        /* Retreat */
        if (b_r >= 0)
        {
            /* Save direction */
            b_d = borg_goto_dir(c_y, c_x, b_y, b_x);

            /* Hack -- set goal */
            g_x = c_x + ddx[b_d];
            g_y = c_y + ddy[b_d];

            /* Note */
            borg_note(format("# Retreating to %d,%d (distance %d) via %d,%d (%d >= %d)",
                             b_x, b_y, b_r, g_x, g_y, p, borg_danger(g_y, g_x, 2)));

            /* Strategic retreat */
            borg_keypress('0' + b_d);

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


    /* Want to back away */
    if (p > avoidance / 2)
    {
        int i, b_i = -1;
        int k, b_k = -1;
        int f, b_f = -1;

        /* Current danger */
        b_k = p;

        /* Check the freedom */
        b_f = borg_freedom(c_y, c_x);

        /* Attempt to find a better grid */
        for (i = 0; i < 8; i++)
        {
            int x = c_x + ddx_ddd[i];
            int y = c_y + ddy_ddd[i];

            /* Access the grid */
            auto_grid *ag = &auto_grids[y][x];

            /* Skip walls/doors */
            if (!borg_cave_floor_grid(ag)) continue;

            /* Skip monster grids */
            if (ag->kill) continue;

            /* Mega-Hack -- skip stores XXX XXX XXX */
            if ((ag->feat >= FEAT_SHOP_HEAD) && (ag->feat <= FEAT_SHOP_TAIL)) continue;

            /* Mega-Hack -- skip traps XXX XXX XXX */
            if ((ag->feat >= FEAT_TRAP_HEAD) && (ag->feat <= FEAT_TRAP_TAIL)) continue;

            /* Extract the danger there */
            k = borg_danger(y, x, 2);

            /* Skip higher danger */
            if (b_k < k) continue;

            /* Check the freedom */
            f = borg_freedom(y, x);

            /* Skip bad locations */
            if ((b_k == k) && (b_f > f)) continue;

            /* Save the info */
            b_i = i; b_k = k; b_f = f;
        }

        /* Back away */
        if (b_i >= 0)
        {
            /* Hack -- set goal */
            g_x = c_x + ddx_ddd[b_i];
            g_y = c_y + ddy_ddd[b_i];

            /* Note */
            borg_note(format("# Backing up to %d,%d (%d >= %d)",
                             g_x, g_y, p, borg_danger(g_y, g_x, 2)));

            /* Back away from danger */
            borg_keypress('0' + ddd[b_i]);

            /* Success */
            return (TRUE);
        }

        /* Note */
        borg_note(format("# Cornered (danger %d)", p));
    }


    /*** Try healing ***/

    /* heal when wounded  */
    if (borg_heal(FALSE, p))
        return TRUE;

    /* Hack -- heal when blind/confused */
    if ((do_blind || do_confused) && (rand_int(100) < 70))
    {
        if (borg_quaff_potion(SV_POTION_CURE_SERIOUS) ||
            borg_quaff_potion(SV_POTION_CURE_CRITICAL))
        {
            return (TRUE);
        }
    }

    /* Hack -- cure wounds when bleeding */
    if (do_cut && (auto_chp < 2 || (rand_int(100) < 10)))
    {
        if (borg_quaff_potion(SV_POTION_CURE_SERIOUS) ||
            borg_quaff_potion(SV_POTION_CURE_CRITICAL))
        {
            return (TRUE);
        }
    }

    /* Hack -- cure poison when poisoned */
    if (do_poisoned && (auto_chp < 2 || rand_int(100) < 10))
    {
        if (borg_spell(1, 4) ||
            borg_prayer(2, 0) ||
            borg_quaff_potion(SV_POTION_CURE_POISON) ||
            borg_quaff_potion(SV_POTION_CURE_CRITICAL))
        {
            return (TRUE);
        }
    }

    /* Hack -- cure fear when afraid */
    if (do_afraid && (rand_int(100) < 70))
    {
        if (borg_prayer(0, 3) ||
            borg_quaff_potion(SV_POTION_BOLDNESS) ||
            borg_quaff_potion(SV_POTION_HEROISM) ||
            borg_quaff_potion(SV_POTION_BESERK_STRENGTH) ||
            borg_spell(7, 2) ||
            borg_spell(7, 0))
        {
            return (TRUE);
        }
    }


    /* restore Mana */
    /* note, blow the staff charges easy because the staff will not last. */
    if (auto_csp < (auto_msp / 5) && (rand_int(100) < 50))
    {
        if (borg_use_staff(SV_STAFF_THE_MAGI))
        {
            borg_note("# Use Magi Staff");
            return (TRUE);
        }
    }

    /* blowing potions is harder */
    /* NOTE: must have enough mana to keep up GOI or do a HEAL */
    if (auto_csp < (auto_msp / 10) || 
        ((auto_depth > 95) && (auto_csp < 70) && (auto_msp > 0))) 
    { 
        /* If deep do not check, just use staff */
        if ((auto_depth > 95) || (rand_int(100) < 30)) 
        {
            int num_mana = 5;

            if (auto_depth > 95)
            {
                /* stock up on mana to take out MORGOTH */
                num_mana = 20; 
            }
            /* only use the potions if we have lots or */
            /*  are battling a unique */
            if (amt_mana > num_mana || borg_fighting_unique)  
            {
                if (borg_use_staff(SV_STAFF_THE_MAGI) ||
                    borg_quaff_potion(SV_POTION_RESTORE_MANA))
                {
                    borg_note("# Restored My Mana");
                    return (TRUE);
                }
            }
        }
    }

    /*** Note impending death XXX XXX XXX ***/

    /* Flee from low hit-points */
    if (((auto_chp < auto_mhp / 3) || 
        ((auto_chp < auto_mhp / 2) && auto_chp < 100)) &&
        (amt_cure_critical < 3) &&
        (amt_heal < 1))
    {
        /* Flee from low hit-points */
        if (auto_depth && (rand_int(100) < 25))
        {
            /* Start leaving */
            if (!goal_leaving)
            {
                /* Flee */
                borg_note("# Leaving (low hit-points)");

                /* Start leaving */
                goal_leaving = TRUE;
            }

            /* Start fleeing */
            if (!goal_fleeing)
            {
                /* Flee */
                borg_note("# Fleeing (low hit-points)");

                /* Start fleeing */
                goal_fleeing = TRUE;
            }
        }
    }

    /* Try an emergency teleport (This will take us to negative mana but, */
    /* what the hell, I am about to die anyway. */
    if ((((p*2)/ 3) > avoidance) && (auto_msp > 1))
    {
        int sv_mana = auto_csp;

        auto_csp = auto_msp;
        if ( borg_spell_fail(1, 5, 15) ||
            borg_prayer_fail(1, 1, 15) ||
            borg_prayer_fail(4, 1, 15) ||
            borg_spell_fail(0, 2, 15)  ||
            borg_prayer_fail(4, 0, 15) ||
            borg_spell_fail(5, 2, 15))
        {
            /* verify use of spell */
            borg_keypress('y');

            /* Flee! */
            borg_note("# Emergency Teleport! AHHHhhhh!!!....");

            /* Hack -- reset the "goal" location */
            g_x = g_y = 0;
            
            goal_fleeing = TRUE;
            
            return (TRUE);
        }
        auto_csp = sv_mana;
    }

    /* Hack -- use "recall" to flee if possible */
    if (goal_fleeing && auto_depth && (borg_recall()))
    {
        /* Note */
        borg_note("# Fleeing the level (recall)");

        /* Success */
        return (TRUE);
    }

    /* Nothing */
    return (FALSE);
}



/*
 * New method for handling attacks, missiles, and spells
 *
 * Every turn, we evaluate every known method of causing damage
 * to monsters, and evaluate the "reward" inherent in each of
 * the known methods which is usable at that time, and then
 * we actually use whichever method, if any, scores highest.
 *
 * For each attack, we need a function which will determine the best
 * possible result of using that attack, and return its value.  Also,
 * if requested, the function should actually perform the action.
 *
 * Note that the functions should return zero if the action is not
 * usable, or if the action is not useful.
 *
 * These functions need to apply some form of "cost" evaluation, to
 * prevent the use of expensive spells with minimal reward.  Also,
 * we should always prefer attacking by hand to using spells if the
 * damage difference is "small", since there is no "cost" in making
 * a physical attack.
 *
 * We should take account of "spell failure", as well as "missile
 * missing" and "blow missing" probabilities.
 *
 * Note that the functions may store local state information when
 * doing a "simulation" and then they can use this information if
 * they are asked to implement their strategy.
 *
 * XXX XXX XXX
 *
 * We should "reward" doing damage to monsters which are "dangerous",
 * unless they are sleeping, in which case we should penalize waking
 * them up, unless we can kill them instantly.  Note that this means
 * that killing a single "gnome mage" with 10 hitpoints should be
 * considered "better" than doing 30 damage to a "white jelly",
 * since the "gnome mage" is much more "dangerous".  We should
 * check the danger over several turns, to take account of nasty
 * monsters which are not right next to us.
 *
 * We should attempt to apply any "brand" effects of the current
 * "weapon" and/or "ammo".
 *
 * We should "attempt" to keep track of each monsters "hitpoints",
 * since this will make the attack code "smarter", but we should
 * not be too optimistic, since mistakes could be fatal.
 *
 * We should try to avoid damaging objects on the ground, that is,
 * we should not use "frost ball" near potions, etc.
 *
 * Note that all "fire" commands have a minimum range of 20, but the
 * various "throw" commands have a range which is limited by strength
 * and weight, and is limited to a total distance of ten.  We should
 * attempt to take into to account the "effective" range.  XXX XXX XXX
 *
 * There are several types of damage inducers:
 *
 *   Attacking physically
 *   Launching missiles
 *   Throwing objects
 *   Casting spells
 *   Praying prayers
 *   Using wands
 *   Using rods
 *   Using staffs
 *   Using scrolls
 */
enum
{
    BF_THRUST,

    BF_LAUNCH,

    BF_OBJECT,

    BF_SPELL_MAGIC_MISSILE,
    BF_SPELL_ELEC_BOLT,
    BF_SPELL_COLD_BOLT,
    BF_SPELL_FIRE_BOLT,
    BF_SPELL_ACID_BOLT,

    BF_SPELL_LITE_BEAM,

    BF_SPELL_POISON_BALL,
    BF_SPELL_COLD_BALL,
    BF_SPELL_ACID_BALL,
    BF_SPELL_FIRE_BALL,

    BF_SPELL_POISON_STORM,
    BF_SPELL_COLD_STORM,
    BF_SPELL_METEOR_STORM,
    BF_SPELL_MANA_STORM,

    BF_PRAYER_HOLY_ORB_BALL,

    BF_ROD_ELEC_BOLT,
    BF_ROD_COLD_BOLT,
    BF_ROD_ACID_BOLT,
    BF_ROD_FIRE_BOLT,

    BF_ROD_LITE_BEAM,

    BF_ROD_ELEC_BALL,
    BF_ROD_COLD_BALL,
    BF_ROD_ACID_BALL,
    BF_ROD_FIRE_BALL,

    BF_WAND_MAGIC_MISSILE,
    BF_WAND_ELEC_BOLT,
    BF_WAND_COLD_BOLT,
    BF_WAND_ACID_BOLT,
    BF_WAND_FIRE_BOLT,

    BF_WAND_LITE_BEAM,

    BF_WAND_STINKING_CLOUD,
    BF_WAND_ELEC_BALL,
    BF_WAND_COLD_BALL,
    BF_WAND_ACID_BALL,
    BF_WAND_FIRE_BALL,

    BF_WAND_DRAGON_COLD,
    BF_WAND_DRAGON_FIRE,

    BF_MAX
};



/*
 * Guess how much damage a physical attack will do to a monster
 */
static int borg_thrust_damage_one(int i)
{
    int dam;
    int mult;

    auto_kill *kill;

    monster_race *r_ptr;

    auto_item *item;

    int chance;


    /* Examine current weapon */
    item = &auto_items[INVEN_WIELD];

    /* Monster record */
    kill = &auto_kills[i];

    /* Monster race */
    r_ptr = &r_info[kill->r_idx];

    /* Damage */
    dam = (item->dd * (item->ds + 1) / 2);

    /* here is the place for slays and such */
    mult = 1;
    if (((my_slay_animal) && (r_ptr->flags3 & RF3_ANIMAL)) ||
       ((my_slay_evil) && (r_ptr->flags3 & RF3_EVIL)))
        mult = 2;
    if (((my_slay_undead) && (r_ptr->flags3 & RF3_ANIMAL)) ||
       ((my_slay_demon) && (r_ptr->flags3 & RF3_DEMON)) ||
       ((my_slay_orc) && (r_ptr->flags3 & RF3_ORC)) ||
       ((my_slay_troll) && (r_ptr->flags3 & RF3_TROLL)) ||
       ((my_slay_giant) && (r_ptr->flags3 & RF3_GIANT)) ||
       ((my_slay_dragon) && (r_ptr->flags3 & RF3_DRAGON)) ||
       ((my_brand_acid) && !(r_ptr->flags3 & RF3_IM_ACID)) ||
       ((my_brand_fire) && !(r_ptr->flags3 & RF3_IM_FIRE)) ||
       ((my_brand_cold) && !(r_ptr->flags3 & RF3_IM_COLD)) ||
       ((my_brand_elec) && !(r_ptr->flags3 & RF3_IM_ELEC)))
        mult = 3;
    if ((my_kill_dragon) && (r_ptr->flags3 & RF3_DRAGON))
        mult = 5;
        dam *= mult;

    dam = dam + item->to_d + my_to_dam;
    dam = dam * my_num_blow;

    /* reduce for % chance to hit (AC) */
    chance = (my_skill_thn + ((my_to_hit + item->to_h) * 3));
    if ((r_ptr->ac * 3 / 4) > 0)
        chance = (chance * 100) / (r_ptr->ac * 3 / 4);

    /* 5% automatic success/fail */
    if (chance > 95) chance = 95;
    if (chance < 5) chance = 5;

    /* add 20% to chance to give a bit more wieght to weapons */
    chance += 20;

    dam = (dam * chance) / 100;

    /* Limit damage to twice maximal hitpoints */
    if (dam > kill->power * 2) dam = kill->power * 2;


    /* Damage */
    return (dam);
}



/*
 * Simulate/Apply the optimal result of making a physical attack
 */
static int borg_attack_aux_thrust(void)
{
    int p, dir;

    int i, b_i = -1;
    int d, b_d = -1;

    auto_grid *ag;

    auto_kill *kill;

    /* Too afraid to attack */
    if (do_afraid) return (0);


    /* Examine possible destinations */
    for (i = 0; i < auto_temp_n; i++)
    {
        int x = auto_temp_x[i];
        int y = auto_temp_y[i];

        /* Require "adjacent" */
        if (distance(c_y, c_x, y, x) > 1) continue;

        /* Acquire grid */
        ag = &auto_grids[y][x];

        /* Calculate "average" damage */
        d = borg_thrust_damage_one(ag->kill);

        /* No damage */
        if (d <= 0) continue;

        /* Obtain the monster */
        kill = &auto_kills[ag->kill];

        /* Hack -- avoid waking most "hard" sleeping monsters */
        if (!kill->awake &&  (d <= kill->power))
        {
            /* Calculate danger */
            p = borg_danger_aux(y, x, 1, ag->kill);

            if (p > avoidance / 2)
                continue;
        }

        /* Calculate "danger" to player */
        p = borg_danger_aux(c_y, c_x, 4, ag->kill);

        /* Reduce "bonus" of partial kills */
        if (d <= kill->power) p = p / 10;

        /* Add the danger to the damage */
        d += p;

        /* Ignore lower damage */
        if ((b_i >= 0) && (d < b_d)) continue;

        /* Save the info */
        b_i = i;
        b_d = d;
    }

    /* Nothing to attack */
    if (b_i < 0) return (0);

    /* Simulation */
    if (auto_simulate) return (b_d);

    /* Save the location */
    g_x = auto_temp_x[b_i];
    g_y = auto_temp_y[b_i];

    /* Note */
    borg_note(format("# Facing location (%d,%d)",
                     g_x, g_y));

    /* Note */
    borg_note(format("# Attacking with weapon '%s'",
                     auto_items[INVEN_WIELD].desc));

    /* Get a direction for attacking */
    dir = borg_extract_dir(c_y, c_x, g_y, g_x);

    /* Attack the grid */
    borg_keypress('0' + dir);

    /* Success */
    return (b_d);
}




/*
 * Target a location.  Can be used alone or at "Direction?" prompt.
 *
 * Warning -- This will only work for locations on the current panel
 */
static bool borg_target(int y, int x)
{
    int x1, y1, x2, y2;

    /* Log */
    borg_note(format("# Targetting location (%d,%d)", x, y));

    /* Target mode */
    borg_keypress('*');

    /* Target a location */
    borg_keypress('p');

    /* Determine "path" */
    x1 = c_x;
    y1 = c_y;
    x2 = x;
    y2 = y;

    /* Move to the location (diagonals) */
    for (; (y1 < y2) && (x1 < x2); y1++, x1++) borg_keypress('3');
    for (; (y1 < y2) && (x1 > x2); y1++, x1--) borg_keypress('1');
    for (; (y1 > y2) && (x1 < x2); y1--, x1++) borg_keypress('9');
    for (; (y1 > y2) && (x1 > x2); y1--, x1--) borg_keypress('7');

    /* 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('5');

    /* Success */
    return (TRUE);
}



/*
 * Guess how much damage a spell attack will do to a monster
 *
 * We only handle the "standard" damage types.
 *
 * We are paranoid about monster resistances
 *
 * We ignore "special" effects for now
 */
static int borg_launch_damage_one(int i, int dam, int typ)
{
    auto_kill *kill;

    monster_race *r_ptr;


    /* Monster record */
    kill = &auto_kills[i];

    /* Monster race */
    r_ptr = &r_info[kill->r_idx];


    /* Analyze the damage type */
    switch (typ)
    {
        /* Magic Missile */
        case GF_MISSILE:
        break;

        /* Arrow */
        case GF_ARROW:
        break;

        /* Pure damage */
        case GF_MANA:
        /* only use mana storm against uniques... this */
        /* should cut down on some mana use. */
        if (!borg_fighting_unique)
            dam = 0;
        break;

        /* Meteor -- powerful magic missile */
        case GF_METEOR:
        break;


        /* Acid */
        case GF_ACID:
        if (r_ptr->flags3 & RF3_IM_ACID) dam /= 9;
        break;

        /* Electricity */
        case GF_ELEC:
        if (r_ptr->flags3 & RF3_IM_ELEC) dam /= 9;
        break;

        /* Fire damage */
        case GF_FIRE:
        if (r_ptr->flags3 & RF3_IM_FIRE) dam /= 9;
        break;

        /* Cold */
        case GF_COLD:
        if (r_ptr->flags3 & RF3_IM_COLD) dam /= 9;
        break;

        /* Poison */
        case GF_POIS:
        if (r_ptr->flags3 & RF3_IM_POIS) dam /= 9;
        break;

        /* Ice */
        case GF_ICE:
        if (r_ptr->flags3 & RF3_IM_COLD) dam /= 9;
        break;


        /* Holy Orb */
        case GF_HOLY_ORB:
        if (r_ptr->flags3 & RF3_EVIL) dam *= 2;
        break;


        /* Weak Lite */
        case GF_LITE_WEAK:
        if (!(r_ptr->flags3 & RF3_HURT_LITE)) dam = 0;
        break;


        /* Drain Life */
        case GF_OLD_DRAIN:
        if ((r_ptr->flags3 & RF3_UNDEAD) ||
            (r_ptr->flags3 & RF3_DEMON) ||
            (strchr("Egv", r_ptr->d_char)))
        {
            dam = 0;
        }
        break;


        /* Weird attacks */
        case GF_PLASMA:
        case GF_NETHER:
        case GF_WATER:
        case GF_CHAOS:
        case GF_SHARDS:
        case GF_SOUND:
        case GF_CONFUSION:
        case GF_DISENCHANT:
        case GF_NEXUS:
        case GF_FORCE:
        case GF_INERTIA:
        case GF_TIME:
        case GF_GRAVITY:
        case GF_LITE:
        case GF_DARK:
        dam /= 2;
        break;


        /* Various */
        case GF_OLD_SLOW:
        case GF_OLD_CONF:
        case GF_OLD_SLEEP:
        case GF_OLD_POLY:
        case GF_OLD_HEAL:
        case GF_OLD_CLONE:
        case GF_OLD_SPEED:
        case GF_DARK_WEAK:
        case GF_KILL_WALL:
        case GF_KILL_DOOR:
        case GF_KILL_TRAP:
        case GF_MAKE_WALL:
        case GF_MAKE_DOOR:
        case GF_MAKE_TRAP:
        case GF_AWAY_UNDEAD:
        case GF_AWAY_EVIL:
        case GF_TURN_UNDEAD:
        case GF_TURN_EVIL:
        case GF_TURN_ALL:
        case GF_DISP_UNDEAD:
        case GF_DISP_EVIL:
        case GF_DISP_ALL:
        dam = 0;
        break;

        /* pretend the monster just gets trashed when it is telleported away */
        case GF_AWAY_ALL:
        dam = 999999;
        /* never teleport away uniques.   These are the guys you are trying */
        /* to kill! */
        if (r_ptr->flags1 & RF1_UNIQUE)
            dam = -5000000;

        break;
    }


    /* Limit damage to twice maximal hitpoints */
    if (dam > kill->power * 2) dam = kill->power * 2;

    /* give a small bonus for whacking a unique */
    /* this should be just enough to give prefrence to wacking uniques */
    if (r_ptr->flags1 & RF1_UNIQUE)
        dam++;

    /* Damage */
    return (dam);
}



/*
 * Simulate / Invoke the launching of a bolt at a monster
 */
static int borg_launch_bolt_aux_hack(int i, int dam, int typ)
{
    int d, p, x, y;

    auto_grid *ag;

    auto_kill *kill;


    /* Monster */
    kill = &auto_kills[i];

    /* Skip dead monsters */
    if (!kill->r_idx) return (0);

    /* Require current knowledge */
    if (kill->when < c_t) return (0);

    /* Acquire location */
    x = kill->x;
    y = kill->y;

    /* Acquire the grid */
    ag = &auto_grids[y][x];

    /* Never shoot walls/doors */
    if (!borg_cave_floor_grid(ag)) return (0);

    /* Hack -- Unknown grids should be avoided some of the time */
    if ((ag->feat == FEAT_NONE) && ((c_t % 8) == 0)) return (0);

    /* Hack -- Weird grids should be avoided some of the time */
    if ((ag->feat == FEAT_INVIS) && ((c_t % 8) == 0)) return (0);

    /* Calculate damage */
    d = borg_launch_damage_one(i, dam, typ);

    /* No damage */
    if (d <= 0 && typ != GF_AWAY_ALL) return (0);

    /* Calculate danger */
    p = borg_danger_aux(y, x, 1, i);

    /* Hack -- avoid waking most "hard" sleeping monsters */
    if (!kill->awake && 
        (p > avoidance / 2) && 
        (d < kill->power) && 
        typ != GF_AWAY_ALL)
    {
        return (-999);
    }

    /* Hack -- ignore "easy" / "sleeping" town monsters */
    if (!auto_depth && !kill->awake)
    {
        return (0);
    }

    /* Calculate "danger" to player */
    p = borg_danger_aux(c_y, c_x, 4, i);

    /* Reduce "bonus" of partial kills */
    if (d < kill->power) p = p / 10;
    
    /* for telleport away, danger is the only factor */
    if (typ == GF_AWAY_ALL && d > 0)
        d = 0;

    /* Add in power */
    d += p;

    /* Result */
    return (d);
}


/*
 * Determine the "reward" of launching a beam/bolt/ball at a location
 *
 * An "unreachable" location always has zero reward.
 *
 * Basically, we sum the "rewards" of doing the appropriate amount of
 * damage to each of the "affected" monsters.
 */
static int borg_launch_bolt_aux(int y, int x, int rad, int dam, int typ, int max)
{
    int i;

    int x1, y1;
    int x2, y2;

    int dist;

    int r, n;

    auto_grid *ag;


    /* Reset damage */
    n = 0;

    /* Initial location */
    x1 = c_x; y1 = c_y;

    /* Final location */
    x2 = x; y2 = y;

    /* Start over */
    x = x1; y = y1;

    /* Simulate the spell/missile path */
    for (dist = 0; dist < max; dist++)
    {
        /* Get the grid */
        ag = &auto_grids[y][x];

        /* Stop at walls */
        /* note: beams end at walls.  */
        if (dist)
        {
            /* Stop at walls */
            /* note if beam, this is the end of the beam */
            if (!borg_cave_floor_grid(ag))
            {
                if (rad != -1)
                    return (0);
                else
                    return (n);
            }
        }

        /* Collect damage (bolts/beams) */
        if (rad <= 0) n += borg_launch_bolt_aux_hack(ag->kill, dam, typ);

        /* Check for arrival at "final target" */
        /* except beams, which keep going. */
        if ((rad != -1) && ((x == x2) && (y == y2))) break;

        /* Stop bolts at monsters  */
        if (!rad && ag->kill) return (0);

        if (dist)
        {
            /* Stop at unknown grids (see above) */
            /* note if beam, this is the end of the beam */
            if (ag->feat == FEAT_NONE)
            {
                if (rad != -1)
                    return (0);
                else
                    return (n);
            }

            /* Stop at weird grids (see above) */
            /* note if beam, this is the end of the beam */
            if (ag->feat == FEAT_INVIS)
            {
                if (rad != -1)
                    return (0);
                else
                    return (n);
            }
        }

        /* Calculate the new location */
        mmove2(&y, &x, y1, x1, y2, x2);
    }

    /* Bolt/Beam attack */
    if (rad <= 0) return (n);

    /* Excessive distance */
    if (dist >= MAX_RANGE) return (0);

    /* Check monsters in blast radius */
    for (i = 0; i < auto_temp_n; i++)
    {
        /* Acquire location */
        x = auto_temp_x[i];
        y = auto_temp_y[i];

        /* Get the grid */
        ag = &auto_grids[y][x];

        /* Check distance */
        r = distance(y2, x2, y, x);

        /* Maximal distance */
        if (r > rad) continue;

        /* Never pass through walls */
        if (!borg_los(y2, x2, y, x)) continue;

        /* Collect damage, lowered by distance */
        n += borg_launch_bolt_aux_hack(ag->kill, dam / (r + 1), typ);

        /* check destroyed stuff. */
        if (ag->take)
        {
            auto_take *take = &auto_takes[ag->take];
            object_kind *k_ptr = &k_info[take->k_idx];

            switch (typ)
            {
                case GF_ACID:
                {
                    /* rings/boots cost extra (might be speed!) */
                    if (k_ptr->tval == TV_BOOTS)
                    {
                        n -= 2000;
                    }
                    break;
                }
                case GF_ELEC:
                {
                    /* rings/boots cost extra (might be speed!) */
                    if (k_ptr->tval == TV_RING)
                    {
                        n -= 2000;
                    }
                    break;
                }

                case GF_FIRE:
                    /* rings/boots cost extra (might be speed!) */
                    if (k_ptr->tval == TV_BOOTS)
                    {
                        n -= 2000;
                    }
                    break;

                case GF_COLD:
                {
                    if (k_ptr->tval == TV_POTION)
                    {
                        n -= 2000;
                    }
                    break;
                }
                case GF_MANA:
                {
                    /* rings/boots cost extra (might be speed!) */
                    if (k_ptr->tval == TV_RING || 
                        k_ptr->tval == TV_BOOTS || 
                        k_ptr->tval == TV_POTION)
                    {
                        n -= 2000;
                    }
                    break;
                }
            }
        }
    }

    /* Result */
    return (n);
}


/*
 * Simulate/Apply the optimal result of launching a beam/bolt/ball
 *
 * Note that "beams" have a "rad" of "-1", "bolts" have a "rad" of "0",
 * and "balls" have a "rad" of "2" or "3", depending on "blast radius".
 */
static int borg_launch_bolt(int rad, int dam, int typ, int max)
{
    int num = 0;

    int i, b_i = -1;
    int n, b_n = 0;


    /* Examine possible destinations */
    for (i = 0; i < auto_temp_n; i++)
    {
        int x = auto_temp_x[i];
        int y = auto_temp_y[i];

        /* Consider it */
        n = borg_launch_bolt_aux(y, x, rad, dam, typ, max);

        /* Skip useless attacks */
        if (n <= 0) continue;

        /* Collect best attack */
        if ((b_i >= 0) && (n < b_n)) continue;

        /* Hack -- reset chooser */
        if ((b_i >= 0) && (n > b_n)) num = 0;

        /* Apply the randomizer */
        if ((num > 1) && (rand_int(num) != 0)) continue;

        /* Track it */
        b_i = i;
        b_n = n;
    }

    /* Simulation */
    if (auto_simulate) return (b_n);


    /* Save the location */
    g_x = auto_temp_x[b_i];
    g_y = auto_temp_y[b_i];

    /* Target the location */
    (void)borg_target(g_y, g_x);

    /* Result */
    return (b_n);
}


/*
 * Simulate/Apply the optimal result of launching a normal missile
 *
 * First, pick the "optimal" ammo, then pick the optimal target
 */
static int borg_attack_aux_launch(void)
{
    int b_n;

    int k, b_k = -1;
    int d, b_d = -1;

    auto_item *bow = &auto_items[INVEN_BOW];


    /* Scan the pack */
    for (k = 0; k < INVEN_PACK; k++)
    {
        auto_item *item = &auto_items[k];

        /* Skip empty items */
        if (!item->iqty) continue;

        /* Skip bad missiles */
        if (item->tval != my_ammo_tval) continue;

        /* Skip worthless missiles */
        if (item->value <= 0) continue;

        /* Skip un-identified, non-average, missiles */
        if (!item->able && !streq(item->note, "{average}")) continue;

        /* Determine average damage */
        d = (item->dd * (item->ds + 1) / 2);
        d = d + item->to_d + bow->to_d;
        d = d * my_ammo_power * my_num_fire;

/* !FIX should do several things here; branded ammo, chance to hit, saving*/
/* good ammo for big baddies.  oh well... later.  AJG */

        /* Paranoia */
        if (d <= 0) continue;

        /* Ignore worse damage */
        if ((b_k >= 0) && (d <= b_d)) continue;

        /* Track */
        b_k = k;
        b_d = d;
    }

    /* Nothing to use */
    if (b_k < 0) return (0);


    /* No firing while blind, confused, or hallucinating */
    if (do_blind || do_confused || do_image) return (0);


    /* Choose optimal location */
    b_n = borg_launch_bolt(0, b_d, GF_ARROW, MAX_RANGE);

    /* Cost one point */
    b_n = b_n - 1;

    /* Simulation */
    if (auto_simulate) return (b_n);


    /* Do it */
    borg_note(format("# Firing standard missile '%s'",
                     auto_items[b_k].desc));

    /* Fire */
    borg_keypress('f');

    /* Use the missile */
    borg_keypress(I2A(b_k));

    /* Use target */
    borg_keypress('5');

    /* Value */
    return (b_n);
}



/*
 * Simulate/Apply the optimal result of throwing an object
 *
 * First choose the "best" object to throw, then check targets.
 */
static int borg_attack_aux_object(void)
{
    int b_n;

    int b_r = 0;

    int k, b_k = -1;
    int d, b_d = -1;

    int div, mul;

    /* Scan the pack */
    for (k = 0; k < INVEN_PACK; k++)
    {
        auto_item *item = &auto_items[k];

        /* Skip empty items */
        if (!item->iqty) continue;

        /* Skip un-identified, non-average, objects */
        if (!item->able && !streq(item->note, "{average}")) continue;

        /* Skip "equipment" items (not ammo) */
        if (borg_wield_slot(item) >= 0) continue;

        /* Determine average damage from object */
        d = (k_info[item->kind].dd * (k_info[item->kind].ds + 1) / 2);

        /* Skip useless stuff */
        if (d <= 0) continue;

        /* Skip "expensive" stuff */
        if (d < item->value) continue;

        /* Hack -- Save last five flasks for fuel, if needed */
        if ((item->tval == TV_FLASK) && (amt_fuel <= 5)) continue;

        /* Ignore worse damage */
        if ((b_k >= 0) && (d <= b_d)) continue;

        /* Track */
        b_k = k;
        b_d = d;

        /* Extract a "distance multiplier" */
        mul = 10;

        /* Enforce a minimum "weight" of one pound */
        div = ((item->weight > 10) ? item->weight : 10);

        /* Hack -- Distance -- Reward strength, penalize weight */
        b_r = (adj_str_blow[my_stat_ind[A_STR]] + 20) * mul / div;

        /* Max distance of 10 */
        if (b_r > 10) b_r = 10;
    }

    /* Nothing to use */
    if (b_k < 0) return (0);


    /* No firing while blind, confused, or hallucinating */
    if (do_blind || do_confused || do_image) return (0);


    /* Choose optimal location */
    b_n = borg_launch_bolt(0, b_d, GF_ARROW, b_r);

    /* Cost one point */
    b_n = b_n - 1;

    /* Simulation */
    if (auto_simulate) return (b_n);


    /* Do it */
    borg_note(format("# Throwing painful object '%s'",
                     auto_items[b_k].desc));

    /* Fire */
    borg_keypress('v');

    /* Use the object */
    borg_keypress(I2A(b_k));

    /* Use target */
    borg_keypress('5');

    /* Value */
    return (b_n);
}




/*
 * Simulate/Apply the optimal result of using a "normal" attack spell
 *
 * Take into account the failure rate of spells/objects/etc.  XXX XXX XXX
 */
static int borg_attack_aux_spell_bolt(int book, int what, int rad, int dam, int typ)
{
    int b_n;

    auto_magic *as = &auto_magics[book][what];


    /* No firing while blind, confused, or hallucinating */
    if (do_blind || do_confused || do_image) return (0);

    /* make sure I am powerfull enough to do another goi if this one falls */
    if (borg_goi && ((auto_csp - as->power) < 70)) return (0);

    /* Paranoia */
    if (auto_simulate && (rand_int(100) < 10)) return (0);

    /* Require ability (right now) */
/* !FIX AJG should check for %fail.... but what fail rate to use?  */
/* 40% for now...*/
    if (!borg_spell_okay_fail(book, what, 40)) return (0);


    /* Choose optimal location */
    b_n = borg_launch_bolt(rad, dam, typ, MAX_RANGE);

    /* Penalize mana usage */
    b_n = b_n - as->power;

    /* Penalize use of reserve mana */
    if (auto_csp - as->power < auto_msp / 2) b_n = b_n - (as->power * 10);

    /* Really penalize use of mana needed for final teleport */
    /* (6 pts for mage) */
    if ((auto_msp > 30) && (auto_csp - as->power) < 6)
        b_n = b_n - (as->power * 50);

    /* Simulation */
    if (auto_simulate) return (b_n);


    /* Cast the spell */
    (void)borg_spell(book, what);

    /* Use target */
    borg_keypress('5');

    /* Value */
    return (b_n);
}



/*
 * Simulate/Apply the optimal result of using a "normal" attack prayer
 */
static int borg_attack_aux_prayer_bolt(int book, int what, int rad, int dam, int typ)
{
    int b_n;

    auto_magic *as = &auto_magics[book][what];


    /* No firing while blind, confused, or hallucinating */
    if (do_blind || do_confused || do_image) return (0);


    /* Paranoia */
    if (auto_simulate && (rand_int(100) < 10)) return (0);


    /* Require ability */
    if (!borg_prayer_okay(book, what)) return (0);


    /* Choose optimal location */
    b_n = borg_launch_bolt(rad, dam, typ, MAX_RANGE);

    /* Penalize mana usage */
    b_n = b_n - as->power;

    /* Penalize use of reserve mana */
    if (auto_csp - as->power < auto_msp / 2) b_n = b_n - as->power * 10;

    /* Simulation */
    if (auto_simulate) return (b_n);


    /* Cast the prayer */
    (void)borg_prayer(book, what);

    /* Use target */
    borg_keypress('5');

    /* Value */
    return (b_n);
}



/*
 * Simulate/Apply the optimal result of using a "normal" attack rod
 */
static int borg_attack_aux_rod_bolt(int sval, int rad, int dam, int typ)
{
    int i;

    int b_n;


    /* No firing while blind, confused, or hallucinating */
    if (do_blind || do_confused || do_image) return (0);


    /* Paranoia */
    if (auto_simulate && (rand_int(100) < 10)) return (0);


    /* Look for that rod */
    i = borg_slot(TV_ROD, sval);

    /* None available */
    if (i < 0) return (0);

    /* Still "charging" */
    if (!auto_items[i].pval) return (0);


    /* Choose optimal location */
    b_n = borg_launch_bolt(rad, dam, typ, MAX_RANGE);

    /* Simulation */
    if (auto_simulate) return (b_n);


    /* Zap the rod */
    (void)borg_zap_rod(sval);

    /* Use target */
    borg_keypress('5');

    /* Value */
    return (b_n);
}



/*
 * Simulate/Apply the optimal result of using a "normal" attack wand
 */
static int borg_attack_aux_wand_bolt(int sval, int rad, int dam, int typ)
{
    int i;

    int b_n;


    /* No firing while blind, confused, or hallucinating */
    if (do_blind || do_confused || do_image) return (0);


    /* Paranoia */
    if (auto_simulate && (rand_int(100) < 10)) return (0);


    /* Look for that wand */
    i = borg_slot(TV_WAND, sval);

    /* None available */
    if (i < 0) return (0);

    /* No charges */
    if (!auto_items[i].pval) return (0);


    /* Choose optimal location */
    b_n = borg_launch_bolt(rad, dam, typ, MAX_RANGE);

    /* Penalize charge usage */
    b_n = b_n - 5;

    /* Simulation */
    if (auto_simulate) return (b_n);


    /* Aim the wand */
    (void)borg_aim_wand(sval);

    /* Use target */
    borg_keypress('5');

    /* Value */
    return (b_n);
}



/*
 * Simulate/Apply the optimal result of using the given "type" of attack
 */
static int borg_attack_aux(int what)
{
    int dam = 0, rad = 0;

    /* Analyze */
    switch (what)
    {
        /* Physical attack */
        case BF_THRUST:
        return (borg_attack_aux_thrust());


        /* Missile attack */
        case BF_LAUNCH:
        return (borg_attack_aux_launch());


        /* Object attack */
        case BF_OBJECT:
        return (borg_attack_aux_object());


        /* Spell -- magic missile */
        case BF_SPELL_MAGIC_MISSILE:
        dam = (3+((auto_level-1)/5))*(4+1)/2;
        return (borg_attack_aux_spell_bolt(0, 0, rad, dam, GF_MISSILE));

        /* Spell -- electric bolt */
        case BF_SPELL_ELEC_BOLT:
        dam = (3+((auto_level-5)/4))*(8+1)/2;
        return (borg_attack_aux_spell_bolt(1, 1, rad, dam, GF_ELEC));

        /* Spell -- cold bolt */
        case BF_SPELL_COLD_BOLT:
        dam = (5+((auto_level-5)/4))*(8+1)/2;
        return (borg_attack_aux_spell_bolt(1, 7, rad, dam, GF_COLD));

        /* Spell -- fire bolt */
        case BF_SPELL_FIRE_BOLT:
        dam = (8+((auto_level-5)/4))*(8+1)/2;
        return (borg_attack_aux_spell_bolt(2, 6, rad, dam, GF_FIRE));

        /* Spell -- acid bolt */
        case BF_SPELL_ACID_BOLT:
        dam = (6+((auto_level-5)/4))*(8+1)/2;
        return (borg_attack_aux_spell_bolt(8, 0, rad, dam, GF_ACID));


        /* Spell -- light beam */
        case BF_SPELL_LITE_BEAM:
        rad = -1;
        dam = (6*(8+1)/2);
        return (borg_attack_aux_spell_bolt(8, 0, rad, dam, GF_LITE_WEAK));


        /* Spell -- stinking cloud */
        case BF_SPELL_POISON_BALL:
        rad = 2;
        dam = (10 + (auto_level/2));
        return (borg_attack_aux_spell_bolt(0, 8, rad, dam, GF_POIS));

        /* Spell -- cold ball */
        case BF_SPELL_COLD_BALL:
        rad = 2;
        dam = (30 + auto_level);
        return (borg_attack_aux_spell_bolt(3, 0, rad, dam, GF_COLD));

        /* Spell -- acid ball */
        case BF_SPELL_ACID_BALL:
        rad = 2;
        dam = (40 + (auto_level/2));
        return (borg_attack_aux_spell_bolt(8, 2, rad, dam, GF_ACID));

        /* Spell -- fire ball */
        case BF_SPELL_FIRE_BALL:
        rad = 2;
        dam = (55 + auto_level);
        return (borg_attack_aux_spell_bolt(3, 4, rad, dam, GF_FIRE));


        /* Spell -- poison storm */
        case BF_SPELL_POISON_STORM:
        rad = 3;
        dam = (20 + (auto_level/2));
        return (borg_attack_aux_spell_bolt(8, 1, rad, dam, GF_POIS));

        /* Spell -- cold storm */
        case BF_SPELL_COLD_STORM:
        rad = 3;
        dam = (70 + auto_level);
        return (borg_attack_aux_spell_bolt(8, 3, rad, dam, GF_COLD));

        /* Spell -- meteor storm */
        case BF_SPELL_METEOR_STORM:
        rad = 3;
        dam = (65 + auto_level);
        return (borg_attack_aux_spell_bolt(8, 4, rad, dam, GF_METEOR));

        /* Spell -- mana storm */
        case BF_SPELL_MANA_STORM:

        rad = 3;
        dam = (300 + (auto_level * 2));
        return (borg_attack_aux_spell_bolt(8, 5, rad, dam, GF_MANA));


        /* Prayer -- orb of draining */
        case BF_PRAYER_HOLY_ORB_BALL:
        rad = ((auto_level >= 30) ? 3 : 2);
        dam = ((auto_class == 2) ? 2 : 4);
        dam = (3*(8+1)/2 + auto_level + (auto_level/dam));
        return (borg_attack_aux_prayer_bolt(2, 1, rad, dam, GF_HOLY_ORB));


        /* Wand -- elec bolt */
        case BF_ROD_ELEC_BOLT:
        dam = 3*(8+1)/2;
        return (borg_attack_aux_rod_bolt(SV_ROD_ELEC_BOLT, rad, dam, GF_ELEC));

        /* Wand -- cold bolt */
        case BF_ROD_COLD_BOLT:
        dam = 5*(8+1)/2;
        return (borg_attack_aux_rod_bolt(SV_ROD_COLD_BOLT, rad, dam, GF_COLD));

        /* Wand -- acid bolt */
        case BF_ROD_ACID_BOLT:
        dam = 6*(8+1)/2;
        return (borg_attack_aux_rod_bolt(SV_ROD_ACID_BOLT, rad, dam, GF_ACID));

        /* Wand -- fire bolt */
        case BF_ROD_FIRE_BOLT:
        dam = 8*(8+1)/2;
        return (borg_attack_aux_rod_bolt(SV_ROD_FIRE_BOLT, rad, dam, GF_FIRE));


        /* Spell -- light beam */
        case BF_ROD_LITE_BEAM:
        rad = -1;
        dam = (6*(8+1)/2);
        return (borg_attack_aux_rod_bolt(SV_ROD_LITE, rad, dam, GF_LITE_WEAK));


        /* Wand -- elec ball */
        case BF_ROD_ELEC_BALL:
        rad = 2;
        dam = 32;
        return (borg_attack_aux_rod_bolt(SV_ROD_ELEC_BALL, rad, dam, GF_ELEC));

        /* Wand -- acid ball */
        case BF_ROD_COLD_BALL:
        rad = 2;
        dam = 48;
        return (borg_attack_aux_rod_bolt(SV_ROD_COLD_BALL, rad, dam, GF_COLD));

        /* Wand -- acid ball */
        case BF_ROD_ACID_BALL:
        rad = 2;
        dam = 60;
        return (borg_attack_aux_rod_bolt(SV_ROD_ACID_BALL, rad, dam, GF_ACID));

        /* Wand -- fire ball */
        case BF_ROD_FIRE_BALL:
        rad = 2;
        dam = 72;
        return (borg_attack_aux_rod_bolt(SV_ROD_FIRE_BALL, rad, dam, GF_FIRE));


        /* Wand -- magic missile */
        case BF_WAND_MAGIC_MISSILE:
        dam = 2*(6+1)/2;
        return (borg_attack_aux_wand_bolt(SV_WAND_MAGIC_MISSILE, rad, dam, GF_MISSILE));

        /* Wand -- elec bolt */
        case BF_WAND_ELEC_BOLT:
        dam = 3*(8+1)/2;
        return (borg_attack_aux_wand_bolt(SV_WAND_ELEC_BOLT, rad, dam, GF_ELEC));

        /* Wand -- cold bolt */
        case BF_WAND_COLD_BOLT:
        dam = 3*(8+1)/2;
        return (borg_attack_aux_wand_bolt(SV_WAND_COLD_BOLT, rad, dam, GF_COLD));

        /* Wand -- acid bolt */
        case BF_WAND_ACID_BOLT:
        dam = 5*(8+1)/2;
        return (borg_attack_aux_wand_bolt(SV_WAND_ACID_BOLT, rad, dam, GF_ACID));

        /* Wand -- fire bolt */
        case BF_WAND_FIRE_BOLT:
        dam = 6*(8+1)/2;
        return (borg_attack_aux_wand_bolt(SV_WAND_FIRE_BOLT, rad, dam, GF_FIRE));


        /* Spell -- light beam */
        case BF_WAND_LITE_BEAM:
        rad = -1;
        dam = (6*(8+1)/2);
        return (borg_attack_aux_wand_bolt(SV_WAND_LITE, rad, dam, GF_LITE_WEAK));


        /* Wand -- stinking cloud */
        case BF_WAND_STINKING_CLOUD:
        rad = 2;
        dam = 12;
        return (borg_attack_aux_wand_bolt(SV_WAND_STINKING_CLOUD, rad, dam, GF_POIS));

        /* Wand -- elec ball */
        case BF_WAND_ELEC_BALL:
        rad = 2;
        dam = 32;
        return (borg_attack_aux_wand_bolt(SV_WAND_ELEC_BALL, rad, dam, GF_ELEC));

        /* Wand -- acid ball */
        case BF_WAND_COLD_BALL:
        rad = 2;
        dam = 48;
        return (borg_attack_aux_wand_bolt(SV_WAND_COLD_BALL, rad, dam, GF_COLD));

        /* Wand -- acid ball */
        case BF_WAND_ACID_BALL:
        rad = 2;
        dam = 60;
        return (borg_attack_aux_wand_bolt(SV_WAND_ACID_BALL, rad, dam, GF_ACID));

        /* Wand -- fire ball */
        case BF_WAND_FIRE_BALL:
        rad = 2;
        dam = 72;
        return (borg_attack_aux_wand_bolt(SV_WAND_FIRE_BALL, rad, dam, GF_FIRE));

        /* Wand -- dragon cold */
        case BF_WAND_DRAGON_COLD:
        rad = 3;
        dam = 80;
        return (borg_attack_aux_wand_bolt(SV_WAND_DRAGON_COLD, rad, dam, GF_COLD));

        /* Wand -- dragon fire */
        case BF_WAND_DRAGON_FIRE:
        rad = 3;
        dam = 100;
        return (borg_attack_aux_wand_bolt(SV_WAND_DRAGON_FIRE, rad, dam, GF_FIRE));
    }

    /* Oops */
    return (0);
}


/*
 * Attack nearby monsters, in the best possible way, if any.
 *
 * We consider a variety of possible attacks, including physical attacks
 * on adjacent monsters, missile attacks on nearby monsters, spell/prayer
 * attacks on nearby monsters, and wand/rod attacks on nearby monsters.
 *
 * Basically, for each of the known "types" of attack, we "simulate" the
 * "optimal" result of using that attack, and then we "apply" the "type"
 * of attack which appears to have the "optimal" result.
 *
 * When calculating the "result" of using an attack, we only consider the
 * effect of the attack on visible, on-screen, known monsters, which are
 * within 16 grids of the player.  This prevents most "spurious" attacks,
 * but we can still be fooled by situations like creeping coins which die
 * while out of sight, leaving behind a pile of coins, which we then find
 * again, and attack with distance attacks, which have no effect.  Perhaps
 * we should "expect" certain results, and take note of failure to observe
 * those effects.  XXX XXX XXX
 *
 * See above for the "semantics" of each "type" of attack.
 */
bool borg_attack(void)
{
    int i, x, y;

    int n, b_n = 0;
    int g, b_g = -1;

    auto_grid *ag;

    /* Nobody around */
    if (!auto_kills_cnt) return (FALSE);

    /* Set the attacking flag so that danger is boosted for monsters */
    /* we want to attack first. */
    borg_attacking = TRUE;

    /* Reset list */
    auto_temp_n = 0;

    /* Find "nearby" monsters */
    for (i = 1; i < auto_kills_nxt; i++)
    {
        auto_kill *kill;

        /* Monster */
        kill = &auto_kills[i];

        /* Skip dead monsters */
        if (!kill->r_idx) continue;

        /* Require current knowledge */
        if (kill->when < c_t) continue;

        /* Ignore multiplying monsters */
        if (goal_ignoring && !do_afraid &&
            (r_info[kill->r_idx].flags2 & RF2_MULTIPLY)) continue;

        /* Acquire location */
        x = kill->x;
        y = kill->y;

        /* Get grid */
        ag = &auto_grids[y][x];

        /* Never shoot off-screen */
        if (!(ag->info & BORG_OKAY)) continue;

        /* Never shoot through walls */
        if (!(ag->info & BORG_VIEW)) continue;

        /* Check the distance XXX XXX XXX */
        if (distance(c_y, c_x, y, x) > 16) continue;

        /* Save the location (careful) */
        auto_temp_x[auto_temp_n] = x;
        auto_temp_y[auto_temp_n] = y;
        auto_temp_n++;
    }

    /* No destinations */
    if (!auto_temp_n) 
    {
        borg_attacking = FALSE;
        return (FALSE);
    }

    /* Simulate */
    auto_simulate = TRUE;

    /* Analyze the possible attacks */
    for (g = 0; g < BF_MAX; g++)
    {
        /* Simulate */
        n = borg_attack_aux(g);

        /* Track "best" attack */
        if (n <= b_n) continue;

        /* Track best */
        b_g = g;
        b_n = n;
    }

    /* Nothing good */
    if (b_n <= 0)
    {
        borg_attacking = FALSE;
        return (FALSE);
    }


    /* Note */
    borg_note(format("# Performing attack type %d with value %d", b_g, b_n));

    /* Instantiate */
    auto_simulate = FALSE;

    /* Instantiate */
    (void)borg_attack_aux(b_g);

    borg_attacking = FALSE;

    /* Success */
    return (TRUE);
}

/*
 * try to make this look like borg_attack stuff
 *
 * There are several types of seup moves:
 *
 *   Temporary speed
 *   Protect From Evil
 *   Bless\Prayer
 *   Berserk\Heroism
 *   Temp Resist (either all or just cold/fire?)
 *   Shield
 *   teleport away
 *
 *
 * * see inviso? 
 * * Glyph of Warding
 *   
 * * some day!
 *
 */
enum
{
    BD_SPEED,
    BD_PROT_FROM_EVIL,
    BD_BLESS,
    BD_BERSERK,
    BD_HERO,
    BD_RESIST1,
    BD_RESIST2,
    BD_RESIST3,
    BD_RESIST4,
    BD_RESIST5,
    BD_RESIST6,
    BD_SHIELD,
    BD_GOI,
    BD_TELL_AWAY,
    BD_CREATE_DOOR,

    BD_MAX
};

/*
 * Bless/Prayer to prepare for battle
 */
static int borg_defend_aux_bless( int p1 )
{
    int fail_allowed = 10;

    /* already blessed */
    if (borg_bless)
        return 0;

    if ( !borg_prayer_okay_fail(0, 2, fail_allowed) &&
         !borg_prayer_okay_fail(3, 0, fail_allowed ) &&
         !borg_prayer_okay_fail(1, 3, fail_allowed ))
        return 0;

    /* if we are in some danger but not much, go for a quick bless */
    if (p1 > avoidance/7 && p1 < avoidance/3)
    {
        /* Simulation */
        /* bless is a low priority */
        if (auto_simulate) return (1);

        /* do it! */
        if ( borg_prayer_fail( 3, 0, fail_allowed ) ||
             borg_prayer_fail( 1, 3, fail_allowed ) ||
             borg_prayer_fail( 0, 2, fail_allowed ))
             return 1;
    }
    
    return 0;
}

/*
 * Speed to prepare for battle
 */
static int borg_defend_aux_speed( int p1 )
{
    int p2 = 0;
/*    int i = 0; */
    bool good_speed = FALSE;
    bool speed_spell = FALSE;
    bool speed_staff = FALSE;
    bool speed_rod = FALSE;
    int fail_allowed = 20;

    /* already fast */
    if (borg_speed) 
        return 0;

    /* if very scary, do not allow for much chance of fail */
    if ( p1 > avoidance)
        fail_allowed -= 19;
    else
    /* a little scary */
    if ( p1 > (avoidance*2)/3)
        fail_allowed -= 10;
    else
    /* not very scary, allow lots of fail */
    if ( p1 < avoidance/3)
        fail_allowed += 20;
    
    /* only cast defence spells if fail rate is not too high */
    if ( borg_spell_okay_fail( 3, 3, fail_allowed ) ||
         borg_spell_okay_fail( 7, 3, fail_allowed ))
        speed_spell = TRUE;

    /* staff must have charges */
    if ( -1 != borg_slot(TV_STAFF, SV_STAFF_SPEED) &&
         auto_items[borg_slot(TV_STAFF, SV_STAFF_SPEED)].pval)
        speed_staff = TRUE;

    /* rod can't be charging */
    if ( -1 != borg_slot(TV_ROD, SV_ROD_SPEED) &&
         auto_items[borg_slot(TV_ROD, SV_ROD_SPEED)].pval)
        speed_rod = TRUE;

    if (0 > borg_slot(TV_POTION, SV_POTION_SPEED) &&
        !speed_staff &&
        !speed_rod &&
        !speed_spell)
        return 0;

    /* if we have an infinite/large suppy of speed we can */
    /* be generious with our use */
    if (speed_rod || speed_spell || speed_staff)
        good_speed = TRUE;

    /* pretend we are protected and look again */
    borg_speed = TRUE;
    p2 = borg_danger(c_y, c_x, 1);
    borg_speed = FALSE;

    /* if we just did GOI do a speed right after. */
    if (good_speed && borg_goi)
    {
        /* HACK pretend that it was scary and will be very safe */
        /* This is done because GOI messes up our calculations */
        p1 = 10000;
        p2 = 1;
    }

    /* if this is an improvement and we may not avoid monster now and */
    /* we may have before */
    if ( ((p1 > p2) && 
         p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/2)) && 
         (p1 > (avoidance/8)) && good_speed) ||
         ((p1 > p2) && 
         p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/3)) && 
         (p1 > (avoidance/2))))
    {
        /* Simulation */
        if (auto_simulate) return (p1-p2 + borg_goi * 50);

        /* do it! */
        if (borg_spell_fail( 7, 3, fail_allowed))
            return (p1-p2);

        if (borg_spell_fail( 3, 3, fail_allowed))
            return (p1-p2);

        if ( borg_zap_rod( SV_ROD_SPEED ) ||
             borg_use_staff( SV_STAFF_SPEED) ||
             borg_quaff_potion(SV_POTION_SPEED) )
            /* Value */
            return (p1-p2 + borg_goi * 50);
    }

    /* default to can't do it. */
    return 0;
}

/* 
 * Globe of Invulnurability
 */
static int borg_defend_aux_goi(int p1)
{
    int p2 = 0;
/*  int i = 0; */
    int fail_allowed = 20;

    if (borg_goi)
        return 0;

    /* if very scary, do not allow for much chance of fail */
    if ( p1 > avoidance)
        fail_allowed -= 19;
    else
    /* a little scary */
    if ( p1 > (avoidance*2)/3)
        fail_allowed -= 10;
    else
    /* a bit scary */
    if ( p1 > (avoidance/2))
        fail_allowed -= 5;
    else
    /* not very scary, allow lots of fail */
    if ( p1 < avoidance/4)
        fail_allowed += 10;

    if (!borg_spell_okay_fail(7, 4, fail_allowed))
        return 0;

    /* pretend we are protected and look again */
    borg_goi = TRUE;
    p2 = borg_danger(c_y, c_x, 1);
    borg_goi = FALSE;

    /* if this is an improvement and we may not avoid monster now and */
    /* we may have before */
    if (p1 > p2 && 
        p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/2)) && 
        p1 > (avoidance/8))
    {
        /* Simulation */
        if (auto_simulate) return (p1-p2);

        /* do it! */
        borg_spell(7, 4);

        /* Value */
        return (p1-p2);
    }

    /* default to can't do it. */
    return 0;
}

/* cold/fire */
static int borg_defend_aux_resist1( p1 )
{
    int p2 = 0;
/*  int i = 0; */
    int fail_allowed = 20;
    bool    save_fire, 
            save_cold;

    if (borg_temp_fire &&
        borg_temp_cold)
        return 0;

    /* if very scary, do not allow for much chance of fail */
    if ( p1 > avoidance)
        fail_allowed -= 19;
    else
    /* a little scary */
    if ( p1 > (avoidance*2)/3)
        fail_allowed -= 10;
    else
    /* not very scary, allow lots of fail */
    if ( p1 < avoidance/3)
        fail_allowed += 20;

    if (!borg_prayer_okay_fail(1, 7, fail_allowed))
        return 0;

    /* pretend we are protected and look again */
    save_fire = borg_temp_fire;
    save_cold = borg_temp_cold;
    borg_temp_fire = TRUE;
    borg_temp_cold = TRUE;
    p2 = borg_danger(c_y, c_x, 1);
    borg_temp_fire = save_fire;
    borg_temp_cold = save_cold;

    /* if this is an improvement and we may not avoid monster now and */
    /* we may have before */
    if (p1 > p2 && 
        p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/2)) && 
        p1 > (avoidance/8))
    {
        /* Simulation */
        if (auto_simulate) return (p1-p2);

        /* do it! */
        borg_prayer(1, 7);

        /* Value */
        return (p1-p2);
    }

    /* default to can't do it. */
    return 0;
}

/* all resists */
static int borg_defend_aux_resist2( int p1)
{
    int p2 = 0;
/*  int i = 0; */
    int fail_allowed = 20;
    bool    save_fire, 
            save_acid, 
            save_poison, 
            save_elec, 
            save_cold;

    if (borg_temp_fire &&
        borg_temp_acid &&
        borg_temp_poison &&
        borg_temp_elec &&
        borg_temp_cold)
        return 0;

    /* if very scary, do not allow for much chance of fail */
    if ( p1 > avoidance)
        fail_allowed -= 19;
    else
    /* a little scary */
    if ( p1 > (avoidance*2)/3)
        fail_allowed -= 10;
    else
    /* not very scary, allow lots of fail */
    if ( p1 < avoidance/3)
        fail_allowed += 20;

    if (!borg_spell_okay_fail(4, 4, fail_allowed))
        return 0;

    /* pretend we are protected and look again */
    save_fire = borg_temp_fire;
    save_acid = borg_temp_acid;
    save_poison =  borg_temp_poison;
    save_elec = borg_temp_elec;
    save_cold = borg_temp_cold;
    borg_temp_fire = TRUE;
    borg_temp_cold = TRUE;
    borg_temp_acid = TRUE;
    borg_temp_poison = TRUE;
    borg_temp_elec = TRUE;
    p2 = borg_danger(c_y, c_x, 1);
    borg_temp_fire = save_fire;
    borg_temp_cold = save_cold;
    borg_temp_acid = save_acid;
    borg_temp_poison = save_poison;
    borg_temp_elec = save_elec;

    /* if this is an improvement and we may not avoid monster now and */
    /* we may have before */
    if (p1 > p2 && 
        p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/2)) && 
        p1 > (avoidance/8))
    {
        /* Simulation */
        if (auto_simulate) return ((p1-p2) -1);

        /* do it! */
        borg_spell(4, 4);

        /* Value */
        return ((p1-p2)-1);
    }

    /* default to can't do it. */
    return 0;
}

/* fire */
static int borg_defend_aux_resist3( p1 )
{
    int p2 = 0;
/*  int i = 0; */
    int fail_allowed = 20;
    bool    save_fire;

    if ( borg_temp_fire )
        return 0;

    /* if very scary, do not allow for much chance of fail */
    if ( p1 > avoidance)
        fail_allowed -= 19;
    else
    /* a little scary */
    if ( p1 > (avoidance*2)/3)
        fail_allowed -= 10;
    else
    /* not very scary, allow lots of fail */
    if ( p1 < avoidance/3)
        fail_allowed += 20;

    if (!borg_spell_okay_fail(4, 0, fail_allowed))
        return 0;

    save_fire = borg_temp_fire;
    /* pretend we are protected and look again */
    borg_temp_fire = TRUE;
    p2 = borg_danger(c_y, c_x, 1);
    borg_temp_fire = save_fire;

    /* if this is an improvement and we may not avoid monster now and */
    /* we may have before */
    if (p1 > p2 && 
        p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/2)) && 
        p1 > (avoidance/8))
    {
        /* Simulation */
        if (auto_simulate) return (p1-p2);

        /* do it! */
        borg_spell(4, 0);

        /* Value */
        return (p1-p2);
    }

    /* default to can't do it. */
    return 0;
}

/* cold */
static int borg_defend_aux_resist4( p1 )
{
    int p2 = 0;
/*  int i = 0; */
    int fail_allowed = 20;
    bool    save_cold;

    if ( borg_temp_cold )
        return 0;

    /* if very scary, do not allow for much chance of fail */
    if ( p1 > avoidance)
        fail_allowed -= 19;
    else
    /* a little scary */
    if ( p1 > (avoidance*2)/3)
        fail_allowed -= 10;
    else
    /* not very scary, allow lots of fail */
    if ( p1 < avoidance/3)
        fail_allowed += 20;

    if (!borg_spell_okay_fail(4, 1, fail_allowed))
        return 0;

    save_cold = borg_temp_cold;
    /* pretend we are protected and look again */
    borg_temp_cold = TRUE;
    p2 = borg_danger(c_y, c_x, 1);
    borg_temp_cold = save_cold;

    /* if this is an improvement and we may not avoid monster now and */
    /* we may have before */
    if (p1 > p2 && 
        p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/2)) && 
        p1 > (avoidance/8))
    {
        /* Simulation */
        if (auto_simulate) return (p1-p2);

        /* do it! */
        borg_spell(4, 1);

        /* Value */
        return (p1-p2);
    }

    /* default to can't do it. */
    return 0;
}

/* acid */
static int borg_defend_aux_resist5( p1 )
{
    int p2 = 0;
/*  int i = 0; */
    int fail_allowed = 20;
    bool    save_acid;

    if ( borg_temp_acid )
        return 0;

    /* if very scary, do not allow for much chance of fail */
    if ( p1 > avoidance)
        fail_allowed -= 19;
    else
    /* a little scary */
    if ( p1 > (avoidance*2)/3)
        fail_allowed -= 10;
    else
    /* not very scary, allow lots of fail */
    if ( p1 < avoidance/3)
        fail_allowed += 20;

    if (!borg_spell_okay_fail(4, 2, fail_allowed))
        return 0;

    save_acid = borg_temp_acid;
    /* pretend we are protected and look again */
    borg_temp_acid = TRUE;
    p2 = borg_danger(c_y, c_x, 1);
    borg_temp_acid = save_acid;

    /* if this is an improvement and we may not avoid monster now and */
    /* we may have before */
    if (p1 > p2 && 
        p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/2)) && 
        p1 > (avoidance/8))
    {
        /* Simulation */
        if (auto_simulate) return (p1-p2);

        /* do it! */
        borg_spell(4, 2);

        /* Value */
        return (p1-p2);
    }

    /* default to can't do it. */
    return 0;
}

/* poison */
static int borg_defend_aux_resist6( p1 )
{
    int p2 = 0;
/*  int i = 0; */
    int fail_allowed = 20;
    bool    save_poison;

    if ( borg_temp_poison )
        return 0;

    /* if very scary, do not allow for much chance of fail */
    if ( p1 > avoidance)
        fail_allowed -= 19;
    else
    /* a little scary */
    if ( p1 > (avoidance*2)/3)
        fail_allowed -= 10;
    else
    /* not very scary, allow lots of fail */
    if ( p1 < avoidance/3)
        fail_allowed += 20;

    if (!borg_spell_okay_fail(4, 3, fail_allowed))
        return 0;

    save_poison = borg_temp_poison;
    /* pretend we are protected and look again */
    borg_temp_poison = TRUE;
    p2 = borg_danger(c_y, c_x, 1);
    borg_temp_poison = save_poison;

    /* if this is an improvement and we may not avoid monster now and */
    /* we may have before */
    if (p1 > p2 && 
        p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/2)) && 
        p1 > (avoidance/8))
    {
        /* Simulation */
        if (auto_simulate) return (p1-p2);

        /* do it! */
        borg_spell(4, 3);

        /* Value */
        return (p1-p2);
    }

    /* default to can't do it. */
    return 0;
}

static int borg_defend_aux_prot_evil( int p1)
{
    int p2 = 0;
    int fail_allowed = 20;

    /* if already protected */
    if (borg_prot_from_evil) 
        return 0;

    /* if very scary, do not allow for much chance of fail */
    if ( p1 > avoidance)
        fail_allowed -= 19;
    else
    /* a little scary */
    if ( p1 > (avoidance*2)/3)
        fail_allowed -= 5;
    else
    /* not very scary, allow lots of fail */
    if ( p1 < avoidance/3)
        fail_allowed += 20;

    if ((!borg_prayer_okay_fail(2, 4, fail_allowed)) &&
        (0 > borg_slot(TV_SCROLL, SV_SCROLL_PROTECTION_FROM_EVIL)) )
        return 0;

    /* pretend we are protected and look again */
    borg_prot_from_evil = TRUE;
    p2 = borg_danger(c_y, c_x, 1);
    borg_prot_from_evil = FALSE;

    /* if this is an improvement and we may not avoid monster now and */
    /* we may have before */
    if (p1 > p2 && 
        p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/2)) && 
        p1 > (avoidance/8))
    {
        /* Simulation */
        if (auto_simulate) return (p1-p2);

        /* do it! */
        if (borg_prayer_fail(2, 4, fail_allowed))
            return (p1-p2);

        borg_read_scroll(SV_SCROLL_PROTECTION_FROM_EVIL);

        /* Value */
        return (p1-p2);
    }

    /* default to can't do it. */
    return 0;
}

static int borg_defend_aux_shield( int p1)
{
    int p2 = 0;
    int fail_allowed = 20;

    /* if already protected */
    if (borg_shield) 
        return 0;

    /* if very scary, do not allow for much chance of fail */
    if ( p1 > avoidance)
        fail_allowed -= 19;
    else
    /* a little scary */
    if ( p1 > (avoidance*2)/3)
        fail_allowed -= 5;
    else
    /* not very scary, allow lots of fail */
    if ( p1 < avoidance/3)
        fail_allowed += 20;

    if (!borg_spell_okay_fail(7, 1, fail_allowed))
        return 0;

    /* pretend we are protected and look again */
    borg_shield = TRUE;
    p2 = borg_danger(c_y, c_x, 1);
    borg_shield = FALSE;

    /* if this is an improvement and we may not avoid monster now and */
    /* we may have before */
    if (p1 > p2 && 
        p2 <= (borg_fighting_unique?((avoidance*2)/3): (avoidance/2)) && 
        p1 > (avoidance/8))
    {
        /* Simulation */
        if (auto_simulate) return (p1-p2);

        /* do it! */
        borg_spell_fail(7, 1, fail_allowed);
        return (p1-p2);
    }

    /* default to can't do it. */
    return 0;
}

/* 
 * Try to get rid of all of the non-uniques around so you can go at it
 * 'mano-e-mano' with the unique.
 */
static int borg_defend_aux_tell_away( int p1)
{
    int b_n = 0;

    int fail_allowed = 1;

    /* This is not working.  It keeps teleporting away the unique! */
    /* I will debug it later... */
    return -1;

    /* Only tell away if scared and there is a local unique */
    if ( p1 < avoidance/2)
        return 0;

    if (!borg_spell_okay_fail(3, 2, fail_allowed))
        return 0;

    if (!borg_fighting_unique) return 0;

    /* Choose optimal location */
    b_n = borg_launch_bolt(-1, 0, GF_AWAY_ALL, MAX_RANGE);

    /* if this doesn't help enough, don't bother. */
    if ((p1 - b_n) > (avoidance*2)/3) return 0;

    /* Simulation */
    if (auto_simulate) return (b_n);

    /* Cast the spell */
    if (borg_spell(3, 2))
    {
        /* Use target */
        borg_keypress('5');

        /* Value */
        return (b_n);
    }

    return 0;
}

/*
 * Simulate/Apply the optimal result of using the given "type" of defence
 * p1 is the current danger level (passed in for effiency)
 */
static int borg_defend_aux(int what, int p1)
{
    int dam = 0, rad = 0;

    /* Analyze */
    switch (what)
    {
        case BD_SPEED:
        {
            return (borg_defend_aux_speed(p1));
        }
        
        case BD_PROT_FROM_EVIL:
        {
            return (borg_defend_aux_prot_evil(p1));
        }
        case BD_RESIST1:
        {
            return (borg_defend_aux_resist1(p1));
        }
        case BD_RESIST2:
        {
            return (borg_defend_aux_resist2(p1));
        }
        case BD_RESIST3:
        {
            return (borg_defend_aux_resist3(p1));
        }
        case BD_RESIST4:
        {
            return (borg_defend_aux_resist4(p1));
        }
        case BD_RESIST5:
        {
            return (borg_defend_aux_resist5(p1));
        }
        case BD_RESIST6:
        {
            return (borg_defend_aux_resist6(p1));
        }
        case BD_BLESS:
        {
            return (borg_defend_aux_bless(p1));
        }
        case BD_HERO:
        {
/*"You feel like a hero!"*/
/*"The heroism wears off."        */
/*          return (borg_defend_aux_hero(p1)); */
            break;
        }
        case BD_BERSERK:
        {
/*"You feel like a killing machine!"*/
/*"You feel less Berserk."*/
/*          return (borg_defend_aux_berserk(p1));*/
            break;
        }
        case BD_SHIELD:
        {
            return (borg_defend_aux_shield(p1));
        }
        case BD_GOI:
        {
            return (borg_defend_aux_goi(p1));
        }
        case BD_TELL_AWAY:
        {
            return (borg_defend_aux_tell_away(p1));
        }
        case BD_CREATE_DOOR:
        {
/* to avoid summoners */
/* again, I have no formula... */
/*            return (borg_defend_aux_create_door(p1)); */
            break;
        }
    }
    return 0;
}

/* 
 * prepare to attack... this is setup for a battle.
 */
bool borg_defend(void)
{
    int p1, n, b_n = 0;
    int g, b_g = -1;

    /* Simulate */
    auto_simulate = TRUE;

    /* check danger level. (this is passed in for efficency) */
    p1 = borg_danger(c_y, c_x, 1);


    /* if you have a globe up and it is about to drop, */
    /* refresh it (if you can) */
    if (borg_goi && borg_goi < 2)
    {
        int p;

        /* check 'true' danger. This will make sure we do not */
        /* refresh our GOI if no-one is around */
        borg_attacking = TRUE;
        p = borg_danger(c_y, c_x, 1);
        borg_attacking = FALSE;
        if (p > auto_fear_region[c_y/11][c_x/11])
        {
            if (borg_spell(7, 4))
            {
                borg_note("# refreshing GOI ");

                borg_goi += 13;
                return (TRUE);
            }
        }
    }

    /* if no danger, no defence needed */
    /* HACK EXCEPT... if goi we will also do speed */
    if ((p1 <= auto_fear_region[c_y/11][c_x/11] && !borg_goi) ||
        (borg_goi && borg_speed)) 
        return FALSE;

    /* Analyze the possible setup moves */
    for (g = 0; g < BD_MAX; g++)
    {
        /* Simulate */
        n = borg_defend_aux(g, p1);

        /* Track "best" attack */
        if (n <= b_n) continue;

        /* Track best */
        b_g = g;
        b_n = n;
    }

    /* Nothing good */
    if (b_n <= 0)
    {
        return (FALSE);
    }

    /* Note */
    borg_note(format("# Performing defence type %d with value %d", b_g, b_n));

    /* Instantiate */
    auto_simulate = FALSE;

    /* Instantiate */
    (void)borg_defend_aux(b_g, p1);

    /* Success */
    return (TRUE);

}

/* 
 * check to make sure there are no monsters around 
 * that should prevent resting
 */
static bool borg_check_rest(void)
{
    int i;

    /* Examine all the monsters */
    for (i = 1; i < auto_kills_nxt; i++)
    {
        auto_kill *kill = &auto_kills[i];
        monster_race *r_ptr = &r_info[kill->r_idx];

        int x9 = kill->x;
        int y9 = kill->y;
        int ax, ay, d;

        /* Skip dead monsters */
        if (!kill->r_idx) continue;

        /* Distance components */
        ax = (x9 > c_x) ? (x9 - c_x) : (c_x - x9);
        ay = (y9 > c_y) ? (y9 - c_y) : (c_y - y9);

        /* Distance */
        d = MAX(ax, ay);

        /* Minimal distance */
        if (d > 20) continue;

        /* if breeder, not safe */
        if (r_ptr->flags2 & RF2_MULTIPLY) return FALSE;

        /* if absorbs mana, not safe */
/* should check LOS... oh well. AJG !FIX */
        if ((r_ptr->flags5 & RF5_DRAIN_MANA) && (auto_msp > 1)) return FALSE;
    }

    return TRUE;
}

/*
 * Attempt to recover from damage and such after a battle
 *
 * Note that resting while in danger is counter-productive, unless
 * the danger is low, in which case it may induce "farming".
 *
 * Note that resting while recall is active will often cause you
 * to lose hard-won treasure from nasty monsters, so we disable
 * resting when waiting for recall in the dungeon near objects.
 *
 * First we try spells/prayers, which are "free", and then we
 * try food, potions, scrolls, staffs, rods, artifacts, etc.
 *
 * XXX XXX XXX
 * Currently, we use healing spells as if they were "free", but really,
 * this is only true if the "danger" is less than the "reward" of doing
 * the healing spell, and if there are no monsters which might soon step
 * around the corner and attack.
 */
bool borg_recover(void)
{
    int p, q, i;

    /*** Handle annoying situations ***/

    /* Refuel current torch */
    if ((auto_items[INVEN_LITE].tval == TV_LITE) &&
        (auto_items[INVEN_LITE].sval == SV_LITE_TORCH))
    {
        /* Refuel the torch if needed */
        if (auto_items[INVEN_LITE].pval < 2500)
        {
            if (borg_refuel_torch()) return (TRUE);

            /* Take note */
            borg_note(format("# Need to refuel but cant!", p));
        }
    }

    /* Refuel current lantern */
    if ((auto_items[INVEN_LITE].tval == TV_LITE) &&
        (auto_items[INVEN_LITE].sval == SV_LITE_LANTERN))
    {
        /* Refuel the lantern if needed */
        if (auto_items[INVEN_LITE].pval < 5000)
        {
            if (borg_refuel_lantern()) return (TRUE);

            /* Take note */
            borg_note(format("# Need to refuel but cant!", p));
        }
    }


    /*** Do not recover when in danger ***/

    /* Look around for danger */
    p = borg_danger(c_y, c_x, 1);

    /* Never recover in dangerous situations */
    if (p > avoidance / 4) return (FALSE);


    /*** Roll for "paranoia" ***/

    /* Base roll */
    q = rand_int(100);

    /* Half dead */
    if (auto_chp < auto_mhp / 2) q = q - 10;

    /* Almost dead */
    if (auto_chp < auto_mhp / 4) q = q - 10;


    /*** Use "cheap" cures ***/

    /* Hack -- cure stun */
    if (do_stun && (q < 75))
    {
        if (borg_prayer(2, 7) ||
            borg_prayer(3, 2) ||
            borg_prayer(6, 1) ||
            borg_prayer(6, 2))
        {
            /* Take note */
            borg_note(format("# Cure Stun", p));

            return (TRUE);
        }
    }

    /* Hack -- cure stun */
    if (do_heavy_stun)
    {
        if (borg_prayer(2, 7) ||
            borg_prayer(3, 2) ||
            borg_prayer(6, 1) ||
            borg_prayer(6, 2))
        {
            /* Take note */
            borg_note(format("# Cure Heavy Stun", p));

            return (TRUE);
        }
    }

    /* Hack -- cure cuts */
    if (do_cut && (q < 75))
    {
        if (borg_prayer(2, 2) ||
            borg_prayer(2, 7) ||
            borg_prayer(3, 2) ||
            borg_prayer(6, 0) ||
            borg_prayer(6, 1) ||
            borg_prayer(6, 2))
        {
            /* Take note */
            borg_note(format("# Cure Cuts", p));

            return (TRUE);
        }
    }

    /* Hack -- cure poison */
    if (do_poisoned && (q < 75))
    {
        if (borg_spell(1, 4) ||
            borg_prayer(2, 0))
        {
            /* Take note */
            borg_note(format("# Cure poison", p));

            return (TRUE);
        }
    }

    /* Hack -- cure fear */
    if (do_afraid && (q < 75))
    {
        if (borg_spell(7, 2) ||
            borg_spell(7, 0) ||
            borg_prayer(0, 3))
        {
            /* Take note */
            borg_note(format("# Cure fear", p));

            return (TRUE);
        }
    }

    /* Hack -- satisfy hunger */
    if (do_hungry && (q < 75))
    {
        if (borg_spell(2, 0) ||
            borg_prayer(1, 5))
        {
            return (TRUE);
        }
    }

    /* Hack -- heal damage */
    if ((auto_chp < auto_mhp / 2) && (q < 75) && p == 0 && 
        (auto_csp > auto_msp /4))
    {
        if (borg_prayer(3, 2) ||
            borg_prayer(6, 2) ||
            borg_prayer(2, 7) ||
            borg_prayer(6, 1) )
        {
            /* Take note */
            borg_note(format("# heal damage (recovering)"));

            return (TRUE);
        }
    }

    /* cure experience loss with prayer */
    if (do_fix_exp && borg_prayer(6, 4))
    {
        return (TRUE);
    }

    /* cure stat drain with prayer */
    for (i = 0; i < 6; i++)
    {
        if ( do_fix_stat[i] && borg_prayer(6, 3) )
        {
            return (TRUE);
        }
    }

    /*** Use "expensive" cures ***/

    /* Hack -- cure stun */
    if (do_stun && (q < 25))
    {
        if (borg_quaff_potion(SV_POTION_CURE_CRITICAL) ||
            borg_use_staff(SV_STAFF_CURING) ||
            borg_zap_rod(SV_ROD_CURING) ||
            borg_zap_rod(SV_ROD_HEALING))
        {
            return (TRUE);
        }
    }

    /* Hack -- cure heavy stun */
    if (do_heavy_stun && (q < 95))
    {
        if (borg_quaff_potion(SV_POTION_CURE_CRITICAL) ||
            borg_use_staff(SV_STAFF_CURING) ||
            borg_zap_rod(SV_ROD_CURING) ||
            borg_zap_rod(SV_ROD_HEALING))
        {
            return (TRUE);
        }
    }

    /* Hack -- cure cuts */
    if (do_cut && (q < 25))
    {
        if (borg_quaff_potion(SV_POTION_CURE_CRITICAL) ||
            borg_use_staff(SV_STAFF_CURING) ||
            borg_zap_rod(SV_ROD_CURING) ||
            borg_zap_rod(SV_ROD_HEALING))
        {
            return (TRUE);
        }
    }

    /* Hack -- cure poison */
    if (do_poisoned && (q < 25))
    {
        if (borg_quaff_potion(SV_POTION_CURE_POISON) ||
            borg_quaff_potion(SV_POTION_SLOW_POISON) ||
            borg_quaff_potion(SV_POTION_CURE_CRITICAL) ||
            borg_eat_food(SV_FOOD_CURE_POISON) ||
            borg_eat_food(SV_FOOD_WAYBREAD) ||
            borg_use_staff(SV_STAFF_CURING) ||
            borg_zap_rod(SV_ROD_CURING) ||
            borg_activate_artifact(ART_DAL))
        {
            return (TRUE);
        }
    }

    /* Hack -- cure blindness */
    if (do_blind && (q < 25))
    {
        if (borg_eat_food(SV_FOOD_CURE_BLINDNESS) ||
            borg_quaff_potion(SV_POTION_CURE_LIGHT) ||
            borg_quaff_potion(SV_POTION_CURE_SERIOUS) ||
            borg_quaff_potion(SV_POTION_CURE_CRITICAL) ||
            borg_use_staff(SV_STAFF_CURING) ||
            borg_use_staff(SV_ROD_CURING))
        {
            return (TRUE);
        }
    }

    /* Hack -- cure confusion */
    if (do_confused && (q < 25))
    {
        if (borg_eat_food(SV_FOOD_CURE_CONFUSION) ||
            borg_quaff_potion(SV_POTION_CURE_SERIOUS) ||
            borg_quaff_potion(SV_POTION_CURE_CRITICAL) ||
            borg_use_staff(SV_STAFF_CURING) ||
            borg_use_staff(SV_ROD_CURING))
        {
            return (TRUE);
        }
    }

    /* Hack -- cure fear */
    if (do_afraid && (q < 25))
    {
        if (borg_eat_food(SV_FOOD_CURE_PARANOIA) ||
            borg_quaff_potion(SV_POTION_BOLDNESS) ||
            borg_quaff_potion(SV_POTION_HEROISM) ||
            borg_quaff_potion(SV_POTION_BESERK_STRENGTH) ||
            borg_activate_artifact(ART_DAL))
        {
            return (TRUE);
        }
    }

    /* Hack -- satisfy hunger */
    if (do_hungry && (q < 25))
    {
        if (borg_read_scroll(SV_SCROLL_SATISFY_HUNGER))
        {
            return (TRUE);
        }
    }

    /* Hack -- heal damage */
    if ((auto_chp < auto_mhp / 2) && (q < 25))
    {
        if (borg_zap_rod(SV_ROD_HEALING) ||
            borg_quaff_potion(SV_POTION_CURE_CRITICAL) ||
            borg_quaff_potion(SV_POTION_CURE_SERIOUS))
        {
            return (TRUE);
        }
    }


    /*** Just Rest ***/

    /* Hack -- rest until healed */
    if ((do_blind || do_confused || do_image ||
         do_poisoned || do_afraid || do_cut || do_stun || do_heavy_stun ||
         (auto_chp < auto_mhp) || (auto_csp < auto_msp)) &&
         (!auto_takes_cnt || !goal_recalling) && !borg_goi &&
        (rand_int(100) < 90) && borg_check_rest( ) && 
        p <= auto_fear_region[c_y/11][c_x/11])
    {
        /* XXX XXX XXX */
        if (!do_weak && !do_hungry)
        {
            /* Take note */
            borg_note(format("# Resting (danger %d)...", p));

            /* Rest until done */
            borg_keypress('R');
            borg_keypress('&');
            borg_keypress('\n');

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


    /* Nope */
    return (FALSE);
}


/*
 * Take one "step" towards the given location, return TRUE if possible
 */
static bool borg_play_step(int y2, int x2)
{
    auto_grid *ag;

    int dir, x, y;


    /* Get a direction, if possible */
    dir = borg_goto_dir(c_y, c_x, y2, x2);

    /* We have arrived */
    if (dir == 5) return (FALSE);


    /* Obtain the destination */
    x = c_x + ddx[dir];
    y = c_y + ddy[dir];

    /* Access the grid we are stepping on */
    ag = &auto_grids[y][x];


    /* Hack -- set goal */
    g_x = x;
    g_y = y;


    /* Monsters -- Attack */
    if (ag->kill)
    {
        auto_kill *kill = &auto_kills[ag->kill];

        /* can't attack someone if afraid! */
        if (do_afraid)
            return (FALSE);

        /* Message */
        borg_note(format("# Walking into a '%s' at (%d,%d)",
                         r_name + r_info[kill->r_idx].name,
                         kill->x, kill->y));

        /* Walk into it */
        borg_keypress('0' + dir);
        return (TRUE);
    }


    /* Objects -- Take */
    if (ag->take)
    {
        auto_take *take = &auto_takes[ag->take];

        /* Message */
        borg_note(format("# Walking onto a '%s' at (%d,%d)",
                         k_name + k_info[take->k_idx].name,
                         take->x, take->y));

        /* Walk onto it */
        borg_keypress('0' + dir);
        return (TRUE);
    }


    /* Traps -- disarm */
    if ((ag->feat >= FEAT_TRAP_HEAD) && (ag->feat <= FEAT_TRAP_TAIL))
    {
        /* Disarm */
        borg_note("# Disarming a trap");
        borg_keypress('D');
        borg_keypress('0' + dir);
        return (TRUE);
    }


    /* Closed Doors -- Open */
    if ((ag->feat >= FEAT_DOOR_HEAD) && (ag->feat <= FEAT_DOOR_HEAD + 0x07))
    {
        /* Paranoia XXX XXX XXX */
        if (!rand_int(100)) return (FALSE);

        /* Open */
        borg_note("# Opening a door");
        borg_keypress('0');
        borg_keypress('9');
        borg_keypress('o');
        borg_keypress('0' + dir);
        return (TRUE);
    }


    /* Jammed Doors -- Bash or destroy */
    if ((ag->feat >= FEAT_DOOR_HEAD + 0x08) && (ag->feat <= FEAT_DOOR_TAIL))
    {
        /* Paranoia XXX XXX XXX */
        if (!rand_int(100)) return (FALSE);

        /* Mega-Hack -- allow "destroy doors" */
        if (borg_prayer(7, 0))
        {
            borg_note("# Unbarring ways");
            return (TRUE);
        }

        /* Mega-Hack -- allow "destroy doors" */
        if (borg_spell(1, 2))
        {
            borg_note("# Destroying doors");
            return (TRUE);
        }

        /* Mega-Hack -- allow "stone to mud" */
        if (borg_spell(1, 8))
        {
            borg_note("# Melting a door");
            borg_keypress('0' + dir);
            return (TRUE);
        }

        /* Bash */
        borg_note("# Bashing a door");
        borg_keypress('B');
        borg_keypress('0' + dir);
        return (TRUE);
    }


    /* Rubble, Treasure, Seams, Walls -- Tunnel or Melt */
    if (ag->feat >= FEAT_SECRET)
    {
        /* Mega-Hack -- prevent infinite loops */
        if (rand_int(100) < 10) return (FALSE);

        /* Mega-Hack -- allow "stone to mud" */
        if (borg_spell(1, 8))
        {
            borg_note("# Melting a wall/etc");
            borg_keypress('0' + dir);
            return (TRUE);
        }

        /* Tunnel */
        borg_note("# Digging through wall/etc");
        borg_keypress('0');
        borg_keypress('9');
        borg_keypress('9');
        borg_keypress('T');
        borg_keypress('0' + dir);
        return (TRUE);
    }


    /* Shops -- Enter */
    if ((ag->feat >= FEAT_SHOP_HEAD) && (ag->feat <= FEAT_SHOP_TAIL))
    {
        /* Message */
        borg_note(format("# Entering a '%d' shop", (ag->feat - FEAT_SHOP_HEAD) + 1));

        /* Enter the shop */
        borg_keypress('0' + dir);
        return (TRUE);
    }


    /* Walk in that direction */
    borg_keypress('0' + dir);


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




/*
 * Act twitchy
 */
bool borg_twitchy(void)
{
    int dir;

    /* This is a bad thing */
    borg_note("# Twitchy!");

    /* Pick a random direction */
    dir = randint(9);

    /* Hack -- set goal */
    g_x = c_x + ddx[dir];
    g_y = c_y + ddy[dir];

    /* Move */
    borg_keypress('0' + dir);

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





/*
 * Commit the current "flow"
 */
static bool borg_flow_commit(cptr who, int why)
{
    int cost;

    /* Cost of current grid */
    cost = auto_data_cost->data[c_y][c_x];

    /* Verify the total "cost" */
    if (cost >= 250) return (FALSE);

    /* Message */
    if (who) borg_note(format("# Flowing toward %s at cost %d", who, cost));

    /* Obtain the "flow" information */
    COPY(auto_data_flow, auto_data_cost, auto_data);

    /* Save the goal type */
    goal = why;

    /* Success */
    return (TRUE);
}





/*
 * Attempt to take an optimal step towards the current goal location
 *
 * Note that the "borg_update()" routine notices new monsters and objects,
 * and movement of monsters and objects, and cancels any flow in progress.
 *
 * Note that the "borg_update()" routine notices when a grid which was
 * not thought to block motion is discovered to in fact be a grid which
 * blocks motion, and removes that grid from any flow in progress.
 *
 * When given multiple alternative steps, this function attempts to choose
 * the "safest" path, by penalizing grids containing embedded gold, monsters,
 * rubble, doors, traps, store doors, and even floors.  This allows the Borg
 * to "step around" dangerous grids, even if this means extending the path by
 * a step or two, and encourages him to prefer grids such as objects and stairs
 * which are not only interesting but which are known not to be invisible traps.
 *
 * XXX XXX XXX XXX This function needs some work.  It should attempt to
 * analyze the "local region" around the player and determine the optimal
 * choice of locations based on some useful computations.
 *
 * If it works, return TRUE, otherwise, cancel the goal and return FALSE.
 */
bool borg_flow_old(int why)
{
    int x, y;

    auto_grid *ag;


    /* Continue */
    if (goal == why)
    {
        int b_n = 0;

        int i, b_i = -1;

        int c, b_c;


        /* Flow cost of current grid */
        b_c = auto_data_flow->data[c_y][c_x] * 10;

        /* Prevent loops */
        b_c = b_c - 5;


        /* Look around */
        for (i = 0; i < 8; i++)
        {
            /* Grid in that direction */
            x = c_x + ddx_ddd[i];
            y = c_y + ddy_ddd[i];

            /* Access the grid */
            ag = &auto_grids[y][x];

            /* Flow cost at that grid */
            c = auto_data_flow->data[y][x] * 10;

            /* Never backtrack */
            if (c > b_c) continue;

            /* Notice new best value */
            if (c < b_c) b_n = 0;

            /* Apply the randomizer to equivalent values */
            if ((++b_n >= 2) && (rand_int(b_n) != 0)) continue;

            /* Track it */
            b_i = i; b_c = c;
        }

        /* Try it */
        if (b_i >= 0)
        {
            /* Access the location */
            x = c_x + ddx_ddd[b_i];
            y = c_y + ddy_ddd[b_i];

            /* Attempt motion */
            if (borg_play_step(y, x)) return (TRUE);
        }

        /* Cancel goal */
        goal = 0;
    }

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




/*
 * Prepare to flee the level via stairs
 */
bool borg_flow_stair_both(int why)
{
    int i;

    /* None to flow to */
    if (!track_less_num && !track_more_num) return (FALSE);

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

    /* Enqueue useful grids */
    for (i = 0; i < track_less_num; i++)
    {
        /* Enqueue the grid */
        borg_flow_enqueue_grid(track_less_y[i], track_less_x[i]);
    }

    /* Enqueue useful grids */
    for (i = 0; i < track_more_num; i++)
    {
        /* Enqueue the grid */
        borg_flow_enqueue_grid(track_more_y[i], track_more_x[i]);
    }

    /* Spread the flow */
    borg_flow_spread(250, TRUE, FALSE);

    /* Attempt to Commit the flow */
    if (!borg_flow_commit("stairs", why)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(why)) return (FALSE);

    /* Success */
    return (TRUE);
}




/*
 * Prepare to flow towards "up" stairs
 */
bool borg_flow_stair_less(int why)
{
    int i;

    /* None to flow to */
    if (!track_less_num) return (FALSE);

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

    /* Enqueue useful grids */
    for (i = 0; i < track_less_num; i++)
    {
        /* Enqueue the grid */
        borg_flow_enqueue_grid(track_less_y[i], track_less_x[i]);
    }

    /* Spread the flow */
    borg_flow_spread(250, TRUE, FALSE);

    /* Attempt to Commit the flow */
    if (!borg_flow_commit("up-stairs", why)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(why)) return (FALSE);

    /* Success */
    return (TRUE);
}


/*
 * Prepare to flow towards "down" stairs
 */
bool borg_flow_stair_more(int why)
{
    int i;

    /* None to flow to */
    if (!track_more_num) return (FALSE);

    /* if not fleeing do not go down unless safe */
    if (!goal_fleeing && (cptr)NULL != borg_prepared(auto_depth + 1))
        return (FALSE);

    /* don't head for the stairs if you are recalling,  */
    /* even if you are fleeing. */
    if (goal_recalling)
        return (FALSE);

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

    /* Enqueue useful grids */
    for (i = 0; i < track_more_num; i++)
    {
        /* Enqueue the grid */
        borg_flow_enqueue_grid(track_more_y[i], track_more_x[i]);
    }

    /* Spread the flow */
    borg_flow_spread(250, TRUE, FALSE);

    /* Attempt to Commit the flow */
    if (!borg_flow_commit("down-stairs", why)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(why)) return (FALSE);

    /* Success */
    return (TRUE);
}


/*
 * Prepare to "flow" towards any non-visited shop
 */
bool borg_flow_shop_visit(void)
{
    int i, x, y;

    /* Must be in town */
    if (auto_depth) return (FALSE);

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

    /* Visit the shops */
    for (i = 0; i < 8; i++)
    {
        /* Must not be visited */
        if (auto_shops[i].when) continue;

        /* Obtain the location */
        x = track_shop_x[i];
        y = track_shop_y[i];

        /* Hack -- Must be known and not under the player */
        if (!x || !y || ((c_x == x) && (c_y == y))) continue;

        /* Enqueue the grid */
        borg_flow_enqueue_grid(y, x);
    }

    /* Spread the flow */
    borg_flow_spread(250, TRUE, FALSE);

    /* Attempt to Commit the flow */
    if (!borg_flow_commit("shops", GOAL_MISC)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(GOAL_MISC)) return (FALSE);

    /* Success */
    return (TRUE);
}


/*
 * Prepare to "flow" towards a specific shop entry
 */
bool borg_flow_shop_entry(int i)
{
    int x, y;

    cptr name = (f_name + f_info[0x08+i].name);

    /* Must be in town */
    if (auto_depth) return (FALSE);

    /* Obtain the location */
    x = track_shop_x[i];
    y = track_shop_y[i];

    /* Hack -- Must be known */
    if (!x || !y) return (FALSE);

    /* Hack -- re-enter a shop if needed */
    if ((x == c_x) && (y == c_y))
    {
        /* Note */
        borg_note("# Re-entering a shop");

        /* Enter the store */
        borg_keypress('5');

        /* Success */
        return (TRUE);
    }

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

    /* Enqueue the grid */
    borg_flow_enqueue_grid(y, x);

    /* Spread the flow */
    borg_flow_spread(250, TRUE, FALSE);

    /* Attempt to Commit the flow */
    if (!borg_flow_commit(name, GOAL_MISC)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(GOAL_MISC)) return (FALSE);

    /* Success */
    return (TRUE);
}






/*
 * Prepare to "flow" towards monsters to "kill"
 *
 * Note that monsters under the player are always deleted
 */
bool borg_flow_kill(bool viewable)
{
    int i, x, y, p;

    auto_grid *ag;


    /* Efficiency -- Nothing to kill */
    if (!auto_kills_cnt) return (FALSE);


    /* Nothing found */
    auto_temp_n = 0;

    /* Scan the monster list */
    for (i = 1; i < auto_kills_nxt; i++)
    {
        auto_kill *kill = &auto_kills[i];

        /* Skip dead monsters */
        if (!kill->r_idx) continue;

        /* Ignore multiplying monsters */
        if (goal_ignoring && !do_afraid &&
            (r_info[kill->r_idx].flags2 & RF2_MULTIPLY)) continue;

        /* Access the location */
        x = kill->x;
        y = kill->y;

        /* Get the grid */
        ag = &auto_grids[y][x];

        /* Require line of sight if requested */
        if (viewable && !(ag->info & BORG_VIEW)) continue;

        /* Calculate danger */
        p = borg_danger_aux(y, x, 1, i);

        /* Hack -- Skip "deadly" monsters */
        if (p > avoidance / 2) continue;

        /* Careful -- Remember it */
        auto_temp_x[auto_temp_n] = x;
        auto_temp_y[auto_temp_n] = y;
        auto_temp_n++;
    }

    /* Nothing to kill */
    if (!auto_temp_n) return (FALSE);


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

    /* Look for something to kill */
    for (i = 0; i < auto_temp_n; i++)
    {
        /* Enqueue the grid */
        borg_flow_enqueue_grid(auto_temp_y[i], auto_temp_x[i]);
    }

    /* Spread the flow */
    /* if we are not flowing toward monsters that we can see, make sure they */
    /* are at least easily reachable.  The second flag is weather or not */
    /* to avoid unkown squares.  This was for performance when we have ESP. */
    borg_flow_spread(250, TRUE, !viewable);

    /* Attempt to Commit the flow */
    if (!borg_flow_commit(NULL, GOAL_KILL)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(GOAL_KILL)) return (FALSE);

    /* Success */
    return (TRUE);
}



/*
 * Prepare to "flow" towards objects to "take"
 *
 * Note that objects under the player are always deleted
 */
bool borg_flow_take(bool viewable)
{
    int i, x, y;

    auto_grid *ag;


    /* Efficiency -- Nothing to take */
    if (!auto_takes_cnt) return (FALSE);


    /* Nothing yet */
    auto_temp_n = 0;

    /* Scan the object list */
    for (i = 1; i < auto_takes_nxt; i++)
    {
        auto_take *take = &auto_takes[i];

        int a;
        bool item_bad;

        /* Skip dead objects */
        if (!take->k_idx) continue;

        /* Access the location */
        x = take->x;
        y = take->y;

        /* look to see if this is on the bad items list */
        item_bad = FALSE;
        for (a = 0; a < 10; a++)
        {
            if (x == bad_obj_x[a] && y == bad_obj_y[a])
                item_bad = TRUE;
        }

        /* it is a bad item, do not track it */
        if (item_bad) continue;

        /* Get the grid */
        ag = &auto_grids[y][x];

        /* Require line of sight if requested */
        if (viewable && !(ag->info & BORG_VIEW)) continue;

        /* Careful -- Remember it */
        auto_temp_x[auto_temp_n] = x;
        auto_temp_y[auto_temp_n] = y;
        auto_temp_n++;
    }

    /* Nothing to take */
    if (!auto_temp_n) return (FALSE);


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

    /* Look for something to take */
    for (i = 0; i < auto_temp_n; i++)
    {
        /* Enqueue the grid */
        borg_flow_enqueue_grid(auto_temp_y[i], auto_temp_x[i]);
    }

    /* Spread the flow */
    /* if we are not flowing toward items that we can see, make sure they */
    /* are at least easily reachable.  The second flag is weather or not  */
    /* to avoid unkown squares.  This was for performance. */
    borg_flow_spread(250, TRUE, !viewable);


    /* Attempt to Commit the flow */
    if (!borg_flow_commit(NULL, GOAL_TAKE)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(GOAL_TAKE)) return (FALSE);

    /* Success */
    return (TRUE);
}



/*
 * Determine if a grid is "interesting" (and should be explored)
 *
 * A grid is "interesting" if it is a closed door, rubble, hidden treasure,
 * or a visible trap, or an "unknown" grid.
 */
static bool borg_flow_dark_interesting(int y, int x)
{
    auto_grid *ag;


    /* Get the auto_grid */
    ag = &auto_grids[y][x];


    /* Explore unknown grids */
    if (ag->feat == FEAT_NONE) return (TRUE);


    /* Efficiency -- Ignore "boring" grids */
    if (ag->feat < FEAT_TRAP_HEAD) return (FALSE);


    /* Explore "known treasure" */
    if ((ag->feat == FEAT_MAGMA_K) || (ag->feat == FEAT_QUARTZ_K))
    {
        /* Do not disarm when confused */
        if (do_confused) return (FALSE);

        /* Allow "stone to mud" ability */
        if (borg_spell_legal(1, 8)) return (TRUE);

        /* Do not dig unless we appear strong enough to succeed XXX XXX XXX */
        if (my_skill_dig < ((ag->feat & 0x01) ? 20 : 10) + 5) return (FALSE);

        /* Okay */
        return (TRUE);
    }


    /* Explore "rubble" */
    if (ag->feat == FEAT_RUBBLE)
    {
        return (TRUE);
    }


    /* Explore "closed doors" */
    if ((ag->feat >= FEAT_DOOR_HEAD) && (ag->feat <= FEAT_DOOR_TAIL))
    {
        return (TRUE);
    }


    /* Explore "visible traps" */
    if ((ag->feat >= FEAT_TRAP_HEAD) && (ag->feat <= FEAT_TRAP_TAIL))
    {
        /* Do not disarm when blind */
        if (do_blind) return (FALSE);

        /* Do not disarm when confused */
        if (do_confused) return (FALSE);

        /* Do not disarm when hallucinating */
        if (do_image) return (FALSE);

        /* Do not disarm without lite */
        if (!my_cur_lite) return (FALSE);

        /* Do not disarm when clumsy */
        if (my_skill_dis < 15) return (FALSE);

        /* Okay */
        return (TRUE);
    }


    /* Ignore other grids */
    return (FALSE);
}


/*
 * Determine if a grid is "reachable" (and can be explored)
 */
static bool borg_flow_dark_reachable(int y, int x)
{
    int j;

    auto_grid *ag;

    /* Scan neighbors */
    for (j = 0; j < 8; j++)
    {
        int y2 = y + ddy_ddd[j];
        int x2 = x + ddx_ddd[j];

        /* Get the grid */
        ag = &auto_grids[y2][x2];

        /* Skip unknown grids (important) */
        if (ag->feat == FEAT_NONE) continue;

        /* Accept known floor grids */
        if (borg_cave_floor_grid(ag)) return (TRUE);
    }

    /* Failure */
    return (FALSE);
}


/*
 * Place a "direct path" into the flow array, checking danger
 *
 * Modify the "cost" array in such a way that from any point on
 * one "direct" path from the player to the given grid, as long
 * as the rest of the path is "safe" and "clear", the Borg will
 * walk along the path to the given grid.
 *
 * This function is used by "borg_flow_dark_1()" to provide an
 * optimized "flow" during the initial exploration of a level.
 */
static void borg_flow_direct(int y, int x)
{
    int n = 0;

    int x1, y1, x2, y2;

    int ay, ax;

    int shift;

    auto_grid *ag;


    /* Avoid icky grids */
    if (auto_data_icky->data[y][x]) return;

    /* Unknown */
    if (!auto_data_know->data[y][x])
    {
        /* Mark as known */
        auto_data_know->data[y][x] = TRUE;

        /* Mark dangerous grids as icky */
        if (borg_danger(y, x, 1) > avoidance / 2)
        {
            /* Icky */
            auto_data_icky->data[y][x] = TRUE;

            /* Avoid */
            return;
        }
    }


    /* Save the flow cost (zero) */
    auto_data_cost->data[y][x] = 0;


    /* Save "origin" */
    y1 = y;
    x1 = x;

    /* Save "destination" */
    y2 = c_y;
    x2 = c_x;

    /* Calculate distance components */
    ay = (y2 < y1) ? (y1 - y2) : (y2 - y1);
    ax = (x2 < x1) ? (x1 - x2) : (x2 - x1);

    /* Path */
    while (1)
    {
        /* Check for arrival at player */
        if ((x == x2) && (y == y2)) return;

        /* Next */
        n++;

        /* Move mostly vertically */
        if (ay > ax)
        {
            /* Extract a shift factor XXX */
            shift = (n * ax + (ay-1) / 2) / ay;

            /* Sometimes move along the minor axis */
            x = (x2 < x1) ? (x1 - shift) : (x1 + shift);

            /* Always move along major axis */
            y = (y2 < y1) ? (y1 - n) : (y1 + n);
        }

        /* Move mostly horizontally */
        else
        {
            /* Extract a shift factor XXX */
            shift = (n * ay + (ax-1) / 2) / ax;

            /* Sometimes move along the minor axis */
            y = (y2 < y1) ? (y1 - shift) : (y1 + shift);

            /* Always move along major axis */
            x = (x2 < x1) ? (x1 - n) : (x1 + n);
        }


        /* Access the grid */
        ag = &auto_grids[y][x];


        /* Ignore "wall" grids */
        if (!borg_cave_floor_grid(ag)) return;


        /* Abort at "icky" grids */
        if (auto_data_icky->data[y][x]) return;

        /* Analyze every grid once */
        if (!auto_data_know->data[y][x])
        {
            /* Mark as known */
            auto_data_know->data[y][x] = TRUE;

            /* Avoid dangerous grids (forever) */
            if (borg_danger(y, x, 1) > avoidance / 2)
            {
                /* Mark as icky */
                auto_data_icky->data[y][x] = TRUE;

                /* Abort */
                return;
            }
        }

        /* Abort "pointless" paths if possible */
        if (auto_data_cost->data[y][x] <= n) break;

        /* Save the new flow cost */
        auto_data_cost->data[y][x] = n;
    }
}


/*
 * Hack -- mark off the edges of a rectangle as "avoid" or "clear"
 */
static void borg_flow_border(int y1, int x1, int y2, int x2, bool stop)
{
    int x, y;

    /* Scan west/east edges */
    for (y = y1; y <= y2; y++)
    {
        /* Avoid/Clear west edge */
        auto_data_know->data[y][x1] = stop;
        auto_data_icky->data[y][x1] = stop;

        /* Avoid/Clear east edge */
        auto_data_know->data[y][x2] = stop;
        auto_data_icky->data[y][x2] = stop;
    }

    /* Scan north/south edges */
    for (x = x1; x <= x2; x++)
    {
        /* Avoid/Clear north edge */
        auto_data_know->data[y1][x] = stop;
        auto_data_icky->data[y1][x] = stop;

        /* Avoid/Clear south edge */
        auto_data_know->data[y2][x] = stop;
        auto_data_icky->data[y2][x] = stop;
    }
}


/*
 * Prepare to "flow" towards "interesting" grids (method 1)
 *
 * This function examines the torch-lit grids for "interesting" grids.
 */
static bool borg_flow_dark_1(void)
{
    int i;

    int x, y;


    /* Hack -- not in town */
    if (!auto_depth) return (FALSE);


    /* Reset */
    auto_temp_n = 0;

    /* Scan torch-lit grids */
    for (i = 0; i < auto_lite_n; i++)
    {
        y = auto_lite_y[i];
        x = auto_lite_x[i];

        /* Skip "boring" grids (assume reachable) */
        if (!borg_flow_dark_interesting(y, x)) continue;

        /* Careful -- Remember it */
        auto_temp_x[auto_temp_n] = x;
        auto_temp_y[auto_temp_n] = y;
        auto_temp_n++;
    }

    /* Nothing */
    if (!auto_temp_n) return (FALSE);


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

    /* Create paths to useful grids */
    for (i = 0; i < auto_temp_n; i++)
    {
        y = auto_temp_y[i];
        x = auto_temp_x[i];

        /* Create a path */
        borg_flow_direct(y, x);
    }


    /* Attempt to Commit the flow */
    if (!borg_flow_commit(NULL, GOAL_DARK)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(GOAL_DARK)) return (FALSE);

    /* Forget goal */
    goal = 0;

    /* Success */
    return (TRUE);
}


/*
 * Prepare to "flow" towards "interesting" grids (method 2)
 *
 * This function is only used when the player is at least 4 grids away
 * from the outer dungeon wall, to prevent any nasty memory errors.
 *
 * This function examines the grids just outside the torch-lit grids
 * for "unknown" grids, and flows directly towards them (one step).
 */
static bool borg_flow_dark_2(void)
{
    int i, r;

    int x, y;

    auto_grid *ag;


    /* Hack -- not in town */
    if (!auto_depth) return (FALSE);


    /* Maximal radius */
    r = my_cur_lite + 1;


    /* Reset */
    auto_temp_n = 0;

    /* Four directions */
    for (i = 0; i < 4; i++)
    {
        y = c_y + ddy_ddd[i] * r;
        x = c_x + ddx_ddd[i] * r;

        /* Check legality */
        if (y < 1) continue;
        if (x < 1) continue;
        if (y > AUTO_MAX_Y - 2) continue;
        if (x > AUTO_MAX_X - 2) continue;

        /* Acquire grid */
        ag = &auto_grids[y][x];

        /* Require unknown */
        if (ag->feat != FEAT_NONE) continue;

        /* Require viewable */
        if (!(ag->info & BORG_VIEW)) continue;

        /* Careful -- Remember it */
        auto_temp_x[auto_temp_n] = x;
        auto_temp_y[auto_temp_n] = y;
        auto_temp_n++;
    }

    /* Nothing */
    if (!auto_temp_n) return (FALSE);


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

    /* Create paths to useful grids */
    for (i = 0; i < auto_temp_n; i++)
    {
        y = auto_temp_y[i];
        x = auto_temp_x[i];

        /* Create a path */
        borg_flow_direct(y, x);
    }


    /* Attempt to Commit the flow */
    if (!borg_flow_commit(NULL, GOAL_DARK)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(GOAL_DARK)) return (FALSE);

    /* Forget goal */
    goal = 0;

    /* Success */
    return (TRUE);
}


/*
 * Prepare to "flow" towards "interesting" grids (method 3)
 *
 * Note the use of a limit on the "depth" of the flow, and of the flag
 * which avoids "unknown" grids when calculating the flow, both of which
 * help optimize this function to only handle "easily reachable" grids.
 *
 * The "auto_temp" array is much larger than any "local region".
 */
static bool borg_flow_dark_3(void)
{
    int i;

    int x, y;

    int x1, y1, x2, y2;


    /* Hack -- not in town */
    if (!auto_depth) return (FALSE);


    /* Local region */
    y1 = c_y - 4;
    x1 = c_x - 4;
    y2 = c_y + 4;
    x2 = c_x + 4;

    /* Restrict to "legal" grids */
    if (y1 < 1) y1 = 1;
    if (x1 < 1) x1 = 1;
    if (y2 > AUTO_MAX_Y - 2) y2 = AUTO_MAX_Y - 2;
    if (x2 > AUTO_MAX_X - 2) x2 = AUTO_MAX_X - 2;


    /* Reset */
    auto_temp_n = 0;

    /* Examine the region */
    for (y = y1; y <= y2; y++)
    {
        /* Examine the region */
        for (x = x1; x <= x2; x++)
        {
            /* Skip "boring" grids */
            if (!borg_flow_dark_interesting(y, x)) continue;

            /* Skip "unreachable" grids */
            if (!borg_flow_dark_reachable(y, x)) continue;

            /* Careful -- Remember it */
            auto_temp_x[auto_temp_n] = x;
            auto_temp_y[auto_temp_n] = y;
            auto_temp_n++;
        }
    }

    /* Nothing interesting */
    if (!auto_temp_n) return (FALSE);


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

    /* Enqueue useful grids */
    for (i = 0; i < auto_temp_n; i++)
    {
        y = auto_temp_y[i];
        x = auto_temp_x[i];

        /* Enqueue the grid */
        borg_flow_enqueue_grid(y, x);
    }

    /* Spread the flow (limit depth) */
    borg_flow_spread(5, TRUE, TRUE);


    /* Attempt to Commit the flow */
    if (!borg_flow_commit(NULL, GOAL_DARK)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(GOAL_DARK)) return (FALSE);

    /* Success */
    return (TRUE);
}


/*
 * Prepare to "flow" towards "interesting" grids (method 4)
 *
 * Note that we avoid grids close to the edge of the panel, since they
 * induce panel scrolling, which is "expensive" in terms of CPU usage,
 * and because this allows us to "expand" the border by several grids
 * to lay down the "avoidance" border in known legal grids.
 *
 * We avoid paths that would take us into different panels by setting
 * the "icky" flag for the "border" grids to prevent path construction,
 * and then clearing them when done, to prevent confusion elsewhere.
 *
 * The "auto_temp" array is large enough to hold one panel full of grids.
 */
static bool borg_flow_dark_4(void)
{
    int i, x, y;

    int x1, y1, x2, y2;


    /* Hack -- not in town */
    if (!auto_depth) return (FALSE);


    /* Local region */
    y1 = c_y - 11;
    x1 = c_x - 11;
    y2 = c_y + 11;
    x2 = c_x + 11;

    /* Restrict to "legal" grids */
    if (y1 < 1) y1 = 1;
    if (x1 < 1) x1 = 1;
    if (y2 > AUTO_MAX_Y - 2) y2 = AUTO_MAX_Y - 2;
    if (x2 > AUTO_MAX_X - 2) x2 = AUTO_MAX_X - 2;


    /* Nothing yet */
    auto_temp_n = 0;

    /* Examine the panel */
    for (y = y1; y <= y2; y++)
    {
        /* Examine the panel */
        for (x = x1; x <= x2; x++)
        {
            /* Skip "boring" grids */
            if (!borg_flow_dark_interesting(y, x)) continue;

            /* Skip "unreachable" grids */
            if (!borg_flow_dark_reachable(y, x)) continue;

            /* Careful -- Remember it */
            auto_temp_x[auto_temp_n] = x;
            auto_temp_y[auto_temp_n] = y;
            auto_temp_n++;
        }
    }

    /* Nothing useful */
    if (!auto_temp_n) return (FALSE);


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

    /* Enqueue useful grids */
    for (i = 0; i < auto_temp_n; i++)
    {
        y = auto_temp_y[i];
        x = auto_temp_x[i];

        /* Enqueue the grid */
        borg_flow_enqueue_grid(y, x);
    }


    /* Expand borders */
    y1--; x1--; y2++; x2++;

    /* Avoid the edges */
    borg_flow_border(y1, x1, y2, x2, TRUE);

    /* Spread the flow (limit depth) */
    borg_flow_spread(32, TRUE, TRUE);

    /* Clear the edges */
    borg_flow_border(y1, x1, y2, x2, FALSE);


    /* Attempt to Commit the flow */
    if (!borg_flow_commit("dark-4", GOAL_DARK)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(GOAL_DARK)) return (FALSE);

    /* Success */
    return (TRUE);
}


/*
 * Prepare to "flow" towards "interesting" grids (method 5)
 */
static bool borg_flow_dark_5(void)
{
    int i, x, y;


    /* Hack -- not in town */
    if (!auto_depth) return (FALSE);


    /* Nothing yet */
    auto_temp_n = 0;

    /* Examine every "legal" grid */
    for (y = 1; y < AUTO_MAX_Y-1; y++)
    {
        for (x = 1; x < AUTO_MAX_X-1; x++)
        {
            /* Skip "boring" grids */
            if (!borg_flow_dark_interesting(y, x)) continue;

            /* Skip "unreachable" grids */
            if (!borg_flow_dark_reachable(y, x)) continue;

            /* Careful -- Remember it */
            auto_temp_x[auto_temp_n] = x;
            auto_temp_y[auto_temp_n] = y;
            auto_temp_n++;

            /* Paranoia -- Check for overflow */
            if (auto_temp_n == AUTO_TEMP_MAX)
            {
                /* Hack -- Double break */
                y = AUTO_MAX_Y;
                x = AUTO_MAX_X;
                break;
            }
        }
    }

    /* Nothing useful */
    if (!auto_temp_n) return (FALSE);


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

    /* Enqueue useful grids */
    for (i = 0; i < auto_temp_n; i++)
    {
        y = auto_temp_y[i];
        x = auto_temp_x[i];

        /* Enqueue the grid */
        borg_flow_enqueue_grid(y, x);
    }

    /* Spread the flow */
    borg_flow_spread(250, TRUE, TRUE);


    /* Attempt to Commit the flow */
    if (!borg_flow_commit("dark-5", GOAL_DARK)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(GOAL_DARK)) return (FALSE);

    /* Success */
    return (TRUE);
}


/*
 * Prepare to "flow" towards "interesting" grids
 *
 * The "exploration" routines are broken into "near" and "far"
 * exploration, and each set is chosen via the flag below.
 */
bool borg_flow_dark(bool neer)
{
    /* Paranoia */
    if (borg_flow_dark_interesting(c_y, c_x))
    {
        borg_oops("darkness");
        return (FALSE);
    }

    /* Near */
    if (neer)
    {
        /* Method 1 */
        if (borg_flow_dark_1()) return (TRUE);

        /* Method 2 */
        if (borg_flow_dark_2()) return (TRUE);

        /* Method 3 */
        if (borg_flow_dark_3()) return (TRUE);
    }

    /* Far */
    else
    {
        /* Method 4 */
        if (borg_flow_dark_4()) return (TRUE);

        /* Method 5 */
        if (borg_flow_dark_5()) return (TRUE);
    }

    /* Fail */
    return (FALSE);
}



/*
 * Hack -- spastic searching
 */

static byte spastic_x;
static byte spastic_y;



/*
 * Search carefully for secret doors and such
 */
bool borg_flow_spastic(bool bored)
{
    int cost;

    int i, x, y, v;

    int b_x = c_x;
    int b_y = c_y;
    int b_v = -1;

    auto_grid *ag;


    /* Hack -- not in town */
    if (!auto_depth) return (FALSE);


    /* Not bored */
    if (!bored)
    {
        /* Look around for danger */
        int p = borg_danger(c_y, c_x, 1);

        /* Avoid searching when in danger */
        if (p > avoidance / 4) return (FALSE);
    }


    /* We have arrived */
    if ((spastic_x == c_x) && (spastic_y == c_y))
    {
        /* Cancel */
        spastic_x = 0;
        spastic_y = 0;

        /* Take note */
        borg_note(format("# Spastic Searching at (%d,%d)...", c_x, c_y));

        /* Count searching */
        for (i = 0; i < 9; i++)
        {
            /* Extract the location */
            int xx = c_x + ddx_ddd[i];
            int yy = c_y + ddy_ddd[i];

            /* Current grid */
            ag = &auto_grids[yy][xx];

            /* Tweak -- Remember the search */
            if (ag->xtra < 100) ag->xtra += 5;
        }

        /* Tweak -- Search a little */
        borg_keypress('0');
        borg_keypress('5');
        borg_keypress('s');

        /* Success */
        return (TRUE);
    }


    /* Reverse flow */
    borg_flow_reverse();

    /* Scan the entire map */
    for (y = 1; y < AUTO_MAX_Y-1; y++)
    {
        for (x = 1; x < AUTO_MAX_X-1; x++)
        {
            auto_grid *ag_ptr[8];

            int wall = 0;
            int supp = 0;
            int diag = 0;


            /* Acquire the grid */
            ag = &auto_grids[y][x];

            /* Skip unknown grids */
            if (ag->feat == FEAT_NONE) continue;

            /* Skip walls/doors */
            if (!borg_cave_floor_grid(ag)) continue;


            /* Acquire the cost */
            cost = auto_data_cost->data[y][x];

            /* Skip "unreachable" grids */
            if (cost >= 250) continue;


            /* Tweak -- Limit total searches */
            if (ag->xtra >= 50) continue;

            /* Limit initial searches until bored */
            if (!bored && (ag->xtra > 5)) continue;

            /* Avoid searching detected sectors */
            if (auto_detect_door[y/11][x/33]) continue;


            /* Extract adjacent locations */
            for (i = 0; i < 8; i++)
            {
                /* Extract the location */
                int xx = x + ddx_ddd[i];
                int yy = y + ddy_ddd[i];

                /* Get the grid contents */
                ag_ptr[i] = &auto_grids[yy][xx];
            }


            /* Count possible door locations */
            for (i = 0; i < 4; i++)
            {
                ag = ag_ptr[i];
                if (ag->feat >= FEAT_WALL_EXTRA) wall++;
            }

            /* No possible secret doors */
            if (wall < 1) continue;


            /* Count supporting evidence for secret doors */
            for (i = 0; i < 4; i++)
            {
                ag = ag_ptr[i];

                /* Rubble */
                if (ag->feat == FEAT_RUBBLE) continue;

                /* Walls, Doors */
                if (((ag->feat >= FEAT_SECRET) && (ag->feat <= FEAT_PERM_SOLID)) ||
                    ((ag->feat == FEAT_OPEN) || (ag->feat == FEAT_BROKEN)) ||
                    ((ag->feat >= FEAT_DOOR_HEAD) && (ag->feat <= FEAT_DOOR_TAIL)))
                {
                    supp++;
                }
            }

            /* Count supporting evidence for secret doors */
            for (i = 4; i < 8; i++)
            {
                ag = ag_ptr[i];

                /* Rubble */
                if (ag->feat == FEAT_RUBBLE) continue;

                /* Walls */
                if (ag->feat >= FEAT_SECRET)
                {
                    diag++;
                }
            }

            /* No possible secret doors */
            if (diag < 2) continue;


            /* Tweak -- Reward walls, punish visitation and distance */
            v = (supp * 500) + (diag * 100) - (ag->xtra * 20) - (cost * 1);

            /* The grid is not searchable */
            if (v <= 0) continue;


            /* Tweak -- Minimal interest until bored */
            if (!bored && (v < 1500)) continue;


            /* Track "best" grid */
            if ((b_v >= 0) && (v < b_v)) continue;

            /* Save the data */
            b_v = v; b_x = x; b_y = y;
        }
    }

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

    /* Hack -- Nothing found */
    if (b_v < 0) return (FALSE);


    /* Access grid */
    ag = &auto_grids[b_y][b_x];

    /* Memorize */
    spastic_x = b_x;
    spastic_y = b_y;


    /* Enqueue the grid */
    borg_flow_enqueue_grid(b_y, b_x);

    /* Spread the flow */
    borg_flow_spread(250, TRUE, FALSE);

    /* Attempt to Commit the flow */
    if (!borg_flow_commit("spastic", GOAL_XTRA)) return (FALSE);

    /* Take one step */
    if (!borg_flow_old(GOAL_XTRA)) return (FALSE);

    /* Success */
    return (TRUE);
}




/*
 * Initialize this file
 */
void borg_init_6(void)
{
    /* Nothing */
}



#else

#ifdef MACINTOSH
static int HACK = 0;
#endif

#endif
