/* File: borg1.c */

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

#include "angband.h"


#ifdef ALLOW_BORG

#include "borg1.h"


/*
 * This file contains various low level variables and routines.
 */




/*
 * Some variables
 */

bool auto_active;       /* Actually active */

bool auto_cancel;       /* Being cancelled */


/* 
 * Hack -- optional cheating flags
 */

bool auto_cheat_equip;  /* Cheat for "equip mode" */

bool auto_cheat_inven;  /* Cheat for "inven mode" */

bool auto_cheat_spell;  /* Cheat for "browse mode" */

bool auto_cheat_panel;  /* Cheat for "panel mode" */


/*
 * Various silly flags
 */

bool auto_flag_save = FALSE;    /* Save savefile at each level */
bool auto_flag_dump = FALSE;    /* Save savefile at each death */
bool borg_save;                 /* do a save next level */


/*
 * Use a simple internal random number generator
 */

bool auto_rand_quick;       /* Save system setting */

u32b auto_rand_value;       /* Save system setting */

u32b auto_rand_local;       /* Save personal setting */


bool auto_do_star_id;


/*
 * Hack -- Time variables
 */

s16b c_t = 0L;          /* Current "time" */

/*
 * Hack -- Other time variables
 */

s16b when_call_lite;        /* When we last did call light */
s16b when_wizard_lite;      /* When we last did wizard light */

s16b when_detect_traps;     /* When we last detected traps */
s16b when_detect_doors;     /* When we last detected doors */
s16b when_detect_walls;     /* When we last detected walls */



/*
 * Some information
 */

s16b goal;          /* Goal type */

bool goal_rising;       /* Currently returning to town */

bool goal_leaving;      /* Currently leaving the level */

bool goal_fleeing;      /* Currently fleeing the level */

bool goal_ignoring;     /* Currently ignoring monsters */

bool goal_recalling;        /* Currently waiting for recall */

s16b borg_times_twitch; /* how often twitchy on this level */

bool stair_less;        /* Use the next "up" staircase */
bool stair_more;        /* Use the next "down" staircase */

s32b auto_began;        /* When this level began */
s32b auto_time_town;    /* how long it has been since I was in town */

s16b avoidance = 0;     /* Current danger thresh-hold */

bool auto_failure;      /* Notice failure */

bool auto_simulate;     /* Simulation flag */
bool borg_attacking;        /* Simulation flag */

bool auto_completed;        /* Completed the level */


/* defence flags */
bool borg_prot_from_evil;
bool borg_speed;
bool borg_bless;
bool borg_temp_fire;
bool borg_temp_cold;
bool borg_temp_acid;
bool borg_temp_poison;
bool borg_temp_elec;
s16b borg_goi;
bool borg_shield;

/*
 * Current shopping information
 */

s16b goal_shop = -1;        /* Next shop to visit */
s16b goal_ware = -1;        /* Next item to buy there */
s16b goal_item = -1;        /* Next item to sell there */



/*
 * Location variables
 */

int w_x;            /* Current panel offset (X) */
int w_y;            /* Current panel offset (Y) */

int c_x;            /* Current location (X) */
int c_y;            /* Current location (Y) */

int g_x;            /* Goal location (X) */
int g_y;            /* Goal location (Y) */

/* BIG HACK! Assume only 10 cursed artifacts */
int bad_obj_x[10];  /* Dropped cursed artifact at location (X) */
int bad_obj_y[10];  /* Dropped cursed artifact at location (Y) */


/*
 * State variables extracted from the screen
 */

bool do_weak;       /* Currently Weak */
bool do_hungry;     /* Currently Hungry/Weak */

bool do_full;       /* Currently Full/Gorged */
bool do_gorged;     /* Currently Gorged */

bool do_blind;      /* Currently Blind */
bool do_afraid;     /* Currently Afraid */
bool do_confused;   /* Currently Confused */
bool do_poisoned;   /* Currently Poisoned */

bool do_cut;        /* Currently bleeding */
bool do_stun;       /* Currently stunned */
bool do_heavy_stun; /* Currently very stunned */

bool do_image;      /* May be hallucinating */
bool do_study;      /* May learn spells */

bool do_fix_lev;    /* Drained LEV */
bool do_fix_exp;    /* Drained EXP */

bool do_fix_stat[6];    /* Drained Stats */


/*
 * Some estimated state variables
 */

s16b my_stat_max[6];    /* Current "maximal" stat values */
s16b my_stat_cur[6];    /* Current "natural" stat values */
s16b my_stat_use[6];    /* Current "resulting" stat values */
s16b my_stat_ind[6];    /* Current "additions" to stat values */
bool my_need_stat_check[6];  /* do I need to check my stats? */

s16b my_stat_add[6];  /* additions to stats  This will allow upgrading of */
                      /* equiptment to allow a ring of int +4 to be traded */
                      /* for a ring of int +6 even if maximized to allow a */
                      /* later swap to be better. */

s16b home_stat_add[6];

s16b my_ac;     /* Base armor */
s16b my_to_ac;      /* Plusses to ac */
s16b my_to_hit;     /* Plusses to hit */
s16b my_to_dam;     /* Plusses to dam */

