/
dirt31/
dirt31/bin/
#include <stdio.h>
#include <unistd.h>
#include "kernel.h"
#include "bootstrap.h"
#include "wizlist.h"
#include "actions.h"
#include "timing.h"
#include "oflags.h"

#define get_newline(f) while (getc(f) != '\n')

extern char *sys_errlist[];
extern int errno;

extern char *Pflags[];
extern char *WizLevels[];

static void boot_world(void);
static int  boot_players(void);
static int  boot_mobiles(FILE *f, char *fname);
static int  boot_levels(FILE *f, char *fname);
static int  boot_locations(FILE *f, char *fname);
static int  boot_messages(FILE *f, char *fname);
static int  boot_objects(FILE *f, char *fname);
static int  boot_pflags(FILE *f, char *fname);
static int  boot_verbs(FILE *f, char *fname);
static int  boot_zones(FILE *f, char *fname);
static int  boot_id_counter(void);

static Boolean read_pflags(FILE *f,PFLAGS p[]);
static char *get_string(FILE *f);

#define ID_CNT_START 200000L

char *PFT[] = { "PflagApprentice",   "MaskApprentice",
		  "PflagWizard",     "MaskWizard",
		  "PflagArchwizard", "MaskArchwizard",
		  "PflagDemigod",    "MaskDemigod",
		  "PflagGod",        "MaskGod",
		  "Comment",
		  TABLE_END};

int bootstrap(void)
{
	FILE *bootf, *f;
	int mem_used = 0;
	int tot_used = 0;
	char *y, x[128];

	boot_world();

	mem_used = boot_id_counter();

	printf("Bootstrap... 'players' used %d bytes.\n",
	       tot_used = boot_players());

	if ((bootf = fopen(BOOTSTRAP, "r")) == NULL) {
		printf("fopen: Bootstrap failed for \"" BOOTSTRAP "\".\n");
		printf("fopen: %s.\n", sys_errlist[errno]);
		return -1;
	}

	while (fgets(x, sizeof x, bootf)) {

		if (y = strchr(x, '\n'))  *y = '\0';

		printf("Bootstrap... %s ", x);

		if ((y = strchr(x, ':')) == NULL) {
			printf("\nInvalid bootstrap declaration\n");
			return -1;
		}

		if ((f = fopen(++y, "r")) == NULL) {
			printf( "---->Can't open %c file %s ", x[0], y);
		}

		switch(x[0]) {
		      case 'A': mem_used = boot_extern(f, y); break;
		      case 'C': mem_used = boot_mobiles(f, y); break;
		      case 'E': mem_used = boot_levels(f, y); break;
		      case 'H': mem_used = boot_hours(f, y); break;
		      case 'L': mem_used = boot_locations(f, y); break;
		      case 'M': mem_used = boot_messages(f, y); break;
		      case 'O': mem_used = boot_objects(f, y); break;
		      case 'P': mem_used = boot_pflags(f, y); break;
		      case 'V': mem_used = boot_verbs(f, y); break;
		      case 'W': set_wizfile(y);
			        mem_used = boot_wizlist(f, y); break;
		      case 'Z': mem_used = boot_zones(f, y); break;
		}

		if (f != NULL) fclose(f);

		if (mem_used < 0) {
			fclose(bootf);
			return mem_used;
		}

		printf("used %d bytes.\n", mem_used);
		tot_used += mem_used;
	}

	fclose(bootf);

	printf( "\nA total of %d bytes used.\n", tot_used);
}


static void boot_world(void)
{
	WORLD_REC *w = &the_world_rec;

	w->w_weather = 0;
	w->w_lock  = 0;
	w->w_mob_stop = 0;
	w->w_peace = 0;
	w->w_max_users = max_players;
	w->w_tournament = 0;
}



static int boot_players(void)
{
	int i;

	PLAYER_REC *p = players = NEW(PLAYER_REC, max_players);

	for (i = 0; i < max_players; i++, p++) {
		p->inp_handler = NULL;
		p->iamon = False;
	}

	return sizeof(PLAYER_REC) * max_players;
}



static int boot_mobiles(FILE *f, char *fname)
{
	int mem_used = 0;
	int new_mem;
	int i;
	int mobs_loaded;

	if (f == NULL)  return -1;

	numchars = max_players;

	ublock = NEW(UBLOCK_REC, char_array_len = numchars + 150);
	mem_used += sizeof(UBLOCK_REC) * char_array_len;

	for (i = 0; i < max_players; i++) {
	        setpname(i, "");
		pnum(i) = -1;
	}

	if ((new_mem = load_mobiles(-1, f, &mobs_loaded, NULL)) < 0)
	        return -1;

	num_const_chars = mobs_loaded + max_players;

	return mem_used + new_mem;
}


