/
circle30bpl5/
circle30bpl5/lib/
circle30bpl5/lib/etc/
circle30bpl5/lib/misc/
circle30bpl5/lib/plrobjs/
circle30bpl5/lib/plrobjs/K-O/
circle30bpl5/lib/plrobjs/P-T/
circle30bpl5/lib/world/
circle30bpl5/lib/world/shp/
/* ************************************************************************
*   File: scheck.c                                      Part of CircleMUD *
*  Usage: Circle world/mob/obj file syntax checker			  *
*                                                                         *
*  All rights reserved.  See license.doc for complete information.        *
*                                                                         *
*  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */

#define __DB_C__

#define log(msg) puts(msg)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#include "../structs.h"
#include "../db.h"
#include "../utils.h"

/**************************************************************************
*  declarations of most of the 'global' variables                         *
************************************************************************ */

struct room_data *world = NULL;		/* array of rooms		*/
int	top_of_world = 0;		/* ref to top element of world	*/

struct char_data *character_list = NULL; /* global linked list of chars	*/
struct index_data *mob_index;		/* index table for mobile file	*/
struct char_data *mob_proto;		/* prototypes for mobs		*/
int	top_of_mobt = 0;		/* top of mobile index table	*/

struct obj_data *object_list = NULL;    /* global linked list of objs	*/
struct index_data *obj_index;		/* index table for object file	*/
struct obj_data *obj_proto;		/* prototypes for objs		*/
int	top_of_objt = 0;		/* top of object index table	*/

struct zone_data *zone_table;		/* zone table			*/
int	top_of_zone_table = 0;		/* top element of zone tab	*/
struct message_list fight_messages[MAX_MESSAGES]; /* fighting messages	*/

struct player_index_element *player_table = NULL; /* index to plr file	*/
FILE *player_fl = NULL;			/* file desc of player file	*/
int	top_of_p_table = 0;		/* ref to top of table		*/
int	top_of_p_file = 0;		/* ref of size of p file	*/
long	top_idnum = 0;			/* highest idnum in use		*/

int	no_mail = 0;			/* mail disabled?		*/
int	mini_mud = 0;			/* mini-mud mode?		*/
int	no_rent_check = 0;		/* skip rent check on boot?	*/
long	boot_time = 0;			/* time of mud boot		*/
int	restrict = 0;			/* level of game restriction	*/
sh_int	r_mortal_start_room;		/* rnum of mortal start room	*/
sh_int	r_immort_start_room;		/* rnum of immort start room	*/
sh_int	r_frozen_start_room;		/* rnum of frozen start room	*/

char	*credits = NULL;		/* game credits			*/
char	*news = NULL;			/* mud news			*/
char	*motd = NULL;			/* message of the day - mortals */
char	*imotd = NULL;			/* message of the day - immorts */
char	*help = NULL;			/* help screen			*/
char	*info = NULL;			/* info page			*/
char	*wizlist = NULL;		/* list of higher gods		*/
char	*immlist = NULL;		/* list of peon gods		*/
char	*background = NULL;		/* background story		*/
char	*handbook = NULL;		/* handbook for new immortals	*/
char	*policies = NULL;		/* policies page		*/

FILE *help_fl = NULL;			/* file for help text		*/
struct help_index_element *help_index = 0; /* the help table		*/
int	top_of_helpt;			/* top of help index table	*/

struct time_info_data time_info;	/* the infomation about the time    */
struct weather_data weather_info;	/* the infomation about the weather */
struct player_special_data dummy_mob;	/* dummy spec area for mobs	*/
struct reset_q_type reset_q;		/* queue of zones to be reset	*/