byte my_immune_acid;    /* Immunity to acid */
byte my_immune_elec;    /* Immunity to lightning */
byte my_immune_fire;    /* Immunity to fire */
byte my_immune_cold;    /* Immunity to cold */

byte my_resist_acid;    /* Resist acid */
byte my_resist_elec;    /* Resist lightning */
byte my_resist_fire;    /* Resist fire */
byte my_resist_cold;    /* Resist cold */
byte my_resist_pois;    /* Resist poison */

byte my_resist_conf;    /* Resist confusion */
byte my_resist_sound;   /* Resist sound */
byte my_resist_lite;    /* Resist light */
byte my_resist_dark;    /* Resist darkness */
byte my_resist_chaos;   /* Resist chaos */
byte my_resist_disen;   /* Resist disenchant */
byte my_resist_shard;   /* Resist shards */
byte my_resist_nexus;   /* Resist nexus */
byte my_resist_blind;   /* Resist blindness */
byte my_resist_neth;    /* Resist nether */
byte my_resist_fear;    /* Resist fear */

byte my_sustain_str;    /* Keep strength */
byte my_sustain_int;    /* Keep intelligence */
byte my_sustain_wis;    /* Keep wisdom */
byte my_sustain_dex;    /* Keep dexterity */
byte my_sustain_con;    /* Keep constitution */
byte my_sustain_chr;    /* Keep charisma */

byte my_aggravate;  /* Aggravate monsters */
byte my_teleport;   /* Random teleporting */

byte my_ffall;      /* No damage falling */
byte my_lite;       /* Permanent light */
byte my_free_act;   /* Never paralyzed */
byte my_see_inv;        /* Can see invisible */
byte my_regenerate; /* Regenerate hit pts */
byte my_hold_life;  /* Resist life draining */
byte my_telepathy;  /* Telepathy */
byte my_slow_digest;    /* Slower digestion */

/* various slays */
byte my_slay_animal;
byte my_slay_evil;
byte my_slay_undead;
byte my_slay_demon;
byte my_slay_orc;
byte my_slay_troll;
byte my_slay_giant;
byte my_slay_dragon;
byte my_kill_dragon;
byte my_impact;
byte my_brand_acid;
byte my_brand_elec;
byte my_brand_fire;
byte my_brand_cold;

s16b my_see_infra;  /* Infravision range */

s16b my_skill_dis;  /* Skill: Disarming */
s16b my_skill_dev;  /* Skill: Magic Devices */
s16b my_skill_sav;  /* Skill: Saving throw */
s16b my_skill_stl;  /* Skill: Stealth factor */
s16b my_skill_srh;  /* Skill: Searching ability */
s16b my_skill_fos;  /* Skill: Searching frequency */
s16b my_skill_thn;  /* Skill: To hit (normal) */
s16b my_skill_thb;  /* Skill: To hit (shooting) */
s16b my_skill_tht;  /* Skill: To hit (throwing) */
s16b my_skill_dig;  /* Skill: Digging ability */

s16b my_num_blow;   /* Number of blows */
s16b my_num_fire;   /* Number of shots */

s16b my_speed;      /* Approximate speed */
s16b my_other;      /* Approximate other */

byte my_ammo_tval;  /* Ammo -- "tval" */
byte my_ammo_sides; /* Ammo -- "sides" */
s16b my_ammo_power; /* Shooting multipler */
s16b my_ammo_range; /* Shooting range */

s16b my_cur_lite;   /* Current lite radius */

s16b my_need_enchant_to_a;  /* Need some enchantment */
s16b my_need_enchant_to_h;  /* Need some enchantment */
s16b my_need_enchant_to_d;  /* Need some enchantment */


/*
 * Hack -- basic "power"
 */

s32b my_power;


/*
 * Various "amounts" (for the player)
 */

s16b amt_fuel;
s16b amt_food;
s16b amt_ident;
s16b amt_star_ident;
s16b amt_recall;
s16b amt_phase;
s16b amt_escape;
s16b amt_teleport;
s16b amt_teleport_staff;

s16b amt_heal;
s16b amt_ez_heal;
s16b amt_mana;
s16b amt_ez_mana;
s16b amt_cure_critical;
s16b amt_cure_serious;

s16b amt_detect_trap;
s16b amt_detect_door;

s16b amt_missile;

s16b amt_book[9];

s16b amt_add_stat[6];
s16b amt_fix_stat[6];
s16b amt_fix_exp;

s16b amt_speed;

s16b amt_enchant_to_a;
s16b amt_enchant_to_d;
s16b amt_enchant_to_h;


/*
 * Various "amounts" (for the home)
 */

s16b num_food;
s16b num_ident;
s16b num_star_ident;
s16b num_recall;
s16b num_phase;
s16b num_escape;
s16b num_teleport;

s16b num_cure_critical;
s16b num_cure_serious;

s16b num_missile;

s16b num_book[9];

s16b num_fix_stat[6];

s16b num_fix_exp;
s16b num_mana;
s16b num_heal;

