Mud20/accounts/
Mud20/accounts/c/
Mud20/accounts/f/
Mud20/accounts/k/
Mud20/accounts/s/
Mud20/accounts/t/
Mud20/area_current/
Mud20/area_current/newareas/
Mud20/bin/
Mud20/clans/
Mud20/gods/
Mud20/old-sources/
Mud20/player/
Mud20/player/a/del/
Mud20/player/b/
Mud20/player/b/bak/
Mud20/player/b/del/
Mud20/player/f/
Mud20/player/f/bak/
Mud20/player/f/del/
Mud20/player/k/
Mud20/player/k/bak/
Mud20/player/k/del/
Mud20/player/k/dmp/
Mud20/player/m/
Mud20/player/m/bak/
Mud20/player/o/
Mud20/player/o/bak/
Mud20/player/p/
Mud20/player/s/
Mud20/player/s/bak/
Mud20/player/s/del/
Mud20/player/t/
Mud20/player/t/del/
Mud20/player/v/
Mud20/public_html/
Mud20/races/
Mud20/skilltables/
__MACOSX/Mud20/accounts/
__MACOSX/Mud20/accounts/c/
__MACOSX/Mud20/accounts/f/
__MACOSX/Mud20/accounts/k/
__MACOSX/Mud20/accounts/s/
__MACOSX/Mud20/area_current/
__MACOSX/Mud20/area_current/core_areas/
__MACOSX/Mud20/area_current/helps/
__MACOSX/Mud20/area_current/newareas/
__MACOSX/Mud20/backups/
__MACOSX/Mud20/bin/
__MACOSX/Mud20/clans/
__MACOSX/Mud20/gods/
__MACOSX/Mud20/log/
__MACOSX/Mud20/old-sources/
__MACOSX/Mud20/player/
__MACOSX/Mud20/player/a/del/
__MACOSX/Mud20/player/b/
__MACOSX/Mud20/player/b/bak/
__MACOSX/Mud20/player/f/
__MACOSX/Mud20/player/f/bak/
__MACOSX/Mud20/player/f/del/
__MACOSX/Mud20/player/k/
__MACOSX/Mud20/player/k/bak/
__MACOSX/Mud20/player/k/del/
__MACOSX/Mud20/player/k/dmp/
__MACOSX/Mud20/player/m/
__MACOSX/Mud20/player/m/bak/
__MACOSX/Mud20/player/o/
__MACOSX/Mud20/player/o/bak/
__MACOSX/Mud20/player/p/
__MACOSX/Mud20/player/s/
__MACOSX/Mud20/player/s/bak/
__MACOSX/Mud20/player/t/del/
__MACOSX/Mud20/player/v/
__MACOSX/Mud20/public_html/
__MACOSX/Mud20/races/
__MACOSX/Mud20/skilltables/
/***************************************************************************
 * Mud20 1.0 by Todd H. Johnson (Kregor) a derivative of the Open Gaming   *
 * License by Wizards of the Coast. All comments referring to D20, OGL,    *
 * and SRD refer to the System Reference Document for the Open Gaming      *
 * system. Any inclusion of these derivatives must include credit to the   *
 * Mud20 system, the full and complete Open Gaming LIcense, and credit to  *
 * the respective authors. See ../doc/srd.txt for more information.        *
 *                                                                         *
 * Emud  2.2 by Igor van den Hoven, Michiel Lange, and Martin Bethlehem.   *
 *                                                                         *
 * MrMud 1.4 by David Bills, Dug Michael and Martin Gallwey                *
 *                                                                         *
 * Merc  2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael      *
 * Chastain, Michael Quan, and Mitchell Tse.                               *
 *                                                                         *
 * Original Diku Mud copyright (C) 1990 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeld, Tom Madsen, and Katje Nyboe.     *
 ***************************************************************************/

/***************************************************************************
 * db.c: Server load, loop and event functions													   *
 ***************************************************************************/

#include <sys/time.h>
#include <stdarg.h>
#include "mud.h"

/*
	Locals.
*/

AREA_DATA	*area_load;
int tot_memory_warning = 0;
CHAR_DATA *supermob;
OBJ_DATA *supermob_obj;
ROOM_INDEX_DATA *supermob_room;

void	create_menu_tree();

/*
	Cpu management
*/

lg_int timers[TIMER_MAXTIMER][5];

const char timer_strings[TIMER_MAXTIMER][40] =
{
	"Area Save Time:",
	"Update Shops:",
	"Update Character:",
	"Update Areas:",
	"Update Weather:",
	"Update Objects:",
	"Char Save Time:",
	"Update Violence:",
	"Update Obj Progs:",
	"Update Mob Progs:",
	"Update Mobiles:",
	"Update Aggressive:",
	"Update Purger:",
	"Update Tactical:",
	"Scan Descriptor:",
	"Process Input:",
	"Process Output:",
	"Update Time:",
};

/*
	Memory management
*/

#define	MAX_PERM_BLOCK	1000000
#define	MAX_MEM_LIST		48

const int  rgSizeList   [MAX_MEM_LIST]  =
{
	8,		16,		24,		32,
	40,		48,		56,		64,
	80,		96,		112,		128,
	144,		160,		176,		192,
	224,		256,		288,		320,
	352,		384,		416,		448,
	512,		576,		640,		704,
	768,		832,		896,		960,
	1088,	1216,	1344,	1472,
	1728,	1984,	2240,	2496,
	3072,	4096,	6144,	8192,
	16384,	32768,	65536,	72016
};

void *  alloc_perm      ( bool iList );

typedef struct  perm_block_list    PERM_BLOCK_LIST;

struct perm_block_list
{
	int               iMemPerm;
};

PERM_BLOCK_LIST *perm_block_index[ 255 ];  /* Maximum perm blocks of 256 */

typedef struct  free_mem_list    FREE_MEM_LIST;

struct free_mem_list
{
	FREE_MEM_LIST * next;
};

FREE_MEM_LIST *rgFreeList       [MAX_MEM_LIST];

int rgFreeCount[MAX_MEM_LIST];  /* count of freed memory */
int rgUsedCount[MAX_MEM_LIST];  /* count of used memory */

/*
	Semi-locals.
*/

FILE *                  fpArea;
char                    strArea[MAX_INPUT_LENGTH];


/*
	Local booting procedures.
*/

void			load_auth_list		args( ( void ) ); /* New Auth Code */
void			save_auth_list		args( ( void ) );
void 			save_style 				args( (int num) );
void			save_styles       args( ( void ) );
void 			load_style 				args( (int num) );
void			load_styles       args( ( void ) );
void			save_races       	args( ( void ) );
void			load_races				args( ( void ) );
void 			save_domain 			args( (int num) );
void			save_domains			args( ( void ) );
void 			load_domain 			args( (int num) );
void			load_domains      args( ( void ) );
void 			save_god		 			args( (int num) );
void			save_gods					args( ( void ) );
void 			load_god					args( (int num) );
void			load_gods		      args( ( void ) );
void			fread_components  args( ( void ) );
void			fread_bloodlines	  args( ( void ) );
void 			save_class 				args( (int num) );
void			save_classes    	args( ( void ) );
void			load_classes      args( ( void ) );
void			load_area					args( ( FILE *fp, int segment ) );
void			load_helps				args( ( FILE *fp ) );
void			load_mobiles			args( ( FILE *fp ) );
void			load_objects			args( ( FILE *fp ) );
void			load_resets				args( ( FILE *fp ) );
void			load_rooms				args( ( FILE *fp ) );
void			load_shops				args( ( FILE *fp ) );
void			load_inns					args( ( FILE *fp ) );
void			load_stables			args( ( FILE *fp ) );
void			load_specials			args( ( FILE *fp ) );
void			load_ranges				args( ( FILE *fp ) );
void			load_version			args( ( FILE *fp ) );
void			load_olc_ranges		args( ( FILE *fp ) );
void			load_resetmsg			args( ( FILE *fp ) );
void			load_justice			args( ( FILE *fp ) );
void			load_authors			args( ( FILE *fp ) );
void			load_flags				args( ( FILE *fp ) );
void			load_temperature	args( ( FILE *fp ) );
void			load_weather			args( ( FILE *fp ) );
void			load_repairs			args( ( FILE *fp ) );
void			load_fk_mobiles		args( ( FILE *fp ) );
void			load_fk_objects		args( ( FILE *fp ) );
void			load_fk_rooms			args( ( FILE *fp ) );
void			load_fk_weather		args( ( FILE *fp ) );
void			load_fk_weather		args( ( FILE *fp ) );
OBJ_PROG	*	load_object_program		args( ( FILE *fp ) );
void			obj_prog_if_dest	args( ( OBJ_INDEX_DATA * ) );
void			expand_mob_prog		args( ( MOB_INDEX_DATA * , OBJ_INDEX_DATA *, ROOM_INDEX_DATA *, MPROG_DATA * ) );
char			expand_line_mprog		args( ( MOB_INDEX_DATA * , OBJ_INDEX_DATA *, ROOM_INDEX_DATA *, MPROG_DATA *, char *, bool, char ) );
RESET_DATA *	get_reset_from_obj		args( ( RESET_DATA *lReset ) );
RESET_DATA *	get_reset_from_mob		args( ( RESET_DATA *lReset ) );
RESET_DATA *	get_reset_from_trap		args( ( RESET_DATA *lReset ) );

/*
	MOBprogram locals
*/

void            mprog_read_programs     args ( ( FILE* fp, MOB_INDEX_DATA *pMobIndex ) );

void init_supermob( void )
{
   supermob = create_mobile( get_mob_index( 3 ) );
   char_to_room( supermob, 3, FALSE );
}

/* 
 * convert a bitvector to a string - Kregor
 */
char *bits_to_str(lg_int number, char *vector)
{
	char *buf;
	lg_int cnt;

	push_call("bits_to_str(%p,%p)",number,vector);

	for (cnt = 0 ; *bitvector_table[cnt].name != '\0' ; cnt++)
	{
		if (!str_prefix(vector, bitvector_table[cnt].name))
		{
			if (number == bitvector_table[cnt].value)
			{
				pop_call();
				return (bitvector_table[cnt].name);
			}
		}
	}

	sprintf(buf, "%lld", number );

	pop_call();
	return buf;
}

/* 
 * convert a string to a bitvector
 * if no value found, return 0 - Kregor
 */
lg_int str_to_bits(char *vector)
{
	lg_int cnt;

	push_call("str_to_bits(%p)",vector);

	for (cnt = 0 ; *bitvector_table[cnt].name != '\0' ; cnt++)
	{
		if (!strcasecmp(vector, bitvector_table[cnt].name))
		{
			pop_call();
			return (bitvector_table[cnt].value);
		}
	}
	pop_call();
	return 0;
}

/* 
 * Return a string of bitvectors - Kregor
 */
char *broken_bits( lg_int number, char *vector, bool linear )
{
	lg_int bit, cnt;
	bool found;
	static char broken_string[MAX_INPUT_LENGTH];

	push_call("broken_bits(%p,%p,%p)",number,vector,linear);

	if (IS_SET(mud->flags, MUD_STRAIGHTNUMBERS))
	{
		sprintf(broken_string, "%lld" , number);
		pop_call();
		return broken_string;
	}

	found	= FALSE;
	bit		= 0;

	broken_string[0] = '\0';

	if (!linear)
	{
		while (bit <= number && number >= 0)
		{
			if (IS_SET(number, bit))
			{
				for (cnt = mud->bitvector_ref[*vector - 'A'] ; *bitvector_table[cnt].name != '\0' ; cnt++)
				{
					if (bit == bitvector_table[cnt].value)
					{
						if (!str_prefix(vector, bitvector_table[cnt].name))
						{
							if (found)
							{
								strcat( broken_string, "|" );
							}
							strcat(broken_string, bitvector_table[cnt].name);
							found = TRUE;
							break;
						}
					}
				}
				if (*bitvector_table[cnt].name == '\0')
				{
					if (found)
					{
						strcat(broken_string, "|" );
					}
					log_printf("broken_bits: %s not found %lld", vector, bit);
					cat_sprintf(broken_string, "%lld", bit);
					found = TRUE;
				}
			}
			if (bit != 0)
			{
				bit *= 2;
			}
			else
			{
				bit++;
			}
		}
	}
	else
	{
		for (cnt = mud->bitvector_ref[*vector - 'A'] ; *bitvector_table[cnt].name != '\0' ; cnt++)
		{
			if (number == bitvector_table[cnt].value)
			{
				if (vector[0] == bitvector_table[cnt].name[0] && !str_prefix(vector, bitvector_table[cnt].name))
				{
					strcat(broken_string, bitvector_table[cnt].name);
					found = TRUE;
					break;
				}
			}
		}
	}
	if (!found)
	{
		sprintf(broken_string, "%lld", number);
	}
	pop_call();
  	return( broken_string);
}

/*
 * for use in load_mobiles in db.c to
 * advance simple mobiles by hit dice - Kregor
 *
 * Compares hard set level to hit dice in race file,
 * advances mobile based on difference.
 */
void advance_mobile( MOB_INDEX_DATA *mob )
{
	int lvl, cnt;

	push_call("resize_mobile(%p)", mob);
	
	// do not run on custom non-raced mobiles
	if (mob->race == RACE_NONE)
	{
		pop_call();
		return;
	}
	// if classed, levels are class levels
	if (mob->class != CLASS_MONSTER)
	{
		pop_call();
		return;
	}
	// humanoids and fey advance by class levels
	switch (race_table[mob->race].type)
	{
		default:
			break;
		case RTYPE_HUMANOID:
		case RTYPE_MONSTROUS:
		case RTYPE_FEY:
			pop_call();
			return;
	}
	
	if (race_table[mob->race].hit_dice >= mob->level)
	{
		pop_call();
		return;
	}
	
	/* can't get any bigger than this... */
	if (race_table[mob->race].size >= SIZE_COLOSSAL)
	{
		pop_call();
		return;
	}
	
	lvl = race_table[mob->race].hit_dice;
	
	// dragons get special advancement rules
	if (race_table[mob->race].type == RTYPE_DRAGON)
	{
		int sizeplus;
		lvl = UMAX(0, mob->level - lvl);
		
		switch(lvl / 2)
		{
			default:
				sizeplus = 5;
				mob->perm_dex = UMAX(1, mob->perm_dex - 8);
				break;
			case 0:
				sizeplus = 0;
				break;
			case 1:
				sizeplus = 1;
				mob->perm_dex = UMAX(1, mob->perm_dex - 2);
				break;
			case 2:
			case 3:
				sizeplus = 2;
				mob->perm_dex = UMAX(1, mob->perm_dex - 4);
				break;
			case 4:
			case 5:
			case 6:
				sizeplus = 3;
				mob->perm_dex = UMAX(1, mob->perm_dex - 6);
				break;
			case 7:
			case 8:
			case 9:
			case 10:
				sizeplus = 4;
				mob->perm_dex = UMAX(1, mob->perm_dex - 8);
				break;
		}
		if (sizeplus)
		{
			mob->size = UMIN(mob->size + sizeplus, SIZE_COLOSSAL);
			mob->nat_armor += lvl * 3 / 2;
			mob->perm_str += lvl + 2;
			if (lvl >= 4)
				mob->perm_str += 2;
			mob->perm_con += sizeplus * 2;
			mob->perm_int += lvl / 2 + 1;
			mob->perm_wis += lvl / 2 + 1;
			mob->perm_cha += lvl / 2 + 1;
		}
	}
	else if (mob->level >= ROUNDUP(lvl * 3 / 2))
	{
		// size up & add stat mods for size
		for (cnt = mob->size ; cnt <= SIZE_COLOSSAL ; cnt++)
		{
			if (mob->level < ROUNDUP(lvl * 3 / 2)) // mob level is less than 50% more, no resize
				break;
			if (mob->size == SIZE_COLOSSAL)
				break;
			lvl *= 3;
			lvl = ROUNDUP(lvl/2);
			if (mob->size > SIZE_FINE)
				mob->perm_str += mob->size;
			if (mob->size < SIZE_GARGANTUAN)
				mob->perm_dex = UMAX(3, mob->perm_dex - 2);
			if (mob->size > SIZE_TINY)
			{
				mob->perm_con += mob->size / 2;
				mob->nat_armor    += mob->size - 3;
			}
			mob->size++;
		}
	}
		
	// add points to racial skills for advancement
	for (cnt = 0 ; is_string(skill_table[cnt].name) ; cnt++)
	{
		if (skill_table[cnt].skilltype != FSKILL_SKILL)
			continue;
		if (skill_table[cnt].race_skill[mob->race])
			mob->learned[cnt] += UMAX(0, mob->level - race_table[mob->race].hit_dice);
	}
	pop_call();
	return;
}

/*
	Big mama top level function.
*/

void boot_db( bool fCopyOver )
{
	lg_int boot_start, boot_end;
	int index, cnt;

 	push_call("boot_db(%p)",fCopyOver);

	boot_start = get_game_usec();

	SET_BIT(mud->flags, MUD_EMUD_BOOTING);
	SET_BIT(mud->flags, MUD_EMUD_BOOTDB);

	srand48(mud->current_time);

	log_string("Loading Bitvector Table...");
	for (index = 0 ; index < 26 ; index++)
	{
		for (cnt = 0 ; *bitvector_table[cnt].name != '\0' ; cnt++)
		{
			if (bitvector_table[cnt].name[0] == 'A' + index)
			{
				/*
				log_printf("bitvector_ref[%c] = %d", 'A' + index, cnt);
				*/
				mud->bitvector_ref[index] = cnt;
				break;
			}
		}
	}

	load_sites();
	load_nsites();
	load_usage();
	load_players();
	load_timeinfo();
	load_bounties();
	load_victors();
	load_hiscores();
	load_classes();
	load_domains();
	load_styles();
	load_races();
	load_gods();
	fread_components();
	fread_bloodlines();


	/*
		Assign table indexes - Scandum
	*/
	for (index = 0 ; index < 26 ; index++)
	{
		for (cnt = 0 ; *cmd_table[cnt].name != '\0' ; cnt++)
		{
			if (*cmd_table[cnt].name == 'a' + index)
			{
				/*
				log_printf("command_ref[%c] = %d", 'a' + index, cnt);
				*/
				mud->command_ref[index] = cnt;
				break;
			}
		}
	}

	for (index = 0 ; index < 26 ; index++)
	{
		for (cnt = 0 ; *social_table[cnt].name != '\0' ; cnt++)
		{
			if (*social_table[cnt].name == 'a' + index)
			{
				/*
				log_printf("social_ref[%c] = %d", 'a' + index, cnt);
				*/
				mud->social_ref[index] = cnt;
				break;
			}
		}
	}

	/* removed dependency on MAX_SKILL changing,
	 * MAX_REAL_SKILL advances until a skill with no
	 * name is reached in skill table - Kregor
	 */
	for (cnt = MAX_REAL_SKILL = 0 ; *skill_table[cnt].name != '\0' ; cnt++)
	{
		if (skill_table[cnt].pgsn != NULL)
		{
			/*
			log_printf("skill_table[%03d].name = %s", cnt, skill_table[cnt].name);
			*/
			*skill_table[cnt].pgsn = cnt;
		}
		MAX_REAL_SKILL++;
	}

	/*
		Read in all the area files.
	*/
	{
		FILE *fpList;

		log_printf("Loading Areas");

		if ((fpList = my_fopen(AREA_LIST, "r", FALSE)) == NULL)
		{
			perror( AREA_LIST );
			abort();
		}

		while (TRUE)
		{
			strcpy(strArea, fread_word(fpList));
			log_string(strArea);

			if (strArea[0] == '$')
			{
				break;
			}
			if ((fpArea = my_fopen(strArea, "r", FALSE)) == NULL)
			{
				perror( strArea );
				abort( );
			}

			fread_area(fpArea, 0);

			my_fclose(fpArea);

			fpArea = NULL;
		}

		if (fpList)
		{
			my_fclose( fpList );
		}
	}

	if (mud->time_info->hour < 5)
	{
		mud->sunlight = SUN_DARK;
	}
	else if (mud->time_info->hour <  6)
	{
		mud->sunlight = SUN_RISE;
	}
	else if ( mud->time_info->hour < 11 )
	{
		mud->sunlight = SUN_LIGHT;
	}
	else if ( mud->time_info->hour < 15 )
	{
		mud->sunlight = SUN_NOON;
	}
	else if ( mud->time_info->hour < 19 )
	{
		mud->sunlight = SUN_LIGHT;
	}
	else if ( mud->time_info->hour < 20 )
	{
		mud->sunlight = SUN_SET;
	}
	else
	{
		mud->sunlight = SUN_DARK;
	}

	SET_BIT(mud->flags, MUD_EMUD_BOOTDB);

	log_string("Loading the SuperMob");
	init_supermob();

	log_string("Updating Areas");
	area_update();

	REMOVE_BIT(mud->flags, MUD_EMUD_BOOTDB);

	log_string("Loading Notes");
	load_notes();

	log_string("Creating Menu Tree");
	create_menu_tree();

	log_string("Loading Saved Storerooms");
	load_lockers();

	log_string( "Loading Clans" );
	load_clans();

	log_string( "Loading Auth Name list" );
	load_auth_list(  );
	save_auth_list(  );

	REMOVE_BIT(mud->flags, MUD_EMUD_BOOTING);

	{
		/*
			Clear out timers
		*/

		int cnt;

		for (cnt = 0 ; cnt < TIMER_MAXTIMER ; cnt++)
		{
			timers[cnt][0] = 0;
			timers[cnt][1] = 0;
			timers[cnt][2] = 0;
			timers[cnt][3] = 0;
			timers[cnt][4] = 0;
		}
	}
	if (fCopyOver)
	{
		copyover_recover();
	}

	boot_end = get_game_usec();

	log_printf("Database booted in %lld usec!", boot_end - boot_start);
	pop_call();
	return;
}

void fread_area(FILE *fp, int segment)
{
	char *word;

	push_call("fread_area(%p,%p)",fp, segment);

	while (TRUE)
	{
		if (fread_letter(fp) != '#')
		{
			bug( "Boot_db: # not found.", 0 );
			abort( );
		}

		word = fread_word(fp);

		switch (word[0])
		{
			case '$':
				pop_call();
				return;
			case 'A':
				if (!strcmp(word, "AREA"))
				{
					load_area(fp, segment);
					break;
				}
				if (!strcmp(word, "AUTHORS") || !strcmp(word, "AUTHOR") )
				{
					load_authors(fp);
					break;
				}
			case 'F':
				if (!strcmp(word, "FLAGS"))
				{
					load_flags(fp);
					break;
				}
			case 'E':
				if (!strcmp(word, "ECONOMY")) // For loading FKMud areas with stupid economy - Kregor
				{
					break;
				}
			case 'H':
				if (!strcmp(word, "HELPS"))
				{
					load_helps(fp);
					break;
				}
			case 'I':
				if (!strcmp(word, "INNS"))
				{
					load_inns(fp);
					break;
				}
			case 'J':
				if (!strcmp(word, "JUSTICE"))
				{
					load_justice(fp);
					break;
				}
			case 'M':
				if (!strcmp(word, "MOBILES"))
				{
					if (area_load->version == 99)
						load_fk_mobiles(fp);
					else
						load_mobiles(fp);
					break;
				}
			case 'O':
				if (!strcmp(word, "OLC_RANGES"))
				{
					load_olc_ranges(fp);
					break;
				}
				if (!strcmp(word, "OBJECTS"))
				{
					if (area_load->version == 99)
						load_fk_objects(fp);
					else
						load_objects (fp);
					break;
				}
			case 'Q':
				if (!strcmp(word, "QUESTS")) // here til I can reverse engineer it - Kregor
				{
					break;
				}
			case 'R':
				if (!strcmp(word, "RANGES"))
				{
					load_ranges(fp);
					break;
				}
				if (!strcmp(word, "REPAIRS")) // Because FKMud uses the silly Smaug way - Kregor
				{
					load_resetmsg(fp);
					break;
				}
				if (!strcmp(word, "RESETMSG"))
				{
					load_resetmsg(fp);
					break;
				}
				if (!strcmp(word, "RESETS"))
				{
					load_resets(fp);
					break;
				}
				if (!strcmp(word, "ROOMS"))
				{
					if (area_load->version == 99)
						load_fk_rooms(fp);
					else
						load_rooms(fp);
					break;
				}
			case 'S':
				if (!strcmp(word, "SHOPS"))
				{
					load_shops(fp);
					break;
				}
				if (!strcmp(word, "SPECIALS"))
				{
					load_specials(fp);
					break;
				}
				if (!strcmp(word, "STABLES"))
				{
					load_stables(fp);
					break;
				}
			case 'T':
				if (!strcmp(word, "TEMPERATURE"))
				{
					load_temperature(fp);
					break;
				}
			case 'V':
				if (!strcmp(word, "VERSION"))
				{
					load_version(fp);
					break;
				}
			case 'W':
				if (!strcmp(word, "WEATHER"))
				{
					if (area_load->version == 99)
						load_fk_weather(fp);
					else
						load_weather(fp);
					break;
				}
			default:
				bug("boot_db: bad section name: %s", word);
				abort( );
		}
	}
}

/*
	Snarf an 'area' header line.
*/

void load_area ( FILE *fp, int segment )
{
	AREA_DATA 	*pArea, *temp_area;
	int cnt;

	push_call("load_area(%p,%p)",fp,segment);

	ALLOCMEM(pArea, AREA_DATA, 1);
	pArea->name								= fread_string( fp );
	pArea->age								= 99;
	pArea->version						= 0;
	pArea->low_r_vnum					= MAX_VNUM-1;
	pArea->low_o_vnum					= MAX_VNUM-1;
	pArea->low_m_vnum					= MAX_VNUM-1;
	pArea->olc_range_lo				= MAX_VNUM-1;
	pArea->resetmsg						= STRDUPE(str_empty);
	pArea->hi_soft_range			= MAX_LEVEL;
	pArea->hi_hard_range			= MAX_LEVEL;
	pArea->authors						= STRDUPE(str_empty);
	for (cnt = 0 ; cnt < CRIME_MAX ; cnt++)
	{
		pArea->punishment[cnt] 	= 0;
	}
	pArea->courtroom					= 0;
	pArea->dungeon						= 0;
	pArea->judge							= 0;
	pArea->guard							= 0;

	ALLOCMEM(pArea->weather_info, WEATHER_DATA, 1);

	pArea->weather_info->temp_winter	= -10;
	pArea->weather_info->temp_summer	=  20;
	pArea->weather_info->temp_daily	=  10;
	pArea->weather_info->wind_scale	=   4;
	pArea->weather_info->wet_scale	=   4;

	{
		for (temp_area = mud->f_area ; temp_area ; temp_area = temp_area->next)
		{
			if (strcmp(pArea->name, temp_area->name) < 0)
			{
				INSERT_LEFT(pArea, temp_area, mud->f_area, next, prev);
				break;
			}
		}
		if (!temp_area)
		{
			LINK(pArea, mud->f_area, mud->l_area, next, prev);
		}
		mud->top_area++;
	}
	pArea->filename	= STRALLOC(strArea);
	area_load			= pArea;
	pop_call();
	return;
}


void load_temperature( FILE * fp )
{
	push_call("load_temperature(%p)",fp);

	fread_number(fp);
	fread_number(fp);
	fread_number(fp);
	fread_number(fp);

	pop_call();
	return;
}


void load_weather( FILE * fp )
{
	push_call("load_weather(%p)",fp);

	area_load->weather_info->temp_winter	= fread_number(fp);
	area_load->weather_info->temp_summer	= fread_number(fp);
	area_load->weather_info->temp_daily	= fread_number(fp);
	area_load->weather_info->wet_scale		= fread_number(fp);
	area_load->weather_info->wind_scale	= fread_number(fp);

	pop_call();
	return;
}


void load_flags( FILE *fp )
{
	if (area_load->version < 2 || area_load->version == 99)
	{
		fread_number(fp);
		fread_number(fp);
	}
	else
	{
		area_load->flags = fread_number(fp);
	}
}


void load_authors( FILE *fp )
{
	push_call("load_authors(%p)",fp);

	STRFREE(area_load->authors);
	area_load->authors = fread_string(fp);
	pop_call();
	return;
}


void load_ranges( FILE *fp )
{
	push_call("load_ranges(%p)",fp);

	area_load->low_soft_range = fread_number( fp );
	area_load->hi_soft_range  = fread_number( fp );
	area_load->low_hard_range = fread_number( fp );
	area_load->hi_hard_range  = fread_number( fp );

	if (area_load->low_soft_range > area_load->hi_soft_range)
	{
		log_printf("Low soft range is greater than high soft range.");
	}
	if (area_load->low_hard_range > area_load->hi_hard_range)
	{
		log_printf("Low hard range is greater than high hard range.");
	}
	pop_call();
	return;
}

void load_version( FILE *fp )
{
	push_call("load_version(%p)",fp);

	area_load->version = fread_number(fp);

	pop_call();
	return;
}

void load_olc_ranges( FILE *fp )
{
	push_call("load_olc_ranges(%p)",fp);

	area_load->olc_range_lo = fread_number( fp );
	area_load->olc_range_hi = fread_number( fp );

	pop_call();
	return;
}