/* local functions */
void	setup_dir(FILE *fl, int room, int dir);
void	index_boot(int mode);
void	discrete_load(FILE *fl, int mode);
void	parse_room(FILE *fl, int virtual_nr);
void	parse_mobile(FILE *mob_f, int nr);
char	*parse_object(FILE *obj_f, int nr);
void	load_zones(FILE *fl);
void	assign_mobiles(void);
void	assign_objects(void);
void	assign_rooms(void);
void	assign_the_shopkeepers(void);
void	build_player_index(void);
void	char_to_store(struct char_data *ch, struct char_file_u *st);
void	store_to_char(struct char_file_u *st, struct char_data *ch);
int	is_empty(int zone_nr);
int	file_to_string(char *name, char *buf);
int	file_to_string_alloc(char *name, char **buf);
void	check_start_rooms(void);
void	renum_world(void);
void	renum_zone_table(void);
void	reset_time(void);
void	clear_char(struct char_data *ch);

/* external functions */
void	load_messages(void);
void	weather_and_time(int mode);
void	mag_assign_spells(void);
void	boot_social_messages(void);
void	update_obj_file(void); /* In objsave.c */
void	sort_commands(void);
void	load_banned(void);
void	Read_Invalid_List(void);
struct help_index_element *build_help_index(FILE *fl, int *num);


/*************************************************************************
*  routines for booting the system                                       *
*********************************************************************** */

/* body of the booting system */
void	main()
{
   int	i;

   log("Boot db -- BEGIN.");

   log("Loading zone table.");
   index_boot(DB_BOOT_ZON);

   log("Loading rooms.");
   index_boot(DB_BOOT_WLD);

   log("Renumbering rooms.");
   renum_world();

   log("Loading mobs and generating index.");
   index_boot(DB_BOOT_MOB);

   log("Loading objs and generating index.");
   index_boot(DB_BOOT_OBJ);

   log("Renumbering zone table.");
   renum_zone_table();

   log("Boot db -- DONE.");
}



/* function to count how many hash-mark delimited records exist in a file */
int	count_hash_records(FILE *fl)
{
   char	buf[128];
   int	count = 0;

   while (fgets(buf, 128, fl))
      if (*buf == '#')
	 count++;

   return (count - 1);
}



void	index_boot(int mode)
{
   char	*index_filename, *prefix;
   FILE * index, *db_file;
   int	rec_count = 0;

   switch (mode) {
   case DB_BOOT_WLD	: prefix = WLD_PREFIX; break;
   case DB_BOOT_MOB	: prefix = MOB_PREFIX; break;
   case DB_BOOT_OBJ	: prefix = OBJ_PREFIX; break;
   case DB_BOOT_ZON	: prefix = ZON_PREFIX; break;
   default:
      log("SYSERR: Unknown subcommand to index_boot!");
      exit(1);
      break;
   }

   if (mini_mud)
      index_filename = MINDEX_FILE;
   else
      index_filename = INDEX_FILE;

   sprintf(buf2, "%s/%s", prefix, index_filename);

   if (!(index = fopen(buf2, "r"))) {
      sprintf(buf1, "Error opening index file '%s'", buf2);
      perror(buf1);
      exit(1);
   }

   /* first, count the number of records in the file so we can malloc */
   fscanf(index, "%s\n", buf1);
   while (*buf1 != '$') {
      sprintf(buf2, "%s/%s", prefix, buf1);
      if (!(db_file = fopen(buf2, "r"))) {
	 perror(buf2);
	 exit(1);
      } else {
	 if (mode == DB_BOOT_ZON)
	    rec_count++;
	 else
	    rec_count += count_hash_records(db_file);
      }

      fclose(db_file);
      fscanf(index, "%s\n", buf1);
   }

   if (!rec_count) {
      log("SYSERR: boot error - 0 records counted");
      exit(1);
   }

   rec_count++;

   switch (mode) {
   case DB_BOOT_WLD :
      CREATE(world, struct room_data, rec_count);
      break;
   case DB_BOOT_MOB :
      CREATE(mob_proto, struct char_data, rec_count);
      CREATE(mob_index, struct index_data, rec_count);
      break;
   case DB_BOOT_OBJ :
      CREATE(obj_proto, struct obj_data, rec_count);
      CREATE(obj_index, struct index_data, rec_count);
      break;
   case DB_BOOT_ZON :
      CREATE(zone_table, struct zone_data, rec_count);
      break;
   }

   rewind(index);
   fscanf(index, "%s\n", buf1);
   while (*buf1 != '$') {
      sprintf(buf2, "%s/%s", prefix, buf1);
      if (!(db_file = fopen(buf2, "r"))) {
	 perror(buf2);
	 exit(1);
      }

      switch (mode) {
      case DB_BOOT_WLD	: 
      case DB_BOOT_OBJ	: 
      case DB_BOOT_MOB	: discrete_load(db_file, mode); break;
      case DB_BOOT_ZON	: load_zones(db_file); break;
      }

      fclose(db_file);
      fscanf(index, "%s\n", buf1);
   }
}


