area/
/***************************************************************************


 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *


 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *


 *                                                                         *


 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *


 *  Chastain, Michael Quan, and Mitchell Tse.                              *


 *                                                                         *


 *  In order to use any part of this Merc Diku Mud, you must comply with   *


 *  both the original Diku license in 'license.doc' as well the Merc       *


 *  license in 'license.txt'.  In particular, you may not remove either of *


 *  these copyright notices.                                               *


 *                                                                         *


 *  Much time and thought has gone into this software and you are          *


 *  benefitting.  We hope that you share your changes too.  What goes      *


 *  around, comes around.                                                  *


 ***************************************************************************/





#if defined(macintosh)


#include <types.h>


#else


#include <sys/types.h>


#endif


#include <ctype.h>


#include <stdio.h>


#include <stdlib.h>


#include <string.h>


#include <time.h>


#include "merc.h"





#if !defined(macintosh)


extern	int	_filbuf		args( (FILE *) );


#endif








/*


 * Globals.


 */
HELP_DATA *		help_first;


HELP_DATA *		help_last;





SHOP_DATA *		shop_first;


SHOP_DATA *		shop_last;





CHAR_DATA *		char_free;


EXTRA_DESCR_DATA *	extra_descr_free;


NOTE_DATA *		note_free;


OBJ_DATA *		obj_free;


PC_DATA *		pcdata_free;





char			bug_buf		[2*MAX_INPUT_LENGTH];


CHAR_DATA *		char_list;


char *			help_greeting;


char			log_buf		[2*MAX_INPUT_LENGTH];


KILL_DATA		kill_table	[MAX_LEVEL];


OBJ_DATA *		object_list;


TIME_INFO_DATA		time_info;


WEATHER_DATA		weather_info;


sh_int			gsn_backstab;


sh_int                  gsn_shred;


sh_int                  gsn_quills;


sh_int 			gsn_cheapshot;


sh_int                  gsn_spit;


sh_int			gsn_venomtong;


sh_int			gsn_spiketail;


sh_int			gsn_badbreath;


sh_int			gsn_magma;


sh_int			gsn_shards;


sh_int			gsn_hide;


sh_int			gsn_peek;


sh_int			gsn_pick_lock;


sh_int			gsn_sneak;


sh_int			gsn_steal;


sh_int			gsn_spiderform;


sh_int			gsn_garotte;


sh_int			gsn_disarm;


sh_int			gsn_tendrils;


sh_int			gsn_berserk;


sh_int			gsn_punch;
sh_int			gsn_headbutt;
sh_int			gsn_shiroken;


sh_int			gsn_inferno;
sh_int			gsn_blinky;
sh_int			gsn_fangs;


sh_int			gsn_buffet;


sh_int			gsn_sweep;


sh_int			gsn_knee;


sh_int                  gsn_rfangs;
sh_int			gsn_thrustkick;
sh_int			gsn_spinkick;
sh_int			gsn_backfist;
sh_int			gsn_elbow;
sh_int			gsn_shinkick;
sh_int			gsn_palmstrike;
sh_int			gsn_lightningkick;
sh_int			gsn_tornadokick;
sh_int			gsn_jumpkick;
sh_int			gsn_spinkick;
sh_int			gsn_monksweep;
sh_int		gsn_circle;


sh_int			gsn_kick;


sh_int			gsn_hurl;


sh_int			gsn_rescue;


sh_int			gsn_track;


sh_int			gsn_polymorph;


sh_int			gsn_web;


sh_int			gsn_drowfire;


sh_int                  gsn_infirmity;


sh_int                  gsn_spew;


sh_int			gsn_blindness;


sh_int			gsn_charm_person;


sh_int			gsn_curse;


sh_int			gsn_invis;


sh_int			gsn_mass_invis;


sh_int			gsn_poison;


sh_int			gsn_sleep;





sh_int			gsn_darkness;


sh_int			gsn_paradox;


sh_int			gsn_laser;
sh_int			gsn_stuntubes;















/*


 * Locals.


 */


MOB_INDEX_DATA *	mob_index_hash		[MAX_KEY_HASH];


OBJ_INDEX_DATA *	obj_index_hash		[MAX_KEY_HASH];


ROOM_INDEX_DATA *	room_index_hash		[MAX_KEY_HASH];


char *			string_hash		[MAX_KEY_HASH];





AREA_DATA *		area_first;


AREA_DATA *		area_last;



CONFIG_DATA *		config_info;
ROOM_INDEX_DATA *	room_list;

HELP_DATA *		first_help;
HELP_DATA *		last_help;




char *			string_space;


char *			top_string;


char			str_empty	[1];





int			top_affect;


int			top_area;


int			top_rt;


int			top_ed;


int			top_exit;


int			top_help;


int			top_mob_index;


int			top_obj_index;


int			top_reset;


int			top_room;


int			top_shop;


int                     top_vnum_room;  /* OLC */
int                     top_vnum_mob;   /* OLC */
int                     top_vnum_obj;   /* OLC */

bool CHAOS = FALSE;
bool VISOR = FALSE;
bool DARKNESS = FALSE;
bool SPEED = FALSE;
bool BRACELET = FALSE;
bool TORC = FALSE;
bool ARMOUR = FALSE;
bool CLAWS = FALSE;






/*


 * Memory management.


 * Increase MAX_STRING if you have too.


 * Tune the others only if you understand what you're doing.





#define			MAX_STRING	1048576





 */





#define			MAX_STRING	1572864


#define			MAX_PERM_BLOCK	131072


#define			MAX_MEM_LIST	11





void *			rgFreeList	[MAX_MEM_LIST];


const int		rgSizeList	[MAX_MEM_LIST]	=


{


    16, 32, 64, 128, 256, 1024, 2048, 4096, 8192, 16384, 32768-64


};





int			nAllocString;


int			sAllocString;


int			nAllocPerm;


int			sAllocPerm;











/*


 * Semi-locals.


 */


bool			fBootDb;


FILE *			fpArea;


char			strArea[MAX_INPUT_LENGTH];











/*


 * Local booting procedures.


 */


void	init_mm		args( ( void ) );





void	load_area	args( ( FILE *fp ) );


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_specials	args( ( FILE *fp ) );


void    load_artifacts  args( ( void ) );
void    new_load_area   args( ( FILE *fp ) );   /* OLC */
void    new_load_rooms  args( ( FILE *fp ) );   /* OLC 1.1b */




void	fix_exits	args( ( void ) );





void	reset_area	args( ( AREA_DATA * pArea ) );












/*


 * Big mama top level function.


 */


void boot_db( void )


{


/*	char buf[MAX_STRING_LENGTH];
*/
    /*


     * Init some data space stuff.


     */


    {


	if ( ( string_space = calloc( 1, MAX_STRING ) ) == NULL )


	{


	    bug( "Boot_db: can't alloc %d string space.", MAX_STRING );


	    exit( 1 );


	}


	top_string	= string_space;


	fBootDb		= TRUE;


    }





    /*


     * Init random number generator.


     */


    {


	init_mm( );


    }





    /*


     * Set time and weather.


     */


    {


	long lhour, lday, lmonth;





	lhour		= (current_time - 650336715)


			/ (PULSE_TICK / PULSE_PER_SECOND);


	time_info.hour	= lhour  % 24;


	lday		= lhour  / 24;


	time_info.day	= lday   % 35;


	lmonth		= lday   / 35;


	time_info.month	= lmonth % 17;


	time_info.year	= lmonth / 17;





	     if ( time_info.hour <  5 ) weather_info.sunlight = SUN_DARK;


	else if ( time_info.hour <  6 ) weather_info.sunlight = SUN_RISE;


	else if ( time_info.hour < 19 ) weather_info.sunlight = SUN_LIGHT;


	else if ( time_info.hour < 20 ) weather_info.sunlight = SUN_SET;


	else                            weather_info.sunlight = SUN_DARK;





	weather_info.change	= 0;


	weather_info.mmhg	= 960;


	if ( time_info.month >= 7 && time_info.month <=12 )


	    weather_info.mmhg += number_range( 1, 50 );


	else


	    weather_info.mmhg += number_range( 1, 80 );





	     if ( weather_info.mmhg <=  980 ) weather_info.sky = SKY_LIGHTNING;


	else if ( weather_info.mmhg <= 1000 ) weather_info.sky = SKY_RAINING;


	else if ( weather_info.mmhg <= 1020 ) weather_info.sky = SKY_CLOUDY;


	else                                  weather_info.sky = SKY_CLOUDLESS;





    }

	initialise_config();


    /*
     * Assign gsn's for skills which have them.


     */


    {


	int sn;





	for ( sn = 0; sn < MAX_SKILL; sn++ )


	{


	    if ( skill_table[sn].pgsn != NULL )


		*skill_table[sn].pgsn = sn;


	}


    }





    /*


     * Read in all the area files.


     */


    {


	FILE *fpList;





	if ( ( fpList = fopen( AREA_LIST, "r" ) ) == NULL )


	{


	    perror( AREA_LIST );


	    exit( 1 );


	}





	for ( ; ; )


	{


	    strcpy( strArea, fread_word( fpList ) );


	    if ( strArea[0] == '$' )


		break;





	    if ( strArea[0] == '-' )


	    {


		fpArea = stdin;


	    }


	    else


	    {


/*		sprintf(buf,"loading %s",strArea);
		log_string(buf);*/
		if ( ( fpArea = fopen( strArea, "r" ) ) == NULL )


		{


		    perror( strArea );


		    exit( 1 );


		}


	    }





	    for ( ; ; )


	    {


		char *word;





		if ( fread_letter( fpArea ) != '#' )


		{


		    bug( "Boot_db: # not found.", 0 );


		    exit( 1 );


		}





		word = fread_word( fpArea );





		     if ( word[0] == '$'               )                 break;


		else if ( !str_cmp( word, "AREA"     ) ) load_area(fpArea);


		else if ( !str_cmp( word, "HELPS"    ) ) load_helps   (fpArea);


		else if ( !str_cmp( word, "MOBILES"  ) ) load_mobiles (fpArea);


		else if ( !str_cmp( word, "OBJECTS"  ) ) load_objects (fpArea);


		else if ( !str_cmp( word, "RESETS"   ) ) load_resets  (fpArea);


		else if ( !str_cmp( word, "ROOMS"    ) ) load_rooms   (fpArea);


		else if ( !str_cmp( word, "SHOPS"    ) ) load_shops   (fpArea);


		else if ( !str_cmp( word, "SPECIALS" ) ) load_specials(fpArea);


                else if ( !str_cmp( word, "AREADATA" ) )        /* OLC */
                    new_load_area( fpArea );
                else if ( !str_cmp( word, "ROOMDATA" ) )        /* OLC 1.1b */
                    new_load_rooms( fpArea );

		else


		{


		    bug( "Boot_db: bad section name.", 0 );


		    exit( 1 );


		}


	    }





	    if ( fpArea != stdin )


		fclose( fpArea );


	    fpArea = NULL;


	}


	fclose( fpList );


    }





    /*


     * Fix up exits.


     * Declare db booting over.


     * Reset all areas once.


     * Load up the notes file.


     */


    {


	fix_exits( );


	fBootDb	= FALSE;


	area_update( );


	load_bans();


	load_kingdoms();
	load_boards();
	save_notes();
	load_disabled();


        load_artifacts();
    }

    return;


}