/* Read mobile spesifications from a file and load them into the game in the
 * zone specified. If it is -1, then use the zone specifications given in
 * the file for each mobile sepeartely. Return the number of mobiles actually
 * read, the total number of mobiles in the file,
 * and the amount of any extra memory allocated as the function value.
 * (-1 on error).
 */
int load_mobiles(int zone, FILE *f, int *loaded, int *infile)
{
	int         ct, c, i;
	int         mem_used = 0;
	int         num_ld, num_infile;
	char        x[256];
	char       *p;

	fgets(x, sizeof x, f);

	if ((num_ld = num_infile = atoi(x)) <= 0)
	        return -1;

        if (numchars + num_infile > char_array_len) {

                int oldlen = char_array_len;

                if (numchars + num_infile> GLOBAL_MAX_MOBS) return -1;

                char_array_len = numchars + 75 + num_infile;

		ublock = resize_array(ublock, sizeof(Mobile),
				      oldlen, char_array_len);

                mem_used += sizeof(Mobile) * (char_array_len - oldlen);
        }

	for (ct = numchars; ct < numchars + num_ld; ct++) {

		ptemporary(ct) = False;

		for (p = pname(ct), i = 0;
		    (c = getc(f)) != '^' && i < MNAME_LEN; *p++ = c, i++);

		*p = '\0';
		get_newline(f);

		if (fscanf(f, "%ld %d %d %ld %d %d %d %d %d %d %d",
		       &mob_id(ct), &pnum(ct),
		       &pzone(ct),
		       &ploc_reset(ct), &pstr_reset(ct),
		       &pdam_reset(ct), &pagg_reset(ct), &parmor_reset(ct),
		       &pspeed_reset(ct), &pvis_reset(ct), &pwimpy_reset(ct))

		   != 11) return -1;

		plev_reset(ct) = -1; /* Negative level for all mobiles. */
		get_newline(f);

		/* If the mobile is allready in the game, skip that record
		 */
		if (mob_id(ct) >= ID_CNT_START &&
		    !insert_entry(mob_id(ct), ct, &id_table)) {

			get_newline(f);
			get_newline(f);

			for (i = 1; i <= 2; i++) {
				while (getc(f) != '^');
			}
			get_newline(f);
			get_newline(f);

			--ct; --num_ld;
			continue;
		}

		fscanf(f, "0x%8x 0x%8x:0x%8x",
		       &sflags_reset(ct),
		       &pflags_reset(ct).h, &pflags_reset(ct).l);

		get_newline(f);

		fscanf(f, "0x%8x:0x%8x",
		       &mflags_reset(ct).h, &mflags_reset(ct).l);

		get_newline(f);

		pname_reset(ct) = COPY(pname(ct));

		pftxt(ct) = get_string(f);

		mem_used += strlen(pftxt(ct)) + strlen(pname_reset(ct)) + 2;

		if (EMPTY(pexam(ct) = get_string(f))) {
			free(pexam(ct));
			pexam(ct) = NULL;
		} else {
			mem_used += strlen(pexam(ct));
		}

		get_newline(f);

		init_intset(pinv(ct), 4);

		mem_used += get_set_mem_usage(pinv(ct));


		if (zone > -1) pzone(ct) = zone;
		zadd_mob(ct, pzone(ct));
	}

	numchars += num_ld;

	if (loaded != NULL) *loaded = num_ld;
	if (infile != NULL) *infile = num_infile;

	return mem_used;
}



static int boot_levels(FILE *f, char *fname)
{
  int i, v, ct;

  if (f == NULL) return -1;
  fscanf(f, "%d", &ct);
  get_newline(f);
  if (ct != LVL_WIZARD) {
    printf("Number of levels in levels file (%d) doesn't match LVL_WIZARD"
	   "(%d).\n", ct, LVL_WIZARD);
    return -1;
  }
  for (i = 1; i <= ct; i++) {
    fscanf(f, "%d", &v);
    get_newline(f);
    levels[i] = v;
  }
  return 0;
}




static int boot_locations(FILE *f, char *fname)
{
	int mem_used = 0;
	int new_mem;

	if (f == NULL) return -1;

	numloc = 0;
	room_data = NEW(Location, loc_array_len = 800);

	mem_used += sizeof(Location) * loc_array_len;

	if ((new_mem = load_locations(-1, f, &num_const_locs, NULL)) < 0)
                return -1;

        return mem_used + new_mem;
}