void	discrete_load(FILE *fl, int mode)
{
   int	nr = -1, last = 0;
   char	line[256];

   char *modes[] = { "world", "mob", "obj" };

   for (; ; ) {
      if (mode != DB_BOOT_OBJ || nr < 0)
	 if (!get_line(fl, line)) {
	    fprintf(stderr, "Format error after %s #%d\n", modes[mode], nr);
	    exit(1);
	 }

      if (*line == '$')
	 return;

      if (*line == '#') {
	 last = nr;
	 if (sscanf(line, "#%d", &nr) != 1) {
	    fprintf(stderr, "Format error after %s #%d\n", modes[mode], last);
	    exit(1);
	 }

	 if (nr >= 99999) 
	    return;
	 else switch (mode) {
	    case DB_BOOT_WLD:	parse_room(fl, nr); break;
	    case DB_BOOT_MOB:	parse_mobile(fl, nr); break;
	    case DB_BOOT_OBJ:	strcpy(line, parse_object(fl, nr)); break;
	 }
      } else {
         fprintf(stderr, "Format error in %s file near %s #%d\n",
		 modes[mode], modes[mode], nr);
	 fprintf(stderr, "Offending line: '%s'\n", line);
	 exit(1);
      }
   }
}



/* load the rooms */
void	parse_room(FILE *fl, int virtual_nr)
{
   static int	room_nr = 0, zone = 0;
   int	t[10], i;
   char	line[256];
   struct extra_descr_data *new_descr;

   sprintf(buf2, "room #%d", virtual_nr);

   if (virtual_nr <= (zone ? zone_table[zone-1].top : -1)) {
      fprintf(stderr, "Room #%d is below zone %d.\n", virtual_nr, zone);
      exit(1);
   }

   while (virtual_nr > zone_table[zone].top)
      if (++zone > top_of_zone_table) {
	 fprintf(stderr, "Room %d is outside of any zone.\n", virtual_nr);
	 exit(1);
      }

   world[room_nr].zone = zone;
   world[room_nr].number = virtual_nr;
   world[room_nr].name = fread_string(fl, buf2);
   world[room_nr].description = fread_string(fl, buf2);

   if (!get_line(fl, line) || sscanf(line, " %d %d %d ", t, t+1, t+2) != 3) {
      fprintf(stderr, "Format error in room #%d\n", virtual_nr);
      exit(1);
   }

   /* t[0] is the zone number; ignored with the zone-file system */
   world[room_nr].room_flags = t[1];
   world[room_nr].sector_type = t[2];

   world[room_nr].func = NULL;
   world[room_nr].contents = NULL;
   world[room_nr].people = NULL;
   world[room_nr].light = 0; /* Zero light sources */

   for (i = 0; i < NUM_OF_DIRS; i++)
      world[room_nr].dir_option[i] = NULL;

   world[room_nr].ex_description = NULL;

   sprintf(buf, "Format error in room #%d (expecting D/E/S)", virtual_nr);

   for (; ; ) {
      if (!get_line(fl, line)) {
	 fprintf(stderr, "%s\n", buf);
	 exit(1);
      }

      switch(*line) {
      case 'D':
	 setup_dir(fl, room_nr, atoi(line + 1));
	 break;
      case 'E':
	 CREATE(new_descr, struct extra_descr_data, 1);
	 new_descr->keyword = fread_string(fl, buf2);
	 new_descr->description = fread_string(fl, buf2);
	 new_descr->next = world[room_nr].ex_description;
	 world[room_nr].ex_description = new_descr;
	 break;
      case 'S': /* end of room */
	 top_of_world = room_nr++;
	 return;
	 break;
      default:
	 fprintf(stderr, "%s\n", buf);
	 exit(1);
	 break;
      }
   }
}



