/* File: init2.c */

/* Purpose: Initialization (part 2) -BEN- */

#include "angband.h"


/*
 * This file is used to initialize various variables and arrays for the
 * Angband game.  Note the use of "fd_read()" and "fd_write()" to bypass
 * the common limitation of "read()" and "write()" to only 32767 bytes
 * at a time.
 *
 * Several of the arrays for Angband are built from "template" files in
 * the "lib/file" directory, from which quick-load binary "image" files
 * are constructed whenever they are not present in the "lib/data"
 * directory, or if those files become obsolete, if we are allowed.
 *
 * Warning -- the "ascii" file parsers use a minor hack to collect the
 * name and text information in a single pass.  Thus, the game will not
 * be able to load any template file with more than 20K of names or 60K
 * of text, even though technically, up to 64K should be legal.
 *
 * The "init1.c" file is used only to parse the ascii template files,
 * to create the binary image files.  If you include the binary image
 * files instead of the ascii template files, then you can undefine
 * "ALLOW_TEMPLATES", saving about 20K by removing "init1.c".  Note
 * that the binary image files are extremely system dependant.
 */



/*
 * Find the default paths to all of our important sub-directories.
 *
 * The purpose of each sub-directory is described in "variable.c".
 *
 * All of the sub-directories should, by default, be located inside
 * the main "lib" directory, whose location is very system dependant.
 *
 * This function takes a writable buffer, initially containing the
 * "path" to the "lib" directory, for example, "/pkg/lib/angband/",
 * or a system dependant string, for example, ":lib:".  The buffer
 * must be large enough to contain at least 32 more characters.
 *
 * Various command line options may allow some of the important
 * directories to be changed to user-specified directories, most
 * importantly, the "info" and "user" and "save" directories,
 * but this is done after this function, see "main.c".
 *
 * In general, the initial path should end in the appropriate
 * "PATH_SEP" string.  All of the "sub-directory" paths created
 * below will also end in the "PATH_SEP" string, and, in general,
 * any replacement paths specified by the user should do the same.
 *
 * Mega-Hack -- support fat raw files under NEXTSTEP, using
 * a special "system prefix" for all the "lib/data" files.
 * This will cause the "lib/data" directory to hold one set
 * of "raw" files for each relevant platform, when necessary,
 * and still hold the "normal" files if no platform is known.
 *
 * Hack -- first we free all the strings, since this is known
 * to succeed even if the strings have not been allocated yet.
 */
void init_file_paths(char *path)
{
    char *tail;


    /*** Free everything ***/

    /* Free the main path */
    string_free(ANGBAND_DIR);

    /* Free the sub-paths */
    string_free(ANGBAND_DIR_APEX);
    string_free(ANGBAND_DIR_BONE);
    string_free(ANGBAND_DIR_DATA);
    string_free(ANGBAND_DIR_EDIT);
    string_free(ANGBAND_DIR_FILE);
    string_free(ANGBAND_DIR_HELP);
    string_free(ANGBAND_DIR_INFO);
    string_free(ANGBAND_DIR_SAVE);
    string_free(ANGBAND_DIR_USER);
    string_free(ANGBAND_DIR_XTRA);


    /*** Prepare the "path" ***/

    /* Hack -- save the main directory */
    ANGBAND_DIR = string_make(path);

    /* Prepare to append to the Base Path */
    tail = path + strlen(path);


#ifdef VM


    /*** Use "flat" paths with VM/ESA ***/

    /* Use "blank" path names */
    ANGBAND_DIR_APEX = string_make("");
    ANGBAND_DIR_BONE = string_make("");
    ANGBAND_DIR_DATA = string_make("");
    ANGBAND_DIR_EDIT = string_make("");
    ANGBAND_DIR_FILE = string_make("");
    ANGBAND_DIR_HELP = string_make("");
    ANGBAND_DIR_INFO = string_make("");
    ANGBAND_DIR_SAVE = string_make("");
    ANGBAND_DIR_USER = string_make("");
    ANGBAND_DIR_XTRA = string_make("");


#else /* VM */


    /*** Build the sub-directory names ***/

    /* Build a path name */
    sprintf(tail, "apex%s", PATH_SEP);
    ANGBAND_DIR_APEX = string_make(path);

    /* Build a path name */
    sprintf(tail, "bone%s", PATH_SEP);
    ANGBAND_DIR_BONE = string_make(path);

    /* Build a path name */
    sprintf(tail, "data%s", PATH_SEP);
    ANGBAND_DIR_DATA = string_make(path);

    /* Build a path name */
    sprintf(tail, "edit%s", PATH_SEP);
    ANGBAND_DIR_EDIT = string_make(path);

    /* Build a path name */
    sprintf(tail, "file%s", PATH_SEP);
    ANGBAND_DIR_FILE = string_make(path);

    /* Build a path name */
    sprintf(tail, "help%s", PATH_SEP);
    ANGBAND_DIR_HELP = string_make(path);

    /* Build a path name */
    sprintf(tail, "info%s", PATH_SEP);
    ANGBAND_DIR_INFO = string_make(path);

    /* Build a path name */
    sprintf(tail, "save%s", PATH_SEP);
    ANGBAND_DIR_SAVE = string_make(path);

    /* Build a path name */
    sprintf(tail, "user%s", PATH_SEP);
    ANGBAND_DIR_USER = string_make(path);

    /* Build a path name */
    sprintf(tail, "xtra%s", PATH_SEP);
    ANGBAND_DIR_XTRA = string_make(path);

#endif /* VM */


#ifdef NeXT

    /* Allow "fat binary" usage with NeXT */
    if (TRUE)
    {
	cptr next = "";

# if defined(m68k)
	next = "m68k.";
# endif

# if defined(i386)
	next = "i386.";
# endif

# if defined(sparc)
	next = "sparc.";
# endif

# if defined(hppa)
	next = "hppa.";
# endif

	/* Forget the old path name */
	string_free(ANGBAND_DIR_DATA);

	/* Build a new path name */
	sprintf(tail, "data%s%s", PATH_SEP, next);
	ANGBAND_DIR_DATA = string_make(path);
    }

#endif /* NeXT */


}



/*
 * Hack -- Explain a broken "lib" folder and quit (see below).
 *
 * XXX XXX XXX This function is "messy" because various things
 * may or may not be initialized, but the "plog()" and "quit()"
 * functions are "supposed" to work under any conditions.
 */
static void show_news_aux(cptr why)
{
    /* Why */
    plog(why);

    /* Explain */
    plog("The 'lib' directory is probably missing or broken.");

    /* More details */
    plog("Perhaps the archive was not extracted correctly.");

    /* Explain */
    plog("See the 'README' file for more information.");

    /* Quit with error */
    quit("Fatal Error.");
}


/*
 * Hack -- verify some files, and display the "news.txt" file
 *
 * This function is often called before "init_some_arrays()",
 * but after the "term.c" package has been initialized, so
 * be aware that many functions will not be "usable" yet.
 *
 * Note that this function attempts to verify the "news" file,
 * and the game aborts (cleanly) on failure.
 *
 * Note that this function attempts to verify (or create) the
 * "high score" file, and the game aborts (cleanly) on failure.
 *
 * Note that one of the most common "extraction" errors involves
 * failing to extract all sub-directories (even empty ones), such
 * as by failing to use the "-d" option of "pkunzip", or failing
 * to use the "save empty directories" option with "Compact Pro".
 * This error will often be caught by the "high score" creation
 * code below, since the "lib/apex" directory, being empty in the
 * standard distributions, is most likely to be "lost", making it
 * impossible to create the high score file.
 */