/* Load locations from file into the game. Return the number of rooms the
 * file contained, and the number actually loaded. Return mem-used for value.
 */
int load_locations(int zone, FILE *f, int *loaded, int *infile)
{
	int ct, mem_used = 0;
	int num_ld, num_infile;
	Location *r;
	char x[128];
	int i;

	fgets(x, sizeof x, f);

	if ((num_ld = num_infile = atoi(x)) <= 0)
	        return -1;

	if (numloc + num_infile > loc_array_len) {

		int oldlen = loc_array_len;

		if (numloc + num_infile> GLOBAL_MAX_LOCS) return -1;

		loc_array_len = 100 + numloc + num_infile;

		room_data = resize_array(room_data, sizeof(Location),
					 oldlen, loc_array_len);

		mem_used += sizeof(Location) * (loc_array_len - oldlen);
	}

	for (r = room_data + numloc, ct = numloc;
	     ct < numloc + num_ld; ct++, r++) {

		if (fscanf(f, "%ld %d %ld %ld %ld %ld %ld %ld",
		       &r->id,
		       &r->zone,
		       &r->r_exit_reset[0], &r->r_exit_reset[1],
		       &r->r_exit_reset[2], &r->r_exit_reset[3],
		       &r->r_exit_reset[4], &r->r_exit_reset[5])

		    != 8) return -1;

		get_newline(f);

		fscanf(f, "0x%8x", &r->r_flags_reset);
		get_newline(f);

		if (r->id >= ID_CNT_START &&
		    !insert_entry(r->id, convroom(ct), &id_table)) {

			for (i = 1; i <= 2; i++) {
				while (getc(f) != '^');
			}
			get_newline(f);

			--r; --ct; --num_ld;
			continue;
		}

		r->temporary = False;
		r->touched = True;
		r->r_short = get_string(f);
		r->r_long  = get_string(f);
		mem_used  += strlen(r->r_short) + strlen(r->r_long) + 2;

		init_intset(&r->objects, 5);
		init_intset(&r->mobiles, 3);
		init_intset(&r->exits_to_me, 3);

		if (zone > -1) r->zone = zone;
		zadd_loc(convroom(ct), r->zone);

		mem_used += get_set_mem_usage(&r->objects)
		  + get_set_mem_usage(&r->mobiles)
		  + get_set_mem_usage(&r->exits_to_me);
	}

	numloc += num_ld;

	if (loaded != NULL) *loaded = num_ld;
	if (infile != NULL) *infile = num_infile;

	return mem_used;
}



static int boot_messages(FILE *f,char *fname)
{
  int v, mem_used, ct;
  char x[32];

  if (f == NULL) return -1;
  fgets( x, sizeof x, f);
  if ((v = atoi(x)) < 0) {
    printf( "Illegal message number %d.\n", v);
    return -1;
  }
  messages = NEW(char *, v);
  mem_used = v * sizeof (char *);
  for (ct = 0; ct < v; ct++) {
    messages[ct] = get_string(f);
    mem_used += strlen(messages[ct]) + 1;
  }
  return mem_used;
}



static int boot_objects(FILE *f,char *fname)
{
	int mem_used = 0;
	int new_mem;

	if (f == NULL) return -1;

	numobs = 0;
	objects = NEW(Object, obj_array_len = 500);

	mem_used += sizeof(Object) * 500;

	if ((new_mem = load_objects(-1, f, &num_const_obs, NULL)) < 0)
	        return -1;

	return mem_used + new_mem;
}


/* Read object spesifications from a file and load them into the game in the
 * zone specified. If it is -1, then use the zone specifications given in
 * the file for each object sepeartely. Return the number of objects actually
 * read, the total number of objects in the file,
 * and the amount of any extra memory allocated as the function value.
 * (-1 on error).
 */