/* read direction data */
void	setup_dir(FILE *fl, int room, int dir)
{
   int	t[5];
   char	line[256];

   sprintf(buf2, "room #%d, direction D%d", world[room].number, dir);

   CREATE(world[room].dir_option[dir], struct room_direction_data, 1);
   world[room].dir_option[dir]->general_description = fread_string(fl, buf2);
   world[room].dir_option[dir]->keyword = fread_string(fl, buf2);

   if (!get_line(fl, line)) {
      fprintf(stderr, "Format error, %s\n", buf2);
      exit(1);
   }

   if (sscanf(line, " %d %d %d ", t, t+1, t+2) != 3) {
      fprintf(stderr, "Format error, %s\n", buf2);
      exit(1);
   }

   if (t[0] == 1)
      world[room].dir_option[dir]->exit_info = EX_ISDOOR;
   else if (t[0] == 2)
      world[room].dir_option[dir]->exit_info = EX_ISDOOR | EX_PICKPROOF;
   else
      world[room].dir_option[dir]->exit_info = 0;

   world[room].dir_option[dir]->key = t[1];
   world[room].dir_option[dir]->to_room = t[2];
}


/* resolve all vnums into rnums in the world */
void	renum_world(void)
{
   register int	room, door;

   for (room = 0; room <= top_of_world; room++)
      for (door = 0; door < NUM_OF_DIRS; door++)
	 if (world[room].dir_option[door])
	    if (world[room].dir_option[door]->to_room != NOWHERE)
	       world[room].dir_option[door]->to_room = 
	           real_room(world[room].dir_option[door]->to_room);
}


/* resulve vnums into rnums in the zone reset tables */
void	renum_zone_table(void)
{
   int	zone, comm, a, b;

   for (zone = 0; zone <= top_of_zone_table; zone++)
      for (comm = 0; zone_table[zone].cmd[comm].command != 'S'; comm++) {
	 a = b = 0;
	 switch (zone_table[zone].cmd[comm].command) {
	 case 'M':
	    a = zone_table[zone].cmd[comm].arg1 = 
	        real_mobile(zone_table[zone].cmd[comm].arg1);
	    b = zone_table[zone].cmd[comm].arg3 = 
	        real_room(zone_table[zone].cmd[comm].arg3);
	    break;
	 case 'O':
	    a = zone_table[zone].cmd[comm].arg1 = 
	        real_object(zone_table[zone].cmd[comm].arg1);
	    if (zone_table[zone].cmd[comm].arg3 != NOWHERE)
	       b = zone_table[zone].cmd[comm].arg3 = 
	           real_room(zone_table[zone].cmd[comm].arg3);
	    break;
	 case 'G':
	    a = zone_table[zone].cmd[comm].arg1 = 
	        real_object(zone_table[zone].cmd[comm].arg1);
	    break;
	 case 'E':
	    a = zone_table[zone].cmd[comm].arg1 = 
	        real_object(zone_table[zone].cmd[comm].arg1);
	    break;
	 case 'P':
	    a = zone_table[zone].cmd[comm].arg1 = 
	        real_object(zone_table[zone].cmd[comm].arg1);
	    b = zone_table[zone].cmd[comm].arg3 = 
	        real_object(zone_table[zone].cmd[comm].arg3);
	    break;
	 case 'D':
	    a = zone_table[zone].cmd[comm].arg1 = 
	        real_room(zone_table[zone].cmd[comm].arg1);
	    break;
	 }
	 if (a < 0 || b < 0) {
	    if (!mini_mud)
	       fprintf(stderr, "Invalid vnum in zone reset cmd: zone #%d, cmd %d .. command disabled.\n",
	            			zone_table[zone].number, comm + 1);
	    zone_table[zone].cmd[comm].command = '*';
	 }
      }
}