void load_resetmsg( FILE *fp )
{
	push_call("load_resetmsg(%p)",fp);

	STRFREE( area_load->resetmsg );
	area_load->resetmsg = fread_string( fp );

	pop_call();
	return;
}


void load_justice( FILE *fp )
{
	char *word;

	push_call("load_justice(%p)",fp);

	while (TRUE)
	{
		word = fread_word(fp);

		switch (word[0])
		{
			case '$':
				pop_call();
				return;
			case 'C':
				if (!strcmp(word, "Courtroom"))
				{
					area_load->courtroom = fread_number(fp);
					break;
				}
				if (!strcmp(word, "Crime"))
				{
					area_load->punishment[fread_number(fp)] = fread_number(fp);
					break;
				}
			case 'D':
				if (!strcmp(word, "Dungeon"))
				{
					area_load->dungeon = fread_number(fp);
					break;
				}
			case 'G':
				if (!strcmp(word, "Guard"))
				{
					area_load->guard = fread_number(fp);
					break;
				}
			case 'J':
				if (!strcmp(word, "Judge"))
				{
					area_load->judge = fread_number(fp);
					break;
				}
			case 'S':
				if (!strcmp(word, "Storeroom"))
				{
					area_load->storeroom = fread_number(fp);
					break;
				}
			default:
				bug("load_justice: bad section name: %s", word);
				abort( );
		}
	}
	pop_call();
	return;
}


/*
	Snarf a help section.
*/

void load_helps( FILE *fp )
{
	HELP_DATA *pHelp;

	push_call("load_helps(%p)",fp);

	while (TRUE)
	{
		ALLOCMEM(pHelp, HELP_DATA, 1);
		pHelp->level	= fread_number( fp );
		pHelp->keyword	= fread_string( fp );
		if (pHelp->keyword[0] == '$')
		{
			FREEMEM(pHelp);
			break;
		}
		if (IS_SET(area_load->flags, AFLAG_NEWHELPS))
		{
			pHelp->title = fread_string( fp );
		}
		pHelp->text	= fread_string( fp );
		pHelp->area	= area_load;

		LINK( pHelp, area_load->first_help, area_load->last_help, next, prev );
		mud->top_help++;
	}
	pop_call();
	return;
}


/*
	Add a character to the list of all characters
*/

void add_char( CHAR_DATA *ch )
{
	push_call("add_char(%p)",ch);

	if (!IS_NPC(ch))
	{
		LINK(ch, mud->f_char, mud->l_char, next, prev);
	}
	else
	{
		LINK(ch, mud->f_char, mud->l_char, next, prev);
		LINK(ch, ch->pIndexData->first_instance, ch->pIndexData->last_instance, next_instance, prev_instance);
	}
	pop_call();
	return;
}

/*
	Snarf a mob section.
*/

void load_mobiles( FILE *fp )
{
	MOB_INDEX_DATA *pMobIndex;
	EXTRA_DESCR_DATA *ed;
	AFFECT_DATA *paf;
	char buf[256], *pt;
	int vnum, sn, value;
	char letter;

	push_call("load_mobiles(%p)",fp);

	while (TRUE)
	{
		letter = fread_letter( fp );
		if (letter != '#')
		{
			bug( "Load_mobiles: # not found.", 0 );
			abort( );
		}

		vnum = fread_number( fp );
		if (vnum == 0)
		{
			break;
		}

		if (vnum < 1 || vnum >= MAX_VNUM)
		{
			bug("load_mobiles: vnum %u out of range.", vnum);
			abort( );
		}
		if (get_mob_index(vnum) != NULL)
		{
			bug("load_mobiles: vnum %u duplicated.", vnum);
			abort( );
		}

		ALLOCMEM(pMobIndex, MOB_INDEX_DATA, 1);

		pMobIndex->vnum			= vnum;
		mob_index[vnum]			= pMobIndex;
		pMobIndex->area			= area_load;

		if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
		{
			if (area_load->low_m_vnum > vnum)
			{
				area_load->low_m_vnum = vnum;
			}
			if (vnum > area_load->hi_m_vnum)
			{
				area_load->hi_m_vnum = vnum;
			}
		}

		pt = fread_string( fp );  /* Add M### system to names */
		sprintf( buf, "m%u", vnum );
		if (strstr(pt, buf) == NULL)
		{
			sprintf( buf, "%s m%u", pt, vnum );
		}
		else
		{
			strcpy( buf, pt );
		}
		STRFREE (pt);

		pMobIndex->player_name	= STRALLOC(buf);
		
		/* pMobIndex->player_name	= fread_string( fp ); */
		pMobIndex->short_descr	= fread_string( fp );
		pMobIndex->long_descr	= fread_string( fp );
		pMobIndex->description	= fread_string( fp );
		
		pMobIndex->unique = FALSE;

		/* The read section for the new mob format starts HERE - Kregor 3/13/07 */
		if (area_load->version >= 4)
		{
			letter				= fread_letter( fp );
			if (letter == 'U')
				pMobIndex->unique = TRUE;
			else if (letter == 'S')
				pMobIndex->unique = FALSE;
			else
			{
				bug( "Load_mobiles: vnum %u not U or S.", vnum );
				abort( );
			}
			pMobIndex->level				= fread_number( fp );
			pMobIndex->class				= fread_number( fp );
			pMobIndex->race					= fread_number( fp );
			pMobIndex->sex					= fread_number( fp );
			pMobIndex->position			= fread_number( fp );
			pMobIndex->god					= fread_number( fp );
			pMobIndex->act					= fread_number( fp );

			// Adjust old area levels to Mud20 standard - Kregor
			if (!IS_SET(pMobIndex->act, ACT_MOBINVIS))
				pMobIndex->level 				= URANGE(1, pMobIndex->level, 30);

			if (!pMobIndex->unique)
			{
				if (pMobIndex->race <= RACE_NONE)
				{
					bug( "Load_mobiles: no race set on S mobile.", vnum );
					pMobIndex->race = RACE_HUMAN;
				}
	
				if (pMobIndex->class != CLASS_MONSTER && pMobIndex->class < MAX_CLASS)
					pMobIndex->hitsizedice 	= class_table[pMobIndex->class].hp_max;
				else if (pMobIndex->race > RACE_NONE)
					pMobIndex->hitsizedice 	= race_type_table[race_table[pMobIndex->race].type].hit_die;
				else
				{
					bug( "Load_mobiles: neither class nor race hit die.", vnum );
					pMobIndex->hitsizedice 	= 8;
				}
				pMobIndex->alignment		= race_table[pMobIndex->race].alignment;
				pMobIndex->ethos				= race_table[pMobIndex->race].ethos;
				pMobIndex->gold					= 0; // need to add means to determine standard random gold
		
				/*
				 * assign stats based on class pri and sec stats
				 * These routines effectively gives standard NPCs
				 * an elite array of abilities - Kregor
				 */
				if (pMobIndex->class > CLASS_MONSTER)
				{
					int class = pMobIndex->class;

					if (class_table[class].attr_prime == APPLY_STR)
						pMobIndex->perm_str			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[0];
					else if (class_table[class].attr_second == APPLY_STR)
						pMobIndex->perm_str			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[0];
					else
						pMobIndex->perm_str			= best_three_of_four() + race_table[pMobIndex->race].race_mod[0];
					if (class_table[class].attr_prime == APPLY_DEX)
						pMobIndex->perm_dex			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[1];
					else if (class_table[class].attr_second == APPLY_DEX)
						pMobIndex->perm_dex			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[1];
					else
						pMobIndex->perm_dex			= best_three_of_four() + race_table[pMobIndex->race].race_mod[1];
					if (class_table[class].attr_prime == APPLY_CON)
						pMobIndex->perm_con			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[2];
					else if (class_table[class].attr_second == APPLY_CON)
						pMobIndex->perm_con			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[2];
					else
						pMobIndex->perm_con			= best_three_of_four() + race_table[pMobIndex->race].race_mod[2];
					if (class_table[class].attr_prime == APPLY_INT)
						pMobIndex->perm_int			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[3];
					else if (class_table[class].attr_second == APPLY_INT)
						pMobIndex->perm_int			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[3];
					else
						pMobIndex->perm_int			= best_three_of_four() + race_table[pMobIndex->race].race_mod[3];
					if (class_table[class].attr_prime == APPLY_WIS)
						pMobIndex->perm_wis			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[4];
					else if (class_table[class].attr_second == APPLY_WIS)
						pMobIndex->perm_wis			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[4];
					else
						pMobIndex->perm_wis			= best_three_of_four() + race_table[pMobIndex->race].race_mod[4];
					if (class_table[class].attr_prime == APPLY_CHA)
						pMobIndex->perm_cha			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[5];
					else if (class_table[class].attr_second == APPLY_CHA)
						pMobIndex->perm_cha			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[5];
					else
						pMobIndex->perm_cha			= best_three_of_four() + race_table[pMobIndex->race].race_mod[5];
				}
				else
				{
					pMobIndex->perm_str			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[0];
					pMobIndex->perm_int			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[1];
					pMobIndex->perm_wis			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[2];
					pMobIndex->perm_dex			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[3];
					pMobIndex->perm_con			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[4];
					pMobIndex->perm_cha			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[5];
				}
				// zero out nonabilities by race
				if (race_table[pMobIndex->race].nonability[STAT_STR])
					pMobIndex->perm_str		= 0;
				if (race_table[pMobIndex->race].nonability[STAT_DEX])
					pMobIndex->perm_dex		= 0;
				if (race_table[pMobIndex->race].nonability[STAT_CON])
					pMobIndex->perm_con		= 0;
				if (race_table[pMobIndex->race].nonability[STAT_INT])
					pMobIndex->perm_int		= 0;
				if (race_table[pMobIndex->race].nonability[STAT_WIS])
					pMobIndex->perm_wis		= 0;
				if (race_table[pMobIndex->race].nonability[STAT_CHA])
					pMobIndex->perm_cha		= 0;
	
				pMobIndex->nat_armor		= race_table[pMobIndex->race].nat_armor;
				pMobIndex->wear_locs		= race_table[pMobIndex->race].wear_locs;
				pMobIndex->size					=	race_table[pMobIndex->race].size;
				pMobIndex->understands	= race_table[pMobIndex->race].understands;
				pMobIndex->speaks				= race_table[pMobIndex->race].speaks;				
			}
			else
			{
				pMobIndex->affected_by	= fread_number( fp );
				pMobIndex->nat_armor		= fread_number( fp );
				pMobIndex->armor_type		= fread_number( fp );
		
				/* 'd' */	fread_letter( fp );
				if (pMobIndex->class > CLASS_MONSTER && pMobIndex->class < MAX_CLASS)
				{
					fread_number( fp );
					pMobIndex->hitsizedice 	= class_table[pMobIndex->class].hp_max;
				} 
				else if (pMobIndex->race > RACE_NONE)
				{
					fread_number( fp );
					pMobIndex->hitsizedice 	= race_type_table[race_table[pMobIndex->race].type].hit_die;
				}
				else
				{
					pMobIndex->hitsizedice	= fread_number( fp );
				}
				/* '+' */	fread_letter( fp );
				pMobIndex->hitplus			= fread_number( fp );

				// damage stats no longer used in Mud20, but keeping in file
				fread_number( fp );
				/* 'd' */	fread_letter( fp );	
				fread_number( fp );
				/* '+' */	fread_letter( fp );	
				fread_number( fp );

				pMobIndex->alignment		= fread_number( fp );
				pMobIndex->ethos				= fread_number( fp );
				pMobIndex->gold					= fread_number( fp );
				pMobIndex->perm_str			= fread_number( fp );
				pMobIndex->perm_int			= fread_number( fp );
				pMobIndex->perm_wis			= fread_number( fp );
				pMobIndex->perm_dex			= fread_number( fp );
				pMobIndex->perm_con			= fread_number( fp );
				pMobIndex->perm_cha			= fread_number( fp );
	
				if (!pMobIndex->race)
				{
					pMobIndex->body_type 		= fread_number( fp );
					pMobIndex->wear_locs 		= fread_number( fp );
					pMobIndex->size					=	fread_number( fp );
					pMobIndex->race_type 		= fread_number( fp );
					pMobIndex->rspecs 			= fread_number( fp );
				}
				else
				{
					/* Unused */	 fread_number( fp );
					pMobIndex->wear_locs	= race_table[pMobIndex->race].wear_locs;
					/* Unused */	 fread_number( fp );
					pMobIndex->size					=	fread_number( fp );
					/* Unused */	 fread_number( fp );
					/* Unused */	 fread_number( fp );
				}
				pMobIndex->understands	= fread_number( fp );
				pMobIndex->speaks				= fread_number( fp );
				/* Unused */	 fread_number( fp );
				/* Unused */	 fread_number( fp );
				/* Unused */	 fread_number( fp );
			}
		}
		else
		{
			pMobIndex->act					= fread_number( fp );
			pMobIndex->affected_by	= fread_number( fp );
			pMobIndex->alignment		= fread_number( fp );
			letter				= fread_letter( fp );
			if (letter != 'S')
			{
				bug( "Load_mobiles: vnum %u non-S.", vnum );
				abort( );
			}
	
			pMobIndex->level				= fread_number( fp );
	
			pMobIndex->level 				= URANGE(1, pMobIndex->level, 40);
	
			/* unused */ fread_number( fp );
			pMobIndex->wear_locs		= fread_number( fp );
			pMobIndex->hitnodice		= fread_number( fp );
					fread_letter( fp );	/* 'd' */
			pMobIndex->hitsizedice	= fread_number( fp );
					fread_letter( fp );	/* '+' */
			pMobIndex->hitplus			= fread_number( fp );
					fread_number( fp );
					fread_letter( fp );	/* 'd' */
					fread_number( fp );
					fread_letter( fp );	/* '+' */
					fread_number( fp );
			pMobIndex->gold					= fread_number( fp );
			pMobIndex->race					= fread_number( fp );
			pMobIndex->position			= fread_number( fp );
								  fread_number( fp );	/* Unused */
			pMobIndex->sex					= fread_number( fp );
	
	   	pMobIndex->perm_str = 10;
	   	pMobIndex->perm_dex = 10;
	   	pMobIndex->perm_int = 10;
	   	pMobIndex->perm_wis = 10;
	   	pMobIndex->perm_cha = 10;
	   	pMobIndex->perm_con = 10;
			if (pMobIndex->race > RACE_NONE)
			{
				if (race_table[pMobIndex->race].nonability[STAT_STR])
					pMobIndex->perm_str		= 0;
				else
					pMobIndex->perm_str		+= race_table[pMobIndex->race].race_mod[0];
				if (race_table[pMobIndex->race].nonability[STAT_DEX])
					pMobIndex->perm_dex		= 0;
				else
					pMobIndex->perm_dex		+= race_table[pMobIndex->race].race_mod[1];
				if (race_table[pMobIndex->race].nonability[STAT_CON])
					pMobIndex->perm_con		= 0;
				else
					pMobIndex->perm_con		+= race_table[pMobIndex->race].race_mod[2];
				if (race_table[pMobIndex->race].nonability[STAT_INT])
					pMobIndex->perm_int		= 0;
				else
					pMobIndex->perm_int		+= race_table[pMobIndex->race].race_mod[3];
				if (race_table[pMobIndex->race].nonability[STAT_WIS])
					pMobIndex->perm_wis		= 0;
				else
					pMobIndex->perm_wis		+= race_table[pMobIndex->race].race_mod[4];
				if (race_table[pMobIndex->race].nonability[STAT_CHA])
					pMobIndex->perm_cha		= 0;
				else
					pMobIndex->perm_cha		+= race_table[pMobIndex->race].race_mod[5];
			}
	  }
		if (pMobIndex->size == 0)
			pMobIndex->size				=	race_table[pMobIndex->race].size;		

		pMobIndex->mclass[pMobIndex->class] = pMobIndex->level;
		
		if (IS_SET(pMobIndex->affected_by, AFF_ETHEREAL))
		{
			SET_BIT(pMobIndex->act, ACT_MOBINVIS);
			REMOVE_BIT(pMobIndex->affected_by, AFF_ETHEREAL);
		}
		while (letter)
		{
			switch (letter = fread_letter(fp))
			{
				case 'A':
					ALLOCMEM(paf, AFFECT_DATA, 1);
					paf->type					= 0;
					paf->duration			= -1;
					paf->location			= fread_number( fp );
					paf->modifier			= fread_number( fp );
					paf->bitvector 		= fread_number( fp );
					paf->bittype			= paf->bitvector ? AFFECT_TO_CHAR : AFFECT_TO_NONE;
					paf->level      	= pMobIndex->level;
					paf->caster				= STRALLOC("None");

					LINK(paf, pMobIndex->first_affect, pMobIndex->last_affect, next, prev);
					mud->top_affect++;
					break;
				case 'C':
					pMobIndex->mclass[fread_number( fp )]	= fread_number( fp );
					break;
				case 'E':
					ALLOCMEM(ed, EXTRA_DESCR_DATA, 1);
					ed->keyword		= fread_string( fp );
					ed->description	= fread_string( fp );
					LINK(ed, pMobIndex->first_extradesc, pMobIndex->last_extradesc, next, prev);
					mud->top_ed++;
					break;
				case 'M':
					pMobIndex->reset_msg	= fread_string( fp );
					break;
				case 'O':
					pMobIndex->load_eq[fread_number( fp )] = fread_number( fp );
					break;
				case 'X':
					pMobIndex->attacks[fread_number( fp )] = fread_number( fp );
					break;
				case '%':
					value = fread_number( fp );
					value = URANGE(0, value, 99);
					sn = skill_lookup( fread_string( fp ) );
					if (sn < 0)
					{
						bug("load_mobiles: %d - unknown skill.", vnum);
						break;
					}
					pMobIndex->learned[sn] = value;
					break;
				case '>':
					ungetc(letter, fp);
					mprog_read_programs(fp, pMobIndex);
					letter = FALSE;
					break;

				default:
					ungetc(letter, fp);
					letter = FALSE;
					break;
			}
		}
		// Add sorcerer "multiclass" to dragon race
		if (race_table[pMobIndex->race].parent_race == RACE_DRAGON && pMobIndex->mclass[CLASS_SORCERER] == 0)
			pMobIndex->mclass[CLASS_SORCERER] = dragon_caster_level(pMobIndex->level);

		if (!pMobIndex->unique && pMobIndex->race && pMobIndex->level > race_table[pMobIndex->race].hit_dice)
			advance_mobile(pMobIndex);

		mud->top_mob_index++;
	}
	pop_call();
	return;
}

/*
	Snarf an obj section.
*/
void load_objects( FILE *fp )
{
	OBJ_PROG *prg;
	OBJ_INDEX_DATA *pObjIndex;
	EXTRA_DESCR_DATA *ed;
	AFFECT_DATA *paf;
	char buf[256], *pt;
	int vnum, val, sn;
	char letter;

	push_call("load_object(%p)",fp);

	while (TRUE)
	{
		letter = fread_letter( fp );

		if ( letter != '#' )
		{
			bug( "Load_objects: # not found.", 0 );
			abort( );
		}

		vnum = fread_number( fp );

		if ( vnum == 0 )
		{
			break;
		}

		if (vnum < 1 || vnum >= MAX_VNUM)
		{
			bug("load_objects: vnum %u out of range.", vnum);
			abort( );
		}

		if (get_obj_index(vnum) != NULL)
		{
			bug("load_objects: vnum %u duplicated.", vnum);
			abort();
		}

		ALLOCMEM(pObjIndex, OBJ_INDEX_DATA, 1);
		pObjIndex->vnum = vnum;

		if (area_load->low_o_vnum > vnum)
		{
			area_load->low_o_vnum = vnum;
		}
		if (vnum > area_load->hi_o_vnum)
		{
			area_load->hi_o_vnum = vnum;
		}
		obj_index[ vnum ] = pObjIndex;
		pObjIndex->area = area_load;

		pt = fread_string( fp );  /* Add I### system to names */
		sprintf( buf, "i%u", vnum );
		if (strstr(pt, buf) == NULL)
		{
			sprintf( buf, "%s i%u", pt, vnum );
		}
		else
		{
			strcpy( buf, pt );
		}
		STRFREE (pt );

		pObjIndex->name					= STRALLOC(buf);
		pObjIndex->short_descr	= fread_string( fp );
		pObjIndex->long_descr		= fread_string( fp );
		pObjIndex->description	= fread_string( fp );
		pObjIndex->item_type		= fread_number( fp );
		pObjIndex->extra_flags	= fread_number( fp );
		pObjIndex->wear_flags		= fread_number( fp );
		if (area_load->version >= 4)
		{
			/* unused */		fread_number( fp );
			pObjIndex->material			= fread_number( fp );
			pObjIndex->hit_points		= fread_number( fp );
			pObjIndex->size					= fread_number( fp );
		}
		pObjIndex->value[0]			= fread_number( fp );
		pObjIndex->value[1]			= fread_number( fp );
		pObjIndex->value[2]			= fread_number( fp );
		pObjIndex->value[3]			= fread_number( fp );
		if (area_load->version > 2)
		{
			pObjIndex->value[4]			= fread_number( fp );
			pObjIndex->value[5]			= fread_number( fp );
			pObjIndex->value[6]			= fread_number( fp );
			pObjIndex->value[7]			= fread_number( fp );
		}
		pObjIndex->weight				= fread_number(fp);
		pObjIndex->cost					= abs(fread_number( fp ));
		pObjIndex->level				= fread_number( fp );
		pObjIndex->attack_string	= STRDUPE(str_empty);
		pObjIndex->id_name			= STRDUPE(str_empty);
		pObjIndex->id_descr			= STRDUPE(str_empty);
		
		/* added to fix new wear size value for armor */
		if (pObjIndex->item_type == ITEM_ARMOR && pObjIndex->value[3] <= 0)
			pObjIndex->value[3] = SIZE_MEDIUM;

		while (letter)
		{
			switch (letter = fread_letter(fp))
			{
				case 'A':
					ALLOCMEM(paf, AFFECT_DATA, 1);
					paf->type					= 0;
					paf->duration			= -1;
					paf->location			= fread_number( fp );
					paf->modifier			= fread_number( fp );
					if (area_load->version != 2)
						paf->bitvector 		= fread_number( fp );
					paf->bittype			= paf->bitvector ? AFFECT_TO_CHAR : AFFECT_TO_NONE;
					paf->level      	= pObjIndex->level;
					paf->caster				= STRALLOC("None");

					LINK(paf, pObjIndex->first_affect, pObjIndex->last_affect, next, prev);
					SET_BIT(pObjIndex->extra_flags, ITEM_MAGIC);
					mud->top_affect++;
					break;
				case 'C':
					STRFREE(pObjIndex->attack_string);
					pObjIndex->attack_string	= fread_string( fp );
					pObjIndex->class_flags	= fread_number( fp );
					break;
				case 'E':
					ALLOCMEM(ed, EXTRA_DESCR_DATA, 1);
					ed->keyword			= fread_string( fp );
					ed->description		= fread_string( fp );
					LINK(ed, pObjIndex->first_extradesc, pObjIndex->last_extradesc, next, prev);
					mud->top_ed++;
					break;
				case 'I':
					STRFREE(pObjIndex->id_name);
					pObjIndex->id_name	= fread_string( fp );
					STRFREE(pObjIndex->id_descr);
					pObjIndex->id_descr	= fread_string( fp );
					break;
				// this remnant of MRMud left to simply allow loading of old areas
				case 'P':
					prg = load_object_program(fp);
					break;
				case '>':
					ungetc(letter, fp);
					oprog_read_programs(fp, pObjIndex);
					letter = FALSE;
					break;
				// added to deprecate skill bitvectors for scrolls etc. - Kregor
				case 'V':
					val = fread_number( fp );
					if ((sn = skill_lookup(fread_word( fp ))) == -1)
					{
						bug("load_objects: %u bad skill for value %d.", vnum, val);
					}
					pObjIndex->value[val] = sn;
					break;

				default:
					ungetc(letter, fp);
					letter = FALSE;
					break;
			}
		}
		if (obj_index_cost(pObjIndex) != -1)
			pObjIndex->cost				= obj_index_cost(pObjIndex);

		fix_materials(pObjIndex);
		fix_sizes(pObjIndex);
		if (load_obj_weight(pObjIndex) != -1)
			pObjIndex->weight			= load_obj_weight(pObjIndex);
		load_obj_hit(pObjIndex);

		mud->top_obj_index++;
	}
	pop_call();
	return;
}

/*
	Snarf a reset section.
*/

void load_resets( FILE *fp )
{
	RESET_DATA *pReset;
	char letter;

	push_call("load_resets(%p)",fp);

	if (area_load == NULL)
	{
		bug( "Load_resets: no #AREA seen yet.", 0 );
		abort( );
	}

	while (TRUE)
	{
		if ((letter = fread_letter(fp)) == 'S')
		{
			break;
		}

		ALLOCMEM(pReset, RESET_DATA, 1);

		pReset->command	= letter;
		if (area_load->version <= 2 || area_load->version == 99) // Get rid of MERC extraneous number - Kregor
			fread_number( fp );
		pReset->arg1		= fread_number( fp );
		pReset->arg2		= fread_number( fp );
		if ((area_load->version < 4 || area_load->version == 99) && letter != 'D') // pre Mud20 1.0 used as a repop limit, not percentage - Kregor
			pReset->arg2 = 100;
		if ((area_load->version <= 2 || area_load->version == 99) && letter == 'G') // Other bases leave this number out - Kregor
			pReset->arg3		= 0;
		else
			pReset->arg3		= fread_number( fp );
		fread_to_eol( fp );

		LINK(pReset, area_load->first_reset, area_load->last_reset, next, prev);
		mud->top_reset++;

		/*
			Add container references while at it - Scandum
		*/

		switch ( letter )
		{
			case 'P':
				pReset->container = get_reset_from_obj(pReset);
				break;

			case 'T':
				pReset->container = get_reset_from_trap(pReset);
				break;

			case 'G':
			case 'E':
				pReset->container = get_reset_from_mob(pReset);
				break;
		}
	}
	pop_call();
	return;
}

/*
	Snarf a room section.
	And counting occurances of things.
*/

void load_rooms( FILE *fp )
{
	ROOM_INDEX_DATA *pRoomIndex;
	EXIT_DATA *pExit;
	EXTRA_DESCR_DATA *ed;
	int vnum;
	bool door;
	char letter;

	push_call("load_rooms(%p)",fp);

	if (area_load == NULL)
	{
		bug( "Load_resets: no #AREA seen yet.", 0 );
		abort( );
	}

	while (TRUE)
	{
		letter = fread_letter( fp );

		if (letter != '#')
		{
		    bug( "Load_rooms: # not found.", 0 );
		    abort( );
		}

		vnum	= fread_number(fp);

		if (vnum == 0)
		{
			break;
		}

		if (vnum < 0 || vnum >= MAX_VNUM)
		{
			bug("load_rooms: vnum %u out of range.", vnum);
			abort( );
		}

		if (room_index[vnum] != NULL && vnum < MAX_VNUM)
		{
			bug("load_rooms: vnum %u duplicated.", vnum);
			abort( );
		}

		ALLOCMEM(pRoomIndex, ROOM_INDEX_DATA, 1);

		if (vnum < area_load->low_r_vnum)
		{
			area_load->low_r_vnum = vnum;
		}
		if (vnum > area_load->hi_r_vnum)
		{
			area_load->hi_r_vnum = vnum;
		}

		pRoomIndex->area			= area_load;
		pRoomIndex->vnum			= vnum;
		room_index[vnum]			= pRoomIndex;

		pRoomIndex->name			= fread_string( fp );
		pRoomIndex->description		= fread_string( fp );
		pRoomIndex->listen_desc		= STRDUPE( str_empty );
		pRoomIndex->night_desc		= STRDUPE( str_empty );
		pRoomIndex->creator_pvnum	= fread_number( fp );
		pRoomIndex->room_flags		= fread_number( fp );
		pRoomIndex->sector_type		= fread_number( fp );
		if (area_load->version >= 4)
		{
			/* not used */	fread_number( fp );
			/* not used */	fread_number( fp );
			/* not used */	fread_number( fp );
		}

		for (door = 0 ; door < MAX_LAST_LEFT ; door++)
		{
			pRoomIndex->last_left[door] = STRDUPE(str_empty);
		}

		while (letter)
		{
			switch (letter = fread_letter(fp))
			{
				case 'S':
					letter = FALSE;
					break;
				case 'D':
					door = fread_number( fp );
					if (door > 5)
					{
						bug("fread_rooms: vnum %u has bad door number.", vnum);
						abort( );
					}
					ALLOCMEM(pExit, EXIT_DATA, 1);
					pExit->description	= fread_string( fp );
					pExit->keyword			= fread_string( fp );
					pExit->exit_info		= fread_number( fp );
					pExit->key					= fread_number( fp );
					pExit->vnum					= fread_number( fp );
					if (area_load->version >= 4)
					{
						pExit->exit_size	= fread_number( fp );
						pExit->climb_dc		= fread_number( fp );
						pExit->fall_dist		= fread_number( fp );
					}
					pExit->to_room			= pExit->vnum;
					pRoomIndex->exit[door]	= pExit;
					mud->top_exit++;
					break;
				case 'E':
					ALLOCMEM(ed, EXTRA_DESCR_DATA, 1);
					ed->keyword				= fread_string( fp );
					ed->description			= fread_string( fp );
					LINK(ed, pRoomIndex->first_extradesc, pRoomIndex->last_extradesc, next, prev);
					mud->top_ed++;
					break;
				case 'L': /* listen desc - Kregor */
					pRoomIndex->listen_desc		= fread_string( fp );
					break;
				case 'N': /* night desc - Kregor */
					pRoomIndex->night_desc		= fread_string( fp );
					break;
				case '>':
					ungetc(letter, fp);
					rprog_read_programs(fp, pRoomIndex);
// 					letter = FALSE;
					break;
				default:
					bug("Load_rooms: vnum %u uses bad flag '%c'.", vnum, letter);
					abort();
			}
		}
		mud->top_room++;
	}
	pop_call();
	return;
}