void show_news(void)
{
    int         fd = -1;

    int         mode = 0644;

    FILE        *fp;

    char        buf[1024];


    /*** Verify the "news" file ***/

    /* Access the "news.txt" file */
    strcpy(buf, ANGBAND_DIR_FILE);
    strcat(buf, "news.txt");

    /* Attempt to open the file */
    fd = fd_open(buf, O_RDONLY);

    /* Failure */
    if (fd < 0)
    {
	char why[1024];

	/* Message */
	sprintf(why, "Cannot access the '%s' file!", buf);

	/* Crash and burn */
	show_news_aux(why);
    }

    /* Close it */
    (void)fd_close(fd);


    /*** Display the "news" file ***/

    /* Clear the screen */
    clear_screen();

    /* Access the "news" file */
    strcpy(buf, ANGBAND_DIR_FILE);
    strcat(buf, "news.txt");

    /* Open the News file */
    fp = my_fopen(buf, "r");

    /* Dump */
    if (fp)
    {
	int i = 0;

	/* Dump the file to the screen */
	while (0 == my_fgets(fp, buf, 1024))
	{
	    /* Display and advance */
	    put_str(buf, i++, 0);
	}

	/* Close */
	my_fclose(fp);
    }

    /* Flush it */
    Term_fresh();


    /*** Verify (or create) the "high score" file ***/

    /* Access the high score file */
    strcpy(buf, ANGBAND_DIR_APEX);
    strcat(buf, "scores.raw");

    /* Attempt to open the high score file */
    fd = fd_open(buf, O_RDONLY);

    /* Failure */
    if (fd < 0)
    {

#if defined(MACINTOSH) && !defined(applec)
	/* Global -- "data file" */
	_feate = 'DATA';
#endif

	/* Create a new high score file */
	fd = fd_make(buf, mode);

	/* Failure */
	if (fd < 0)
	{
	    char why[1024];

	    /* Message */
	    sprintf(why, "Cannot create the '%s' file!", buf);

	    /* Crash and burn */
	    show_news_aux(why);
	}
    }

    /* Close it */
    (void)fd_close(fd);
}



/*
 * Hack -- take notes on line 23
 */
static void note(cptr str)
{
    Term_erase(0, 23, 80, 1);
    Term_putstr(20, 23, -1, TERM_WHITE, str);
    Term_fresh();
}




#ifdef ALLOW_TEMPLATES


/*
 * Hack -- help give useful error messages
 */
s16b error_idx;
s16b error_line;


/*
 * Hack -- help initialize the fake "name" and "text" arrays when
 * parsing an "ascii" template file.
 */
u16b fake_name_size;
u16b fake_text_size;


/*
 * Standard error message text
 */
static cptr err_str[8] =
{
    NULL,
    "parse error",
    "obsolete file",
    "missing record header",
    "non-sequential records",
    "invalid flag specification",
    "undefined directive",
    "out of memory"
};


#endif



/*** Initialize from binary image files ***/


/*
 * Initialize the "f_info" array, by parsing a binary "image" file
 */
static errr init_f_info_raw(int fd)
{
    header test;


    /* Read and Verify the header */
    if (fd_read(fd, (char*)(&test), sizeof(header)) ||
	(test.v_major != f_head->v_major) ||
	(test.v_minor != f_head->v_minor) ||
	(test.v_patch != f_head->v_patch) ||
	(test.v_extra != f_head->v_extra) ||
	(test.info_num != f_head->info_num) ||
	(test.info_len != f_head->info_len) ||
	(test.head_size != f_head->head_size) ||
	(test.info_size != f_head->info_size))
    {
	/* Error */
	return (-1);
    }


    /* Accept the header */
    (*f_head) = test;


    /* Allocate the "f_info" array */
    C_MAKE(f_info, f_head->info_num, feature_type);

    /* Read the "f_info" array */
    fd_read(fd, (char*)(f_info), f_head->info_size);


    /* Allocate the "f_name" array */
    C_MAKE(f_name, f_head->name_size, char);

    /* Read the "f_name" array */
    fd_read(fd, (char*)(f_name), f_head->name_size);


#ifndef DELAY_LOAD_F_TEXT

    /* Allocate the "f_text" array */
    C_MAKE(f_text, f_head->text_size, char);

    /* Read the "f_text" array */
    fd_read(fd, (char*)(f_text), f_head->text_size);

#endif


    /* Success */
    return (0);
}



/*
 * Initialize the "f_info" array
 *
 * Note that we let each entry have a unique "name" and "text" string,
 * even if the string happens to be empty (everyone has a unique '\0').
 */
static errr init_f_info(void)
{
    int fd;

    int mode = 0644;

    errr err;

    FILE *fp;

    /* General buffer */
    char buf[1024];


    /*** Make the header ***/

    /* Allocate the "header" */
    MAKE(f_head, header);

    /* Save the "version" */
    f_head->v_major = VERSION_MAJOR;
    f_head->v_minor = VERSION_MINOR;
    f_head->v_patch = VERSION_PATCH;
    f_head->v_extra = VERSION_TYPE;

    /* Save the "record" information */
    f_head->info_num = MAX_F_IDX;
    f_head->info_len = sizeof(feature_type);

    /* Save the size of "f_head" and "f_info" */
    f_head->head_size = sizeof(header);
    f_head->info_size = f_head->info_num * f_head->info_len;


#ifdef ALLOW_TEMPLATES

    /*** Load the binary image file ***/

    /* Access the "f_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "f_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd >= 0)
    {
	/* Attempt to parse the "raw" file */
	err = init_f_info_raw(fd);

	/* Close it */
	(void)fd_close(fd);

	/* Success */
	if (!err) return (0);

	/* Information */
	msg_print("Ignoring obsolete/defective 'f_info.raw' file.");
	msg_print(NULL);
    }


    /*** Make the fake arrays ***/

    /* Fake the size of "f_name" and "f_text" */
    fake_name_size = 20 * 1024L;
    fake_text_size = 60 * 1024L;

    /* Allocate the "f_info" array */
    C_MAKE(f_info, f_head->info_num, feature_type);

    /* Hack -- make "fake" arrays */
    C_MAKE(f_name, fake_name_size, char);
    C_MAKE(f_text, fake_text_size, char);


    /*** Load the ascii template file ***/

    /* Access the "f_info.txt" file */
    strcpy(buf, ANGBAND_DIR_EDIT);
    strcat(buf, "f_info.txt");

    /* Open the file */
    fp = my_fopen(buf, "r");

    /* Parse it */
    if (!fp) quit("Cannot open 'f_info.txt' file.");

    /* Parse the file */
    err = init_f_info_txt(fp, buf);

    /* Close it */
    my_fclose(fp);

    /* Errors */
    if (err)
    {
	cptr oops;

	/* Error string */
	oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");

	/* Oops */
	msg_format("Error %d at line %d of 'f_info.txt'.", err, error_line);
	msg_format("Record %d contains a '%s' error.", error_idx, oops);
	msg_format("Parsing '%s'.", buf);
	msg_print(NULL);

	/* Quit */
	quit("Error in 'f_info.txt' file.");
    }


    /*** Dump the binary image file ***/

#if defined(MACINTOSH) && !defined(applec)
    /* Global -- "data file" */
    _feate = 'DATA';
#endif

    /* Access the "f_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "f_info.raw");

    /* Attempt to create the raw file */
    fd = fd_make(buf, mode);

    /* Dump to the file */
    if (fd >= 0)
    {
	/* Dump it */
	fd_write(fd, (char*)(f_head), f_head->head_size);

	/* Dump the "f_info" array */
	fd_write(fd, (char*)(f_info), f_head->info_size);

	/* Dump the "f_name" array */
	fd_write(fd, (char*)(f_name), f_head->name_size);

	/* Dump the "f_text" array */
	fd_write(fd, (char*)(f_text), f_head->text_size);

	/* Close */
	(void)fd_close(fd);
    }


    /*** Kill the fake arrays ***/

    /* Free the "f_info" array */
    C_KILL(f_info, f_head->info_num, feature_type);

    /* Hack -- Free the "fake" arrays */
    C_KILL(f_name, fake_name_size, char);
    C_KILL(f_text, fake_text_size, char);

    /* Forget the array sizes */
    fake_name_size = 0;
    fake_text_size = 0;

#endif  /* ALLOW_TEMPLATES */


    /*** Load the binary image file ***/

    /* Access the "f_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "f_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd < 0) quit("Cannot load 'f_info.raw' file.");

    /* Attempt to parse the "raw" file */
    err = init_f_info_raw(fd);

    /* Close it */
    (void)fd_close(fd);

    /* Error */
    if (err) quit("Cannot parse 'f_info.raw' file.");

    /* Success */
    return (0);
}



/*
 * Initialize the "k_info" array, by parsing a binary "image" file
 */
static errr init_k_info_raw(int fd)
{
    header test;


    /* Read and Verify the header */
    if (fd_read(fd, (char*)(&test), sizeof(header)) ||
	(test.v_major != k_head->v_major) ||
	(test.v_minor != k_head->v_minor) ||
	(test.v_patch != k_head->v_patch) ||
	(test.v_extra != k_head->v_extra) ||
	(test.info_num != k_head->info_num) ||
	(test.info_len != k_head->info_len) ||
	(test.head_size != k_head->head_size) ||
	(test.info_size != k_head->info_size))
    {
	/* Error */
	return (-1);
    }


    /* Accept the header */
    (*k_head) = test;


    /* Allocate the "k_info" array */
    C_MAKE(k_info, k_head->info_num, object_kind);

    /* Read the "k_info" array */
    fd_read(fd, (char*)(k_info), k_head->info_size);


    /* Allocate the "k_name" array */
    C_MAKE(k_name, k_head->name_size, char);

    /* Read the "k_name" array */
    fd_read(fd, (char*)(k_name), k_head->name_size);


#ifndef DELAY_LOAD_K_TEXT

    /* Allocate the "k_text" array */
    C_MAKE(k_text, k_head->text_size, char);

    /* Read the "k_text" array */
    fd_read(fd, (char*)(k_text), k_head->text_size);

#endif


    /* Success */
    return (0);
}