void	parse_mobile(FILE *mob_f, int nr)
{
   static int	i = 0;
   int	j, t[10];
   char	line[256], *tmpptr, letter;

   mob_index[i].virtual = nr;
   mob_index[i].number  = 0;
   mob_index[i].func    = NULL;

   clear_char(mob_proto + i);

   mob_proto[i].player_specials = &dummy_mob;
   sprintf(buf2, "mob vnum %d", nr);

   /***** String data *** */
   mob_proto[i].player.name = fread_string(mob_f, buf2);
   tmpptr = mob_proto[i].player.short_descr = fread_string(mob_f, buf2);
   mob_proto[i].player.long_descr = fread_string(mob_f, buf2);
   mob_proto[i].player.description = fread_string(mob_f, buf2);
   mob_proto[i].player.title = NULL;

   /* *** Numeric data *** */
   get_line(mob_f, line);
   sscanf(line, "%d %d %d %c", t, t+1, t+2, &letter);
   MOB_FLAGS(mob_proto + i) = t[0];
   SET_BIT(MOB_FLAGS(mob_proto + i), MOB_ISNPC);
   AFF_FLAGS(mob_proto + i) = t[1];
   GET_ALIGNMENT(mob_proto + i) = t[2];

   switch (letter) {
   case 'S': /* Simple monsters */
      mob_proto[i].real_abils.str = 11;
      mob_proto[i].real_abils.intel = 11;
      mob_proto[i].real_abils.wis = 11;
      mob_proto[i].real_abils.dex = 11;
      mob_proto[i].real_abils.con = 11;

      get_line(mob_f, line);
      if (sscanf(line, " %d %d %d %dd%d+%d %dd%d+%d ",
	     t, t+1, t+2, t+3, t+4, t+5, t+6, t+7, t+8) != 9) {
	 fprintf(stderr,"Format error in mob #%d, first line after S flag\n"
			"...expecting line of form '# # # #d#+# #d#+#'\n", nr);
	 exit(1);
      }

      GET_LEVEL(mob_proto + i) = t[0];
      mob_proto[i].points.hitroll = 20 - t[1];
      mob_proto[i].points.armor = 10 * t[2];

      /* max hit = 0 is a flag that H, M, V is xdy+z */
      mob_proto[i].points.max_hit = 0;
      mob_proto[i].points.hit = t[3];
      mob_proto[i].points.mana = t[4];
      mob_proto[i].points.move = t[5];

      mob_proto[i].points.max_mana = 10;
      mob_proto[i].points.max_move = 50;

      mob_proto[i].mob_specials.damnodice = t[6];
      mob_proto[i].mob_specials.damsizedice = t[7];
      mob_proto[i].points.damroll = t[8];

      get_line(mob_f, line);
      sscanf(line, " %d %d ", t, t+1);
      GET_GOLD(mob_proto + i) = t[0];
      GET_EXP(mob_proto + i) = t[1];

      get_line(mob_f, line);
      if (sscanf(line, " %d %d %d %d ", t, t+1, t+2, t+3) == 4)
	 mob_proto[i].mob_specials.attack_type = t[3];
      else
	 mob_proto[i].mob_specials.attack_type = 0;

      mob_proto[i].char_specials.position = t[0];
      mob_proto[i].mob_specials.default_pos = t[1];
      mob_proto[i].player.sex = t[2];

      mob_proto[i].player.class = 0;
      mob_proto[i].player.weight = 200;
      mob_proto[i].player.height = 198;

      break;
   default:
      fprintf(stderr, "Unsupported mob type %c in mob #%d\n", letter, nr);
      exit(1);
      break;
   }

   mob_proto[i].aff_abils = mob_proto[i].real_abils;

   for (j = 0; j < NUM_WEARS; j++)
      mob_proto[i].equipment[j] = NULL;

   mob_proto[i].nr = i;
   mob_proto[i].desc = NULL;

   top_of_mobt = i++;
}




