/* borg_basics.c; main routines */

#include "angband.h"

#ifdef AUTO_PLAY

/* main routine */
#define EXTERN /* extern */
#define MAIN_ROUTINE
#include "borg.h"

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

    /* Store the char, advance the queue */
    key_queue[key_head++] = k;

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

    /* Hack -- Catch overflow (forget oldest) */
    if (key_head == key_tail) core("Borg overflowed keypress buffer");

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

    /* Success */
    return (0);
}


/*
 * Get the next Borg keypress
 */
EXTERN int borg_inkey(void)
{
    int i;

    /* Nothing ready */
    if (key_head == key_tail) return (0);
        
    /* Extract the keypress, advance the queue */
    i = key_queue[key_tail++];

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

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



/*
 * Query the "attr/chars" at a given location on the screen
 * We return "TRUE" only if a string of some form existed
 * Note that the string must be done in a single attribute.
 * Normally, the string must be "n" characters long.
 * If "n" is "negative", we will grab until the attribute changes.
 * Note that "a" points to a single "attr", "s" to a string of "chars".
 */
EXTERN errr Term_what_text(int x, int y, int n, byte *a, char *s)
{
    int i;
    byte t_a;
    char t_c;

    /* Max length to scan for */
    int m = ABS(n);
    
    /* Hack -- Pre-terminate the string */
    s[0] = '\0';
    
    /* Check the first character, make sure it exists */
    if (Term_what(x, y, &t_a, &t_c)) return (-1);

    /* Save the attribute */
    (*a) = t_a;
    
    /* Scan for it */
    for (i = 0; i < m; i++) {

	/* Ask for the screen contents */
	if (Term_what(x+i, y, &t_a, &t_c)) return (-2);

	/* Hack -- negative "n" stops at attribute change */
	if ((n < 0) && (t_a != (*a))) break;
	
	/* Verify the "attribute" */
	if (t_a != (*a)) return (-3);
		
	/* Save the character */
	s[i] = t_c;
    }

    /* Terminate the string */
    s[i] = '\0';
    
    /* Success */
    return (0);
}




/*
 * Determine if a missile shot from (y1,x1) to (y2,x2) will arrive
 * at the final destination, assuming no monster gets in the way.
 * Adapted from "projectable()" in "spells1.c".
 */
EXTERN bool borg_projectable(int y1, int x1, int y2, int x2)
{
    register int dist, y, x;
    register auto_grid *ag;

    /* Start at the initial location */
    y = y1, x = x1;
        
    /* Simulate the spell/missile path */
    for (dist = 0; dist < MAX_RANGE; dist++) {

	/* Get the grid */
	ag = grid(x, y);
	
	/* Never pass through walls (including outer edge) */
	if (dist && strchr("#%", ag->o_c)) break;

	/* Check for arrival at "final target" */
	if ((x == x2) && (y == y2)) return (TRUE);

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


    /* Assume obstruction */
    return (FALSE);
}



/*
 * Hack -- set the options the way we like them
 */
EXTERN void borg_play_options(void)
{
    /* Hack -- uses hilite to determine state */
    hilite_player = FALSE;

    /* Paranoia -- require explicit acknowledgement */
    quick_messages = FALSE;

    /* Uses original keypress commands */
    rogue_like_commands = FALSE;

    /* Uses color for various purposes */
    use_color = TRUE;

    /* Pick up items when stepped on */
    always_pickup = TRUE;

    /* Accept all "throw" commands */
    always_throw = TRUE;

    /* Do *not* use old target */
    use_old_target = FALSE;
    
    /* Do *not* query any actions */
    other_query_flag = FALSE;
    carry_query_flag = FALSE;
    
    /* When we open/bash/disarm/tunnel, make it count */
    always_repeat = TRUE;

    /* Auto-player gets confused by extra info */
    plain_descriptions = TRUE;

    /* Buy/Sell without haggling */
    no_haggle_flag = TRUE;

    /* Maximal information */
    fresh_before = TRUE;
    fresh_after = TRUE;
    
    /* Read the level directly */
    depth_in_feet = FALSE;
}


#if 0

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

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

#endif


/*
 * Hack -- Display (and save) a note to the user
 */
EXTERN void borg_note(cptr what)
{
    /* Add to the message recall */
    message_new(what, -1);

#ifdef FRITSDEBUG
    if (logging == 1)
       fprintf(logfile,"%s\n",what);
#endif /* FRITSDEBUG */

    /* Do not use the recall window unless allowed */
    if (!use_recall_win || !term_recall) return;

    /* Hack -- dump the message in the recall window */
    Term_activate(term_recall);    
    Term_clear();
    Term_putstr(0,0,-1,TERM_WHITE,what);
    Term_fresh();
    Term_activate(term_screen);
}


/*
 * Hack -- Stop processing on errors
 */
EXTERN void borg_oops(cptr what)
{
#ifdef FRITSDEBUG
   borg_note("In routine borg_oops()");
#endif /* FRITSDEBUG */
    /* Forget the state */
    state = 0;

    /* Give a warning */
    borg_note(format("The %cBORG has broken (%s).",007, what));
}




/*
 * Hack -- access the "set" of rooms containing a given point
 *
 * We should probably build a "list" of "used rooms", where the "tail"
 * of that list is all the "crossed rooms", and also keep a pointer to
 * that tail for "fast" access to the "crossed rooms" set.
 *
 * This function is necessary because some grids (though not many)
 * can be contained in multiple rooms, because we allow "crossing"
 * rooms.  The Borg uses crossing rooms not only for actual "cross"
 * and "overlap" rooms in the dungeon, but also weird double width
 * corridors, the corners of "ragged edge" rooms, and various regions
 * in the town.  Actually, the worst "offenders" come from the town...
 */
EXTERN auto_room *room(bool go, int gx, int gy)
{
    static int x = 0, y = 0, i = 0;

    /* We just got a new grid */
    if (go) {

	auto_grid *ag = grid(gx, gy);
	
	/* Default to no rooms */
	i = auto_room_max;
	
	/* Paranoia -- no rooms */
	if (!ag->room) return (NULL);
	
	/* Efficiency -- Single room */
	if (ag->room < AUTO_ROOMS) return (&auto_rooms[ag->room]);

	/* Scan through multiple rooms */
	x = gx; y = gy; i = 0;
    }

    /* Look for a room */
    for (i++; i < auto_room_max; i++) {

	/* Access the room */
	auto_room *ar = &auto_rooms[i];
	
	/* Skip "dead" rooms */
	if (!ar->when) continue;
	
	/* If the room contains it, use it */
	if ((x >= ar->x1) && (x <= ar->x2) &&
	    (y >= ar->y1) && (y <= ar->y2)) {
	    return (ar);
	}
    }

    /* Default */
    return (NULL);
}





/*
 * Decide whether to "inspect" a grid
 */
EXTERN bool borg_inspect(int x, int y)
{
    int		i, door = 0, wall = 0;
    char	c[8];

    /* Hack -- Never inspect the town */
    if (auto_depth == 0) return (FALSE);

    /* Only occasionally */
    if (rand_int(5) == 0) return (FALSE);
    
    /* Examine adjacent locations */
    for (i = 0; i < 8; i++) {

	int xx, yy;
	auto_grid *ag;
	
	/* Extract the location */
	xx = x + ddx[ddd[i]];
	yy = y + ddy[ddd[i]];
	
	/* Illegal grid */
	if (!grid_legal(xx, yy)) return (FALSE);
	
	/* Obtain the grid */
	ag = grid(xx, yy);

	/* Unknown grid */
	if (ag->o_c == ' ') return (FALSE);
	
	/* Extract the contents */
	c[i] = ag->o_c;

	/* Count "possible door locations" */
	if ((i < 4) && (c[i] == '#')) door++;

	/* Count "intersection indicators" */
	if (strchr("#%", c[i])) wall++;
    }
    
    /* Examine suspicious dead ends */
    if (door && (wall >= 7)) return (TRUE);

    /* Assume no suspicions */
    return (FALSE);
}





/*
 * Determine if the given grid is a "snake" grid
 * A "snake" is a "normal" section of corridor, with no
 * bends or intersections.  Only the "center" counts.
 * Note that a "1x1" grid (or "diagonal" grid) is a "snake".
 * A "snake" grid cannot touch "unknown" grids.
 */
EXTERN bool borg_build_snake(int x, int y)
{
    register auto_grid *ag, *ag1, *ag2;

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

    /* Central grid cannot be unknown */
    if (ag->o_c == ' ') return (FALSE);
    
    /* Central grid must be a non-wall */
    if (strchr("#%", ag->o_c)) return (FALSE);
    
    /* South/North blockage induces a snake */
    ag1 = grid(x, y+1); ag2 = grid(x, y-1);
    if (strchr("#%", ag1->o_c) && strchr("#%", ag2->o_c)) return (TRUE);
    
    /* East/West blockage induces a snake */
    ag1 = grid(x+1, y); ag2 = grid(x-1, y);
    if (strchr("#%", ag1->o_c) && strchr("#%", ag2->o_c)) return (TRUE);
    
    /* No good */
    return (FALSE);
}



/*
 * Determine if the given "box" in the world is fully made of "floor"
 */
EXTERN bool borg_build_room_floor(int x1, int y1, int x2, int y2)
{
    int x, y;
    
    /* Check for "easy expand" */
    for (y = y1; y <= y2; y++) {
	for (x = x1; x <= x2; x++) {
	
	    /* Access that grid */
	    auto_grid *ag = grid(x, y);
	    
	    /* Refuse to accept unknown grids */
	    if (ag->o_c == ' ') return (FALSE);

	    /* Refuse to accept walls/seams/doors */
	    if (strchr("#%+'", ag->o_c)) return (FALSE);

	    /* XXX Hack -- Require floors (or stairs) */
	    if (!strchr(".<>", ag->o_c)) return (FALSE);
	}
    }

    /* Must be okay */
    return (TRUE);
}


/*
 * Determine if the given "box" in the world is fully "known"
 */
EXTERN bool borg_build_room_known(int x1, int y1, int x2, int y2)
{
    int x, y;
    
    /* Check for "unknown" grids */
    for (y = y1; y <= y2; y++) {
	for (x = x1; x <= x2; x++) {
	
	    /* Access that grid */
	    auto_grid *ag = grid(x, y);
	    
	    /* Refuse to accept unknown grids */
	    if (ag->o_c == ' ') return (FALSE);
	}
    }

    /* Must be okay */
    return (TRUE);
}




/*
 * Attempt to build a "bigger" room for the given location
 *
 * We use a "free list" to simplify "room allocation".
 *
 * We return TRUE if a "new" room was created.
 */
EXTERN bool borg_build_room(int x, int y)
{
    uint i, j;

    int x1, y1, x2, y2;

    auto_grid *ag;
    auto_room *ar;


    /* Attempt to expand a 3x3 room */
    if (borg_build_room_floor(x-1, y-1, x+1, y+1)) {
	x1 = x - 1; y1 = y - 1; x2 = x + 1; y2 = y + 1;
    }
    
    /* Or attempt to expand a 3x2 room (south) */
    else if (borg_build_room_floor(x-1, y, x+1, y+1)) {
	x1 = x - 1; y1 = y; x2 = x + 1; y2 = y + 1;
    }
    
    /* Or attempt to expand a 3x2 room (north) */
    else if (borg_build_room_floor(x-1, y-1, x+1, y)) {
	x1 = x - 1; y1 = y - 1; x2 = x + 1; y2 = y;
    }
        
    /* Or attempt to expand a 2x3 room (east) */
    else if (borg_build_room_floor(x, y-1, x+1, y+1)) {
	x1 = x; y1 = y - 1; x2 = x + 1; y2 = y + 1;
    }
    
    /* Or attempt to expand a 2x3 room (west) */
    else if (borg_build_room_floor(x-1, y-1, x, y+1)) {
	x1 = x - 1; y1 = y - 1; x2 = x; y2 = y + 1;
    }
    
    /* Or attempt to expand a 2x2 room (south east) */
    else if (borg_build_room_floor(x, y, x+1, y+1)) {
	x1 = x; y1 = y; x2 = x + 1; y2 = y + 1;
    }
    
    /* Or attempt to expand a 2x2 room (south west) */
    else if (borg_build_room_floor(x-1, y, x, y+1)) {
	x1 = x - 1; y1 = y; x2 = x; y2 = y + 1;
    }
    
    /* Or attempt to expand a 2x2 room (north east) */
    else if (borg_build_room_floor(x, y-1, x+1, y)) {
	x1 = x; y1 = y - 1; x2 = x + 1; y2 = y;
    }
    
    /* Or attempt to expand a 2x2 room (north west) */
    else if (borg_build_room_floor(x-1, y-1, x, y)) {
	x1 = x - 1; y1 = y - 1; x2 = x; y2 = y;
    }

    /* Hack -- only "snake" grids can grow corridors */
    else if (!borg_build_snake(x, y)) {
	x1 = x; y1 = y; x2 = x; y2 = y;
    }
    
    /* Or attempt to extend a corridor (south) */
    else if (borg_build_snake(x, y+1)) {
	x1 = x; y1 = y; x2 = x; y2 = y + 1;
    }

    /* Or attempt to extend a corridor (north) */
    else if (borg_build_snake(x, y-1)) {
	x1 = x; y1 = y - 1; x2 = x; y2 = y;
    }

    /* Or attempt to extend a corridor (east) */
    else if (borg_build_snake(x+1, y)) {
	x1 = x; y1 = y; x2 = x + 1; y2 = y;
    }

    /* Or attempt to extend a corridor (west) */
    else if (borg_build_snake(x-1, y)) {
	x1 = x - 1; y1 = y; x2 = x; y2 = y;
    }


    /* Default to 1x1 grid */
    else {
	x1 = x; y1 = y; x2 = x; y2 = y;
    }
    
    
    /* Hack -- Single grid (1x1) rooms are boring */
    if ((x1 == x2) && (y1 == y2)) return (FALSE);
    

    /* Expand a north/south corridor */
    if (x1 == x2) {

	/* Grow south/north */
	while (borg_build_snake(x, y2+1)) y2++;
	while (borg_build_snake(x, y1-1)) y1--;
    }
    
    /* Expand a east/west corridor */
    else if (y1 == y2) {

	/* Grow east/west */
	while (borg_build_snake(x2+1, y)) x2++;
	while (borg_build_snake(x1-1, y)) x1--;
    }

    /* Expand a rectangle -- try south/north first */
    else if (rand_int(2) == 0) {

	/* Grow south/north */
	while (borg_build_room_floor(x1, y2+1, x2, y2+1)) y2++;
	while (borg_build_room_floor(x1, y1-1, x2, y1-1)) y1--;

	/* Grow east/west */
	while (borg_build_room_floor(x2+1, y1, x2+1, y2)) x2++;
	while (borg_build_room_floor(x1-1, y1, x1-1, y2)) x1--;
    }

    /* Expand a rectangle -- try east/west first */
    else {

	/* Grow east/west */
	while (borg_build_room_floor(x2+1, y1, x2+1, y2)) x2++;
	while (borg_build_room_floor(x1-1, y1, x1-1, y2)) x1--;

	/* Grow south/north */
	while (borg_build_room_floor(x1, y2+1, x2, y2+1)) y2++;
	while (borg_build_room_floor(x1, y1-1, x2, y1-1)) y1--;
    }


    /* Hack -- refuse to build rooms touching unknowns */
    if (!borg_build_room_known(x1-1, y2+1, x2+1, y2+1)) return (FALSE);
    if (!borg_build_room_known(x1-1, y1-1, x2+1, y1-1)) return (FALSE);
    if (!borg_build_room_known(x2+1, y1-1, x2+1, y2+1)) return (FALSE);
    if (!borg_build_room_known(x1-1, y1-1, x1-1, y2+1)) return (FALSE);


    /* Make sure this room does not exist and is not contained */
    for (ar = room(1,x,y); ar; ar = room(0,0,0)) {

	/* Never make a room "inside" another room */
	if ((ar->x1 <= x1) && (x2 <= ar->x2) &&
	    (ar->y1 <= y1) && (y2 <= ar->y2)) {

	    /* The room already exists */
	    return (FALSE);
	}
    }


    /* Message */
    borg_note(format("Building a room from %d,%d to %d,%d", x1, y1, x2, y2));
    
    
    /* Acquire a "free" room */
    i = auto_rooms[0].free;
    auto_rooms[0].free = auto_rooms[i].free;
    auto_rooms[i].free = 0;
    
    /* Paranoia */
    if (!i) {
	borg_oops("room list full");
	return (FALSE);
    }
    
    /* Take note of new "maximums" */
    if (i + 1 > auto_room_max) auto_room_max = i + 1;
    
    /* Access the new room */
    ar = &auto_rooms[i];
	
    /* Initialize the new room */
    ar->x1 = x1;
    ar->x2 = x2;
    ar->y1 = y1;
    ar->y2 = y2;

    /* Paranoia */
    ar->when = c_t;

    /* Forget the flow */
    ar->flow = 0;
    ar->x = ar->y = 0;
    ar->prev = ar->next = NULL;
    
    /* Absorb old rooms */
    for (j = 1; j < auto_room_max; j++) {

	/* Skip the "current" room! */
	if (i == j) continue;
	
	/* Get the room */
	ar = &auto_rooms[j];
	
	/* Skip "free" rooms */
	if (!ar->when) continue;

	/* Skip non-contained rooms */
	if ((ar->x1 < x1) || (ar->y1 < y1)) continue;
	if ((x2 < ar->x2) || (y2 < ar->y2)) continue;

	/* Scan the "contained" room */
	for (y = ar->y1; y <= ar->y2; y++) {
	    for (x = ar->x1; x <= ar->x2; x++) {
	
		/* Get the "contained" grid */
		ag = grid(x, y);

		/* Normal grids "lose" their parents. */
		if (ag->room < AUTO_ROOMS) ag->room = 0;

		/* Cross-rooms lose one parent */
		if (ag->room > AUTO_ROOMS) ag->room--;
	    }
	}

	/* That room is now "gone" */
	ar->when = 0L;
	ar->x1 = ar->x2 = ar->y1 = ar->y2 = 0;
	ar->prev = ar->next = NULL;
	
	/* Add it to the "free list" */
	auto_rooms[j].free = auto_rooms[0].free;
	auto_rooms[0].free = j;
    }


    /* Access the new room */
    ar = &auto_rooms[i];
    
    /* Scan the grids contained in the new room */
    for (y = ar->y1; y <= ar->y2; y++) {
	for (x = ar->x1; x <= ar->x2; x++) {
	
	    /* Get the "contained" grid */
	    ag = grid(x, y);

	    /* Steal "absorbed" grids */
	    if (ag->room == AUTO_ROOMS) ag->room = i;
	    
	    /* Steal "fresh" grids */
	    if (ag->room == 0) ag->room = i;

	    /* Skip grids owned by this room */
	    if (ag->room == i) continue;
	    
	    /* Normal grids become "cross-grids" (one parent) */
	    if (ag->room < AUTO_ROOMS) ag->room = AUTO_ROOMS + 1;
	    
	    /* All cross-grids now have another parent */
	    ag->room++;
	}
    }

    /* The room set has changed */
    return (TRUE);
}


/*
 * Maintain the "old" hook
 */
EXTERN errr (*Term_xtra_hook_old)(int n, int v) = NULL;


/*
 * Our own hook.  Allow thinking when no keys ready.
 */
EXTERN errr Term_xtra_borg(int n, int v)
{
    /* Hack -- The Borg pre-empts keypresses */
    while (state && (n == TERM_XTRA_EVENT)) {
    
	int i, x, y;
	byte t_a;
	char buf[128];

	errr res = 0;    

	bool visible;

	static inside = 0;

	/* Hack -- pause when main window hidden */
	if (Term != term_screen) break;

	/* Hack -- pause in wizard mode */
	if (wizard) break;
	
	/* Hack -- no recursion */
	if (inside) {
	    Term_keypress(' ');
	    return (0);
	}
	
	/* Hack -- Extract the cursor visibility */
	visible = (!Term_hide_cursor());
	if (visible) Term_show_cursor();
    
	/* Hack -- Pass most methods through */
	res = (*Term_xtra_hook_old)(TERM_XTRA_CHECK, v);
    
	/* Hack -- 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-", then clear it */
	if (visible &&
	    (!Term_locate(&x, &y) && (y == 0) && (x >= 6)) &&
	    (!Term_what_text(x-6, y, 6, &t_a, buf)) &&
	    (streq(buf, "-more-"))) {

	    /* Clear the message */
	    Term_keypress(' ');

	    /* Done */
	    return (0);
	}

	/* Check for a Borg keypress */
	i = borg_inkey();

	/* Take the next keypress */
	if (i) {

	    /* Enqueue the keypress */
	    Term_keypress(i);

	    /* Success */
	    return (0);
	}
	
	/* Inside */
	inside++;
	
	/* Think */
	borg_play_perform();

	/* Outside */
	inside--;
    }

    /* Hack -- Usually just pass the call through */
    return ((*Term_xtra_hook_old)(n, v));
}


/*
 * Initialize the Borg
 */
void borg_init(void)
{
    int i, k;

    char buf[256];
	

    /* Only initialize once */
    if (ready) return;

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

    /* Message */
    msg_print("Initializing the Borg...");

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

    /*** Input/Output ***/
        
    /* Remember the "normal" event scanner */
    Term_xtra_hook_old = Term->xtra_hook;
    
    /* Cheat -- drop a hook into the "event scanner" */
    Term->xtra_hook = Term_xtra_borg;


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

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

    /* Make the array of grids */
    C_MAKE(auto_grids, AUTO_MAX_Y, auto_grid*);

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

    /* Hack -- array of "nearby" grids */
    C_MAKE(near_x, NEAR_MAX, byte);
    C_MAKE(near_y, NEAR_MAX, byte);


    /*** Flow queue ***/
    
    /* The head is always first */
    auto_flow_head.flow = 0;

    /* The tail is always last */
    auto_flow_tail.flow = MAX_SHORT;
    
    /* Empty queue */
    auto_flow_head.next = &auto_flow_tail;
    auto_flow_tail.prev = &auto_flow_head;
    

    /*** Item/Ware arrays ***/
    
    /* Make some item/ware arrays */
    C_MAKE(auto_items, INVEN_TOTAL, auto_item);
    C_MAKE(auto_wares, 24, auto_item);


    /*** Item description parsers ***/
    
    /* Count the useful "item kinds" */
    for (k = 0; k < MAX_K_IDX; k++) {

	/* Get the kind */
	inven_kind *k_ptr = &k_list[k];
	
	/* Skip non-items */
	if (!k_ptr->tval) continue;
	
	/* Skip "dungeon terrain" objects */
	if (k_ptr->tval >= TV_GOLD) continue;

	/* Skip "special amulets" and "special rings" */
	if (((k_ptr->tval == TV_AMULET) || (k_ptr->tval == TV_RING)) &&
	    (k_ptr->flags3 & TR3_INSTA_ART)) continue;
	
	/* Count the items */
	i_size++;
    }

    /* Allocate the "item parsing arrays" */
    C_MAKE(i_kind, i_size, u16b);
    C_MAKE(i_single, i_size, cptr);
    C_MAKE(i_plural, i_size, cptr);
        
    /* Analyze the "item kinds" -- Hack -- reverse order */
    for (i = 0, k = MAX_K_IDX-1; k >= 0; k--) {

	inven_type hack;
	
	/* Get the kind */
	inven_kind *k_ptr = &k_list[k];
	
	/* Skip non-items */
	if (!k_ptr->tval) continue;
	
	/* Skip "dungeon terrain" objects */
	if (k_ptr->tval >= TV_GOLD) continue;

	/* Skip "special amulets" and "special rings" */
	if (((k_ptr->tval == TV_AMULET) || (k_ptr->tval == TV_RING)) &&
	    (k_ptr->flags3 & TR3_INSTA_ART)) continue;
	
	/* Save the object kind */
	i_kind[i] = k;

	/* Hack -- make an item */
	invcopy(&hack, k);
	
	/* Describe a "plural" object */
	hack.number = 2;
	objdes_store(buf, &hack, FALSE);
	i_plural[i] = string_make(buf);

	/* Describe a "singular" object */
	hack.number = 1;
	objdes_store(buf, &hack, FALSE);
	i_single[i] = string_make(buf);
	
	/* Advance */
	i++;
    }
    
    /* Hack -- Impossible level */
    auto_depth = 9999;

    borg_initvar();

    /* Done initialization */
    msg_print("done.");

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

/* FD; init some more global variables */
void borg_initvar()
{
int i,j;

protevil = 0;
drained_stat=0;
pclass = PCLASS_PALADIN;
sclass = SCLASS_PRIEST;
/* manacost[class][book][spell] */
/* initialized in borg.h */

ready = FALSE;	/* Initialized */

state = 0;		/* Current "state" */

state_store = 0;	/* Store symbol, if any */

goal = 0;		/* Current "goal" */

goal_level = 0;	/* Desired stair direction (if any) */

cheat_inven = TRUE;
cheat_equip = TRUE;

auto_began = 0L;	/* When this level began */
auto_shock = 0L;	/* When last "shocked" */

auto_recall = 0L;	/* When we read word of recall */

near_n = 0;		/* Size of the "near" array */

/* initialized in borg.h */
/*
auto_str_take = "^+:;$*?!_-\\|/\"=~{([])},s";
auto_str_kill = "ABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrtuvwxyz&";
*/

do_watch_breeders=0L;	/* timer for breeding monsters */
key_head=0;		/* queue of keypresses */
key_tail=0;

/* spellbook variables */
known_spells=0;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
spells_known[i][j]=FALSE;

/* change it's name */
borg_keypress('C');
borg_keypress('c');
borg_keypress('P'); borg_keypress('a'); borg_keypress('r');
borg_keypress('s'); borg_keypress('i'); borg_keypress('v');
borg_keypress('a'); borg_keypress('l'); borg_keypress(' ');
borg_keypress('v'); borg_keypress('1'); borg_keypress('.');
borg_keypress('0'); borg_keypress('\n'); borg_keypress(ESCAPE);

}


/* 
 * Hack -- interact with the Borg.  Includes "initialization" call.
 */
void borg_mode(void)
{
    char cmd;


    /* Not initialized? */
    if (!ready) return;
    

    /* Hack -- Never interupt the "special states" */
    if (state && (state != STATE_START)) return;
    
    /* Clear the state */
    state = 0;
    
    /* Get a special command */    
    if (!get_com("Borg command: ", &cmd)) return;

    
    /* Command: Resume */
    if (cmd == 'r') {
	wizard = FALSE;
	state = STATE_START;
    }

    /* Command: Resume, but Wipe goals */
    else if (cmd == 'w') {
	wizard = FALSE;
	state = STATE_START;
	goal_level = 0;
	goal = 0;
    }
    
    /* Command: Restart -- use an "illegal" level */
    else if (cmd == 'z') {
	wizard = FALSE;
		state = STATE_START;
		goal_level = 0;
		goal = 0;
		auto_depth = 9999;
#ifdef FRITS
		do_watch_breeders=0L; /* counter for lice etc. */
#endif /* FRITS */
	    }


	    /* Command: toggle "cheat" for "inventory" */
	    else if (cmd == 'i') {
		cheat_inven = !cheat_inven;
	    }
	    
	    /* Command: toggle "cheat" for "equipment" */
	    else if (cmd == 'e') {
		cheat_equip = !cheat_equip;
	    }
	    

	    /* Command: Show all Rooms (Containers) */
	    else if (cmd == 's') {

		int n, k, x, y;

		auto_room *ar;

		/* Examine all the rooms */
		for (n = 0; n < auto_room_max; n++) {

		    int i = 0;
		    
		    /* Access the n'th room */
		    ar = &auto_rooms[n];

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

		    /* Hack -- hilite the room -- count draws */
		    for (y = ar->y1; y <= ar->y2; y++) {	    
			for (x = ar->x1; x <= ar->x2; x++) {	    
			    if (panel_contains(y, x)) i++;
			    mh_print_rel('*', TERM_RED, 0, y, x);
			}
		    }

		    /* Nothing done -- skip this room */
		    if (!i) continue;

		    /* Describe and wait */
		    Term_putstr(0, 0, -1, TERM_WHITE,
				format("Room %d (%dx%d). ", n,
				(1 + ar->x2 - ar->x1), (1 + ar->y2 - ar->y1)));

		    /* Get a key */
		    k = inkey();
		    
		    /* Hack -- fix the room */
		    for (y = ar->y1; y <= ar->y2; y++) {	    
			for (x = ar->x1; x <= ar->x2; x++) {	    
			    lite_spot(y, x);
			}
		    }
		    
		    /* Flush the erase */
		    Term_fresh();

		    /* Leave this loop */
		    if (k == ESCAPE) break;
		}
	    }

	    /* Command: Rooms (Containers) */
	    else if (cmd == 'c') {

		int n, w, h;

		auto_room *ar;

		int used = 0, n_1x1 = 0, n_1xN = 0, n_Nx1 = 0;
		int n_2x2 = 0, n_2xN = 0, n_Nx2 = 0, n_NxN = 0;
		
		/* Examine all the rooms */
		for (n = 0; n < AUTO_ROOMS; n++) {

		    /* Access the n'th room */
		    ar = &auto_rooms[n];

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

		    /* Extract the "size" */
		    w = 1 + ar->x2 - ar->x1;
		    h = 1 + ar->y2 - ar->y1;

		    /* Count the "singles" */
		    if ((w == 1) && (h == 1)) n_1x1++;
		    else if (w == 1) n_1xN++;
		    else if (h == 1) n_Nx1++;
		    else if ((w == 2) && (h == 2)) n_2x2++;
		    else if (w == 2) n_2xN++;
		    else if (h == 2) n_Nx2++;
		    else n_NxN++;
		}


		/* Display some info */	
		msg_print(format("Rooms: %d/%d used.", used, auto_room_max));
		msg_print(format("Corridors: 1xN (%d), Nx1 (%d)", n_1xN, n_Nx1));
		msg_print(format("Thickies: 2x2 (%d), 2xN (%d), Nx2 (%d)",
				 n_2x2, n_2xN, n_Nx2));
		msg_print(format("Singles: %d.  Normals: %d.", n_1x1, n_NxN));
		msg_print(NULL);
	    }

	    /* Command: Grid Info */
	    else if (cmd == 'g') {

		int x, y, n;

		auto_grid *ag;
		auto_room *ar;

		int tg = 0;
		int tr = 0;

		int cc[16];
		
		/* Count the crossing factors */
		cc[0] = cc[1] = cc[2] = cc[3] = cc[4] = cc[5] = cc[6] = cc[7] = cc[8] = 0;
		
		/* Total explored grids */
		for (y = 0; y < AUTO_MAX_Y; y++) {
		    for (x = 0; x < AUTO_MAX_X; x++) {

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

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

			/* Count them */
			tg++;

			/* Count the rooms this grid is in */
			for (n = 0, ar = room(1,x,y); ar && (n<16); ar = room(0,0,0)) n++;

			/* Hack -- Mention some locations */
			if ((n > 1) && !cc[n]) {
			    msg_print(format("The grid at %d,%d is in %d rooms.", x, y, n));
			}

			/* Count them */
			if (n > 0) tr++;
			
			/* Count the number of grids in that many rooms */
			cc[n]++;
		    }
		}

		/* Display some info */	
		msg_print(format("Grids: %d known, %d in rooms.", tg, tr));
		msg_print(format("Roomies: %d, %d, %d, %d, %d, %d, %d, %d, %d.",
				 cc[0], cc[1], cc[2], cc[3], cc[4],
				 cc[5], cc[6], cc[7], cc[8]));
		msg_print(NULL);
	    }

#ifdef FRITS
	    else if (cmd == 'l') {
#ifdef FRITSDEBUG
	      logging=1-logging;
              if (logging == 0) {
                 msg_print("Borg: logging off");
                 fprintf(logfile,"\nStop logging at time %d\n",c_t);
                 fclose(logfile);
              } else {
                 msg_print("Borg: logging on, file is borglog");
                 if ((logfile=fopen("borglog","a"))==NULL) {
                    msg_print("ERROR: can't open borglog...");
                    logging=0;
                 } else {
                    fprintf(logfile,"\n\nStart logging at time %d\n",c_t);
                 }
              }
#else
	      msg_print("Borg: recompile with -DFRITSDEBUG to log the Borg");
#endif /* FRITSDEBUG */
            }
#endif
}

#endif /* AUTO_PLAY */