/*
	Snarf a shop section.
*/
void load_shops( FILE *fp )
{
	SHOP_DATA *pShop;
	MOB_INDEX_DATA *pMobIndex;
	bool iTrade;

	push_call("load_shops(%p)",fp);

	while (TRUE)
	{
		ALLOCMEM( pShop, SHOP_DATA, 1);

		pShop->keeper = fread_number( fp );

		if (pShop->keeper == 0)
		{
			FREEMEM(pShop);
			break;
		}
		if (get_mob_index(pShop->keeper) == NULL)
		{
			bug("load_shop: Mobile %d does not exist", pShop->keeper);
			abort();
		}
		for (iTrade = 0 ; iTrade < MAX_TRADE ; iTrade++)
		{
			pShop->buy_type[iTrade] = fread_number( fp );
		}
		pShop->shop_flags	= fread_number( fp );
		if (area_load->version < 4 || area_load->version == 99)
			pShop->shop_flags = 0;
		pShop->profit_buy	= fread_number( fp );
		pShop->profit_buy	= UMAX(pShop->profit_buy, 100);
		pShop->profit_sell	= fread_number( fp );
		pShop->profit_sell	= UMIN(pShop->profit_sell, 50);
		pShop->open_hour	= fread_number( fp );
		pShop->close_hour	= fread_number( fp );
		fread_to_eol( fp );
		pMobIndex 		= get_mob_index( pShop->keeper );

		pMobIndex->pShop	= pShop;

		LINK(pShop, mud->f_shop, mud->l_shop, next, prev);

		mud->top_shop++;
	}
	pop_call();
	return;
}

/*
	Snarf a inn section.
*/
void load_inns( FILE *fp )
{
	INN_DATA *pInn;
	MOB_INDEX_DATA *pMobIndex;
	int iRoom;

	push_call("load_inns(%p)",fp);

	while (TRUE)
	{
		ALLOCMEM( pInn, INN_DATA, 1);

		pInn->keeper = fread_number( fp );

		if (pInn->keeper == 0)
		{
			FREEMEM(pInn);
			break;
		}
		if (get_mob_index(pInn->keeper) == NULL)
		{
			bug("load_inn: Mobile %d does not exist", pInn->keeper);
			abort();
		}
		for (iRoom = 0 ; iRoom < MAX_INN_ROOMS ; iRoom++)
		{
			pInn->room[iRoom] = fread_number( fp );
			if (pInn->room[iRoom] > 0 && room_index[pInn->room[iRoom]] == NULL)
			{
				bug("load_inn: Room %d does not exist", pInn->room);
				abort();
			}
		}
		for (iRoom = 0 ; iRoom < MAX_INN_ROOMS ; iRoom++)
		{
			pInn->rent[iRoom] = fread_number( fp );
		}
		fread_number( fp );
		pInn->open_hour		= fread_number( fp );
		pInn->close_hour	= fread_number( fp );
		pInn->shop_flags	= fread_number( fp );
		fread_to_eol( fp );
		pMobIndex 				= get_mob_index( pInn->keeper );

		pMobIndex->pInn	= pInn;

		LINK(pInn, mud->f_inn, mud->l_inn, next, prev);

		mud->top_inn++;
	}
	pop_call();
	return;
}


/*
	Snarf a stable section.
*/
void load_stables( FILE *fp )
{
	STABLE_DATA *pStable;
	MOB_INDEX_DATA *pMobIndex;

	push_call("load_stables(%p)",fp);

	while (TRUE)
	{
		ALLOCMEM( pStable, STABLE_DATA, 1);

		pStable->keeper = fread_number( fp );

		if (pStable->keeper == 0)
		{
			FREEMEM(pStable);
			break;
		}
		if (get_mob_index(pStable->keeper) == NULL)
		{
			bug("load_stable: Mobile %d does not exist", pStable->keeper);
			abort();
		}
		pStable->room				= fread_number( fp );
		if (room_index[pStable->room] == NULL)
		{
			bug("load_stable: Room %d does not exist", pStable->room);
			abort();
		}
		pStable->shop_flags	= fread_number( fp );
		pStable->rent				= fread_number( fp );
		pStable->open_hour	= fread_number( fp );
		pStable->close_hour	= fread_number( fp );
		fread_to_eol( fp );
		pMobIndex 					= get_mob_index( pStable->keeper );

		pMobIndex->pStable	= pStable;

		LINK(pStable, mud->f_stable, mud->l_stable, next, prev);

		mud->top_stable++;
	}
	pop_call();
	return;
}


/*
	Snarf spec proc declarations.
*/

void load_specials( FILE *fp )
{
	int vnum;
	MOB_INDEX_DATA *pMobIndex;
	char letter;

	push_call("load_special(%p)",fp);

	while (TRUE)
	{
		switch (letter = fread_letter(fp))
		{
			default:
				bug("load_specials: letter '%c' not MSO.", letter);
				abort( );

			case 'S':
				pop_call();
				return;

			case 'M':
				vnum				= fread_number ( fp );
				pMobIndex		= get_mob_index ( vnum );
				pMobIndex->spec_fun = spec_lookup ( fread_word   ( fp ) );
				if (pMobIndex->spec_fun == NULL)
				{
					log_printf("load_specials: 'M': vnum %u.", pMobIndex->vnum );
				}
				break;
		}
		fread_to_eol( fp );
	}
	pop_call();
	return;
}


/*
	Conversion for FKMud/Smaug repair shops.
*/
void load_repairs( FILE *fp )
{
	int vnum, skill;
	MOB_INDEX_DATA *pMobIndex;

	push_call("load_shops(%p)",fp);

	while (TRUE)
	{
		if ((vnum = fread_number( fp )) == 0)
		{
			break;
		}

		if ((pMobIndex = get_mob_index(vnum)) == NULL)
		{
			bug("load_shop: Mobile %d does not exist", vnum);
			abort();
		}
		// grabs each item type repair and converts to Mud20 skill
		switch (fread_number( fp ))
		{
			case ITEM_ARMOR:
				skill = gsn_craft_armor;
				break;
			case ITEM_WEAPON:
				skill = gsn_craft_weapons;
				break;
			case ITEM_TREASURE:
				skill = gsn_craft_jewelry;
				break;
			case ITEM_CONTAINER:
				skill = gsn_craft_leather;
				break;
			default:
				skill = -1;
				break;
		}
		if (skill != -1)
		{
			pMobIndex->learned[skill] = pMobIndex->level + 3;
		}
		switch (fread_number( fp ))
		{
			case ITEM_ARMOR:
				skill = gsn_craft_armor;
				break;
			case ITEM_WEAPON:
				skill = gsn_craft_weapons;
				break;
			case ITEM_TREASURE:
				skill = gsn_craft_jewelry;
				break;
			case ITEM_CONTAINER:
				skill = gsn_craft_leather;
				break;
			default:
				skill = -1;
				break;
		}
		if (skill != -1)
		{
			pMobIndex->learned[skill] = pMobIndex->level + 3;
		}
		// just get rid of substance type because it's assumed in Mud20 skill
		fread_number( fp );
		// and the rest don't matter
		fread_to_eol( fp );
	}
	pop_call();
	return;
}

/*
 * Written to covert areas from my
 * previous server FKMud - Kregor
 */
void load_fk_mobiles( FILE *fp )
{
	MOB_INDEX_DATA *pMobIndex;
	EXTRA_DESCR_DATA *ed;
	AFFECT_DATA *paf;
	char buf[256], *pt;
	int vnum, sn, value;
	char letter;

	push_call("load_mobiles(%p)",fp);

	while (TRUE)
	{
		letter = fread_letter( fp );
		if (letter != '#')
		{
			bug( "Load_mobiles: # not found.", 0 );
			abort( );
		}

		vnum = fread_number( fp );
		if (vnum == 0)
		{
			break;
		}

		if (vnum < 1 || vnum >= MAX_VNUM)
		{
			bug("load_mobiles: vnum %u out of range.", vnum);
			abort( );
		}
		if (get_mob_index(vnum) != NULL)
		{
			bug("load_mobiles: vnum %u duplicated.", vnum);
			abort( );
		}

		ALLOCMEM(pMobIndex, MOB_INDEX_DATA, 1);

		pMobIndex->vnum			= vnum;
		mob_index[vnum]			= pMobIndex;
		pMobIndex->area			= area_load;

		if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
		{
			if (area_load->low_m_vnum > vnum)
			{
				area_load->low_m_vnum = vnum;
			}
			if (vnum > area_load->hi_m_vnum)
			{
				area_load->hi_m_vnum = vnum;
			}
		}

		pt = fread_string( fp );  /* Add M### system to names */
		sprintf( buf, "m%u", vnum );
		if (strstr(pt, buf) == NULL)
		{
			sprintf( buf, "%s m%u", pt, vnum );
		}
		else
		{
			strcpy( buf, pt );
		}
		STRFREE (pt);

		pMobIndex->player_name	= STRALLOC(buf);
		
		pMobIndex->short_descr	= fread_string( fp );
		pMobIndex->long_descr	= fread_string( fp );
		pMobIndex->description	= fread_string( fp );
		
		pMobIndex->unique = FALSE;

		letter				= fread_letter( fp );
		if (letter == 'U')
			pMobIndex->unique = TRUE;
		else if (letter == 'S')
			pMobIndex->unique = FALSE;
		else
		{
			bug( "Load_mobiles: vnum %u not U or S.", vnum );
			abort( );
		}
		pMobIndex->level				= fread_number( fp );
		pMobIndex->class				= fread_number( fp );
		pMobIndex->race					= fread_number( fp );
		pMobIndex->sex					= fread_number( fp );
		pMobIndex->position			= fread_number( fp );
		pMobIndex->god					= fread_number( fp );
		pMobIndex->act					= fread_number( fp );

		// Convert 50 level scale to 20 - Kregor
		if (!IS_SET(pMobIndex->act, ACT_MOBINVIS))
			pMobIndex->level 				= UMAX(1, pMobIndex->level / 2);

		if (!pMobIndex->unique)
		{
			if (pMobIndex->race <= RACE_NONE)
			{
				bug( "Load_mobiles: no race set on S mobile.", vnum );
				pMobIndex->race = RACE_HUMAN;
			}
			if (pMobIndex->class != CLASS_MONSTER && pMobIndex->class < MAX_CLASS)
				pMobIndex->hitsizedice 	= class_table[pMobIndex->class].hp_max;
			else if (pMobIndex->race > RACE_NONE)
				pMobIndex->hitsizedice 	= race_type_table[race_table[pMobIndex->race].type].hit_die;
			else
			{
				bug( "Load_mobiles: neither class nor race hit die.", vnum );
				pMobIndex->hitsizedice 	= 8;
			}
			pMobIndex->alignment		= race_table[pMobIndex->race].alignment;
			pMobIndex->ethos				= race_table[pMobIndex->race].ethos;
			pMobIndex->gold					= 0; // need to add means to determine standard random gold
	
			/*
			 * assign stats based on class pri and sec stats
			 * These routines effectively gives standard NPCs
			 * an elite array of abilities - Kregor
			 */
			if (pMobIndex->class > CLASS_MONSTER)
			{
				int class = pMobIndex->class;

				if (class_table[class].attr_prime == APPLY_STR)
					pMobIndex->perm_str			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[0];
				else if (class_table[class].attr_second == APPLY_STR)
					pMobIndex->perm_str			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[0];
				else
					pMobIndex->perm_str			= best_three_of_four() + race_table[pMobIndex->race].race_mod[0];
				if (class_table[class].attr_prime == APPLY_DEX)
					pMobIndex->perm_dex			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[1];
				else if (class_table[class].attr_second == APPLY_DEX)
					pMobIndex->perm_dex			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[1];
				else
					pMobIndex->perm_dex			= best_three_of_four() + race_table[pMobIndex->race].race_mod[1];
				if (class_table[class].attr_prime == APPLY_CON)
					pMobIndex->perm_con			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[2];
				else if (class_table[class].attr_second == APPLY_CON)
					pMobIndex->perm_con			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[2];
				else
					pMobIndex->perm_con			= best_three_of_four() + race_table[pMobIndex->race].race_mod[2];
				if (class_table[class].attr_prime == APPLY_INT)
					pMobIndex->perm_int			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[3];
				else if (class_table[class].attr_second == APPLY_INT)
					pMobIndex->perm_int			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[3];
				else
					pMobIndex->perm_int			= best_three_of_four() + race_table[pMobIndex->race].race_mod[3];
				if (class_table[class].attr_prime == APPLY_WIS)
					pMobIndex->perm_wis			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[4];
				else if (class_table[class].attr_second == APPLY_WIS)
					pMobIndex->perm_wis			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[4];
				else
					pMobIndex->perm_wis			= best_three_of_four() + race_table[pMobIndex->race].race_mod[4];
				if (class_table[class].attr_prime == APPLY_CHA)
					pMobIndex->perm_cha			= 12 + dice(1,6) + race_table[pMobIndex->race].race_mod[5];
				else if (class_table[class].attr_second == APPLY_CHA)
					pMobIndex->perm_cha			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[5];
				else
					pMobIndex->perm_cha			= best_three_of_four() + race_table[pMobIndex->race].race_mod[5];
			}
			else
			{
				pMobIndex->perm_str			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[0];
				pMobIndex->perm_int			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[1];
				pMobIndex->perm_wis			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[2];
				pMobIndex->perm_dex			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[3];
				pMobIndex->perm_con			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[4];
				pMobIndex->perm_cha			= 8 + dice(1,6) + race_table[pMobIndex->race].race_mod[5];
			}
			// zero out nonabilities by race
			if (race_table[pMobIndex->race].nonability[STAT_STR])
				pMobIndex->perm_str		= 0;
			if (race_table[pMobIndex->race].nonability[STAT_DEX])
				pMobIndex->perm_dex		= 0;
			if (race_table[pMobIndex->race].nonability[STAT_CON])
				pMobIndex->perm_con		= 0;
			if (race_table[pMobIndex->race].nonability[STAT_INT])
				pMobIndex->perm_int		= 0;
			if (race_table[pMobIndex->race].nonability[STAT_WIS])
				pMobIndex->perm_wis		= 0;
			if (race_table[pMobIndex->race].nonability[STAT_CHA])
				pMobIndex->perm_cha		= 0;

			pMobIndex->nat_armor		= race_table[pMobIndex->race].nat_armor;
			pMobIndex->wear_locs		= race_table[pMobIndex->race].wear_locs;
			pMobIndex->size					=	race_table[pMobIndex->race].size;
			pMobIndex->understands	= race_table[pMobIndex->race].understands;
			pMobIndex->speaks				= race_table[pMobIndex->race].speaks;				
		}
		else
		{
			pMobIndex->affected_by	= fread_number( fp );
			pMobIndex->armor_type		= fread_number( fp );
			/*unused*/	fread_number( fp );
	
			/* 'd' */	fread_letter( fp );
			if (pMobIndex->class > CLASS_MONSTER && pMobIndex->class < MAX_CLASS)
			{
				fread_number( fp );
				pMobIndex->hitsizedice 	= class_table[pMobIndex->class].hp_max;
			} 
			else if (pMobIndex->race > RACE_NONE)
			{
				fread_number( fp );
				pMobIndex->hitsizedice 	= race_type_table[race_table[pMobIndex->race].type].hit_die;
			}
			else
			{
				pMobIndex->hitsizedice	= fread_number( fp );
			}
			/* '+' */	fread_letter( fp );
			pMobIndex->hitplus			= fread_number( fp );
			pMobIndex->alignment		= fread_number( fp );
			pMobIndex->perm_str			= fread_number( fp );
			pMobIndex->perm_int			= fread_number( fp );
			pMobIndex->perm_wis			= fread_number( fp );
			pMobIndex->perm_dex			= fread_number( fp );
			pMobIndex->perm_con			= fread_number( fp );
			pMobIndex->perm_cha			= fread_number( fp );
																fread_number( fp );  // read and discard LUCK stat
																fread_number( fp );  // unused field
																fread_number( fp );  // unused field
																fread_number( fp );  // unused field
																fread_number( fp );  // unused field
																fread_number( fp );  // unused field
			pMobIndex->speaks				= fread_number( fp );
			pMobIndex->understands	= fread_number( fp );
			/* Unused */	 fread_number( fp );
			/* Unused */	 fread_number( fp );
			/* Unused */	 fread_number( fp );
		}
		if (pMobIndex->size == 0)
			pMobIndex->size				=	race_table[pMobIndex->race].size;		

		pMobIndex->mclass[pMobIndex->class] = pMobIndex->level;
		
		while (letter)
		{
			switch (letter = fread_letter(fp))
			{
				case 'A':
					ALLOCMEM(paf, AFFECT_DATA, 1);
					paf->type					= 0;
					paf->duration			= -1;
					paf->location			= fread_number( fp );
					paf->modifier			= fread_number( fp );
					paf->bittype			= AFFECT_TO_NONE;
					paf->level      	= pMobIndex->level;
					paf->caster				= STRALLOC("None");

					LINK(paf, pMobIndex->first_affect, pMobIndex->last_affect, next, prev);
					mud->top_affect++;
					break;
				case 'E':
					ALLOCMEM(ed, EXTRA_DESCR_DATA, 1);
					ed->keyword		= fread_string( fp );
					ed->description	= fread_string( fp );
					LINK(ed, pMobIndex->first_extradesc, pMobIndex->last_extradesc, next, prev);
					mud->top_ed++;
					break;
				case '%':
					value = fread_number( fp );
					value = URANGE(0, value, 99);
									fread_number( fp ); // unused
					sn = skill_lookup( fread_string( fp ) );
					if (sn < 0)
					{
						break;
					}
					if (skill_table[sn].skilltype != FSKILL_FEAT
					&& skill_table[sn].skilltype != FSKILL_SKILL
					&& skill_table[sn].skilltype != FSKILL_SPELL
					&& skill_table[sn].skilltype != FSKILL_CRAFT
					&& skill_table[sn].skilltype != FSKILL_KNOWLEDGE)
					{
						break;
					}
					pMobIndex->learned[sn] = value;
					break;
				case '>':
					ungetc(letter, fp);
					mprog_read_programs(fp, pMobIndex);
					letter = FALSE;
					break;

				default:
					ungetc(letter, fp);
					letter = FALSE;
					break;
			}
		}
		// Add sorcerer "multiclass" to dragon race
		if (race_table[pMobIndex->race].parent_race == RACE_DRAGON && pMobIndex->mclass[CLASS_SORCERER] == 0)
			pMobIndex->mclass[CLASS_SORCERER] = dragon_caster_level(pMobIndex->level);

		if (!pMobIndex->unique && pMobIndex->race && pMobIndex->level > race_table[pMobIndex->race].hit_dice)
			advance_mobile(pMobIndex);

		mud->top_mob_index++;
	}
	pop_call();
	return;
}

void load_fk_objects( FILE *fp )
{
	OBJ_INDEX_DATA *pObjIndex;
	EXTRA_DESCR_DATA *ed;
	AFFECT_DATA *paf;
	char buf[256], *pt;
	int vnum;
	char letter;

	push_call("load_object(%p)",fp);

	while (TRUE)
	{
		letter = fread_letter( fp );

		if ( letter != '#' )
		{
			bug( "Load_objects: # not found.", 0 );
			abort( );
		}

		vnum = fread_number( fp );

		if ( vnum == 0 )
		{
			break;
		}

		if (vnum < 1 || vnum >= MAX_VNUM)
		{
			bug("load_objects: vnum %u out of range.", vnum);
			abort( );
		}

		if (get_obj_index(vnum) != NULL)
		{
			bug("load_objects: vnum %u duplicated.", vnum);
			abort();
		}

		ALLOCMEM(pObjIndex, OBJ_INDEX_DATA, 1);
		pObjIndex->vnum = vnum;

		if (area_load->low_o_vnum > vnum)
		{
			area_load->low_o_vnum = vnum;
		}
		if (vnum > area_load->hi_o_vnum)
		{
			area_load->hi_o_vnum = vnum;
		}
		obj_index[ vnum ] = pObjIndex;
		pObjIndex->area = area_load;

		pt = fread_string( fp );  /* Add i### system to names */
		sprintf( buf, "i%u", vnum );
		if (strstr(pt, buf) == NULL)
		{
			sprintf( buf, "%s i%u", pt, vnum );
		}
		else
		{
			strcpy( buf, pt );
		}
		STRFREE (pt);

		pObjIndex->name					= STRALLOC(buf);
		pObjIndex->short_descr	= fread_string( fp );
		pObjIndex->long_descr		= fread_string( fp );
		pObjIndex->description	= fread_string( fp );
		pObjIndex->item_type		= fread_number( fp );
		pObjIndex->extra_flags	= fread_number( fp );
		pObjIndex->wear_flags		= fread_number( fp );
							/* unused */		fread_number( fp ); // was quality in FKMud
		pObjIndex->material			= fread_number( fp );
		pObjIndex->hit_points		= fread_number( fp );
		pObjIndex->size					= fread_number( fp );
		pObjIndex->value[0]			= fread_number( fp );
		pObjIndex->value[1]			= fread_number( fp );
		pObjIndex->value[2]			= fread_number( fp );
		pObjIndex->value[3]			= fread_number( fp );
		pObjIndex->value[4]			= fread_number( fp );
		pObjIndex->value[5]			= fread_number( fp );
		pObjIndex->attack_string	= STRDUPE(str_empty);
		pObjIndex->id_name			= STRDUPE(str_empty);
		pObjIndex->id_descr			= STRDUPE(str_empty);
		
		/* added to fix new wear size value for armor */
		if (pObjIndex->item_type == ITEM_ARMOR && pObjIndex->value[3] <= 0)
			pObjIndex->value[3] = SIZE_MEDIUM;

		while (letter)
		{
			switch (letter = fread_letter(fp))
			{
				case 'A':
					ALLOCMEM(paf, AFFECT_DATA, 1);
					paf->type					= 0;
					paf->duration			= -1;
					paf->location			= fread_number( fp );
					paf->modifier			= fread_number( fp );
					paf->bittype			= AFFECT_TO_NONE;
					paf->level      	= obj_level_estimate(pObjIndex);
					paf->caster				= STRALLOC("None");

					LINK(paf, pObjIndex->first_affect, pObjIndex->last_affect, next, prev);
					SET_BIT(pObjIndex->extra_flags, ITEM_MAGIC);
					mud->top_affect++;
					break;
				case 'E':
					ALLOCMEM(ed, EXTRA_DESCR_DATA, 1);
					ed->keyword			= fread_string( fp );
					ed->description		= fread_string( fp );
					LINK(ed, pObjIndex->first_extradesc, pObjIndex->last_extradesc, next, prev);
					mud->top_ed++;
					break;
				case 'I':
					STRFREE(pObjIndex->id_name);
					pObjIndex->id_name	= fread_line( fp );
					STRFREE(pObjIndex->id_descr);
					pObjIndex->id_descr	= fread_string( fp );
					break;
				// this remnant of MRMud left to simply allow loading of old areas
				case '>':
					ungetc(letter, fp);
					oprog_read_programs(fp, pObjIndex);
					letter = FALSE;
					break;
				default:
					ungetc(letter, fp);
					letter = FALSE;
					break;
			}
		}
		if (obj_index_cost(pObjIndex) != -1)
			pObjIndex->cost				= obj_index_cost(pObjIndex);
		fix_materials(pObjIndex);
		fix_sizes(pObjIndex);
		if (load_obj_weight(pObjIndex) != -1)
			pObjIndex->weight			= load_obj_weight(pObjIndex);
		load_obj_hit(pObjIndex);

		mud->top_obj_index++;
	}
	pop_call();
	return;
}

/*
 * Read in FKMud/Smaug weather stat,
 * convert into Mud20 stats - Kregor
 */
void load_fk_weather( FILE * fp )
{
	push_call("load_weather(%p)",fp);

	area_load->weather_info->temp_summer	= fread_number(fp) * 12;
	area_load->weather_info->temp_winter	= area_load->weather_info->temp_summer / 2;
	area_load->weather_info->temp_daily	= (area_load->weather_info->temp_summer - area_load->weather_info->temp_summer) / 2;
	area_load->weather_info->wet_scale		= fread_number(fp);

	pop_call();
	return;
}


void load_fk_rooms( FILE *fp )
{
	ROOM_INDEX_DATA *pRoomIndex;
	EXIT_DATA *pExit;
	EXTRA_DESCR_DATA *ed;
	int vnum;
	bool door;
	char letter;

	push_call("load_rooms(%p)",fp);

	if (area_load == NULL)
	{
		bug( "Load_resets: no #AREA seen yet.", 0 );
		abort( );
	}

	while (TRUE)
	{
		letter = fread_letter( fp );

		if (letter != '#')
		{
		    bug( "Load_rooms: # not found.", 0 );
		    abort( );
		}

		vnum	= fread_number(fp);

		if (vnum == 0)
		{
			break;
		}

		if (vnum < 0 || vnum >= MAX_VNUM)
		{
			bug("load_rooms: vnum %u out of range.", vnum);
			abort( );
		}

		if (room_index[vnum] != NULL && vnum < MAX_VNUM)
		{
			bug("load_rooms: vnum %u duplicated.", vnum);
			abort( );
		}

		ALLOCMEM(pRoomIndex, ROOM_INDEX_DATA, 1);

		if (vnum < area_load->low_r_vnum)
		{
			area_load->low_r_vnum = vnum;
		}
		if (vnum > area_load->hi_r_vnum)
		{
			area_load->hi_r_vnum = vnum;
		}

		pRoomIndex->area			= area_load;
		pRoomIndex->vnum			= vnum;
		room_index[vnum]			= pRoomIndex;

		pRoomIndex->name			= fread_string( fp );
		pRoomIndex->description		= fread_string( fp );
		pRoomIndex->listen_desc		= STRDUPE( str_empty );
		pRoomIndex->night_desc		= STRDUPE( str_empty );
			/* not used */	fread_number( fp );
		pRoomIndex->room_flags		= fread_number( fp );
		pRoomIndex->sector_type		= fread_number( fp );
			/* not used */	fread_number( fp );
			/* not used */	fread_number( fp );
			/* not used */	fread_number( fp );

		for (door = 0 ; door < MAX_LAST_LEFT ; door++)
		{
			pRoomIndex->last_left[door] = STRDUPE(str_empty);
		}

		while (letter)
		{
			switch (letter = fread_letter(fp))
			{
				case 'S':
					letter = FALSE;
					break;
				case 'D':
					door = fread_number( fp );
					if (door > 5)
					{
						bug("fread_rooms: vnum %u has bad door number.", vnum);
						abort( );
					}
					ALLOCMEM(pExit, EXIT_DATA, 1);
					pExit->description	= fread_string( fp );
					pExit->keyword			= fread_string( fp );
					pExit->exit_info		= fread_number( fp );
					pExit->key					= fread_number( fp );
					pExit->vnum					= fread_number( fp );
							/* not used */	fread_number( fp );
					pExit->to_room			= pExit->vnum;
					pRoomIndex->exit[door]	= pExit;
					mud->top_exit++;
					break;
				case 'E':
					ALLOCMEM(ed, EXTRA_DESCR_DATA, 1);
					ed->keyword				= fread_string( fp );
					ed->description			= fread_string( fp );
					LINK(ed, pRoomIndex->first_extradesc, pRoomIndex->last_extradesc, next, prev);
					mud->top_ed++;
					break;
				case '>':
					ungetc(letter, fp);
					rprog_read_programs(fp, pRoomIndex);
// 					letter = FALSE;
					break;
				default:
					bug("Load_rooms: vnum %u uses bad flag '%c'.", vnum, letter);
					abort();
			}
		}
		mud->top_room++;
	}
	pop_call();
	return;
}

/*
	This procedure is responsible for reading any in_file MOBprograms.
*/

