/* File: borg9.c */

/* Purpose: Highest level functions 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"
#include "borg7.h"
#include "borg8.h"
#include "borg9.h"

bool borg_cheat_death;

/*
 * This file implements the "Ben Borg", an "Automatic Angband Player".
 *
 * This version of the "Ben Borg" is designed for use with Angband 2.7.9v6.
 *
 * Use of the "Ben Borg" requires re-compilation with ALLOW_BORG defined,
 * and with the various "borg*.c" files linked into the executable.
 *
 * Note that you can only use the Borg if your character has been marked
 * as a "Borg User".  You can do this, if necessary, by responding "y"
 * when asked if you really want to use the Borg.  This will (normally)
 * result in your character being inelligible for the high score list.
 *
 * The "do_cmd_borg()" function, called when the user hits "^Z", allows
 * the user to interact with the Borg.  You do so by typing "Borg Commands",
 * including 'z' to activate (or re-activate), 'K' to show monsters, 'T' to
 * show objects, 'd' to toggle "demo mode", 'f' to open/shut the "log file",
 * 'i' to display internal flags, etc.  See "do_cmd_borg()" for more info.
 *
 * The first time you enter a Borg command, the Borg is initialized.  This
 * consists of three major steps, and requires at least 400K of free memory,
 * if the memory is not available, the game may abort.
 *
 * (1) The various "borg" modules are initialized.
 *
 * (2) Some important "state" information is extracted, including the level
 *     and race/class of the player, and some more initialization is done.
 *
 * (3) Some "historical" information (killed uniques, maximum dungeon depth)
 *     is "stolen" from the game.
 *
 * When the Ben Borg is "activated", it uses the "Term_inkey_hook" to steal
 * control from the user.  Later, if it detects any input from the real user,
 * it gracefully relinquishes control by clearing the "Term_inkey_hook" after
 * any pending key-sequences are complete.
 *
 * The Borg will abort if it detects any "errors", or if it detects any
 * "situations" such as "death", or if it detects any "panic" situations,
 * such as "imminent death", if the appropriate flags are set.
 *
 * The Ben Borg is only supposed to "know" what is visible on the screen,
 * which it learns by using the "term.c" screen access function "Term_what()",
 * the cursor location function "Term_locate()", and the cursor visibility
 * extraction function "Term_get_cursor()".
 *
 * The Ben Borg is only supposed to "send" keypresses when the "Term_inkey()"
 * function asks for a keypress, which is accomplished by using a special
 * function hook in the "z-term.c" file, which allows the Borg to "steal"
 * control from the "Term_inkey()" and "Term_flush()" functions.  This
 * allows the Ben Borg to pretend to be a normal user.
 *
 * Note that if properly designed, the Ben Borg could be run as an external
 * process, which would actually examine the screen (or pseudo-terminal),
 * and send keypresses directly to the keyboard (or pseudo-terminal).  Thus
 * it should never access any "game variables", unless it is able to extract
 * those variables for itself by code duplication or complex interactions,
 * or, in certain situations, if those variables are not actually "required".
 *
 * Currently, the Ben Borg is a few steps away from being able to be run as
 * an external process, primarily in the "low level" details, such as knowing
 * when the game is ready for a keypress.  Also, the Ben Borg assumes that a
 * character has already been rolled, and maintains no state between saves,
 * which is partially offset by "cheating" to "acquire" the maximum dungeon
 * depth, without which equipment analysis will be faulty.
 *
 * The "theory" behind the Borg is that is should be able to run as a
 * separate process, playing Angband in a window just like a human, that
 * is, examining the screen for information, and sending keypresses to
 * the game.  The current Borg does not actually do this, because it would
 * be very slow and would not run except on Unix machines, but as far as
 * possible, I have attempted to make sure that the Borg *could* run that
 * way.  This involves "cheating" as little as possible, where "cheating"
 * means accessing information not available to a normal Angband player.
 * And whenever possible, this "cheating" should be optional, that is,
 * there should be software options to disable the cheating, and, if
 * necessary, to replace it with "complex" parsing of the screen.
 *
 * Thus, the Borg COULD be written as a separate process which runs Angband
 * in a pseudo-terminal and "examines" the "screen" and sends keypresses
 * directly (as with a terminal emulator), although it would then have
 * to explicitly "wait" to make sure that the game was completely done
 * sending information.
 *
 * The Borg is thus allowed to examine the screen directly (by efficient
 * direct access of the "Term->scr->a" and "Term->scr->c" arrays, which
 * could be replaced by calls to "Term_grab()"), and to access the cursor
 * location (via "Term_locate()") and visibility (via "Term_get_cursor()"),
 * and, as mentioned above, the Borg is allowed to send keypresses directly
 * to the game, and only when needed, using the "Term_inkey_hook" hook, and
 * uses the same hook to know when it should discard all pending keypresses.
 *
 * The Borg should not know when the game is ready for a keypress, and
 * should really do something nasty such as "pause" between turns for
 * some amount of time to ensure that the game is really waiting for
 * a keypress.
 *
 * Various other "cheats" (mostly optional) are described where they are
 * used, primarily in this file.
 *
 * Note that any "user input" will be ignored, and will cancel the Borg,
 * after the Borg has completed any key-sequences currently in progress.
 *
 * Note that the "c_t" parameter bears a close resemblance to the number of
 * "player turns" that have gone by.  Except that occasionally, the Borg will
 * do something that he *thinks* will take time but which actually does not
 * (for example, attempting to open a hallucinatory door), and that sometimes,
 * the Borg performs a "repeated" command (rest, open, tunnel, or search),
 * which may actually take longer than a single turn.  This has the effect
 * that the "c_t" variable is slightly lacking in "precision".  Note that
 * we can store every time-stamp in a 's16b', since we reset the clock to
 * 1000 on each new level, and we refuse to stay on any level longer than
 * 30000 turns, unless we are totally stuck, in which case we abort.
 *
 * Note that as of 2.7.9, the Borg can play any class, that is, he can make
 * "effective" use of at least a few spells/prayers, and is not "broken"
 * by low strength, blind-ness, hallucination, etc.  This does not, however,
 * mean that he plays all classes equally well, especially since he is so
 * dependant on a high strength for so many things.  The "demo" mode is useful
 * for many classes (especially Mage) since it allows the Borg to "die" a few
 * times, without being penalized.
 *
 * The Borg assumes that the "maximize" flag is off, and that the
 * "preserve" flag is on, since he cannot actually set those flags.
 * If the "maximize" flag is on, the Borg may not work correctly.
 * If the "preserve" flag is off, the Borg may miss artifacts.
 */


/*
 * We currently handle:
 *   Level changing (intentionally or accidentally)
 *   Embedded objects (gold) that must be extracted
 *   Ignore embedded objects if too "weak" to extract
 *   Traps (disarm), Doors (open/etc), Rubble (tunnel)
 *   Stores (enter via movement, exit via escape)
 *   Stores (limited commands, and different commands)
 *   Always deal with objects one at a time, not in piles
 *   Discard junk before trying to pick up more stuff
 *   Use "identify" to obtain knowledge and/or money
 *   Rely on "sensing" objects as much as possible
 *   Do not sell junk or worthless items to any shop
 *   Do not attempt to buy something without the cash
 *   Use the non-optimal stairs if stuck on a level
 *   Use "flow" code for all tasks for consistency
 *   Cancel all goals when major world changes occur
 *   Use the "danger" code to avoid potential death
 *   Use the "danger" code to avoid inconvenience
 *   Try to avoid danger (both actively and passively)
 *   Handle "Mace of Disruption", "Scythe of Slicing", etc
 *   Learn spells, and use them when appropriate
 *   Remember that studying prayers is slightly random
 *   Do not try to read scrolls when blind or confused
 *   Do not study/use spells/prayers when blind/confused
 *   Use spells/prayers at least once for the experience
 *   Attempt to heal when "confused", "blind", etc
 *   Attempt to fix "fear", "poison", "cuts", etc
 *   Analyze potential equipment in proper context
 *   Priests should avoid edged weapons (spell failure)
 *   Mages should avoid most gloves (lose mana)
 *   Non-warriors should avoid heavy armor (lose mana)
 *   Keep "best" ring on "tight" right finger in stores
 *   Remove items which do not contribute to total fitness
 *   Wear/Remove/Sell/Buy items in most optimal order
 *   Pursue optimal combination of available equipment
 *   Notice "failure" when using rods/staffs/artifacts
 *   Notice "failure" when attempting spells/prayers
 *   Attempt to correctly track terrain, objects, monsters
 *   Take account of "clear" and "multi-hued" monsters
 *   Take account of "flavored" (randomly colored) objects
 *   Handle similar objects/monsters (mushrooms, coins)
 *   Multi-hued/Clear monsters, and flavored objects
 *   Keep in mind that some monsters can move (quickly)
 *   Do not fire at monsters that may not actually exist
 *   Assume everything is an object until proven otherwise
 *   Parse messages to correct incorrect assumptions
 *   Search for secret doors after exploring the level
 *   React intelligently to changes in the wall structure
 *   Do not recalculate "flow" information unless required
 *   Collect monsters/objects/terrain not currently in view
 *   Keep in mind that word of recall is a delayed action
 *   Keep track of charging items (rods and artifacts)
 *   Be very careful not to access illegal locations!
 *   Do not rest next to dangerous (or immobile) monsters
 *   Recall into dungeon if prepared for resulting depth
 *   Do not attempt to destroy cursed ("terrible") artifacts
 *   Attempted destruction will yield "terrible" inscription
 *   Use "maximum" level and depth to prevent "thrashing"
 *   Use "maximum" hp's and sp's when checking "potentials"
 *   Attempt to recognize large groups of "disguised" monsters
 *   Beware of firing at a monster which is no longer present
 *   Stockpile items in the Home, and use those stockpiles
 *   Discounted spell-books (low level ones are ignored)
 *   Take items out of the home to sell them when no longer needed
 *   Trappers and Mimics (now treated as invisible monsters)
 *   Invisible monsters (induce "fear" of nearby regions)
 *   Fleeing monsters are "followed" down corridors and such
 *
 * We ignore:
 *   Running out of light can (fatally) confuse the Borg
 *   Running out of food can kill you, try not to starve
 *   Long object descriptions may have clipped inscriptions
 *
 * We need to handle:
 *   Better "fleeing" code from nasty monsters
 *   Appearance of "similar" monsters (jackals + grip)
 *   Hallucination (induces fake objects and monsters)
 *   Special screens (including tombstone) with no "walls"
 *   Appearance of the '@' symbol on "special" screens
 *   Technically a room can have no exits, requiring digging
 *   Try to use a shovel/pick to help with tunnelling
 *   If wounded, must run away from monsters, then rest
 *   When blind, monster and object info may be invalid
 *   When totally surrounded by monsters, try to escape rooms
 *   Conserve memory space (each grid byte costs about 15K)
 *   Conserve computation time (especially with the flow code)
 *   Note -- nutrition can come from food, scrolls, or spells
 *   Note -- recall can come from scrolls, rods, or spells
 *   Note -- identify can come from scrolls, rods, staffs, or spells
 *   Becoming "afraid" (attacking takes a turn for no effect)
 *   Beware of firing missiles at a food ration under a mushroom
 *   Attempt to save possibly useful equipment in the home
 *
 * We need to handle "loading" saved games:
 *   The "max_depth" value is lost if loaded in the town
 *   If we track "dead uniques" then this information is lost
 *   The "map" info, "flow" info, "tracking" info, etc is lost
 *   The contents of the shops (and the home) are lost
 *   We may be asked to "resume" a non-Borg character (icky)
 */