s16b num_enchant_to_a;
s16b num_enchant_to_d;
s16b num_enchant_to_h;

s16b num_artifact;

s16b home_slot_free;
s16b home_damage;
s16b num_duplicate_items;
s16b num_slow_digest;
s16b num_regenerate;
s16b num_telepathy;
s16b num_lite;
s16b num_see_inv;
s16b num_ffall;
s16b num_free_act;
s16b num_hold_life;
s16b num_immune_acid;
s16b num_immune_elec;
s16b num_immune_fire;
s16b num_immune_cold;
s16b num_resist_acid;
s16b num_resist_elec;
s16b num_resist_fire;
s16b num_resist_cold;
s16b num_resist_pois;
s16b num_resist_conf;
s16b num_resist_sound;
s16b num_resist_lite;
s16b num_resist_dark;
s16b num_resist_chaos;
s16b num_resist_disen;
s16b num_resist_shard;
s16b num_resist_nexus;
s16b num_resist_blind;
s16b num_resist_neth;
s16b num_speed;
s16b num_edged_weapon;
s16b num_bad_gloves;
s16b num_weapons;
s16b num_bow;
s16b num_rings;
s16b num_neck;
s16b num_armor;
s16b num_cloaks;
s16b num_shields;
s16b num_hats;
s16b num_gloves;
s16b num_boots;

/*
 * Hack -- extra state variables
 */

int auto_feeling = 0;   /* Current level "feeling" */

int auto_max_level = 0; /* Maximum player level */
int auto_max_depth = 0; /* Maximum dungeon depth */

int fear_depth = 0;     /* Maximum dungeon depth */


/*
 * Hack -- current shop index
 */

s16b shop_num = -1;     /* Current shop index */



/*
 * State variables extracted from the screen
 */

int auto_depth;     /* Current dungeon "level" */

int auto_level;     /* Current level */

bool borg_king;     /* We won!  Time to retire. */

s32b auto_exp;      /* Current experience */

s32b auto_gold;     /* Current gold */

int auto_speed;     /* Current speed */

int auto_ac;        /* Current ac */

int auto_chp;       /* Current hitpoints */
int auto_mhp;       /* Maximum hitpoints */

int auto_csp;       /* Current spell points */
int auto_msp;       /* Maximum spell points */

int auto_stat[6];   /* Current stat values */

int auto_book[9];   /* Current book slots */


/*
 * State variables extracted from the inventory/equipment
 */

int auto_cur_wgt;   /* Current weight */


/*
 * Constant state variables
 */

int auto_race;      /* Player race */
int auto_class;     /* Player class */


/*
 * Hack -- access the class/race records
 */

player_race *rb_ptr;    /* Player race info */
player_class *cb_ptr;   /* Player class info */

player_magic *mb_ptr;   /* Player magic info */



/*
 * Number of turns to step for (zero means forever)
 */
u16b auto_step = 0;     /* Step count (if any) */


/*
 * Status message search string
 */
char auto_match[128] = "";  /* Search string */


/*
 * Log file
 */
FILE *auto_fff = NULL;      /* Log file */


/*
 * Hack -- single character constants
 */

const char p1 = '(', p2 = ')';
const char c1 = '{', c2 = '}';
const char b1 = '[', b2 = ']';


/*
 * Hack -- the detection arrays
 */

bool auto_detect_wall[6][6];

bool auto_detect_trap[6][6];

bool auto_detect_door[6][6];


/*
 * Locate the store doors
 */

byte *track_shop_x;
byte *track_shop_y;


/*
 * Track "stairs up"
 */

s16b track_less_num;
s16b track_less_size;
byte *track_less_x;
byte *track_less_y;


/*
 * Track "stairs down"
 */

s16b track_more_num;
s16b track_more_size;
byte *track_more_x;
byte *track_more_y;


/*
 * The object list.  This list is used to "track" objects.
 */

s16b auto_takes_cnt;

s16b auto_takes_nxt;

auto_take *auto_takes;


/*
 * The monster list.  This list is used to "track" monsters.
 */

s16b auto_kills_cnt;

s16b auto_kills_nxt;

auto_kill *auto_kills;


/*
 * Hack -- depth readiness
 */
int auto_fear_depth = 0;  /* number of times level completed */
bool finished_level;
bool borg_collect_potions_morgoth;
/* a 3 state boolean */
/*-1 = not checked yet */
/* 0 = not ready */
/* 1 = ready */
int borg_ready_morgoth; 


/*
 * Hack -- extra fear per "region"
 */

u16b auto_fear_region[6][18];


/*
 * Hack -- count racial appearances per level
 */

s16b *auto_race_count;


/*
 * Hack -- count racial kills (for uniques)
 */

s16b *auto_race_death;


/*
 * Classification of map symbols
 */

bool auto_is_take[256];     /* Symbol may be an object */

bool auto_is_kill[256];     /* Symbol may be a monster */


/*
 * The current map
 */

auto_grid *auto_grids[AUTO_MAX_Y];  /* The grids */


#ifdef BORG_ROOMS

/*
 * Some "map" related variables
 */

int auto_room_max = 0;      /* First totally free room */