void mprog_read_programs( FILE *fp, MOB_INDEX_DATA *pMobIndex)
{
	MPROG_DATA *mprg;
	bool        done = FALSE;

	push_call("mprog_read_programs(%p,%p)",fp,pMobIndex);

	if (fread_letter(fp) != '>')
	{
		bug("load_mobiles: vnum %d MOBPROG char", pMobIndex->vnum);
		abort( );
	}

	ALLOCMEM(mprg, MPROG_DATA, 1);

	while (!done)
	{
		mprg->type = mprog_name_to_type(fread_word(fp));

		switch ( mprg->type )
		{
			case ERROR_PROG:
				bug("load_mobiles: vnum %u ERROR_PROG type.", pMobIndex->vnum);
				abort( );
				break;
			default:
				SET_BIT(pMobIndex->progtypes, mprg->type);

				mprg->arglist		= fread_string( fp );
				fread_to_eol( fp );

				mprg->comlist		= fread_string( fp );
				fread_to_eol( fp );

				if (strstr(mprg->comlist, "$r") != NULL)
				{
					SET_BIT(mprg->flags, MPTRIGGER_RAND_PLR);
				}
				expand_mob_prog( pMobIndex, NULL, NULL, mprg );  /* Tokenize Mobprog */

				LINK(mprg, pMobIndex->first_prog, pMobIndex->last_prog, next, prev);

				switch (fread_letter( fp ) )
				{
					case '>':
						ALLOCMEM(mprg, MPROG_DATA, 1);
						break;
					case '|':
						fread_to_eol( fp );
						done = TRUE;
						break;
					default:
						bug( "Load_mobiles: vnum %u bad MOBPROG.", pMobIndex->vnum );
						abort();
						break;
				}
				break;
		}
	}
	pop_call();
	return;
}

/*
	This procedure is responsible for reading any in_file OBJprograms.
*/
void oprog_read_programs( FILE *fp, OBJ_INDEX_DATA *pObjIndex)
{
	MPROG_DATA *mprg;
	bool done = FALSE;
	char letter;

	push_call("oprog_read_programs(%p,%p)",fp,pObjIndex);

	if ((letter = fread_letter(fp)) != '>')
	{
		bug("load_objects: vnum %d MOBPROG obj, letter is '%c'", pObjIndex->vnum, letter);
		abort( );
	}

	ALLOCMEM(mprg, MPROG_DATA, 1);

	while (!done)
	{
		mprg->type = mprog_name_to_type(fread_word(fp));

		switch ( mprg->type )
		{
			case ERROR_PROG:
				bug("load_objects: vnum %u ERROR_PROG type.", pObjIndex->vnum);
				abort( );
				break;
			default:
				SET_BIT(pObjIndex->progtypes, mprg->type);

				mprg->arglist		= fread_string( fp );
				fread_to_eol( fp );

				mprg->comlist		= fread_string( fp );
				fread_to_eol( fp );

				if (strstr(mprg->comlist, "$r") != NULL)
				{
					SET_BIT(mprg->flags, MPTRIGGER_RAND_PLR);
				}
				expand_mob_prog( NULL, pObjIndex, NULL, mprg );  /* Tokenize Mobprog */

				LINK(mprg, pObjIndex->first_prog, pObjIndex->last_prog, next, prev);

				switch (fread_letter( fp ) )
				{
					case '>':
						ALLOCMEM(mprg, MPROG_DATA, 1);
						break;
					case '|':
						fread_to_eol( fp );
						done = TRUE;
						break;
					default:
						bug( "Load_objects: vnum %u bad MOBPROG obj.", pObjIndex->vnum );
						abort();
						break;
				}
				break;
		}
	}
	pop_call();
	return;
}


/*
	This procedure is responsible for reading any in_file ROOMprograms.
*/

void rprog_read_programs( FILE *fp, ROOM_INDEX_DATA *pRoomIndex)
{
	MPROG_DATA *mprg;
	bool		  done = FALSE;

	push_call("rprog_read_programs(%p,%p)",fp,pRoomIndex);

	if (fread_letter(fp) != '>')
	{
		bug("load_rooms: vnum %d MOBPROG obj", pRoomIndex->vnum);
		abort( );
	}

	ALLOCMEM(mprg, MPROG_DATA, 1);

	while (!done)
	{
		mprg->type = mprog_name_to_type(fread_word(fp));

		switch ( mprg->type )
		{
			case ERROR_PROG:
				bug("load_mobiles: vnum %u ERROR_PROG type.", pRoomIndex->vnum);
				abort( );
				break;
			default:
				SET_BIT(pRoomIndex->progtypes, mprg->type);

				mprg->arglist		= fread_string( fp );
				fread_to_eol( fp );

				mprg->comlist		= fread_string( fp );
				fread_to_eol( fp );

				if (strstr(mprg->comlist, "$r") != NULL)
				{
					SET_BIT(mprg->flags, MPTRIGGER_RAND_PLR);
				}
				expand_mob_prog( NULL, NULL, pRoomIndex, mprg );  /* Tokenize Mobprog */

				LINK(mprg, pRoomIndex->first_prog, pRoomIndex->last_prog, next, prev);

				switch (fread_letter( fp ) )
				{
					case '>':
						ALLOCMEM(mprg, MPROG_DATA, 1);
						break;
					case '|':
						fread_to_eol( fp );
						done = TRUE;
						break;
					default:
						bug( "load_rooms: vnum %u bad MOBPROG room.", pRoomIndex->vnum );
						abort();
						break;
				}
				break;
		}
	}
	pop_call();
	return;
}


void expand_mob_prog( MOB_INDEX_DATA *mind, OBJ_INDEX_DATA *obj, ROOM_INDEX_DATA *room, MPROG_DATA *mprog )
{
	char buf[MAX_INPUT_LENGTH];
	char *pti, *pto;
	char level;

	push_call("expand_mob_prog(%p,%p,%p,%p)",mind,obj,room,mprog);

	pti = mprog->comlist;
	level = 0;

	while (*pti != '\0')
	{
		while (*pti == '\n' || *pti == '\r')
		{
			pti++;
		}
		if (*pti != '\0')
		{
			for (pto = buf ; *pti != '\r' && *pti != '\n' && *pti != '\0' ; pti++, pto++)
			{
				*pto = *pti;
			}
			*pto = '\0';
			level = expand_line_mprog( mind, obj, room, mprog, buf, FALSE, level );
		}
	}

	/*
		fixer_mprog will rebuild the old comlist - Scandum
	*/
	STRFREE(mprog->comlist);
	pop_call();
	return;
}

char expand_line_mprog( MOB_INDEX_DATA *mind, OBJ_INDEX_DATA *obj, ROOM_INDEX_DATA *room, MPROG_DATA *mprog, char *line, bool iForce, char level )
{
	char *pti, *pto;
	char buf[MAX_INPUT_LENGTH];
	char string[MAX_INPUT_LENGTH];
	int type;
	void *func;
	int value;
	NPC_TOKEN *token;
	char achange, bchange;

	push_call("expand_line_mprog(%p,%p,%p,%p,%p,%p,%p)",mind,obj,room,mprog,line,iForce,level);

	func = NULL;

	for (pti = line ; *pti == ' ' ; pti++);
	
	for (pto = buf ; isalnum(*pti) ; pti++, pto++)
	{
		*pto = *pti;
	}
	*pto = '\0';

	if (*buf == '\0')
	{
		pop_call();
		return(level);
	}
	type		= 0;	/* Error type */
	value	= 0;
	achange	= 0;
	bchange	= 0;

	switch (buf[0])
	{
		case 'b':
			if (!strcmp(buf, "break"))
			{
				type		= MPTOKEN_BREAK;
			}
			break;
		case 'c':
			if (!strcmp(buf, "case"))
			{
				type = MPTOKEN_CASE;
				bchange	= -1;
				achange	= 1;
			}
			break;
		case 'd':
			if (!strcmp(buf, "default"))
			{	
				type		= MPTOKEN_DEFAULT;
				bchange	= -1;
				achange	= 1;
			}
			break;
		case 'e':
			if (!strcmp(buf, "else"))
			{
				type		= MPTOKEN_ELSE;
				bchange	=-1;
				achange	= 1;
			}
			else if (!strcmp(buf, "endif"))
			{
				type		= MPTOKEN_ENDIF;
				bchange	=-1;
			}
			else if (!strcmp(buf, "endswitch"))
			{
				type		= MPTOKEN_ENDSWITCH;
				bchange	= -2;
			}
			break;
		case 'i':
			if (!strcmp(buf, "if"))
			{
				type		= MPTOKEN_IF;
				achange	= 1;
			}
			else if (!strcmp(buf, "ifnot"))
			{
				type		= MPTOKEN_IFNOT;
				achange	= 1;
			}
			break;
		case 'o':
			if (!strcmp(buf, "or"))
			{
				type		= MPTOKEN_OR;
				bchange	= -1;
				achange	=  1;
			}
			else if (!strcmp(buf, "ornot"))
			{
				type		= MPTOKEN_ORNOT;
				bchange	= -1;
				achange	=  1;
			}
			break;
		case 's':
			if (!strcmp(buf, "switch"))
			{
				type = MPTOKEN_SWITCH;
				achange	= 2;
			}
			break;
	}

	if (type == 0)
	{
		if ((value = find_command(buf, MAX_LEVEL - 1)) >= 0)
		{
			func = (void *) cmd_table[value].do_fun;
			type = 2;
		}
		else if ((value = find_social(buf)) >= 0)
		{
			func = (void *) social_table[value].name;
			type = 1;
		}
		if (func == NULL)
		{
			log_printf("expand_line_mprog: unknown command: %s", buf);
			value = 0;
			type  = 0;
		}
	}

	ALLOCMEM(token, NPC_TOKEN, 1);
	token->type		= type;
	token->function	= func;
	token->value		= value;

	mud->top_mprog++;

	LINK(token, mprog->first_token, mprog->last_token, next, prev);

	level += bchange;		/* before change */
	if (level < 0)
	{
		level = 0;
	}
	token->level = level;
	level += achange;		/* after change */

	while (*pti == ' ')
	{
		pti++;
	}

	if (type == MPTOKEN_IF || type == MPTOKEN_OR || type == MPTOKEN_SWITCH)
	{
		pto = string;

		while (*pti != '(')
		{
			if (*pti == '\0')
			{
				if (mind)
					log_build_printf(mind->vnum, "ifchck syntax error");
				else if (obj)
					log_build_printf(obj->vnum, "ifchck syntax error");
				else if (room)
					log_build_printf(room->vnum, "ifchck syntax error");

				token->type = 0;
				break;
			}
			else	if (*pti == ' ')
			{
				pti++;
			}
			else
			{
				*pto++ = *pti++;
			}
		}
		*pto++ = ' ';

		while (*pti != ')')
		{
			if (*pti == '\0')
			{
				if (mind)
					log_build_printf(mind->vnum, "ifchck syntax error");
				else if (obj)
					log_build_printf(obj->vnum, "ifchck syntax error");
				else if (room)
					log_build_printf(room->vnum, "ifchck syntax error");

				token->type = 0;
				break;
			}
// 			else	if (*pti == ' ')
// 			{
// 				pti++;
// 			}
			else
			{
				*pto++ = *pti++;
			}
		}
		*pto++ = *pti++;

		while (*pti == ' ')
		{
			pti++;
		}

		if (*pti == '\0')
		{
			*pto = '\0';
			token->string = STRALLOC(string);

			pop_call();
			return level;
		}
		else
		{
			*pto++ = ' ';

			while (*pti != ' ' && !isalnum(*pti))
			{
				if (*pti == '\0')
				{
					if (mind)
						log_build_printf(mind->vnum, "ifchck operator without value");
					else if (obj)
						log_build_printf(obj->vnum, "ifchck operator without value");
					else if (room)
						log_build_printf(room->vnum, "ifchck operator without value");
						
					token->string = STRDUPE(str_empty);

					pop_call();
					return level;
				}
				else
				{
					*pto++ = *pti++;
				}
			}

			while (*pti == ' ')
			{
				pti++;
			}

			*pto++ = ' ';

			while (*pti != '\0') /* took out *pto++ != ' ' right here */
			{
				*pto++ = *pti++;
			}
			*pto = '\0';

			token->string = STRALLOC(string);

			pop_call();
			return level;
		}
	}

	for (pto = string ; *pti != '\0' && *pti != '\r' && *pti != '\n' ; pti++, pto++)
	{
		*pto = *pti;
	}
	*pto = '\0';

	token->string = STRALLOC(string);

	pop_call();
	return(level);
}


/*
	Repopulate areas periodically.
*/

void repop_area ( AREA_DATA *pArea )
{
	PLAYER_GAME *gpl;
	
	push_call("repop_area(%p)",pArea);

	pArea->age++;

	if (pArea->nplayer > 0 && pArea->age == 39 && (!pArea->resetmsg || strcasecmp(pArea->resetmsg, "off")))
	{
		int rnd = number_range(1, 4);

		for (gpl = mud->f_player ; gpl ; gpl = gpl->next)
		{
			if (IS_AWAKE(gpl->ch) && gpl->ch->in_room && gpl->ch->in_room->area == pArea)
			{
				if (pArea->resetmsg && pArea->resetmsg[0] != '\0')
				{
					ch_printf_color(gpl->ch, "%s\n\r", pArea->resetmsg);
				}
				else
				{
					switch (gpl->ch->in_room->sector_type)
					{
						case SECT_INSIDE:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "You hear the boards creaking.\n\r");	break;
								case 2: ch_printf_color(gpl->ch, "You hear growling echoing in the distance.\n\r");	break;
								case 3: ch_printf_color(gpl->ch, "You hear wax dripping off a candle.\n\r" );	break;
								case 4: ch_printf_color(gpl->ch, "You hear foot steps in the distance.\n\r");	break;
							}
							break;
						case SECT_CITY:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "You hear the shuffle of feet upon the street.\n\r");	break;
								case 2: ch_printf_color(gpl->ch, "You hear the idle chatter of passers by.\n\r");	break;
								case 3: ch_printf_color(gpl->ch, "You hear shopkeepers announcing their wares.\n\r");	break;
								case 4: ch_printf_color(gpl->ch, "Patrons and merchants roam about the streets.\n\r");	break;
							}
							break;
						case SECT_FIELD:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sYou hear small creatures rustling the grass.\n\r", ansi_translate("{128}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sYou hear large creatures rustling the grass.\n\r", ansi_translate("{128}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sField mice scurrying about in the brush.\n\r", ansi_translate("{128}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sThe wind whispers softly through the grasses.\n\r", ansi_translate("{128}"));	break;
							}
							break;
						case SECT_FOREST:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sYou hear the trees creaking in the wind.\n\r", ansi_translate("{028}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sThe sound of forest creatures echoes around the trees.\n\r", ansi_translate("{028}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sThe wind carries the scent of evergreens through the trees.\n\r", ansi_translate("{028}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sYou hear the distinct sound of trees grooming one another in the wind.\n\r", ansi_translate("{028}"));	break;
							}
							break;
						case SECT_HILLS:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sThe wind causes the grass to sway along the rolling hills.\n\r", ansi_translate("{038}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sYou hear nothing but a peaceful, easy calm.\n\r", ansi_translate("{038}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sWildflowers dance with the grass in the wind.\n\r", ansi_translate("{038}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sThe bleating of a goat carries far across the hillside.\n\r", ansi_translate("{038}"));	break;
							}
							break;
						case SECT_MOUNTAIN:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sYou hear a rockslide off in the distance.\n\r", ansi_translate("{038}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sYou hear echos of large hooved animals wandering across the rocks.\n\r", ansi_translate("{038}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sThe sound of rams' horns clashing echoes in the distance.\n\r", ansi_translate("{038}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sThe wind whips briskly along the side of the mountain.\n\r", ansi_translate("{038}"));	break;
							}
							break;
						case SECT_LAKE:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sYou hear fish splashing in the water.\n\r", ansi_translate("{168}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sBubbles gently rise to the surface of the water.\n\r", ansi_translate("{168}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sThe water ripples gently around you.\n\r", ansi_translate("{168}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sWater laps lightly against the shoreline.\n\r", ansi_translate("{168}"));	break;
							}
							break;
						case SECT_RIVER:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sThe river's waters gurgle softly as they flow.\n\r", ansi_translate("{168}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sWater splashes as it runs over the rocks.\n\r", ansi_translate("{168}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sSmall fishes splash about in the water.\n\r", ansi_translate("{168}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sThe flow of the water continues its way downstream.\n\r", ansi_translate("{168}"));	break;
							}
							break;
						case SECT_OCEAN:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sThe waves crest around you loudly.\n\r", ansi_translate("{148}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sLarge fishes splash in the water around you.\n\r", ansi_translate("{148}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sYou hear a fog horn echoing through the darkness.\n\r", ansi_translate("{148}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sYou hear the echoes of sea creatures deep below.\n\r", ansi_translate("{148}"));	break;
							}
							break;
						case SECT_AIR:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "The wind blows harshly around you.\n\r");	break;
								case 2: ch_printf_color(gpl->ch, "You hear birds of prey screeching nearby.\n\r");	break;
								case 3: ch_printf_color(gpl->ch, "The clouds roll and whisp around you.\n\r");	break;
								case 4: ch_printf_color(gpl->ch, "The air rushes at you from all directions at once.\n\r");	break;
							}
							break;
						case SECT_DESERT:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sThe desert wind whips the sand fiercely.\n\r", ansi_translate("{138}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sThe desert heat radiates off of the sands.\n\r", ansi_translate("{138}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sYou hear a sandstorm growing in the distance.\n\r", ansi_translate("{138}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sAn oasis appears and fades as a mirage in the distance.\n\r", ansi_translate("{138}"));	break;
							}
							break;
						case SECT_LAVA:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sYou hear the bubbling of molten stone.\n\r", ansi_translate("{118}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sYou hear grinding of rocks.\n\r", ansi_translate("{118}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sLava steams and sizzles as it bubbles onto cold stone.\n\r", ansi_translate("{118}"));	break;
								case 4: ch_printf_color(gpl->ch, "%scraters of molten earth groan and bubble around you.\n\r", ansi_translate("{118}"));	break;
							}
							break;
						case SECT_ETHEREAL:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "You hear echos of an unknown creature.\n\r");	break;
								case 2: ch_printf_color(gpl->ch, "You hear the distant explosions of power.\n\r");	break;
								case 3: ch_printf_color(gpl->ch, "You hear an indescribable sound.\n\r");	break;
								case 4: ch_printf_color(gpl->ch, "You feel a transparent mist appear and thicken about you momentarily.\n\r");	break;
							}
							break;
						case SECT_ASTRAL:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "You hear silence echoing in your head.\n\r");	break;
								case 2: ch_printf_color(gpl->ch, "You hear the pain of a lost soul.\n\r");	break;
								case 3: ch_printf_color(gpl->ch, "You hear the beating of your own heart.\n\r");	break;
								case 4: ch_printf_color(gpl->ch, "You hear high pitched voices whispering quietly around you.\n\r");	break;
							}
							break;
						case SECT_UNDER_WATER:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sYou hear the gurgling of the water.\n\r", ansi_translate("{048}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sYou hear the clicking of a large marine animal.\n\r", ansi_translate("{048}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sSmall fish dart back and forth before your eyes.\n\r", ansi_translate("{048}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sYou hear the echoing roar of a giant sea creature.\n\r", ansi_translate("{048}"));	break;
							}
							break;
						case SECT_UNDER_GROUND:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "You hear a loud crash!\n\r");	break;
								case 2: ch_printf_color(gpl->ch, "Some cracks appear in the rock above your head.\n\r");	break;
								case 3: ch_printf_color(gpl->ch, "The echo of dripping water echoes against the walls.\n\r");	break;
								case 4: ch_printf_color(gpl->ch, "You hear nothing but the sound of your own breathing.\n\r");	break;
							}
							break;
						case SECT_DEEP_EARTH:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sYou hear a distant cry echoing all around you.\n\r", ansi_translate("{108}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sYou hear the groan of the immense weight above you.\n\r", ansi_translate("{108}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sYou smell ozone in the air around you.\n\r", ansi_translate("{108}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sYou hear the rocks around you shifting and settling.\n\r", ansi_translate("{108}"));	break;
							}
							break;
						case SECT_ROAD:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sA trading caravan rolls by.\n\r", ansi_translate("{038}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sYou hear clop of trotting hooves in the distance.\n\r", ansi_translate("{038}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sYou hear crickets hidden alongside the road.\n\r", ansi_translate("{038}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sYou feel a gust of wind and dust blown from the road.\n\r", ansi_translate("{038}"));	break;
							}
							break;
						case SECT_SWAMP:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sGurgling bubbles belch forth from the calm surface of the water.\n\r", ansi_translate("{028}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sYou hear frogs croaking in the distance.\n\r", ansi_translate("{028}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sYou hear mosquitos buzzing around you.\n\r", ansi_translate("{028}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sThe sounds of marsh life echo all around you.\n\r", ansi_translate("{028}"));	break;
							}
							break;
						case SECT_BEACH:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sA cool salty spray blows in the air.\n\r", ansi_translate("{168}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sThe grating squawk of a seabirds echoes overhead.\n\r", ansi_translate("{168}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sThe soft roar of waves crashing echoes across the beach.\n\r", ansi_translate("{168}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sThe clean scent of seaweed fills the air as it washes up on the beach.\n\r", ansi_translate("{168}"));	break;
							}
							break;
						case SECT_TUNDRA:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sThe faint sound of arctic creatures can be heard in the distance.\n\r", ansi_translate("{178}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sThe wind whistles as snows dance and spiral over the tundra.\n\r", ansi_translate("{178}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sThe icy silence is broken by the sound of a distant snowslide.\n\r", ansi_translate("{178}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sThe icy chill of the wind stabs at you like daggers.\n\r", ansi_translate("{178}"));	break;
							}
							break;
						case SECT_BARREN:
							switch (rnd)
							{
								case 1: ch_printf_color(gpl->ch, "%sA tumbleweed rolls by, driven by an eerily quiet breeze.\n\r", ansi_translate("{038}"));	break;
								case 2: ch_printf_color(gpl->ch, "%sThe sound of a lone cyote calls in the distance.\n\r", ansi_translate("{038}"));	break;
								case 3: ch_printf_color(gpl->ch, "%sA flock of buzzards circles in the distance over some unknown quarry.\n\r", ansi_translate("{038}"));	break;
								case 4: ch_printf_color(gpl->ch, "%sA light arid breeze offers only momentary reprieve from the dry air.\n\r", ansi_translate("{038}"));	break;
							}
							break;
						default:
							ch_printf_color(gpl->ch, "You hear the patter of little feet.\n\r");
							break;
					}
				}	
			}
		}
	}

	/*
		Check age and reset.
	*/

	if (pArea->age >= 40)
	{
		reset_area( pArea );
	}
	pop_call();
	return;
}

void area_update( void )
{
	AREA_DATA *pArea;

	push_call("area_update(void)");

	for (pArea = mud->f_area ; pArea ; pArea = pArea->next)
	{
		repop_area(pArea);
	}
	pop_call();
	return;
}

/*
	Locate last instance of obj reset
*/

RESET_DATA *get_reset_from_obj(RESET_DATA *lReset)
{
	RESET_DATA *pReset;

	push_call("get_reset_from_obj(%p)",lReset);

	for (pReset = lReset ; pReset ; pReset = pReset->prev)
	{
		if (pReset->arg1 == lReset->arg3)
		{
			if (pReset->command == 'O' || pReset->command == 'G' || pReset->command == 'E')
			{
				pop_call();
				return pReset;
			}
		}
	}
	log_printf("get_reset_from_obj: bad '%c' reset", lReset->command);
	pop_call();
	return NULL;
}

/*
	Locate last instance of mobile reset
*/

RESET_DATA *get_reset_from_mob( RESET_DATA *lReset )
{
	RESET_DATA *pReset;

	push_call("get_reset_from_mob(%p)",lReset);

	for (pReset = lReset->prev ; pReset ; pReset = pReset->prev)
	{
		if (pReset->command == 'M')
		{
			pop_call();
			return pReset;
		}
	}
	log_printf("get_reset_from_mob: bad '%c' reset", lReset->command);

	pop_call();
	return NULL;
}

/*
	Locate last instance of door reset
*/

RESET_DATA *get_reset_from_trap( RESET_DATA *lReset )
{
	RESET_DATA *pReset;

	push_call("get_reset_from_trap(%p)",lReset);

	for (pReset = lReset->prev ; pReset ; pReset = pReset->prev)
	{
		if (pReset->arg1 == lReset->arg2)
		{
			if (pReset->command == 'O' || pReset->command == 'G' || pReset->command == 'E' || pReset->command == 'D')
			{
				pop_call();
				return pReset;
			}
		}
	}
	log_printf("get_reset_from_trap: bad '%c' reset", lReset->command);

	pop_call();
	return NULL;
}

void do_resetarea( CHAR_DATA *ch, char *arg)
{
	push_call("do_resetarea(%p,%p)",ch,arg);

	if (IS_NPC(ch))
	{
		log_printf("mob using area reset.");
		dump_stack();
		pop_call();
		return;
	}

	if (!can_olc_modify(ch, ch->in_room->vnum))
	{
		ch_printf_color(ch, "This area is not in your allocated range.\n\r");
		pop_call();
		return;
	}

	SET_BIT(mud->flags, MUD_EMUD_BOOTDB);

	if (IS_SET(mud->flags, MUD_EMUD_REALGAME))
	{
		log_printf("%s resetted area %s", get_name(ch), ch->in_room->area->name);
	}

	send_to_char("Resetting area.\n\r", ch);
	reset_area(ch->in_room->area);

	REMOVE_BIT(mud->flags, MUD_EMUD_BOOTDB);

	pop_call();
	return;
}

/*
	Create an instance of a mobile.
*/

CHAR_DATA *create_mobile( MOB_INDEX_DATA *pMobIndex )
{
	CHAR_DATA *mob;
	AFFECT_DATA *paf;
	NPC_DATA *np;
	int cnt;

	push_call("create_mobile(%p)",pMobIndex);

	if (pMobIndex == NULL)
	{
		bug("create_mobile: NULL pMobIndex.");
		abort( );
	}

	if (pMobIndex->total_mobiles > 1000)
	{
		log_build_printf(pMobIndex->vnum, "More than 1000 mobs created: %d.\n\r", pMobIndex->total_mobiles);
	}

	mud->total_mob++;

	ALLOCMEM(mob, CHAR_DATA, 1);
	ALLOCMEM(np,  NPC_DATA,  1);

	mob->level			= URANGE(1, pMobIndex->level, 45);

  clear_char( mob );

	mob->npcdata			= np;
	mob->pIndexData		= pMobIndex;
	mob->name					= STRDUPE(pMobIndex->player_name);
	mob->short_descr	= STRDUPE(pMobIndex->short_descr);
	mob->long_descr		= STRDUPE(pMobIndex->long_descr);
	mob->description	= STRDUPE(pMobIndex->description);
	mob->act					= pMobIndex->act;
	mob->spec_fun			= pMobIndex->spec_fun;
	mob->affected_by	= pMobIndex->affected_by;
	mob->alignment		= pMobIndex->alignment;
	mob->ethos				= pMobIndex->ethos;
	mob->sex					= pMobIndex->sex;
	mob->size					= pMobIndex->size;
	mob->max_hit			= UMAX(pMobIndex->level, dice(pMobIndex->level, pMobIndex->hitsizedice)) + pMobIndex->hitplus;
	mob->gold					= number_fuzzy(pMobIndex->gold);

	mob->perm_str			= pMobIndex->perm_str;
	mob->perm_dex			= pMobIndex->perm_dex;
	mob->perm_int			= pMobIndex->perm_int;
	mob->perm_wis			= pMobIndex->perm_wis;
	mob->perm_con			= pMobIndex->perm_con;
	mob->perm_cha			= pMobIndex->perm_cha;

	mob->npcdata->remember			= STRDUPE(str_empty);
	mob->npcdata->hate_fear			= 0;
	mob->npcdata->sac_timer			= -1;
	mob->npcdata->sac_string		= STRDUPE(str_empty);
	mob->npcdata->prog_cmd			= STRDUPE(str_empty);

	mob->race       	= pMobIndex->race;
	mob->class				= pMobIndex->class;
	
	height_weight(mob);
		
	if (IS_CLASSED(mob))
	{
		mob->max_hit = 0;
		for (cnt = 1 ; cnt < MAX_CLASS ; cnt++)
		{
			if (mob->class == cnt && pMobIndex->mclass[cnt] == 0)
				mob->mclass[cnt] = mob->level;
			if (pMobIndex->mclass[cnt] > 0)
			{
				mob->mclass[cnt] = pMobIndex->mclass[cnt];
				if (cnt == CLASS_MONSTER)
					mob->max_hit += dice(pMobIndex->mclass[cnt], race_type_table[race_type(mob)].hit_die);				
				else
					mob->max_hit += dice(pMobIndex->mclass[cnt], class_table[cnt].hp_max);
			}
		}
	}
	else if (!mob->race)
	{
		mob->max_hit		= dice(mob->level, race_type_table[race_table[mob->race].type].hit_die);
		mob->speak			= race_table[mob->race].speaks;
		mob->language		= race_table[mob->race].understands;
	}
	else
	{
		mob->max_hit		= dice(mob->level, pMobIndex->hitsizedice);
	}
	if (pMobIndex->speaks > 0)
		mob->speak 			= pMobIndex->speaks;
	SET_BIT(mob->language, pMobIndex->understands);
	
	for (cnt = 0 ; *skill_table[cnt].name != '\0' ; cnt++)
	{
		if (pMobIndex->learned[cnt] > 0)
		{
			mob->learned[cnt] = pMobIndex->learned[cnt];
			continue;
		}
		if (skill_table[cnt].flags != FSKILL_SKILL)
			continue;
		mob->learned[cnt] = learned(mob, cnt);
	}
	restore_mana(mob);
	mob->speed        = 1;
	mob->position     = pMobIndex->position;
	mob->hit					= get_max_hit(mob);
	mob->move					= get_max_move(mob);

	//transfer MobIndex effects to local effects
	for (paf = mob->pIndexData->first_affect ; paf != NULL ; paf = paf->next)
	{
		affect_to_char(NULL, mob, paf);
	}	
	/*
		Insert in list.
	*/
	add_char( mob );
	pMobIndex->total_mobiles++;
	
	/* add objects from load_eq */
	OBJ_DATA *obj;
	int vnum;

	for (cnt = 0 ; cnt < MAX_WEAR ; cnt++)
	{
		if ((vnum = pMobIndex->load_eq[cnt]) > 0)
		{
			if ((obj = create_object(obj_index[vnum], 0)) == NULL)
			{
				log_printf("create_mobile: NULL obj in load_eq %d.", vnum);
				continue;
			}
			obj_to_char(obj, mob);
			equip_char(mob, obj, cnt);
		}
	}
	
	char_reset(mob); //clean up and load applies and resists

	pop_call();
	return mob;
}