/*
 * Initialize the "k_info" array
 *
 * Note that we let each entry have a unique "name" and "text" string,
 * even if the string happens to be empty (everyone has a unique '\0').
 */
static errr init_k_info(void)
{
    int fd;

    int mode = 0644;

    errr err;

    FILE *fp;

    /* General buffer */
    char buf[1024];


    /*** Make the header ***/

    /* Allocate the "header" */
    MAKE(k_head, header);

    /* Save the "version" */
    k_head->v_major = VERSION_MAJOR;
    k_head->v_minor = VERSION_MINOR;
    k_head->v_patch = VERSION_PATCH;
    k_head->v_extra = VERSION_TYPE;

    /* Save the "record" information */
    k_head->info_num = MAX_K_IDX;
    k_head->info_len = sizeof(object_kind);

    /* Save the size of "k_head" and "k_info" */
    k_head->head_size = sizeof(header);
    k_head->info_size = k_head->info_num * k_head->info_len;


#ifdef ALLOW_TEMPLATES

    /*** Load the binary image file ***/

    /* Access the "k_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "k_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd >= 0)
    {
	/* Attempt to parse the "raw" file */
	err = init_k_info_raw(fd);

	/* Close it */
	(void)fd_close(fd);

	/* Success */
	if (!err) return (0);

	/* Information */
	msg_print("Ignoring obsolete/defective 'k_info.raw' file.");
	msg_print(NULL);
    }


    /*** Make the fake arrays ***/

    /* Fake the size of "k_name" and "k_text" */
    fake_name_size = 20 * 1024L;
    fake_text_size = 60 * 1024L;

    /* Allocate the "k_info" array */
    C_MAKE(k_info, k_head->info_num, object_kind);

    /* Hack -- make "fake" arrays */
    C_MAKE(k_name, fake_name_size, char);
    C_MAKE(k_text, fake_text_size, char);


    /*** Load the ascii template file ***/

    /* Access the "k_info.txt" file */
    strcpy(buf, ANGBAND_DIR_EDIT);
    strcat(buf, "k_info.txt");

    /* Open the file */
    fp = my_fopen(buf, "r");

    /* Parse it */
    if (!fp) quit("Cannot open 'k_info.txt' file.");

    /* Parse the file */
    err = init_k_info_txt(fp, buf);

    /* Close it */
    my_fclose(fp);

    /* Errors */
    if (err)
    {
	cptr oops;

	/* Error string */
	oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");

	/* Oops */
	msg_format("Error %d at line %d of 'k_info.txt'.", err, error_line);
	msg_format("Record %d contains a '%s' error.", error_idx, oops);
	msg_format("Parsing '%s'.", buf);
	msg_print(NULL);

	/* Quit */
	quit("Error in 'k_info.txt' file.");
    }


    /*** Dump the binary image file ***/

#if defined(MACINTOSH) && !defined(applec)
    /* Global -- "data file" */
    _feate = 'DATA';
#endif

    /* Access the "k_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "k_info.raw");

    /* Attempt to create the raw file */
    fd = fd_make(buf, mode);

    /* Dump to the file */
    if (fd >= 0)
    {
	/* Dump it */
	fd_write(fd, (char*)(k_head), k_head->head_size);

	/* Dump the "k_info" array */
	fd_write(fd, (char*)(k_info), k_head->info_size);

	/* Dump the "k_name" array */
	fd_write(fd, (char*)(k_name), k_head->name_size);

	/* Dump the "k_text" array */
	fd_write(fd, (char*)(k_text), k_head->text_size);

	/* Close */
	(void)fd_close(fd);
    }


    /*** Kill the fake arrays ***/

    /* Free the "k_info" array */
    C_KILL(k_info, k_head->info_num, object_kind);

    /* Hack -- Free the "fake" arrays */
    C_KILL(k_name, fake_name_size, char);
    C_KILL(k_text, fake_text_size, char);

    /* Forget the array sizes */
    fake_name_size = 0;
    fake_text_size = 0;

#endif  /* ALLOW_TEMPLATES */


    /*** Load the binary image file ***/

    /* Access the "k_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "k_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd < 0) quit("Cannot load 'k_info.raw' file.");

    /* Attempt to parse the "raw" file */
    err = init_k_info_raw(fd);

    /* Close it */
    (void)fd_close(fd);

    /* Error */
    if (err) quit("Cannot parse 'k_info.raw' file.");

    /* Success */
    return (0);
}



/*
 * Initialize the "a_info" array, by parsing a binary "image" file
 */
static errr init_a_info_raw(int fd)
{
    header test;


    /* Read and Verify the header */
    if (fd_read(fd, (char*)(&test), sizeof(header)) ||
	(test.v_major != a_head->v_major) ||
	(test.v_minor != a_head->v_minor) ||
	(test.v_patch != a_head->v_patch) ||
	(test.v_extra != a_head->v_extra) ||
	(test.info_num != a_head->info_num) ||
	(test.info_len != a_head->info_len) ||
	(test.head_size != a_head->head_size) ||
	(test.info_size != a_head->info_size))
    {
	/* Error */
	return (-1);
    }


    /* Accept the header */
    (*a_head) = test;


    /* Allocate the "a_info" array */
    C_MAKE(a_info, a_head->info_num, artifact_type);

    /* Read the "a_info" array */
    fd_read(fd, (char*)(a_info), a_head->info_size);


    /* Allocate the "a_name" array */
    C_MAKE(a_name, a_head->name_size, char);

    /* Read the "a_name" array */
    fd_read(fd, (char*)(a_name), a_head->name_size);


#ifndef DELAY_LOAD_A_TEXT

    /* Allocate the "a_text" array */
    C_MAKE(a_text, a_head->text_size, char);

    /* Read the "a_text" array */
    fd_read(fd, (char*)(a_text), a_head->text_size);

#endif


    /* Success */
    return (0);
}



/*
 * Initialize the "a_info" array
 *
 * Note that we let each entry have a unique "name" and "text" string,
 * even if the string happens to be empty (everyone has a unique '\0').
 */
static errr init_a_info(void)
{
    int fd;

    int mode = 0644;

    errr err;

    FILE *fp;

    /* General buffer */
    char buf[1024];


    /*** Make the "header" ***/

    /* Allocate the "header" */
    MAKE(a_head, header);

    /* Save the "version" */
    a_head->v_major = VERSION_MAJOR;
    a_head->v_minor = VERSION_MINOR;
    a_head->v_patch = VERSION_PATCH;
    a_head->v_extra = VERSION_TYPE;

    /* Save the "record" information */
    a_head->info_num = MAX_A_IDX;
    a_head->info_len = sizeof(artifact_type);

    /* Save the size of "a_head" and "a_info" */
    a_head->head_size = sizeof(header);
    a_head->info_size = a_head->info_num * a_head->info_len;


#ifdef ALLOW_TEMPLATES

    /*** Load the binary image file ***/

    /* Access the "a_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "a_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd >= 0)
    {
	/* Attempt to parse the "raw" file */
	err = init_a_info_raw(fd);

	/* Close it */
	(void)fd_close(fd);

	/* Success */
	if (!err) return (0);

	/* Information */
	msg_print("Ignoring obsolete/defective 'a_info.raw' file.");
	msg_print(NULL);
    }


    /*** Make the fake arrays ***/

    /* Fake the size of "a_name" and "a_text" */
    fake_name_size = 20 * 1024L;
    fake_text_size = 60 * 1024L;

    /* Allocate the "a_info" array */
    C_MAKE(a_info, a_head->info_num, artifact_type);

    /* Hack -- make "fake" arrays */
    C_MAKE(a_name, fake_name_size, char);
    C_MAKE(a_text, fake_text_size, char);


    /*** Load the ascii template file ***/

    /* Access the "a_info.txt" file */
    strcpy(buf, ANGBAND_DIR_EDIT);
    strcat(buf, "a_info.txt");

    /* Open the file */
    fp = my_fopen(buf, "r");

    /* Parse it */
    if (!fp) quit("Cannot open 'a_info.txt' file.");

    /* Parse the file */
    err = init_a_info_txt(fp, buf);

    /* Close it */
    my_fclose(fp);

    /* Errors */
    if (err)
    {
	cptr oops;

	/* Error string */
	oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");

	/* Oops */
	msg_format("Error %d at line %d of 'a_info.txt'.", err, error_line);
	msg_format("Record %d contains a '%s' error.", error_idx, oops);
	msg_format("Parsing '%s'.", buf);
	msg_print(NULL);

	/* Quit */
	quit("Error in 'a_info.txt' file.");
    }


    /*** Dump the binary image file ***/