/* read all objects from obj file; generate index and prototypes */
char	*parse_object(FILE *obj_f, int nr)
{
   static int	i = 0;
   static char	line[256];
   int	t[10], j;
   char	*tmpptr;
   struct extra_descr_data *new_descr;

   obj_index[i].virtual = nr;
   obj_index[i].number  = 0;
   obj_index[i].func    = NULL;

   clear_object(obj_proto + i);
   obj_proto[i].in_room = NOWHERE;
   obj_proto[i].item_number = i;

   sprintf(buf2, "object #%d", nr);

   /* *** string data *** */
   if ((obj_proto[i].name = fread_string(obj_f, buf2)) == NULL) {
      fprintf(stderr, "Null obj name or format error at or near %s\n", buf2);
      exit(1);
   }

   tmpptr = obj_proto[i].short_description = fread_string(obj_f, buf2);
   tmpptr = obj_proto[i].description = fread_string(obj_f, buf2);
   if (tmpptr && *tmpptr)
      *tmpptr = UPPER(*tmpptr);
   obj_proto[i].action_description = fread_string(obj_f, buf2);

   /* *** numeric data *** */
   if (!get_line(obj_f, line) || sscanf(line, " %d %d %d", t, t+1, t+2) != 3) {
      fprintf(stderr, "Format error in first numeric line, %s\n", buf2);
      exit(1);
   }
   obj_proto[i].obj_flags.type_flag = t[0];
   obj_proto[i].obj_flags.extra_flags = t[1];
   obj_proto[i].obj_flags.wear_flags = t[2];

   if (!get_line(obj_f,line) || sscanf(line, "%d %d %d %d", t,t+1,t+2,t+3)!=4){
      fprintf(stderr, "Format error in second numeric line, %s\n", buf2);
      exit(1);
   }
   obj_proto[i].obj_flags.value[0] = t[0];
   obj_proto[i].obj_flags.value[1] = t[1];
   obj_proto[i].obj_flags.value[2] = t[2];
   obj_proto[i].obj_flags.value[3] = t[3];

   if (!get_line(obj_f, line) || sscanf(line, "%d %d %d", t, t+1, t+2) != 3) {
      fprintf(stderr, "Format error in third numeric line, %s\n", buf2);
      exit(1);
   }
   obj_proto[i].obj_flags.weight = t[0];
   obj_proto[i].obj_flags.cost = t[1];
   obj_proto[i].obj_flags.cost_per_day = t[2];

   /* *** extra descriptions and affect fields *** */

   for (j = 0; j < MAX_OBJ_AFFECT; j++) {
      obj_proto[i].affected[j].location = APPLY_NONE;
      obj_proto[i].affected[j].modifier = 0;
   }

   strcat(buf2, ", after numeric constants (expecting E/A/#xxx)");
   j = 0;

   for (; ; ) {
      if (!get_line(obj_f, line)) {
	 fprintf(stderr, "Format error in %s\n", buf2);
	 exit(1);
      }

      switch(*line) {
      case 'E':
	 CREATE(new_descr, struct extra_descr_data, 1);
	 new_descr->keyword = fread_string(obj_f, buf2);
	 new_descr->description = fread_string(obj_f, buf2);
	 new_descr->next = obj_proto[i].ex_description;
	 obj_proto[i].ex_description = new_descr;
	 break;
      case 'A':
	 if (j >= MAX_OBJ_AFFECT) {
	    fprintf(stderr, "Too many A fields (%d max), %s\n", MAX_OBJ_AFFECT, buf2);
	    exit(1);
	 }
	 get_line(obj_f, line);
	 sscanf(line, " %d %d ", t, t+1);
	 obj_proto[i].affected[j].location = t[0];
	 obj_proto[i].affected[j].modifier = t[1];
	 j++;
	 break;
      case '$': case '#':
	 top_of_objt = i++;
	 return line;
	 break;
      default:
	 fprintf(stderr, "Format error in %s\n", buf2);
	 exit(1);
	 break;
      }
   }
}