int load_objects(int zone, FILE *f, int *loaded, int *infile)
{
	int j, size, ct, mem_used = 0;
	int num_ld, num_infile;
	char name[64], altname[64];
	long int link;

	j = fscanf(f, "%d", &num_infile);

	if (j != 1 || (num_ld = num_infile) <= 0)
	        return -1;

	get_newline(f);

	if (numobs + num_infile > obj_array_len) {

		int oldlen = obj_array_len;

		if (numobs + num_infile> GLOBAL_MAX_OBJS) return -1;

		obj_array_len = 75 + numobs + num_infile;

		objects = resize_array(objects, sizeof(Object),
				       oldlen, obj_array_len);

		mem_used += sizeof(Object) * (obj_array_len - oldlen);
	}

	for (ct = numobs; ct < numobs + num_ld; ct++) {

		if (fscanf(f,"%s %s %d %ld %d %ld "
		         "%d %d %ld %d %d %d %ld %d %d %d %*d",
		       name, altname,
		       &ozone(ct), &obj_id(ct), &onum(ct),
		       &link,

		       &ovis_reset(ct), &ocarrf_reset(ct), &oloc_reset(ct),
		       &state_reset(ct), &odamage_reset(ct),
		       &oarmor_reset(ct), &obits_reset(ct),
		       &omaxstate(ct), &ovalue_reset(ct),
		       &osize_reset(ct))

		    != 16) return -1;

		get_newline(f);

		/* If it allready existed, skip it.
		 */
		if (obj_id(ct) >= ID_CNT_START &&
		    !insert_entry(obj_id(ct), ct, &id_table)) {

			for (j = 1; j <= 5; j++) {
				while (getc(f) != '^');
			}
			get_newline(f);
			get_newline(f);

			--ct, --num_ld;
			continue;
		}

		oname(ct) = COPY(name);
		oaltname(ct) = COPY(altname);

		if (link <= -1) olinked(ct) = -1;
		else
		if (link < numobs + num_infile) olinked(ct) = link;
		else
		if ((link = lookup_entry(link, &id_table)) != NOT_IN_TABLE) {
		        olinked(ct) = link;
			olinked(link) = ct;
		}
		else
		        olinked(ct) = -1;


		mem_used += strlen(name) + strlen(altname) + 2;

		for (j = 0; j < 4; j++) {
			olongt(ct, j) = get_string(f);
			mem_used += strlen(olongt(ct, j)) + 1;
		}

		if (zone == -1) {
			oexam_text(ct) = NULL;
			oexamine(ct) = ftell(f);

			for (j = 1; fgetc(f) != '^'; j++);
			if (j == 1)  oexamine(ct) = 0;
		}
		else {
			oexam_text(ct) = get_string(f);
			oexamine(ct) = 0;
		}

		otemporary(ct) = False;

		init_intset(oinv(ct),
			    xtstbit(obits_reset(ct), OFL_CONTAINER) ? 10 : 0);

		if (zone > -1) ozone(ct) = zone;
		zadd_obj(ct, ozone(ct));

		mem_used += get_set_mem_usage(oinv(ct));
	}

	numobs += num_ld;

	if (loaded != NULL) *loaded = num_ld;
	if (infile != NULL) *infile = num_infile;

	return mem_used;
}


static int boot_pflags(FILE *f,char *fname)
{
  WORLD_REC *w = &the_world_rec;
  PFLAGS p[10];
  int x, y;

  if (f == NULL) return -1;
  if (!read_pflags(f,p)) {
    printf( "\nIllegal syntax in %s.\n", fname );
    return -1;
  }
  for (x = y = 0; x < 5; ++x) {
    w->w_pflags[x] = p[y++];
    w->w_mask[x] = p[y++];
  }
  return 0;
}

static int boot_verbs(FILE *f,char *fname)
{
  int v, ct, mem_used;
  char x[64];

  if (f == NULL) return -1;
  fscanf(f, "%d", &v);
  mem_used = sizeof (char *) * (v + 1);
  mem_used = sizeof (int) * (v + 1);

  verbtxt = NEW(char *,v + 1);
  verbnum = NEW(int, v + 1);
  for (ct = 0; ct < v; ct++) {
    fscanf( f, "%s %d", x, &verbnum[ct]);
    verbtxt[ct] = COPY(x);
    mem_used += strlen(x) + 1;
  }
  verbtxt[ct] = NULL;
  return mem_used;
}


static int boot_zones(FILE *f, char *fname)
{
	int ct, mem_used;
	char x[64];

	if (f == NULL) return -1;

	fgets(x, sizeof x, f);

	numzon = num_const_zon = atoi(x);
	zon_array_len = num_const_zon + 20;

	zoname = NEW(ZONE, zon_array_len);

	mem_used = sizeof (ZONE) * zon_array_len;

	for (ct = 0; ct < num_const_zon; ct++) {

		fscanf(f, "%s %*d", x);
		zname(ct) = COPY(x);

		init_intset(zlocs(ct), 15);
		init_intset(zmobs(ct), 5);
		init_intset(zobjs(ct), 10);

		ztemporary(ct) = False;

		mem_used += strlen(x) + 1;
		/* add the space for the intsets later */
	}

	return mem_used;
}