/*
 * Load the Artifacts ( whee ).
 */

void load_artifacts( void )
{
    CHAR_DATA *pMob;
    OBJ_DATA *obj;
/*
    bug( "Loading Artifacts.", 0 );
*/
    /* Gaia */
    pMob = create_mobile( get_mob_index( 70000 ) );
    char_to_room( pMob, get_room_index( 9200 ) );
    obj = create_object( get_obj_index( 29516 ), 0 );
    obj_to_char( obj, pMob );

    /* Zombie Lord - Chaos Axe */
    pMob = create_mobile( get_mob_index( 1212 ) );
    char_to_room( pMob, get_room_index( 3001 ) );
    obj = create_object( get_obj_index( 29503 ), 0 );
    obj_to_char( obj, pMob );

    /* The Master Wizard - Visor of Vision */
    pMob = create_mobile( get_mob_index( 70007 ) );
    char_to_room( pMob, get_room_index( 1498 ) );
    obj = create_object( get_obj_index( 29515 ), 0 );
    obj_to_char( obj, pMob );

    /* Satan - Sword of Darkness */
    pMob = create_mobile( get_mob_index( 70006 ) );
    char_to_room( pMob, get_room_index( 2551 ) );
    obj = create_object( get_obj_index( 29512 ), 0 );
    obj_to_char( obj, pMob );

    /* Lloth the Spider Queen - Bracelet of Lloth */
    pMob = create_mobile( get_mob_index( 70003 ) );
    char_to_room( pMob, get_room_index( 5143 ) );
    obj = create_object( get_obj_index( 29518 ), 0 );
    obj_to_char( obj, pMob );

    /* Allah - Torc of Continual Restoration */
    pMob = create_mobile( get_mob_index( 70002 ) );
    char_to_room( pMob, get_room_index( 951 ) );
    obj = create_object( get_obj_index( 29504 ), 0 );
    obj_to_char( obj, pMob );

    /* Caine - The Armour of Resistance */
    pMob = create_mobile( get_mob_index( 70001 ) );
    char_to_room( pMob, get_room_index( 3475 ) );
    obj = create_object( get_obj_index( 29514 ), 0 );
    obj_to_char( obj, pMob );

    return;
}

/*


 * Snarf an 'area' header line.


 */


void load_area( FILE *fp )


{


    AREA_DATA *pArea;





    pArea		= alloc_perm( sizeof(*pArea) );


    pArea->name		= fread_string( fp );


    pArea->age		= 15;


    pArea->nplayer	= 0;





    pArea->area_flags   = AREA_LOADING;         /* OLC */
    pArea->security     = 3;                    /* OLC */
    pArea->builders     = str_dup( "None" );    /* OLC */
    pArea->lvnum        = 0;                    /* OLC */
    pArea->uvnum        = 0;                    /* OLC */
    pArea->vnum         = top_area;             /* OLC */
    pArea->filename     = str_dup( strArea );   /* OLC */

    if ( area_first == NULL )


	area_first = pArea;


    if ( area_last  != NULL )

 {
	area_last->next = pArea;


	REMOVE_BIT(area_last->area_flags, AREA_LOADING); /* OLC */
	}
    area_last	= pArea;


    pArea->next	= NULL;





    top_area++;


    return;


}










#if defined(KEY)
#undef KEY
#endif
                    
#define KEY( literal, field, value )                \
                if ( !str_cmp( word, literal ) )    \
                {                                   \
                    field  = value;                 \
                    fMatch = TRUE;                  \
                    break;                          \
                }
    
#define SKEY( string, field )                       \
                if ( !str_cmp( word, string ) )     \
                {                                   \
                    free_string( field );           \
                    field = fread_string( fp );     \
                    fMatch = TRUE;                  \
                    break;                          \
                }
  

/* OLC
 * Snarf an 'area' header line.   Check this format.  MUCH better.  Add fields
 * too.             
dv *
 * #AREAFILE
 * Name   { All } Locke    Newbie School~
 * Repop  A teacher pops in the room and says, 'Repop coming!'~
 * Recall 3001   
 * End
 */
void new_load_area( FILE *fp )
{
    AREA_DATA *pArea;
    char      *word;
    bool      fMatch;
    pArea               = alloc_perm( sizeof(*pArea) );
    pArea->age          = 15;
    pArea->nplayer      = 0;
    pArea->filename     = str_dup( strArea );
    pArea->vnum         = top_area;
    pArea->name         = str_dup( "New Area" );
    pArea->builders     = str_dup( "" );
    pArea->security     = 3;
    pArea->lvnum        = 0;
    pArea->uvnum        = 0;
    pArea->area_flags   = 0;
    pArea->recall       = ROOM_VNUM_TEMPLE;
 
    for ( ; ; )
    {
       word   = feof( fp ) ? "End" : fread_word( fp );
       fMatch = FALSE;
 
       switch ( UPPER(word[0]) )
       {
           case 'N':
            SKEY( "Name", pArea->name );
            break;   
           case 'S':
             KEY( "Security", pArea->security, fread_number( fp ) );
            break;
           case 'V':
            if ( !str_cmp( word, "VNUMs" ) )
            {
                pArea->lvnum = fread_number( fp );
                pArea->uvnum = fread_number( fp );
            }
            break;
           case 'E':
             if ( !str_cmp( word, "End" ) )
             {
                 fMatch = TRUE;
                 if ( area_first == NULL ) 
                    area_first = pArea;
                 if ( area_last  != NULL )
                    area_last->next = pArea;
                 area_last   = pArea;
                 pArea->next = NULL;
                 top_area++;
                 return;
            }
            break;  
           case 'B':
            SKEY( "Builders", pArea->builders );
            break;  
           case 'R':
             KEY( "Recall", pArea->recall, fread_number( fp ) );
            break;  
        }
    }
}
                
             
            
/*
 * Sets vnum range for area using OLC protection features.
 */
void assign_area_vnum( int vnum )
{
    if ( area_last->lvnum == 0 || area_last->uvnum == 0 )
        area_last->lvnum = area_last->uvnum = vnum;
    if ( vnum != URANGE( area_last->lvnum, vnum, area_last->uvnum ) )
        if ( vnum < area_last->lvnum )
            area_last->lvnum = vnum;
        else
            area_last->uvnum = vnum;
    return;  
}




/*
 * Returns an uppercase string.
 */
char *strupper( const char *str )
{
    static char strup[MAX_STRING_LENGTH];
    int i;

    for ( i = 0; str[i] != '\0'; i++ )
	strup[i] = UPPER(str[i]);
    strup[i] = '\0';
    return strup;
}


/*
 * Adds a help page to the list if it is not a duplicate of an existing page.
 * Page is insert-sorted by keyword.			-Thoric
 * (The reason for sorting is to keep do_hlist looking nice)
 */
void add_help( HELP_DATA *pHelp )
{
    HELP_DATA *tHelp;
   /* char buf[MAX_STRING_LENGTH];*/
    int match;

    for ( tHelp = first_help; tHelp; tHelp = tHelp->next )
/*
	if ( pHelp->level == tHelp->level
	&&  !strcmp(pHelp->keyword, tHelp->keyword) )
	{
	    sprintf(buf, "Duplicate %s. Deleting Help.\n\r",pHelp->keyword);
	    bug(buf,0);
	    STRFREE( pHelp->text );
	    STRFREE( pHelp->keyword );
	    DISPOSE( pHelp );
	    return;
	}
	else
*/
	if ( (match=strcmp(pHelp->keyword[0]=='\'' ? pHelp->keyword+1 : pHelp->keyword,
			   tHelp->keyword[0]=='\'' ? tHelp->keyword+1 : tHelp->keyword)) < 0
	||   (match == 0 && pHelp->level > tHelp->level) )
	{
	    if ( !tHelp->prev )
		first_help	  = pHelp;
	    else
		tHelp->prev->next = pHelp;
	    pHelp->prev		  = tHelp->prev;
	    pHelp->next		  = tHelp;
	    tHelp->prev		  = pHelp;
	    break;
	}

    if ( !tHelp )
	LINK( pHelp, first_help, last_help, next, prev );

    top_help++;
}


/*
 * Load a help section.
 */
void load_helps( FILE *fp )
{
    HELP_DATA *pHelp;

    for ( ; ; )
    {
	CREATE( pHelp, HELP_DATA, 1 );
	pHelp->level	= fread_number( fp );
	pHelp->keyword	= fread_string( fp );
	if ( pHelp->keyword[0] == '$' )
	    break;
	pHelp->text	= fread_string( fp );
	if ( pHelp->keyword[0] == '\0' )
	{
	    STRFREE( pHelp->text );
	    STRFREE( pHelp->keyword );
	    DISPOSE( pHelp );
	    continue;
	}

	if ( !str_cmp( pHelp->keyword, "greeting" ) )
	    help_greeting = pHelp->text;
	add_help( pHelp );
    }
    return;
}


/*


 * Snarf a mob section.


 */


void load_mobiles( FILE *fp )


{


    MOB_INDEX_DATA *pMobIndex;






    if ( !area_last )   /* OLC */
    {
        bug( "Load_mobiles: no #AREA seen yet.", 0 );
        exit( 1 );
    }
 
    for ( ; ; )


    {


	int vnum;


	char letter;


	int iHash;





	letter				= fread_letter( fp );


	if ( letter != '#' )


	{


	    bug( "Load_mobiles: # not found.", 0 );


	    exit( 1 );


	}





	vnum				= fread_number( fp );


	if ( vnum == 0 )


	    break;





	fBootDb = FALSE;


	if ( get_mob_index( vnum ) != NULL )


	{


	    bug( "Load_mobiles: vnum %d duplicated.", vnum );


	    exit( 1 );


	}


	fBootDb = TRUE;





	pMobIndex			= alloc_perm( sizeof(*pMobIndex) );


	pMobIndex->vnum			= vnum;


        pMobIndex->area                 = area_last;            /* OLC */
	pMobIndex->player_name		= fread_string( fp );


	pMobIndex->short_descr		= fread_string( fp );


	pMobIndex->long_descr		= fread_string( fp );


	pMobIndex->description		= fread_string( fp );





	pMobIndex->long_descr[0]	= UPPER(pMobIndex->long_descr[0]);


	pMobIndex->description[0]	= UPPER(pMobIndex->description[0]);





	pMobIndex->act			= fread_number( fp ) | ACT_IS_NPC;


	pMobIndex->affected_by		= fread_number( fp );


	pMobIndex->itemaffect		= 0;


	pMobIndex->pShop		= NULL;


	pMobIndex->alignment		= fread_number( fp );


	letter				= fread_letter( fp );


	pMobIndex->level		= number_fuzzy( fread_number( fp ) );





	/*


	 * The unused stuff is for imps who want to use the old-style


	 * stats-in-files method.


	 */


	pMobIndex->hitroll		= fread_number( fp );	/* Unused */


	pMobIndex->ac			= fread_number( fp );	/* Unused */


	pMobIndex->hitnodice		= fread_number( fp );	/* Unused */


	/* 'd'		*/		  fread_letter( fp );	/* Unused */


	pMobIndex->hitsizedice		= fread_number( fp );	/* Unused */


	/* '+'		*/		  fread_letter( fp );	/* Unused */


	pMobIndex->hitplus		= fread_number( fp );	/* Unused */


	pMobIndex->damnodice		= fread_number( fp );	/* Unused */


	/* 'd'		*/		  fread_letter( fp );	/* Unused */


	pMobIndex->damsizedice		= fread_number( fp );	/* Unused */


	/* '+'		*/		  fread_letter( fp );	/* Unused */


	pMobIndex->damplus		= fread_number( fp );	/* Unused */


	pMobIndex->gold			= fread_number( fp );	/* Unused */


	/* xp can't be used! */		  fread_number( fp );	/* Unused */


	/* position	*/		  fread_number( fp );	/* Unused */


	/* start pos	*/		  fread_number( fp );	/* Unused */





	/*


	 * Back to meaningful values.


	 */


	pMobIndex->sex			= fread_number( fp );





	if ( letter != 'S' )


	{


	    bug( "Load_mobiles: vnum %d non-S.", vnum );


	    exit( 1 );


	}





	iHash			= vnum % MAX_KEY_HASH;


	pMobIndex->next		= mob_index_hash[iHash];


	mob_index_hash[iHash]	= pMobIndex;


	top_mob_index++;


        top_vnum_mob = top_vnum_mob < vnum ? vnum : top_vnum_mob;  /* OLC */
        assign_area_vnum( vnum );                                  /* OLC */

	kill_table[URANGE(0, pMobIndex->level, MAX_LEVEL-1)].number++;


    }





    return;


}