/* load the zone table and command tables */
void	load_zones(FILE *fl)
{
   static int	zon = 0;
   int	cmd_no = 0, expand, tmp;
   char	*check, buf[81];

   for (; ; ) {
      fscanf(fl, " #%d\n", &tmp);
      sprintf(buf2, "beginning of zone #%d", tmp);
      check = fread_string(fl, buf2);

      if (*check == '$')
	 break;		/* end of file */

      zone_table[zon].number = tmp;
      zone_table[zon].name = check;
      fscanf(fl, " %d ", &zone_table[zon].top);
      fscanf(fl, " %d ", &zone_table[zon].lifespan);
      fscanf(fl, " %d ", &zone_table[zon].reset_mode);

      /* read the command table */

      cmd_no = 0;

      for (expand = 1; ; ) {
	 if (expand)
	    if (!cmd_no)
	       CREATE(zone_table[zon].cmd, struct reset_com, 1);
	    else if (!(zone_table[zon].cmd = 
	        (struct reset_com *) realloc(zone_table[zon].cmd, 
	        (cmd_no + 1) * sizeof(struct reset_com)))) {
	       perror("reset command load");
	       exit(1);
	    }

	 expand = 1;

	 fscanf(fl, " "); /* skip blanks */
	 fscanf(fl, "%c", 
	     &zone_table[zon].cmd[cmd_no].command);

	 if (zone_table[zon].cmd[cmd_no].command == 'S')
	    break;

	 if (zone_table[zon].cmd[cmd_no].command == '*') {
	    expand = 0;
	    fgets(buf, 80, fl); /* skip command */
	    continue;
	 }

	 fscanf(fl, " %d %d %d", 
	     &tmp,
	     &zone_table[zon].cmd[cmd_no].arg1,
	     &zone_table[zon].cmd[cmd_no].arg2);

	 zone_table[zon].cmd[cmd_no].if_flag = tmp;

	 if (zone_table[zon].cmd[cmd_no].command == 'M' || 
	     zone_table[zon].cmd[cmd_no].command == 'O' || 
	     zone_table[zon].cmd[cmd_no].command == 'E' || 
	     zone_table[zon].cmd[cmd_no].command == 'P' || 
	     zone_table[zon].cmd[cmd_no].command == 'D')
	    fscanf(fl, " %d", &zone_table[zon].cmd[cmd_no].arg3);

	 fgets(buf, 80, fl);	/* read comment */

	 cmd_no++;
      }
      zon++;
   }
   top_of_zone_table = zon - 1;
   free(check);
}



/*************************************************************************
*  procedures for resetting, both play-time and boot-time	 	 *
*********************************************************************** */


/* read and allocate space for a '~'-terminated string from a given file */
char *fread_string(FILE *fl, char *error)
{
   static char buf[MAX_STRING_LENGTH], tmp[512], *rslt;
   register char *point;
   int done=0, length=0, templength=0;

   bzero(buf, MAX_STRING_LENGTH);
   do {
      if (!fgets(tmp, 512, fl)) {
	 fprintf(stderr, "SYSERR: fread_string: format error at or near %s\n",
		 error);
	 exit(1);
      }

      /* If there is a '~', end the string; else an "\r\n" over the '\n'. */
      if ((point = strchr(tmp, '~')) != NULL) {
	 *point = '\0';
	 done = 1;
      } else {
	 point = tmp + strlen(tmp) - 1;
         *(point++) = '\r';
         *(point++) = '\n';
         *point = '\0';
      }

      templength = strlen(tmp);

      if (length + templength >= MAX_STRING_LENGTH) {
	 log("SYSERR: fread_string: string too large (db.c)");
	 exit(1);
      } else {
	 strcat(buf+length, tmp);
	 length += templength;
      }
   } while (!done);

   if (strlen(buf) > 0) {
      rslt = buf;
   } else
      rslt = NULL;

  return rslt;
}