/*
 * Currently, the Borg "cheats" in a few situations...
 *
 * Cheats that are significant, and possibly unavoidable:
 *   Knowledge of when we are being asked for a keypress.
 *   Note that this could be avoided by LONG timeouts/delays
 *
 * Cheats "required" by implementation, but not signifant:
 *   Direct access to the "screen image" (parsing screen)
 *   Direct access to the "keypress queue" (sending keys)
 *   Direct access to the "cursor visibility" (game state)
 *
 * Cheats that could be avoided by simple (ugly) code:
 *   Direct modification of the "current options"
 *
 * Cheats that could be avoided by duplicating code:
 *   Use of the tables in "tables.c"
 *   Use of the arrays initialized in "init.c"
 *
 * Cheats that can be avoided by toggling a switch:
 *   Direct extraction of "panel" info (auto_cheat_panel)
 *   Direct extraction of "inven" info (auto_cheat_inven)
 *   Direct extraction of "equip" info (auto_cheat_equip)
 *   Direct extraction of "spell" info (auto_cheat_spell)
 *
 * Cheats that the Borg would love:
 *   Immunity to hallucination, blindness, confusion
 *   Unique attr/char codes for every monster and object
 *   Removal of the "mimic" and "trapper" monsters
 *   Removal of the "mushroom" and "gold" monsters
 */


/*
 * Stat advantages:
 *   High STR (attacks, to-dam, digging, weight limit)
 *   High DEX (attacks, to-hit, armor class)
 *   High CON (hitpoints, recovery)
 *   High WIS (better prayers, saving throws)
 *   High INT (better spells, disarming, device usage)
 *   High CHR (better item costs)
 *
 * Class advantages:
 *   Warrior (good fighting, sensing)
 *   Mage (good spells)
 *   Priest (good prayers, fighting)
 *   Ranger (some spells, fighting)
 *   Rogue (some spells, fighting, sensing)
 *   Paladin (prayers, fighting, sensing)
 *
 * Race advantages:
 *   Gnome (free action)
 *   Dwarf (resist blindness)
 *   High elf (see invisible)
 *   Non-human (infravision)
 */




/*
 * Some variables
 */

static bool initialized;    /* Hack -- Initialized */



/*
 * Mega-Hack -- extract some "hidden" variables
 *
 * XXX XXX XXX This step would not be necessary if more info
 * was available on the screen.
 *
 */
static void borg_hidden(void)
{
    int i;

    /* Clear the stat modifiers */
    for (i = 0; i < 6; i++) my_stat_add[i] = 0;

    /* Scan the usable inventory */
    for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
    {
        auto_item *item = &auto_items[i];

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

        /* if we have on unidentified stuff we may have misguessed our */
        /* stats. */
        if (!item->able)
        {
            my_need_stat_check[0] = TRUE;
            my_need_stat_check[1] = TRUE;
            my_need_stat_check[2] = TRUE;
            my_need_stat_check[3] = TRUE;
            my_need_stat_check[4] = TRUE;
            my_need_stat_check[5] = TRUE;
            break;
        }

        /* Affect stats */
        if (item->flags1 & TR1_STR) my_stat_add[A_STR] += item->pval;
        if (item->flags1 & TR1_INT) my_stat_add[A_INT] += item->pval;
        if (item->flags1 & TR1_WIS) my_stat_add[A_WIS] += item->pval;
        if (item->flags1 & TR1_DEX) my_stat_add[A_DEX] += item->pval;
        if (item->flags1 & TR1_CON) my_stat_add[A_CON] += item->pval;
        if (item->flags1 & TR1_CHR) my_stat_add[A_CHR] += item->pval;
    }

    /* Mega-Hack -- Guess at "my_stat_cur[]" */
    for (i = 0; i < 6; i++)
    {
        int value;

        if (!my_need_stat_check[i]) continue;

        /* Reverse known bonuses to get the base stat value */
        value = modify_stat_value(auto_stat[i], -my_stat_add[i]);

        /* If the displayed stat is 18/220 this was just a guess.  */ 
        /* The player still needs to take off some stuff to get the */
        /* real value. */
        if (auto_stat[i] < 238)
        {
            my_need_stat_check[i] = FALSE;
        }

        /* Hack -- save the maximum/current stats */
        my_stat_cur[i] = value;
        
        /* Max stat is the max that the cur stat ever is. */
        if (my_stat_cur[i] > my_stat_max[i])
            my_stat_max[i] = my_stat_cur[i];
            
        /* if this stat is not in need of fixing and */
        /* it is less than the max it should be equal to the max */
        /* and we are done. */
#if 0 
/* there is a problem with this when you get drained but are above */
/* 18/220 and after you forget your stuff */
        if (my_need_stat_check[i] && !do_fix_stat[i] && 
            my_stat_max[i] > my_stat_cur[i])
        {
            my_stat_cur[i] = my_stat_max[i];
            my_need_stat_check[i] = FALSE;
        }
#endif       
    }
}



/*
 * Think about the world and perform an action
 *
 * Check inventory/equipment/spells/panel once per "turn"
 *
 * Process "store" and other modes when necessary
 *
 * Note that the non-cheating "inventory" and "equipment" parsers
 * will get confused by a "weird" situation involving an ant ("a")
 * on line one of the screen, near the left, next to a shield, of
 * the same color, and using --(-- the ")" symbol, directly to the
 * right of the ant.  This is very rare, but perhaps not completely
 * impossible.  I ignore this situation.  :-)
 *
 * The handling of stores is a complete and total hack, but seems
 * to work remarkably well, considering... :-)  Note that while in
 * a store, time does not pass, and most actions are not available,
 * and a few new commands are available ("sell" and "purchase").
 *
 * Note the use of "cheat" functions to extract the current inventory,
 * the current equipment, the current panel, and the current spellbook
 * information.  These can be replaced by (very expensive) "parse"
 * functions, which cause an insane amount of "screen flashing".
 *
 * Technically, we should attempt to parse all the messages that
 * indicate that it is necessary to re-parse the equipment, the
 * inventory, or the books, and only set the appropriate flags
 * at that point.  This would not only reduce the potential
 * screen flashing, but would also optimize the code a lot,
 * since the "cheat_inven()" and "cheat_equip()" functions
 * are expensive.  For paranoia, we could always select items
 * and spells using capital letters, and keep a global verification
 * buffer, and induce failure and recheck the inventory/equipment
 * any time we get a mis-match.  We could even do some of the state
 * processing by hand, for example, charge reduction and such.  This
 * might also allow us to keep track of how long we have held objects,
 * especially if we attempt to do "item tracking" in the inventory
 * extraction code.
 */