/*


 * Snarf an obj section.


 */


void load_objects( FILE *fp )


{


    OBJ_INDEX_DATA *pObjIndex;






    if ( !area_last )   /* OLC */
    {
        bug( "Load_objects: no #AREA seen yet.", 0 );
        exit( 1 );
    }

    for ( ; ; )


    {


	int vnum;


	char letter;


	int iHash;





	letter				= fread_letter( fp );


	if ( letter != '#' )


	{


	    bug( "Load_objects: # not found.", 0 );


	    exit( 1 );


	}





	vnum				= fread_number( fp );


	if ( vnum == 0 )


	    break;



/*
	     if ( vnum == 29503 && CHAOS )
	  return;
        else if ( vnum == 29515 && VISOR )
          return;
        else if ( vnum == 29512 && DARKNESS )
          return;
        else if ( vnum == 29505 && SPEED )
          return;
        else if ( vnum == 29518 && BRACELET )
          return;
        else if ( vnum == 29504 && TORC )
          return;
        else if ( vnum == 29514 && ARMOUR )
          return;
        else if ( vnum == 29516 && CLAWS )
          return;
*/

	fBootDb = FALSE;
	if ( get_obj_index( vnum ) != NULL )
	{
	    bug( "Load_objects: vnum %d duplicated.", vnum );
	    exit( 1 );
	}

	fBootDb = TRUE;

	pObjIndex			= alloc_perm( sizeof(*pObjIndex) );
	pObjIndex->vnum			= vnum;
        pObjIndex->area                 = area_last;            /* OLC */
	pObjIndex->name			= fread_string( fp );


	pObjIndex->short_descr		= fread_string( fp );


	pObjIndex->description		= fread_string( fp );


	/* Action description */	  fread_string( fp );





	pObjIndex->short_descr[0]	= LOWER(pObjIndex->short_descr[0]);


	pObjIndex->description[0]	= UPPER(pObjIndex->description[0]);





	pObjIndex->item_type		= fread_number( fp );


	pObjIndex->extra_flags		= fread_number( fp );


	pObjIndex->wear_flags		= fread_number( fp );


	switch (pObjIndex->item_type) {
	case ITEM_WAND:
	case ITEM_STAFF:
		pObjIndex->value[0] = fread_number(fp);
		pObjIndex->value[1] = fread_number(fp);
		pObjIndex->value[2] = fread_number(fp);
		pObjIndex->value[3] = skill_lookup(fread_word(fp));
		break;
	case ITEM_POTION:
	case ITEM_PILL:
	case ITEM_SCROLL:
		pObjIndex->value[0] = fread_number(fp);
		pObjIndex->value[1] = skill_lookup(fread_word(fp));
		pObjIndex->value[2] = skill_lookup(fread_word(fp));
		pObjIndex->value[3] = skill_lookup(fread_word(fp));
		break;
	default:
	pObjIndex->value[0]		= fread_number( fp );


	pObjIndex->value[1]		= fread_number( fp );


	pObjIndex->value[2]		= fread_number( fp );


	pObjIndex->value[3]		= fread_number( fp );


	break;
	}
	pObjIndex->weight		= fread_number( fp );


	pObjIndex->cost			= fread_number( fp );	/* Unused */


	pObjIndex->affected		= NULL;


	pObjIndex->extra_descr		= NULL;


	pObjIndex->chpoweron		= NULL;


	pObjIndex->chpoweroff		= NULL;


	pObjIndex->chpoweruse		= NULL;


	pObjIndex->victpoweron		= NULL;


	pObjIndex->victpoweroff		= NULL;


	pObjIndex->victpoweruse		= NULL;


	pObjIndex->spectype		= 0;


	pObjIndex->specpower		= 0;


	/* Cost per day */		  fread_number( fp );


/*


	if ( pObjIndex->item_type == ITEM_POTION )


	    SET_BIT(pObjIndex->extra_flags, ITEM_NODROP);


*/


	for ( ; ; )


	{


	    char letter;





	    letter = fread_letter( fp );





	    if ( letter == 'A' )


	    {


		AFFECT_DATA *paf;





		paf			= alloc_perm( sizeof(*paf) );


		paf->type		= -1;


		paf->duration		= -1;


		paf->location		= fread_number( fp );


		paf->modifier		= fread_number( fp );


		paf->bitvector		= 0;


		paf->next		= pObjIndex->affected;


		pObjIndex->affected	= paf;


		top_affect++;


	    }





	    else if ( letter == 'E' )


	    {


		EXTRA_DESCR_DATA *ed;





		ed			= alloc_perm( sizeof(*ed) );


		ed->keyword		= fread_string( fp );


		ed->description		= fread_string( fp );


		ed->next		= pObjIndex->extra_descr;


		pObjIndex->extra_descr	= ed;


		top_ed++;


	    }





	    else if ( letter == 'Q' )


	    {


		pObjIndex->chpoweron	= fread_string( fp );


		pObjIndex->chpoweroff	= fread_string( fp );


		pObjIndex->chpoweruse	= fread_string( fp );


		pObjIndex->victpoweron	= fread_string( fp );


		pObjIndex->victpoweroff	= fread_string( fp );


		pObjIndex->victpoweruse	= fread_string( fp );


		pObjIndex->spectype	= fread_number( fp );


		pObjIndex->specpower	= fread_number( fp );


	    }





	    else


	    {


		ungetc( letter, fp );


		break;


	    }


	}





	/*


	 * Translate spell "slot numbers" to internal "skill numbers."


	 */


	switch ( pObjIndex->item_type )


	{


	case ITEM_PILL:


	case ITEM_POTION:


	case ITEM_SCROLL:


	    pObjIndex->value[1] = slot_lookup( pObjIndex->value[1] );


	    pObjIndex->value[2] = slot_lookup( pObjIndex->value[2] );


	    pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] );


	    break;





	case ITEM_STAFF:


	case ITEM_WAND:


	    pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] );


	    break;


	}

	if ( vnum == 29503 )
          CHAOS = TRUE;
        if ( vnum == 29515 )
          VISOR = TRUE;
        if ( vnum == 29512 )
          DARKNESS = TRUE;
        if ( vnum == 29505 )
          SPEED = TRUE;
        if ( vnum == 29518 )
          BRACELET = TRUE;
        if ( vnum == 29504 )
          TORC = TRUE;
        if ( vnum == 29514 )
          ARMOUR = TRUE;
        if ( vnum == 29516 )
	  CLAWS = TRUE;

	iHash			= vnum % MAX_KEY_HASH;


	pObjIndex->next		= obj_index_hash[iHash];


	obj_index_hash[iHash]	= pObjIndex;


	top_obj_index++;


        top_vnum_obj = top_vnum_obj < vnum ? vnum : top_vnum_obj;  /* OLC */
        assign_area_vnum( vnum );                                  /* OLC */
 
    }





    return;


}



/*
 * Adds a reset to a room.  OLC
 * Similar to add_reset in olc.c
 */
void new_reset( ROOM_INDEX_DATA *pR, RESET_DATA *pReset )
{
    RESET_DATA *pr;
     
    if ( !pR )
       return;

    pr = pR->reset_last;
        
    if ( !pr )
    {
        pR->reset_first = pReset;
        pR->reset_last  = pReset;
    }
    else
    {
        pR->reset_last->next = pReset;
        pR->reset_last       = pReset;
        pR->reset_last->next = NULL;
    }   

    top_reset++;
    return;
}


/*   
 * Snarf a reset section.       Changed for OLC.
 */      
void load_resets( FILE *fp )
{
    RESET_DATA  *pReset;
    int         iLastRoom = 0;
    int         iLastObj  = 0;
    
    if ( !area_last )
    {
        bug( "Load_resets: no #AREA seen yet.", 0 );
        exit( 1 );
    }    
  
    for ( ; ; )
    {
        EXIT_DATA       *pexit;
        ROOM_INDEX_DATA *pRoomIndex;
        char             letter;
    
        if ( ( letter = fread_letter( fp ) ) == 'S' )
            break;
     
        if ( letter == '*' )
        {
            fread_to_eol( fp );
            continue;
        }

        pReset          = alloc_perm( sizeof( *pReset ) );
        pReset->command = letter;
        /* if_flag */     fread_number( fp );
        pReset->arg1    = fread_number( fp );
        pReset->arg2    = fread_number( fp );
        pReset->arg3    = ( letter == 'G' || letter == 'R' )
                            ? 0 : fread_number( fp );
                          fread_to_eol( fp );
        
        /*
         * Validate parameters.
         * We're calling the index functions for the side effect.
         */
        switch ( letter )
        {
        default:
            bug( "Load_resets: bad command '%c'.", letter );
            exit( 1 );
            break;
     
        case 'M':
            get_mob_index  ( pReset->arg1 );
            if ( ( pRoomIndex = get_room_index ( pReset->arg3 ) ) )
            {
                new_reset( pRoomIndex, pReset );
                iLastRoom = pReset->arg3;
            }
            break;
        
        case 'O':
            get_obj_index  ( pReset->arg1 ); 
            if ( ( pRoomIndex = get_room_index ( pReset->arg3 ) ) )
            {
                new_reset( pRoomIndex, pReset );
                iLastObj = pReset->arg3;
            }
            break;
         
        case 'P':
            get_obj_index  ( pReset->arg1 );
            if ( ( pRoomIndex = get_room_index ( iLastObj ) ) )
            {   
                new_reset( pRoomIndex, pReset );
            }
            break;
     
        case 'G':
        case 'E':
            get_obj_index  ( pReset->arg1 );
            if ( ( pRoomIndex = get_room_index ( iLastRoom ) ) )
            {
                new_reset( pRoomIndex, pReset );
                iLastObj = iLastRoom;
            }
            break;
        
        case 'D':
            pRoomIndex = get_room_index( pReset->arg1 );
             
            if (   pReset->arg2 < 0
                || pReset->arg2 > 5
                || !pRoomIndex
                || !( pexit = pRoomIndex->exit[pReset->arg2] )
                || !IS_SET( pexit->rs_flags, EX_ISDOOR ) )
            {
                bug( "Load_resets: 'D': exit %d not door.", pReset->arg2 );
                exit( 1 );
            }   
                
            switch ( pReset->arg3 )     /* OLC 1.1b */
            {
                default:
                    bug( "Load_resets: 'D': bad 'locks': %d." , pReset->arg3);
                case 0:
                    break;
                case 1: SET_BIT( pexit->rs_flags, EX_CLOSED );  
                    break;
                case 2: SET_BIT( pexit->rs_flags, EX_CLOSED | EX_LOCKED );
                    break;
            }
            break;
        
        case 'R':
            if ( pReset->arg2 < 0 || pReset->arg2 > 6 ) /* Last Door. */
            {
                bug( "Load_resets: 'R': bad exit %d.", pReset->arg2 );
                exit( 1 );
            }
                
            if ( ( pRoomIndex = get_room_index( pReset->arg1 ) ) )
                new_reset( pRoomIndex, pReset );
                
            break;
        }
    }           
            
            
    return;  
}