/*
	Create an instance of an object.
*/

OBJ_DATA *create_object( OBJ_INDEX_DATA *pObjIndex, bool hashed )
{
	OBJ_DATA *obj;
	AFFECT_DATA *paf;

	push_call("create_object(%p,%p)",pObjIndex,hashed);

	if (pObjIndex == NULL)
	{
		log_string("Create_object: NULL pObjIndex.");
		pop_call();
		return NULL;
	}

	ALLOCMEM(obj, OBJ_DATA, 1);
	obj->pIndexData	= pObjIndex;
	obj->level			= pObjIndex->level;
	obj->wear_loc		= WEAR_NONE;

	if (!hashed)
	{
		add_obj_ref_hash(obj);
	}

	obj->name					= STRDUPE(pObjIndex->name);
	obj->short_descr	= STRDUPE(pObjIndex->short_descr);
	obj->long_descr		= STRDUPE(pObjIndex->long_descr);
	obj->description	= STRDUPE(pObjIndex->description);
	obj->id_name			= STRDUPE(pObjIndex->id_name);
	obj->id_descr			= STRDUPE(pObjIndex->id_descr);
	obj->item_type		= pObjIndex->item_type;
	obj->extra_flags	= pObjIndex->extra_flags;
	obj->wear_flags		= pObjIndex->wear_flags;
	obj->material			= pObjIndex->material;
	obj->hit_points		= pObjIndex->hit_points;
	obj->size					= pObjIndex->size;
	obj->value[0]			= pObjIndex->value[0];
	obj->value[1]			= pObjIndex->value[1];
	obj->value[2]			= pObjIndex->value[2];
	obj->value[3]			= pObjIndex->value[3];
	obj->value[4]			= pObjIndex->value[4];
	obj->value[5]			= pObjIndex->value[5];
	obj->value[6]			= pObjIndex->value[6];
	obj->value[7]			= pObjIndex->value[7];
	obj->weight				= pObjIndex->weight;
	obj->cost					= pObjIndex->cost;
	obj->level				= pObjIndex->level;
	obj->identified		= FALSE;

	//transfer ObjIndex effects to local effects
	for (paf = obj->pIndexData->first_affect ; paf != NULL ; paf = paf->next)
	{
		affect_to_obj(NULL, obj, paf);
	}	

	/*
		Mess with object properties.
	*/

	switch (obj->item_type)
	{
		default:
			log_printf("create_object: vnum %u has bad item_type", pObjIndex->vnum);
			break;

		case ITEM_FIRE:
		case ITEM_LIGHT:
		case ITEM_SYMBOL:
		case ITEM_SPELLBOOK:
		case ITEM_TREASURE:
		case ITEM_FURNITURE:
		case ITEM_TRASH:
		case ITEM_SPELLPOUCH:
		case ITEM_CONTAINER:
		case ITEM_CART:
		case ITEM_SHEATH:
		case ITEM_QUIVER:
		case ITEM_DRINK_CON:
		case ITEM_KEY:
		case ITEM_CRAFT:
		case ITEM_PIECE:
		case ITEM_FOOD:
		case ITEM_BOAT:
		case ITEM_CORPSE_NPC:
		case ITEM_CORPSE_PC:
		case ITEM_FOUNTAIN:
		case ITEM_PORTAL:
		case ITEM_WINDOW:
		case ITEM_PAPER:
		case ITEM_TRAP:
		case ITEM_TOTEM:
		case ITEM_BOOK:
			break;

		case ITEM_TOOLS:
			obj->value[1]		= number_fuzzy(obj->value[1]);
			break;

		case ITEM_SCROLL:
		case ITEM_POTION:
		case ITEM_PILL:
		case ITEM_COMPONENT:
			obj->value[0]		= number_fuzzy(obj->value[0]);
			break;

		case ITEM_WAND:
		case ITEM_STAFF:
			obj->value[0]		= number_fuzzy(obj->value[0]);
			obj->value[1]		= number_fuzzy(obj->value[1]);
			break;

		case ITEM_WEAPON:
			obj->weight			= weapon_table[obj->value[0]].weight;
			obj->apply[APPLY_HITROLL] = get_obj_apply(obj, APPLY_HITROLL);
			obj->apply[APPLY_DAMROLL] = get_obj_apply(obj, APPLY_DAMROLL);
			break;

		case ITEM_ARMOR:
			obj->weight			= armor_table[obj->value[0]].weight;
			obj->apply[APPLY_ENHANCE_AC] = get_obj_apply(obj, APPLY_ENHANCE_AC);
			break;

		case ITEM_MONEY:
			obj->cost		= obj->value[0] * 100;
			obj->cost		+= obj->value[1] * 10;
			obj->cost		+= obj->value[2];
			break;

		case ITEM_AMMO:
			obj->value[1]		= number_fuzzy(obj->value[1]);
			obj->apply[APPLY_HITROLL] = get_obj_apply(obj, APPLY_HITROLL);
			obj->apply[APPLY_DAMROLL] = get_obj_apply(obj, APPLY_DAMROLL);
			break;
	}
	
	LINK(obj, mud->f_obj, mud->l_obj, next, prev);
	LINK(obj, obj->pIndexData->first_instance, obj->pIndexData->last_instance, next_instance, prev_instance);
	mud->total_obj++;
	pObjIndex->total_objects++;
	pop_call();
	return obj;
}

/*
	Clear a new character.
*/

void clear_char( CHAR_DATA *ch )
{
	push_call("clear_char(%p)",ch);

	ch->position	= POS_STANDING;
	ch->hit				= 0;
	ch->max_hit		= 0;
	ch->move			= 0;
	ch->max_move	= 0;

	pop_call();
	return;
}

/*
	Free a character.
*/

void free_char( CHAR_DATA *ch )
{
	POISON_DATA *pd;
	CRIME_DATA  *crime;
	int cnt;

	push_call("free_char(%p)",ch);

	while (ch->first_carrying)
	{
		extract_obj(ch->first_carrying);
	}

	while (ch->first_affect)
	{
		affect_from_char(ch, ch->first_affect);
	}

	while (ch->first_disease)
	{
		disease_from_char(ch, ch->first_disease);
	}

	while ((pd = ch->poison) != NULL)
	{
		ch->poison = ch->poison->next;
		FREEMEM(pd);
	}

	STRFREE(ch->name);
	STRFREE(ch->short_descr);
	STRFREE(ch->long_descr);
	STRFREE(ch->description);

	if (in_combat(ch) || ch->in_battle != NULL)
	{
		char_from_combat(ch);
	}

	if (ch->last_attacked)
	{
		ch->last_attacked = NULL;
	}
	if (ch->last_attacker)
	{
		ch->last_attacker = NULL;
	}

	if (ch->pcdata)
	{
		STRFREE(ch->pcdata->host			);
		STRFREE(ch->pcdata->account		);
		STRFREE(ch->pcdata->mail_address	);
		STRFREE(ch->pcdata->html_address	);
		STRFREE(ch->pcdata->block_list	);
		STRFREE(ch->pcdata->title		);
		STRFREE(ch->pcdata->auto_command	);
		STRFREE(ch->pcdata->adjective	);
		STRFREE(ch->pcdata->authed_by	);
		STRFREE(ch->pcdata->bamfin		);
		STRFREE(ch->pcdata->bamfout		);
		STRFREE(ch->pcdata->pwd			);
		STRFREE(ch->pcdata->page_buf		);
		STRFREE(ch->pcdata->edit_buf		);
		STRFREE(ch->pcdata->prompt_layout	);
		STRFREE(ch->pcdata->subprompt		);
		STRFREE(ch->pcdata->clan_name		);
		STRFREE(ch->pcdata->clan_pledge	);
		STRFREE(ch->pcdata->last_command	);
		STRFREE(ch->pcdata->bio	);
		STRFREE(ch->pcdata->pose	);
		STRFREE(ch->pcdata->disguise	);
		STRFREE(ch->pcdata->disguise_descr	);

		ch->pcdata->tracking = NULL;

		while ((crime = ch->pcdata->first_record) != NULL)
		{
			ch->pcdata->first_record = crime->next;

			STRFREE(crime->crime_record);
			STRFREE(crime->arrester);
			STRFREE(crime->releaser);
			FREEMEM(crime);
		}

		if (ch->pcdata->pnote != NULL)
		{
			STRFREE(ch->pcdata->pnote->text);
			STRFREE(ch->pcdata->pnote->subject);
			STRFREE(ch->pcdata->pnote->to_list);
			STRFREE(ch->pcdata->pnote->date);
			STRFREE(ch->pcdata->pnote->sender);
			FREEMEM(ch->pcdata->pnote);
		}

		if (ch->pcdata->editor)
		{
			stop_editing(ch);
		}

		for (cnt = 0 ; cnt < MAX_PK_ATTACKS ; cnt++)
		{
			STRFREE(ch->pcdata->last_pk_attack_name[cnt]);
		}

		for (cnt = 0 ; cnt < MAX_ALIAS ; cnt++)
		{
			STRFREE (ch->pcdata->alias[cnt] );
			STRFREE (ch->pcdata->alias_c[cnt] );
		}

		for (cnt = 0 ; cnt < 26 ; cnt++)
		{
			STRFREE(ch->pcdata->back_buf[cnt] );
		}

		for (cnt = 0 ; cnt < MAX_AREA ; cnt++)
		{
			if (ch->pcdata->quest[cnt] != NULL)
			{
				FREEMEM(ch->pcdata->quest[cnt]);
			}
		}

		if (ch->pcdata->tactical)
		{
			FREEMEM(ch->pcdata->tactical);
		}

		FREEMEM(ch->pcdata);
	}

	if (ch->npcdata)
	{
		if (ch->npcdata->mob_quest)
		{
			FREEMEM(ch->npcdata->mob_quest);
		}
		STRFREE(ch->npcdata->remember);
		STRFREE(ch->npcdata->sac_string);
		ch->npcdata->hate_fear = 0;

		FREEMEM(ch->npcdata);
	}

	FREEMEM(ch);

	pop_call();
	return;
}

/*
	Get an extra description from a list.
*/

char *get_extra_descr( const char *name, EXTRA_DESCR_DATA *ed )
{
	push_call("get_extra_descr(%p,%p)",name,ed);

	for ( ; ed ; ed = ed->next)
	{
		if (is_name(name, ed->keyword))
		{
			pop_call();
			return ed->description;
		}
	}
	pop_call();
	return NULL;
}


/*
	Read a letter from a file.
*/

char fread_letter( FILE *fp )
{
	char c;

	push_call("fread_letter(%p)",fp);

	do
	{
		if (feof(fp))
		{
			bug("fread_letter: EOF encountered on read.\n\r");
			if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
			{
				exit(1);
			}
			pop_call();
			return '\0';
		}
		c = getc(fp);
	}
	while (isspace(c));

	pop_call();
	return c;
}

/*
	Read a number from a file.
*/

lg_int fread_number( FILE *fp )
{
	int cnt;
	lg_int number;
	bool sign;
	char c;
	char buf[100];

	push_call("fread_number(%p)",fp);

	buf[0] = '\0';

	do
	{
		if (feof(fp))
		{
			bug("fread_number: EOF encountered on read.\n\r");
			if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
			{
				exit(1);
			}
			pop_call();
			return 0;
		}
		c = getc(fp);
	}
	while (isspace(c));

	number = 0;

	sign = (c == '-');

	if (c == '+' || c == '-')
	{
		c = getc(fp);
	}

	for (cnt = 0 ; isdigit(c) || isupper(c) || c == '_' ; cnt++)
	{
		buf[cnt] = c;

		c = getc(fp);
	}
	buf[cnt] = '\0';

	if (isupper(buf[0]))
	{
		for (cnt = mud->bitvector_ref[*buf - 'A'] ; *bitvector_table[cnt].name != '\0' ; cnt++)
		{
			if (!strcmp(bitvector_table[cnt].name, buf))
			{
				number = bitvector_table[cnt].value;
				break;
			}
		}
		if (*bitvector_table[cnt].name == '\0')
		{
			log_printf("fread_number: bad format1 '%s'.", buf);
			dump_stack();
		}
	}
	else
	{
		if (!isdigit(buf[0]))
		{
			log_printf("fread_number: bad format2 '%c%s'", c, fread_word(fp));
			pop_call();
			return number;
		}

		number = atoll(buf);
	}
	if (sign)
	{
		number = 0 - number;
	}
	if (c == '|')
	{
		number += fread_number( fp );
	}
	else if (c != ' ')
	{
		ungetc( c, fp );
	}
	pop_call();
	return number;
}

/*
	Read and allocate space for a string from a file.
	Strings are created and placed in Dynamic Memory.
*/

char *fread_string( FILE *fp )
{
	char buf[MAX_STRING_LENGTH];
	char *plast;
	char c;
	int ln;

	push_call("fread_string(%p)",fp);

	plast = buf;
	buf[0] = '\0';
	ln = 0;

	/*
		Skip blanks.
		Read first char.
	*/

	do
	{
		if (feof(fp))
		{
			bug("fread_string: EOF encountered on read.\n\r");
			if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
			{
				exit(1);
			}
			pop_call();
			return STRDUPE(str_empty);
		}
		c = getc( fp );
	}
	while (isspace(c));

	if ((*plast++ = c) == '~')
	{
		pop_call();
		return STRDUPE(str_empty);
	}

	for (ln = 0 ; ln < MAX_STRING_LENGTH ; ln++, plast++)
	{
		switch (*plast = getc(fp))
		{
			case EOF:
				bug( "Fread_string: EOF" );
				if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
				{
					exit( 1 );
				}
				*plast = '\0';
				pop_call();
				return STRALLOC(buf);

			case '\n':
				plast++;
				ln++;
				*plast = '\r';
				break;

			case '\r':
				plast--;
				ln--;
				break;

			case '~':
				*plast = '\0';
				pop_call();
				return STRALLOC( buf );
		}
	}
	bug("fread_string: string too long" );

	if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
	{
		abort();
	}
	*plast = '\0';

	pop_call();
	return STRALLOC(buf);
}


/*
	Read to end of line (for comments).
*/

void fread_to_eol( FILE *fp )
{
	char c;

	push_call("fread_to_eol(%p)",fp);

	do
	{
		if (feof(fp))
		{
			bug("fread_to_eol: EOF encountered on read.\n\r", 0);
			if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
			{
				abort();
			}
			pop_call();
			return;
		}
		c = getc( fp );
	}
	while (c != '\n' && c != '\r');

	do
	{
		c = getc( fp );
	}
	while (c == '\n' || c == '\r');

	ungetc(c, fp);
	pop_call();
	return;
}


char *fread_line( FILE *fp )
{
	static char line[MAX_STRING_LENGTH];
	char *pline;
	char c;
	int ln;

	push_call("fread_line(%p)",fp);

	pline = line;
	line[0] = '\0';
	ln = 0;

	/*
		Skip blanks.
		Read first char.
	*/

	do
	{
		if (feof(fp))
		{
			bug("fread_line: EOF encountered on read.\n\r",0);
			if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
			{
				abort();
			}
			strcpy(line, "");
			pop_call();
			return line;
		}
		c = getc( fp );
	}
	while (isspace(c));

	ungetc(c, fp);

	do
	{
		if (feof(fp))
		{
			bug("fread_line: EOF encountered on read.\n\r",0);
			if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
			{
				abort();
			}
			*pline = '\0';
			pop_call();
			return line;
		}
		c = getc( fp );
		*pline++ = c; ln++;
		if (ln >= (MAX_STRING_LENGTH - 1))
		{
			bug( "fread_line: line too long",0 );
			if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
			{
				abort();
			}
			break;
		}
	}
	while (c != '\n' && c != '\r');

	do
	{
		c = getc( fp );
	}
	while (c == '\n' || c == '\r');

	ungetc( c, fp );

	*pline = '\0';
	pop_call();
	return line;
}

/*
	Read one word (into static buffer).
*/

char *fread_word( FILE *fp )
{
	static char word[MAX_INPUT_LENGTH];
	char *pword;
	char cEnd;
	int cnt;

	push_call("fread_word(%p)",fp);

	do
	{
		if (feof(fp))
		{
			bug("fread_word: EOF encountered on read.\n\r", 0);
			if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
			{
				abort();
			}
			word[0] = '\0';
			pop_call();
			return word;
		}
		cEnd = getc( fp );
	}
	while ( isspace(cEnd) );

	if (cEnd == '\'' || cEnd == '"')
	{
		pword	= word;
	}
	else
	{
		word[0] = cEnd;
		pword   = word+1;
		cEnd    = ' ';
	}

	for (cnt = 0 ; cnt < MAX_INPUT_LENGTH ; cnt++, pword++)
	{
		if (feof(fp))
		{
			bug("fread_word: EOF encountered on read.\n\r", 0);
			if (IS_SET(mud->flags, MUD_EMUD_BOOTDB))
			{
				abort();
			}
			*pword = '\0';
			pop_call();
			return word;
		}

		*pword = getc(fp);

		if (*pword == cEnd || *pword == EOF || *pword == '\n')
		{
			if (*pword == EOF || cEnd == ' ')
			{
				ungetc( *pword, fp );
			}
			*pword = '\0';
			pop_call();
			return word;
		}
	}
	word[10] = '\0';
	bug("fread_word: word '%s' too long.", word);
	abort( );
}

/*
	Returns 1000 times normal percentage value
*/

lg_int display_timer( CHAR_DATA *ch, int timer )
{
	lg_int tot_usage, ind_usage;

	push_call("display_timer(%p,%p)",ch,timer);

	tot_usage = mud->total_io_exec + mud->total_io_delay;

	if (tot_usage == 0)
	{
		pop_call();
		return(0);
	}

	if (timers[timer][1] == 0 || timers[timer][4] == 0)
	{
		pop_call();
		return(0);
	}
	ind_usage = timers[timer][0] / timers[timer][1] * timers[timer][4];

	ch_printf_color(ch, "%-30s%8lld       %8lld      %8.2f     %8.2f\n\r",
		timer_strings[timer],
		timers[timer][0] / timers[timer][1],
		timers[timer][3] / timers[timer][4] / 1000,
		100.0 * (double) ind_usage / (double) mud->total_io_exec,
		100.0 * (double) ind_usage / (double) tot_usage);

	pop_call();
	return ind_usage;
}


void start_timer( int timer )
{
	struct timeval last_time;
	lg_int cur_time;

	gettimeofday(&last_time, NULL);

	cur_time = (lg_int) last_time.tv_usec + 1000000LL * (lg_int) last_time.tv_sec;

	if (timers[timer][2] == 0)
	{
		timers[timer][2] = cur_time ;
		return;
	}

	timers[timer][3] += cur_time - timers[timer][2];
	timers[timer][2] = cur_time;
	timers[timer][4] ++;

	return;
}


void close_timer( int timer )
{
	struct timeval last_time;
	lg_int cur_time;

	gettimeofday(&last_time, NULL);

	cur_time = (lg_int) last_time.tv_usec + 1000000LL * (lg_int) last_time.tv_sec;

/*
	if (cur_time - timers[timer][2] > 1000000 / PULSE_PER_SECOND)
	{
		bug("%s heartbeat violation of %lld usec", timer_strings[timer], cur_time - timers[timer][2] - (1000000LL / PULSE_PER_SECOND));
	}
*/
	timers[timer][0] += (cur_time - timers[timer][2]);
	timers[timer][1] ++;

	return;
}

/*
	randomize number by -10 to 10 percent
*/
int number_fuzzy( int number )
{
	return (number - number/10 + number_range(0, number/10*2));
}

/*
	randomize each digit in number by -1 to +1
*/
int big_number_fuzzy( int number )
{
  char numbuf[MAX_STRING_LENGTH];
  sh_int i;

  sprintf(numbuf, "%d", number);
  for ( i = 0; numbuf[i] != '\0'; i++ )
    numbuf[i] = number_fuzzy(numbuf[i]);

  number = atoi(numbuf);
  return UMAX( 1, number );
}

float what_percent(float current, float max)
{
	float percent;

	push_call("what_percent(%p,%p)",current,max);

	percent = 100 * UMAX(0, current) / UMAX(1, max);

  pop_call();
  return percent;
}


/*
	Generate a random number.
*/

int number_range( int from, int to )
{
	int val;

	push_call("number_range(%p,%p)",from,to);

	if (from > to || from < 0 || to < 0)
	{
		log_printf("number_range: invalid range (%d,%d)", from, to);
		dump_stack();

		if (from > to)
		{
			val	= from;
			from = to;
			to	= val;
		}
	}

	pop_call();
	return (lrand48() % (to - from + 1)) + from;
}

/*
	Roll some dice.
*/

int dice( int number, int size )
{
	int idice, sum;

	push_call("dice(%p,%p)",number,size);

	if (size <= 0)
	{
		pop_call();
		return 0;
	}

	for (idice = sum = 0 ; idice < number ; idice++)
	{
		sum += (lrand48() % size) + 1;
	}
	pop_call();
	return sum;
}

/*
	Return a value between 1 and 100
*/

int number_percent( void )
{
	return ((lrand48() % 100) + 1);
}


/*
	Generate a random door.
*/

int number_door( void )
{
	return (lrand48() % 6);
}

/*
	return a value between 0 and given power of 2
*/

int number_bits( int width )
{
	return (lrand48() % (1 << width));
}


/*
	Append a string to a file.
*/

void append_file( CHAR_DATA *ch, char *fname, FILE *fp, char *str )
{
	push_call("append_file(%p,%p,%p,%p)",ch,fname,fp,str);

	if ((ch != NULL && IS_NPC(ch)) || str == NULL || str[0] == '\0')
	{
		pop_call();
		return;
	}

	if (fpAppend)
	{
		my_fclose( fpAppend );
	}

	if (fp == NULL)
	{
		fp = my_fopen( fname, "a",FALSE);
	}

	if (fp == NULL)
	{
		perror( fname );
		fpAppend = my_fopen( NULL_FILE, "r",FALSE);
		pop_call();
		return;
	}

	if (ch == NULL)
	{
		fprintf( fp, "%s\n", str );
		fflush( fp );
		fpAppend = my_fopen( NULL_FILE, "r",FALSE);
		pop_call();
		return;
	}

	fprintf( fp, "[%s] %s: %s\n", get_time_string(mud->current_time), ch->name, str );

	fflush( fp );

	fpAppend = my_fopen( NULL_FILE, "r",FALSE);

	pop_call();
	return;
}

/*
	Reports a bug.        -1 param does not put in logs.
*/

void bug( const char *str, ... )
{
	char buf[MAX_STRING_LENGTH];

	push_call("bug(%p)",str);

	if (fpArea != NULL)
	{
		int iLine;
		int iChar;

		if (fpArea == stdin)
		{
			iLine = 0;
		}
		else
		{
			iChar = ftell(fpArea);
			fseek(fpArea, 0, 0);

			for (iLine = 0 ; ftell(fpArea) < iChar ; iLine++)
			{
				while (getc(fpArea) != '\n')
				{
					;
				}
			}
			fseek(fpArea, iChar, 0);
		}
		log_printf("[*****] FILE: %s LINE: %d", strArea, iLine);
	}

	strcpy(buf, "[+++++] ");
	{
		va_list param;

		va_start(param, str);
		vsprintf( buf + strlen(buf), str, param );
		va_end(param);
	}
	log_string( buf );
	log_printf("[+++++] %s", mud->last_player_cmd);

	pop_call();
	return;
}

/*
 * Dump a text file to a player, a line at a time
 * originally by Thoric
 */
void show_file( CHAR_DATA * ch, char *filename )
{
	FILE *fp;
	char buf[MAX_STRING_LENGTH];
	int c;
	int num = 0;

	if( ( fp = my_fopen( filename, "r", FALSE ) ) != NULL )
	{
		while( !feof( fp ) )
		{
			while( ( buf[num] = fgetc( fp ) ) != EOF
					 && buf[num] != '\n' && buf[num] != '\r' && num < ( MAX_STRING_LENGTH - 2 ) )
				num++;
			c = fgetc( fp );
			if( ( c != '\n' && c != '\r' ) || c == buf[num] )
				ungetc( c, fp );
			buf[num++] = '\n';
			buf[num++] = '\r';
			buf[num] = '\0';
			send_to_char_color( buf, ch );
			num = 0;
		}
		my_fclose( fp );
	}
}

/*
	Writes a string to the log.
*/
void log_string( char *str )
{
	char *strtime;
	struct timeval log_time;
	CHAR_DATA  *fch;
	PLAYER_GAME *fpl;

	push_call("log_string(%p)",str);

	for (fpl = mud->f_player ; fpl ; fpl = fpl->next)
	{
		fch = fpl->ch;
		if (IS_NPC(fch))
		{
			continue;
		}
		if (!IS_SET(fch->act, PLR_HEARLOG) || !IS_IMMORTAL(fch))
		{
			continue;
		}
		ch_printf_color(fch, "{058}Log: %s\n\r", justify(str, get_page_width(fch)));
	}

	gettimeofday(&log_time, NULL);
	strtime                    = ctime(&log_time.tv_sec);
	strtime[strlen(strtime)-6] = '\0';
	fprintf( stderr, "%s- %s\n", strtime, str );

	pop_call();
	return;
}

void log_build_string(int vnum, char *str )
{
	struct timeval log_time;
	char *strtime;
	CHAR_DATA  *fch;
	PLAYER_GAME *fpl;

	push_call("log_build_string(%p)",str);

	for (fpl = mud->f_player ; fpl ; fpl = fpl->next)
	{
		fch = fpl->ch;

		if (!IS_SET(fpl->ch->act, PLR_HEARLOG) || !can_olc_modify(fpl->ch, vnum))
		{
			continue;
		}
		ch_printf_color(fch, "{058}Log: [%u] %s\n\r", vnum, str);
	}
	gettimeofday(&log_time, NULL);
	strtime                    = ctime(&log_time.tv_sec);
	strtime[strlen(strtime)-6] = '\0';
	fprintf( stderr, "%s- [%u] %s\n", strtime, vnum, str );

	pop_call();
	return;
}

void log_wiz_string( char *str )
{
	CHAR_DATA  *fch;
	PLAYER_GAME *fpl;

	push_call("log_wiz_string(%p)",str);

	for (fpl = mud->f_player ; fpl ; fpl = fpl->next)
	{
		fch = fpl->ch;
		if (IS_NPC(fch))
			continue;

		if (!IS_SET(fpl->ch->act, PLR_WIZTIME))
			continue;

		ch_printf_color(fch, "{058}DEBUG: %s\n\r", str);
	}
	pop_call();
	return;
}

void log_god_string( char *str )
{
	char *strtime;
	struct timeval log_time;
	CHAR_DATA  *fch;
	PLAYER_GAME *fpl;

	push_call("log_god_string(%p)",str);

	for (fpl = mud->f_player ; fpl ; fpl = fpl->next)
	{
		fch = fpl->ch;
		if (IS_NPC(fch))
		{
			continue;
		}
		if (!IS_SET(fch->act, PLR_HEARLOG) || !IS_GOD(fch))
		{
			continue;
		}
		ch_printf_color(fch, "{058}Log: %s\n\r", justify(str, get_page_width(fch)));
	}
	gettimeofday(&log_time, NULL);
	strtime                    = ctime(&log_time.tv_sec);
	strtime[strlen(strtime)-6] = '\0';
	fprintf( stderr, "%s- %s\n", strtime, str );

	pop_call();
	return;
}