auto_room *auto_rooms;      /* Current "room list" */

auto_room *auto_room_head;  /* &auto_rooms[0] */

auto_room *auto_room_tail;  /* &auto_rooms[AUTO_MAX_ROOMS-1] */

#endif


/*
 * Maintain a set of grids marked as "BORG_LITE"
 */

s16b auto_lite_n = 0;

byte auto_lite_x[AUTO_LITE_MAX];
byte auto_lite_y[AUTO_LITE_MAX];


/*
 * Maintain a set of grids marked as "BORG_VIEW"
 */

s16b auto_view_n = 0;

byte auto_view_x[AUTO_VIEW_MAX];
byte auto_view_y[AUTO_VIEW_MAX];


/*
 * Maintain a temporary set of grids
 */

s16b auto_temp_n = 0;

byte auto_temp_x[AUTO_TEMP_MAX];
byte auto_temp_y[AUTO_TEMP_MAX];



/*
 * Maintain a circular queue of grids
 */

s16b auto_flow_n = 0;

byte auto_flow_x[AUTO_FLOW_MAX];
byte auto_flow_y[AUTO_FLOW_MAX];


/*
 * Hack -- use "flow" array as a queue
 */

int flow_head = 0;
int flow_tail = 0;



/*
 * Some variables
 */

auto_data *auto_data_flow;  /* Current "flow" data */

auto_data *auto_data_cost;  /* Current "cost" data */

auto_data *auto_data_hard;  /* Constant "hard" data */

auto_data *auto_data_know;  /* Current "know" flags */

auto_data *auto_data_icky;  /* Current "icky" flags */



/*
 * Strategy flags -- recalculate things
 */

bool auto_danger_wipe = FALSE;  /* Recalculate danger */

bool auto_update_view = FALSE;  /* Recalculate view */

bool auto_update_lite = FALSE;  /* Recalculate lite */


/*
 * Strategy flags -- examine the world
 */

bool auto_do_inven = TRUE;  /* Acquire "inven" info */

bool auto_do_equip = TRUE;  /* Acquire "equip" info */

bool auto_do_panel = TRUE;  /* Acquire "panel" info */

bool auto_do_frame = TRUE;  /* Acquire "frame" info */

bool auto_do_spell = TRUE;  /* Acquire "spell" info */

byte auto_do_spell_aux = 0; /* Hack -- book for "auto_do_spell" */

bool auto_do_browse = 0;    /* Acquire "store" info */

byte auto_do_browse_what = 0;   /* Hack -- store for "auto_do_browse" */

byte auto_do_browse_more = 0;   /* Hack -- pages for "auto_do_browse" */


/*
 * Strategy flags -- run certain functions
 */

bool auto_do_crush_junk = FALSE;

bool auto_do_crush_hole = FALSE;

bool auto_do_crush_slow = FALSE;

/* am I fighting a unique? */
bool borg_fighting_unique;


/*
 * Query the "attr/char" at a given location on the screen
 * We return "zero" if the given location was legal
 *
 * XXX XXX XXX We assume the given location is legal
 */
errr borg_what_char(int x, int y, byte *a, char *c)
{
    /* Direct access XXX XXX XXX */
    (*a) = (Term->scr->a[y][x]);
    (*c) = (Term->scr->c[y][x]);

    /* Success */
    return (0);
}


/*
 * Query the "attr/chars" at a given location on the screen
 *
 * Note that "a" points to a single "attr", and "s" to an array
 * of "chars", into which the attribute and text at the given
 * location are stored.
 *
 * We will not grab more than "ABS(n)" characters for the string.
 * If "n" is "positive", we will grab exactly "n" chars, or fail.
 * If "n" is "negative", we will grab until the attribute changes.
 *
 * We automatically convert all "blanks" and "invisible text" into
 * spaces, and we ignore the attribute of such characters.
 *
 * We do not strip final spaces, so this function will very often
 * read characters all the way to the end of the line.
 *
 * We succeed only if a string of some form existed, and all of
 * the non-space characters in the string have the same attribute,
 * and the string was long enough.
 *
 * XXX XXX XXX We assume the given location is legal
 */
errr borg_what_text(int x, int y, int n, byte *a, char *s)
{
    int i;

    byte t_a;
    char t_c;

    byte *aa;
    char *cc;

    /* Current attribute */
    byte d_a = 0;

    /* Max length to scan for */
    int m = ABS(n);

    /* Hack -- Do not run off the screen */
    if (x + m > 80) m = 80 - x;

    /* Direct access XXX XXX XXX */
    aa = &(Term->scr->a[y][x]);
    cc = &(Term->scr->c[y][x]);

    /* Grab the string */
    for (i = 0; i < m; i++)
    {
        /* Access */
        t_a = *aa++;
        t_c = *cc++;

        /* Handle spaces */
        if ((t_c == ' ') || !t_a)
        {
            /* Save space */
            s[i] = ' ';
        }

        /* Handle real text */
        else
        {
            /* Attribute ready */
            if (d_a)
            {
                /* Verify the "attribute" (or stop) */
                if (t_a != d_a) break;
            }

            /* Acquire attribute */
            else
            {
                /* Save it */
                d_a = t_a;
            }

            /* Save char */
            s[i] = t_c;
        }
    }

    /* Terminate the string */
    s[i] = '\0';

    /* Save the attribute */
    (*a) = d_a;

    /* Too short */
    if ((n > 0) && (i != n)) return (1);

    /* Success */
    return (0);
}