/*


 * Snarf a room section.


 */


void load_rooms( FILE *fp )


{


    ROOM_INDEX_DATA *pRoomIndex;





    if ( area_last == NULL )


    {


	bug( "Load_resets: no #AREA seen yet.", 0 );


	exit( 1 );


    }





    for ( ; ; )


    {


	int vnum;


	char letter;


	int door;


	int iHash;





	letter				= fread_letter( fp );


	if ( letter != '#' )


	{


	    bug( "Load_rooms: # not found.", 0 );


	    exit( 1 );


	}





	vnum				= fread_number( fp );


	if ( vnum == 0 )


	    break;





	fBootDb = FALSE;


	if ( get_room_index( vnum ) != NULL )


	{


	    bug( "Load_rooms: vnum %d duplicated.", vnum );


	    exit( 1 );


	}


	fBootDb = TRUE;





	pRoomIndex			= alloc_perm( sizeof(*pRoomIndex) );


	pRoomIndex->people		= NULL;


	pRoomIndex->contents		= NULL;


	pRoomIndex->first_person	= NULL;
	pRoomIndex->last_person		= NULL;
	pRoomIndex->first_content	= NULL;
	pRoomIndex->last_content	= NULL;
	pRoomIndex->extra_descr		= NULL;
	pRoomIndex->first_extradesc	= NULL;
	pRoomIndex->last_extradesc	= NULL;
	pRoomIndex->area		= area_last;


	pRoomIndex->vnum		= vnum;


	pRoomIndex->name		= fread_string( fp );


	pRoomIndex->description		= fread_string( fp );


	/* Area number */		  fread_number( fp );


	pRoomIndex->room_flags		= fread_number( fp );


	pRoomIndex->sector_type		= fread_number( fp );


	pRoomIndex->light		= 0;


	pRoomIndex->blood		= 0;


	pRoomIndex->roomtext		= NULL;


	pRoomIndex->first_exit		= NULL;
	pRoomIndex->last_exit		= NULL;
	for ( door = 0; door <= 4; door++ )


	{


	    pRoomIndex->track[door] 	= str_dup( "" );


	    pRoomIndex->track_dir[door] = 0;
	}
	for ( door = 0; door <= 5; door++ )
	    pRoomIndex->exit[door] = NULL;


	for ( ; ; )


	{


	    letter = fread_letter( fp );





	    if ( letter == 'S' )


		break;





	    if ( letter == 'D' )


	    {


		EXIT_DATA *pexit;


		int locks;





		door = fread_number( fp );


		if ( door < 0 || door > 5 )


		{


		    bug( "Fread_rooms: vnum %d has bad door number.", vnum );


		    exit( 1 );


		}





		pexit			= alloc_perm( sizeof(*pexit) );


		pexit->description	= fread_string( fp );


		pexit->keyword		= fread_string( fp );


		pexit->exit_info	= 0;


                pexit->rs_flags         = 0;                    /* OLC */ 
		locks			= fread_number( fp );


		pexit->key		= fread_number( fp );


		pexit->vnum		= fread_number( fp );





/*		switch ( locks )


		{


		case 1: pexit->exit_info = EX_ISDOOR;                break;


		case 2: pexit->exit_info = EX_ISDOOR | EX_PICKPROOF; break;


		}


*/

                switch ( locks )        /* OLC exit_info to rs_flags. */
                {
                case 1: pexit->rs_flags  = EX_ISDOOR;                    break;
                case 2: pexit->rs_flags  = EX_ISDOOR | EX_PICKPROOF;     break;
                }




		pRoomIndex->exit[door]	= pexit;


		top_exit++;


	    }


	    else if ( letter == 'E' )


	    {


		EXTRA_DESCR_DATA *ed;





		ed			= alloc_perm( sizeof(*ed) );


		ed->keyword		= fread_string( fp );


		ed->description		= fread_string( fp );


		ed->next		= pRoomIndex->extra_descr;


		pRoomIndex->extra_descr	= ed;


		top_ed++;


	    }


	    else if ( letter == 'T' )


	    {


		ROOMTEXT_DATA *rt;





		rt			= alloc_perm( sizeof(*rt) );


		rt->input		= fread_string( fp );


		rt->output		= fread_string( fp );


		rt->choutput		= fread_string( fp );


		rt->name		= fread_string( fp );


		rt->type		= fread_number( fp );


		rt->power		= fread_number( fp );


		rt->mob			= fread_number( fp );


		rt->next		= pRoomIndex->roomtext;


		pRoomIndex->roomtext	= rt;


		top_rt++;


	    }


	    else


	    {


		bug( "Load_rooms: vnum %d has flag not 'DES'.", vnum );


		exit( 1 );


	    }


	}





	iHash			= vnum % MAX_KEY_HASH;


	pRoomIndex->next	= room_index_hash[iHash];


	room_index_hash[iHash]	= pRoomIndex;


	pRoomIndex->next_room	= room_list;
	room_list		= pRoomIndex;
	top_room++;


       top_vnum_room = top_vnum_room < vnum ? vnum : top_vnum_room; /* OLC */
        assign_area_vnum( vnum );                                    /* OLC */

    }





    return;


}



/* OLC 1.1b */
void new_load_rooms( FILE *fp )
{   
    ROOM_INDEX_DATA *pRoomIndex;
    
    if ( !area_last )
    {
        bug( "Load_rooms: no #AREA seen yet.", 0 );
        exit( 1 ); 
    }
        
    for ( ; ; )
    {
        char letter;
        int  vnum;
        int  door;
        int  iHash;
    
        letter                          = fread_letter( fp );
        if ( letter != '#' )
        {
            bug( "Load_rooms: # not found.", 0 );  
            exit( 1 );
        }       

        vnum                            = fread_number( fp );
        if ( vnum == 0 )
            break;
    
        fBootDb = FALSE;
        if ( get_room_index( vnum ) )
        {
            bug( "Load_rooms: vnum %d duplicated.", vnum );
            exit( 1 );
        }
        fBootDb = TRUE;
        
        pRoomIndex                      = alloc_perm( sizeof( *pRoomIndex ) );
        pRoomIndex->people              = NULL;
        pRoomIndex->contents            = NULL;
        pRoomIndex->extra_descr         = NULL;
        pRoomIndex->area                = area_last;
        pRoomIndex->vnum                = vnum;
        pRoomIndex->name                = fread_string( fp );
        pRoomIndex->description         = fread_string( fp );
        /* Area number */                 fread_number( fp );   /* Unused */
        pRoomIndex->room_flags          = fread_number( fp );
        pRoomIndex->sector_type         = fread_number( fp );
        pRoomIndex->light               = 0;
	pRoomIndex->blood		= 0;
	pRoomIndex->roomtext		= NULL;
	for ( door = 0; door <= 4; door++)
	{
		pRoomIndex->track[door]= str_dup("");
		pRoomIndex->track_dir[door] = 0;
	}
        for ( door = 0; door <= 5; door++ )
            pRoomIndex->exit[door] = NULL;
        
        for ( ; ; )
        {
            letter = fread_letter( fp );
        
            if ( letter == 'S' || letter == 's' )
            {
                if ( letter == 's' )
                    bug( "Load_rooms: vnum %d has lowercase 's'", vnum );
                break;
            }
        
            if ( letter == 'D' )
            {
                EXIT_DATA *pexit;
                int        locks;
        
                door = fread_number( fp );
                if ( door < 0 || door > 5 )
                {
                    bug( "Fread_rooms: vnum %d has bad door number.", vnum );
                    exit( 1 );
                }
        
                pexit                   = alloc_perm( sizeof( *pexit ) );
                pexit->description      = fread_string( fp );
                pexit->keyword          = fread_string( fp );
                locks                   = fread_number( fp );
                pexit->exit_info        = locks;
                pexit->rs_flags         = locks;
                pexit->key              = fread_number( fp );
                pexit->vnum             = fread_number( fp );
             
                
                pRoomIndex->exit[door]          = pexit;
                top_exit++;
            }
            else if ( letter == 'E' )
            {
                EXTRA_DESCR_DATA *ed;
                
                ed                      = alloc_perm( sizeof( *ed ) );
                ed->keyword             = fread_string( fp );
                ed->description         = fread_string( fp );
                ed->next                = pRoomIndex->extra_descr;
                pRoomIndex->extra_descr = ed;
                top_ed++;
            }
            else if ( letter == 'T' )
            {
                ROOMTEXT_DATA *rt;

                rt                      = alloc_perm( sizeof(*rt) );
                rt->input               = fread_string( fp );
                rt->output              = fread_string( fp );
                rt->choutput            = fread_string( fp );
                rt->name                = fread_string( fp );
                rt->type                = fread_number( fp );
                rt->power               = fread_number( fp );
                rt->mob                 = fread_number( fp );
                rt->next                = pRoomIndex->roomtext;
                pRoomIndex->roomtext    = rt;
                top_rt++;
            }

            else 
            {
                bug( "Load_rooms: vnum %d has flag not 'DES'.", vnum );  
                exit( 1 );
            }
        }
                
        iHash                   = vnum % MAX_KEY_HASH;
        pRoomIndex->next        = room_index_hash[iHash];
        room_index_hash[iHash]  = pRoomIndex;
        top_room++;
        top_vnum_room = top_vnum_room < vnum ? vnum : top_vnum_room;
        assign_area_vnum( vnum );
    }
             
    return;
}

/*


 * Snarf a shop section.


 */


void load_shops( FILE *fp )


{


    SHOP_DATA *pShop;





    for ( ; ; )


    {


	MOB_INDEX_DATA *pMobIndex;


	int iTrade;





	pShop			= alloc_perm( sizeof(*pShop) );


	pShop->keeper		= fread_number( fp );


	if ( pShop->keeper == 0 )


	    break;


	for ( iTrade = 0; iTrade < MAX_TRADE; iTrade++ )


	    pShop->buy_type[iTrade]	= fread_number( fp );


	pShop->profit_buy	= fread_number( fp );


	pShop->profit_sell	= fread_number( fp );


	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;





	if ( shop_first == NULL )


	    shop_first = pShop;


	if ( shop_last  != NULL )


	    shop_last->next = pShop;





	shop_last	= pShop;


	pShop->next	= NULL;


	top_shop++;


    }





    return;


}