static bool borg_think(void)
{
    int i;

    byte t_a;

    char buf[128];


    /*** Process inventory/equipment ***/

    /* Cheat */
    if (auto_cheat_equip && auto_do_equip)
    {
        /* Only do it once */
        auto_do_equip = FALSE;

        /* Cheat the "equip" screen */
        borg_cheat_equip();

        /* Done */
        return (FALSE);
    }

    /* Cheat */
    if (auto_cheat_inven && auto_do_inven)
    {
        /* Only do it once */
        auto_do_inven = FALSE;

        /* Cheat the "inven" screen */
        borg_cheat_inven();

        /* Done */
        return (FALSE);
    }

    /* save now */
    if (borg_save && borg_save_game())
    {
        /* Log */
        borg_note("# Auto Save!");
    
        borg_save = FALSE;
        return (TRUE);
    }

    /* Parse "equip" mode */
    if ((0 == borg_what_text(0, 0, 10, &t_a, buf)) &&
        (streq(buf, "Equipment ")))
    {
        /* Parse the "equip" screen */
        borg_parse_equip();

        /* Leave this mode */
        borg_keypress(ESCAPE);

        /* Done */
        return (TRUE);
    }


    /* Parse "inven" mode */
    if ((0 == borg_what_text(0, 0, 10, &t_a, buf)) &&
        (streq(buf, "Inventory ")))
    {
        /* Parse the "inven" screen */
        borg_parse_inven();

        /* Leave this mode */
        borg_keypress(ESCAPE);

        /* Done */
        return (TRUE);
    }


    /* Check "equip" */
    if (auto_do_equip)
    {
        /* Only do it once */
        auto_do_equip = FALSE;

        /* Enter "equip" mode */
        borg_keypress('e');

        /* Done */
        return (TRUE);
    }

    /* Check "inven" */
    if (auto_do_inven)
    {
        /* Only do it once */
        auto_do_inven = FALSE;

        /* Enter "inven" mode */
        borg_keypress('i');

        /* Done */
        return (TRUE);
    }


    /*** Find books ***/

    /* Only if needed */
    if (auto_do_spell && (auto_do_spell_aux == 0))
    {
        /* Assume no books */
        for (i = 0; i < 9; i++) auto_book[i] = -1;

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

            /* Skip non-books */
            if (item->tval != mb_ptr->spell_book) continue;

            /* Note book locations */
            auto_book[item->sval] = i;
        }
    }


    /*** Process books ***/

    /* Hack -- Warriors never browse */
    if (auto_class == 0) auto_do_spell = FALSE;

    /* Hack -- Blind or Confused prevents browsing */
    if (do_blind || do_confused) auto_do_spell = FALSE;

    /* XXX XXX XXX Dark */

    /* Hack -- Stop doing spells when done */
    if (auto_do_spell_aux > 8) auto_do_spell = FALSE;

    /* Cheat */
    if (auto_cheat_spell && auto_do_spell)
    {
        /* Look for the book */
        i = auto_book[auto_do_spell_aux];

        /* Cheat the "spell" screens (all of them) */
        if (i >= 0)
        {
            /* Cheat that page */
            borg_cheat_spell(auto_do_spell_aux);
        }

        /* Advance to the next book */
        auto_do_spell_aux++;

        /* Done */
        return (FALSE);
    }

    /* Check for "browse" mode */
    if ((0 == borg_what_text(COL_SPELL, ROW_SPELL, -12, &t_a, buf)) &&
        (streq(buf, "Lv Mana Fail")))
    {
        /* Parse the "spell" screen */
        borg_parse_spell(auto_do_spell_aux);

        /* Advance to the next book */
        auto_do_spell_aux++;

        /* Leave that mode */
        borg_keypress(ESCAPE);

        /* Done */
        return (TRUE);
    }

    /* Check "spells" */
    if (auto_do_spell)
    {
        /* Look for the book */
        i = auto_book[auto_do_spell_aux];

        /* Enter the "spell" screen */
        if (i >= 0)
        {
            /* Enter "browse" mode */
            borg_keypress('b');

            /* Pick the next book */
            borg_keypress(I2A(i));

            /* Done */
            return (TRUE);
        }

        /* Advance to the next book */
        auto_do_spell_aux++;

        /* Done */
        return (FALSE);
    }

    /* check for anything that needs *ID* */
    if ( auto_do_star_id )
    {
        if (borg_object_star_id())
            return (TRUE);

        auto_do_star_id = FALSE;
    }

    /* if king and in town, retire.  Let the player do this. */
    if (borg_king && !auto_depth)
    {
        borg_oops("retire"); 
    }

    /*** Handle stores ***/

    /* Hack -- Check for being in a store */
    if ((0 == borg_what_text(3, 5, 16, &t_a, buf)) &&
        (streq(buf, "Item Description")))
    {
        /* Assume the Home */
        shop_num = 7;

        /* Extract the "store" name */
        if (0 == borg_what_text(50, 3, -20, &t_a, buf))
        {
            int i;

            /* Check the store names */
            for (i = 0; i < 7; i++)
            {
                cptr name = (f_name + f_info[0x08+i].name);
                if (prefix(buf, name)) shop_num = i;
            }
        }

        /* Hack -- reset page/more */
        auto_shops[shop_num].page = 0;
        auto_shops[shop_num].more = 0;

        /* React to new stores */
        if (auto_do_browse_what != shop_num)
        {
            /* Clear all the items */
            for (i = 0; i < 24; i++)
            {
                /* XXX Wipe the ware */
                WIPE(&auto_shops[shop_num].ware[i], auto_item);
            }

            /* Save the store */
            auto_do_browse_what = shop_num;
        }


        /* Extract the "page", if any */
        if ((0 == borg_what_text(20, 5, 8, &t_a, buf)) &&
            (prefix(buf, "(Page "))) /* --)-- */
        {
            /* Take note of the page */
            auto_shops[shop_num].more = 1;
            auto_shops[shop_num].page = (buf[6] - '0') - 1;
        }

        /* React to disappearing pages */
        if (auto_do_browse_more != auto_shops[shop_num].more)
        {
            /* Clear the second page */
            for (i = 12; i < 24; i++)
            {
                /* XXX Wipe the ware */
                WIPE(&auto_shops[shop_num].ware[i], auto_item);
            }

            /* Save the new one */
            auto_do_browse_more = auto_shops[shop_num].more;
            auto_do_browse = auto_do_browse_more;
        }

        /* Extract the current gold (unless in home) */
        if (0 == borg_what_text(68, 19, -9, &t_a, buf))
        {
            /* Save the gold, if valid */
            if (buf[0]) auto_gold = atol(buf);
        }

        /* Parse the store (or home) inventory */
        for (i = 0; i < 12; i++)
        {
            int n;

            char desc[80];
            char cost[10];

            /* Default to "empty" */
            desc[0] = '\0';
            cost[0] = '\0';

            /* Verify "intro" to the item */
            if ((0 == borg_what_text(0, i + 6, 3, &t_a, buf)) &&
                (buf[0] == I2A(i)) && (buf[1] == p2) && (buf[2] == ' '))
            {
                int k;

                /* Extract the item description */
                if (0 != borg_what_text(3, i + 6, -65, &t_a, desc))
                {
                    desc[0] = '\0';
                }

                /* Strip trailing spaces */
                for (k = strlen(desc); (k > 0) && (desc[k-1] == ' '); k--) /* loop */;
                desc[k] = '\0';

                /* Extract the item cost in stores */
                if (shop_num != 7)
                {
                    if (0 != borg_what_text(68, i + 6, -9, &t_a, cost))
                    {
                        cost[0] = '\0';
                    }
                }
            }

            /* Extract actual index */
            n = auto_shops[shop_num].page * 12 + i;

            /* Ignore "unchanged" descriptions */
            if (streq(desc, auto_shops[shop_num].ware[n].desc)) continue;

            /* Analyze the item */
            borg_item_analyze(&auto_shops[shop_num].ware[n], desc);

            /*need to be able to analize the home inventory to see if it was */
            /* *fully ID*d. */
            /* This is a BIG CHEAT!  It will be less of a cheat if code is put*/
            /* in place to allow 'I' in stores. */
#ifdef ID_MENTAL
            if (store[shop_num].stock[n].ident & ID_MENTAL)
            {
                /* XXX XXX XXX for now, allways cheat to get info on items at */
                /*   home. */
                borg_object_star_id_aux( &auto_shops[shop_num].ware[n], 
                                         &store[shop_num].stock[n]);
                auto_shops[shop_num].ware[n].fully_identified = TRUE;
            }
#endif
            /* Hack -- Save the declared cost */
            auto_shops[shop_num].ware[n].cost = atol(cost);
        }

        /* Hack -- browse as needed */
        if (auto_shops[shop_num].more && auto_do_browse)
        {
            /* Check next page */
            borg_keypress(' ');

            /* Done browsing */
            auto_do_browse = FALSE;

            /* Done */
            return (TRUE);
        }

        /* Recheck inventory */
        auto_do_inven = TRUE;

        /* Recheck equipment */
        auto_do_equip = TRUE;

        /* Recheck spells */
        auto_do_spell = TRUE;

        /* Restart spells */
        auto_do_spell_aux = 0;

        /* Hack -- browse again later */
        auto_do_browse = TRUE;

        /* Examine the inventory */
        borg_notice();

        /* Evaluate the current world */
        my_power = borg_power();

        /* Hack -- allow user abort */
        if (auto_cancel) return (TRUE);

        /* Think until done */
        return (borg_think_store());
    }



    /*** Determine panel ***/

    /* Hack -- cheat */
    if (auto_cheat_panel)
    {
        /* Cheat */
        w_y = panel_row * (SCREEN_HGT / 2);
        w_x = panel_col * (SCREEN_WID / 2);

        /* Done */
        auto_do_panel = FALSE;
    }

    /* Hack -- Check for "sector" mode */
    if ((0 == borg_what_text(0, 0, 16, &t_a, buf)) &&
        (prefix(buf, "Map sector ")))
    {
        /* Hack -- get the panel info */
        w_y = (buf[12] - '0') * (SCREEN_HGT / 2);
        w_x = (buf[14] - '0') * (SCREEN_WID / 2);

        /* Leave panel mode */
        borg_keypress(ESCAPE);

        /* Done */
        return (TRUE);
    }

    /* Check equipment */
    if (auto_do_panel)
    {
        /* Only do it once */
        auto_do_panel = FALSE;

        /* Enter "panel" mode */
        borg_keypress('L');

        /* Done */
        return (TRUE);
    }


    /*** Analyze the Frame ***/

    /* Analyze the frame */
    if (auto_do_frame)
    {
        /* Only once */
        auto_do_frame = FALSE;

        /* Analyze the "frame" */
        borg_update_frame();
    }


    /*** Re-activate Tests ***/

    /* Check equip again later */
    auto_do_equip = TRUE;

    /* Check inven again later */
    auto_do_inven = TRUE;

    /* Check panel again later */
    auto_do_panel = TRUE;

    /* Check frame again later */
    auto_do_frame = TRUE;

    /* Check spells again later */
    auto_do_spell = TRUE;

    /* Hack -- Start the books over */
    auto_do_spell_aux = 0;


    /*** Analyze status ***/

    /* Track best level */
    if (auto_level > auto_max_level) auto_max_level = auto_level;
    if (auto_depth > auto_max_depth)
    {
        auto_max_depth = auto_depth;
        finished_level = FALSE;
    }

    /*** Think about it ***/

    /* Increment the clock */
    c_t++;

    /* Examine the screen */
    borg_update();

    /* Extract some "hidden" variables */
    borg_hidden();

    /* Examine the equipment/inventory */
    borg_notice();

    /* Evaluate the current world */
    my_power = borg_power();

    /* Hack -- allow user abort */
    if (auto_cancel) return (TRUE);

    /* Do something */
    return (borg_think_dungeon());
}



/*
 * Hack -- methods of hurting a monster (order not important).
 *
 * See "message_pain()" for details.
 */
static cptr suffix_pain[] =
{
    " barely notices.",
    " flinches.",
    " squelches.",
    " quivers in pain.",
    " writhes about.",
    " writhes in agony.",
    " jerks limply.",

    " shrugs off the attack.",
    " snarls with pain.",
    " yelps in pain.",
    " howls in pain.",
    " howls in agony.",
    /* xxx */
    " yelps feebly.",

    " ignores the attack.",
    " grunts with pain.",
    " squeals in pain.",
    " shrieks in pain.",
    " shrieks in agony.",
    /* xxx */
    " cries out feebly.",

    /* xxx */
    /* xxx */
    " cries out in pain.",
    " screams in pain.",
    " screams in agony.",
    /* xxx */
    /* xxx */

    NULL
};


/*
 * Hack -- methods of killing a monster (order not important).
 *
 * See "mon_take_hit()" for details.
 */
static cptr prefix_kill[] =
{
    "You have killed ",
    "You have slain ",
    "You have destroyed ",
    NULL
};


/*
 * Hack -- methods of monster death (order not important).
 *
 * See "project_m()", "do_cmd_fire()", "mon_take_hit()" for details.
 */
static cptr suffix_died[] =
{
    " dies.",
    " is destroyed.",
    " dissolves!",
    " shrivels away in the light!",
    NULL
};


/*
 * Hack -- methods of hitting the player (order not important).
 *
 * The "insult", "moan", and "begs you for money" messages are ignored.
 *
 * See "make_attack_normal()" for details.
 */
static cptr suffix_hit_by[] =
{
    " hits you.",
    " touches you.",
    " punches you.",
    " kicks you.",
    " claws you.",
    " bites you.",
    " stings you.",
    " butts you.",
    " crushes you.",
    " engulfs you.",
    " crawls on you.",
    " drools on you.",
    " spits on you.",
    " gazes at you.",
    " wails at you.",
    " releases spores at you.",
    NULL
};


/*
 * Hack -- methods of casting spells at the player (order important).
 *
 * See "make_attack_spell()" for details.
 */