/*
 * Log a message to a file
 */
void borg_info(cptr what)
{
    /* Dump a log file message */
    if (auto_fff) fprintf(auto_fff, "%s\n", what);
}



/*
 * Memorize a message, Log it, Search it, and Display it in pieces
 */
void borg_note(cptr what)
{
    int j, n, i, k;

    int w, h, x, y;

    term *old = Term;


    /* Memorize it */
    message_add(what);


    /* Log the message */
    borg_info(what);


    /* Mega-Hack -- Check against the search string */
    if (auto_match[0] && strstr(what, auto_match))
    {
        /* Clean cancel */
        auto_cancel = TRUE;
    }


    /* Scan windows */
    for (j = 0; j < 8; j++)
    {
        if (!angband_term[j]) continue;

        /* Check flag */
        if (!(window_flag[j] & PW_BORG_1)) continue;

        /* Activate */
        Term_activate(angband_term[j]);

        /* Access size */
        Term_get_size(&w, &h);

        /* Access cursor */
        Term_locate(&x, &y);

        /* Erase current line */
        Term_erase(0, y, 255);


        /* Total length */
        n = strlen(what);

        /* Too long */
        if (n > w - 2)
        {
            char buf[1024];

            /* Split */
            while (n > w - 2)
            {
                /* Default */
                k = w - 2;

                /* Find a split point */
                for (i = w / 2; i < w - 2; i++)
                {
                    /* Pre-emptive split point */
                    if (isspace(what[i])) k = i;
                }

                /* Copy over the split message */
                for (i = 0; i < k; i++)
                {
                    /* Copy */
                    buf[i] = what[i];
                }

                /* Indicate split */
                buf[i++] = '\\';

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

                /* Show message */
                Term_addstr(-1, TERM_WHITE, buf);

                /* Advance (wrap) */
                if (++y >= h) y = 0;

                /* Erase next line */
                Term_erase(0, y, 255);

                /* Advance */
                what += k;

                /* Reduce */
                n -= k;
            }

            /* Show message tail */
            Term_addstr(-1, TERM_WHITE, what);

            /* Advance (wrap) */
            if (++y >= h) y = 0;

            /* Erase next line */
            Term_erase(0, y, 255);
        }

        /* Normal */
        else
        {
            /* Show message */
            Term_addstr(-1, TERM_WHITE, what);

            /* Advance (wrap) */
            if (++y >= h) y = 0;

            /* Erase next line */
            Term_erase(0, y, 255);
        }


        /* Flush output */
        Term_fresh();

        /* Use correct window */
        Term_activate(old);
    }
}




/*
 * Abort the Borg, noting the reason
 */
void borg_oops(cptr what)
{
    /* Stop processing */
    auto_active = FALSE;

    /* Give a warning */
    borg_note(format("# Aborting (%s).", what));

    /* Forget borg keys */
    borg_flush();
}



/*
 * A Queue of keypresses to be sent
 */
static char *auto_key_queue;
static s16b auto_key_head;
static s16b auto_key_tail;


/*
 * Add a keypress to the "queue" (fake event)
 */
errr borg_keypress(char k)
{
    /* Hack -- Refuse to enqueue "nul" */
    if (!k) return (-1);

    /* Hack -- note the keypress */
    if (auto_fff) borg_info(format("& Key <%c>", k));

    /* Store the char, advance the queue */
    auto_key_queue[auto_key_head++] = k;

    /* Circular queue, handle wrap */
    if (auto_key_head == KEY_SIZE) auto_key_head = 0;

    /* Hack -- Catch overflow (forget oldest) */
    if (auto_key_head == auto_key_tail) borg_oops("overflow");

    /* Hack -- Overflow may induce circular queue */
    if (auto_key_tail == KEY_SIZE) auto_key_tail = 0;

    /* Success */
    return (0);
}


/*
 * Add a keypress to the "queue" (fake event)
 */
errr borg_keypresses(cptr str)
{
    cptr s;

    /* Enqueue them */
    for (s = str; *s; s++) borg_keypress(*s);

    /* Success */
    return (0);
}


/*
 * Get the next Borg keypress
 */
char borg_inkey(bool take)
{
    int i;

    /* Nothing ready */
    if (auto_key_head == auto_key_tail) 
        return (0);

    /* Extract the keypress */
    i = auto_key_queue[auto_key_tail];

    /* Do not advance */
    if (!take) return (i);

    /* Advance the queue */
    auto_key_tail++;

    /* Circular queue requires wrap-around */
    if (auto_key_tail == KEY_SIZE) auto_key_tail = 0;

    /* Return the key */
    return (i);
}



/*
 * Get the next Borg keypress
 */