/*


 * Snarf spec proc declarations.


 */


void load_specials( FILE *fp )


{


    for ( ; ; )


    {


	MOB_INDEX_DATA *pMobIndex;


	char letter;





	switch ( letter = fread_letter( fp ) )


	{


	default:


	    bug( "Load_specials: letter '%c' not *MS.", letter );


	    exit( 1 );





	case 'S':


	    return;





	case '*':


	    break;





	case 'M':


	    pMobIndex		= get_mob_index	( fread_number ( fp ) );


	    pMobIndex->spec_fun	= spec_lookup	( fread_word   ( fp ) );


	    if ( pMobIndex->spec_fun == 0 )


	    {


		bug( "Load_specials: 'M': vnum %d.", pMobIndex->vnum );


		exit( 1 );


	    }


	    break;


	}





	fread_to_eol( fp );


    }


}








/*


 * Translate all room exits from virtual to real.


 * Has to be done after all rooms are read in.


 * Check for bad reverse exits.


 */


void fix_exits( void )


{


    extern const sh_int rev_dir [];


    char buf[MAX_STRING_LENGTH];


    ROOM_INDEX_DATA *pRoomIndex;


    ROOM_INDEX_DATA *to_room;


    EXIT_DATA *pexit;


    EXIT_DATA *pexit_rev;


    int iHash;


    int door;





    for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )


    {


	for ( pRoomIndex  = room_index_hash[iHash];


	      pRoomIndex != NULL;


	      pRoomIndex  = pRoomIndex->next )


	{


	    bool fexit;





	    fexit = FALSE;


	    for ( door = 0; door <= 5; door++ )


	    {


		if ( ( pexit = pRoomIndex->exit[door] ) != NULL )


		{


		    fexit = TRUE;


		    if ( pexit->vnum <= 0 )


			pexit->to_room = NULL;


		    else


			pexit->to_room = get_room_index( pexit->vnum );


		}


	    }





	    if ( !fexit )


		SET_BIT( pRoomIndex->room_flags, ROOM_NO_MOB );


	}


    }





    for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )


    {


	for ( pRoomIndex  = room_index_hash[iHash];


	      pRoomIndex != NULL;


	      pRoomIndex  = pRoomIndex->next )


	{


	    for ( door = 0; door <= 5; door++ )


	    {


		if ( ( pexit     = pRoomIndex->exit[door]       ) != NULL


		&&   ( to_room   = pexit->to_room               ) != NULL


		&&   ( pexit_rev = to_room->exit[rev_dir[door]] ) != NULL


		&&   pexit_rev->to_room != pRoomIndex )


		{


		    sprintf( buf, "Fix_exits: %d:%d -> %d:%d -> %d.",


			pRoomIndex->vnum, door,


			to_room->vnum,    rev_dir[door],


			(pexit_rev->to_room == NULL)


			    ? 0 : pexit_rev->to_room->vnum );


/*		    bug( buf, 0 ); */


		}


	    }


	}


    }





    return;


}











/*


 * Repopulate areas periodically.


 */


void area_update( void )


{


    AREA_DATA *pArea;





    for ( pArea = area_first; pArea != NULL; pArea = pArea->next )


    {


	CHAR_DATA *pch;





	if ( ++pArea->age < 3 )


	    continue;





	/*


	 * Check for PC's.


	 */


	if ( pArea->nplayer > 0 && pArea->age == 15 - 1 )


	{


	    for ( pch = char_list; pch != NULL; pch = pch->next )


	    {


		if ( !IS_NPC(pch)


		&&   IS_AWAKE(pch)


		&&   pch->in_room != NULL


		&&   pch->in_room->area == pArea )


		{


		    send_to_char( "You hear an agonised scream in the distance.\n\r",


			pch );


		}





	    }


	}





	/*


	 * Check age and reset.


	 * Note: Mud School resets every 3 minutes (not 15).


	 */


	if ( pArea->nplayer == 0 || pArea->age >= 15 )


	{


	    ROOM_INDEX_DATA *pRoomIndex;





	    reset_area( pArea );


	    pArea->age = number_range( 0, 3 );


	    pRoomIndex = get_room_index( ROOM_VNUM_SCHOOL );


	    if ( pRoomIndex != NULL && pArea == pRoomIndex->area )


		pArea->age = 15 - 3;


	}


    }





    return;


}



/* OLC
 * Reset one room.  Called by reset_area and olc.
 */
void reset_room( ROOM_INDEX_DATA *pRoom )
{
    RESET_DATA  *pReset;
    CHAR_DATA   *pMob;
    OBJ_DATA    *pObj;
    CHAR_DATA   *LastMob = NULL;
    OBJ_DATA    *LastObj = NULL;
    int iExit;
    int level = 0;
    bool last;
                
    if ( !pRoom )
        return;
   
    pMob        = NULL;
    last        = FALSE;
            
    for ( iExit = 0;  iExit < MAX_DIR;  iExit++ )
    {
        EXIT_DATA *pExit;
        if ( ( pExit = pRoom->exit[iExit] ) )
        {
            pExit->exit_info = pExit->rs_flags;
            if ( ( pExit->to_room != NULL )
              && ( ( pExit = pExit->to_room->exit[rev_dir[iExit]] ) ) )
            {
                /* nail the other side */
                pExit->exit_info = pExit->rs_flags;
            }
        }
    }
    
    for ( pReset = pRoom->reset_first; pReset != NULL; pReset = pReset->next )
    {
        MOB_INDEX_DATA  *pMobIndex;
        OBJ_INDEX_DATA  *pObjIndex;
        OBJ_INDEX_DATA  *pObjToIndex;
        ROOM_INDEX_DATA *pRoomIndex;
   
        switch ( pReset->command )
        {
        default:
                bug( "Reset_room: bad command %c.", pReset->command );
                break;
        
        case 'M':
            if ( !( pMobIndex = get_mob_index( pReset->arg1 ) ) )
            {
                bug( "Reset_room: 'M': bad vnum %d.", pReset->arg1 );
                continue;
            }
             
            /*
             * Some hard coding.
             */
            if ( ( pMobIndex->spec_fun == spec_lookup( "spec_cast_ghost" ) &&
                 ( weather_info.sunlight != SUN_DARK ) ) ) continue;
    
            if ( pMobIndex->count >= pReset->arg2 )
            {
                last = FALSE;
                break;
            }
        
            pMob = create_mobile( pMobIndex );
        
            /*
             * Some more hard coding.
             */
            if ( room_is_dark( pRoom ) )
                SET_BIT(pMob->affected_by, AFF_INFRARED);
        
            /*
             * Pet shop mobiles get ACT_PET set.
             */
            {
                ROOM_INDEX_DATA *pRoomIndexPrev;
             
                pRoomIndexPrev = get_room_index( pRoom->vnum - 1 );
                if ( pRoomIndexPrev
                    && IS_SET( pRoomIndexPrev->room_flags, ROOM_PET_SHOP ) )
                    SET_BIT( pMob->act, ACT_PET);
            }
    
            char_to_room( pMob, pRoom );
             
            LastMob = pMob;  
            level  = URANGE( 0, pMob->level - 2, LEVEL_HERO );
            last = TRUE;
            break;
            
        case 'O':
            if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) )
            {
                bug( "Reset_room: 'O': bad vnum %d.", pReset->arg1 );
                continue;
            }
        
            if ( !( pRoomIndex = get_room_index( pReset->arg3 ) ) )
            {
                bug( "Reset_room: 'O': bad vnum %d.", pReset->arg3 );
                continue;
            }
             
            if ( pRoom->area->nplayer > 0
              || count_obj_list( pObjIndex, pRoom->contents ) > 0 )
                break;
                    
            pObj = create_object( pObjIndex, number_fuzzy( level ) );
            pObj->cost = 0;
            obj_to_room( pObj, pRoom ); 
            break;
            
        case 'P':
            if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) )
            {
                bug( "Reset_room: 'P': bad vnum %d.", pReset->arg1 );
                continue;
            }
            if ( !( pObjToIndex = get_obj_index( pReset->arg3 ) ) )  
            {
                bug( "Reset_room: 'P': bad vnum %d.", pReset->arg3 );
                continue;
            }
             
            if ( pRoom->area->nplayer > 0
              || !( LastObj = get_obj_type( pObjToIndex ) )
              || count_obj_list( pObjIndex, LastObj->contains ) > 0 )
                break;
            
            pObj = create_object( pObjIndex, number_fuzzy( level ) );
            obj_to_obj( pObj, LastObj );
                    
            /*
             * Ensure that the container gets reset.    OLC 1.1b
             */
            if ( LastObj->item_type == ITEM_CONTAINER )
            {
                LastObj->value[1] = LastObj->pIndexData->value[1];
            }
            else
            {
                    /* THIS SPACE INTENTIONALLY LEFT BLANK */
            }
            break;
            
        case 'G':
        case 'E':
            if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) )
            {
                bug( "Reset_room: 'E' or 'G': bad vnum %d.", pReset->arg1 );
                continue;
            }
              
            if ( !last )
                break;
            
            if ( !LastMob )
            {       
                bug( "Reset_room: 'E' or 'G': null mob for vnum %d.",
                    pReset->arg1 );
                last = FALSE;
                break;
            }
                
            if ( LastMob->pIndexData->pShop )   /* Shop-keeper? */
            {   
                int olevel;
                    
                switch ( pObjIndex->item_type )
                { 
                default:                olevel = 0;                      break;
                case ITEM_PILL:         olevel = number_range(  0, 10 ); break;
                case ITEM_POTION:       olevel = number_range(  0, 10 ); break;
                case ITEM_SCROLL:       olevel = number_range(  5, 15 ); break;
                case ITEM_WAND:         olevel = number_range( 10, 20 ); break;
                case ITEM_STAFF:        olevel = number_range( 15, 25 ); break;
                case ITEM_ARMOR:        olevel = number_range(  5, 15 ); break;
                case ITEM_WEAPON:       if ( pReset->command == 'G' )
                                            olevel = number_range( 5, 15 );
                                        else
                                            olevel = number_fuzzy( level );
                  break;
                }
              
		if ( pObjIndex->vnum == 29603 && CHAOS ) return;
		if ( pObjIndex->vnum == 29603 ) CHAOS = TRUE;      

                pObj = create_object( pObjIndex, olevel );
                if ( pReset->command == 'G' )
                    SET_BIT( pObj->extra_flags, ITEM_INVENTORY );
            }
            else
            {   
                pObj = create_object( pObjIndex, number_fuzzy( level ) );
            }   
            obj_to_char( pObj, LastMob );
            if ( pReset->command == 'E' )
                equip_char( LastMob, pObj, pReset->arg3 );
            last = TRUE;
            break;
                
        case 'D':
            break;
                
        case 'R':
/* OLC 1.1b
            if ( !( pRoomIndex = get_room_index( pReset->arg1 ) ) )  
            {
                bug( "Reset_room: 'R': bad vnum %d.", pReset->arg1 );
                continue;
            }
                 
            {       
                EXIT_DATA *pExit;
                int d0;
                int d1;
             
                for ( d0 = 0; d0 < pReset->arg2 - 1; d0++ )
                {
                    d1                   = number_range( d0, pReset->arg2-1 );
                    pExit                = pRoomIndex->exit[d0];
                    pRoomIndex->exit[d0] = pRoomIndex->exit[d1];
                    pRoomIndex->exit[d1] = pExit;
                }
            }
*/
            break;
        }
    }
                
    return;
}