#if defined(MACINTOSH) && !defined(applec)
    /* Global -- "data file" */
    _feate = 'DATA';
#endif

    /* Access the "a_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "a_info.raw");

    /* Attempt to create the raw file */
    fd = fd_make(buf, mode);

    /* Dump to the file */
    if (fd >= 0)
    {
	/* Dump it */
	fd_write(fd, (char*)(a_head), a_head->head_size);

	/* Dump the "a_info" array */
	fd_write(fd, (char*)(a_info), a_head->info_size);

	/* Dump the "a_name" array */
	fd_write(fd, (char*)(a_name), a_head->name_size);

	/* Dump the "a_text" array */
	fd_write(fd, (char*)(a_text), a_head->text_size);

	/* Close */
	(void)fd_close(fd);
    }


    /*** Kill the fake arrays ***/

    /* Free the "a_info" array */
    C_KILL(a_info, a_head->info_num, artifact_type);

    /* Hack -- Free the "fake" arrays */
    C_KILL(a_name, fake_name_size, char);
    C_KILL(a_text, fake_text_size, char);

    /* Forget the array sizes */
    fake_name_size = 0;
    fake_text_size = 0;

#endif  /* ALLOW_TEMPLATES */


    /*** Load the binary image file ***/

    /* Access the "a_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "a_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd < 0) quit("Cannot open 'a_info.raw' file.");

    /* Attempt to parse the "raw" file */
    err = init_a_info_raw(fd);

    /* Close it */
    (void)fd_close(fd);

    /* Error */
    if (err) quit("Cannot parse 'a_info.raw' file.");

    /* Success */
    return (0);
}



/*
 * Initialize the "e_info" array, by parsing a binary "image" file
 */
static errr init_e_info_raw(int fd)
{
    header test;


    /* Read and Verify the header */
    if (fd_read(fd, (char*)(&test), sizeof(header)) ||
	(test.v_major != e_head->v_major) ||
	(test.v_minor != e_head->v_minor) ||
	(test.v_patch != e_head->v_patch) ||
	(test.v_extra != e_head->v_extra) ||
	(test.info_num != e_head->info_num) ||
	(test.info_len != e_head->info_len) ||
	(test.head_size != e_head->head_size) ||
	(test.info_size != e_head->info_size))
    {
	/* Error */
	return (-1);
    }


    /* Accept the header */
    (*e_head) = test;


    /* Allocate the "e_info" array */
    C_MAKE(e_info, e_head->info_num, ego_item_type);

    /* Read the "e_info" array */
    fd_read(fd, (char*)(e_info), e_head->info_size);


    /* Allocate the "e_name" array */
    C_MAKE(e_name, e_head->name_size, char);

    /* Read the "e_name" array */
    fd_read(fd, (char*)(e_name), e_head->name_size);


#ifndef DELAY_LOAD_E_TEXT

    /* Allocate the "e_text" array */
    C_MAKE(e_text, e_head->text_size, char);

    /* Read the "e_text" array */
    fd_read(fd, (char*)(e_text), e_head->text_size);

#endif


    /* Success */
    return (0);
}



/*
 * Initialize the "e_info" array
 *
 * Note that we let each entry have a unique "name" and "text" string,
 * even if the string happens to be empty (everyone has a unique '\0').
 */
static errr init_e_info(void)
{
    int fd;

    int mode = 0644;

    errr err;

    FILE *fp;

    /* General buffer */
    char buf[1024];


    /*** Make the "header" ***/

    /* Allocate the "header" */
    MAKE(e_head, header);

    /* Save the "version" */
    e_head->v_major = VERSION_MAJOR;
    e_head->v_minor = VERSION_MINOR;
    e_head->v_patch = VERSION_PATCH;
    e_head->v_extra = VERSION_TYPE;

    /* Save the "record" information */
    e_head->info_num = MAX_E_IDX;
    e_head->info_len = sizeof(ego_item_type);

    /* Save the size of "e_head" and "e_info" */
    e_head->head_size = sizeof(header);
    e_head->info_size = e_head->info_num * e_head->info_len;


#ifdef ALLOW_TEMPLATES

    /*** Load the binary image file ***/

    /* Access the "e_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "e_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd >= 0)
    {
	/* Attempt to parse the "raw" file */
	err = init_e_info_raw(fd);

	/* Close it */
	(void)fd_close(fd);

	/* Success */
	if (!err) return (0);

	/* Information */
	msg_print("Ignoring obsolete/defective 'e_info.raw' file.");
	msg_print(NULL);
    }


    /*** Make the fake arrays ***/

    /* Fake the size of "e_name" and "e_text" */
    fake_name_size = 20 * 1024L;
    fake_text_size = 60 * 1024L;

    /* Allocate the "e_info" array */
    C_MAKE(e_info, e_head->info_num, ego_item_type);

    /* Hack -- make "fake" arrays */
    C_MAKE(e_name, fake_name_size, char);
    C_MAKE(e_text, fake_text_size, char);


    /*** Load the ascii template file ***/

    /* Access the "e_info.txt" file */
    strcpy(buf, ANGBAND_DIR_EDIT);
    strcat(buf, "e_info.txt");

    /* Open the file */
    fp = my_fopen(buf, "r");

    /* Parse it */
    if (!fp) quit("Cannot open 'e_info.txt' file.");

    /* Parse the file */
    err = init_e_info_txt(fp, buf);

    /* Close it */
    my_fclose(fp);

    /* Errors */
    if (err)
    {
	cptr oops;

	/* Error string */
	oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");

	/* Oops */
	msg_format("Error %d at line %d of 'e_info.txt'.", err, error_line);
	msg_format("Record %d contains a '%s' error.", error_idx, oops);
	msg_format("Parsing '%s'.", buf);
	msg_print(NULL);

	/* Quit */
	quit("Error in 'e_info.txt' file.");
    }


    /*** Dump the binary image file ***/

#if defined(MACINTOSH) && !defined(applec)
    /* Global -- "data file" */
    _feate = 'DATA';
#endif

    /* Access the "e_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "e_info.raw");

    /* Attempt to create the raw file */
    fd = fd_make(buf, mode);

    /* Dump to the file */
    if (fd >= 0)
    {
	/* Dump it */
	fd_write(fd, (char*)(e_head), e_head->head_size);

	/* Dump the "e_info" array */
	fd_write(fd, (char*)(e_info), e_head->info_size);

	/* Dump the "e_name" array */
	fd_write(fd, (char*)(e_name), e_head->name_size);

	/* Dump the "e_text" array */
	fd_write(fd, (char*)(e_text), e_head->text_size);

	/* Close */
	(void)fd_close(fd);
    }


    /*** Kill the fake arrays ***/

    /* Free the "e_info" array */
    C_KILL(e_info, e_head->info_num, ego_item_type);

    /* Hack -- Free the "fake" arrays */
    C_KILL(e_name, fake_name_size, char);
    C_KILL(e_text, fake_text_size, char);

    /* Forget the array sizes */
    fake_name_size = 0;
    fake_text_size = 0;

#endif  /* ALLOW_TEMPLATES */


    /*** Load the binary image file ***/

    /* Access the "e_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "e_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd < 0) quit("Cannot load 'e_info.raw' file.");

    /* Attempt to parse the "raw" file */
    err = init_e_info_raw(fd);

    /* Close it */
    (void)fd_close(fd);

    /* Error */
    if (err) quit("Cannot parse 'e_info.raw' file.");

    /* Success */
    return (0);
}



/*
 * Initialize the "r_info" array, by parsing a binary "image" file
 */