void borg_flush(void)
{
    /* Simply forget old keys */
    auto_key_tail = auto_key_head;
}






/*
 * Hack -- take a note later
 */
bool borg_tell(cptr what)
{
    cptr s;

    /* Hack -- self note */
    borg_keypress(':');
    for (s = what; *s; s++) borg_keypress(*s);
    borg_keypress('\n');

    /* Success */
    return (TRUE);
}



/*
 * Attempt to change the borg's name
 */
bool borg_change_name(cptr str)
{
    cptr s;

    /* Cancel everything */
    borg_keypress(ESCAPE);
    borg_keypress(ESCAPE);

    /* Character description */
    borg_keypress('C');

    /* Change the name */
    borg_keypress('c');

    /* Enter the new name */
    for (s = str; *s; s++) borg_keypress(*s);

    /* End the name */
    borg_keypress('\r');

    /* Cancel everything */
    borg_keypress(ESCAPE);
    borg_keypress(ESCAPE);

    /* Success */
    return (TRUE);
}


/*
 * Attempt to dump a character description file
 */
bool borg_dump_character(cptr str)
{
    cptr s;

    /* Cancel everything */
    borg_keypress(ESCAPE);
    borg_keypress(ESCAPE);

    /* Character description */
    borg_keypress('C');

    /* Dump character file */
    borg_keypress('f');

    /* Enter the new name */
    for (s = str; *s; s++) borg_keypress(*s);

    /* End the file name */
    borg_keypress('\r');

    /* Cancel everything */
    borg_keypress(ESCAPE);
    borg_keypress(ESCAPE);

    /* Success */
    return (TRUE);
}




/*
 * Attempt to save the game
 */
bool borg_save_game(void)
{
    /* Cancel everything */
    borg_keypress(ESCAPE);
    borg_keypress(ESCAPE);

    /* Save the game */
    borg_keypress('^');
    borg_keypress('S');

    /* Cancel everything */
    borg_keypress(ESCAPE);
    borg_keypress(ESCAPE);

    /* Success */
    return (TRUE);
}




/*
 * Update the Borg based on the current "frame"
 *
 * Assumes the Borg is actually in the dungeon.
 */