static char *id_counter_file() { return ID_COUNTER; }


/* Boot ID counter and initialize ID table.
 */
static int boot_id_counter(void)
{
	int mem_used = 0;

	FILE *f = fopen(id_counter_file(), "r");

	printf("Bootstrap... ID-table & ID-counter ");

	if (f == NULL) {
		printf("(Creating %s)", id_counter_file());

		if ((f = fopen(id_counter_file(), "w")) == NULL) {
			printf("fopen: Bootstrap failed for \"%s\".\n",
			       id_counter_file());

			perror("fopen");
			exit(1);
		}

		fprintf(f, "%ld", id_counter = ID_CNT_START);
	}
	else {
		int status = fscanf(f, "%ld", &id_counter);

		if (status != 1 || id_counter < ID_CNT_START) {
			printf("Erroneous contents in %s\n",id_counter_file());
			exit(1);
		}
	}

	fclose(f);

	init_inttable(&id_table, 1024);

	printf("used %d bytes.\n", mem_used = get_table_mem_usage(&id_table));
	return mem_used;
}


Boolean save_id_counter(void)
{
	FILE *f;
	int status;

	if ((f = fopen(id_counter_file(), "w")) == NULL) {
		progerror(id_counter_file());
		return False;
	}

	status = fprintf(f, "%ld\n", id_counter);

	fclose(f);

	if (status == EOF) {
		progerror(id_counter_file());
		return False;
	}
	return True;
}


/* Is this a character legal in a Pflag ?
 */
static Boolean islegal(int c)
{
	return isalpha(c) || c == '/';
}



/*
**  Read pflags.
*/
static Boolean read_pflags(FILE *F,PFLAGS p[])
{
    int	x;	/* 0 = PX, MX, PW, MW, PA, MA, PD, MD, PG, MG */
    int y;
    char *s;
    PFLAGS f;
    int k, v;
    int c;
    int w;
    int i;
    char b[160];

    f.l = f.h = 0;
    w = -1;
    for (i = 0; i < 10; i++) {
      p[i].h = p[i].l = 0;
    }
    for (k = getc(F); k != EOF; k = getc(F)) {
	if (!islegal(k))
	    continue;

	for (s = b; islegal(k); k = getc(F))
	  *s++ = k;

	*s = 0;

	if (k != ':' || (x = tlookup(b,PFT)) == -1)
	  return False;

	if (x >= 10) {
	  while ((k = getc(F)) != EOF && k != '\n');
	  if (k == EOF)
	    break;
	  continue;
	}

	if (x < w)
	    return False;

	y = 0;
	w = x;

	while ((c = getc(F)) != ';') {
	    if (c == EOF)
		return False;
	    if (c == '+') {
		y = 1;
		continue;
	    } else if (c == '-') {
		y = -1;
		continue;
	    } else if (!islegal(c)) {
		y = 0;
		continue;
	    }

	    for (s = b; islegal(c);c = getc(F)) {
		*s++ = c;
	    }
	    ungetc(c,F);
	    *s = 0;
	    if ((v = tlookup(b,Pflags)) == -1) {
	      printf("\nUnknown Pflag: %s.", b);
	      return False;
	    }

	    if (v >= 32) {
	      v -= 32;
	      k = 1 << v;
	      if (y > 0) {
		p[w].h |= k;
	      } else if (y < 0) {
		p[w].h &= ~k;
	      } else if ((w & 1) == 0) {
		for (i = w; i < 10; i++) {
		  p[i].h |= k;
		}
	      } else {
		for (i = w; i < 10; i += 2) {
		  p[i].h |= k;
		}
	      }
	    } else {
	      k = 1 << v;
	      if (y > 0) {
		p[w].l |= k;
	      } else if (y < 0) {
		p[w].l &= ~k;
	      } else if ((w & 1) == 0) {
		for (i = w; i < 10; i++) {
		  p[i].l |= k;
		}
	      } else {
		for (i = w; i < 10; i += 2) {
		  p[i].l |= k;
		}
	      }
	    }
	    y = 0;
	}
    }

    return(w >= 0);
}

static char *get_string(FILE *f)
{
  char *y;
  char x[2048];

  for (y = x; (*y = fgetc(f)) != '^'; y++);
  *y = 0;
  get_newline(f);
  return COPY(x);
}