static errr init_r_info_raw(int fd)
{
    header test;


    /* Read and Verify the header */
    if (fd_read(fd, (char*)(&test), sizeof(header)) ||
	(test.v_major != r_head->v_major) ||
	(test.v_minor != r_head->v_minor) ||
	(test.v_patch != r_head->v_patch) ||
	(test.v_extra != r_head->v_extra) ||
	(test.info_num != r_head->info_num) ||
	(test.info_len != r_head->info_len) ||
	(test.head_size != r_head->head_size) ||
	(test.info_size != r_head->info_size))
    {
	/* Error */
	return (-1);
    }


    /* Accept the header */
    (*r_head) = test;


    /* Allocate the "r_info" array */
    C_MAKE(r_info, r_head->info_num, monster_race);

    /* Read the "r_info" array */
    fd_read(fd, (char*)(r_info), r_head->info_size);


    /* Allocate the "r_name" array */
    C_MAKE(r_name, r_head->name_size, char);

    /* Read the "r_name" array */
    fd_read(fd, (char*)(r_name), r_head->name_size);


#ifndef DELAY_LOAD_R_TEXT

    /* Allocate the "r_text" array */
    C_MAKE(r_text, r_head->text_size, char);

    /* Read the "r_text" array */
    fd_read(fd, (char*)(r_text), r_head->text_size);

#endif


    /* Success */
    return (0);
}



/*
 * Initialize the "r_info" array
 *
 * Note that we let each entry have a unique "name" and "text" string,
 * even if the string happens to be empty (everyone has a unique '\0').
 */
static errr init_r_info(void)
{
    int fd;

    int mode = 0644;

    errr err;

    FILE *fp;

    /* General buffer */
    char buf[1024];


    /*** Make the header ***/

    /* Allocate the "header" */
    MAKE(r_head, header);

    /* Save the "version" */
    r_head->v_major = VERSION_MAJOR;
    r_head->v_minor = VERSION_MINOR;
    r_head->v_patch = VERSION_PATCH;
    r_head->v_extra = VERSION_TYPE;

    /* Save the "record" information */
    r_head->info_num = MAX_R_IDX;
    r_head->info_len = sizeof(monster_race);

    /* Save the size of "r_head" and "r_info" */
    r_head->head_size = sizeof(header);
    r_head->info_size = r_head->info_num * r_head->info_len;


#ifdef ALLOW_TEMPLATES

    /*** Load the binary image file ***/

    /* Access the "r_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "r_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd >= 0)
    {
	/* Attempt to parse the "raw" file */
	err = init_r_info_raw(fd);

	/* Close it */
	(void)fd_close(fd);

	/* Success */
	if (!err) return (0);

	/* Information */
	msg_print("Ignoring obsolete/defective 'r_info.raw' file.");
	msg_print(NULL);
    }


    /*** Make the fake arrays ***/

    /* Assume the size of "r_name" and "r_text" */
    fake_name_size = 20 * 1024L;
    fake_text_size = 60 * 1024L;

    /* Allocate the "r_info" array */
    C_MAKE(r_info, r_head->info_num, monster_race);

    /* Hack -- make "fake" arrays */
    C_MAKE(r_name, fake_name_size, char);
    C_MAKE(r_text, fake_text_size, char);


    /*** Load the ascii template file ***/

    /* Access the "r_info.txt" file */
    strcpy(buf, ANGBAND_DIR_EDIT);
    strcat(buf, "r_info.txt");

    /* Open the file */
    fp = my_fopen(buf, "r");

    /* Parse it */
    if (!fp) quit("Cannot open 'r_info.txt' file.");

    /* Parse the file */
    err = init_r_info_txt(fp, buf);

    /* Close it */
    my_fclose(fp);

    /* Errors */
    if (err)
    {
	cptr oops;

	/* Error string */
	oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");

	/* Oops */
	msg_format("Error %d at line %d of 'r_info.txt'.", err, error_line);
	msg_format("Record %d contains a '%s' error.", error_idx, oops);
	msg_format("Parsing '%s'.", buf);
	msg_print(NULL);

	/* Quit */
	quit("Error in 'r_info.txt' file.");
    }


    /*** Dump the binary image file ***/

#if defined(MACINTOSH) && !defined(applec)
    /* Global -- "data file" */
    _feate = 'DATA';
#endif

    /* Access the "r_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "r_info.raw");

    /* Attempt to create the raw file */
    fd = fd_make(buf, mode);

    /* Dump to the file */
    if (fd >= 0)
    {
	/* Dump it */
	fd_write(fd, (char*)(r_head), r_head->head_size);

	/* Dump the "r_info" array */
	fd_write(fd, (char*)(r_info), r_head->info_size);

	/* Dump the "r_name" array */
	fd_write(fd, (char*)(r_name), r_head->name_size);

	/* Dump the "r_text" array */
	fd_write(fd, (char*)(r_text), r_head->text_size);

	/* Close */
	(void)fd_close(fd);
    }


    /*** Kill the fake arrays ***/

    /* Free the "r_info" array */
    C_KILL(r_info, r_head->info_num, monster_race);

    /* Hack -- Free the "fake" arrays */
    C_KILL(r_name, fake_name_size, char);
    C_KILL(r_text, fake_text_size, char);

    /* Forget the array sizes */
    fake_name_size = 0;
    fake_text_size = 0;

#endif  /* ALLOW_TEMPLATES */


    /*** Load the binary image file ***/

    /* Access the "r_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "r_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd < 0) quit("Cannot load 'r_info.raw' file.");

    /* Attempt to parse the "raw" file */
    err = init_r_info_raw(fd);

    /* Close it */
    (void)fd_close(fd);

    /* Error */
    if (err) quit("Cannot parse 'r_info.raw' file.");

    /* Success */
    return (0);
}



/*
 * Initialize the "v_info" array, by parsing a binary "image" file
 */
static errr init_v_info_raw(int fd)
{
    header test;


    /* Read and Verify the header */
    if (fd_read(fd, (char*)(&test), sizeof(header)) ||
	(test.v_major != v_head->v_major) ||
	(test.v_minor != v_head->v_minor) ||
	(test.v_patch != v_head->v_patch) ||
	(test.v_extra != v_head->v_extra) ||
	(test.info_num != v_head->info_num) ||
	(test.info_len != v_head->info_len) ||
	(test.head_size != v_head->head_size) ||
	(test.info_size != v_head->info_size))
    {
	/* Error */
	return (-1);
    }


    /* Accept the header */
    (*v_head) = test;


    /* Allocate the "v_info" array */
    C_MAKE(v_info, v_head->info_num, vault_type);

    /* Read the "v_info" array */
    fd_read(fd, (char*)(v_info), v_head->info_size);


    /* Allocate the "v_name" array */
    C_MAKE(v_name, v_head->name_size, char);

    /* Read the "v_name" array */
    fd_read(fd, (char*)(v_name), v_head->name_size);


#ifndef DELAY_LOAD_V_TEXT

    /* Allocate the "v_text" array */
    C_MAKE(v_text, v_head->text_size, char);

    /* Read the "v_text" array */
    fd_read(fd, (char*)(v_text), v_head->text_size);

#endif

    /* Success */
    return (0);
}



/*
 * Initialize the "v_info" array
 *
 * Note that we let each entry have a unique "name" and "text" string,
 * even if the string happens to be empty (everyone has a unique '\0').
 */
static errr init_v_info(void)
{
    int fd;

    int mode = 0644;

    errr err;

    FILE *fp;

    /* General buffer */
    char buf[1024];


    /*** Make the header ***/

    /* Allocate the "header" */
    MAKE(v_head, header);

    /* Save the "version" */
    v_head->v_major = VERSION_MAJOR;
    v_head->v_minor = VERSION_MINOR;
    v_head->v_patch = VERSION_PATCH;
    v_head->v_extra = VERSION_TYPE;

    /* Save the "record" information */
    v_head->info_num = MAX_V_IDX;
    v_head->info_len = sizeof(feature_type);

    /* Save the size of "v_head" and "v_info" */
    v_head->head_size = sizeof(header);
    v_head->info_size = v_head->info_num * v_head->info_len;


#ifdef ALLOW_TEMPLATES

    /*** Load the binary image file ***/

    /* Access the "v_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "v_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd >= 0)
    {
	/* Attempt to parse the "raw" file */
	err = init_v_info_raw(fd);

	/* Close it */
	(void)fd_close(fd);

	/* Success */
	if (!err) return (0);

	/* Information */
	msg_print("Ignoring obsolete/defective 'v_info.raw' file.");
	msg_print(NULL);
    }


    /*** Make the fake arrays ***/

    /* Fake the size of "v_name" and "v_text" */
    fake_name_size = 20 * 1024L;
    fake_text_size = 60 * 1024L;

    /* Allocate the "k_info" array */
    C_MAKE(v_info, v_head->info_num, vault_type);

    /* Hack -- make "fake" arrays */
    C_MAKE(v_name, fake_name_size, char);
    C_MAKE(v_text, fake_text_size, char);


    /*** Load the ascii template file ***/

    /* Access the "v_info.txt" file */
    strcpy(buf, ANGBAND_DIR_EDIT);
    strcat(buf, "v_info.txt");

    /* Open the file */
    fp = my_fopen(buf, "r");

    /* Parse it */
    if (!fp) quit("Cannot open 'v_info.txt' file.");

    /* Parse the file */
    err = init_v_info_txt(fp, buf);

    /* Close it */
    my_fclose(fp);

    /* Errors */
    if (err)
    {
	cptr oops;

	/* Error string */
	oops = (((err > 0) && (err < 8)) ? err_str[err] : "unknown");

	/* Oops */
	msg_format("Error %d at line %d of 'v_info.txt'.", err, error_line);
	msg_format("Record %d contains a '%s' error.", error_idx, oops);
	msg_format("Parsing '%s'.", buf);
	msg_print(NULL);

	/* Quit */
	quit("Error in 'v_info.txt' file.");
    }


    /*** Dump the binary image file ***/