void borg_update_frame(void)
{
    int i;

    byte t_a;

    char buf[160];


    /* Check for "   Town" or "  Lev 8" or " Lev 13" */
    if (0 == borg_what_text(COL_DEPTH, ROW_DEPTH, -7, &t_a, buf))
    {
        cptr s;

        /* Skip the non-digits */
        for (s = buf; *s && !isdigit(*s); s++) /* loop */;

        /* Extract the current level */
        auto_depth = atoi(s);
    }


    /* XXX XXX XXX Title (ignore) */


    /* XXX XXX XXX Info (monster health) */


    /* Assume level is fine */
    do_fix_lev = FALSE;

    /* Check for drained level */
    if (0 == borg_what_text(COL_LEVEL, ROW_LEVEL, -3, &t_a, buf))
    {
        /* Note "Lev" vs "LEV" */
        if (islower(buf[2])) do_fix_lev = TRUE;
    }

    /* Extract current level */
    if (0 == borg_what_text(COL_LEVEL + 6, ROW_LEVEL, -6, &t_a, buf))
    {
        /* Extract "LEVEL xxxxxx" */
        auto_level = atoi(buf);
    }

    /* Extract current level */
    if (0 == borg_what_text(COL_TITLE, ROW_TITLE, -8, &t_a, buf))
    {
        /* Note "Lev" vs "LEV" */
        borg_king = (buf[0] == '*' &&
            buf[1] == '*' &&
            buf[2] == 'K' &&
            buf[3] == 'I' &&
            buf[4] == 'N' &&
            buf[5] == 'G' &&
            buf[6] == '*' &&
            buf[7] == '*');
    }

    /* Assume experience is fine */
    do_fix_exp = FALSE;

    /* Check for drained experience */
    if (0 == borg_what_text(COL_EXP, ROW_EXP, -3, &t_a, buf))
    {
        /* Note "Exp" vs "EXP" */
        if (islower(buf[2])) do_fix_exp = TRUE;
    }

    /* Extract current experience */
    if (0 == borg_what_text(COL_EXP + 4, ROW_EXP, -8, &t_a, buf))
    {
        /* Extract "EXP xxxxxxxx" */
        auto_exp = atol(buf);
    }


    /* Extract current gold */
    if (0 == borg_what_text(COL_GOLD + 3, ROW_GOLD, -9, &t_a, buf))
    {
        /* Extract "AU xxxxxxxxx" */
        auto_gold = atol(buf);
    }


    /* Extract speed */
    if (0 == borg_what_text(COL_SPEED, ROW_SPEED, -14, &t_a, buf))
    {
        /* Extract "Fast (+x)" or "Slow (-x)" */
        auto_speed = 110 + atoi(buf + 6);

        /* if hasting, it doesn't count as 'auto_speed'.  The speed */
        /* gained from hasting is counted seperately. */
        if (borg_speed)
            auto_speed -= 10;
    }

    /* Extract armor class */
    if (0 == borg_what_text(COL_AC + 7, ROW_AC, -5, &t_a, buf))
    {
        /* Extract "Cur AC xxxxx" */
        auto_ac = atoi(buf);
    }


    /* Extract maximum hitpoints */
    if (0 == borg_what_text(COL_MAXHP + 7, ROW_MAXHP, -5, &t_a, buf))
    {
        /* Extract "Max HP xxxxx" */
        auto_mhp = atoi(buf);
    }

    /* Extract current hitpoints */
    if (0 == borg_what_text(COL_CURHP + 7, ROW_CURHP, -5, &t_a, buf))
    {
        /* Extract "Cur HP xxxxx" */
        auto_chp = atoi(buf);
    }


    /* Extract maximum spell points */
    if (0 == borg_what_text(COL_MAXSP + 7, ROW_MAXSP, -5, &t_a, buf))
    {
        /* Extract "Max SP xxxxx" (or zero) */
        auto_msp = atoi(buf);
    }

    /* Extract current spell points */
    if (0 == borg_what_text(COL_CURSP + 7, ROW_CURSP, -5, &t_a, buf))
    {
        /* Extract "Cur SP xxxxx" (or zero) */
        auto_csp = atoi(buf);
    }



    /* Clear all the "state flags" */
    do_weak = do_hungry = do_full = do_gorged = FALSE;
    do_blind = do_confused = do_afraid = do_poisoned = FALSE;
    do_cut = do_stun = do_heavy_stun = do_image = do_study = FALSE;

    /* Check for hunger */
    if (0 == borg_what_text(COL_HUNGRY, ROW_HUNGRY, -1, &t_a, buf))
    {
        /* Check for "Hungry" */
        if (buf[0] == 'H') do_hungry = TRUE;

        /* Check for "Weak" */
        if (buf[0] == 'W') do_weak = do_hungry = TRUE;

        /* Check for "Full" */
        if (buf[0] == 'F') do_full = TRUE;

        /* Check for "Gorged" */
        if (buf[0] == 'G') do_gorged = do_full = TRUE;
    }

    /* Check for blind */
    if (0 == borg_what_text(COL_BLIND, ROW_BLIND, -1, &t_a, buf))
    {
        /* Check for "Blind" */
        if (buf[0] == 'B') do_blind = TRUE;
    }

    /* Check for confused */
    if (0 == borg_what_text(COL_CONFUSED, ROW_CONFUSED, -1, &t_a, buf))
    {
        /* Check for "Confused" */
        if (buf[0] == 'C') do_confused = TRUE;
    }

    /* Check for afraid */
    if (0 == borg_what_text(COL_AFRAID, ROW_AFRAID, -1, &t_a, buf))
    {
        /* Check for "Afraid" */
        if (buf[0] == 'A') do_afraid = TRUE;
    }

    /* Check for poisoned */
    if (0 == borg_what_text(COL_POISONED, ROW_POISONED, -1, &t_a, buf))
    {
        /* Check for "Poisoned" */
        if (buf[0] == 'P') do_poisoned = TRUE;
    }


    /* XXX XXX Check for cut */
    if (0 == borg_what_text(COL_CUT, ROW_CUT, -1, &t_a, buf))
    {
        /* Check for any text */
        if (isalpha(buf[0])) do_cut = TRUE;
    }

    /* XXX XXX Check for stun */
    if (0 == borg_what_text(COL_STUN, ROW_STUN, -1, &t_a, buf))
    {
        /* Check for Stun */
        if (buf[0] == 'S') do_stun = TRUE;

        /* Check for Heavy Stun */
        if (buf[0] == 'H') do_heavy_stun = TRUE;
    }


    /* XXX XXX XXX Parse "State" */


    /* Check for study */
    if (0 == borg_what_text(COL_STUDY, ROW_STUDY, -1, &t_a, buf))
    {
        /* Check for "Study" */
        if (buf[0] == 'S') do_study = TRUE;
    }


    /* Parse stats */
    for (i = 0; i < 6; i++)
    {
        /* Check "NNN   xxxxxx" */
        if (0 == borg_what_text(COL_STAT, ROW_STAT+i, -3, &t_a, buf))
        {
            /* Note "Nnn" vs "NNN" */
            do_fix_stat[i] = (islower(buf[2]));
        }

        /* Check "NNN   xxxxxx" */
        if (0 == borg_what_text(COL_STAT+6, ROW_STAT+i, -6, &t_a, buf))
        {
            /* Parse "18/..." */
            if (buf[5] == '*') auto_stat[i] = 18 + 220;

            /* Parse "18/NNN" */
            else if (buf[2] == '/') auto_stat[i] = 18 + atoi(buf+3);

            /* Parse " 18/NN" */
            else if (buf[3] == '/') auto_stat[i] = 18 + atoi(buf+4);

            /* Parse "    NN" */
            else auto_stat[i] = atoi(buf+4);
        }
    }
}



/*
 * Initialize this file
 */