static cptr suffix_spell[] =
{
    " makes a high pitched shriek.",        /* RF4_SHRIEK */
    " does something.",             /* RF4_XXX2X4 */
    " does something.",             /* RF4_XXX3X4 */
    " does something.",             /* RF4_XXX4X4 */
    " fires an arrow.",             /* RF4_ARROW_1 */
    " fires an arrow!",             /* RF4_ARROW_2 */
    " fires a missile.",            /* RF4_ARROW_3 */
    " fires a missile!",            /* RF4_ARROW_4 */
    " breathes acid.",              /* RF4_BR_ACID */
    " breathes lightning.",         /* RF4_BR_ELEC */
    " breathes fire.",              /* RF4_BR_FIRE */
    " breathes frost.",             /* RF4_BR_COLD */
    " breathes gas.",               /* RF4_BR_POIS */
    " breathes nether.",            /* RF4_BR_NETH */
    " breathes light.",             /* RF4_BR_LITE */
    " breathes darkness.",          /* RF4_BR_DARK */
    " breathes confusion.",         /* RF4_BR_CONF */
    " breathes sound.",             /* RF4_BR_SOUN */
    " breathes chaos.",             /* RF4_BR_CHAO */
    " breathes disenchantment.",        /* RF4_BR_DISE */
    " breathes nexus.",             /* RF4_BR_NEXU */
    " breathes time.",              /* RF4_BR_TIME */
    " breathes inertia.",           /* RF4_BR_INER */
    " breathes gravity.",           /* RF4_BR_GRAV */
    " breathes shards.",            /* RF4_BR_SHAR */
    " breathes plasma.",            /* RF4_BR_PLAS */
    " breathes force.",             /* RF4_BR_WALL */
    " does something.",             /* RF4_BR_MANA */
    " does something.",             /* RF4_XXX5X4 */
    " does something.",             /* RF4_XXX6X4 */
    " does something.",             /* RF4_XXX7X4 */
    " does something.",             /* RF4_XXX8X4 */

    " casts an acid ball.",         /* RF5_BA_ACID */
    " casts a lightning ball.",         /* RF5_BA_ELEC */
    " casts a fire ball.",          /* RF5_BA_FIRE */
    " casts a frost ball.",         /* RF5_BA_COLD */
    " casts a stinking cloud.",         /* RF5_BA_POIS */
    " casts a nether ball.",            /* RF5_BA_NETH */
    " gestures fluidly.",           /* RF5_BA_WATE */
    " invokes a mana storm.",           /* RF5_BA_MANA */
    " invokes a darkness storm.",       /* RF5_BA_DARK */
    " draws psychic energy from you!",      /* RF5_DRAIN_MANA */
    " gazes deep into your eyes.",      /* RF5_MIND_BLAST */
    " looks deep into your eyes.",      /* RF5_BRAIN_SMASH */
    " points at you and curses.",       /* RF5_CAUSE_1 */
    " points at you and curses horribly.",  /* RF5_CAUSE_2 */
    " points at you, incanting terribly!",  /* RF5_CAUSE_3 */
    " points at you, screaming the word DIE!",  /* RF5_CAUSE_4 */
    " casts a acid bolt.",          /* RF5_BO_ACID */
    " casts a lightning bolt.",         /* RF5_BO_ELEC */
    " casts a fire bolt.",          /* RF5_BO_FIRE */
    " casts a frost bolt.",         /* RF5_BO_COLD */
    " does something.",             /* RF5_BO_POIS */
    " casts a nether bolt.",            /* RF5_BO_NETH */
    " casts a water bolt.",         /* RF5_BO_WATE */
    " casts a mana bolt.",          /* RF5_BO_MANA */
    " casts a plasma bolt.",            /* RF5_BO_PLAS */
    " casts an ice bolt.",          /* RF5_BO_ICEE */
    " casts a magic missile.",          /* RF5_MISSILE */
    " casts a fearful illusion.",       /* RF5_SCARE */
    " casts a spell, burning your eyes!",   /* RF5_BLIND */
    " creates a mesmerising illusion.",     /* RF5_CONF */
    " drains power from your muscles!",     /* RF5_SLOW */
    " stares deep into your eyes!",     /* RF5_HOLD */

    " concentrates on XXX body.",       /* RF6_HASTE */
    " does something.",             /* RF6_XXX1X6 */
    " concentrates on XXX wounds.",     /* RF6_HEAL */
    " does something.",             /* RF6_XXX2X6 */
    " blinks away.",                /* RF6_BLINK */
    " teleports away.",             /* RF6_TPORT */
    " does something.",             /* RF6_XXX3X6 */
    " does something.",             /* RF6_XXX4X6 */
    " commands you to return.",         /* RF6_TELE_TO */
    " teleports you away.",         /* RF6_TELE_AWAY */
    " gestures at your feet.",          /* RF6_TELE_LEVEL */
    " does something.",             /* RF6_XXX5 */
    " gestures in shadow.",         /* RF6_DARKNESS */
    " casts a spell and cackles evilly.",   /* RF6_TRAPS */
    " tries to blank your mind.",       /* RF6_FORGET */
    " does something.",             /* RF6_XXX6X6 */
    " does something.",             /* RF6_XXX7X6 */
    " does something.",             /* RF6_XXX8X6 */
    " magically summons help!",         /* RF6_S_MONSTER */
    " magically summons monsters!",     /* RF6_S_MONSTERS */
    " magically summons ants.",         /* RF6_S_ANT */
    " magically summons spiders.",      /* RF6_S_SPIDER */
    " magically summons hounds.",       /* RF6_S_HOUND */
    " magically summons hydras.",       /* RF6_S_HYDRA */
    " magically summons an angel!",     /* RF6_S_ANGEL */
    " magically summons a hellish adversary!",  /* RF6_S_DEMON */
    " magically summons an undead adversary!",  /* RF6_S_UNDEAD */
    " magically summons a dragon!",     /* RF6_S_DRAGON */
    " magically summons greater undead!",   /* RF6_S_HI_UNDEAD */
    " magically summons ancient dragons!",  /* RF6_S_HI_DRAGON */
    " magically summons mighty undead opponents!",  /* RF6_S_WRAITH */
    " magically summons special opponents!",        /* RF6_S_UNIQUE */

    NULL
};



#if 0
/* XXX XXX XXX */
msg_format("%^s looks healthier.", m_name);
msg_format("%^s looks REALLY healthy!", m_name);
#endif



/*
 * Hack -- Spontaneous level feelings (order important).
 *
 * See "do_cmd_feeling()" for details.
 */
static cptr prefix_feeling[] =
{
    "Looks like any other level",
    "You feel there is something special",
    "You have a superb feeling",
    "You have an excellent feeling",
    "You have a very good feeling",
    "You have a good feeling",
    "You feel strangely lucky",
    "You feel your luck is turning",
    "You like the look of this place",
    "This level can't be all bad",
    "What a boring place",
    NULL
};



/*
 * Hack -- Parse a message from the world
 *
 * Note that detecting "death" is EXTREMELY important, to prevent
 * all sorts of errors arising from attempting to parse the "tomb"
 * screen, and to allow the user to "observe" the "cause" of death.
 *
 * Note that detecting "failure" is EXTREMELY important, to prevent
 * bizarre situations after failing to use a staff of perceptions,
 * which would otherwise go ahead and send the "item index" which
 * might be a legal command (such as "a" for "aim").  This method
 * is necessary because the Borg cannot parse "prompts", and must
 * assume the success of the prompt-inducing command, unless told
 * otherwise by a failure message.  Also, we need to detect failure
 * because some commands, such as detection spells, need to induce
 * furthur processing if they succeed, but messages are only given
 * if the command fails.
 *
 * Note that certain other messages may contain useful information,
 * and so they are "analyzed" and sent to "borg_react()", which just
 * queues the messages for later analysis in the proper context.
 *
 * Along with the actual message, we send a special formatted buffer,
 * containing a leading "opcode", which may contain extra information,
 * such as the index of a spell, and an "argument" (for example, the
 * capitalized name of a monster), with a "colon" to separate them.
 *
 * XXX XXX XXX Several message strings take a "possessive" of the form
 * "his" or "her" or "its".  These strings are all represented by the
 * encoded form "XXX" in the various match strings.  Unfortunately,
 * the encode form is never decoded, so the Borg currently ignores
 * messages about several spells (heal self and haste self).
 *
 * XXX XXX XXX We notice a few "terrain feature" messages here so
 * we can acquire knowledge about wall types and door types.
 */