#if defined(MACINTOSH) && !defined(applec)
    /* Global -- "data file" */
    _feate = 'DATA';
#endif

    /* Access the "v_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "v_info.raw");

    /* Attempt to create the raw file */
    fd = fd_make(buf, mode);

    /* Dump to the file */
    if (fd >= 0)
    {
	/* Dump it */
	fd_write(fd, (char*)(v_head), v_head->head_size);

	/* Dump the "v_info" array */
	fd_write(fd, (char*)(v_info), v_head->info_size);

	/* Dump the "v_name" array */
	fd_write(fd, (char*)(v_name), v_head->name_size);

	/* Dump the "v_text" array */
	fd_write(fd, (char*)(v_text), v_head->text_size);

	/* Close */
	(void)fd_close(fd);
    }


    /*** Kill the fake arrays ***/

    /* Free the "v_info" array */
    C_KILL(v_info, v_head->info_num, vault_type);

    /* Hack -- Free the "fake" arrays */
    C_KILL(v_name, fake_name_size, char);
    C_KILL(v_text, fake_text_size, char);

    /* Forget the array sizes */
    fake_name_size = 0;
    fake_text_size = 0;

#endif  /* ALLOW_TEMPLATES */


    /*** Load the binary image file ***/

    /* Access the "v_info.raw" file */
    strcpy(buf, ANGBAND_DIR_DATA);
    strcat(buf, "v_info.raw");

    /* Attempt to open the "raw" file */
    fd = fd_open(buf, O_RDONLY);

    /* Process existing "raw" file */
    if (fd < 0) quit("Cannot load 'v_info.raw' file.");

    /* Attempt to parse the "raw" file */
    err = init_v_info_raw(fd);

    /* Close it */
    (void)fd_close(fd);

    /* Error */
    if (err) quit("Cannot parse 'v_info.raw' file.");

    /* Success */
    return (0);
}




/*** Initialize others ***/



/*
 * Hack -- Objects sold in the stores -- by tval/sval pair.
 */