/* OLC
 * Reset one area.
 */
void reset_area( AREA_DATA *pArea )
{
    ROOM_INDEX_DATA *pRoom;
    int  vnum;
             
    for ( vnum = pArea->lvnum; vnum <= pArea->uvnum; vnum++ )
    {
        if ( ( pRoom = get_room_index(vnum) ) )
            reset_room(pRoom);
    }
                    
    return;
}









/*


 * Create an instance of a mobile.


 */


CHAR_DATA *create_mobile( MOB_INDEX_DATA *pMobIndex )


{


    CHAR_DATA *mob;


    int tempvalue;





    if ( pMobIndex == NULL )


    {


	bug( "Create_mobile: NULL pMobIndex.", 0 );


	exit( 1 );


    }





    if ( char_free == NULL )


    {


	mob		= alloc_perm( sizeof(*mob) );


    }


    else


    {


	mob		= char_free;


	char_free	= char_free->next;


    }





    clear_char( mob );


    mob->pIndexData	= pMobIndex;





    mob->hunting	= str_dup( "" );


    mob->lord		= str_dup( "" );


    mob->morph		= str_dup( "" );


    mob->createtime	= str_dup( "" );


    mob->lasttime	= str_dup( "" );


    mob->lasthost	= str_dup( "" );


    mob->powertype	= str_dup( "" );


    mob->poweraction	= str_dup( "" );


    mob->pload		= str_dup( "" );


    mob->prompt		= str_dup( "" );


    mob->cprompt	= str_dup( "" );





    mob->name           = str_dup( pMobIndex->player_name );    /* OLC */
    mob->short_descr    = str_dup( pMobIndex->short_descr );    /* OLC */
    mob->long_descr     = str_dup( pMobIndex->long_descr );     /* OLC */
    mob->description    = str_dup( pMobIndex->description );    /* OLC */



    mob->spec_fun	= pMobIndex->spec_fun;





    mob->home		= 3001;


    mob->form		= 32767;


    mob->level		= number_fuzzy( pMobIndex->level );


    mob->act		= pMobIndex->act;


    mob->affected_by	= pMobIndex->affected_by;


    mob->alignment	= pMobIndex->alignment;


    mob->sex		= pMobIndex->sex;





    mob->armor		= interpolate( mob->level, 100, -100 );





    tempvalue		= mob->level * 8 + number_range(


				mob->level * mob->level / 4,


				mob->level * mob->level );


    if (tempvalue > 100000) mob->max_hit = 100000;


    else mob->max_hit	= tempvalue;





    mob->hit		= mob->max_hit;





    mob->hitroll	= mob->level;


    mob->damroll	= mob->level;


	mob->practice   = mob->level * (number_range(10,20)/10);




     /* Random Forge Objects */

  if (number_percent() < 25)
  {
    if (number_percent() < 2)
    {
	OBJ_DATA *obj;
	obj = create_object( get_obj_index( number_range( 30049,30071 ) ), 0 );
	obj_to_char(obj,mob);
    }
  }
    /*


     * Insert in list.


     */


    mob->next		= char_list;


    char_list		= mob;


    pMobIndex->count++;


    return mob;


}











/*


 * Create an instance of an object.


 */


OBJ_DATA *create_object( OBJ_INDEX_DATA *pObjIndex, int level )


{


    static OBJ_DATA obj_zero;


    OBJ_DATA *obj;





    if ( pObjIndex == NULL )


    {


	bug( "Create_object: NULL pObjIndex.", 0 );


	exit( 1 );


    }





    if ( obj_free == NULL )


    {


	obj		= alloc_perm( sizeof(*obj) );


    }


    else


    {


	obj		= obj_free;


	obj_free	= obj_free->next;


    }





    *obj		= obj_zero;


    obj->pIndexData	= pObjIndex;


    obj->in_room	= NULL;


    obj->level		= level;


    obj->wear_loc	= -1;





    obj->name           = str_dup( pObjIndex->name );           /* OLC */
    obj->short_descr    = str_dup( pObjIndex->short_descr );    /* OLC */
    obj->description    = str_dup( pObjIndex->description );    /* OLC */
 


    if (pObjIndex->chpoweron != NULL)


    {


	obj->chpoweron    = pObjIndex->chpoweron;


	obj->chpoweroff   = pObjIndex->chpoweroff;


	obj->chpoweruse   = pObjIndex->chpoweruse;


	obj->victpoweron  = pObjIndex->victpoweron;


	obj->victpoweroff = pObjIndex->victpoweroff;


	obj->victpoweruse = pObjIndex->victpoweruse;


	obj->spectype     = pObjIndex->spectype;


	obj->specpower    = pObjIndex->specpower;


    }


    else


    {


	obj->chpoweron    = str_dup( "(null)" );


	obj->chpoweroff   = str_dup( "(null)" );


	obj->chpoweruse   = str_dup( "(null)" );


	obj->victpoweron  = str_dup( "(null)" );


	obj->victpoweroff = str_dup( "(null)" );


	obj->victpoweruse = str_dup( "(null)" );


	obj->spectype     = 0;


	obj->specpower    = 0;


    }


    obj->questmaker     = str_dup( "" );


    obj->questowner     = str_dup( "" );





    obj->chobj		= NULL;





    obj->quest		= 0;


    obj->points		= 0;





    obj->item_type	= pObjIndex->item_type;


    obj->extra_flags	= pObjIndex->extra_flags;


    obj->wear_flags	= pObjIndex->wear_flags;


    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->weight		= pObjIndex->weight;


    obj->cost		= number_fuzzy( 10 )


			* number_fuzzy( level ) * number_fuzzy( level );





	if (obj->pIndexData->vnum >= 29600 && obj->pIndexData->vnum <= 29625)


	{


	obj->condition = 100;


	obj->toughness = 100;


	SET_BIT(obj->spectype,SITEM_DROW);


	SET_BIT(obj->quest,QUEST_RELIC);


	} else {





    if (obj->pIndexData->vnum >=  29500 && obj->pIndexData->vnum <= 29599)


    {


	SET_BIT(obj->quest, QUEST_ARTIFACT);


    	obj->condition	= 100;


    	obj->toughness	= 100;


    	obj->resistance	= 1;


	obj->level	= 60;


	obj->cost	= 1000000;


    }


    else if (obj->pIndexData->vnum >= 29666 


             && obj->pIndexData->vnum <= 29679


	     && !IS_SET(obj->spectype, SITEM_PDEMONIC))


	{


    SET_BIT(obj->spectype, SITEM_PDEMONIC);


    SET_BIT(obj->quest, QUEST_RELIC);


        obj->condition  = 100;


        obj->toughness  = 100;


        obj->resistance = 1; 


	}


    else if (obj->pIndexData->vnum >= 27650 && obj->pIndexData->vnum <= 29711)


    {


	SET_BIT(obj->quest, QUEST_RELIC);


    	obj->condition	= 100;


    	obj->toughness	= 100;


    	obj->resistance	= 1;


    }


    else


    {


    	obj->condition	= 100;


    	obj->toughness	= 5;


    	obj->resistance	= 25;


    }


}


    /*


     * Mess with object properties.


     */


    switch ( obj->item_type )


    {


    default:


	bug( "Read_object: vnum %d bad type.", pObjIndex->vnum );


	break;





    case ITEM_LIGHT:


    case ITEM_TREASURE:


    case ITEM_FURNITURE:


    case ITEM_TRASH:


    case ITEM_CONTAINER:


    case ITEM_DRINK_CON:


    case ITEM_KEY:


    case ITEM_FOOD:


    case ITEM_BOAT:


    case ITEM_CORPSE_NPC:


    case ITEM_CORPSE_PC:


    case ITEM_FOUNTAIN:


    case ITEM_PORTAL:


    case ITEM_EGG:


    case ITEM_VOODOO:


    case ITEM_STAKE:


    case ITEM_MISSILE:


    case ITEM_AMMO:


    case ITEM_QUEST:


    case ITEM_QUESTCARD:


    case ITEM_QUESTMACHINE:


    case ITEM_SYMBOL:


    case ITEM_BOOK:


    case ITEM_PAGE:


    case ITEM_TOOL:


    case ITEM_COPPER:


    case ITEM_IRON:


    case ITEM_STEEL:


    case ITEM_ADAMANTITE:


    case ITEM_GEMSTONE:


    case ITEM_HILT:


	break;





    case ITEM_SCROLL:


	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] );


	obj->value[2]	= obj->value[1];


	break;





    case ITEM_WEAPON:


	if (!IS_SET(obj->quest, QUEST_ARTIFACT)


	    && !IS_SET(obj->quest, QUEST_RELIC))


	{


	    obj->value[1]	= number_range( 1, 10 );


	    obj->value[2]	= number_range((obj->value[1]+1),(obj->value[1]*2));


	}


	break;





    case ITEM_ARMOR:


	if (!IS_SET(obj->quest, QUEST_ARTIFACT)


	    && !IS_SET(obj->quest, QUEST_RELIC))


	    obj->value[0]	= number_range( 5, 15 );


	break;





    case ITEM_POTION:


    case ITEM_PILL:


	obj->value[0]	= number_fuzzy( number_fuzzy( obj->value[0] ) );


	break;





    case ITEM_MONEY:


	obj->value[0]	= obj->cost;


	break;


    }





    obj->next		= object_list;


    object_list		= obj;


    pObjIndex->count++;





    return obj;


}











/*


 * Clear a new character.


 */


void clear_char( CHAR_DATA *ch )


{


    static CHAR_DATA ch_zero;





    *ch				= ch_zero;


    ch->name			= &str_empty[0];


    ch->short_descr		= &str_empty[0];


    ch->long_descr		= &str_empty[0];


    ch->description		= &str_empty[0];


    ch->lord			= &str_empty[0];


    ch->morph			= &str_empty[0];


    ch->createtime		= &str_empty[0];


    ch->lasthost		= &str_empty[0];


    ch->lasttime		= &str_empty[0];


    ch->powertype		= &str_empty[0];


    ch->poweraction		= &str_empty[0];


    ch->pload			= &str_empty[0];


    ch->prompt			= &str_empty[0];


    ch->cprompt			= &str_empty[0];


    ch->hunting			= &str_empty[0];





    ch->logon			= current_time;


    ch->armor			= 100;


    ch->position		= POS_STANDING;


    ch->practice		= 0;


    ch->hit			= 1000;


    ch->max_hit			= 1000;


    ch->mana			= 1500;


    ch->max_mana		= 1500;


    ch->move			= 1500;


    ch->max_move		= 1500;


    ch->master			= NULL;


    ch->leader			= NULL;


    ch->fighting		= NULL;


    ch->mount			= NULL;


    ch->wizard			= NULL;


    ch->paradox[0]              = 0;        


    ch->paradox[1]              = 0;        


    ch->paradox[2]              = 0;        


    ch->damcap[0]		= 1000;


    ch->damcap[1]		= 0;


    return;


}











/*


 * Free a character.


 */


void free_char( CHAR_DATA *ch )