static void borg_parse_aux(cptr msg, int len)
{
    int i, tmp;

    char who[256];
    char buf[256];

    auto_grid *ag = &auto_grids[g_y][g_x];


    /* Log (if needed) */
    if (auto_fff) borg_info(format("& Msg <%s>", msg));


    /* Hack -- Notice death */
    if (prefix(msg, "You die."))
    {
        /* Abort (unless cheating) */
        if (!(wizard || cheat_live))
        {
            /* Abort */
            borg_oops("death");

            /* Abort right now! */
            auto_active = FALSE;

            /* Noise XXX XXX XXX */
            Term_xtra(TERM_XTRA_NOISE, 1);
        }

        /* Done */
        return;
    }


    /* Hack -- Notice "failure" */
    if (prefix(msg, "You failed "))
    {
        /* Hack -- store the keypress */
        borg_note("# Normal failure.");

        /* Set the failure flag */
        auto_failure = TRUE;

        /* Flush our key-buffer */
        borg_flush();
        return;
    }


    /* Ignore teleport trap */
    if (prefix(msg, "You hit a teleport")) return;

    /* Ignore arrow traps */
    if (prefix(msg, "An arrow ")) return;

    /* Ignore dart traps */
    if (prefix(msg, "A small dart ")) return;

    if (prefix(msg, "The cave ")) 
    {
        borg_react(msg, "QUAKE");
        return;
    }
    
    /* need to check stat */
    if (prefix(msg, "You feel very") || 
        prefix(msg, "You feel less") ||
        prefix(msg, "Wow!  You feel very"))
    {
        /* need to check str */
        if (prefix(msg, "You feel very weak"))
        {
            my_need_stat_check[0] = TRUE;
        }
        if (prefix(msg, "You feel less weak"))
        {
            my_need_stat_check[0] = TRUE;
        }
        if (prefix(msg, "Wow!  You feel very strong"))
        {
            my_need_stat_check[0] = TRUE;
        }

        /* need to check int */
        if (prefix(msg, "You feel very stupid"))
        {
            my_need_stat_check[1] = TRUE;
        }
        if (prefix(msg, "You feel less stupid"))
        {
            my_need_stat_check[1] = TRUE;
        }
        if (prefix(msg, "Wow!  You feel very smart"))
        {
            my_need_stat_check[1] = TRUE;
        }

        /* need to check wis */
        if (prefix(msg, "You feel very naive"))
        {
            my_need_stat_check[2] = TRUE;
        }
        if (prefix(msg, "You feel less naive"))
        {
            my_need_stat_check[2] = TRUE;
        }
        if (prefix(msg, "Wow!  You feel very wise"))
        {
            my_need_stat_check[2] = TRUE;
        }

        /* need to check dex */
        if (prefix(msg, "You feel very clumsy"))
        {
            my_need_stat_check[3] = TRUE;
        }
        if (prefix(msg, "You feel less clumsy"))
        {
            my_need_stat_check[3] = TRUE;
        }
        if (prefix(msg, "Wow!  You feel very dextrous"))
        {
            my_need_stat_check[3] = TRUE;
        }

        /* need to check con */
        if (prefix(msg, "You feel very sickly"))
        {
            my_need_stat_check[4] = TRUE;
        }
        if (prefix(msg, "You feel less sickly"))
        {
            my_need_stat_check[4] = TRUE;
        }
        if (prefix(msg, "Wow!  You feel very healthy"))
        {
            my_need_stat_check[4] = TRUE;
        }

        /* need to check cha */
        if (prefix(msg, "You feel very ugly"))
        {
            my_need_stat_check[5] = TRUE;
        }
        if (prefix(msg, "You feel less ugly"))
        {
            my_need_stat_check[5] = TRUE;
        }
        if (prefix(msg, "Wow!  You feel very cute"))
        {
            my_need_stat_check[5] = TRUE;
        }
    }

    /* time attacks, just do all stats. */
    if (prefix(msg, "You're not as"))
    {
        my_need_stat_check[0] = TRUE;
        my_need_stat_check[1] = TRUE;
        my_need_stat_check[2] = TRUE;
        my_need_stat_check[3] = TRUE;
        my_need_stat_check[4] = TRUE;
        my_need_stat_check[5] = TRUE;
    }
      
    /* Nexus attacks, need to check everything! */
    if (prefix(msg, "Your body starts to scramble..."))
    {
        my_need_stat_check[0] = TRUE;
        my_need_stat_check[1] = TRUE;
        my_need_stat_check[2] = TRUE;
        my_need_stat_check[3] = TRUE;
        my_need_stat_check[4] = TRUE;
        my_need_stat_check[5] = TRUE;

        /* max stats may have lowered */
        my_stat_max[0] = 0;
        my_stat_max[1] = 0;
        my_stat_max[2] = 0;
        my_stat_max[3] = 0;
        my_stat_max[4] = 0;
        my_stat_max[5] = 0;

    }
    
    /* Hit somebody */
    if (prefix(msg, "You hit "))
    {
        tmp = strlen("You hit ");
        strnfmt(who, 1 + len - (tmp + 1), "%s", msg + tmp);
        strnfmt(buf, 256, "HIT:%^s", who);
        borg_react(msg, buf);
        return;
    }

    /* Miss somebody */
    if (prefix(msg, "You miss "))
    {
        tmp = strlen("You miss ");
        strnfmt(who, 1 + len - (tmp + 1), "%s", msg + tmp);
        strnfmt(buf, 256, "MISS:%^s", who);
        borg_react(msg, buf);
        return;
    }

    /* Miss somebody (because of fear) */
    if (prefix(msg, "You are too afraid to attack "))
    {
        tmp = strlen("You are too afraid to attack ");
        strnfmt(who, 1 + len - (tmp + 1), "%s", msg + tmp);
        strnfmt(buf, 256, "MISS:%^s", who);
        borg_react(msg, buf);
        return;
    }


    /* "It screams in pain." (etc) */
    for (i = 0; suffix_pain[i]; i++)
    {
        /* "It screams in pain." (etc) */
        if (suffix(msg, suffix_pain[i]))
        {
            tmp = strlen(suffix_pain[i]);
            strnfmt(who, 1 + len - tmp, "%s", msg);
            strnfmt(buf, 256, "PAIN:%^s", who);
            borg_react(msg, buf);
            return;
        }
    }


    /* "You have killed it." (etc) */
    for (i = 0; prefix_kill[i]; i++)
    {
        /* "You have killed it." (etc) */
        if (prefix(msg, prefix_kill[i]))
        {
            tmp = strlen(prefix_kill[i]);
            strnfmt(who, 1 + len - (tmp + 1), "%s", msg + tmp);
            strnfmt(buf, 256, "KILL:%^s", who);
            borg_react(msg, buf);
            return;
        }
    }


    /* "It dies." (etc) */
    for (i = 0; suffix_died[i]; i++)
    {
        /* "It dies." (etc) */
        if (suffix(msg, suffix_died[i]))
        {
            tmp = strlen(suffix_died[i]);
            strnfmt(who, 1 + len - tmp, "%s", msg);
            strnfmt(buf, 256, "DIED:%^s", who);
            borg_react(msg, buf);
            return;
        }
    }


    /* "It misses you." */
    if (suffix(msg, " misses you."))
    {
        tmp = strlen(" misses you.");
        strnfmt(who, 1 + len - tmp, "%s", msg);
        strnfmt(buf, 256, "MISS_BY:%^s", who);
        borg_react(msg, buf);
        return;
    }

    /* "It is repelled.." */
    /* treat as a miss */
    if (suffix(msg, " is repelled."))
    {
        tmp = strlen(" is repelled.");
        strnfmt(who, 1 + len - tmp, "%s", msg);
        strnfmt(buf, 256, "MISS_BY:%^s", who);
        borg_react(msg, buf);
        return;
    }

    /* "It hits you." (etc) */
    for (i = 0; suffix_hit_by[i]; i++)
    {
        /* "It hits you." (etc) */
        if (suffix(msg, suffix_hit_by[i]))
        {
            tmp = strlen(suffix_hit_by[i]);
            strnfmt(who, 1 + len - tmp, "%s", msg);
            strnfmt(buf, 256, "HIT_BY:%^s", who);
            borg_react(msg, buf);
            return;
        }
    }


    /* "It casts a spell." (etc) */
    for (i = 0; suffix_spell[i]; i++)
    {
        /* "It casts a spell." (etc) */
        if (suffix(msg, suffix_spell[i]))
        {
            tmp = strlen(suffix_spell[i]);
            strnfmt(who, 1 + len - tmp, "%s", msg);
            strnfmt(buf, 256, "SPELL_%03d:%^s", 96+i, who);
            borg_react(msg, buf);
            return;
        }
    }


    /* State -- Asleep */
    if (suffix(msg, " falls asleep!"))
    {
        tmp = strlen(" falls asleep!");
        strnfmt(who, 1 + len - tmp, "%s", msg);
        strnfmt(buf, 256, "STATE_SLEEP:%^s", who);
        borg_react(msg, buf);
        return;
    }

    /* State -- Not Asleep */
    if (suffix(msg, " wakes up."))
    {
        tmp = strlen(" wakes up.");
        strnfmt(who, 1 + len - tmp, "%s", msg);
        strnfmt(buf, 256, "STATE_AWAKE:%^s", who);
        borg_react(msg, buf);
        return;
    }

    /* State -- Afraid */
    if (suffix(msg, " flees in terror!"))
    {
        tmp = strlen(" flees in terror!");
        strnfmt(who, 1 + len - tmp, "%s", msg);
        strnfmt(buf, 256, "STATE__FEAR:%^s", who);
        borg_react(msg, buf);
        return;
    }

    /* State -- Not Afraid */
    if (suffix(msg, " recovers his courage."))
    {
        tmp = strlen(" recovers his courage.");
        strnfmt(who, 1 + len - tmp, "%s", msg);
        strnfmt(buf, 256, "STATE__BOLD:%^s", who);
        borg_react(msg, buf);
        return;
    }

    /* State -- Not Afraid */
    if (suffix(msg, " recovers her courage."))
    {
        tmp = strlen(" recovers her courage.");
        strnfmt(who, 1 + len - tmp, "%s", msg);
        strnfmt(buf, 256, "STATE__BOLD:%^s", who);
        borg_react(msg, buf);
        return;
    }

    /* State -- Not Afraid */
    if (suffix(msg, " recovers its courage."))
    {
        tmp = strlen(" recovers its courage.");
        strnfmt(who, 1 + len - tmp, "%s", msg);
        strnfmt(buf, 256, "STATE__BOLD:%^s", who);
        borg_react(msg, buf);
        return;
    }


    /* Feature XXX XXX XXX */
    if (streq(msg, "The door appears to be broken."))
    {
        /* Only process open doors */
        if (ag->feat == FEAT_OPEN)
        {
            /* Mark as broken */
            ag->feat = FEAT_BROKEN;
        }
        return;
    }

    /* Feature XXX XXX XXX */
    if (streq(msg, "The door appears to be stuck."))
    {
        /* Only process non-jammed doors */
        if ((ag->feat >= FEAT_DOOR_HEAD) && (ag->feat <= FEAT_DOOR_HEAD + 0x07))
        {
            /* Mark the door as jammed */
            ag->feat = FEAT_DOOR_HEAD + 0x08;

            /* Clear goals */
            goal = 0;
        }

        return;
    }


#if 0

    /* Feature XXX XXX XXX */
    if (streq(msg, "This seems to be permanent rock."))
    {
        /* Skip granite walls */
        if (ag->feat == FEAT_WALL_EXTRA) continue;

        /* Only process walls */
        if ((ag->feat >= FEAT_WALL_EXTRA) && (ag->feat <= FEAT_PERM_SOLID))
        {
            /* Mark the wall as permanent */
            ag->feat = FEAT_PERM_SOLID;

            /* Clear goals */
            goal = 0;
        }

        return;
    }

    /* Feature XXX XXX XXX */
    if (streq(msg, "You tunnel into the granite wall."))
    {
        /* Skip granite walls */
        if (ag->feat == FEAT_WALL_EXTRA) continue;

        /* Only process walls */
        if ((ag->feat >= FEAT_WALL_EXTRA) && (ag->feat <= FEAT_PERM_SOLID))
        {
            /* Mark the wall as granite */
            ag->feat = FEAT_WALL_EXTRA;

            /* Clear goals */
            goal = 0;
        }

        return;
    }

#endif

    /* Feature XXX XXX XXX */
    if (streq(msg, "You tunnel into the quartz vein."))
    {
        /* Process magma veins with treasure */
        if (ag->feat == FEAT_MAGMA_K)
        {
            /* Mark the vein */
            ag->feat = FEAT_QUARTZ_K;

            /* Clear goals */
            goal = 0;
        }

        /* Process magma veins */
        else if (ag->feat == FEAT_MAGMA)
        {
            /* Mark the vein */
            ag->feat = FEAT_QUARTZ;

            /* Clear goals */
            goal = 0;
        }

        return;
    }

    /* Feature XXX XXX XXX */
    if (streq(msg, "You tunnel into the magma vein."))
    {
        /* Process quartz veins with treasure */
        if (ag->feat == FEAT_QUARTZ_K)
        {
            /* Mark the vein */
            ag->feat = FEAT_MAGMA_K;

            /* Clear goals */
            goal = 0;
        }

        /* Process quartz veins */
        else if (ag->feat == FEAT_QUARTZ)
        {
            /* Mark the vein */
            ag->feat = FEAT_MAGMA;

            /* Clear goals */
            goal = 0;
        }

        return;
    }


    /* Word of Recall -- Ignition */
    if (prefix(msg, "The air about you becomes "))
    {
        /* Initiate recall */
        goal_recalling = TRUE;
        return;
    }

    /* Word of Recall -- Lift off */
    if (prefix(msg, "You feel yourself yanked "))
    {
        /* Recall complete */
        goal_recalling = FALSE;
        finished_level = FALSE;
        return;
    }

    /* Word of Recall -- Cancelled */
    if (prefix(msg, "A tension leaves "))
    {
        /* Hack -- Oops */
        goal_recalling = FALSE;
        return;
    }

    /* protect from evil */
    if (prefix(msg, "You feel safe from evil!"))
    {
        borg_prot_from_evil = TRUE;
        return;
    }
    if (prefix(msg, "You no longer feel safe from evil."))
    {
        borg_prot_from_evil = FALSE;
        return;
    }
    /* haste self */
    if (prefix(msg, "You feel yourself moving faster!"))
    {
        borg_speed = TRUE;
        return;
    }
    if (prefix(msg, "You feel yourself slow down."))
    {
        borg_speed = FALSE;
        return;
    }
    /* Bless */
    if (prefix(msg, "You feel righteous!"))
    {
        borg_bless = TRUE;
        return;
    }
    if (prefix(msg, "The prayer has expired."))
    {
        borg_bless = FALSE;
        return;
    }

    /* resist acid */
    if (prefix(msg, "You feel resistant to acid!"))
    {
        borg_temp_acid = TRUE;
        return;
    }
    if (prefix(msg, "You feel less resistant to acid."))
    {
        borg_temp_acid = FALSE;
        return;
    }
    /* resist electricity */
    if (prefix(msg, "You feel resistant to electricity!"))
    {
        borg_temp_elec = TRUE;
        return;
    }
    if (prefix(msg, "You feel less resistant to electricity."))
    {
        borg_temp_elec = FALSE;
        return;
    }
    /* resist fire */
    if (prefix(msg, "You feel resistant to fire!"))
    {
        borg_temp_fire = TRUE;
        return;
    }
    if (prefix(msg, "You feel less resistant to fire."))
    {
        borg_temp_fire = FALSE;
        return;
    }
    /* resist cold */
    if (prefix(msg, "You feel resistant to cold!"))
    {
        borg_temp_cold = TRUE;
        return;
    }
    if (prefix(msg, "You feel less resistant to cold."))
    {
        borg_temp_cold = FALSE;
        return;
    }
    /* resist poison */
    if (prefix(msg, "You feel resistant to poison!"))
    {
        borg_temp_poison = TRUE;
        return;
    }
    if (prefix(msg, "You feel less resistant to poison."))
    {
        borg_temp_poison = FALSE;
        return;
    }
    /* GOI! */
    if (prefix(msg, "You feel invulnerable!"))
    {
        borg_goi = 11; /* keep track of how long it has left (a guess) */
        return;
    }
    if (prefix(msg, "You feel vulnerable once more."))
    {
        borg_goi = 0;
        return;
    }
    /* Shield */
    if (prefix(msg, "A mystic shield forms around your body!"))
    {
        borg_shield = TRUE; 
        return;
    }
    if (prefix(msg, "Your mystic shield crumbles away."))
    {
        borg_shield = FALSE;
        return;
    }

    /* Feelings about the level */
    for (i = 0; prefix_feeling[i]; i++)
    {
        /* "You feel..." (etc) */
        if (prefix(msg, prefix_feeling[i]))
        {
            strnfmt(buf, 256, "FEELING:%d", i);
            borg_react(msg, buf);
            return;
        }
    }
}