static byte store_table[MAX_STORES-2][STORE_CHOICES][2] =
{
    {
	/* General Store */
	{ TV_FOOD, SV_FOOD_RATION },
	{ TV_FOOD, SV_FOOD_RATION },
	{ TV_FOOD, SV_FOOD_RATION },
	{ TV_FOOD, SV_FOOD_RATION },
	{ TV_FOOD, SV_FOOD_RATION },
	{ TV_FOOD, SV_FOOD_RATION },
	{ TV_FOOD, SV_FOOD_BISCUIT },
	{ TV_FOOD, SV_FOOD_JERKY },
	{ TV_FOOD, SV_FOOD_PINT_OF_WINE },
	{ TV_FOOD, SV_FOOD_PINT_OF_ALE },
	{ TV_DIGGING, SV_SHOVEL },
	{ TV_DIGGING, SV_PICK },
	{ TV_CLOAK, SV_CLOAK },
	{ TV_CLOAK, SV_CLOAK },
	{ TV_CLOAK, SV_CLOAK },
        { TV_CLOAK, SV_CLOAK },
	{ TV_POTION, SV_POTION_WATER },
        { TV_POTION, SV_POTION_WATER },
        { TV_POTION, SV_POTION_WATER },
	{ TV_POTION, SV_POTION_APPLE_JUICE },
	{ TV_LITE, SV_LITE_TORCH },
	{ TV_LITE, SV_LITE_TORCH },
	{ TV_LITE, SV_LITE_TORCH },
	{ TV_LITE, SV_LITE_TORCH },
	{ TV_LITE, SV_LITE_LANTERN },
	{ TV_LITE, SV_LITE_LANTERN },
	{ TV_FLASK, 0 },
	{ TV_FLASK, 0 },
	{ TV_FLASK, 0 },
	{ TV_FLASK, 0 },
	{ TV_FLASK, 0 },
	{ TV_FLASK, 0 }
    },

    {
	/* Armory */
	{ TV_BOOTS, SV_PAIR_OF_SOFT_LEATHER_BOOTS },
	{ TV_BOOTS, SV_PAIR_OF_SOFT_LEATHER_BOOTS },
	{ TV_BOOTS, SV_PAIR_OF_HARD_LEATHER_BOOTS },
	{ TV_BOOTS, SV_PAIR_OF_HARD_LEATHER_BOOTS },
	{ TV_HELM, SV_HARD_LEATHER_CAP },
	{ TV_HELM, SV_HARD_LEATHER_CAP },
	{ TV_HELM, SV_METAL_CAP },
	{ TV_HELM, SV_IRON_HELM },
	{ TV_SOFT_ARMOR, SV_ROBE },
	{ TV_SOFT_ARMOR, SV_ROBE },
	{ TV_SOFT_ARMOR, SV_SOFT_LEATHER_ARMOR },
	{ TV_SOFT_ARMOR, SV_SOFT_LEATHER_ARMOR },
	{ TV_SOFT_ARMOR, SV_HARD_LEATHER_ARMOR },
	{ TV_SOFT_ARMOR, SV_HARD_LEATHER_ARMOR },
	{ TV_SOFT_ARMOR, SV_HARD_STUDDED_LEATHER },
	{ TV_SOFT_ARMOR, SV_LEATHER_SCALE_MAIL },
	{ TV_SOFT_ARMOR, SV_LEATHER_SCALE_MAIL },
	{ TV_HARD_ARMOR, SV_METAL_SCALE_MAIL },
	{ TV_HARD_ARMOR, SV_CHAIN_MAIL },
	{ TV_HARD_ARMOR, SV_CHAIN_MAIL },
	{ TV_HARD_ARMOR, SV_AUGMENTED_CHAIN_MAIL },
	{ TV_HARD_ARMOR, SV_BAR_CHAIN_MAIL },
	{ TV_HARD_ARMOR, SV_METAL_BRIGANDINE_ARMOR },
	{ TV_HARD_ARMOR, SV_DOUBLE_CHAIN_MAIL },
	{ TV_GLOVES, SV_SET_OF_LEATHER_GLOVES },
	{ TV_GLOVES, SV_SET_OF_LEATHER_GLOVES },
	{ TV_GLOVES, SV_SET_OF_GAUNTLETS },
	{ TV_SHIELD, SV_SMALL_LEATHER_SHIELD },
	{ TV_SHIELD, SV_SMALL_LEATHER_SHIELD },
	{ TV_SHIELD, SV_LARGE_LEATHER_SHIELD },
	{ TV_SHIELD, SV_SMALL_METAL_SHIELD }
    },

    {
	/* Weaponsmith */
	{ TV_SWORD, SV_DAGGER },
	{ TV_SWORD, SV_MAIN_GAUCHE },
	{ TV_SWORD, SV_RAPIER },
	{ TV_SWORD, SV_SMALL_SWORD },
	{ TV_SWORD, SV_SHORT_SWORD },
	{ TV_SWORD, SV_SABRE },
	{ TV_SWORD, SV_CUTLASS },
	{ TV_SWORD, SV_TULWAR },
	{ TV_SWORD, SV_BROAD_SWORD },
	{ TV_SWORD, SV_LONG_SWORD },
	{ TV_SWORD, SV_SCIMITAR },
	{ TV_SWORD, SV_KATANA },
	{ TV_SWORD, SV_BASTARD_SWORD },
	{ TV_POLEARM, SV_SPEAR },
	{ TV_POLEARM, SV_AWL_PIKE },
	{ TV_POLEARM, SV_TRIDENT },
	{ TV_POLEARM, SV_PIKE },
	{ TV_POLEARM, SV_BEAKED_AXE },
	{ TV_POLEARM, SV_BROAD_AXE },
	{ TV_POLEARM, SV_LANCE },
	{ TV_POLEARM, SV_BATTLE_AXE },
	{ TV_HAFTED, SV_WHIP },
	{ TV_BOW, SV_SLING },
	{ TV_BOW, SV_SHORT_BOW },
	{ TV_BOW, SV_LONG_BOW },
	{ TV_BOW, SV_LIGHT_XBOW },
	{ TV_SHOT, SV_AMMO_LIGHT },
	{ TV_SHOT, SV_AMMO_NORMAL },
	{ TV_ARROW, SV_AMMO_NORMAL },
	{ TV_ARROW, SV_AMMO_NORMAL },
	{ TV_BOLT, SV_AMMO_NORMAL },
	{ TV_BOLT, SV_AMMO_NORMAL },
    },

    {
	/* Temple */
	{ TV_HAFTED, SV_WHIP },
	{ TV_HAFTED, SV_QUARTERSTAFF },
	{ TV_HAFTED, SV_MACE },
	{ TV_HAFTED, SV_BALL_AND_CHAIN },
	{ TV_HAFTED, SV_WAR_HAMMER },
	{ TV_HAFTED, SV_LUCERN_HAMMER },
	{ TV_HAFTED, SV_MORNING_STAR },
	{ TV_HAFTED, SV_FLAIL },
	{ TV_HAFTED, SV_LEAD_FILLED_MACE },
	{ TV_SCROLL, SV_SCROLL_REMOVE_CURSE },
	{ TV_SCROLL, SV_SCROLL_BLESSING },
	{ TV_SCROLL, SV_SCROLL_HOLY_CHANT },
	{ TV_POTION, SV_POTION_BOLDNESS },
	{ TV_POTION, SV_POTION_HEROISM },
	{ TV_POTION, SV_POTION_CURE_LIGHT },
	{ TV_POTION, SV_POTION_CURE_SERIOUS },
	{ TV_POTION, SV_POTION_CURE_SERIOUS },
	{ TV_POTION, SV_POTION_CURE_CRITICAL },
	{ TV_POTION, SV_POTION_CURE_CRITICAL },
	{ TV_POTION, SV_POTION_RESTORE_EXP },
	{ TV_POTION, SV_POTION_RESTORE_EXP },
	{ TV_POTION, SV_POTION_RESTORE_EXP },
	{ TV_PRAYER_BOOK, 0 },
	{ TV_PRAYER_BOOK, 0 },
	{ TV_PRAYER_BOOK, 0 },
	{ TV_PRAYER_BOOK, 0 },
	{ TV_PRAYER_BOOK, 1 },
	{ TV_PRAYER_BOOK, 1 },
	{ TV_PRAYER_BOOK, 1 },
	{ TV_PRAYER_BOOK, 2 },
	{ TV_PRAYER_BOOK, 2 },
	{ TV_PRAYER_BOOK, 3 }
    },

    {
	/* Alchemy shop */
	{ TV_SCROLL, SV_SCROLL_ENCHANT_WEAPON_TO_HIT },
	{ TV_SCROLL, SV_SCROLL_ENCHANT_WEAPON_TO_DAM },
	{ TV_SCROLL, SV_SCROLL_ENCHANT_ARMOR },
	{ TV_SCROLL, SV_SCROLL_IDENTIFY },
	{ TV_SCROLL, SV_SCROLL_IDENTIFY },
	{ TV_SCROLL, SV_SCROLL_IDENTIFY },
	{ TV_SCROLL, SV_SCROLL_IDENTIFY },
	{ TV_SCROLL, SV_SCROLL_LIGHT },
	{ TV_SCROLL, SV_SCROLL_PHASE_DOOR },
	{ TV_SCROLL, SV_SCROLL_PHASE_DOOR },
	{ TV_SCROLL, SV_SCROLL_PHASE_DOOR },
	{ TV_SCROLL, SV_SCROLL_MONSTER_CONFUSION },
	{ TV_SCROLL, SV_SCROLL_MAPPING },
	{ TV_SCROLL, SV_SCROLL_DETECT_GOLD },
	{ TV_SCROLL, SV_SCROLL_DETECT_ITEM },
	{ TV_SCROLL, SV_SCROLL_DETECT_TRAP },
	{ TV_SCROLL, SV_SCROLL_DETECT_DOOR },
	{ TV_SCROLL, SV_SCROLL_DETECT_INVIS },
	{ TV_SCROLL, SV_SCROLL_RECHARGING },
	{ TV_SCROLL, SV_SCROLL_SATISFY_HUNGER },
	{ TV_SCROLL, SV_SCROLL_WORD_OF_RECALL },
	{ TV_SCROLL, SV_SCROLL_WORD_OF_RECALL },
	{ TV_SCROLL, SV_SCROLL_WORD_OF_RECALL },
	{ TV_SCROLL, SV_SCROLL_WORD_OF_RECALL },
	{ TV_POTION, SV_POTION_RESIST_HEAT },
	{ TV_POTION, SV_POTION_RESIST_COLD },
	{ TV_POTION, SV_POTION_RES_STR },
	{ TV_POTION, SV_POTION_RES_INT },
	{ TV_POTION, SV_POTION_RES_WIS },
	{ TV_POTION, SV_POTION_RES_DEX },
	{ TV_POTION, SV_POTION_RES_CON },
	{ TV_POTION, SV_POTION_RES_CHR }
    },

    {
	/* Magic-User store */
	{ TV_RING, SV_RING_SEARCHING },
	{ TV_RING, SV_RING_FEATHER_FALL },
	{ TV_RING, SV_RING_PROTECTION },
	{ TV_AMULET, SV_AMULET_CHARISMA },
	{ TV_AMULET, SV_AMULET_SLOW_DIGEST },
	{ TV_AMULET, SV_AMULET_RESIST_ACID },
	{ TV_WAND, SV_WAND_SLOW_MONSTER },
	{ TV_WAND, SV_WAND_CONFUSE_MONSTER },
	{ TV_WAND, SV_WAND_SLEEP_MONSTER },
	{ TV_WAND, SV_WAND_MAGIC_MISSILE },
	{ TV_WAND, SV_WAND_STINKING_CLOUD },
	{ TV_WAND, SV_WAND_WONDER },
	{ TV_STAFF, SV_STAFF_LITE },
	{ TV_STAFF, SV_STAFF_MAPPING },
	{ TV_STAFF, SV_STAFF_DETECT_TRAP },
	{ TV_STAFF, SV_STAFF_DETECT_DOOR },
	{ TV_STAFF, SV_STAFF_DETECT_GOLD },
	{ TV_STAFF, SV_STAFF_DETECT_ITEM },
	{ TV_STAFF, SV_STAFF_DETECT_INVIS },
	{ TV_STAFF, SV_STAFF_DETECT_EVIL },
	{ TV_STAFF, SV_STAFF_TELEPORTATION },
	{ TV_STAFF, SV_STAFF_IDENTIFY },
	{ TV_MAGIC_BOOK, 0 },
	{ TV_MAGIC_BOOK, 0 },
	{ TV_MAGIC_BOOK, 0 },
	{ TV_MAGIC_BOOK, 0 },
	{ TV_MAGIC_BOOK, 1 },
	{ TV_MAGIC_BOOK, 1 },
	{ TV_MAGIC_BOOK, 1 },
	{ TV_MAGIC_BOOK, 2 },
	{ TV_MAGIC_BOOK, 2 },
	{ TV_MAGIC_BOOK, 3 }
    }
};




/*
 * Initialize some other arrays
 */