{


    OBJ_DATA *obj;


    OBJ_DATA *obj_next;


    AFFECT_DATA *paf;


    AFFECT_DATA *paf_next;





    for ( obj = ch->carrying; obj != NULL; obj = obj_next )


    {


	obj_next = obj->next_content;


	extract_obj( obj );


    }





    for ( paf = ch->affected; paf != NULL; paf = paf_next )


    {


	paf_next = paf->next;


	affect_remove( ch, paf );


    }





    free_string( ch->name		);


    free_string( ch->short_descr	);


    free_string( ch->long_descr		);


    free_string( ch->description	);


    free_string( ch->lord 		);


    free_string( ch->morph 		);


    free_string( ch->createtime 	);


    free_string( ch->lasttime 		);


    free_string( ch->lasthost 		);


    free_string( ch->powertype 		);


    free_string( ch->poweraction 	);


    free_string( ch->pload 		);


    free_string( ch->prompt 		);


    free_string( ch->cprompt 		);


    free_string( ch->hunting		);





    if ( ch->pcdata != NULL )


    {


	free_string( ch->pcdata->pwd		);


	free_string( ch->pcdata->bamfin		);


	free_string( ch->pcdata->bamfout	);


	free_string( ch->pcdata->title		);


	free_string( ch->pcdata->conception	);


	free_string( ch->pcdata->parents	);


	free_string( ch->pcdata->cparents	);


	free_string( ch->pcdata->marriage	);


	free_string( ch->pcdata->email		);


	ch->pcdata->next = pcdata_free;


	pcdata_free      = ch->pcdata;


    }





    ch->next	     = char_free;


    char_free	     = ch;


    return;


}











/*


 * Get an extra description from a list.


 */


char *get_extra_descr( char *name, EXTRA_DESCR_DATA *ed )


{


    for ( ; ed != NULL; ed = ed->next )


    {


	if ( is_name( name, ed->keyword ) )


	    return ed->description;


    }


    return NULL;


}











/*


 * Translates mob virtual number to its mob index struct.


 * Hash table lookup.


 */


MOB_INDEX_DATA *get_mob_index( int vnum )


{


    MOB_INDEX_DATA *pMobIndex;





    for ( pMobIndex  = mob_index_hash[vnum % MAX_KEY_HASH];


	  pMobIndex != NULL;


	  pMobIndex  = pMobIndex->next )


    {


	if ( pMobIndex->vnum == vnum )


	    return pMobIndex;


    }





    if ( fBootDb )


    {


	bug( "Get_mob_index: bad vnum %d.", vnum );


	exit( 1 );


    }





    return NULL;


}











/*


 * Translates mob virtual number to its obj index struct.


 * Hash table lookup.


 */


OBJ_INDEX_DATA *get_obj_index( int vnum )


{


    OBJ_INDEX_DATA *pObjIndex;





    for ( pObjIndex  = obj_index_hash[vnum % MAX_KEY_HASH];


	  pObjIndex != NULL;


	  pObjIndex  = pObjIndex->next )


    {


	if ( pObjIndex->vnum == vnum )


	    return pObjIndex;


    }





    if ( fBootDb )


    {


	bug( "Get_obj_index: bad vnum %d.", vnum );


	exit( 1 );


    }





    return NULL;


}











/*


 * Translates mob virtual number to its room index struct.


 * Hash table lookup.


 */


ROOM_INDEX_DATA *get_room_index( int vnum )


{


    ROOM_INDEX_DATA *pRoomIndex;





    for ( pRoomIndex  = room_index_hash[vnum % MAX_KEY_HASH];


	  pRoomIndex != NULL;


	  pRoomIndex  = pRoomIndex->next )


    {


	if ( pRoomIndex->vnum == vnum )


	    return pRoomIndex;


    }





    if ( fBootDb )


    {


	bug( "Get_room_index: bad vnum %d.", vnum );


	exit( 1 );


    }





    return NULL;


}











/*


 * Read a letter from a file.


 */


char fread_letter( FILE *fp )


{


    char c;





    do


    {


	c = getc( fp );


    }


    while ( isspace(c) );





    return c;


}











/*


 * Read a number from a file.


 */


int fread_number( FILE *fp )


{


    int number;


    bool sign;


    char c;





    do


    {


	c = getc( fp );


    }


    while ( isspace(c) );





    number = 0;





    sign   = FALSE;


    if ( c == '+' )


    {


	c = getc( fp );


    }


    else if ( c == '-' )


    {


	sign = TRUE;


	c = getc( fp );


    }





    if ( !isdigit(c) )


    {


	bug( "Fread_number: bad format.", 0 );


	exit( 1 );


    }





    while ( isdigit(c) )


    {


	number = number * 10 + c - '0';


	c      = getc( fp );


    }





    if ( sign )


	number = 0 - number;





    if ( c == '|' )


	number += fread_number( fp );


    else if ( c != ' ' )


	ungetc( c, fp );





    return number;


}











/*


 * Read and allocate space for a string from a file.


  * These strings are read-only and shared.


 * Strings are hashed:


 *   each string prepended with hash pointer to prev string,


 *   hash code is simply the string length.


 * This function takes 40% to 50% of boot-up time.


 */


char *fread_string( FILE *fp )


{


    char *plast;


    char c;





    plast = top_string + sizeof(char *);


    if ( plast > &string_space[MAX_STRING - MAX_STRING_LENGTH] )


    {


	bug( "Fread_string: MAX_STRING %d exceeded.", MAX_STRING );


	exit( 1 );


    }





    /*


     * Skip blanks.


     * Read first char.


     */


    do


    {


	c = getc( fp );


    }


    while ( isspace(c) );





    if ( ( *plast++ = c ) == '~' )


	return &str_empty[0];


    for ( ;; )


    {


	/*


	 * Back off the char type lookup,


	 *   it was too dirty for portability.


	 *   -- Furey


	 */


	switch ( *plast = getc( fp ) )


	{


	default:


	    plast++;


	    break;





	case EOF:


	    bug( "Fread_string: EOF", 0 );


	    exit( 1 );


	    break;





	case '\n':


	    plast++;


	    *plast++ = '\r';


	    break;





	case '\r':


	    break;





	case '~':


	    plast++;


	    {


		union


		{


		    char *	pc;


		    char	rgc[sizeof(char *)];


		} u1;


		int ic;


		int iHash;


		char *pHash;


		char *pHashPrev;


		char *pString;





		plast[-1] = '\0';


		iHash     = UMIN( MAX_KEY_HASH - 1, plast - 1 - top_string );


		for ( pHash = string_hash[iHash]; pHash; pHash = pHashPrev )


		{


		    for ( ic = 0; ic < sizeof(char *); ic++ )


			u1.rgc[ic] = pHash[ic];


		    pHashPrev = u1.pc;


		    pHash    += sizeof(char *);





		    if ( top_string[sizeof(char *)] == pHash[0]


		    &&   !strcmp( top_string+sizeof(char *)+1, pHash+1 ) )


			return pHash;


		}





		if ( fBootDb )


		{


		    pString		= top_string;


		    top_string		= plast;


		    u1.pc		= string_hash[iHash];


		    for ( ic = 0; ic < sizeof(char *); ic++ )


			pString[ic] = u1.rgc[ic];


		    string_hash[iHash]	= pString;





		    nAllocString += 1;


		    sAllocString += top_string - pString;


		    return pString + sizeof(char *);


		}


		else


		{


		    return str_dup( top_string + sizeof(char *) );


		}


	    }


	}


    }


}











/*


 * Read to end of line (for comments).


 */


void fread_to_eol( FILE *fp )


{


    char c;





    do


    {


	c = getc( fp );


    }


    while ( c != '\n' && c != '\r' );





    do


    {


	c = getc( fp );


    }


    while ( c == '\n' || c == '\r' );





    ungetc( c, fp );


    return;


}











/*


 * Read one word (into static buffer).


 */


char *fread_word( FILE *fp )


{


    static char word[MAX_INPUT_LENGTH];


    char *pword;


    char cEnd;





    do


    {


	cEnd = getc( fp );


    }


    while ( isspace( cEnd ) );





    if ( cEnd == '\'' || cEnd == '"' )


    {


	pword   = word;


    }


    else


    {


	word[0] = cEnd;


	pword   = word+1;


	cEnd    = ' ';


    }





    for ( ; pword < word + MAX_INPUT_LENGTH; pword++ )


    {


	*pword = getc( fp );


	if ( cEnd == ' ' ? isspace(*pword) : *pword == cEnd )


	{


	    if ( cEnd == ' ' )


		ungetc( *pword, fp );


	    *pword = '\0';


	    return word;


	}


    }





    bug( "Fread_word: word too long.", 0 );


    exit( 1 );


    return NULL;


}











/*


 * Allocate some ordinary memory,


 *   with the expectation of freeing it someday.


 */


void *alloc_mem( int sMem )


{


    void *pMem;


    int iList;





    for ( iList = 0; iList < MAX_MEM_LIST; iList++ )


    {


	if ( sMem <= rgSizeList[iList] )


	    break;


    }





    if ( iList == MAX_MEM_LIST )


    {


	bug( "Alloc_mem: size %d too large.", sMem );


	exit( 1 );


    }





    if ( rgFreeList[iList] == NULL )


    {


	pMem		  = alloc_perm( rgSizeList[iList] );


    }


    else


    {


	pMem              = rgFreeList[iList];


	rgFreeList[iList] = * ((void **) rgFreeList[iList]);


    }





    return pMem;


}











/*


 * Free some memory.


 * Recycle it back onto the free list for blocks of that size.


 */


void free_mem( void *pMem, int sMem )


{


    int iList;





    for ( iList = 0; iList < MAX_MEM_LIST; iList++ )


    {


	if ( sMem <= rgSizeList[iList] )


	    break;


    }





    if ( iList == MAX_MEM_LIST )


    {


	bug( "Free_mem: size %d too large.", sMem );


	exit( 1 );


    }





    * ((void **) pMem) = rgFreeList[iList];


    rgFreeList[iList]  = pMem;





    return;


}











/*


 * Allocate some permanent memory.


 * Permanent memory is never freed,


 *   pointers into it may be copied safely.


 */


void *alloc_perm( int sMem )


{


    static char *pMemPerm;


    static int iMemPerm;


    void *pMem;





    while ( sMem % sizeof(long) != 0 )


	sMem++;


    if ( sMem > MAX_PERM_BLOCK )


    {


	bug( "Alloc_perm: %d too large.", sMem );


	exit( 1 );


    }





    if ( pMemPerm == NULL || iMemPerm + sMem > MAX_PERM_BLOCK )


    {


	iMemPerm = 0;


	if ( ( pMemPerm = calloc( 1, MAX_PERM_BLOCK ) ) == NULL )


	{


	    perror( "Alloc_perm" );


	    exit( 1 );


	}


    }





    pMem        = pMemPerm + iMemPerm;


    iMemPerm   += sMem;


    nAllocPerm += 1;


    sAllocPerm += sMem;


    return pMem;


}











/*


 * Duplicate a string into dynamic memory.


 * Fread_strings are read-only and shared.


 */


char *str_dup( const char *str )


{


    char *str_new;





    if ( str[0] == '\0' )


	return &str_empty[0];





    if ( str >= string_space && str < top_string )


	return (char *) str;





    str_new = alloc_mem( strlen(str) + 1 );


    strcpy( str_new, str );


    return str_new;


}