/*
 * Parse a message, piece of a message, or set of messages.
 *
 * We must handle long messages which are "split" into multiple
 * pieces, and also multiple messages which may be "combined"
 * into a single set of messages.
 */
static void borg_parse(cptr msg)
{
    static char len = 0;
    static char buf[1024];


    /* Flush messages */
    if (len && (!msg || (msg[0] != ' ')))
    {
        int i, j;

        /* Split out punctuation */
        for (j = i = 0; i < len-1; i++)
        {
            /* Check for punctuation */
            if ((buf[i] == '.') ||
                (buf[i] == '!') ||
                (buf[i] == '?') ||
                (buf[i] == '"'))
            {
                /* Require space */
                if (buf[i+1] == ' ')
                {
                    /* Terminate */
                    buf[i+1] = '\0';

                    /* Parse fragment */
                    borg_parse_aux(buf + j, (i + 1) - j);

                    /* Restore */
                    buf[i+1] = ' ';

                    /* Advance past spaces */
                    for (j = i + 2; buf[j] == ' '; j++) /* loop */;
                }
            }
        }

        /* Parse tail */
        borg_parse_aux(buf + j, len - j);

        /* Forget */
        len = 0;
    }


    /* No message */
    if (!msg)
    {
        /* Start over */
        len = 0;
    }

    /* Continued message */
    else if (msg[0] == ' ')
    {
        /* Collect, verify, and grow */
        len += strnfmt(buf+len, 1024-len, "%s", msg+1);
    }

    /* New message */
    else
    {
        /* Collect, verify, and grow */
        len = strnfmt(buf, 1024, "%s", msg);
    }
}




/*
 * XXX XXX XXX Mega-Hack -- keypress stealer from "z-term.c"
 */
extern errr (*Term_inkey_hook)(char *ch, bool wait, bool take);


/*
 * This function lets the Borg "steal" control from the user.
 *
 * The "z-term.c" file provides a special hook which we use to
 * bypass the standard "Term_flush()" and "Term_inkey()" functions
 * and replace them with the function below.
 *
 * The only way that the Borg can be stopped once it is started,
 * unless it dies or encounters an error, is to press any key.
 * This function checks for user input on a regular basic, and
 * when any is encountered, it relinquishes control gracefully.
 *
 * We handle "broken" messages, in which long messages are "broken"
 * into pieces, and all but the first message are "indented" by one
 * space, by collecting all the pieces into a complete message and
 * then parsing the message once it is known to be complete.
 *
 * Note the complete hack that allows the Borg to run in "demo"
 * mode, which allows the Borg to cheat death 100 times, and stamps
 * the number of cheats in the player "age" field.  XXX XXX XXX
 *
 * Note that this function hook automatically removes itself when
 * it realizes that it should no longer be active.  Note that this
 * may take place after the game has asked for the next keypress,
 * but the various "keypress" routines should be able to handle this.
 *
 * XXX XXX XXX We do not correctly handle the "take" flag
 */
static errr Term_inkey_borg(char *ch, bool wait, bool take)
{
    int i, x, y;

    int visible;

    byte t_a;

    char buf[128];


    /* XXX XXX XXX */
    if (!auto_active)
    {
        /* Message */
        borg_note("# Removing keypress hook");

        /* Remove hook */
        Term_inkey_hook = NULL;

        /* Flush keys */
        borg_flush();

        /* Clear if needed */
        if (ch) (*ch) = '\0';

        /* Nothing ready */
        return (1);
    }


    /* Hack -- flush keys */
    if (!ch)
    {
        /* Flush keys */
        borg_flush();

        /* Success */
        return (0);
    }


    /* Clear the key */
    (*ch) = '\0';


    /* Always wait for keys */
    if (!wait) return (1);


    /* Check the "cursor state" XXX XXX XXX */
    /* Note that the cursor visibility determines whether the */
    /* game is asking us for a "command" or for some other key. */
    /* This requires that "hilite_player" be FALSE. */

    /* Hack -- Extract the cursor visibility */
    (void)Term_get_cursor(&visible);


    /* XXX XXX XXX Mega-Hack -- Catch "Die? [y/n]" messages */

    /* Hack -- cheat death */
    if (visible &&
        (0 == Term_locate(&x, &y)) && (y == 0) && (x >= 4) &&
        (0 == borg_what_text(0, 0, 4, &t_a, buf)) &&
        (prefix(buf, "Die?")))
    {
        /* Take note */
        borg_note("# Cheating death...");

if (borg_cheat_death)
        /* Cheat death */
        (*ch) = 'n';
else
    /* This will allow the user to decide what to do next. */
    /* if it is used in combination with auto_save you can go back to */
    /* before the borg died and replay the dieing moves! */
    borg_oops("death"); 


        /* Success */
        return (0);
    }


    /* XXX XXX XXX Mega-Hack -- Catch "-more-" messages */

    /* If the cursor is visible... */
    /* And the cursor is on the top line... */
    /* And there is text before the cursor... */
    /* And that text is "-more-" */
    if (visible &&
        (0 == Term_locate(&x, &y)) && (y == 0) && (x >= 7) &&
        (0 == borg_what_text(x-7, y, 7, &t_a, buf)) &&
        (streq(buf, " -more-")))
    {
        /* Get the message */
        if (0 == borg_what_text(0, 0, x-7, &t_a, buf))
        {
            /* Parse it */
            borg_parse(buf);
        }

        /* Hack -- not active */
        if (!auto_active) return (1);

        /* Clear the message */
        (*ch) = ' ';

        /* Done */
        return (0);
    }


    /* XXX XXX XXX Mega-Hack -- catch normal messages */

    /* If the cursor is NOT visible... */
    /* And there is text on the first line... */
    if (!visible &&
        (0 == borg_what_text(0, 0, 3, &t_a, buf)) &&
        (t_a == TERM_WHITE) && buf[0] &&
        ((buf[0] != ' ') || (buf[1] != ' ') || (buf[2] != ' ')))
    {
        /* Get the message */
        if (0 == borg_what_text(0, 0, -80, &t_a, buf))
        {
            int k = strlen(buf);

            /* Strip trailing spaces */
            while ((k > 0) && (buf[k-1] == ' ')) k--;

            /* Terminate */
            buf[k] = '\0';

            /* Parse it */
            borg_parse(buf);
        }

        /* Hack -- not active */
        if (!auto_active) return (1);

        /* Clear the message */
        (*ch) = ' ';

        /* Done */
        return (0);
    }


    /* Flush messages */
    borg_parse(NULL);


    /* Check for key */
    i = borg_inkey(FALSE);

    /* Need more keys */
    if (!i)
    {
        /* Hack -- Process events (do not wait) */
        (void)Term_xtra(TERM_XTRA_EVENT, FALSE);

        /* Hack -- User Abort XXX XXX XXX */
        if (Term->key_head != Term->key_tail)
        {
            /* Take note */
            borg_note("# Preparing to abort");

            /* Cancel later */
            auto_cancel = TRUE;

            /* Hack -- Forget all keypresses */
            Term->key_head = Term->key_tail = 0;

            /* Hack -- Flush all events */
            (void)Term_xtra(TERM_XTRA_FLUSH, 0);
        }

        /* XXX XXX XXX */
        if (death)
        {
            /* Oops */
            borg_oops("unexpected death!");

            /* Return */
            return (1);
        }

        /* Save the system random info */
        auto_rand_quick = Rand_quick;
        auto_rand_value = Rand_value;

        /* Use the local random info */
        Rand_quick = TRUE;
        Rand_value = auto_rand_local;

        /* Update and Think */
        while (!borg_think()) /* loop */;

        /* Save the local random info */
        auto_rand_local = Rand_value;

        /* Restore the system random info */
        Rand_quick = auto_rand_quick;
        Rand_value = auto_rand_value;

        /* Hack -- allow stepping to induce a clean cancel */
        if (auto_step && (!--auto_step)) auto_cancel = TRUE;
    }

    /* Check for key */
    i = borg_inkey(take);

    /* Use it */
    if (!i)
    {
        /* Oops */
        borg_oops("user abort");

        /* Hack -- Escape! */
        i = ESCAPE;
    }

    /* Enqueue the keypress */
    (*ch) = i;

    /* Success */
    return (0);
}



/*
 * Initialize the Borg
 */
void borg_init_9(void)
{
    int i;

    byte t_a;

    char buf[80];

    byte *test;


    /*** Hack -- verify system ***/

    /* Message */
    prt("Initializing the Borg... (memory)", 0, 0);

    /* Hack -- flush it */
    Term_fresh();

    /* Mega-Hack -- verify memory */
    C_MAKE(test, 400 * 1024L, byte);
    C_KILL(test, 400 * 1024L, byte);


    /*** Hack -- initialize game options ***/

    /* Message */
    prt("Initializing the Borg... (options)", 0, 0);

    /* Hack -- flush it */
    Term_fresh();

    /* We use the original keypress codes */
    rogue_like_commands = FALSE;

    /* We pick up items when we step on them */
    always_pickup = TRUE;

    /* We specify targets by hand */
    use_old_target = FALSE;

    /* We do NOT query any commands */
    carry_query_flag = FALSE;
    other_query_flag = FALSE;

    /* We repeat by hand */
    always_repeat = FALSE;

    /* We do not haggle */
    auto_haggle = TRUE;

    /* do not start out auto-scumming. */
    auto_scum = FALSE;

    /* We need space */
    show_labels = FALSE;
    show_weights = FALSE;

    /* We need color */
    use_color = TRUE;

    /* We need the dungeon level */
    depth_in_feet = FALSE;

    /* Allow items to stack */
    stack_allow_items = TRUE;

    /* Allow wands to stack */
    stack_allow_wands = TRUE;

    /* Ignore discounts */
    stack_force_costs = TRUE;

    /* Ignore inscriptions */
    stack_force_notes = TRUE;

    /* Efficiency */
    avoid_abort = TRUE;

    /* Efficiency */
    hitpoint_warn = 0;

    /* Hack -- notice "command" mode */
    hilite_player = FALSE;

    /* Hack -- reset visuals */
    reset_visuals();

    /* Hack -- Redraw */
    do_cmd_redraw();


    /*** Various ***/

    /* Message */
    prt("Initializing the Borg... (various)", 0, 0);

    /* Hack -- flush it */
    Term_fresh();


    /*** Cheat / Panic ***/

    /* Mega-Hack -- Cheat a lot */
    auto_cheat_inven = TRUE;
    auto_cheat_equip = TRUE;

    /* Mega-Hack -- Cheat a lot */
    auto_cheat_spell = TRUE;

    /* Mega-Hack -- Cheat a lot */
    auto_cheat_panel = TRUE;

    /* more cheating */
    borg_cheat_death = FALSE;

    /*** Initialize ***/

    /* Initialize */
    borg_init_1();
    borg_init_2();
    borg_init_3();
    borg_init_4();
    borg_init_5();
    borg_init_6();
    borg_init_7();
    borg_init_8();


    /*** Hack -- Extract race ***/

    /* Check for textual race */
    if (0 == borg_what_text(COL_RACE, ROW_RACE, -12, &t_a, buf))
    {
        /* Scan the races */
        for (i = 0; i < 10; i++)
        {
            /* Check the race */
            if (prefix(buf, race_info[i].title))
            {
                /* We got one */
                auto_race = i;
                break;
            }
        }
    }

    /* Extract the race pointer */
    rb_ptr = &race_info[auto_race];


    /*** Hack -- Extract class ***/

    /* Check for textual class */
    if (0 == borg_what_text(COL_CLASS, ROW_CLASS, -12, &t_a, buf))
    {
        /* Scan the classes */
        for (i = 0; i < 6; i++)
        {
            /* Check the race */
            if (prefix(buf, class_info[i].title))
            {
                /* We got one */
                auto_class = i;
                break;
            }
        }
    }

    /* Extract the class pointer */
    cb_ptr = &class_info[auto_class];

    /* Extract the magic pointer */
    mb_ptr = &magic_info[auto_class];


    /*** Hack -- react to race and class ***/

    /* Notice the new race and class */
    prepare_race_class_info();


    /*** All done ***/

    /* Done initialization */
    prt("Initializing the Borg... done.", 0, 0);

    /* Clear line */
    prt("", 0, 0);

    /* Official message */
    borg_note("# Ready...");

    /* Now it is ready */
    initialized = TRUE;
}