static errr init_other(void)
{
    int i, j, k;

    object_kind *k_ptr;
    monster_race *r_ptr;

    s16b aux[256];


    /*** Prepare the "dungeon" information ***/

    /* Allocate and Wipe the object list */
    C_MAKE(i_list, MAX_I_IDX, object_type);

    /* Allocate and Wipe the monster list */
    C_MAKE(m_list, MAX_M_IDX, monster_type);


    /* Allocate and wipe each line of the cave */
    for (i = 0; i < MAX_HGT; i++)
    {
	/* Allocate one row of the cave */
	C_MAKE(cave[i], MAX_WID, cave_type);
    }


    /*** Prepare the various "bizarre" arrays ***/

    /* Macro variables */
    C_MAKE(macro__pat, MACRO_MAX, cptr);
    C_MAKE(macro__act, MACRO_MAX, cptr);
    C_MAKE(macro__cmd, MACRO_MAX, bool);

    /* Macro action buffer */
    C_MAKE(macro__buf, 1024, char);

    /* Quark variables */
    C_MAKE(quark__str, QUARK_MAX, cptr);

    /* Message variables */
    C_MAKE(message__ptr, MESSAGE_MAX, u16b);
    C_MAKE(message__buf, MESSAGE_BUF, char);

    /* Hack -- No messages yet */
    message__tail = MESSAGE_BUF;


    /*** Prepare the Player inventory ***/

    /* Allocate it */
    C_MAKE(inventory, INVEN_TOTAL, object_type);


    /*** Prepare the Object Kind Allocator ***/

    /* Clear the aux array */
    C_WIPE(&aux, MAX_DEPTH, s16b);

    /* Make the index */
    C_MAKE(alloc_kind_index, MAX_DEPTH, s16b);

    /* Scan all of the objects */
    for (i = 1; i < MAX_K_IDX; i++)
    {
	/* Get the i'th object */
	k_ptr = &k_info[i];

	/* Scan all of the locale/chance pairs */
	for (j = 0; j < 4; j++)
	{
	    /* Count valid pairs */
	    if (k_ptr->chance[j] && (k_ptr->locale[j] < MAX_DEPTH))
	    {
		/* Count the total entries */
		alloc_kind_size++;

		/* Count the entries at each level */
		alloc_kind_index[k_ptr->locale[j]]++;
	    }
	}
    }

    /* Combine the "alloc_kind_index" entries */
    for (i = 1; i < MAX_DEPTH; i++)
    {
	alloc_kind_index[i] += alloc_kind_index[i-1];
    }

    /* Allocate the table */
    C_MAKE(alloc_kind_table, alloc_kind_size, kind_entry);

    /* Initialize the table */
    for (i = 1; i < MAX_K_IDX; i++)
    {
	/* Get the i'th object */
	k_ptr = &k_info[i];

	/* Scan all of the locale/chance pairs */
	for (j = 0; j < 4; j++)
	{
	    /* Count valid pairs */
	    if (k_ptr->chance[j] && (k_ptr->locale[j] < MAX_DEPTH))
	    {
		int r, x, y, z;

		/* Extract the chance/locale */
		r = k_ptr->chance[j];
		x = k_ptr->locale[j];

		/* Skip entries preceding our locale */
		y = (x > 0) ? alloc_kind_index[x-1] : 0;

		/* Skip previous entries at this locale */
		z = y + aux[x];

		/* Load the table entry */
		alloc_kind_table[z].k_idx = i;
		alloc_kind_table[z].locale = x;
		alloc_kind_table[z].chance = r;

		/* Another entry complete for this locale */
		aux[x]++;
	    }
	}
    }

    /* Paranoia */
    if (!alloc_kind_index[0]) quit("No town objects!");


    /*** Prepare the Monster Race Allocator ***/

    /* Clear the aux array */
    C_WIPE(&aux, MAX_DEPTH, s16b);

    /* Allocate and clear the index */
    C_MAKE(alloc_race_index, MAX_DEPTH, s16b);

    /* Scan the monsters (not the ghost) */
    for (i = 1; i < MAX_R_IDX - 1; i++)
    {
	/* Get the i'th race */
	r_ptr = &r_info[i];

	/* Process "real" monsters */
	if (r_ptr->rarity && (r_ptr->level < MAX_DEPTH))
	{
	    /* Count the total entries */
	    alloc_race_size++;

	    /* Count the entries at each level */
	    alloc_race_index[r_ptr->level]++;
	}
    }

    /* Combine the "alloc_race_index" entries */
    for (i = 1; i < MAX_DEPTH; i++)
    {
	alloc_race_index[i] += alloc_race_index[i-1];
    }

    /* Allocate the alloc_race_table */
    C_MAKE(alloc_race_table, alloc_race_size, race_entry);

    /* Scan the monsters (not the ghost) */
    for (i = 1; i < MAX_R_IDX - 1; i++)
    {
	/* Get the i'th race */
	r_ptr = &r_info[i];

	/* Count valid pairs */
	if (r_ptr->rarity && (r_ptr->level < MAX_DEPTH))
	{
	    int r, x, y, z;

	    /* Extract the level/rarity */
	    x = r_ptr->level;
	    r = r_ptr->rarity;

	    /* Skip entries preceding our locale */
	    y = (x > 0) ? alloc_race_index[x-1] : 0;

	    /* Skip previous entries at this locale */
	    z = y + aux[x];

	    /* Load the table entry */
	    alloc_race_table[z].r_idx = i;
	    alloc_race_table[z].locale = x;
	    alloc_race_table[z].chance = r;

	    /* Another entry complete for this locale */
	    aux[x]++;
	}
    }

    /* Paranoia */
    if (!alloc_race_index[0]) quit("No town monsters!");


    /*** Prepare the Stores ***/

    /* Allocate the stores */
    C_MAKE(store, MAX_STORES, store_type);

    /* Fill in each store */
    for (i = 0; i < MAX_STORES; i++)
    {
	/* Access the store */
	store_type *st_ptr = &store[i];

	/* Assume full stock */
	st_ptr->stock_size = STORE_INVEN_MAX;

	/* Allocate the stock */
	C_MAKE(st_ptr->stock, st_ptr->stock_size, object_type);

	/* No table for the black market or home */
	if ((i == 6) || (i == 7)) continue;

	/* Assume full table */
	st_ptr->table_size = STORE_CHOICES;

	/* Allocate the stock */
	C_MAKE(st_ptr->table, st_ptr->table_size, s16b);

	/* Scan the choices */
	for (k = 0; k < STORE_CHOICES; k++)
	{
	    int k_idx;

	    /* Extract the tval/sval codes */
	    int tv = store_table[i][k][0];
	    int sv = store_table[i][k][1];

	    /* Look for it */
	    for (k_idx = 1; k_idx < MAX_K_IDX; k_idx++)
	    {
		object_kind *k_ptr = &k_info[k_idx];

		/* Found a match */
		if ((k_ptr->tval == tv) && (k_ptr->sval == sv)) break;
	    }

	    /* Catch errors */
	    if (k_idx == MAX_K_IDX) continue;

	    /* Add that item index to the table */
	    st_ptr->table[st_ptr->table_num++] = k_idx;
	}
    }


    /*** Pre-allocate the basic "auto-inscriptions" ***/

    /* The "basic" feelings */
    quark_add("cursed");
    quark_add("broken");
    quark_add("average");
    quark_add("good");

    /* The "extra" feelings */
    quark_add("excellent");
    quark_add("worthless");
    quark_add("special");
    quark_add("terrible");

    /* Some extra strings */
    quark_add("uncursed");
    quark_add("on sale");


    /*** Set the "default" options ***/

    /* Scan the options */
    for (i = 0; options[i].o_desc; i++)
    {
	/* Set the "default" options */
	if (options[i].o_var) (*options[i].o_var) = options[i].o_norm;
    }


    /*** Pre-allocate space for the "format()" buffer ***/

    /* Hack -- Just call the "format()" function */
    format("%s (%s).", "Matt Craighead", MAINTAINER);


    /*** Pre-allocate space for save/restore screen ***/

    /* Save the screen */
    Term_save();

    /* Save the screen (embedded) */
    Term_save();

    /* Restore the screen (embedded) */
    Term_load();

    /* Restore the screen */
    Term_load();


    /* Success */
    return (0);
}



/*
 * Initialize various Angband variables and arrays.
 *
 * This initialization involves the parsing of special files
 * in the "lib/data" and sometimes the "lib/edit" directories.
 *
 * Note that the "template" files are initialized first, since they
 * often contain errors.  This means that macros and message recall
 * and things like that are not available until after they are done.
 */
void init_some_arrays(void)
{
    /* Initialize feature info */
    note("[Initializing arrays... (features)]");
    if (init_f_info()) quit("Cannot initialize features");

    /* Initialize object info */
    note("[Initializing arrays... (objects)]");
    if (init_k_info()) quit("Cannot initialize objects");

    /* Initialize artifact info */
    note("[Initializing arrays... (artifacts)]");
    if (init_a_info()) quit("Cannot initialize artifacts");

    /* Initialize ego-item info */
    note("[Initializing arrays... (ego-items)]");
    if (init_e_info()) quit("Cannot initialize ego-items");

    /* Initialize monster info */
    note("[Initializing arrays... (monsters)]");
    if (init_r_info()) quit("Cannot initialize monsters");

    /* Initialize feature info */
    note("[Initializing arrays... (vaults)]");
    if (init_v_info()) quit("Cannot initialize vaults");

    /* Initialize some other arrays */
    note("[Initializing arrays...]");
    if (init_other()) quit("Cannot initialize arrays");

    /* Hack -- all done */
    note("[Initializing arrays... done]");
}