void create_menu_tree()
{
	char *pt;
	int cnt;
	char line[200];
	AREA_DATA *pArea, *tArea;
	HELP_DATA *pHelp, *tHelp;
	HELP_MENU_DATA *menu;
	char buf[MAX_STRING_LENGTH];

	push_call("create_menu_tree()");

	for (pArea = mud->f_area ; pArea ; pArea = pArea->next)
	{
		for (pHelp = pArea->first_help ; pHelp ; pHelp = pHelp->next)
		{
			strcpy(buf, pHelp->text);
			pt = buf;
			pt += strlen(buf) / 4;
			while (*pt != '\0')
			{
				if (*(pt+1) != '{' || *(pt+2) == '\0' || *(pt+3) != '}')
				{
					pt++;
					continue;
				}
				pt++;
				*pt = '\0';

				if (pHelp->first_menu == NULL)
				{
					STRFREE(pHelp->text);
					pHelp->text = STRALLOC(buf);
				}

				*pt = '{';
				/*
					find menu items here
				*/

				cnt = 0;
				while (*pt != '\r' && *pt != '\n' && *pt != '\0')
				{
					line[cnt] = *pt;
					cnt++;
					pt++;
				}
				line[cnt] = '\0';

				for (tHelp = pHelp->area->first_help ; tHelp ; tHelp = tHelp->next)
				{
					if (line[3] == tHelp->keyword[0] && line[4] == tHelp->keyword[1] && !strcmp(&line[3], tHelp->keyword))
					{
						ALLOCMEM(menu, HELP_MENU_DATA, 1);
						menu->option = tolower(line[1]);
						menu->help   = tHelp;
						LINK(menu, pHelp->first_menu, pHelp->last_menu, next, prev);
						goto end_of_loop;
					}
				}
				/*
				log_printf("create_menu: inter area help menu: %s", line);
				*/
				for (tArea = mud->f_area ; tArea ; tArea = tArea->next)
				{
					for (tHelp = tArea->first_help ; tHelp ; tHelp = tHelp->next)
					{
						if (line[3] == tHelp->keyword[0] && line[4] == tHelp->keyword[1] && !strcmp(&line[3], tHelp->keyword))
						{
							ALLOCMEM(menu, HELP_MENU_DATA, 1);
							menu->option = tolower(line[1]);
							menu->help   = tHelp;
							LINK(menu, pHelp->first_menu, pHelp->last_menu, next, prev);
							goto end_of_loop;
						}
					}
				}

				log_printf("create_menu: failed perfect match: %s", line);

				for (tArea = mud->f_area ; tArea ; tArea = tArea->next)
				{
					for (tHelp = tArea->first_help ; tHelp ; tHelp = tHelp->next)
					{
						if (is_name(&line[3], tHelp->keyword))
						{
							ALLOCMEM(menu, HELP_MENU_DATA, 1);
							menu->option = tolower(line[1]);
							menu->help   = tHelp;
							LINK(menu, pHelp->first_menu, pHelp->last_menu, next, prev);
							goto end_of_loop;
						}
					}
				}
				end_of_loop:
				continue;
			}
		}
	}
	pop_call();
	return;
}


int find_command( char *cmd_str, int trust )
{
	int cmd;

	push_call("find_command(%p)",cmd_str);

	if (isalpha(*cmd_str))
	{
		for (cmd = mud->command_ref[tolower(*cmd_str) - 'a'] ; *cmd_table[cmd].name == *cmd_str ; cmd++)
		{
			if (IS_SET(cmd_table[cmd].flags, CMD_BUILDER|CMD_TESTER) && !str_prefix(cmd_str, cmd_table[cmd].name))
			{
				pop_call();
				return cmd;
			}
			if (cmd_table[cmd].level <= trust && !str_prefix(cmd_str, cmd_table[cmd].name))
			{
				pop_call();
				return cmd;
			}
		}
	}
	else
	{
		for (cmd = 0 ; !isalpha(*cmd_table[cmd].name) ; cmd++)
		{
			if (IS_SET(cmd_table[cmd].flags, CMD_BUILDER|CMD_TESTER) && !str_prefix(cmd_str, cmd_table[cmd].name))
			{
				pop_call();
				return cmd;
			}
			if (cmd_table[cmd].level <= trust && !str_prefix(cmd_str, cmd_table[cmd].name))
			{
				pop_call();
				return cmd;
			}
		}
	}
	pop_call();
	return -1;
}

int find_social( char *social_str )
{
	int cmd;

	push_call("find_social(%p)",social_str);

	if (isalpha(*social_str))
	{
		for (cmd = mud->social_ref[tolower(*social_str) - 'a'] ; *social_table[cmd].name == *social_str ; cmd++)
		{
			if (!str_prefix(social_str, social_table[cmd].name))
			{
				pop_call();
				return cmd;
			}
		}
	}
	pop_call();
	return -1;
}

		
OBJ_PROG * load_object_program( FILE *fp)
{
	OBJ_PROG *prg;
	char buf[MAX_INPUT_LENGTH];

	push_call("load_object_program(%p)",fp);

	ALLOCMEM(prg, OBJ_PROG, 1);

	prg->unknown   = STRDUPE(str_empty);
	prg->if_symbol = '=';
	prg->argument  = STRDUPE(str_empty);

	prg->index	= fread_number( fp );	/* get index number */
	prg->trigger	= fread_number( fp );	/* get trigger command type */

	mud->top_oprog++;

	switch (prg->trigger)
	{
		case TRIG_VOID:
			break;

		case TRIG_COMMAND:
		case TRIG_ROOM_COMMAND:
		case TRIG_WEAR_COMMAND:
			prg->percentage = fread_number( fp );
			if ((prg->cmd = find_command(fread_word(fp), MAX_LEVEL - 1)) == -1)
			{
				bug("Bad obj_command command name: %s", buf);
				abort();
			}
			break;

		case TRIG_UNKNOWN:
		case TRIG_ROOM_UNKNOWN:
		case TRIG_WEAR_UNKNOWN:
			prg->percentage = fread_number( fp );
			STRFREE(prg->unknown);
			prg->unknown = STRALLOC(fread_word( fp )) ;
			break;

		case TRIG_TICK:
		case TRIG_DAMAGE:
		case TRIG_HIT:
		case TRIG_WEAR:
		case TRIG_REMOVE:
		case TRIG_SACRIFICE:
			prg->percentage = fread_number( fp );
			break;

		default:
			log_string( "Bad obj_command type");
	}

	prg->obj_command = fread_number( fp );

	switch (prg->obj_command)
	{
		case OPROG_ECHO:
		case OPROG_GOD_COMMAND:
		case OPROG_GOD_ARGUMENT:
		case OPROG_COMMAND:
		case OPROG_ARGUMENT:
			STRFREE(prg->argument);
			prg->argument		= fread_string( fp ) ;
			break;
		case OPROG_QUEST_SET:
			prg->quest_offset	= fread_number( fp );
			prg->quest_bits	= fread_number( fp );
			prg->if_value		= fread_number( fp );
			break;
		case OPROG_QUEST_ADD:
			prg->quest_offset	= fread_number( fp );
			prg->quest_bits	= fread_number( fp );
			prg->if_value		= fread_number( fp );
			break;
		case OPROG_PLAYER_QUEST_IF:
			prg->quest_offset	= fread_number( fp );
			prg->quest_bits	= fread_number( fp );
			prg->if_symbol		= fread_letter( fp );
			prg->if_value		= fread_number( fp );
			prg->if_true		= fread_number( fp );
			prg->if_false		= fread_number( fp );
			break;
		case OPROG_OBJECT_QUEST_IF:
			prg->quest_offset	= fread_number( fp );
			prg->quest_bits	= fread_number( fp );
			prg->if_symbol		= fread_letter( fp );
			prg->if_value		= fread_number( fp );
			prg->if_true		= fread_number( fp );
			prg->if_false		= fread_number( fp );
			break;
		case OPROG_IF_HAS_OBJECT:
			prg->if_value		= fread_number( fp );
			prg->if_true		= fread_number( fp );
			prg->if_false		= fread_number( fp );
			break;
		case OPROG_IF:
			prg->if_check		= fread_number( fp );
			prg->if_symbol		= fread_letter( fp );
			prg->if_value		= fread_number( fp );
			prg->if_true		= fread_number( fp );
			prg->if_false		= fread_number( fp );
			break;
		case OPROG_APPLY:
			prg->if_check		= fread_number( fp );
			prg->if_value		= fread_number( fp );
			break;
		case OPROG_JUNK:
			break;
		default:
			log_string( "Bad obj_command reaction type");
	}
	pop_call();
	return( prg );
}

void obj_prog_if_dest( OBJ_INDEX_DATA *obj )
{
	push_call("obj_prog_if_dest(%p)",obj);

	pop_call();
	return;
}


/*
	Load default weight of an object from index data.
*/
int load_obj_weight( OBJ_INDEX_DATA *obj )
{
	int weight;

	push_call("load_obj_weight(%p)",obj);
	
	switch (obj->item_type)
	{
		default:
			bug("load_obj_weight(%d): unknown item type %d!", obj->vnum, obj->item_type);
			pop_call();
			return 0;
		case ITEM_WAND:
			weight = 5;
			break;
		case ITEM_STAFF:
			weight = 40;
			break;
		case ITEM_FURNITURE:
		case ITEM_TOTEM:
			weight = obj->size/SIZE_MEDIUM * 500;
			break;
		case ITEM_TRASH:
			weight = obj->size/SIZE_MEDIUM * 50;
			break;
		case ITEM_LIGHT:
			weight = 10;
			break;
		case ITEM_POTION:
			weight = 10;
			if (obj->value[0] == 0)
				weight /= 3;
			break;
		case ITEM_SPELLBOOK:
			weight = obj->value[0];
			break;
		case ITEM_BOOK:
			weight = 30;
			break;
		case ITEM_FOOD:
		case ITEM_DRINK_CON:
			weight = UMAX(1, obj->value[0] * 2);
			break;
		case ITEM_SCROLL:
		case ITEM_COMPONENT:
		case ITEM_KEY:
		case ITEM_PILL:
		case ITEM_PAPER:
		case ITEM_FIRE:
			weight = 0;
			break;
		case ITEM_TRAP:
		case ITEM_PORTAL:
		case ITEM_WINDOW:
		case ITEM_CRAFT:
		case ITEM_PIECE:
			weight = -1;
			break;
		case ITEM_TOOLS:
			weight = tool_table[obj->value[0]].weight;
			break;
		case ITEM_WEAPON:
			weight = weapon_table[obj->value[0]].weight;
			break;
		case ITEM_AMMO:
			weight = 1;
			break;
		case ITEM_ARMOR:
			weight = armor_weight(obj);
			break;
		case ITEM_QUIVER:
		case ITEM_SHEATH:
		case ITEM_CART:
		case ITEM_CONTAINER:
		case ITEM_SPELLPOUCH:
			if (IS_SET(obj->value[1], CONT_HOLDING))
				weight = ROUNDUP(obj->value[0]/160);
			else
				weight = obj->size * 10;
			break;
		case ITEM_SYMBOL:
		case ITEM_FOUNTAIN:
		case ITEM_TREASURE:
			weight = obj->size << obj->size;
			break;
		case ITEM_MONEY:
			weight = obj->value[0];
			weight += obj->value[1];
			weight += obj->value[2];
			break;
		case ITEM_BOAT:
			weight = 100;
			break;
		case ITEM_CORPSE_NPC:
		case ITEM_CORPSE_PC:
			weight = 1;
			break;
	}
	pop_call();
	return(weight);
}

/* 
 * Used in load_objects to fix objects that
 * load with no material data.
 */
void fix_materials( OBJ_INDEX_DATA *obj )
{
	int material;
	
	push_call("fix_materials(%p)", obj);
	
	if ((material = obj->material) <= 0 || material >= MATERIAL_MAX)
	{
		switch (obj->item_type)
		{
			case ITEM_WEAPON:
				if (IS_SET(weapon_table[obj->value[0]].weap_spec, WSPEC_MISSILE))
					material = MATERIAL_SOFTWOOD;
				else if (IS_SET(weapon_table[obj->value[0]].weap_spec, WSPEC_WOODEN_HAFTED))
					material = MATERIAL_HARDWOOD;
				else
					material = MATERIAL_STEEL;
				break;
			case ITEM_ARMOR:
				if (obj->value[0] <= ARMOR_TYPE_PADDED)
					material = MATERIAL_CLOTH;
				else if (obj->value[0] <= ARMOR_TYPE_STUDDED_LEATHER)
					material = MATERIAL_LEATHER;
				else if (obj->value[0] <= ARMOR_TYPE_HIDE)
					material = MATERIAL_HIDE;
				else if (obj->value[0] <= ARMOR_TYPE_FULL_PLATE)
					material = MATERIAL_STEEL;
				else if (obj->value[0] <= ARMOR_TYPE_LIGHT_SHIELD)
					material = MATERIAL_HARDWOOD;
				else
					material = MATERIAL_STEEL;
				break;
			case ITEM_SCROLL:
			case ITEM_PAPER:
			case ITEM_BOOK:
			case ITEM_MAP:
			case ITEM_SPELLBOOK:
				material = MATERIAL_PAPER;
				break;
			case ITEM_WAND:
			case ITEM_STAFF:
			case ITEM_FURNITURE:
			case ITEM_TRASH:
			case ITEM_BOAT:
			case ITEM_TOTEM:
			case ITEM_AMMO:
			case ITEM_CART:
				material = MATERIAL_HARDWOOD;
				break;
			case ITEM_POTION:
			case ITEM_WINDOW:
			case ITEM_DRINK_CON:
				material = MATERIAL_GLASS;
				break;
			case ITEM_SPELLPOUCH:
			case ITEM_SHEATH:
			case ITEM_CONTAINER:
			case ITEM_QUIVER:
				material = MATERIAL_LEATHER;
				break;
			case ITEM_KEY:
				material = MATERIAL_BRONZE;
				break;
			case ITEM_TOOLS:
				material = MATERIAL_STEEL;
				break;
			case ITEM_FOUNTAIN:
				material = MATERIAL_STONE;
				break;
			case ITEM_FOOD:
			case ITEM_CORPSE_PC:
			case ITEM_CORPSE_NPC:
				material = MATERIAL_FLESH;
				break;
			case ITEM_MONEY:
			case ITEM_TREASURE:
			case ITEM_SYMBOL:
				material = MATERIAL_SILVER;
				break;
			default:
				material = -1; // need a control for irrelevant item types
				break;
		}
		if (material != -1)
		{
			obj->material = material;
			bug("fix_materials: obj vnum %d with bad material, fixed.", obj->vnum);
		}
	}
	pop_call();
	return;
}


/* 
 * Used in load_objects to fix objects that
 * load with no size data.
 */
void fix_sizes( OBJ_INDEX_DATA *obj )
{
	int size;
	
	push_call("fix_sizes(%p)", obj);
	
	if ((size = obj->size) <= 0 || size > SIZE_COLOSSAL)
	{
		switch (obj->item_type)
		{
			case ITEM_WEAPON:
				size = weapon_table[obj->value[0]].size;
				break;
			case ITEM_SYMBOL:
			case ITEM_KEY:
				size = SIZE_FINE;
				break;
			case ITEM_LIGHT:
			case ITEM_POTION:
			case ITEM_TREASURE:
			case ITEM_SPELLPOUCH:
			case ITEM_FOOD:
			case ITEM_AMMO:
			case ITEM_MAP:
				size = SIZE_DIMINUTIVE;
				break;
			case ITEM_PAPER:
			case ITEM_WAND:
			case ITEM_SCROLL:
			case ITEM_DRINK_CON:
			case ITEM_TRASH:
			case ITEM_SPELLBOOK:
			case ITEM_BOOK:
			case ITEM_TOOLS:
			case ITEM_PIECE:
				size = SIZE_TINY;
				break;
			case ITEM_FIRE:
			case ITEM_TRAP:
			case ITEM_CRAFT:
			case ITEM_CONTAINER:
			case ITEM_SHEATH:
			case ITEM_QUIVER:
				size = SIZE_SMALL;
				break;
			case ITEM_ARMOR:
			case ITEM_CORPSE_NPC:
			case ITEM_CORPSE_PC:
			case ITEM_WINDOW:
			case ITEM_FURNITURE:
				size = SIZE_MEDIUM;
				break;
			case ITEM_STAFF:
			case ITEM_PORTAL:
			case ITEM_TOTEM:
			case ITEM_CART:
				size = SIZE_LARGE;
				break;
			case ITEM_BOAT:
			case ITEM_FOUNTAIN:
				size = SIZE_HUGE;
				break;
			default:
				size = SIZE_FINE;
				break;
		}
		if (size > 0)
		{
			obj->size = size;
// 			bug("fix_sizes: obj vnum %d with bad size, fixed.", obj->vnum);
		}
	}
	pop_call();
	return;
}


/* 
 * calculate obj hit points in edit and loading.
 */
void load_obj_hit( OBJ_INDEX_DATA *obj )
{
	int hit;
	
	push_call("load_obj_hit(%p)", obj);
	
	switch (obj->item_type)
	{
		default:
			hit = obj->size * material_table[obj->material].hit;
			break;
		case ITEM_WEAPON:
			hit = weapon_table[obj->value[0]].weight / 10;
			break;
		case ITEM_ARMOR:
			hit = armor_table[obj->value[0]].ac_bonus * 5;
			break;
		case ITEM_SYMBOL:
		case ITEM_KEY:
		case ITEM_SCROLL:
		case ITEM_SPELLPOUCH:
		case ITEM_AMMO:
		case ITEM_PAPER:
		case ITEM_MAP:
		case ITEM_POTION:
		case ITEM_DRINK_CON:
		case ITEM_TOOLS:
		case ITEM_PIECE:
		case ITEM_TRAP:
		case ITEM_SHEATH:
		case ITEM_QUIVER:
			hit = ROUNDUP(obj->size / 2) * material_table[obj->material].hit;
			break;
		case ITEM_SPELLBOOK:
		case ITEM_BOOK:
		case ITEM_BOAT:
		case ITEM_FOUNTAIN:
			hit = obj->size * obj->size * material_table[obj->material].hit;
			break;
	}
	if (hit > 0)
	{
		obj->hit_points = hit;
	}

	pop_call();
	return;
}


/*
	creation and deletion for OLC - Scandum 22-06-2002
*/

void create_shop( MOB_INDEX_DATA *mob )
{
	SHOP_DATA *pShop;
	int iTrade;

	push_call("create_shop(%p)",mob);

	ALLOCMEM(pShop, SHOP_DATA, 1);

	pShop->keeper = mob->vnum;

	for (iTrade = 0 ; iTrade < MAX_TRADE ; iTrade++)
	{
		pShop->buy_type[iTrade] = ITEM_NOTHING;
	}

	pShop->profit_buy	= 100;
	pShop->profit_sell	=  50;
	pShop->open_hour	=   0;
	pShop->close_hour	=  23;
	mob->pShop		= pShop;

	LINK(pShop, mud->f_shop, mud->l_shop, next, prev);

	mud->top_shop++;

	pop_call();
	return;
}


void delete_shop( MOB_INDEX_DATA *mob )
{
	push_call("delete_shop(%p)",mob);

	if (mob->pShop)
	{
		UNLINK(mob->pShop, mud->f_shop, mud->l_shop, next, prev);
		FREEMEM(mob->pShop);
		mob->pShop = NULL;
		--mud->top_shop;
	}
	pop_call();
	return;
}


void create_stable( MOB_INDEX_DATA *mob )
{
	STABLE_DATA *pStable;

	push_call("create_stable(%p)",mob);

	ALLOCMEM(pStable, STABLE_DATA, 1);

	pStable->keeper = mob->vnum;

	pStable->room					=   0;
	pStable->shop_flags		=   0;
	pStable->rent					=  50;
	pStable->open_hour		=   0;
	pStable->close_hour		=  23;
	mob->pStable					= pStable;

	LINK(pStable, mud->f_stable, mud->l_stable, next, prev);

	mud->top_stable++;

	pop_call();
	return;
}


void delete_stable( MOB_INDEX_DATA *mob )
{
	push_call("delete_stable(%p)",mob);

	if (mob->pStable)
	{
		UNLINK(mob->pStable, mud->f_stable, mud->l_stable, next, prev);
		FREEMEM(mob->pStable);
		mob->pStable = NULL;
		--mud->top_stable;
	}
	pop_call();
	return;
}


void create_inn( MOB_INDEX_DATA *mob )
{
	INN_DATA *pInn;
	int iRoom;

	push_call("create_inn(%p)",mob);

	ALLOCMEM(pInn, INN_DATA, 1);

	pInn->keeper = mob->vnum;

	for (iRoom = 0 ; iRoom < MAX_INN_ROOMS ; iRoom++)
	{
		pInn->room[iRoom] = -1;
	}
	for (iRoom = 0 ; iRoom < MAX_INN_ROOMS ; iRoom++)
	{
		pInn->rent[iRoom] = 50;
	}
	pInn->shop_flags		=   0;
	pInn->open_hour			=   0;
	pInn->close_hour		=  23;
	mob->pInn						= pInn;

	LINK(pInn, mud->f_inn, mud->l_inn, next, prev);

	mud->top_inn++;

	pop_call();
	return;
}


void delete_inn( MOB_INDEX_DATA *mob )
{
	push_call("delete_inn(%p)",mob);

	if (mob->pInn)
	{
		UNLINK(mob->pInn, mud->f_inn, mud->l_inn, next, prev);
		FREEMEM(mob->pInn);
		mob->pInn = NULL;
		--mud->top_inn;
	}
	pop_call();
	return;
}


void create_exit( ROOM_INDEX_DATA *room, int door)
{
	EXIT_DATA *pExit;

	push_call("create_exit(%p,%d)",room,door);

	if (room->exit[door] != NULL)
	{
		pop_call();
		return;
	}

	ALLOCMEM(pExit, EXIT_DATA, 1);

	pExit->description		= STRDUPE(str_empty);
	pExit->keyword			= STRDUPE(str_empty);
	pExit->pvnum			= -1;
	pExit->vnum			= -1;
	pExit->key			= -1;
	room->exit[door]		= pExit;

	mud->top_exit++;

	pop_call();
	return;
}


void delete_exit( ROOM_INDEX_DATA *room, int door)
{
	EXIT_DATA *pExit;

	push_call("delete_exit(%p,%d)",room,door);

	if ((pExit = room->exit[door]) == NULL)
	{
		pop_call();
		return;
	}

	STRFREE(pExit->keyword);
	STRFREE(pExit->description);
	FREEMEM(pExit);
	mud->top_exit--;

	room->exit[door] = NULL;

	pop_call();
	return;
}


void create_room( int vnum )
{
	ROOM_INDEX_DATA *room;

	push_call("create_room(%d)",vnum);

	ALLOCMEM(room, ROOM_INDEX_DATA, 1);

	room_index[vnum] = room;
	mud->top_room++;

	pop_call();
	return;
}


bool delete_room( ROOM_INDEX_DATA *room )
{
	bool door;
	int  vnum;
	ROOM_INDEX_DATA *prev;
	OBJ_DATA *o;
	CHAR_DATA *ch;
	EXTRA_DESCR_DATA *ed;
	RESET_DATA *pReset;

	push_call("delete_room(%p)",room);

	switch (room->vnum)
	{
		case ROOM_VNUM_LIMBO:
		case ROOM_VNUM_JUNK:
		case ROOM_VNUM_TEMPLE:
		case ROOM_VNUM_SCHOOL:
		case ROOM_VNUM_ARENA:
		case ROOM_VNUM_CLANHALLS:
			log_printf("Refusing to delete hardcore vnum: %d", room->vnum);
			dump_stack();
			pop_call();
			return FALSE;
	}

	del_room_timer(room->vnum, -1);

	while ((ch = room->first_person) != NULL)
	{
		if (!IS_NPC(ch))
		{
			char_from_room(ch);
			char_to_room(ch, ROOM_VNUM_TEMPLE, TRUE);
		}
		else
		{
			log_printf("junking mob %s", ch->name);
			junk_mob(ch);
		}
	}

	while ((o = room->first_content) != NULL)
	{
		junk_obj(o);
	}


	while ((ed = room->first_extradesc) != NULL)
	{
		room->first_extradesc = ed->next;
		STRFREE(ed->keyword);
		STRFREE(ed->description);
		FREEMEM(ed );
		--mud->top_ed;
	}

	if (!IS_SET(room->room_flags, ROOM_HASH))
	{
		for (pReset = room->area->first_reset ; pReset ; )
		{
			if (is_room_reset(pReset, room))
			{
				delete_reset(room->area, pReset);

				pReset = room->area->first_reset;
			}
			else
			{
				pReset = pReset->next;
			}
		}

		for (vnum = 0 ; vnum < MAX_VNUM ; vnum++)
		{
			if ((prev = room_index[vnum]) == NULL)
			{
				continue;
			}

			for (door = 0 ; door <= 5 ; door++)
			{
				if (prev->exit[door] == NULL)
				{
					continue;
				}

				if (prev->exit[door]->vnum != room->vnum)
				{
					continue;
				}

				log_printf("[%u] Deleting connection to room [%u]", prev->vnum, prev->exit[door]->vnum);

				delete_exit(prev, door);
			}
		}

		if (room->vnum == room->area->low_r_vnum)
		{
			vnum = room->area->low_r_vnum + 1;

			for (room->area->low_r_vnum = MAX_VNUM-1 ; vnum <= room->area->hi_r_vnum ; vnum++)
			{
				if ((prev = get_room_index(vnum)) == NULL)
				{
					continue;
				}
				if (prev->area != room->area)
				{
					continue;
				}
				room->area->low_r_vnum = prev->vnum;
				break;
			}
		}

		if (room->vnum == room->area->hi_r_vnum)
		{
			vnum = room->area->hi_r_vnum - 1;

			for (room->area->hi_r_vnum = 0 ; vnum >= room->area->low_r_vnum ; vnum--)
			{
				if ((prev = get_room_index(vnum)) == NULL)
				{
					continue;
				}
				if (prev->area != room->area)
				{
					continue;
				}
				room->area->hi_r_vnum = prev->vnum;
				break;
			}
		}
	}

	for (door = 0 ; door <= 5 ; door++)
	{
		if (room->exit[door] == NULL)
		{
			continue;
		}
/*
		log_printf("[%u] Deleting connection to room [%u]", room->vnum, room->exit[door]->vnum);
*/
		delete_exit(room, door);
	}

	for (door = 0 ; door < MAX_LAST_LEFT ; door++)
	{
		STRFREE(room->last_left[door]);
	}
	STRFREE (room->name);
	STRFREE (room->description);

	if (room->vnum >= ROOM_VNUM_WILDERNESS)
	{
		room_index[room->vnum] = room_index[ROOM_VNUM_WILDERNESS + room->sector_type];
	}
	else
	{
		room_index[room->vnum] = NULL;
	}
	FREEMEM(room );
	--mud->top_room;

	pop_call();
	return TRUE;
}

bool delete_obj( OBJ_INDEX_DATA *obj )
{
	EXTRA_DESCR_DATA	*ed;
	AFFECT_DATA		*af;
	RESET_DATA		*pReset;

	push_call("delete_obj(%p)",obj);

	if (obj->vnum < 100)
	{
		log_printf("Refusing to delete hardcore vnum: %d", obj->vnum);
		dump_stack();
		pop_call();
		return FALSE;
	}

	while (obj->first_instance)
	{
		extract_obj(obj->first_instance);
	}

	for (pReset = obj->area->first_reset ; pReset ; )
	{
		if (is_obj_reset(pReset, obj))
		{
			delete_reset(obj->area, pReset);

			pReset = obj->area->first_reset;
		}
		else
		{
			pReset = pReset->next;
		}
	}

	/* Remove references to object index */

	while ((ed = obj->first_extradesc) != NULL)
	{
		obj->first_extradesc = ed->next;
		STRFREE (ed->keyword);
		STRFREE (ed->description);
		FREEMEM(ed);
		--mud->top_ed;
	}

	while ((af = obj->first_affect) != NULL)
	{
		obj->first_affect = af->next;
		FREEMEM(af);
		--mud->top_affect;
	}

	if (obj->vnum == obj->area->low_o_vnum && obj->vnum == obj->area->hi_o_vnum)
	{
		obj->area->low_o_vnum = MAX_VNUM - 1;
		obj->area->hi_o_vnum  = 0;
	}
	else if (obj->vnum == obj->area->low_o_vnum)
	{
		for (obj->area->low_o_vnum++ ; obj->area->low_o_vnum <= obj->area->hi_o_vnum ; obj->area->low_o_vnum++)
		{
			if (obj_index[obj->area->low_o_vnum] != NULL)
			{
				break;
			}
		}
	}
	else if (obj->vnum == obj->area->hi_o_vnum)
	{
		for (obj->area->hi_o_vnum-- ; obj->area->hi_o_vnum >= obj->area->low_o_vnum ; obj->area->hi_o_vnum--)
		{
			if (obj_index[obj->area->hi_o_vnum] != NULL)
			{
				break;
			}
		}
	}

	STRFREE (obj->name);
	STRFREE (obj->short_descr);
	STRFREE (obj->long_descr);
	STRFREE (obj->description);
	STRFREE (obj->attack_string);

	obj_index[obj->vnum] = NULL;

	FREEMEM(obj);
	--mud->top_obj_index;

	pop_call();
	return TRUE;
}

/*
	Scandum 28-04-2002
*/