/*
 * Hack -- forward declare
 */
void do_cmd_borg(void);


/*
 * Hack -- interact with the "Ben Borg".
 */
void do_cmd_borg(void)
{
    char cmd;


    /* Get a "Borg command", or abort */
    if (!get_com("Borg command: ", &cmd)) return;


    /* Simple help */
    if (cmd == '?')
    {
        int i = 2;

        /* Save the screen */
        Term_save();

        /* Clear the screen */
        Term_clear();

        /* Dump commands */
        Term_putstr(5, i++, -1, TERM_WHITE, "Command '?' displays this screen.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command '$' initializes the Borg.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'z' activates the Borg.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'u' updates the Borg.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'x' steps the Borg.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'f' modifies the normal flags.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'c' modifies the cheat flags.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'l' activates a log file.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 's' activates search mode.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'i' displays grid info.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'g' displays grid feature.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'a' displays avoidances.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'k' displays monster info.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 't' displays object info.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command '%' displays current flow.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command '#' displays danger grid.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command '_' Depth info.");
        Term_putstr(5, i++, -1, TERM_WHITE, "Command 'p' Borg Power.");

        /* Prompt for key */
        msg_print("Available commands: ?,$,z,u,x,f,c,w,l,s,i,a,k,t,%,#,_,p.");
        msg_print(NULL);

        /* Restore the screen */
        Term_load();

        /* Done */
        return;
    }


    /* Hack -- force initialization */
    if (!initialized) borg_init_9();

    switch (cmd)
    {
        /* Command: Nothing */
        case '$':
        {
            break;
        }
        /* Command: Activate */
        case 'z':
        case 'Z':
        {
            /* Activate */
            auto_active = TRUE;

            /* Reset cancel */
            auto_cancel = FALSE;

            /* Step forever */
            auto_step = 0;

            /* need to check all stats */
            my_need_stat_check[0] = TRUE;
            my_need_stat_check[1] = TRUE;
            my_need_stat_check[2] = TRUE;
            my_need_stat_check[3] = TRUE;
            my_need_stat_check[4] = TRUE;
            my_need_stat_check[5] = TRUE;

            /* Allowable Cheat -- Obtain "recall" flag */
            goal_recalling = (p_ptr->word_recall ? TRUE : FALSE);

            /* Allowable Cheat -- Obtain "prot_from_evil" flag */ 
            borg_prot_from_evil = (p_ptr->protevil ? TRUE : FALSE);
            /* Allowable Cheat -- Obtain "speed" flag */
            borg_speed = (p_ptr->fast ? TRUE : FALSE);
            /* Allowable Cheat -- Obtain "goi" flag */
            borg_goi = (p_ptr->invuln ? 9 : 0);
            /* Allowable Cheat -- Obtain "resist" flags */
            borg_temp_acid = (p_ptr->oppose_acid ? TRUE : FALSE);
            borg_temp_elec = (p_ptr->oppose_elec ? TRUE : FALSE);
            borg_temp_fire = (p_ptr->oppose_fire ? TRUE : FALSE);
            borg_temp_cold = (p_ptr->oppose_cold ? TRUE : FALSE);
            borg_temp_poison = (p_ptr->oppose_pois ? TRUE : FALSE);
            borg_bless = (p_ptr->blessed ? TRUE : FALSE);
            borg_shield = (p_ptr->shield ? TRUE : FALSE);
#if 0
            /*!FIX AJG not coded yet */.
            borg_hero = (p_ptr->hero ? TRUE : FALSE);
            if (!borg_hero)
                borg_hero = (p_ptr->shero ? TRUE : FALSE);
#endif
            /* Message */
            borg_note("# Installing keypress hook");

            /* Activate the key stealer */
            Term_inkey_hook = Term_inkey_borg;

            break;
        }

        /* Command: Update */
        case 'u':
        case 'U':
        {
            /* Activate */
            auto_active = TRUE;

            /* Immediate cancel */
            auto_cancel = TRUE;

            /* Step forever */
            auto_step = 0;

            /* Allowable Cheat -- Obtain "recall" flag */
            goal_recalling = (p_ptr->word_recall ? TRUE : FALSE);

            /* Allowable Cheat -- Obtain "prot_from_evil" flag */
            borg_prot_from_evil = (p_ptr->protevil ? TRUE : FALSE);
            /* Allowable Cheat -- Obtain "speed" flag */
            borg_speed = (p_ptr->fast ? TRUE : FALSE);
            /* Allowable Cheat -- Obtain "goi" flag */
            borg_goi = (p_ptr->invuln ? 9 : 0);
            /* Allowable Cheat -- Obtain "resist" flags */
            borg_temp_acid = (p_ptr->oppose_acid ? TRUE : FALSE);
            borg_temp_elec = (p_ptr->oppose_elec ? TRUE : FALSE);
            borg_temp_fire = (p_ptr->oppose_fire ? TRUE : FALSE);
            borg_temp_cold = (p_ptr->oppose_cold ? TRUE : FALSE);
            borg_temp_poison = (p_ptr->oppose_pois ? TRUE : FALSE);
            borg_bless = (p_ptr->blessed ? TRUE : FALSE);
            borg_shield = (p_ptr->shield ? TRUE : FALSE);
#if 0
            /*!FIX AJG not coded yet */.
            borg_hero = (p_ptr->hero ? TRUE : FALSE);
            if (!borg_hero)
                borg_hero = (p_ptr->shero ? TRUE : FALSE);
#endif

            /* Message */
            borg_note("# Installing keypress hook");

            /* Activate the key stealer */
            Term_inkey_hook = Term_inkey_borg;

            break;
        }


        /* Command: Step */
        case 'x':
        case 'X':
        {
            /* Activate */
            auto_active = TRUE;

            /* Reset cancel */
            auto_cancel = FALSE;

            /* Step for one (or more) turns */
            auto_step = (command_arg > 0) ? command_arg : 1;

            /* need to check all stats */
            my_need_stat_check[0] = TRUE;
            my_need_stat_check[1] = TRUE;
            my_need_stat_check[2] = TRUE;
            my_need_stat_check[3] = TRUE;
            my_need_stat_check[4] = TRUE;
            my_need_stat_check[5] = TRUE;

            /* Allowable Cheat -- Obtain "recall" flag */
            goal_recalling = (p_ptr->word_recall ? TRUE : FALSE);
            /* Allowable Cheat -- Obtain "prot_from_evil" flag */
            borg_prot_from_evil = (p_ptr->protevil ? TRUE : FALSE);
            /* Allowable Cheat -- Obtain "speed" flag */
            borg_speed = (p_ptr->fast ? TRUE : FALSE);
            /* Allowable Cheat -- Obtain "goi" flag */
            borg_goi = (p_ptr->invuln ? 9 : 0);
            /* Allowable Cheat -- Obtain "resist" flags */
            borg_temp_acid = (p_ptr->oppose_acid ? TRUE : FALSE);
            borg_temp_elec = (p_ptr->oppose_elec ? TRUE : FALSE);
            borg_temp_fire = (p_ptr->oppose_fire ? TRUE : FALSE);
            borg_temp_cold = (p_ptr->oppose_cold ? TRUE : FALSE);
            borg_temp_poison = (p_ptr->oppose_pois ? TRUE : FALSE);
            borg_bless = (p_ptr->blessed ? TRUE : FALSE);
            borg_shield = (p_ptr->shield ? TRUE : FALSE);
#if 0
            /*!FIX AJG not coded yet */.
            borg_hero = (p_ptr->hero ? TRUE : FALSE);
            if (!borg_hero)
                borg_hero = (p_ptr->shero ? TRUE : FALSE);
#endif

            /* Message */
            borg_note("# Installing keypress hook");

            /* Activate the key stealer */
            Term_inkey_hook = Term_inkey_borg;

            break;
        }

        /* Command: toggle "flags" */
        case 'f':
        case 'F':
        {
            /* Get a "Borg command", or abort */
            if (!get_com("Borg command: Toggle Flag: (d/s/f) ", &cmd)) return;

            switch (cmd)
            {
                /* Dump savefile at each death */
                case 'd':
                case 'D':
                {
                    auto_flag_dump = !auto_flag_dump;
                    msg_format("Borg -- auto_flag_dump is now %d.", 
                                auto_flag_dump);
                    break;
                }

                /* Dump savefile at each level */
                case 's':
                case 'S':
                {
                    auto_flag_save = !auto_flag_save;
                    msg_format("Borg -- auto_flag_save is now %d.", 
                                auto_flag_save);
                    break;
                }

                /* clear 'fear' levels */
                case 'f':
                case 'F':
                {
                    msg_format("Command No Longer Usefull");
                    break;
                }
            }
            break;
        }



        /* Command: toggle "cheat" flags */
        case 'c':
        case 'C':
        {
            /* Get a "Borg command", or abort */
            if (!get_com("Borg command: Toggle Cheat: (d/i/e/s/p)", &cmd)) 
                return;

            switch (cmd)
            {
                case 'd':
                case 'D':
                {
                    borg_cheat_death = !borg_cheat_death;
                    msg_format("Borg -- auto_cheat_death is now %d.", 
                                borg_cheat_death);
                    break;
                }
                case 'i':
                case 'I':
                {
                    auto_cheat_inven = !auto_cheat_inven;
                    msg_format("Borg -- auto_cheat_inven is now %d.", 
                                auto_cheat_inven);
                    break;
                }
                case 'e':
                case 'E':
                {
                    auto_cheat_equip = !auto_cheat_equip;
                    msg_format("Borg -- auto_cheat_equip is now %d.", 
                                auto_cheat_equip);
                    break;
                }
                case 's':
                case 'S':
                {
                    auto_cheat_spell = !auto_cheat_spell;
                    msg_format("Borg -- auto_cheat_spell is now %d.", 
                                auto_cheat_spell);
                    break;
                }
                case 'p':
                case 'P':
                {
                    auto_cheat_panel = !auto_cheat_panel;
                    msg_format("Borg -- auto_cheat_panel is now %d.", 
                                auto_cheat_panel);
                    break;
                }
            }
            break;

        }


        /* Start a new log file */
        case 'l':
        case 'L':
        {
            char buf[80];

            /* Close the log file */
            if (auto_fff) my_fclose(auto_fff);

            /* Hack -- drop permissions */
            safe_setuid_drop();

            /* Default  */
            strcpy(buf, "borg.log");

            /* XXX XXX XXX Get the name and open the log file */
            if (get_string("Borg Log File: ", buf, 70))
            {
                /* Open a new file */
                auto_fff = my_fopen(buf, "w");

                /* Failure */
                if (!auto_fff) msg_print("Cannot open that file.");
            }

            /* Hack -- grab permissions */
            safe_setuid_grab();
        }


        /* Activate a search string */
        case 's':
        case 'S':
        {
            /* Get the new search string (or cancel the matching) */
            if (!get_string("Borg Match String: ", auto_match, 70))
            {
                /* Cancel it */
                strcpy(auto_match, "");

                /* Message */
                msg_print("Borg Match String de-activated.");
            }
            break;
        }


        /* Command: check Grid "feature" flags */
        case 'g':
        case 'G':
        {
            int x, y;

            u16b low, high;

            /* Get a "Borg command", or abort */
            if (!get_com("Borg command: Show grids: ", &cmd)) return;

            /* Extract a flag */
            switch (cmd)
            {
                case '0': low = high = 1 << 0; break;
                case '1': low = high = 1 << 1; break;
                case '2': low = high = 1 << 2; break;
                case '3': low = high = 1 << 3; break;
                case '4': low = high = 1 << 4; break;
                case '5': low = high = 1 << 5; break;
                case '6': low = high = 1 << 6; break;
                case '7': low = high = 1 << 7; break;

                case '.': low = high = FEAT_FLOOR; break;
                case ' ': low = high = FEAT_NONE; break;
                case 'i': low = high = FEAT_INVIS; break;
                case ';': low = high = FEAT_GLYPH; break;
                case ',': low = high = FEAT_OPEN; break;
                case 'x': low = high = FEAT_BROKEN; break;
                case '>': low = high = FEAT_LESS; break;
                case '<': low = high = FEAT_MORE; break;
                case '@': low = FEAT_SHOP_HEAD; 
                          high = FEAT_SHOP_TAIL;
                           break;
                case '^': low = FEAT_TRAP_HEAD; 
                          high = FEAT_TRAP_TAIL; 
                          break;
                case '+': low  = FEAT_DOOR_HEAD; break;
                          high = FEAT_DOOR_TAIL; break;
                case 's': low = high = FEAT_SECRET; break;
                case ':': low = high = FEAT_RUBBLE; break;
                case 'm': low = high = FEAT_MAGMA; break;
                case 'q': low = high = FEAT_QUARTZ; break;
                case 'r': low = high = FEAT_QUARTZ_H; break;
                case 'k': low = high = FEAT_MAGMA_K; break;
                case '&': low = high = FEAT_QUARTZ_K; break;
                case 'w': low = FEAT_WALL_EXTRA; 
                          high = FEAT_WALL_SOLID; 
                          break;
                case 'p': low = FEAT_PERM_EXTRA; 
                          high = FEAT_PERM_SOLID; 
                          break;

                default: low = high = 0x00; break;
            }

            /* Scan map */
            for (y = w_y; y < w_y + SCREEN_HGT; y++)
            {
                for (x = w_x; x < w_x + SCREEN_WID; x++)
                {
                    byte a = TERM_RED;

                    auto_grid *ag = &auto_grids[y][x];

                    /* show only those grids */
                    if (!(ag->feat >= low && ag->feat <= high)) continue;

                    /* Color */
                    if (borg_cave_floor_bold(y, x)) a = TERM_YELLOW;

                    /* Display */
                    print_rel('*', a, y, x);
                }
            }

            /* Get keypress */
            msg_print("Press any key.");
            msg_print(NULL);

            /* Redraw map */
            prt_map();
            break;
        }

        /* Command: check "info" flags */
        case 'i':
        case 'I':
        {
            int x, y;

            u16b mask;

            /* Get a "Borg command", or abort */
            if (!get_com("Borg command: Show grids: ", &cmd)) return;

            /* Extract a flag */
            switch (cmd)
            {
                case '0': mask = 1 << 0; break;
                case '1': mask = 1 << 1; break;
                case '2': mask = 1 << 2; break;
                case '3': mask = 1 << 3; break;
                case '4': mask = 1 << 4; break;
                case '5': mask = 1 << 5; break;
                case '6': mask = 1 << 6; break;
                case '7': mask = 1 << 7; break;

                case 'm': mask = BORG_MARK; break;
                case 'g': mask = BORG_GLOW; break;
                case 'd': mask = BORG_DARK; break;
                case 'o': mask = BORG_OKAY; break;
                case 'l': mask = BORG_LITE; break;
                case 'v': mask = BORG_VIEW; break;
                case 't': mask = BORG_TEMP; break;
                case 'x': mask = BORG_XTRA; break;

                default: mask = 0x00; break;
            }

            /* Scan map */
            for (y = w_y; y < w_y + SCREEN_HGT; y++)
            {
                for (x = w_x; x < w_x + SCREEN_WID; x++)
                {
                    byte a = TERM_RED;

                    auto_grid *ag = &auto_grids[y][x];

                    /* Given mask, show only those grids */
                    if (mask && !(ag->info & mask)) continue;

                    /* Given no mask, show unknown grids */
                    if (!mask && (ag->info & BORG_MARK)) continue;
                    
                    /* Color */
                    if (borg_cave_floor_bold(y, x)) a = TERM_YELLOW;

                    /* Display */
                    print_rel('*', a, y, x);
                }
            }

            /* Get keypress */
            msg_print("Press any key.");
            msg_print(NULL);

            /* Redraw map */
            prt_map();
            break;
        }

    /* Command: check "avoidances" */
        case 'a':
        case 'A':
        {
            int x, y, p;

            /* Scan map */
            for (y = w_y; y < w_y + SCREEN_HGT; y++)
            {
                for (x = w_x; x < w_x + SCREEN_WID; x++)
                {
                    byte a = TERM_RED;

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

                    /* Skip non-avoidances */
                    if (p <= avoidance / 2) continue;

                    /* Use yellow for less painful */
                    if (p <= avoidance) a = TERM_YELLOW;

                    /* Display */
                    print_rel('*', a, y, x);
                }
            }

            /* Get keypress */
            msg_format("Avoidance value %d.", avoidance);
            msg_print(NULL);

            /* Redraw map */
            prt_map();
            break;
        }


        /* Command: show "monsters" */
        case 'k':
        case 'K':
        {
            int i, n = 0;

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

                /* Still alive */
                if (kill->r_idx)
                {
                    int x = kill->x;
                    int y = kill->y;

                    /* Display */
                    print_rel('*', TERM_RED, y, x);

                    /* Count */
                    n++;
                }
            }

            /* Get keypress */
            msg_format("There are %d known monsters.", n);
            msg_print(NULL);

            /* Redraw map */
            prt_map();
            break;
        }


        /* Command: show "objects" */
        case 't':
        case 'T':
        {
            int i, n = 0;

            /* Scan the objects */
            for (i = 1; i < auto_takes_nxt; i++)
            {
                auto_take *take = &auto_takes[i];

                /* Still alive */
                if (take->k_idx)
                {
                    int x = take->x;
                    int y = take->y;

                    /* Display */
                    print_rel('*', TERM_RED, y, x);

                    /* Count */
                    n++;
                }
            }

            /* Get keypress */
            msg_format("There are %d known objects.", n);
            msg_print(NULL);

            /* Redraw map */
            prt_map();
            break;
        }


        /* Command: debug -- current flow */
        case '%':
        {
            int i, x, y;

            /* Flow */
            for (i = 0; i < 250; i++)
            {
                int n = 0;

                /* Scan map */
                for (y = w_y; y < w_y + SCREEN_HGT; y++)
                {
                    for (x = w_x; x < w_x + SCREEN_WID; x++)
                    {
                        byte a = TERM_RED;

                        /* Verify flow cost */
                        if (auto_data_flow->data[y][x] != i) continue;

                        /* Display */
                        print_rel('*', a, y, x);

                        /* Count */
                        n++;
                    }
                }

                /* Nothing */
                if (!n) break;

                /* Get keypress */
                msg_format("Flow depth %d.", i);
                msg_print(NULL);

                /* Redraw map */
                prt_map();
            }
            break;
        }

        /* Command: debug -- danger of grid */
        case '#':
        {
            int n;

            /* Turns */
            n = (command_arg ? command_arg : 1);

            /* Danger of grid */
            msg_format("Danger(%d,%d,%d) is %d",
                        target_col, target_row, n,
                        borg_danger(target_row, target_col, n));
            break;
        }

        /* Command: debug -- fear of depth */
        case '_':
        {
            /* Max depth */
            msg_format("Max depth %d, ", auto_max_depth);

            /* Fear depth */
            msg_format("Fear depth %d, ", fear_depth);

            /* Dump fear codes */
            msg_format("times completed fear depth %d", auto_fear_depth);
            break;
        }

        /* Command: debug -- Power */
        case 'p':
        case 'P':
        {
            s32b p;

            /* Examine the screen */
            borg_update_frame();

            /* Examine the screen */
            borg_update();

            /* Cheat the "equip" screen */
            borg_cheat_equip();

            /* Cheat the "inven" screen */
            borg_cheat_inven();

            /* Extract some "hidden" variables */
            borg_hidden();

            /* Examine the inventory */
            borg_notice();

            /* Evaluate */
            p = borg_power();

            /* Max depth */
            msg_format("Current Borg Power %ld", p);

            break;
        }

        /* Command: Show time */
        case '!':
        {
            s32b time = c_t - auto_began;
            msg_format("time: (%d) ", time);
            time = (auto_time_town + (c_t - auto_began));
            msg_format("time from town (%d)", time);
            break;
        }
        
        /* Command: my Stats */
        case '@':
            msg_format("str (m%d,c%d)", my_stat_max[0], my_stat_cur[0]);
            msg_format("int (m%d,c%d)", my_stat_max[1], my_stat_cur[1]);
            msg_format("wis (m%d,c%d)", my_stat_max[2], my_stat_cur[2]);
            msg_format("dex (m%d,c%d)", my_stat_max[3], my_stat_cur[3]);
            msg_format("con (m%d,c%d)", my_stat_max[4], my_stat_cur[4]);
            msg_format("cha (m%d,c%d)", my_stat_max[5], my_stat_cur[5]);
            break;

        /* Oops */
        default:
        {
            /* Message */
            msg_print("That is not a legal Borg command.");
            break;
        }
    }
}



#else

#ifdef MACINTOSH
static int HACK = 0;
#endif

#endif