void borg_init_1(void)
{
    int i, x, y;


    /* Allocate the "keypress queue" */
    C_MAKE(auto_key_queue, KEY_SIZE, char);


    /* Prapare a local random number seed */
if (!auto_rand_local)
    auto_rand_local = rand_int(0x10000000);



#ifdef BORG_ROOMS

    /*** Rooms ***/

    /* Make the array of rooms */
    C_MAKE(auto_rooms, AUTO_ROOMS, auto_room);

    /* Initialize the rooms */
    for (i = 0; i < AUTO_ROOMS; i++)
    {
        /* Save our own index */
        auto_rooms[i].self = i;

        /* Initialize the "free" list */
        auto_rooms[i].free = i + 1;
    }

    /* Save the head/tail of the room array */
    auto_room_head = &auto_rooms[0];
    auto_room_tail = &auto_rooms[AUTO_ROOMS-1];

    /* Prepare the "tail" of the free list */
    auto_room_tail->free = auto_room_tail->self;

    /* Reset the free list */
    auto_room_head->free = 1;

    /* Maximum room index */
    auto_room_max = 1;

#endif


    /*** Grids ***/

    /* Make each row of grids */
    for (y = 0; y < AUTO_MAX_Y; y++)
    {
        /* Make each row */
        C_MAKE(auto_grids[y], AUTO_MAX_X, auto_grid);
    }


    /*** Grid data ***/

    /* Allocate */
    MAKE(auto_data_flow, auto_data);

    /* Allocate */
    MAKE(auto_data_cost, auto_data);

    /* Allocate */
    MAKE(auto_data_hard, auto_data);

    /* Allocate */
    MAKE(auto_data_know, auto_data);

    /* Allocate */
    MAKE(auto_data_icky, auto_data);

    /* Prepare "auto_data_hard" */
    for (y = 0; y < AUTO_MAX_Y; y++)
    {
        for (x = 0; x < AUTO_MAX_X; x++)
        {
            /* Prepare "auto_data_hard" */
            auto_data_hard->data[y][x] = 255;
        }
    }


    /*** Very special "tracking" array ***/

    /* Track the shop locations */
    C_MAKE(track_shop_x, 8, byte);
    C_MAKE(track_shop_y, 8, byte);


    /*** Special "tracking" arrays ***/

    /* Track "up" stairs */
    track_less_num = 0;
    track_less_size = 16;
    C_MAKE(track_less_x, track_less_size, byte);
    C_MAKE(track_less_y, track_less_size, byte);

    /* Track "down" stairs */
    track_more_num = 0;
    track_more_size = 16;
    C_MAKE(track_more_x, track_more_size, byte);
    C_MAKE(track_more_y, track_more_size, byte);


    /*** Object tracking ***/

    /* No objects yet */
    auto_takes_cnt = 0;
    auto_takes_nxt = 1;

    /* Array of objects */
    C_MAKE(auto_takes, 256, auto_take);

    /* Scan the objects */
    for (i = 1; i < MAX_K_IDX; i++)
    {
        object_kind *k_ptr = &k_info[i];

        /* Skip non-items */
        if (!k_ptr->name) continue;

        /* Notice this object */
        auto_is_take[(byte)(k_ptr->x_char)] = TRUE;
    }


    /*** Monster tracking ***/

    /* No monsters yet */
    auto_kills_cnt = 0;
    auto_kills_nxt = 1;

    /* Array of monsters */
    C_MAKE(auto_kills, 256, auto_kill);

    /* Scan the monsters */
    for (i = 1; i < MAX_R_IDX-1; i++)
    {
        monster_race *r_ptr = &r_info[i];

        /* Skip non-monsters */
        if (!r_ptr->name) continue;

        /* Hack -- Skip "clear" monsters XXX XXX XXX */
        if (r_ptr->flags1 & RF1_CHAR_CLEAR) continue;

        /* Hack -- Skip "multi" monsters XXX XXX XXX */
        if (r_ptr->flags1 & RF1_CHAR_MULTI) continue;

        /* Notice this monster */
        auto_is_kill[(byte)(r_ptr->x_char)] = TRUE;
    }


    /*** Special counters ***/

    /* Count racial appearances */
    C_MAKE(auto_race_count, MAX_R_IDX, s16b);

    /* Count racial deaths */
    C_MAKE(auto_race_death, MAX_R_IDX, s16b);


    /*** XXX XXX XXX Hack -- Cheat ***/

    /* Hack -- Extract dead uniques */
    for (i = 1; i < MAX_R_IDX-1; i++)
    {
        monster_race *r_ptr = &r_info[i];

        /* Skip non-monsters */
        if (!r_ptr->name) continue;

        /* Skip non-uniques */
        if (!(r_ptr->flags1 & RF1_UNIQUE)) continue;

        /* Mega-Hack -- Access "dead unique" list */
        if (r_ptr->max_num == 0) auto_race_death[i] = 1;
    }

    /* Hack -- Access max depth */
    auto_max_depth = p_ptr->max_dlv;

    /* HACK when restarting the fear depth is the current max depth */
    fear_depth = p_ptr->max_dlv;
    auto_fear_depth = 0;
    finished_level = FALSE;
}



#else

#ifdef MACINTOSH
static int HACK = 0;
#endif

#endif