bool delete_mob( MOB_INDEX_DATA *mob )
{
	int vnum;
	MOB_INDEX_DATA	*prev;
	RESET_DATA	*pReset;

	push_call("delete_mob(%p)",mob);

	if (mob->vnum >= 9900 && mob->vnum < 10000)
	{
		log_printf("Refusing to delete hardcore vnum: %d", mob->vnum);
		dump_stack();
		pop_call();
		return FALSE;
	}

	while (mob_index[mob->vnum]->first_instance)
	{
		extract_char(mob_index[mob->vnum]->first_instance);
	}

	for (pReset = mob->area->first_reset ; pReset ; )
	{
		if (is_mob_reset(pReset, mob))
		{
			delete_reset(mob->area, pReset);

			pReset = mob->area->first_reset;
		}
		else
		{
			pReset = pReset->next;
		}
	}

	if (mob->pShop)
	{
		delete_shop(mob);
	}

	if (mob->pStable)
	{
		delete_shop(mob);
	}

	if (mob->pInn)
	{
		delete_inn(mob);
	}

	if (mob->vnum == mob->area->low_m_vnum)
	{
		vnum = mob->area->low_m_vnum+1;

		for (mob->area->low_m_vnum = MAX_VNUM-1 ; vnum <= mob->area->hi_m_vnum ; vnum++)
		{
			if ((prev = get_mob_index(vnum)) == NULL)
			{
				continue;
			}
			if (prev->area != mob->area)
			{
				continue;
			}
			mob->area->low_m_vnum = prev->vnum;
			break;
		}
	}

	if (mob->vnum == mob->area->hi_m_vnum)
	{
		vnum = mob->area->hi_m_vnum-1;

		for (mob->area->hi_m_vnum = 0 ; vnum > mob->area->low_m_vnum ; vnum--)
		{
			if ((prev = get_mob_index(vnum)) == NULL)
			{
				continue;
			}
			if (prev->area != mob->area)
			{
				continue;
			}
			mob->area->hi_m_vnum = prev->vnum;
			break;
		}
	}

	STRFREE (mob->player_name);
	STRFREE (mob->short_descr);
	STRFREE (mob->long_descr);
	STRFREE (mob->description);
	STRFREE (mob->reset_msg);

	mob_index[mob->vnum] = NULL;

	FREEMEM(mob);
	--mud->top_mob_index;

	pop_call();
	return TRUE;
}

bool delete_help( HELP_DATA *help )
{
	HELP_MENU_DATA *menu;

	push_call("delete_help(%p)",help);

	while ((menu = help->first_menu) != NULL)
	{
		help->first_menu = menu->next;
		FREEMEM(menu);
	}

	STRFREE (help->keyword);
	STRFREE (help->title);
	STRFREE (help->text);
	UNLINK(help, help->area->first_help, help->area->last_help, next, prev);
	FREEMEM(help);
	--mud->top_help;

	pop_call();
	return TRUE;
}


int get_alloc_size( unsigned char *str )
{
	push_call("get_alloc_size(%p)",str);

	if (str == NULL)
	{
		log_printf("get_alloc_size: null pointer");
		pop_call();
		return -1;
	}

	if (*(str-1) != *(str-2) + *(str-3) + *(str-4))
	{
		log_printf("get_alloc_size: failed check sum");
		pop_call();
		return -1;
	}

	switch (*(str-3))
	{
		case 'F':
		case 'D':
		case 'S':
			pop_call();
			return rgSizeList[*(str-2)];
	}
	log_printf("get_alloc_size: bad block type");

	pop_call();
	return -1;
}

unsigned char *set_block_header( bool iBlock, bool typ, bool iList, bool *pMem )
{
	push_call("set_block_header(%p,%p,%p,%p)",iBlock,typ,iList,pMem);

	*pMem = iBlock;			/* Index for perm_block_index */
	pMem++;

	*pMem = typ;				/* D dynamic, P perm, F Free */
	pMem++;

	*pMem = iList;				/* Index for rgSizeList */
	pMem++;

	*pMem = iList + typ + iBlock;	/* Checksum */
	pMem++;

	pop_call();
	return( pMem );
}

void set_block_type( bool typ, bool *pMem )
{
	push_call("set_block_type(%p,%p)",typ,pMem);

	*(pMem-3) = typ;

	*(pMem-1) = *(pMem-2) + *(pMem-3) + *(pMem-4);

	pop_call();
	return;
}

/*
	Allocate some ordinary memory,
	with the expectation of freeing it someday.
*/

void *alloc_mem( int sMem )
{
	PERM_BLOCK_LIST *pBlock;
	bool iList, *pMem;

	push_call("alloc_mem(%d)",sMem);

	for (iList = 0 ; iList < MAX_MEM_LIST ; iList++)
	{
		if (sMem <= rgSizeList[iList])
		{
			break;
		}
	}

	if (iList == MAX_MEM_LIST)
	{
		log_printf("alloc_mem: size %d too large.", sMem);
		dump_stack();
		abort();
	}

	if (rgFreeList[iList] == NULL)
	{
		pMem = (bool *) alloc_perm(iList);
		rgUsedCount[iList]++;
	}
	else
	{
		pMem = (bool *) rgFreeList[iList];

		rgFreeList[iList] = rgFreeList[iList]->next;
		rgFreeCount[iList]--;

		pBlock = perm_block_index[*(pMem-4)];

		if (get_alloc_size(pMem) != rgSizeList[iList])
		{
			log_string("alloc_mem: allocating a free with wrong size");
			dump_stack();

			pMem = (bool *) alloc_perm(iList);
			rgUsedCount[iList]++;

			tot_memory_warning++;
		}
		else if (pBlock == NULL || (bool *) pBlock > pMem || (bool *) pBlock + MAX_PERM_BLOCK < pMem)
		{
			log_printf("free_mem: bad header: block index out of range");
			dump_stack();

			pMem = (bool *) alloc_perm(iList);
			rgUsedCount[iList]++;

			tot_memory_warning++;
		}
		else
		{
			rgUsedCount[iList]++;
		}
	}

	memset(pMem, 0, sMem);

	set_block_type('D', pMem);

	pop_call();
	return ((void *) pMem);
}

/*
	Free some memory.
	Recycle it back onto the free list for blocks of that size.
	The pAdd is the pointer to the pointer of the memory.
*/

void free_mem( bool *pMem )
{
	FREE_MEM_LIST *fm;
	PERM_BLOCK_LIST *pBlock;
	bool iBlock, iList;

	push_call("free_mem(%p)",pMem);

	if (pMem == NULL)
	{
		log_printf("free_mem: null pointer");
		dump_stack();
		pop_call();
		return;
	}

	iList  = *(pMem-2);
	iBlock = *(pMem-4);

	if (get_alloc_size(pMem) < 0)
	{
		dump_stack();
		tot_memory_warning++;

		pop_call();
		return;
	}

	pBlock = perm_block_index[iBlock];

	if (pBlock == NULL || (bool *) pBlock > pMem || (bool *) pBlock + MAX_PERM_BLOCK < pMem)
	{
		log_printf("free_mem: bad header: block index out of range");
		dump_stack();
		tot_memory_warning++;

		pop_call();
		return;
	}

	fm = (FREE_MEM_LIST *) pMem;
	fm->next = rgFreeList[iList];
	rgFreeList[iList] = fm;

	rgFreeCount[iList]++;
	rgUsedCount[iList]--;

	set_block_type( 'F', pMem );

	pop_call();
	return;
}


/*
	Allocate some permanent memory.
	Permanent memory is never freed,
	pointers into it may be copied safely.
*/

void *alloc_perm( bool iList )
{
	int sMem;
	PERM_BLOCK_LIST *pBlock;
	bool block_index, *pMem;

	push_call("alloc_perm(%p)", iList);

	sMem  = rgSizeList[iList];
	sMem += 4;				/* Add 4 bytes for header */

	for (block_index = 0 ; block_index < 255 && perm_block_index[block_index] ; block_index++)
	{
		if (perm_block_index[block_index]->iMemPerm + sMem < MAX_PERM_BLOCK)
		{
			break;
		}
	}

	if (block_index == 255)
	{
		log_string( "alloc_perm: no free blocks left" );
		abort();
	}

	pBlock = perm_block_index[block_index];

	if (pBlock == NULL)
	{
		if ((pBlock = calloc(1, MAX_PERM_BLOCK)) == NULL)
		{
			perror("alloc_perm");
			abort();
		}

		pBlock->iMemPerm = sizeof( *pBlock );

		perm_block_index[block_index] = pBlock;
	}

	pMem        		 = (bool *) pBlock + pBlock->iMemPerm;
	pBlock->iMemPerm	+= sMem;

	set_block_header(block_index, 'P', iList, pMem);

	pop_call();
	return (void *) (pMem+4);
}

void do_memory( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	int cnt, Ftotal, Utotal, Ptotal;

	push_call("do_memory(%p,%p)",ch,argument);

	buf[0] = '\0';

	cat_sprintf(buf, "{078}Players:  {178}%6d    ",	mud->total_plr);
	cat_sprintf(buf, "{078}Descs:    {178}%6d    ",	mud->total_desc);
	cat_sprintf(buf, "{078}Areas:    {178}%6d    ",	mud->top_area);
	cat_sprintf(buf, "{078}Helps:    {178}%6d\n\r",	mud->top_help);

	cat_sprintf(buf, "{078}Rooms:    {178}%6d    ",	mud->top_room);
	cat_sprintf(buf, "{078}MobsIn:   {178}%6d    ",	mud->top_mob_index);
	cat_sprintf(buf, "{078}ObjsIn:   {178}%6d    ",	mud->top_obj_index);
	cat_sprintf(buf, "{078}Resets:   {178}%6d\n\r",	mud->top_reset);

	cat_sprintf(buf, "{078}Exits:    {178}%6d    ",	mud->top_exit);
	cat_sprintf(buf, "{078}Mobs:     {178}%6d    ",	mud->total_mob);
	cat_sprintf(buf, "{078}Objs:     {178}%6d    ",	mud->total_obj);
	cat_sprintf(buf, "{078}Affects:  {178}%6d\n\r",	mud->top_affect);


	cat_sprintf(buf, "{078}Shops:    {178}%6d    ",	mud->top_shop);
	cat_sprintf(buf, "{078}Stables:  {178}%6d    ",	mud->top_stable);
	cat_sprintf(buf, "{078}Inns:     {178}%6d    ",	mud->top_inn);
	cat_sprintf(buf, "{078}Skills:   {178}%6d\n\r",	MAX_REAL_SKILL);
	
	cat_sprintf(buf, "{078}Mprog:    {178}%6d    ",	mud->top_mprog);
	cat_sprintf(buf, "{078}Oprog:    {178}%6d    ",	mud->top_oprog);
	cat_sprintf(buf, "{078}Extra:    {178}%6d\n\r",	mud->top_ed);

	Utotal = Ftotal = 0;

	for (cnt = 0 ; cnt < MAX_MEM_LIST ; cnt++)
	{
		Utotal += (4 + rgSizeList[cnt]) * rgUsedCount[cnt];
		Ftotal += (4 + rgSizeList[cnt]) * rgFreeCount[cnt];
	}

	for (Ptotal = 0 ; Ptotal < 255 ; Ptotal++)
	{
		if (perm_block_index[Ptotal] == NULL)
		{
			Ptotal *= MAX_PERM_BLOCK;
			break;
		}
	}

	cat_sprintf(buf, "\n\r");

	cat_sprintf(buf, "{078}Perm Mem: {178}%8d   ", Ptotal);
	cat_sprintf(buf, "{078}Used Mem: {178}%8d   ", Utotal);
	cat_sprintf(buf, "{078}Free Mem: {178}%8d   ", Ftotal);
	cat_sprintf(buf, "\n\r\n\r");

	for (cnt = 0 ; cnt < MAX_MEM_LIST ; cnt++)
	{
		cat_sprintf(buf, "{178}%6d {118}%6d {128}%5d ",
			rgSizeList[cnt],
			rgUsedCount[cnt],
			rgFreeCount[cnt]);

		if (cnt % 4 == 3)
		{
			strcat(buf, "\n\r");
		}
	}
	if (str_suffix("\n\r", buf))
	{
		strcat(buf, "\n\r");
	}

	if (tot_memory_warning)
	{
		cat_sprintf(buf, "\n\r{018}Total Memory Warnings: {178}%8d\n\r", tot_memory_warning);
	}

	send_to_char_color(buf, ch);
	pop_call();
	return;
}

/*
	Create new stuff (OLC) - Scandum 10-07-2002
*/

ROOM_INDEX_DATA *make_room( int vnum )
{
	ROOM_INDEX_DATA *pRoomIndex;
	bool door;

	push_call("make_room(%p)",vnum);

	if (get_area_from_vnum(vnum) == NULL)
	{
		log_printf("make_room: failed to add area data.");
		pop_call();
		return NULL;
	}

	ALLOCMEM( pRoomIndex, ROOM_INDEX_DATA, 1 );

	pRoomIndex->vnum			= vnum;
	pRoomIndex->area			= get_area_from_vnum(vnum);

	if (vnum < pRoomIndex->area->low_r_vnum)
	{
		pRoomIndex->area->low_r_vnum = vnum;
	}

	if (vnum > pRoomIndex->area->hi_r_vnum)
	{
		pRoomIndex->area->hi_r_vnum = vnum;
	}

	pRoomIndex->name		= STRALLOC("Floating in a void");
	pRoomIndex->description	= STRDUPE(str_empty);
	pRoomIndex->listen_desc	= STRDUPE(str_empty);
	pRoomIndex->night_desc	= STRDUPE(str_empty);

	for (door = 0 ; door < MAX_LAST_LEFT ; door++)
	{
		pRoomIndex->last_left[door] = STRDUPE(str_empty);
	}

	room_index[vnum]		= pRoomIndex;
	mud->top_room++;

	pop_call();
	return pRoomIndex;
}



OBJ_INDEX_DATA *make_object(int vnum)
{
	OBJ_INDEX_DATA	*pObjIndex;

	push_call("make_object(%p)",vnum);

	if (get_area_from_vnum(vnum) == NULL)
	{
		log_printf("Make_object: Failed to add area data to object.");
		pop_call();
		return NULL;
	}

	ALLOCMEM( pObjIndex, OBJ_INDEX_DATA, 1 );

	pObjIndex->vnum		= vnum;
	pObjIndex->area		= get_area_from_vnum(vnum);

	if (vnum < pObjIndex->area->low_o_vnum)
	{
		pObjIndex->area->low_o_vnum = vnum;
	}
	if (vnum > pObjIndex->area->hi_o_vnum)
	{
		pObjIndex->area->hi_o_vnum = vnum;
	}

	obj_index[vnum]						= pObjIndex;
	pObjIndex->name						= STRDUPE(str_empty);
	pObjIndex->short_descr		= STRDUPE(str_empty);
	pObjIndex->long_descr			= STRDUPE(str_empty);
	pObjIndex->description		= STRDUPE(str_empty);
	pObjIndex->attack_string	= STRDUPE(str_empty);
	pObjIndex->id_name				= STRDUPE(str_empty);
	pObjIndex->id_descr				= STRDUPE(str_empty);
	pObjIndex->item_type			= ITEM_TRASH;
	pObjIndex->extra_flags		= 0;
	pObjIndex->wear_flags			= 0;
	pObjIndex->value[0]				= 0;
	pObjIndex->value[1]				= 0;
	pObjIndex->value[2]				= 0;
	pObjIndex->value[3]				= 0;
	pObjIndex->value[4]				= 0;
	pObjIndex->value[5]				= 0;
	pObjIndex->value[6]				= 0;
	pObjIndex->value[7]				= 0;
	pObjIndex->weight					= 1;
	pObjIndex->cost						= 10;
	pObjIndex->level					= 1;
	pObjIndex->level					= 1;
	pObjIndex->progtypes			= 0;

	mud->top_obj_index++;

	pop_call();
	return pObjIndex;
}

HELP_DATA * make_helpfile( char *argument, AREA_DATA *area )
{
	HELP_DATA *help;

	push_call("make_helpfile(%p,%p)",argument,area);

	ALLOCMEM(help, HELP_DATA, 1);

	help->level	= 0;
	help->keyword	= STRALLOC(argument);
	help->text	= STRDUPE(str_empty);
	help->area	= area;

	LINK (help, area->first_help, area->last_help, next, prev );
	mud->top_help++;

	pop_call();
	return help;
}

AREA_DATA * get_area_from_vnum (int vnum)
{
	AREA_DATA * pArea;

	push_call("get_area_from_vnum(%p)",vnum);

	for (pArea = mud->f_area ; pArea ; pArea = pArea->next)
	{
		if (pArea->olc_range_lo <= vnum && pArea->olc_range_hi >= vnum)
		{
			break;
		}
		if (pArea->low_r_vnum <= vnum && pArea->hi_r_vnum >= vnum)
		{
			break;
		}
		if (pArea->low_m_vnum <= vnum && pArea->hi_m_vnum >= vnum)
		{
			break;
		}
		if (pArea->low_o_vnum <= vnum && pArea->hi_o_vnum >= vnum)
		{
			break;
		}
	}
	pop_call();
	return pArea;
}

/*
	Create a new INDEX mobile (OLC)
*/

MOB_INDEX_DATA *make_mobile( int vnum )
{
	MOB_INDEX_DATA *pMobIndex;

	push_call("make_mobile(%p)",vnum);

	if (get_area_from_vnum(vnum) == NULL)
	{
		log_printf("make_mobile: couldn't find area.\n\r");
		pop_call();
		return NULL;
	}

	ALLOCMEM( pMobIndex, MOB_INDEX_DATA, 1 );

	pMobIndex->vnum					= vnum;
	pMobIndex->player_name	= STRALLOC("newly created mobile");
	pMobIndex->short_descr	= STRALLOC("a newly created mobile");
	pMobIndex->long_descr   = STRALLOC("a newly created mobile stands here");
	pMobIndex->description  = STRALLOC("");
	pMobIndex->act					= ACT_SENTINEL;
	pMobIndex->level				= 1;
	pMobIndex->hitplus			= 0;
	pMobIndex->position			= POS_STANDING;
	pMobIndex->area					= get_area_from_vnum (vnum);

	if (vnum < pMobIndex->area->low_m_vnum)
	{
		pMobIndex->area->low_m_vnum = vnum;
	}
	if (vnum > pMobIndex->area->hi_m_vnum)
	{
		pMobIndex->area->hi_m_vnum = vnum;
	}

	mob_index[vnum]			= pMobIndex;
	mud->top_mob_index++;

	pop_call();
	return pMobIndex;
}


EXIT_DATA *make_exit( ROOM_INDEX_DATA *pRoomIndex, ROOM_INDEX_DATA *to_room, bool door )
{
	EXIT_DATA *pExit;

	push_call("make_exit(%p,%p,%p)",pRoomIndex,to_room,door);

	ALLOCMEM(pExit, EXIT_DATA, 1);

	pExit->exit_info	= 0;
	pExit->pvnum			= 0;
	pExit->key				= -1;
	pExit->exit_size	= 0;
	pExit->climb_dc		= 0;
	pExit->fall_dist		= 0;

	if (to_room)
	{
		pExit->to_room	= to_room->vnum;
		pExit->vnum	= to_room->vnum;
	}
	room_index[pRoomIndex->vnum]->exit[door] = pExit;
	mud->top_exit++;

	pop_call();
	return pExit;
}

/*
	This routine makes sure that files are not cross linked or chopped
	Chaos  - 4/26/99
*/

bool is_valid_save( char *file_name , char *text_crc)
{
	char buf[MAX_INPUT_LENGTH];
	sh_int cnt, cf;
	FILE *fp;

	push_call("is_valid_save(%p,%p)",file_name,text_crc);

	if ((fp = my_fopen(file_name, "r", FALSE)) == NULL)
	{
		pop_call();
		return( FALSE );
	}

	fseek(fp, 0, SEEK_END);

	if (ftell(fp) < 10)
	{
		my_fclose(fp);

		log_printf("Oops, file system full!  %s failed.", file_name);

		pop_call();
		return( FALSE );
	}

	cf  = ' ';
	cnt = 0;

	while (cf != '#' && cnt > -25)
	{
		cnt--;
		fseek(fp, cnt, SEEK_END);
		cf = fgetc( fp );
	}

	if (cnt < -25)
	{
		my_fclose(fp);

		log_printf("Didn't find an #%s on %s", text_crc, file_name);

		pop_call();
		return( FALSE );
	}

	cf = fgetc(fp);

	for (cnt = 0 ; cf != '\n' && cf != EOF ; cnt++)
	{
		buf[cnt] = cf;

		cf = fgetc(fp);
	}
	buf[cnt] = '\0';

	if (!strcmp(buf, text_crc))
	{
		my_fclose( fp );

		pop_call();
		return( TRUE );
	}

	my_fclose( fp );

	log_printf("Cross linked file %s on %s", buf, file_name);

	pop_call();
	return( FALSE );
}

/* Save this class */
/*
 * Thanks for Erwin's MERC tips on dynamically
 * loading class tables - Kregor
 */
void fwrite_class (int num)
{
	FILE *fp;
	char buf[MAX_STRING_LENGTH];
	int sn;
	
	sprintf (buf, "%s/%s.txt", CLASSES_DIR, bits_to_str(num, "CLASS_"));
	
	close_reserve();

	if ((fp = my_fopen(buf, "w", FALSE)) == NULL)
	{
		log_printf("Could not open file %s in order to save class.", buf);
	}
	
	fprintf( fp, "Name        %s~\n", !is_string(class_table[num].who_name_long) ? strlower(bits_to_str(num, "CLASS_")) : class_table[num].who_name_long);
	fprintf( fp, "WhoName     %s~\n", !is_string(class_table[num].who_name) ? "???" : class_table[num].who_name);

	fprintf( fp, "HitDice     %d\n", class_table[num].hp_max );
	fprintf( fp, "FORTSave    %d\n", class_table[num].fort_save );
	fprintf( fp, "REFLSave    %d\n", class_table[num].refl_save );
	fprintf( fp, "WILLSave    %d\n", class_table[num].will_save );
	fprintf( fp, "EntryLvl    %d\n", class_table[num].pc_class );
	fprintf( fp, "Mana        %d\n", class_table[num].mana_table );
	fprintf( fp, "BAB         %d\n", class_table[num].base_attack );
	fprintf( fp, "AttrPrime   %d\n", class_table[num].attr_prime );
	fprintf( fp, "AttrSecond  %d\n", class_table[num].attr_second );
	fprintf( fp, "PriMod      %d\n", class_table[num].prime_mod );
	fprintf( fp, "SecMod      %d\n", class_table[num].sec_mod );
	fprintf( fp, "SkillPts    %d\n", class_table[num].skill_pts );
	fprintf( fp, "MaxLevel    %d\n", class_table[num].max_level );
	fprintf( fp, "FirstFeat   %d\n", class_table[num].first_bonus );
	fprintf( fp, "FeatLevel   %d\n", class_table[num].bonus_lvl );

	for (sn = 0; *skill_table[sn].name != '\0' ; sn++)
	{
		if (skill_table[sn].name == NULL)
			continue;
		if (skill_table[sn].skill_level[num] < LEVEL_IMMORTAL)
			fprintf (fp, "Skill       %d '%s'\n", skill_table[sn].skill_level[num], skill_table[sn].name);
		if (skill_table[sn].skilltype == FSKILL_FEAT && skill_table[sn].bonus_feat[num] < LEVEL_IMMORTAL)
			fprintf (fp, "BonusFeat   %d '%s'\n", skill_table[sn].bonus_feat[num], skill_table[sn].name);
	}
	
	fprintf( fp, "%s", "EndClass\n\n" );
	my_fclose (fp);

	open_reserve();
}

void save_classes()
{
	int i;
	
	for (i = 0; i < MAX_CLASS; i++)
	{
		fwrite_class(i);
	}
}

/* Load a class */
void fread_class (int num)
{
	char buf[MAX_STRING_LENGTH];
	char *word;
	bool fMatch;
	FILE *fp;
	
	sprintf (buf, "%s/%s.txt", CLASSES_DIR, bits_to_str(num, "CLASS_"));

	close_reserve();

	if ((fp = my_fopen(buf, "r", FALSE)) == NULL)
	{
		fwrite_class(num);
		fread_class(num);
		return;
	}
	
	for ( ; ; )
	{
		word   = feof(fp) ? "EndClass" : fread_word(fp);
		fMatch = FALSE;

		switch (word[0])
		{
			case 'A':
				NKEY("AttrPrime",			class_table[num].attr_prime, fread_number(fp));
				NKEY("AttrSecond",			class_table[num].attr_second, fread_number(fp));
				break;

			case 'B':
				if ( !strcasecmp( word, "BonusFeat" ) )
				{
					int sn;
					int value;

					value = fread_number( fp );

					sn = skill_lookup( fread_word( fp ) );

					if (sn < 0)
					{
						bug("fread_class: %s - unknown skill.", class_table[num].who_name_long);
					}
					else if (skill_table[sn].skilltype == FSKILL_FEAT)
					{
						skill_table[sn].bonus_feat[num] = value;
					}
					fMatch = TRUE;
					break;
				}
				NKEY("BAB", class_table[num].base_attack,	fread_number(fp));
				break;

			case 'E':
				NKEY( "EntryLvl", class_table[num].pc_class, fread_number(fp));
				if (!strcmp(word, "EndClass"))
					return;
				break;

			case 'F':
				NKEY( "FORTSave", class_table[num].fort_save, fread_number(fp));
				NKEY( "FirstFeat", class_table[num].first_bonus, fread_number(fp));
				NKEY( "FeatLevel", class_table[num].bonus_lvl, fread_number(fp));
				break;

			case 'H':
				NKEY( "HitDice", class_table[num].hp_max, fread_number(fp));
				break;

			case 'M':
				NKEY( "Mana", class_table[num].mana_table, fread_number(fp));
				NKEY( "MaxLevel", class_table[num].max_level, fread_number(fp));
				break;

			case 'N':
				if ( !strcasecmp( word, "Name" ) )
				{
					char *name = STRALLOC(fread_string(fp));
					
					if (!is_string(name))
						sprintf(class_table[num].who_name_long, "%s", strlower(bits_to_str(num, "CLASS_")));
					else
						sprintf(class_table[num].who_name_long, "%s", name);
					fMatch = TRUE;
					break;
				}
				break;

			case 'P':
				NKEY( "PriMod", class_table[num].prime_mod, fread_number(fp));

			case 'R':
				NKEY( "REFLSave", class_table[num].refl_save, fread_number(fp));

			case 'S':
				if ( !strcasecmp( word, "Skill" ) )
				{
					int sn;
					int value;

					value = fread_number( fp );

					sn = skill_lookup( fread_word( fp ) );

					if (sn < 0)
					{
						bug("fread_class: %s - unknown skill.", class_table[num].who_name_long);
					}
					else
					{
						skill_table[sn].skill_level[num] = value;
					}
					fMatch = TRUE;
					break;
				}
				NKEY( "SecMod", class_table[num].sec_mod, fread_number(fp));
				NKEY( "SkillPts", class_table[num].skill_pts, fread_number(fp));
				break;

			case 'W':
				if ( !strcasecmp( word, "WhoName" ) )
				{
					char *name = STRALLOC(fread_string(fp));
					
					if (!is_string(name))
						sprintf(class_table[num].who_name, "???");
					else
						sprintf(class_table[num].who_name, "%s", name);
					fMatch = TRUE;
					break;
				}
				NKEY( "WILLSave", class_table[num].will_save, fread_number(fp));
				break;
		}

		if (fMatch == FALSE)
		{
			log_printf("fread_class: no match: %s %s", word, fread_line(fp));
		}
	}
	my_fclose (fp);
	open_reserve();
}
	
void load_classes ()
{
	int cls,sn;

	log_string("Loading Class Table...");

	for (cls = 0; cls < MAX_CLASS; cls++)
	{
		for (sn = 0; *skill_table[sn].name != '\0' ; sn++)
		{
			skill_table[sn].skill_level[cls] = LEVEL_IMMORTAL;
			skill_table[sn].bonus_feat[cls] = LEVEL_IMMORTAL;
		}
		fread_class(cls);
	}
// 	for (sn = 0; *skill_table[sn].name != '\0' ; sn++)
// 	{
// 		if (skill_table[sn].skilltype != FSKILL_FEAT)
// 			continue;
// 		if (IS_SET(skill_table[sn].spell_school, FEAT_ROGUE))
// 		{
// 			skill_table[sn].bonus_feat[CLASS_ROGUE] = IS_SET(skill_table[sn].spell_school, FEAT_ADVANCED) ? 10 : 1;
// 		}
// 		if (IS_SET(skill_table[sn].spell_school, FEAT_METAMAGIC|FEAT_CREATION|FEAT_WIZARD))
// 		{
// 			skill_table[sn].bonus_feat[CLASS_WIZARD] = 1;
// 			skill_table[sn].bonus_feat[CLASS_LOREMASTER] = 1;
// 		}
// 		if (IS_SET(skill_table[sn].spell_school, FEAT_FIGHTER))
// 		{
// 			skill_table[sn].bonus_feat[CLASS_FIGHTER] = 1;
// 			skill_table[sn].bonus_feat[CLASS_ELDRITCH_KNIGHT] = 1;
// 		}
// 		if (IS_SET(skill_table[sn].spell_school, FEAT_PALADIN))
// 		{
// 			skill_table[sn].bonus_feat[CLASS_PALADIN] = 1;
// 			skill_table[sn].bonus_feat[CLASS_BLACKGUARD] = 1;
// 		}
// 	}
}

/* Save this domain skill table */
void save_domain (int num)
{
	FILE *fp;
	char buf[MAX_STRING_LENGTH];
	int lev, i;
	
	sprintf (buf, "%s/%s.txt", DOMAIN_DIR, domain_types[num]);
	
	close_reserve();

	if ((fp = my_fopen(buf, "w", FALSE)) == NULL)
	{
		log_printf("Could not open file %s in order to save domain %s.", buf, domain_types[num]);
		return;
	}
	
	for (lev = 0; lev < LEVEL_IMMORTAL; lev++)
	{
		for (i = 0; *skill_table[i].name != '\0'; i++)
		{
			if (!skill_table[i].name || !skill_table[i].name[0])
				continue;
				
			if (skill_table[i].domains[num] == lev)
				fprintf (fp, "%d %s\n", lev, skill_table[i].name);
		}
	}
	
	fprintf (fp, "-1"); /* EOF -1 */
	my_fclose (fp);

	open_reserve();
}