/* read contents of a text file, and place in buf */
int	file_to_string(char *name, char *buf)
{
   FILE * fl;
   char	tmp[100];

   *buf = '\0';

   if (!(fl = fopen(name, "r"))) {
      sprintf(tmp, "Error reading %s", name);
      perror(tmp);
      *buf = '\0';
      return(-1);
   }

   do {
      fgets(tmp, 99, fl);

      if (!feof(fl)) {
	 if (strlen(buf) + strlen(tmp) + 2 > MAX_STRING_LENGTH) {
	    log("SYSERR: fl->strng: string too big (db.c, file_to_string)");
	    *buf = '\0';
	    return(-1);
	 }

	 strcat(buf, tmp);
	 *(buf + strlen(buf) + 1) = '\0';
	 *(buf + strlen(buf)) = '\r';
      }
   } while (!feof(fl));

   fclose(fl);

   return(0);
}




/* clear ALL the working variables of a char; do NOT free any space alloc'ed */
void	clear_char(struct char_data *ch)
{
   bzero((char *)ch, sizeof(struct char_data));

   ch->in_room = NOWHERE;
   GET_WAS_IN(ch) = NOWHERE;
   GET_POS(ch) = POS_STANDING;
   ch->mob_specials.default_pos = POS_STANDING;

   GET_AC(ch) = 100; /* Basic Armor */
   if (ch->points.max_mana < 100)
      ch->points.max_mana = 100;
}


void	clear_object(struct obj_data *obj)
{
   bzero((char *)obj, sizeof(struct obj_data));

   obj->item_number = -1;
   obj->in_room	= NOWHERE;
}




/* returns the real number of the room with given virtual number */
int	real_room(int virtual)
{
   int	bot, top, mid;

   bot = 0;
   top = top_of_world;

   /* perform binary search on world-table */
   for (; ; ) {
      mid = (bot + top) / 2;

      if ((world + mid)->number == virtual)
	 return(mid);
      if (bot >= top) {
	 if (!mini_mud)
	    fprintf(stderr, "Room %d does not exist in database\n", virtual);
	 return(-1);
      }
      if ((world + mid)->number > virtual)
	 top = mid - 1;
      else
	 bot = mid + 1;
   }
}




/* returns the real number of the monster with given virtual number */
int	real_mobile(int virtual)
{
   int	bot, top, mid;

   bot = 0;
   top = top_of_mobt;

   /* perform binary search on mob-table */
   for (; ; ) {
      mid = (bot + top) / 2;

      if ((mob_index + mid)->virtual == virtual)
	 return(mid);
      if (bot >= top)
	 return(-1);
      if ((mob_index + mid)->virtual > virtual)
	 top = mid - 1;
      else
	 bot = mid + 1;
   }
}



/* returns the real number of the object with given virtual number */
int	real_object(int virtual)
{
   int	bot, top, mid;

   bot = 0;
   top = top_of_objt;

   /* perform binary search on obj-table */
   for (; ; ) {
      mid = (bot + top) / 2;

      if ((obj_index + mid)->virtual == virtual)
	 return(mid);
      if (bot >= top)
	 return(-1);
      if ((obj_index + mid)->virtual > virtual)
	 top = mid - 1;
      else
	 bot = mid + 1;
   }
}

/* get_line reads the next non-blank line off of the input stream.
 * The newline character is removed from the input.  Lines which begin
 * with '*' are considered to be comments.
 */
int	get_line(FILE *fl, char *buf)
{
   char temp[256];

   do {
      fgets(temp, 256, fl);
      if (*temp)
	 temp[strlen(temp) - 1] = '\0';
   } while (!feof(fl) && (*temp == '*' || !*temp));

   if (feof(fl))
      return 0;
   else {
      strcpy(buf, temp);
      return 1;
   }
}