/*


 * Free a string.


 * Null is legal here to simplify callers.


 * Read-only shared strings are not touched.


 */


void free_string( char *pstr )


{


    if ( pstr == NULL


    ||   pstr == &str_empty[0]


    || ( pstr >= string_space && pstr < top_string ) )


	return;





    free_mem( pstr, strlen(pstr) + 1 );


    return;


}













void do_areas( CHAR_DATA *ch, char *argument )


{


    char buf[MAX_STRING_LENGTH];


    AREA_DATA *pArea1;


    AREA_DATA *pArea2;


    int iArea;


    int iAreaHalf;


    WAIT_STATE(ch,10);


    iAreaHalf = (top_area + 1) / 2;


    pArea1    = area_first;


    pArea2    = area_first;


    for ( iArea = 0; iArea < iAreaHalf; iArea++ )


	pArea2 = pArea2->next;





    


   for ( iArea = 0; iArea < iAreaHalf; iArea++ )


    {


	sprintf( buf, "%-39s%-39s\n\r",


	    pArea1->name, (pArea2 != NULL) ? pArea2->name : "" );


	send_to_char( buf, ch );


	pArea1 = pArea1->next;


	if ( pArea2 != NULL )


	    pArea2 = pArea2->next;


    }





    return;


}











void do_memory( CHAR_DATA *ch, char *argument )


{


    char buf[MAX_STRING_LENGTH];





    sprintf( buf, "Affects %5d\n\r", top_affect    ); send_to_char( buf, ch );


    sprintf( buf, "Areas   %5d\n\r", top_area      ); send_to_char( buf, ch );


    sprintf( buf, "RmTxt   %5d\n\r", top_rt        ); send_to_char( buf, ch );


    sprintf( buf, "ExDes   %5d\n\r", top_ed        ); send_to_char( buf, ch );


    sprintf( buf, "Exits   %5d\n\r", top_exit      ); send_to_char( buf, ch );


    sprintf( buf, "Helps   %5d\n\r", top_help      ); send_to_char( buf, ch );


    sprintf( buf, "Mobs    %5d\n\r", top_mob_index ); send_to_char( buf, ch );


    sprintf( buf, "Objs    %5d\n\r", top_obj_index ); send_to_char( buf, ch );


    sprintf( buf, "Resets  %5d\n\r", top_reset     ); send_to_char( buf, ch );


    sprintf( buf, "Rooms   %5d\n\r", top_room      ); send_to_char( buf, ch );


    sprintf( buf, "Shops   %5d\n\r", top_shop      ); send_to_char( buf, ch );





    sprintf( buf, "Strings %5d strings of %7d bytes (max %d).\n\r",


	nAllocString, sAllocString, MAX_STRING );


    send_to_char( buf, ch );





    sprintf( buf, "Perms   %5d blocks  of %7d bytes.\n\r",


	nAllocPerm, sAllocPerm );


    send_to_char( buf, ch );





    return;


}











/*


 * Stick a little fuzz on a number.


 */


int number_fuzzy( int number )


{


    switch ( number_bits( 2 ) )


    {


    case 0:  number -= 1; break;


    case 3:  number += 1; break;


    }





    return UMAX( 1, number );


}











/*


 * Generate a random number.


 */


int number_range( int from, int to )


{


    int power;


    int number;





    if ( ( to = to - from + 1 ) <= 1 )


	return from;





    for ( power = 2; power < to; power <<= 1 )


	;





    while ( ( number = number_mm( ) & (power - 1) ) >= to )


	;





    return from + number;


}











/*


 * Generate a percentile roll.


 */


int number_percent( void )


{


    int percent;





    while ( ( percent = number_mm( ) & (128-1) ) > 99 )


	;





    return 1 + percent;


}











/*


 * Generate a random door.


 */


int number_door( void )


{


    int door;





    while ( ( door = number_mm( ) & (8-1) ) > 5 )


	;





    return door;


}











int number_bits( int width )


{


    return number_mm( ) & ( ( 1 << width ) - 1 );


}











/*


 * I've gotten too many bad reports on OS-supplied random number generators.


 * This is the Mitchell-Moore algorithm from Knuth Volume II.


 * Best to leave the constants alone unless you've read Knuth.


 * -- Furey


 */


static	int	rgiState[2+55];





void init_mm( )


{


    int *piState;


    int iState;





    piState	= &rgiState[2];





    piState[-2]	= 55 - 55;


    piState[-1]	= 55 - 24;





    piState[0]	= ((int) current_time) & ((1 << 30) - 1);


    piState[1]	= 1;


    for ( iState = 2; iState < 55; iState++ )


    {


	piState[iState] = (piState[iState-1] + piState[iState-2])


			& ((1 << 30) - 1);


    }


    return;


}











int number_mm( void )


{


    int *piState;


    int iState1;


    int iState2;


    int iRand;





    piState		= &rgiState[2];


    iState1	 	= piState[-2];


    iState2	 	= piState[-1];


    iRand	 	= (piState[iState1] + piState[iState2])


			& ((1 << 30) - 1);


    piState[iState1]	= iRand;


    if ( ++iState1 == 55 )


	iState1 = 0;


    if ( ++iState2 == 55 )


	iState2 = 0;


    piState[-2]		= iState1;


    piState[-1]		= iState2;


    return iRand >> 6;


}











/*


 * Roll some dice.


 */


int dice( int number, int size )


{


    int idice;


    int sum;





    switch ( size )


    {


    case 0: return 0;


    case 1: return number;


    }





    for ( idice = 0, sum = 0; idice < number; idice++ )


	sum += number_range( 1, size );





    return sum;


}











/*


 * Simple linear interpolation.


 */


int interpolate( int level, int value_00, int value_32 )


{


    return value_00 + level * (value_32 - value_00) / 32;


}











/*


 * Removes the tildes from a string.


 * Used for player-entered strings that go into disk files.


 */


void smash_tilde( char *str )


{


    for ( ; *str != '\0'; str++ )


    {


	if ( *str == '~' )


	    *str = '-';


    }





    return;


}











/*


 * Compare strings, case insensitive.


 * Return TRUE if different


 *   (compatibility with historical functions).


 */


bool str_cmp( const char *astr, const char *bstr )
{
    if ( astr == NULL )
    {
	bug( "Str_cmp: null astr.", 0 );
	return TRUE;
    }

    if ( bstr == NULL )
    {
	bug( "Str_cmp: null bstr.", 0 );
	return TRUE;
    }

    for ( ; *astr || *bstr; astr++, bstr++ )
    {
	if ( LOWER(*astr) != LOWER(*bstr) )
	    return TRUE;
    }

    return FALSE;
}



/*


 * Compare strings, case insensitive, for prefix matching.


 * Return TRUE if astr not a prefix of bstr


 *   (compatibility with historical functions).


 */


bool str_prefix( const char *astr, const char *bstr )


{


    if ( astr == NULL )


    {


	bug( "Strn_cmp: null astr.", 0 );


	return TRUE;


    }





    if ( bstr == NULL )


    {


	bug( "Strn_cmp: null bstr.", 0 );


	return TRUE;


    }





    for ( ; *astr; astr++, bstr++ )


    {


	if ( LOWER(*astr) != LOWER(*bstr) )


	    return TRUE;


    }





    return FALSE;


}











/*


 * Compare strings, case insensitive, for match anywhere.


 * Returns TRUE is astr not part of bstr.


 *   (compatibility with historical functions).


 */


bool str_infix( const char *astr, const char *bstr )


{


    int sstr1;


    int sstr2;


    int ichar;


    char c0;





    if ( ( c0 = LOWER(astr[0]) ) == '\0' )


	return FALSE;





    sstr1 = strlen(astr);


    sstr2 = strlen(bstr);





    for ( ichar = 0; ichar <= sstr2 - sstr1; ichar++ )


    {


	if ( c0 == LOWER(bstr[ichar]) && !str_prefix( astr, bstr + ichar ) )


	    return FALSE;


    }





    return TRUE;


}











/*


 * Compare strings, case insensitive, for suffix matching.


 * Return TRUE if astr not a suffix of bstr


 *   (compatibility with historical functions).


 */


bool str_suffix( const char *astr, const char *bstr )


{


    int sstr1;


    int sstr2;





    sstr1 = strlen(astr);


    sstr2 = strlen(bstr);


    if ( sstr1 <= sstr2 && !str_cmp( astr, bstr + sstr2 - sstr1 ) )


	return FALSE;


    else


	return TRUE;


}











/*


 * Returns an initial-capped string.


 */


char *capitalize( const char *str )


{


    static char strcap[MAX_STRING_LENGTH];


    int i;





    for ( i = 0; str[i] != '\0'; i++ )


	strcap[i] = LOWER(str[i]);


    strcap[i] = '\0';


    strcap[0] = UPPER(strcap[0]);


    return strcap;


}











/*


 * Append a string to a file.


 */


void append_file( CHAR_DATA *ch, char *file, char *str )


{


    FILE *fp;





    if ( IS_NPC(ch) || str[0] == '\0' )


	return;





    fclose( fpReserve );


    if ( ( fp = fopen( file, "a" ) ) == NULL )


    {


	perror( file );


	send_to_char( "Could not open the file!\n\r", ch );


    }


    else


    {


	fprintf( fp, "[%5d] %s: %s\n",


	    ch->in_room ? ch->in_room->vnum : 0, ch->name, str );


	fclose( fp );


    }





    fpReserve = fopen( NULL_FILE, "r" );


    return;


}











/*


 * Reports a bug.


 */


void bug( const char *str, int param )


{


    char buf[MAX_STRING_LENGTH];


    FILE *fp;





    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 );


	}





	sprintf( buf, "[*****] FILE: %s LINE: %d", strArea, iLine );


	log_string( buf );





	if ( ( fp = fopen( "shutdown.txt", "a" ) ) != NULL )


	{


	    fprintf( fp, "[*****] %s\n", buf );


	    fclose( fp );


	}


    }





    strcpy( buf, "[*****] BUG: " );


    sprintf( buf + strlen(buf), str, param );


    log_string( buf );





    fclose( fpReserve );


    if ( ( fp = fopen( BUG_FILE, "a" ) ) != NULL )


    {


	fprintf( fp, "%s\n", buf );


	fclose( fp );


    }


    fpReserve = fopen( NULL_FILE, "r" );





    return;


}











/*


 * Writes a string to the log.


 */


void log_string( const char *str )


{


    char *strtime;


    char logout [MAX_STRING_LENGTH];





    strtime                    = ctime( &current_time );


    strtime[strlen(strtime)-1] = '\0';


    fprintf( stderr, "%s :: %s\n", strtime, str );


    strcpy ( logout, str );


    logchan( logout );


    return;


}













/*


 * This function is here to aid in debugging.


 * If the last expression in a function is another function call,


 *   gcc likes to generate a JMP instead of a CALL.


 * This is called "tail chaining."


 * It hoses the debugger call stack for that call.


 * So I make this the last call in certain critical functions,


 *   where I really need the call stack to be right for debugging!


 *


 * If you don't understand this, then LEAVE IT ALONE.


 * Don't remove any calls to tail_chain anywhere.


 *


 * -- Furey


 */


void tail_chain( void )


{


    return;


}