void save_domains()
{
	int i;
	
	for (i = 0; i < MAX_DOMAIN; i++)
		save_domain (i);
}

/* Load a domain skill table */
void load_domain (int num)
{
	char buf[MAX_STRING_LENGTH];
	int level,n;
	FILE *fp;
	
	sprintf (buf, "%s/%s.txt", DOMAIN_DIR, domain_types[num]);
	
	close_reserve();

	if ((fp = my_fopen(buf, "r", FALSE)) == NULL)
	{
		log_printf ("Could not open file %s in order to load domain %s.", buf, domain_types[num]);
		return;
	}
	
	fscanf (fp, "%d", &level);
	
	while (level != -1)
	{
		fscanf (fp, " %[^\n]\n", buf); /* read name of skill into buf */
		
		n = skill_lookup (buf); /* find index */
		
		if (n == -1)
		{
			char buf2[200];
			sprintf (buf2, "Domain %s: unknown skill/spell %s", domain_types[num], buf);
			log_printf (buf2, 0);
		}
		else
			skill_table[n].domains[num] = level;

		fscanf (fp, "%d", &level);
	}
	
	my_fclose (fp);
	open_reserve();
}
	
void load_domains ()
{
	int i,j;

	log_string("Skill Table: Domains...");

	for (i = 0; i < MAX_DOMAIN; i++)
	{
		for (j = 0; *skill_table[j].name != '\0'; j++)
		{
			skill_table[j].domains[i] = LEVEL_IMMORTAL;
		}
		load_domain (i);
	}
}

/* Save this style */
void save_style (int num)
{
	FILE *fp;
	char buf[MAX_STRING_LENGTH];
	int lev, i;
	
	sprintf (buf, "%s/%s.txt", STYLE_DIR, combat_styles[num]);
	
	close_reserve();

	if ((fp = my_fopen(buf, "w", FALSE)) == NULL)
	{
		log_printf("Could not open file %s in order to save style %s.", buf, combat_styles[num]);
		return;
	}
	
	for (lev = 0; lev < LEVEL_IMMORTAL; lev++)
	{
		for (i = 0; *skill_table[i].name != '\0' ; i++)
		{
			if (!skill_table[i].name || !skill_table[i].name[0])
				continue;
				
			if (skill_table[i].styles[num] == lev)
				fprintf (fp, "%d %s\n", lev, skill_table[i].name);
		}
	}
	
	fprintf (fp, "-1"); /* EOF -1 */
	my_fclose (fp);

	open_reserve();
}

void save_styles()
{
	int i;
	
	for (i = 0; i < STYLE_MAX; i++)
		save_style (i);
}

/* Load a style */
void load_style (int num)
{
	char buf[MAX_STRING_LENGTH];
	int level,n;
	FILE *fp;
	
	sprintf (buf, "%s/%s.txt", STYLE_DIR, combat_styles[num]);
	
	close_reserve();

	if ((fp = my_fopen(buf, "r", FALSE)) == NULL)
	{
		log_printf ("Could not open file %s in order to load style %s.", buf, combat_styles[num]);
		return;
	}
	
	fscanf (fp, "%d", &level);
	
	while (level != -1)
	{
		fscanf (fp, " %[^\n]\n", buf); /* read name of skill into buf */
		
		n = skill_lookup (buf); /* find index */
		
		if (n == -1)
		{
			char buf2[200];
			sprintf (buf2, "Style %s: unknown skill/spell %s", combat_styles[num], buf);
			log_printf (buf2, 0);
		}
		else
			skill_table[n].styles[num] = level;

		fscanf (fp, "%d", &level);
	}
	
	my_fclose (fp);
	open_reserve();
}
	
void load_styles ()
{
	int i,j;

	log_string("Skill Table: Combat Styles...");

	for (i = 0; i < STYLE_MAX; i++)
	{
		for (j = 0; *skill_table[j].name != '\0' ; j++)
		{
			skill_table[j].styles[i] = LEVEL_IMMORTAL;
		}		
		load_style (i);
	}
}

/* Save this race */
void fwrite_race (int num)
{
	FILE *fp;
	char buf[MAX_STRING_LENGTH];
	int sn;
	
	sprintf (buf, "%s/%s.txt", RACE_DIR, bits_to_str(num, "RACE_"));
	
	close_reserve();

	if ((fp = my_fopen(buf, "w", FALSE)) == NULL)
	{
		log_printf("Could not open file %s in order to save race.", buf);
	}
	
	fprintf( fp, "Name        %s~\n", !is_string(race_table[num].race_name) ? strlower(bits_to_str(num, "RACE_")) : race_table[num].race_name);

	fprintf( fp, "Size        ");
	break_bits( fp, race_table[num].size, "SIZE_", TRUE);
	fprintf( fp, "\n"	);
	fprintf( fp, "RaceType    ");
	break_bits( fp, race_table[num].type, "RTYPE_", TRUE);
	fprintf( fp, "\n"	);
	fprintf( fp, "BodyType    ");
	break_bits( fp, race_table[num].body_type, "BTYPE_", TRUE);
	fprintf( fp, "\n"	);

	fprintf( fp, "HitDice     %d\n", race_table[num].hit_dice );
	fprintf( fp, "SpeedLand   %d\n", race_table[num].land_speed );
	fprintf( fp, "SpeedBurrow %d\n", race_table[num].burrow_speed );
	fprintf( fp, "SpeedClimb  %d\n", race_table[num].climb_speed );
	fprintf( fp, "SpeedFly    %d\n", race_table[num].fly_speed );
	fprintf( fp, "SpeedSwim   %d\n", race_table[num].swim_speed );
	fprintf( fp, "NaturalAC   %d\n", race_table[num].nat_armor );
	fprintf( fp, "DeflectAC   %d\n", race_table[num].deflection );
	fprintf( fp, "PCRace      %d\n", race_table[num].pcrace );
	fprintf( fp, "Align       %d\n", race_table[num].alignment );
	fprintf( fp, "Ethos       %d\n", race_table[num].ethos );
	fprintf( fp, "AttrMod     %d %d %d %d %d %d\n", race_table[num].race_mod[0], race_table[num].race_mod[1], race_table[num].race_mod[2], race_table[num].race_mod[3], race_table[num].race_mod[4], race_table[num].race_mod[5] );
	fprintf( fp, "Nonabil     %d %d %d %d %d %d\n", race_table[num].nonability[0], race_table[num].nonability[1], race_table[num].nonability[2], race_table[num].nonability[3], race_table[num].nonability[4], race_table[num].nonability[5] );
	fprintf( fp, "Weight      %d\n", race_table[num].weight );
	fprintf( fp, "Height      %d\n", race_table[num].height );
	fprintf( fp, "ParentRace  ");
	break_bits( fp, race_table[num].parent_race, "RACE_", TRUE);
	fprintf( fp, "\n"	);

	fprintf( fp, "Material    ");
	break_bits( fp, race_table[num].material, "MATERIAL_", TRUE);
	fprintf( fp, "\n"	);

	fprintf( fp, "Vulnerable  ");
	break_bits( fp, race_table[num].vulnerability, "DAM_", FALSE);
	fprintf( fp, "\n"	);

	fprintf( fp, "AffectedBy  ");
	break_bits( fp, race_table[num].affected_by, "AFF_", FALSE);
	fprintf( fp, "\n"	);

	fprintf( fp, "Speaks      ");
	break_bits( fp, race_table[num].speaks, "LANG_", FALSE);
	fprintf( fp, "\n"	);
	fprintf( fp, "Understands ");
	break_bits( fp, race_table[num].understands, "LANG_", FALSE);
	fprintf( fp, "\n"	);
	fprintf( fp, "BonusLangs  ");
	break_bits( fp, race_table[num].bonus_langs, "LANG_", FALSE);
	fprintf( fp, "\n"	);

	fprintf( fp, "Specials    ");
	break_bits( fp, race_table[num].flags, "RSPEC_", FALSE);
	fprintf( fp, "\n"	);

	fprintf( fp, "Sectors     ");
	break_bits( fp, race_table[num].sectors, "RACESECT_", FALSE);
	fprintf( fp, "\n"	);

	fprintf( fp, "WearLocs    ");
	break_bits( fp, race_table[num].wear_locs, "CAN_WEAR", FALSE);
	fprintf( fp, "\n"	);

	if (race_table[num].poison)
	{
		fprintf( fp, "Poison  ");
		break_bits( fp, race_table[num].poison_part, "ATTK_", TRUE);
		fprintf( fp, " "	);
		break_bits( fp, race_table[num].poison, "POISON_", TRUE);
		fprintf( fp, "\n"	);
	}

	if (race_table[num].disease)
	{
		fprintf( fp, "Disease ");
		break_bits( fp, race_table[num].disease_part, "ATTK_", TRUE);
		fprintf( fp, " "	);
		break_bits( fp, race_table[num].disease, "DIS_", TRUE);
		fprintf( fp, "\n"	);
	}

	fprintf( fp, "FavoredCls  ");
	break_bits( fp, race_table[num].favored_class, "CLASS_", TRUE);
	fprintf( fp, "\n"	);

	fprintf( fp, "LevelAdj    %d\n", race_table[num].lvl_adj );
	fprintf( fp, "Align       %d\n", race_table[num].alignment );
	fprintf( fp, "Ethos       %d\n", race_table[num].ethos );

	for (sn = 0; *skill_table[sn].name != '\0' ; sn++)
	{
		if (skill_table[sn].name == NULL)
			continue;
		if (skill_table[sn].race_skill[num])
			fprintf (fp, "Skill       %d '%s'\n", skill_table[sn].race_skill[num], skill_table[sn].name);
	}
	
	for (sn = 0; sn < MAX_APPLY; sn++)
	{
		if (race_table[num].apply[sn])
		{
			fprintf (fp, "Apply       ");
			break_bits( fp, sn, "APPLY_", TRUE);
			fprintf( fp, " %d\n", race_table[num].apply[sn] );
		}
	}
	
	for (sn = 0; sn < ATTK_MAX; sn++)
	{
		if (race_table[num].attacks[sn])
		{
			fprintf (fp, "Attack      ");
			break_bits( fp, sn, "ATTK_", TRUE);
			fprintf( fp, " %d\n", race_table[num].attacks[sn] );
		}
	}
	
	fprintf( fp, "%s", "EndRace\n\n" );
	my_fclose (fp);

	open_reserve();
}

void save_races()
{
	int i;
	
	for (i = 0; i < MAX_RACE; i++)
	{
		fwrite_race(i);
	}
}

/* Load a race */
void fread_race (int num)
{
	char buf[MAX_STRING_LENGTH];
	char *word;
	char *line;
	bool fMatch;
	int x1,x2,x3,x4,x5,x6;
	int cnt;
	FILE *fp;
	
	sprintf (buf, "%s/%s.txt", RACE_DIR, bits_to_str(num, "RACE_"));

	close_reserve();

	if ((fp = my_fopen(buf, "r", FALSE)) == NULL)
	{
		fwrite_race(num);
		fread_race(num);
		return;
	}
	
	for ( ; ; )
	{
		word   = feof(fp) ? "EndRace" : fread_word(fp);
		fMatch = FALSE;

// 		if (!is_string(race_table[num].race_name))
// 			sprintf(race_table[num].race_name, strlower(bits_to_str(num, "RACE")));
// 
		switch (word[0])
		{
			case 'A':
				if ( !strcasecmp( word, "AttParts" ) )
				{
					fMatch = TRUE;
					break;
				}
				NKEY("Align",			race_table[num].alignment, fread_number(fp));
				AKEY("Apply",			race_table[num].apply, fread_number(fp));
				AKEY("Attack",		race_table[num].attacks, fread_number(fp));
				NKEY("AffectedBy",race_table[num].affected_by, fread_number(fp));
				if ( !strcasecmp( word, "AttrMod"  ) )
				{
					line = fread_line( fp );
					x1=x2=x3=x4=x5=x6=0;
					sscanf( line, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 );
					race_table[num].race_mod[0] = x1;
					race_table[num].race_mod[1] = x2;
					race_table[num].race_mod[2] = x3;
					race_table[num].race_mod[3] = x4;
					race_table[num].race_mod[4] = x5;
					race_table[num].race_mod[5] = x6;
					fMatch = TRUE;
					break;
				}
				break;

			case 'B':
				NKEY("BonusLangs", race_table[num].bonus_langs,	fread_number(fp));
				NKEY("BodyType", race_table[num].body_type, fread_number(fp));
				break;

			case 'D':
				if ( !strcasecmp( word, "Disease" ) )
				{
					int body;
					int value;

					body = fread_number( fp );
					value = fread_number( fp );
					
					if (!race_table[num].attacks)
					{
						bug("fread_race: %s - poisoned part not set in attack parts.", race_table[num].race_name);
						break;
					}
					if (disease_table[value].name == NULL)
					{
						bug("fread_race: %s - unknown disease type.", race_table[num].race_name);
						break;
					}
					race_table[num].disease_part = body;
					race_table[num].disease = value;

					fMatch = TRUE;
					break;
				}
				NKEY( "DeflectAC", race_table[num].deflection, fread_number(fp));
				break;

			case 'E':
				NKEY( "Ethos", race_table[num].ethos, fread_number(fp));
				if (!strcmp(word, "EndRace"))
					return;
				break;

			case 'F':
				NKEY( "FavoredCls", race_table[num].favored_class, fread_number(fp));
				break;

			case 'H':
				NKEY( "Height", race_table[num].height, fread_number(fp));
				NKEY( "HitDice", race_table[num].hit_dice, fread_number(fp));
				break;

			case 'L':
				NKEY( "LevelAdj", race_table[num].lvl_adj, fread_number(fp));
				break;

			case 'M':
				NKEY( "Material", race_table[num].material, fread_number(fp));
				break;
				
			case 'N':
				NKEY( "NaturalAC", race_table[num].nat_armor, fread_number(fp));
				if ( !strcasecmp( word, "Name" ) )
				{
					char *name = STRALLOC(fread_string(fp));
					
					if (!is_string(name))
						sprintf(race_table[num].race_name, "%s", strlower(bits_to_str(num, "RACE_")));
					else
						sprintf(race_table[num].race_name, "%s", name);
					fMatch = TRUE;
					break;
				}
				if ( !strcasecmp( word, "Nonabil"  ) )
				{
					line = fread_line( fp );
					x1=x2=x3=x4=x5=x6=0;
					sscanf( line, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 );
					race_table[num].nonability[0] = x1;
					race_table[num].nonability[1] = x2;
					race_table[num].nonability[2] = x3;
					race_table[num].nonability[3] = x4;
					race_table[num].nonability[4] = x5;
					race_table[num].nonability[5] = x6;
					fMatch = TRUE;
					break;
				}
				break;

			case 'P':
				if ( !strcasecmp( word, "PriPart" ) )
				{
					fMatch = TRUE;
					break;
				}
				NKEY( "PCRace", race_table[num].pcrace, fread_number(fp));
				NKEY( "ParentRace", race_table[num].parent_race, fread_number(fp));
				if ( !strcasecmp( word, "Poison" ) )
				{
					int body;
					int value;

					body = fread_number( fp );
					value = fread_number( fp );
					
					if (!race_table[num].attacks)
					{
						bug("fread_race: %s - poisoned part not set in attack parts.", race_table[num].race_name);
						break;
					}
					if (poison_table[value].name == NULL)
					{
						bug("fread_race: %s - unknown poison type.", race_table[num].race_name);
						break;
					}
					race_table[num].poison_part = body;
					race_table[num].poison = value;

					fMatch = TRUE;
					break;
				}
				break;

			case 'R':
				NKEY( "RaceType", race_table[num].type, fread_number(fp));
				break;

			case 'S':
				NKEY( "Size", race_table[num].size, fread_number(fp));
				NKEY( "Speaks", race_table[num].speaks, fread_number(fp));
				NKEY( "Specials", race_table[num].flags, fread_number(fp));
				NKEY( "SpeedBurrow", race_table[num].burrow_speed, fread_number(fp));
				NKEY( "SpeedClimb", race_table[num].climb_speed, fread_number(fp));
				NKEY( "SpeedFly", race_table[num].fly_speed, fread_number(fp));
				NKEY( "SpeedLand", race_table[num].land_speed, fread_number(fp));
				NKEY( "SpeedSwim", race_table[num].swim_speed, fread_number(fp));
				NKEY( "Sectors",	race_table[num].sectors, fread_number(fp));
				if ( !strcasecmp( word, "Skill" ) )
				{
					int sn;
					int value;

					value = fread_number( fp );

					sn = skill_lookup( fread_word( fp ) );

					if (sn < 0)
					{
						bug("fread_race: %s - unknown skill.", race_table[num].race_name);
					}
					else
					{
						skill_table[sn].race_skill[num] = value;
					}
					fMatch = TRUE;
					break;
				}
				break;

			case 'U':
				NKEY("Understands", race_table[num].understands, fread_number(fp));
				break;

			case 'V':
				NKEY("Vulnerable", race_table[num].vulnerability, fread_number(fp));
				break;

			case 'W':
				NKEY("WearLocs", race_table[num].wear_locs, fread_number(fp));
				NKEY("Weight", race_table[num].weight, fread_number(fp));
				break;
		}

		if (fMatch == FALSE)
		{
			log_printf("fread_race: no match: %s %s", word, fread_line(fp));
		}
	}
	my_fclose (fp);
	open_reserve();
}
	

void load_races ()
{
	int i;
//	int j;

	log_string("Loading Races...");

	for (i = 0; i < MAX_RACE; i++)
	{
// 		for (j = 0; *skill_table[j].name != '\0' ; j++)
// 		{
// 			skill_table[j].race_skill[i] = 0;
// 		}
		fread_race(i);
	}
}

/* Save this god */
void fwrite_god (int num)
{
	FILE *fp;
	char buf[MAX_STRING_LENGTH];
	int cnt;
	
	sprintf (buf, "%s/%s.txt", GOD_DIR, bits_to_str(num, "GOD_"));
	
	close_reserve();

	if ((fp = my_fopen(buf, "w", FALSE)) == NULL)
	{
		log_printf("Could not open file %s in order to save god.", buf);
		return;
	}
	
	fprintf( fp, "Name        %s~\n", !is_string(god_table[num].god_name) ? strlower(bits_to_str(num, "GOD_")) : god_table[num].god_name);
	fprintf( fp, "LogMsg      %s~\n", god_table[num].logout_msg );

	for (cnt = 0; cnt < MAX_DOMAIN; cnt++)
	{
		if (!god_table[num].domain[cnt])
			continue;
		fprintf (fp, "Domain    ");
		break_bits( fp, cnt, "DOMAIN_", TRUE);
		fprintf( fp, " 1\n"	);
	}
	fprintf( fp, "Domain1     %d\n", god_table[num].domain1 );
	fprintf( fp, "Domain2     %d\n", god_table[num].domain2 );
	
	fprintf( fp, "FaveWeapon  ");
	break_bits( fp, god_table[num].favored_weapon, "WEAPON_TYPE_", TRUE);
	fprintf( fp, "\n"	);

	fprintf( fp, "Align       %d\n", god_table[num].align );
	fprintf( fp, "Ethos       %d\n", god_table[num].ethos );
	fprintf( fp, "AlignHi     %d\n", god_table[num].align_hi );
	fprintf( fp, "AlignLo     %d\n", god_table[num].align_lo );
	fprintf( fp, "EthosHi     %d\n", god_table[num].ethos_hi );
	fprintf( fp, "EthosLo     %d\n", god_table[num].ethos_lo );

	fprintf( fp, "Race        ");
	break_bits( fp, god_table[num].race, "RSPEC_", FALSE);
	fprintf( fp, "\n"	);

	fprintf( fp, "PaladinMulti ");
	break_bits( fp, god_table[num].paladin_multi, "FLAG_CLASS", FALSE);
	fprintf( fp, "\n"	);

	fprintf( fp, "MonkMulti   ");
	break_bits( fp, god_table[num].monk_multi, "FLAG_CLASS", FALSE);
	fprintf( fp, "\n"	);

	for (cnt = 0; cnt < MAX_GOD; cnt++)
	{
		if (god_table[cnt].god_name == NULL)
			continue;
		if (god_table[num].faith_enemy[cnt] > 0)
		{
			fprintf (fp, "FaithEnemy  ");
			break_bits( fp, cnt, "GOD_", TRUE);
			fprintf( fp, " 1\n"	);
		}
	}
	
	for (cnt = 0; cnt < MAX_GOD; cnt++)
	{
		if (god_table[cnt].god_name == NULL)
			continue;
		if (god_table[num].faith_ally[cnt])
		{
			fprintf (fp, "FaithAlly   ");
			break_bits( fp, cnt, "GOD_", TRUE);
			fprintf( fp, " 1\n"	);
		}
	}
	
	fprintf( fp, "%s", "EndGod\n\n" );
	my_fclose (fp);

	open_reserve();
}

void save_gods()
{
	int i;
	
	for (i = 0; i < MAX_GOD; i++)
	{
		fwrite_god(i);
	}
}

/* Load a god */
void fread_god (int num)
{
	char buf[MAX_STRING_LENGTH];
	char *word;
	bool fMatch;
	int cnt;
	FILE *fp;
	
	sprintf (buf, "%s/%s.txt", GOD_DIR, bits_to_str(num, "GOD_"));
	
	close_reserve();

	if ((fp = my_fopen(buf, "r", FALSE)) == NULL)
	{
		fwrite_god(num);
		fread_god(num);
		return;
	}
	
	for (cnt = 0 ; cnt < 5 ; cnt++)
		RESTRING(god_table[num].ranking[cnt], str_empty);
		
	for ( ; ; )
	{
		word   = feof(fp) ? "EndGod" : fread_word(fp);
		fMatch = FALSE;

// 		if (!is_string(god_table[num].god_name))
// 			sprintf(god_table[num].god_name, strlower(bits_to_str(num, "GOD_")));
// 
		switch (word[0])
		{
			case 'A':
				NKEY("Align",			god_table[num].align, fread_number(fp));
				NKEY("AlignHi",		god_table[num].align_hi, fread_number(fp));
				NKEY("AlignLo",		god_table[num].align_lo, fread_number(fp));
				break;

			case 'D':
				NKEY( "Domain1", god_table[num].domain1, fread_number(fp));
				NKEY( "Domain2", god_table[num].domain2, fread_number(fp));
				AKEY( "Domain",  god_table[num].domain,  fread_number(fp));
				break;

			case 'E':
				NKEY( "Ethos", god_table[num].ethos, fread_number(fp));
				NKEY( "EthosHi", god_table[num].ethos_hi, fread_number(fp));
				NKEY( "EthosLo", god_table[num].ethos_lo, fread_number(fp));
				if (!strcmp(word, "EndGod"))
				{
					return;
				}
				break;

			case 'F':
				NKEY( "FaveWeapon", god_table[num].favored_weapon, fread_number(fp));
				AKEY( "FaithEnemy",	god_table[num].faith_enemy, fread_number(fp));
				AKEY( "FaithAlly",	god_table[num].faith_ally, fread_number(fp));
				break;

			case 'L':
				if ( !strcasecmp( word, "LogMsg" ) )
				{
					char *msg = STRALLOC(fread_string(fp));
					
					sprintf(god_table[num].logout_msg, "%s", msg);
					fMatch = TRUE;
				}
				break;

			case 'M':
				NKEY( "MonkMulti", god_table[num].monk_multi, fread_number(fp));
				break;

			case 'N':
				if ( !strcasecmp( word, "Name" ) )
				{
					char *name = STRALLOC(fread_string(fp));
					
					if (!is_string(name))
						sprintf(god_table[num].god_name, "%s", strlower(bits_to_str(num, "GOD_")));
					else
						sprintf(god_table[num].god_name, "%s", name);
					fMatch = TRUE;
				}
				break;

			case 'P':
				NKEY( "PaladinMulti", god_table[num].paladin_multi, fread_number(fp));
				break;

			case 'R':
				NKEY( "Race", god_table[num].race, fread_number(fp));
				break;
		}

		if (fMatch == FALSE)
		{
			log_printf("fread_god: no match: %s %s", word, fread_line(fp));
		}
	}	
	my_fclose (fp);
	open_reserve();
}
	

void load_gods ()
{
	int i;

	log_string("Loading Gods...");

	for (i = 0; i < MAX_GOD; i++)
	{
		fread_god(i);
	}
}

/* Save the components table */
void fwrite_components (void)
{
	FILE *fp;
	char buf[MAX_STRING_LENGTH];
	int i, j;
	
	sprintf (buf, "../skilltables/components.txt");
	
	close_reserve();

	if ((fp = my_fopen(buf, "w", FALSE)) == NULL)
	{
		log_printf("Could not open file %s in order to save components table.", buf);
		return;
	}
	
	for (i = 0; *skill_table[i].name != '\0'; i++)
	{
		if (!skill_table[i].name || !skill_table[i].name[0])
			continue;
			
		if (skill_table[i].components[0] == 0)
			continue;
			
		fprintf (fp, "'%s'", skill_table[i].name);
		for (j = 0 ; j < 5 ;j++)
		{
			fprintf (fp, " ");
			break_bits( fp, skill_table[i].components[j], "COMP_", TRUE);
		}
		fprintf (fp, "\n\r");
	}
	
	fprintf (fp, "End\n\r"); /* EOF */
	my_fclose (fp);

	open_reserve();
}

/* Load the components table */
void fread_components (void)
{
	char buf[MAX_STRING_LENGTH];
	char *word;
	int sn;
	FILE *fp;
	
	sprintf (buf, "../skilltables/components.txt");
	
	close_reserve();

	if ((fp = my_fopen(buf, "r", FALSE)) == NULL)
	{
		log_printf ("Could not open file %s in order to load components.", buf);
// 		abort();
		return;
	}
	
	log_printf ("Loading components...");
	
	for ( ; ; )
	{
		word   = feof(fp) ? "End" : fread_word(fp);
		
		if (!strcmp(word, "End"))
			return;

		if ((sn = skill_lookup(word)) == -1)
		{
			log_printf("fread_components: no such skill: %s %s", word, fread_line(fp));
			continue;
		}
		skill_table[sn].components[0] = fread_number(fp);
		skill_table[sn].components[1] = fread_number(fp);
		skill_table[sn].components[2] = fread_number(fp);
		skill_table[sn].components[3] = fread_number(fp);
		skill_table[sn].components[4] = fread_number(fp);
	}
	
	my_fclose (fp);
	open_reserve();
}
	
/* Save the bloodline table */
void fwrite_bloodlines (void)
{
	FILE *fp;
	char buf[MAX_STRING_LENGTH];
	int i, j;
	
	sprintf (buf, "../skilltables/bloodline.txt");
	
	close_reserve();

	if ((fp = my_fopen(buf, "w", FALSE)) == NULL)
	{
		log_printf("Could not open file %s in order to save bloodline table.", buf);
		return;
	}
	
	for (i = 0; *skill_table[i].name != '\0'; i++)
	{
		if (!skill_table[i].name || !skill_table[i].name[0])
			continue;
			
		for (j = 0 ; j < BLOODLINE_MAX ;j++)
		{
			if (skill_table[i].bloodline[j] >= 75)
				continue;

			fprintf (fp, "'%s'", skill_table[i].name);
			fprintf (fp, " ");
			break_bits( fp, j, "BLOODLINE_", TRUE);
			fprintf (fp, "  %d \n", skill_table[i].bloodline[j]);
		}
	}
	
	fprintf (fp, "End\n\r"); /* EOF */
	my_fclose (fp);

	open_reserve();
}

/* Load the bloodline table */
void fread_bloodlines (void)
{
	char buf[MAX_STRING_LENGTH];
	char *word;
	int sn, i, j;
	FILE *fp;
	
	// initialize all skills to immortal first.
	for (i = 0; *skill_table[i].name != '\0'; i++)
	{
		if (!skill_table[i].name || !skill_table[i].name[0])
			continue;
			
		for (j = 0 ; j < BLOODLINE_MAX ;j++)
		{
			skill_table[i].bloodline[j] = LEVEL_IMMORTAL;
		}
	}

	sprintf (buf, "../skilltables/bloodline.txt");
	
	close_reserve();

	if ((fp = my_fopen(buf, "r", FALSE)) == NULL)
	{
		log_printf ("Could not open file %s in order to load bloodline.", buf);
// 		abort();
		return;
	}
	
	log_printf ("Loading bloodline skill table...");
	
	for ( ; ; )
	{
		word = feof(fp) ? "End" : fread_word(fp);
		
		if (!strcmp(word, "End"))
			return;

		if ((sn = skill_lookup(word)) == -1)
		{
			log_printf("fread_bloodline: no such skill: %s %s", word, fread_line(fp));
			continue;
		}
		skill_table[sn].bloodline[fread_number(fp)] = fread_number(fp);
	}
	
	my_fclose (fp);
	open_reserve();
}