cm3/
cm3/clans/
cm3/mudprogs/
cm3/player/a/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 * 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{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 *		     Character saving and loading module		    *
 ****************************************************************************/

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#ifndef WIN32
  #include <dirent.h>
#endif
#include "mud.h"


/*
 * Increment with every major format change.
 */
#define SAVEVERSION	4

/*
 * Array to keep track of equipment temporarily.		-Thoric
 */
OBJ_DATA *save_equipment[MAX_WEAR][8];
CHAR_DATA *quitting_char, *loading_char, *saving_char;

int file_ver;

/* handler.c */
MATERIAL_DATA *material_lookup( int number );

extern NATION_DATA *find_nation( char *name );

/*
 * Array of containers read for proper re-nesting of objects.
 */
static	OBJ_DATA *	rgObjNest	[MAX_NEST];

/*
 * Local functions.
 */
void	fwrite_char	args( ( CHAR_DATA *ch, FILE *fp ) );
void	fread_char	args( ( CHAR_DATA *ch, FILE *fp, bool preload) );
void	write_corpses	args( ( CHAR_DATA *ch, char *name, OBJ_DATA *objrem ) );
void    fwrite_alias    args( ( CHAR_DATA *ch, ALIAS_DATA *first_alias, FILE *fp ) );
void    fread_alias     args( ( CHAR_DATA *ch, FILE *fp ) );
void	save_world( CHAR_DATA *ch);
int		get_obj_room_vnum_recursive(OBJ_DATA *obj);


#ifdef WIN32                    /* NJG */
UINT timer_code = 0;            /* needed to kill the timer */
/* Note: need to include: WINMM.LIB to link to timer functions */
void caught_alarm();
void CALLBACK alarm_handler(
	UINT IDEvent,		/* identifies timer event */
	UINT uReserved,		/* not used */
	DWORD dwUser,		/* application-defined instance data */
	DWORD dwReserved1,	/* not used */
	DWORD dwReserved2)	/* not used */
{
    caught_alarm();
}

void kill_timer()
{
    if (timer_code)
	timeKillEvent(timer_code);
    timer_code = 0;
}

#endif



/*
 * Un-equip character before saving to ensure proper	-Thoric
 * stats are saved in case of changes to or removal of EQ
 */
void de_equip_char( CHAR_DATA *ch )
{
    char buf[MAX_STRING_LENGTH];
    OBJ_DATA *obj;
    int x,y;

    for ( x = 0; x < MAX_WEAR; x++ )
	for ( y = 0; y < MAX_LAYERS; y++ )
	    save_equipment[x][y] = NULL;
    for ( obj = ch->first_carrying; obj; obj = obj->next_content )
	if ( obj->wear_loc > -1 && obj->wear_loc < MAX_WEAR )
	{
		for ( x = 0; x < MAX_LAYERS; x++ )
		   if ( !save_equipment[obj->wear_loc][x] )
		   {
			save_equipment[obj->wear_loc][x] = obj;
			break;
		   }
		if ( x == MAX_LAYERS )
		{
		    sprintf( buf, "%s had on more than %d layers of clothing in one location (%d): %s",
			ch->name, MAX_LAYERS, obj->wear_loc, obj->name );
		    bug( buf, 0 );
		}
	    unequip_char(ch, obj);
	}
}

/*
 * Re-equip character					-Thoric
 */
void re_equip_char( CHAR_DATA *ch )
{
    int x,y;

    for ( x = 0; x < MAX_WEAR; x++ )
	for ( y = 0; y < MAX_LAYERS; y++ )
	   if ( save_equipment[x][y] != NULL )
	   {
		if ( quitting_char != ch )
		   equip_char(ch, save_equipment[x][y]);
		save_equipment[x][y] = NULL;
	   }
	   else
		break;
}


/*
 * Save a character and inventory.
 * Would be cool to save NPC's too for quest purposes,
 *   some of the infrastructure is provided.
 */
void save_char_obj( CHAR_DATA *ch )
{
    char strsave[MAX_INPUT_LENGTH];
    char strback[MAX_INPUT_LENGTH];
    FILE *fp;

    if ( !ch )
    {
	bug( "Save_char_obj: null ch!", 0 );
	return;
    }

    if ( IS_NPC(ch) )
	return;

    saving_char = ch;

    if ( ch->desc && ch->desc->original )
	ch = ch->desc->original;

    de_equip_char( ch );

    ch->save_time = current_time;
    sprintf( strsave, "%s%c/%s",PLAYER_DIR,tolower(ch->pcdata->filename[0]),
				 capitalize( ch->pcdata->filename ) );

    /*
     * Auto-backup pfile (can cause lag with high disk access situtations).
     */
    /* Backup of each pfile on save as above can cause lag in high disk
       access situations on big muds like Realms.  Quitbackup saves most
       of that and keeps an adequate backup -- Blodkai, 10/97 */

    if ( IS_SET( sysdata.save_flags, SV_BACKUP ) || 
       ( IS_SET( sysdata.save_flags, SV_QUITBACKUP ) && quitting_char == ch ))
    {
        sprintf( strback,"%s%c/%s",BACKUP_DIR,tolower(ch->pcdata->filename[0]), capitalize( ch->pcdata->filename ) );
        rename( strsave, strback );
    }

    if ( ( fp = fopen( strsave, "w" ) ) == NULL )
    {
	bug( "Save_char_obj: fopen", 0 );
	perror( strsave );
    }
    else
    {
	fwrite_char( ch, fp );
	if ( ch->first_carrying )
	  fwrite_obj( ch, ch->last_carrying, fp, 0, OS_CARRY );
        if ( !IS_NPC( ch ) && ch->pcdata->first_alias )
          fwrite_alias( ch, ch->pcdata->first_alias, fp );

	if ( sysdata.save_pets && ch->pcdata->pet )
		fwrite_mobile( fp, ch->pcdata->pet );
	fprintf( fp, "#END\n" );
	fclose( fp );
    }

    re_equip_char( ch );

    quitting_char = NULL;
    saving_char   = NULL;
    return;
}



/*
 * Write the char.
 */
void fwrite_char( CHAR_DATA *ch, FILE *fp )
{
    PART_DATA *part;
    EXPLORED_AREA *xarea;
    AFFECT_DATA *paf;
    int i, sn;
    sh_int pos;
    SKILLTYPE *skill = NULL;

    fprintf( fp, "#PLAYER\n"		);

    fprintf( fp, "Version      %d\n",   SAVEVERSION		);
    fprintf( fp, "Name         %s~\n",	ch->name		);
    if ( ch->description )
      fprintf( fp, "Description  %s~\n",	ch->description	);
    fprintf( fp, "Sex          %d\n",	ch->sex			);
    fprintf( fp, "Race         %d\n",	ch->race		);
    fprintf( fp, "Permissions	%d\n", ch->pcdata->permissions);
    fprintf( fp, "Points		%d\n", ch->pcdata->points );
	
	for (i=0; i < MAX_DEITY; i++) {
		if (ch->talent[i] > -1)
			fprintf(fp, "Talent		%d %d %d\n", i, ch->talent[i], ch->curr_talent[i]);
	}
	
	fprintf( fp, "Played       %d\n",
	ch->played + (int) (current_time - ch->logon)		);
    fprintf( fp, "Room         %d\n",
	(  ch->in_room == get_room_index( ROOM_VNUM_LIMBO )
	&& ch->was_in_room )
	    ? ch->was_in_room->vnum
	    : ch->in_room->vnum );

    fprintf( fp, "Memorized		%d %d %d %d %d %d %d %d\n",
		ch->pcdata->memorize[0],
		ch->pcdata->memorize[1],
		ch->pcdata->memorize[2],
		ch->pcdata->memorize[3],
		ch->pcdata->memorize[4],
		ch->pcdata->memorize[5],
		ch->pcdata->memorize[6],
		ch->pcdata->memorize[7] );
    fprintf( fp, "HpManaMove   %d %d %d %d %d %d\n",
	ch->hit, ch->max_hit, ch->mana, ch->max_mana, ch->move, ch->max_move );
    fprintf( fp, "Gold         %ld\n",	ch->gold		);
	fprintf( fp, "Bank         %ld\n",	ch->pcdata->balance);
	if (xIS_SET(ch->act, PLR_BOUNTY))
		fprintf( fp, "Bounty	   %d\n",	ch->pcdata->bounty);
    fprintf( fp, "Exp          %d\n",	ch->exp			);
    fprintf( fp, "Height          %d\n",	ch->height	);
    fprintf( fp, "Weight          %d\n",	ch->weight	);
    if ( !xIS_EMPTY(ch->act) )
      fprintf( fp, "Act          %s\n", print_bitvector(&ch->act) );
    if ( !xIS_EMPTY(ch->affected_by) )
      fprintf( fp, "AffectedBy   %s\n",	print_bitvector(&ch->affected_by) );
    if ( !xIS_EMPTY(ch->no_affected_by) )
      fprintf( fp, "NoAffectedBy %s\n",	print_bitvector(&ch->no_affected_by) );
    if ( !xIS_EMPTY(ch->pcdata->perm_aff) )
      fprintf( fp, "PermAffects	%s\n",print_bitvector(&ch->pcdata->perm_aff));

    /*
     * Strip off fighting positions & store as
     * new style (pos>=100 flags new style in character loading)
     */
    pos = ch->position;
    pos +=100;
    fprintf( fp, "Position     %d\n", pos);

    fprintf( fp, "SavingThrows %d %d %d %d %d\n",
    		  ch->saving_poison_death,
		  ch->saving_wand,
    		  ch->saving_para_petri,
    		  ch->saving_breath,
    		  ch->saving_spell_staff			);
    fprintf( fp, "Hitroll      %d\n",	ch->hitroll		);
    fprintf( fp, "Damroll      %d\n",	ch->damroll		);
    fprintf( fp, "Armor        %d\n",	ch->armor		);
    if ( ch->wimpy )
      fprintf( fp, "Wimpy        %d\n",	ch->wimpy		);
    if ( ch->resistant )
      fprintf( fp, "Resistant    %d\n",	ch->resistant		);
    if ( ch->no_resistant )
      fprintf( fp, "NoResistant  %d\n",	ch->no_resistant	);
    if ( ch->immune )
      fprintf( fp, "Immune       %d\n",	ch->immune		);
    if ( ch->no_immune )
      fprintf( fp, "NoImmune     %d\n",	ch->no_immune		);
    if ( ch->susceptible )
      fprintf( fp, "Susceptible  %d\n",	ch->susceptible		);
    if ( ch->no_susceptible )
      fprintf( fp, "NoSusceptible  %d\n",ch->no_susceptible	);
    if ( ch->mental_state != -10 )
      fprintf( fp, "Mentalstate  %d\n",	ch->mental_state	);

        fprintf( fp, "Password     %s~\n",	ch->pcdata->pwd		);
	if ( ch->pcdata->rank && ch->pcdata->rank[0] != '\0' )
	  fprintf( fp, "Rank         %s~\n",	ch->pcdata->rank	);
	fprintf( fp, "Title        %s~\n",	ch->pcdata->title	);
	if ( ch->pcdata->homepage && ch->pcdata->homepage[0] != '\0' )
	  fprintf( fp, "Homepage     %s~\n",	ch->pcdata->homepage	);
	if ( ch->pcdata->bio && ch->pcdata->bio[0] != '\0' )
	  fprintf( fp, "Bio          %s~\n",	ch->pcdata->bio 	);
          if ( ch->pcdata && ch->pcdata->restore_time )
            fprintf( fp, "Restore_time %ld\n",ch->pcdata->restore_time );
          fprintf( fp, "WizInvis     %d\n", ch->pcdata->wizinvis );
	if ( ch->pcdata->prompt && *ch->pcdata->prompt )
	  fprintf( fp, "Prompt       %s~\n",	ch->pcdata->prompt	);
 	if ( ch->pcdata->fprompt && *ch->pcdata->fprompt )
	  fprintf( fp, "FPrompt	     %s~\n",    ch->pcdata->fprompt	);
	if ( ch->pcdata->pagerlen != 24 )
	  fprintf( fp, "Pagerlen     %d\n",	ch->pcdata->pagerlen	);
 	for ( pos = 0; pos < MAX_ALIAS ; pos++ ) /* alias - shogar */
	{
 		if ( !ch->pcdata->alias[pos]
 		||   !ch->pcdata->alias_sub[pos] )
			break;
 		fprintf( fp, "Alias %s %s~\n", ch->pcdata->alias[pos],
 					      ch->pcdata->alias_sub[pos] );
	}
	  
	if (IS_SET(ch->pcdata->permissions, PERMIT_BUILD))
	{
	  if ( ch->pcdata->bamfin && ch->pcdata->bamfin[0] != '\0' )
	    fprintf( fp, "Bamfin       %s~\n",	ch->pcdata->bamfin	);
	  if ( ch->pcdata->bamfout && ch->pcdata->bamfout[0] != '\0' )
	    fprintf( fp, "Bamfout      %s~\n",	ch->pcdata->bamfout	);
	  if ( ch->pcdata->r_range_lo && ch->pcdata->r_range_hi )
	    fprintf( fp, "RoomRange    %d %d\n", ch->pcdata->r_range_lo,
	  					 ch->pcdata->r_range_hi	);
	  if ( ch->pcdata->o_range_lo && ch->pcdata->o_range_hi )
	    fprintf( fp, "ObjRange     %d %d\n", ch->pcdata->o_range_lo,
	  					 ch->pcdata->o_range_hi	);
	  if ( ch->pcdata->m_range_lo && ch->pcdata->m_range_hi )
	    fprintf( fp, "MobRange     %d %d\n", ch->pcdata->m_range_lo,
	  					 ch->pcdata->m_range_hi	);
	}
        if ( ch->pcdata->deity_name && ch->pcdata->deity_name[0] != '\0' )
	  fprintf( fp, "Deity	     %s~\n",	ch->pcdata->deity_name	 );
        fprintf( fp, "Flags        %d\n",	ch->pcdata->flags	);
        if ( ch->pcdata->release_date > current_time )
            fprintf( fp, "Helled       %d %s~\n",
        	(int)ch->pcdata->release_date, ch->pcdata->helled_by );
	fprintf( fp, "PKills       %d\n",	ch->pcdata->pkills	);
	fprintf( fp, "PDeaths      %d\n",	ch->pcdata->pdeaths	);
	fprintf( fp, "RKills	   %d\n",	ch->pcdata->rkills	);
	fprintf( fp, "RDeaths	   %d\n",	ch->pcdata->rdeaths	); 
	if ( get_timer( ch , TIMER_PKILLED)       
         && ( get_timer( ch , TIMER_PKILLED) > 0 ) )
         fprintf( fp, "PTimer       %d\n",     get_timer(ch, TIMER_PKILLED));
        fprintf( fp, "MKills       %d\n",	ch->pcdata->mkills	);
	fprintf( fp, "MDeaths      %d\n",	ch->pcdata->mdeaths	);
	fprintf( fp, "AttrPerm     %d %d %d %d %d %d %d\n",
	    ch->perm_str,
	    ch->perm_int,
	    ch->perm_wis,
	    ch->perm_dex,
	    ch->perm_con,
	    ch->perm_cha,
	    ch->perm_lck );

	fprintf( fp, "AttrMod      %d %d %d %d %d %d %d\n",
	    ch->mod_str, 
	    ch->mod_int, 
	    ch->mod_wis,
	    ch->mod_dex, 
	    ch->mod_con,
	    ch->mod_cha, 
	    ch->mod_lck );

	fprintf( fp, "Weapons	%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
	    ch->pcdata->weapon[0],
            ch->pcdata->weapon[1],
            ch->pcdata->weapon[2],
            ch->pcdata->weapon[3],
            ch->pcdata->weapon[4],
            ch->pcdata->weapon[5],
            ch->pcdata->weapon[6],
            ch->pcdata->weapon[7],
            ch->pcdata->weapon[8],
            ch->pcdata->weapon[9],
            ch->pcdata->weapon[10],
            ch->pcdata->weapon[11],
            ch->pcdata->weapon[12],
            ch->pcdata->weapon[13],
            ch->pcdata->weapon[14],
            ch->pcdata->weapon[15],
            ch->pcdata->weapon[16],
            ch->pcdata->weapon[17],
            ch->pcdata->weapon[18],
            ch->pcdata->weapon[19] );

	fprintf( fp, "WeaponExp	%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
	    ch->pcdata->weapon_exp[0],
            ch->pcdata->weapon_exp[1],
            ch->pcdata->weapon_exp[2],
            ch->pcdata->weapon_exp[3],
            ch->pcdata->weapon_exp[4],
            ch->pcdata->weapon_exp[5],
            ch->pcdata->weapon_exp[6],
            ch->pcdata->weapon_exp[7],
            ch->pcdata->weapon_exp[8],
            ch->pcdata->weapon_exp[9],
            ch->pcdata->weapon_exp[10],
            ch->pcdata->weapon_exp[11],
            ch->pcdata->weapon_exp[12],
            ch->pcdata->weapon_exp[13],
            ch->pcdata->weapon_exp[14],
            ch->pcdata->weapon_exp[15],
            ch->pcdata->weapon_exp[16],
            ch->pcdata->weapon_exp[17],
            ch->pcdata->weapon_exp[18],
            ch->pcdata->weapon_exp[19] );

	fprintf( fp, "TalentExp	%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
	    ch->pcdata->talent_exp[0],
            ch->pcdata->talent_exp[1],
            ch->pcdata->talent_exp[2],
            ch->pcdata->talent_exp[3],
            ch->pcdata->talent_exp[4],
            ch->pcdata->talent_exp[5],
            ch->pcdata->talent_exp[6],
            ch->pcdata->talent_exp[7],
            ch->pcdata->talent_exp[8],
            ch->pcdata->talent_exp[9],
            ch->pcdata->talent_exp[10],
            ch->pcdata->talent_exp[11],
            ch->pcdata->talent_exp[12],
            ch->pcdata->talent_exp[13],
            ch->pcdata->talent_exp[14],
            ch->pcdata->talent_exp[15],
            ch->pcdata->talent_exp[16],
            ch->pcdata->talent_exp[17],
            ch->pcdata->talent_exp[18] );

	fprintf( fp, "Noncombat	%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
	    ch->pcdata->noncombat[0],
            ch->pcdata->noncombat[1],
            ch->pcdata->noncombat[2],
            ch->pcdata->noncombat[3],
            ch->pcdata->noncombat[4],
            ch->pcdata->noncombat[5],
            ch->pcdata->noncombat[6],
            ch->pcdata->noncombat[7],
            ch->pcdata->noncombat[8],
            ch->pcdata->noncombat[9],
            ch->pcdata->noncombat[10],
            ch->pcdata->noncombat[11],
            ch->pcdata->noncombat[12],
            ch->pcdata->noncombat[13],
            ch->pcdata->noncombat[14],
            ch->pcdata->noncombat[15],
            ch->pcdata->noncombat[16],
            ch->pcdata->noncombat[17],
            ch->pcdata->noncombat[18],
            ch->pcdata->noncombat[19] );

	fprintf( fp, "NoncombatExp	%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
	    ch->pcdata->noncombat_exp[0],
            ch->pcdata->noncombat_exp[1],
            ch->pcdata->noncombat_exp[2],
            ch->pcdata->noncombat_exp[3],
            ch->pcdata->noncombat_exp[4],
            ch->pcdata->noncombat_exp[5],
            ch->pcdata->noncombat_exp[6],
            ch->pcdata->noncombat_exp[7],
            ch->pcdata->noncombat_exp[8],
            ch->pcdata->noncombat_exp[9],
            ch->pcdata->noncombat_exp[10],
            ch->pcdata->noncombat_exp[11],
            ch->pcdata->noncombat_exp[12],
            ch->pcdata->noncombat_exp[13],
            ch->pcdata->noncombat_exp[14],
            ch->pcdata->noncombat_exp[15],
            ch->pcdata->noncombat_exp[16],
            ch->pcdata->noncombat_exp[17],
            ch->pcdata->noncombat_exp[18],
            ch->pcdata->noncombat_exp[19] );

	fprintf( fp, "Condition    %d %d %d %d\n",
	    ch->pcdata->condition[0],
	    ch->pcdata->condition[1],
	    ch->pcdata->condition[2],
	    ch->pcdata->condition[3] );
	if ( ch->desc && ch->desc->host )
            fprintf( fp, "Site         %s\n", ch->desc->host );
	else
            fprintf( fp, "Site         (Link-Dead)\n" );

	xarea = ch->pcdata->first_explored;
	while (xarea) {
		fprintf( fp, "Explored	%d %s\n",
		xarea->index,
		print_bitvector(&xarea->rooms));
		xarea = xarea->next;
	}
	
	part = ch->first_part;
	while (part) {
	    if (part->cond != PART_WELL || part->flags != PART_WELL)
		fprintf(fp, "Part	%d %d %d\n",
		part->loc,
		part->cond,
		part->flags);
		part = part->next;
	}

	for ( sn = 1; sn < top_sn; sn++ )
	{
	    if ( skill_table[sn]->name && ch->pcdata->learned[sn] > 0 )
		switch( skill_table[sn]->type )
		{
		    default:
			fprintf( fp, "Skill        %d '%s'\n",
			  ch->pcdata->learned[sn], skill_table[sn]->name);
			break;
		    case SKILL_SPELL:
			fprintf( fp, "Spell        %d '%s'\n",
			  ch->pcdata->learned[sn], skill_table[sn]->name);
			break;
		}
	}

    for ( paf = ch->first_affect; paf; paf = paf->next )
    {
	if ( paf->type >= 0 && (skill=get_skilltype(paf->type)) == NULL )
	    continue;

	if ( paf->type >= 0 && paf->type < TYPE_RACIAL )
	  fprintf( fp, "AffectData   '%s' %3d %3d %3d %s\n",
	    skill->name,
	    paf->duration,
	    paf->modifier,
	    paf->location,
	    print_bitvector(&paf->bitvector)
	    );
	else
	  fprintf( fp, "Affect       %3d %3d %3d %3d %s\n",
	    paf->type,
	    paf->duration,
	    paf->modifier,
	    paf->location,
	    print_bitvector(&paf->bitvector)
	    );
    }

	if (ch->pcdata->first_qbit) {
		BIT_DATA *bit;

		for (bit = ch->pcdata->first_qbit; bit; bit = bit->next)
			fprintf(fp, "Qbit	%d %s~\n", bit->number, bit->desc);
	}

	if (ch->species)
		fprintf(fp, "Species	%s~\n", ch->species);
	if (ch->pcdata->type)
		fprintf(fp, "Type	%s~\n", ch->pcdata->type);
	if (ch->pcdata->parent)
		fprintf(fp, "Parent	%s~\n", ch->pcdata->parent);
	if (ch->pcdata->family)
		fprintf(fp, "Family	%s~\n", ch->pcdata->family);
	fprintf(fp, "Generation	%d\n", ch->pcdata->gen);
        fprintf(fp, "Age	%d\n", ch->pcdata->age_adjust);	
	fprintf(fp, "Shield	%d\n", ch->shield);
	if (ch->pcdata->spouse)
		fprintf(fp, "Spouse	%s~\n", ch->pcdata->spouse);
	if (ch->pcdata->maiden_name)
		fprintf(fp, "Maiden	%s~\n", ch->pcdata->maiden_name);

	if (ch->pcdata->name_disguise)
		fprintf(fp, "Ndisguise	%s~\n", ch->pcdata->name_disguise);
	if (ch->pcdata->were_race)
		fprintf(fp, "Wererace	%s~\n", ch->pcdata->were_race);
	if (ch->pcdata->auto_attack)
		fprintf(fp, "AutoAttack	%s~\n", ch->pcdata->auto_attack);
	fprintf(fp, "Speed	%d\n", ch->speed);
	fprintf(fp, "Inborn	%d\n", ch->pcdata->inborn);
	fprintf(fp, "Channels	%s~\n", ch->pcdata->channels);
	if (ch->pcdata->outputprefix)
		fprintf(fp, "Outputprefix %s~\n", ch->pcdata->outputprefix);
	if (ch->pcdata->outputsuffix)
		fprintf(fp, "Outputsuffix %s~\n", ch->pcdata->outputsuffix);
	if (ch->pcdata->eyes)
		fprintf(fp, "Eyes	%s~\n", ch->pcdata->eyes);
	if (ch->pcdata->hair)
		fprintf(fp, "Hair	%s~\n", ch->pcdata->hair);
	if (ch->pcdata->skin_color)
		fprintf(fp, "Skin_color	%s~\n", ch->pcdata->skin_color);
	if (ch->pcdata->skin_type)
		fprintf(fp, "Skin_type	%s~\n", ch->pcdata->skin_type);
	if (ch->pcdata->extra_color)
		fprintf(fp, "Extra_color	%s~\n", ch->pcdata->extra_color);
	if (ch->pcdata->extra_type)
		fprintf(fp, "Extra_type	%s~\n", ch->pcdata->extra_type);

#ifdef I3
    i3save_char( ch, fp );
#endif
#ifdef IMC
    imc_savechar( ch, fp );
#endif

    fprintf( fp, "End\n\n" );
    return;
}



/*
 * Write an object and its contents.
 */
void fwrite_obj( CHAR_DATA *ch, OBJ_DATA *obj, FILE *fp, int iNest,
		 sh_int os_type )
{
    EXTRA_DESCR_DATA *ed;
    AFFECT_DATA *paf;
    sh_int wear, wear_loc, x;

    if ( iNest >= MAX_NEST )
    {
	bug( "fwrite_obj: iNest hit MAX_NEST %d", iNest );
	return;
    }

	/*
     * Slick recursion to write lists backwards,
     *   so loading them will load in forwards order.
     */
    if ( obj->prev_content && os_type != OS_GEM )
	if (os_type==OS_CARRY)
		fwrite_obj( ch, obj->prev_content, fp, iNest, OS_CARRY );

    /*
     * Castrate storage characters.
     * Catch deleted objects                                    -Thoric
     * Do NOT save prototype items!				-Thoric
     */
    if ( obj_extracted(obj) 
    ||   IS_OBJ_STAT( obj, ITEM_PROTOTYPE ) )
	return;

    /* Gem saving -Keolah */
    fprintf( fp, (os_type == OS_GEM ? "#GEM\n" : "#OBJECT\n") );

    if ( iNest )
	fprintf( fp, "Nest         %d\n",	iNest		     );
    if ( obj->count > 1 )
	fprintf( fp, "Count        %d\n",	obj->count	     );
    if ( QUICKMATCH( obj->name, obj->pIndexData->name ) == 0 )
	fprintf( fp, "Name         %s~\n",	obj->name	     );
    if ( QUICKMATCH( obj->short_descr, obj->pIndexData->short_descr ) == 0 )
	fprintf( fp, "ShortDescr   %s~\n",	obj->short_descr     );
    if ( QUICKMATCH( obj->description, obj->pIndexData->description ) == 0 )
	fprintf( fp, "Description  %s~\n",	obj->description     );
	if (obj->obj_by != NULL)
		fprintf(fp, "ObjBy	%s~\n", obj->obj_by);
    if ( QUICKMATCH( obj->action_desc, obj->pIndexData->action_desc ) == 0 )
	fprintf( fp, "ActionDesc   %s~\n",	obj->action_desc     );
    fprintf( fp, "Vnum         %d\n",	obj->pIndexData->vnum	     );
    if (obj->material != NULL)
		fprintf( fp, "Material	%d\n", obj->material->number );
	if (os_type == OS_GROUND && obj->in_room )
      fprintf( fp, "Room         %d\n",   obj->in_room->vnum         );
/*    else if (((IS_OBJ_STAT(obj, ITEM_ARTIFACT)) || (IS_OBJ_STAT(obj, ITEM_PLRBLD))) && !obj->in_room)
		fprintf( fp, "Room		%d\n",  get_obj_room_vnum_recursive(obj));
*/	if ( !xSAME_BITS(obj->extra_flags, obj->pIndexData->extra_flags) )
	fprintf( fp, "ExtraFlags   %s\n",	print_bitvector(&obj->extra_flags) );
    wear_loc = -1;
    for ( wear = 0; wear < MAX_WEAR; wear++ )
	for ( x = 0; x < MAX_LAYERS; x++ )
	   if ( obj == save_equipment[wear][x] )
	   {
		wear_loc = wear;
		break;
	   }
	   else
	   if ( !save_equipment[wear][x] )
		break;
    if ( wear_loc != -1 )
	fprintf( fp, "WearLoc      %d\n",	wear_loc	     );
    if ( obj->item_type != obj->pIndexData->item_type )
	fprintf( fp, "ItemType     %d\n",	obj->item_type	     );
	if ( obj->weight != obj->pIndexData->weight )
      fprintf( fp, "Weight       %d\n",	obj->weight		     );
	fprintf( fp, "Condition	%d\n", obj->condition	);
    if (obj->size && !xIS_EMPTY(obj->parts))
	fprintf( fp, "Size	%d\n", obj->size	);
    if ( obj->mana )
      fprintf( fp, "Mana        %d\n", obj->mana);
	if (obj->raw_mana)
      fprintf( fp, "RawMana     %d\n", obj->raw_mana);
	if (obj->timer)
      fprintf( fp, "Timer        %d\n",	obj->timer		     );
    if ( obj->cost != obj->pIndexData->cost )
      fprintf( fp, "Cost         %d\n",	obj->cost		     );
    if ( obj->value[0] || obj->value[1] || obj->value[2]
    ||   obj->value[3] || obj->value[4] || obj->value[5]
    || obj->value[6] )
      fprintf( fp, "Values       %d %d %d %d %d %d %d\n",
	obj->value[0], obj->value[1], obj->value[2],
	obj->value[3], obj->value[4], obj->value[5], obj->value[6]     );

    switch ( obj->item_type )
    {
    case ITEM_PILL: /* was down there with staff and wand, wrongly - Scryn */
    case ITEM_POTION:
    case ITEM_SCROLL:
	if ( IS_VALID_SN(obj->value[1]) )
	    fprintf( fp, "Spell 1      '%s'\n",
		skill_table[obj->value[1]]->name );

	if ( IS_VALID_SN(obj->value[2]) )
	    fprintf( fp, "Spell 2      '%s'\n",
		skill_table[obj->value[2]]->name );

	if ( IS_VALID_SN(obj->value[3]) )
	    fprintf( fp, "Spell 3      '%s'\n",
		skill_table[obj->value[3]]->name );

	break;

    case ITEM_STAFF:
    case ITEM_WAND:
	if ( IS_VALID_SN(obj->value[3]) )
	    fprintf( fp, "Spell 3      '%s'\n",
		skill_table[obj->value[3]]->name );

	break;
    case ITEM_SALVE:
	if ( IS_VALID_SN(obj->value[4]) )
	    fprintf( fp, "Spell 4      '%s'\n",
		skill_table[obj->value[4]]->name );

	if ( IS_VALID_SN(obj->value[5]) )
	    fprintf( fp, "Spell 5      '%s'\n",
		skill_table[obj->value[5]]->name );
	break;
    }

    for ( paf = obj->first_affect; paf; paf = paf->next )
    {
	/*
	 * Save extra object affects				-Thoric
	 */
	if ( paf->type < 0 || paf->type >= top_sn )
	{
	  fprintf( fp, "Affect       %d %d %d %d %s\n",
	    paf->type,
	    paf->duration,
	     ((paf->location == APPLY_WEAPONSPELL
	    || paf->location == APPLY_WEARSPELL
	    || paf->location == APPLY_REMOVESPELL
	    || paf->location == APPLY_STRIPSN
	    || paf->location == APPLY_RECURRINGSPELL)
	    && IS_VALID_SN(paf->modifier))
	    ? skill_table[paf->modifier]->slot : paf->modifier,
	    paf->location,
	    print_bitvector(&paf->bitvector)
	    );
	}
	else
	  fprintf( fp, "AffectData   '%s' %d %d %d %s\n",
	    skill_table[paf->type]->name,
	    paf->duration,
	     ((paf->location == APPLY_WEAPONSPELL
	    || paf->location == APPLY_WEARSPELL
	    || paf->location == APPLY_REMOVESPELL
	    || paf->location == APPLY_STRIPSN
	    || paf->location == APPLY_RECURRINGSPELL)
	    && IS_VALID_SN(paf->modifier))
	    ? skill_table[paf->modifier]->slot : paf->modifier,
	    paf->location,
	    print_bitvector(&paf->bitvector)
	    );
    }

    for ( ed = obj->first_extradesc; ed; ed = ed->next )
	fprintf( fp, "ExtraDescr   %s~ %s~\n",
	    ed->keyword, ed->description );

    fprintf( fp, "End\n\n" );

	/* If we want multiple gems on an item,
	 * will need to change them to a linked list or
	 * something. One gem is plenty for me though. -keo
	 */
    if ( obj->gem && obj->name )
	fwrite_obj( ch, obj->gem, fp, iNest+1, OS_GEM );

    if ( obj->first_content )
	fwrite_obj( ch, obj->last_content, fp, iNest + 1, OS_CARRY );

    return;
}

void fwrite_alias( CHAR_DATA *ch, ALIAS_DATA *first_alias, FILE *fp )
{
    ALIAS_DATA *alias;

    for ( alias = first_alias; alias; alias = alias->next )
    {
        fprintf( fp, "#ALIAS\n" );
        fprintf( fp, "Name     %s~\n", alias->name  );
        fprintf( fp, "Commands %s~\n", alias->alias );
        fprintf( fp, "End\n\n" );
    }
    return;
}

/*
 * Load a char and inventory into a new ch structure.
 */
bool load_char_obj( DESCRIPTOR_DATA *d, char *name, bool preload )
{
    char strsave[MAX_INPUT_LENGTH];
    CHAR_DATA *ch;
    FILE *fp;
    bool found;
    struct stat fst;
    int i, x;
    extern FILE *fpArea;
    extern char strArea[MAX_INPUT_LENGTH];
    char buf[MAX_INPUT_LENGTH];

    CREATE( ch, CHAR_DATA, 1 );
    for ( x = 0; x < MAX_WEAR; x++ )
	for ( i = 0; i < MAX_LAYERS; i++ )
	    save_equipment[x][i] = NULL;
    clear_char( ch );
    loading_char = ch;

    CREATE( ch->pcdata, PC_DATA, 1 );
    d->character		= ch;
    ch->desc			= d;
    ch->pcdata->filename	= STRALLOC( name );
    ch->name			= NULL;
    ch->act			= multimeb(PLR_BLANK, PLR_COMBINE, PLR_PROMPT, -1);
    ch->perm_str		= 100;
    ch->perm_int		= 100;
    ch->perm_wis		= 100;
    ch->perm_dex		= 100;
    ch->perm_con		= 100;
    ch->perm_cha		= 100;
    ch->perm_lck		= 100;
	ch->base_hit		= 0;
	ch->base_mana		= 0;
	ch->base_move		= 0;
	ch->no_resistant 		= 0;
    ch->no_susceptible 		= 0;
    ch->no_immune 		= 0;
    ch->was_in_room		= NULL;
    xCLEAR_BITS(ch->no_affected_by);
    xCLEAR_BITS(ch->pcdata->perm_aff);
    ch->pcdata->condition[COND_THIRST]	= 48;
    ch->pcdata->condition[COND_FULL]	= 48;
    ch->pcdata->wizinvis		= 0;
    ch->pcdata->family			= NULL;
    ch->pcdata->gen			= 1;
    ch->pcdata->auto_attack		= NULL;
    ch->in_obj				= NULL;
    ch->on				= NULL;
    ch->pcdata->spouse			= NULL;
    ch->pcdata->eyes			= NULL;
    ch->pcdata->hair			= NULL;
    ch->pcdata->skin_color			= NULL;
    ch->pcdata->skin_type			= NULL;
    ch->pcdata->extra_color			= NULL;
    ch->pcdata->extra_type			= NULL;
    ch->pcdata->first_mutation		= NULL;
    ch->pcdata->last_mutation		= NULL;
    ch->pcdata->maiden_name		= NULL;
    ch->pcdata->name_disguise		= NULL;
    ch->pcdata->channels		= NULL;
    ch->pcdata->outputprefix		= NULL;
    ch->pcdata->outputsuffix		= NULL;
    ch->pcdata->permissions		= 0;
    ch->pcdata->inborn			= -1;
    ch->pcdata->age_adjust		= 0;
    ch->mental_state			= -10;
    ch->mobinvis			= 0;
    for(i = 0; i < MAX_SKILL; i++)
        ch->pcdata->learned[i]		= 0;
    ch->pcdata->release_date		= 0;
    ch->pcdata->helled_by		= NULL;
    ch->saving_poison_death 		= 0;
    ch->saving_wand			= 0;
    ch->saving_para_petri		= 0;
    ch->saving_breath			= 0;
    ch->saving_spell_staff		= 0;
    ch->pcdata->pagerlen		= 24;
#ifdef I3
    i3init_char( ch );
#endif
#ifdef IMC
    imc_initchar( ch );
#endif

    found = FALSE;
    sprintf( strsave, "%s%c/%s", PLAYER_DIR, tolower(name[0]),
			capitalize( name ) );
    if ( stat( strsave, &fst ) != -1 )
    {
      if ( fst.st_size == 0 )
      {
	sprintf( strsave, "%s%c/%s", BACKUP_DIR, tolower(name[0]),
			capitalize( name ) );
	send_to_char( "Restoring your backup player file...", ch );
	bug("Restoring backup pfile...", 0);
      }
      else
      {
	sprintf( buf, "%s player data for: %s (%dK)",
	  preload ? "Preloading" : "Loading", ch->pcdata->filename,
		(int) fst.st_size/1024 );
	log_string_plus( buf, LOG_COMM, 0 );
      }
    }
    /* else no player file */

    if ( ( fp = fopen( strsave, "r" ) ) == NULL )
    { 
		return FALSE;
	} /* if fopen */
	else
	{
		int iNest;

		for ( iNest = 0; iNest < MAX_NEST; iNest++ )
		    rgObjNest[iNest] = NULL;

		found = TRUE;
		/* Cheat so that bug will show line #'s -- Altrag */
		fpArea = fp;
		strcpy(strArea, strsave);
		for ( ; ; )
		{
		    char letter;
		    char *word;

		    letter = fread_letter( fp );
		    if ( letter == '*' )
		    {
				fread_to_eol( fp );
				continue;
			}

		    if ( letter != '#' )
		    {
				bug( "Load_char_obj: # not found.", 0 );
				bug( name, 0 );
				return FALSE;
		    }

		    word = fread_word( fp );
		    if ( !strcmp( word, "PLAYER" ) )
		    {
				fread_char ( ch, fp, preload );
				if ( preload )
				  break;
		    }
            else if ( !strcmp( word, "ALIAS" ) )     /* Aliases     */
				fread_alias( ch, fp );
			else if ( !strcmp( word, "OBJECT" ) )	/* Objects	*/
				fread_obj  ( ch, fp, OS_CARRY );
			else if ( !strcmp( word, "GEM" ) )
				fread_obj (ch, fp, OS_GEM );
			else if ( !strcmp( word, "MOBILE") ) {
				CHAR_DATA *mob;
			
				mob = fread_mobile( fp );
				if (!mob)
					bug("Bad pet vnum.", 0);
				else { 
					ch->pcdata->pet = mob;
					mob->master = ch;
					xSET_BIT(mob->affected_by, AFF_CHARM);
				}
			}
			else if ( !strcmp( word, "END"    ) )	/* Done		*/
				break;
			else {
				bug( "Load_char_obj: bad section.", 0 );
				bug( name, 0 );
				break;
			}
			
		}
		fclose( fp );
		fpArea = NULL;
		strcpy(strArea, "$");
	}

	if ( !found )
    {
        ch->name	   		= STRALLOC( name );
	ch->short_descr			= STRALLOC( "" );
	ch->description			= STRALLOC( "" );
	ch->species			= STRALLOC( "human" );
	ch->nation			= NULL;
	ch->speed			= 100;
	ch->pcdata->parent			= STRALLOC( "" );
	ch->encumberance		= 0;
	ch->last_hit			= NULL;
	ch->pcdata->were_race		= STRALLOC( "" );
	ch->shield			= 0;
	ch->pcdata->consenting		= NULL;
	ch->pcdata->magiclink		= NULL;
	ch->pcdata->mindlink		= NULL;
	ch->editor			= NULL;
  	ch->pcdata->deity_name		= STRALLOC( "" );
	ch->pcdata->deity		= NULL;
	ch->pcdata->pet			= NULL;
	ch->pcdata->pwd			= str_dup( "" );
	ch->pcdata->bamfin		= NULL;
	ch->pcdata->bamfout		= NULL;
	ch->pcdata->rank		= str_dup( "" );
	ch->pcdata->title		= STRALLOC( "" );
	ch->pcdata->homepage		= str_dup( "" );
	ch->pcdata->bio 		= STRALLOC( "" );
	ch->pcdata->prompt		= STRALLOC( "" );
	ch->pcdata->fprompt		= STRALLOC( "" );
	ch->pcdata->r_range_lo		= 0;
	ch->pcdata->r_range_hi		= 0;
	ch->pcdata->m_range_lo		= 0;
	ch->pcdata->m_range_hi		= 0;
	ch->pcdata->o_range_lo		= 0;
	ch->pcdata->o_range_hi		= 0;
	ch->pcdata->rkills		= 0;
	ch->pcdata->rdeaths		= 0;
	ch->pcdata->wizinvis		= 0;
   
    }
    else
    {
	if ( !ch->name )
    		ch->name	= STRALLOC( name );
	if ( !ch->pcdata->deity_name )
	{
	  ch->pcdata->deity_name = STRALLOC( "" );
	  ch->pcdata->deity	 = NULL;
	}
        if ( !ch->pcdata->bio )
          ch->pcdata->bio	 = STRALLOC( "" );

	{ /* Give 'em a brand new body! -- Scion */
		check_bodyparts(ch);
	}

	if ( IS_SET(ch->pcdata->permissions, PERMIT_BUILD) )
	{
 	  assign_area( ch );
	}
	if ( file_ver > 1 ) {
		for ( i = 0; i < MAX_WEAR; i++ ) {
			for ( x = 0; x < MAX_LAYERS; x++ ) {
				if ( save_equipment[i][x] )	{
					equip_char( ch, save_equipment[i][x]);
					save_equipment[i][x] = NULL;
				} else
					break;
			}
		}
	}
    }

    /* Rebuild affected_by and RIS to catch errors - FB */
    update_aris(ch);

    loading_char = NULL;
    return found;
}



/*
 * Read in a char.
 */

#if defined(KEY)
#undef KEY
#endif

#define KEY( literal, field, value )					\
				if ( !strcmp( word, literal ) )	\
				{					\
				    field  = value;			\
				    fMatch = TRUE;			\
				    break;				\
				}

void fread_char( CHAR_DATA *ch, FILE *fp, bool preload )
{
    PART_DATA *part;
    EXPLORED_AREA *xarea;
    char buf[MAX_STRING_LENGTH];
    char *line;
    char *word;
    int x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20;
    sh_int killcnt;
    bool fMatch;
    int count=0;

    file_ver = 0;
    killcnt = 0;
    for ( ; ; )
    {
	word   = feof( fp ) ? "End" : fread_word( fp );
	fMatch = FALSE;

	switch ( UPPER(word[0]) )
	{
	case '*':
	    fMatch = TRUE;
	    fread_to_eol( fp );
	    break;

	case 'A':
	    KEY( "Act",		ch->act,		fread_bitvector( fp ) );
	    KEY( "AffectedBy",	ch->affected_by,	fread_bitvector( fp ) );
	    KEY( "AutoAttack",  ch->pcdata->auto_attack,fread_string(fp));
	    KEY( "Age",	ch->pcdata->age_adjust,	fread_number(fp));
	    KEY( "Armor",	ch->armor,		fread_number( fp ) );

	/* convert from old system -keo */
	    if (ch->armor < 0) ch->armor = abs(ch->armor / 10);

	    if ( !strcmp( word, "Affect" ) || !strcmp( word, "AffectData" ) )
	    {
		AFFECT_DATA *paf;

		if ( preload )
		{
		    fMatch = TRUE;
		    fread_to_eol( fp );
		    break;
		}
		CREATE( paf, AFFECT_DATA, 1 );
		if ( !strcmp( word, "Affect" ) )
		{
		    paf->type	= fread_number( fp );
		}
		else
		{
		    int sn;
		    char *sname = fread_word(fp);

		    if ( (sn=skill_lookup(sname)) < 0 )
		    {
			if ( (sn=herb_lookup(sname)) < 0 )
			    bug( "Fread_char: unknown skill.", 0 );
			else
			    sn += TYPE_HERB;
		    }
		    paf->type = sn;
		}

		paf->duration	= fread_number( fp );
		paf->modifier	= fread_number( fp );
		paf->location	= fread_number( fp );
		if ( paf->location == APPLY_WEAPONSPELL
		||   paf->location == APPLY_WEARSPELL
		||   paf->location == APPLY_REMOVESPELL
		||   paf->location == APPLY_STRIPSN
		||   paf->location == APPLY_RECURRINGSPELL )
		  paf->modifier	= slot_lookup( paf->modifier );
		paf->bitvector	= fread_bitvector( fp );
		LINK(paf, ch->first_affect, ch->last_affect, next, prev );
		fMatch = TRUE;
		break;
	    }

	    if ( !strcmp( word, "AttrMod"  ) )
	    {
		line = fread_line( fp );
		x1=x2=x3=x4=x5=x6=x7=13;
		sscanf( line, "%d %d %d %d %d %d %d",
		      &x1, &x2, &x3, &x4, &x5, &x6, &x7 );
		ch->mod_str = x1;
		ch->mod_int = x2;
		ch->mod_wis = x3;
		ch->mod_dex = x4;
		ch->mod_con = x5;
		ch->mod_cha = x6;
		ch->mod_lck = x7;
		fMatch = TRUE;
		break;
	    }
	    if ( !str_cmp( word, "Alias" ) )
	    {
			if( count >= MAX_ALIAS )
			{
				fread_to_eol( fp );
				fMatch = TRUE;
				break;
			}
 	    	
			ch->pcdata->alias[count]      =	 str_dup( fread_word( fp ) );
			ch->pcdata->alias_sub[count]  =	 fread_string_nohash( fp );
			count++;
			fMatch 			      =  TRUE;
			break;
	    }
     
		if ( !strcmp( word, "AttrPerm" ) )
	    {
		line = fread_line( fp );
		x1=x2=x3=x4=x5=x6=x7=0;
		sscanf( line, "%d %d %d %d %d %d %d",
		      &x1, &x2, &x3, &x4, &x5, &x6, &x7 );
		ch->perm_str = x1;
		ch->perm_int = x2;
		ch->perm_wis = x3;
		ch->perm_dex = x4;
		ch->perm_con = x5;
		ch->perm_cha = x6;
		ch->perm_lck = x7;
		fMatch = TRUE;
		break;
	    }
	    break;

	case 'B':
	    KEY( "Bamfin",	ch->pcdata->bamfin,	fread_string_nohash( fp ) );
	    KEY( "Bamfout",	ch->pcdata->bamfout,	fread_string_nohash( fp ) );
	    KEY( "Bio",		ch->pcdata->bio,	fread_string( fp ) );
		KEY( "Bank",	ch->pcdata->balance,	fread_number( fp ) );
		KEY( "Bounty",	ch->pcdata->bounty,	fread_number( fp ) );
	    break;

	case 'C':
	    KEY( "Channels", ch->pcdata->channels, fread_string(fp));
	    if ( !strcmp( word, "Condition" ) )
	    {
		line = fread_line( fp );
		sscanf( line, "%d %d %d %d",
		      &x1, &x2, &x3, &x4 );
		ch->pcdata->condition[0] = x1;
		ch->pcdata->condition[1] = x2;
		ch->pcdata->condition[2] = x3;
		ch->pcdata->condition[3] = x4;
		fMatch = TRUE;
		break;
	    }

	    break;

	case 'D':
	    KEY( "Damroll",	ch->damroll,		fread_number( fp ) );
	    KEY( "Description",	ch->description,	fread_string( fp ) );
	    break;

	/* 'E' was moved to after 'S' */
        case 'F':
	    KEY( "Family",	ch->pcdata->family,	fread_string(fp));
	    if ( !strcmp( word, "Filename" ) )
	    {
		/*
		 * File Name already set externally.
		 */
		fread_to_eol( fp );
		fMatch = TRUE;
		break;
	    }
	    KEY( "Flags",	ch->pcdata->flags,	fread_number( fp ) );
	    KEY( "FPrompt",	ch->pcdata->fprompt,	fread_string( fp ) );
            break;

	case 'G':
	    KEY( "Generation",	ch->pcdata->gen,	fread_number(fp));
	    KEY( "Gold",	ch->gold,		fread_number( fp ) );
            break;

	case 'H':
	    KEY( "Hair",	ch->pcdata->hair, fread_string(fp));
            KEY( "Height",        ch->height,   fread_number( fp ) );

	    if ( !strcmp(word, "Helled") )
	    {
	      ch->pcdata->release_date = fread_number(fp);
	      ch->pcdata->helled_by = fread_string(fp);
	      if ( ch->pcdata->release_date < current_time )
	      {
	        STRFREE(ch->pcdata->helled_by);
	        ch->pcdata->helled_by = NULL;
	        ch->pcdata->release_date = 0;
	      }
	      fMatch = TRUE;
	      break;
	    }

	    KEY( "Hitroll",	ch->hitroll,		fread_number( fp ) );
	    KEY( "Homepage",	ch->pcdata->homepage,	fread_string_nohash( fp ) );

	    if ( !strcmp( word, "HpManaMove" ) )
	    {
		ch->hit		= fread_number( fp );
		ch->max_hit	= fread_number( fp );
		ch->mana	= fread_number( fp );
		ch->max_mana	= fread_number( fp );
		ch->move	= fread_number( fp );
		ch->max_move	= fread_number( fp );
		fMatch = TRUE;
		break;
	    }
	    break;

	case 'I':
	    KEY ( "Inborn",	ch->pcdata->inborn,	fread_number( fp ) );
	    KEY( "Immune",	ch->immune,		fread_number( fp ) );
#ifdef I3
	   if( ( fMatch = i3load_char( ch, fp, word ) ) )
		break;
#endif
#ifdef IMC
           if( ( fMatch = imc_loadchar( ch, fp, word ) ) )
                break;
#endif
	    break;

	case 'K':
	    break;

	case 'L':
	    KEY( "Long",	ch->description,	fread_string(fp));
	    break;

	case 'M':
	    KEY( "Maiden",	ch->pcdata->maiden_name, fread_string(fp));
	    KEY( "MDeaths",	ch->pcdata->mdeaths,	fread_number( fp ) );
		if (!strcmp(word, "Memorized" )) {
			ch->pcdata->memorize[0] = fread_number( fp );
			ch->pcdata->memorize[1] = fread_number( fp );
			ch->pcdata->memorize[2] = fread_number( fp );
			ch->pcdata->memorize[3] = fread_number( fp );
			ch->pcdata->memorize[4] = fread_number( fp );
			ch->pcdata->memorize[5] = fread_number( fp );
			ch->pcdata->memorize[6] = fread_number( fp );
			ch->pcdata->memorize[7] = fread_number( fp );
			fMatch = TRUE;
		}
		KEY( "Mentalstate", ch->mental_state,	fread_number( fp ) );
	    KEY( "MKills",	ch->pcdata->mkills,	fread_number( fp ) );
	    KEY( "Mobinvis",	ch->mobinvis,		fread_number( fp ) );
	    if ( !strcmp( word, "MobRange" ) )
	    {
		ch->pcdata->m_range_lo = fread_number( fp );
		ch->pcdata->m_range_hi = fread_number( fp );
		fMatch = TRUE;
	    }
	    break;

	case 'N':
            if ( !strcmp( word, "Noncombat"  ) )
            {
                line = fread_line( fp );
x1=x2=x3=x4=x5=x6=x7=x8=x9=x10=x11=x12=x13=x14=x15=x16=x17=x18=x19=x20=1;
                sscanf( line, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
                      &x1, &x2, &x3, &x4, &x5, &x6, &x7, &x8, &x9, &x10,
&x11, &x12, &x13, &x14, &x15, &x16, &x17, &x18, &x19, &x20 );
                ch->pcdata->noncombat[0] = x1;
               ch->pcdata->noncombat[1] = x2;
                ch->pcdata->noncombat[2] = x3;
               ch->pcdata->noncombat[3] = x4;
                ch->pcdata->noncombat[4] = x5;
               ch->pcdata->noncombat[5] = x6;
                ch->pcdata->noncombat[6] = x7;
               ch->pcdata->noncombat[7] = x8;
                ch->pcdata->noncombat[8] = x9;
               ch->pcdata->noncombat[9] = x10;
                ch->pcdata->noncombat[10] = x11;
               ch->pcdata->noncombat[11] = x12;
                ch->pcdata->noncombat[12] = x13;
               ch->pcdata->noncombat[13] = x14;
                ch->pcdata->noncombat[14] = x15;
               ch->pcdata->noncombat[15] = x16;
                ch->pcdata->noncombat[16] = x17;
               ch->pcdata->noncombat[17] = x18;
                ch->pcdata->noncombat[18] = x19;
               ch->pcdata->noncombat[19] = x20;
                fMatch = TRUE;
                break;
            }
            if ( !strcmp( word, "NoncombatExp"  ) )
            {
                line = fread_line( fp );
x1=x2=x3=x4=x5=x6=x7=x8=x9=x10=x11=x12=x13=x14=x15=x16=x17=x18=x19=x20=1;
                sscanf( line, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
                      &x1, &x2, &x3, &x4, &x5, &x6, &x7, &x8, &x9, &x10,
&x11, &x12, &x13, &x14, &x15, &x16, &x17, &x18, &x19, &x20 );
                ch->pcdata->noncombat_exp[0] = x1;
               ch->pcdata->noncombat_exp[1] = x2;
                ch->pcdata->noncombat_exp[2] = x3;
               ch->pcdata->noncombat_exp[3] = x4;
                ch->pcdata->noncombat_exp[4] = x5;
               ch->pcdata->noncombat_exp[5] = x6;
                ch->pcdata->noncombat_exp[6] = x7;
               ch->pcdata->noncombat_exp[7] = x8;
                ch->pcdata->noncombat_exp[8] = x9;
               ch->pcdata->noncombat_exp[9] = x10;
                ch->pcdata->noncombat_exp[10] = x11;
               ch->pcdata->noncombat_exp[11] = x12;
                ch->pcdata->noncombat_exp[12] = x13;
               ch->pcdata->noncombat_exp[13] = x14;
                ch->pcdata->noncombat_exp[14] = x15;
               ch->pcdata->noncombat_exp[15] = x16;
                ch->pcdata->noncombat_exp[16] = x17;
               ch->pcdata->noncombat_exp[17] = x18;
                ch->pcdata->noncombat_exp[18] = x19;
               ch->pcdata->noncombat_exp[19] = x20;
                fMatch = TRUE;
                break;
            }
	    KEY ("Name", ch->name, fread_string( fp ) );
	    KEY ("Ndisguise", ch->pcdata->name_disguise, fread_string(fp));
            KEY ("NoAffectedBy", ch->no_affected_by, fread_bitvector( fp ) );
            KEY ("NoImmune", ch->no_immune, fread_number( fp ) );
            KEY ("NoResistant", ch->no_resistant, fread_number( fp ) );
            KEY ("NoSusceptible", ch->no_susceptible, fread_number( fp ) );
	    break;
	case 'O':
	    KEY( "Outputprefix", ch->pcdata->outputprefix, fread_string(fp));
	    KEY( "Outputsuffix", ch->pcdata->outputsuffix, fread_string(fp));
	    if ( !strcmp( word, "ObjRange" ) )
	    {
		ch->pcdata->o_range_lo = fread_number( fp );
		ch->pcdata->o_range_hi = fread_number( fp );
		fMatch = TRUE;
	    }
	    break;

	case 'P':
	    KEY( "Permissions", ch->pcdata->permissions, fread_number(fp));
	    KEY( "Pagerlen",	ch->pcdata->pagerlen,	fread_number( fp ) );
	    KEY( "Parent",	ch->pcdata->parent, fread_string( fp ) );
            if (!strcmp( word, "Part" )) {
		if (!ch->first_part) check_bodyparts(ch);
		if ((part = find_bodypart(ch, fread_number(fp))) != NULL) {
			part->cond = fread_number(fp);
			part->flags = fread_number(fp);
		}
                fMatch = TRUE;
                break;
            }
	    KEY( "Password",	ch->pcdata->pwd,	fread_string_nohash( fp ) );
	    KEY( "PDeaths",	ch->pcdata->pdeaths,	fread_number( fp ) );
	    KEY( "PKills",	ch->pcdata->pkills,	fread_number( fp ) );
	    KEY( "PermAffects", ch->pcdata->perm_aff, fread_bitvector(fp));
	    KEY( "Played",	ch->played,		fread_number( fp ) );
	    KEY( "Points",	ch->pcdata->points,	fread_number( fp ) );
            /*
             *  new positions are stored in the file from 100 up
             *  old positions are from 0 up
             *  if reading an old position, some translation is necessary
             */
            if (!strcmp ( word, "Position" ) )
            {
               ch->position          = fread_number( fp );
               if(ch->position<100){
                  switch(ch->position){
                      default: ;
                      case 0: ;
                      case 1: ;
                      case 2: ;
                      case 3: ;
                      case 4: break;
                      case 5: ch->position=6; break;
                      case 6: ch->position=7; break;
                      case 7: ch->position=9; break;
                      case 8: ch->position=12; break;
                      case 9: ch->position=13; break;
                      case 10: ch->position=14; break;
                      case 11: ch->position=15; break;
                  }
                  fMatch = TRUE;
               } else {
                  ch->position-=100;
                  fMatch = TRUE;
               }
            }
	    KEY( "Prompt",	ch->pcdata->prompt,	fread_string( fp ) );
	    if (!strcmp ( word, "PTimer" ) )
	    {
		add_timer( ch , TIMER_PKILLED, fread_number(fp), NULL, 0 );	
		fMatch = TRUE;
		break;
	    }
	    break;

	case 'Q':
		if (!strcmp(word, "Qbit")) {
			BIT_DATA *bit;
			BIT_DATA *desc;

			CREATE(bit, BIT_DATA, 1);

			bit->number = fread_number(fp);
			if ((desc = find_qbit(bit->number))==NULL)
				strcpy(bit->desc, fread_string(fp));
			else {
				strcpy(bit->desc, desc->desc);
				fread_string(fp);
			}

			LINK(bit, ch->pcdata->first_qbit, ch->pcdata->last_qbit, next, prev);
			fMatch = TRUE;
		}
		break;
	case 'R':
	    KEY( "Race",        ch->race,		fread_number( fp ) );
	    KEY( "Rank",        ch->pcdata->rank,	fread_string_nohash( fp ) );
	    KEY( "Resistant",	ch->resistant,		fread_number( fp ) );
	    KEY( "Restore_time",ch->pcdata->restore_time, fread_number( fp ) );
            KEY( "RKills",      ch->pcdata->rkills,     fread_number( fp ) );
            KEY( "RDeaths",     ch->pcdata->rdeaths,     fread_number( fp ));

	    if ( !strcmp( word, "Room" ) )
	    {
		ch->in_room = get_room_index( fread_number( fp ) );
		if ( !ch->in_room )
		    ch->in_room = get_room_index( ROOM_VNUM_LIMBO );
		fMatch = TRUE;
		break;
	    }
	    if ( !strcmp( word, "RoomRange" ) )
	    {
		ch->pcdata->r_range_lo = fread_number( fp );
		ch->pcdata->r_range_hi = fread_number( fp );
		fMatch = TRUE;
	    }
	    break;

	case 'S':
	    KEY( "Sex",		ch->sex,		fread_number( fp ) );
	    KEY( "Shield",	ch->shield,		fread_number(fp));
	    KEY( "Speed",	ch->speed,		fread_number(fp));
	    KEY( "ShortDescr",	ch->short_descr,	fread_string( fp ) );
	    KEY( "Skin_color",	ch->pcdata->skin_color, fread_string(fp));
	    KEY( "Skin_type",	ch->pcdata->skin_type, fread_string(fp));
	    KEY( "Species",	ch->species,		fread_string( fp ) );
	    KEY( "Spouse",	ch->pcdata->spouse,	fread_string(fp));
	    KEY( "Susceptible",	ch->susceptible,	fread_number( fp ) );
	    if (ch->species) {
		ch->nation=find_nation(ch->species);
		ch->xflags = ch->nation->parts;
	    }
	    if ( !strcmp( word, "SavingThrow" ) )
	    {
		ch->saving_wand 	= fread_number( fp );
		ch->saving_poison_death = ch->saving_wand;
		ch->saving_para_petri 	= ch->saving_wand;
		ch->saving_breath 	= ch->saving_wand;
		ch->saving_spell_staff 	= ch->saving_wand;
		fMatch = TRUE;
		break;
	    }

	    if ( !strcmp( word, "SavingThrows" ) )
	    {
		ch->saving_poison_death = fread_number( fp );
		ch->saving_wand 	= fread_number( fp );
		ch->saving_para_petri 	= fread_number( fp );
		ch->saving_breath 	= fread_number( fp );
		ch->saving_spell_staff 	= fread_number( fp );
		fMatch = TRUE;
		break;
	    }

	    if ( !strcmp( word, "Site" ) )
	    {
		if ( !preload )
		{
		  sprintf( buf, "Last connected from: %s\n\r", fread_word( fp ) );
		  send_to_char( buf, ch );
		}
		else
		  fread_to_eol( fp );
		fMatch = TRUE;
		if ( preload )
		  word = "End";
		else
		  break;
	    }

	    if ( !strcmp( word, "Skill" ) )
	    {
		int sn;
		int value;

		if ( preload )
		  word = "End";
		else
		{
		  value = fread_number( fp );
		  if ( file_ver < 3 )
		    sn = skill_lookup( fread_word( fp ) );
		  else
		    sn = bsearch_skill_exact( fread_word( fp ),
		    gsn_first_skill, gsn_top_sn-1 );
		  if ( sn < 0 )
		    bug( "Fread_char: unknown skill.", 0 );
		  else
		  {
		    ch->pcdata->learned[sn] = value;
		  }
		  fMatch = TRUE;
		  break;
		}
	    }

	    if ( !strcmp( word, "Spell" ) )
	    {
		int sn;
		int value;

		if ( preload )
		  word = "End";
		else
		{
		  value = fread_number( fp );

		  sn = bsearch_skill_exact( fread_word( fp ), gsn_first_spell, gsn_first_skill-1 );
		  if ( sn < 0 )
		    bug( "Fread_char: unknown spell.", 0 );
		  else
		  {
		    ch->pcdata->learned[sn] = value;
			if ( skill_table[sn]->skill_level[get_best_talent(ch, sn)] >= 1000 )
			{
			    ch->pcdata->learned[sn] = 0;
			} 
		  }
		  fMatch = TRUE;
		  break;
		}
	    }
	    if ( strcmp( word, "End" ) )
		break;

	case 'E':
	    if ( !strcmp( word, "End" ) )
	    {
		if (!ch->short_descr)
		  ch->short_descr	= STRALLOC( "" );
		if (!ch->description)
		  ch->description	= STRALLOC( "" );
		if (!ch->pcdata->pwd)
		  ch->pcdata->pwd	= str_dup( "" );
		if (!ch->pcdata->bio)
		  ch->pcdata->bio	= STRALLOC( "" );
		if (!ch->pcdata->rank)
		  ch->pcdata->rank	= str_dup( "" );
		if (!ch->pcdata->title)
		  ch->pcdata->title	= STRALLOC( "" );
		if (!ch->pcdata->homepage)
		  ch->pcdata->homepage	= str_dup( "" );
		if (!ch->pcdata->prompt )
		  ch->pcdata->prompt	= STRALLOC( "" );
	        if (!ch->pcdata->fprompt )
		  ch->pcdata->fprompt   = STRALLOC( "" );
		ch->editor		= NULL;

		if ( !ch->pcdata->prompt )
		  ch->pcdata->prompt = STRALLOC("");

		return;
	    }
	    KEY( "Exp",		ch->exp,		fread_number( fp ) );
	    if (!strcmp( word, "Explored" )) {
		CREATE(xarea, EXPLORED_AREA, 1);
		xarea->index = fread_number(fp);
		xarea->rooms = fread_bitvector(fp);
		LINK(xarea, ch->pcdata->first_explored, ch->pcdata->last_explored, next, prev);
		fMatch = TRUE;
		break;
	    }
	    KEY( "Extra_color",	ch->pcdata->extra_color, fread_string(fp));
	    KEY( "Extra_type",	ch->pcdata->extra_type, fread_string(fp));
	    KEY( "Eyes",	ch->pcdata->eyes, fread_string(fp));
	    break;

	case 'T':
		if ( !strcmp( word, "Talent" ) ) {
			int i;

			i = fread_number(fp);

			if (i == -1 || i >= MAX_DEITY)
				bug("Fread_char: illegal Talent number %d", i);
			else {
				ch->talent[i] = fread_number(fp);
				ch->curr_talent[i] = fread_number(fp);
			}
			fMatch = TRUE;
			break;
		}

            if ( !strcmp( word, "TalentExp"  ) )
            {
                line = fread_line( fp );
x1=x2=x3=x4=x5=x6=x7=x8=x9=x10=x11=x12=x13=x14=x15=x16=x17=x18=x19=1;
                sscanf( line, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
                      &x1, &x2, &x3, &x4, &x5, &x6, &x7, &x8, &x9, &x10,
&x11, &x12, &x13, &x14, &x15, &x16, &x17, &x18, &x19);
                ch->pcdata->talent_exp[0] = x1;
               ch->pcdata->talent_exp[1] = x2;
                ch->pcdata->talent_exp[2] = x3;
               ch->pcdata->talent_exp[3] = x4;
                ch->pcdata->talent_exp[4] = x5;
               ch->pcdata->talent_exp[5] = x6;
                ch->pcdata->talent_exp[6] = x7;
               ch->pcdata->talent_exp[7] = x8;
                ch->pcdata->talent_exp[8] = x9;
               ch->pcdata->talent_exp[9] = x10;
                ch->pcdata->talent_exp[10] = x11;
               ch->pcdata->talent_exp[11] = x12;
                ch->pcdata->talent_exp[12] = x13;
               ch->pcdata->talent_exp[13] = x14;
                ch->pcdata->talent_exp[14] = x15;
               ch->pcdata->talent_exp[15] = x16;
                ch->pcdata->talent_exp[16] = x17;
               ch->pcdata->talent_exp[17] = x18;
                ch->pcdata->talent_exp[18] = x19;
                fMatch = TRUE;
                break;
            }

	    KEY( "Type", ch->pcdata->type, fread_string(fp));

	    if ( !strcmp( word, "Title" ) )
	    {
		ch->pcdata->title = fread_string( fp );
		if ( isalpha(ch->pcdata->title[0])
		||   isdigit(ch->pcdata->title[0]) )
		{
		    sprintf( buf, " %s", ch->pcdata->title );
		    if ( ch->pcdata->title )
		      STRFREE( ch->pcdata->title );
		    ch->pcdata->title = STRALLOC( buf );
		}
		fMatch = TRUE;
		break;
	    }

	    break;

	case 'V':
	    if ( !strcmp( word, "Vnum" ) )
	    {
		ch->pIndexData = get_mob_index( fread_number( fp ) );
		fMatch = TRUE;
		break;
	    }
	    KEY( "Version",	file_ver,		fread_number( fp ) );
	    break;

	case 'W':
            if ( !strcmp( word, "Weapons"  ) )
            {
                line = fread_line( fp );
x1=x2=x3=x4=x5=x6=x7=x8=x9=x10=x11=x12=x13=x14=x15=x16=x17=x18=x19=x20=1;
                sscanf( line, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
                      &x1, &x2, &x3, &x4, &x5, &x6, &x7, &x8, &x9, &x10, &x11, &x12, &x13, &x14, &x15, &x16, &x17, &x18, &x19, &x20 );
                ch->pcdata->weapon[0] = x1;
               ch->pcdata->weapon[1] = x2;
                ch->pcdata->weapon[2] = x3;
               ch->pcdata->weapon[3] = x4;
                ch->pcdata->weapon[4] = x5;
               ch->pcdata->weapon[5] = x6;
                ch->pcdata->weapon[6] = x7;
               ch->pcdata->weapon[7] = x8;
                ch->pcdata->weapon[8] = x9;
               ch->pcdata->weapon[9] = x10;
                ch->pcdata->weapon[10] = x11;
               ch->pcdata->weapon[11] = x12;
                ch->pcdata->weapon[12] = x13;
               ch->pcdata->weapon[13] = x14;
                ch->pcdata->weapon[14] = x15;
               ch->pcdata->weapon[15] = x16;
                ch->pcdata->weapon[16] = x17;
               ch->pcdata->weapon[17] = x18;
                ch->pcdata->weapon[18] = x19;
               ch->pcdata->weapon[19] = x20;
                fMatch = TRUE;
                break;
            }
            if ( !strcmp( word, "WeaponExp"  ) )
            {
                line = fread_line( fp );
x1=x2=x3=x4=x5=x6=x7=x8=x9=x10=x11=x12=x13=x14=x15=x16=x17=x18=x19=x20=1;
                sscanf( line, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
                      &x1, &x2, &x3, &x4, &x5, &x6, &x7, &x8, &x9, &x10,
&x11, &x12, &x13, &x14, &x15, &x16, &x17, &x18, &x19, &x20 );
                ch->pcdata->weapon_exp[0] = x1;
               ch->pcdata->weapon_exp[1] = x2;
                ch->pcdata->weapon_exp[2] = x3;
               ch->pcdata->weapon_exp[3] = x4;
                ch->pcdata->weapon_exp[4] = x5;
               ch->pcdata->weapon_exp[5] = x6;
                ch->pcdata->weapon_exp[6] = x7;
               ch->pcdata->weapon_exp[7] = x8;
                ch->pcdata->weapon_exp[8] = x9;
               ch->pcdata->weapon_exp[9] = x10;
                ch->pcdata->weapon_exp[10] = x11;
               ch->pcdata->weapon_exp[11] = x12;
                ch->pcdata->weapon_exp[12] = x13;
               ch->pcdata->weapon_exp[13] = x14;
                ch->pcdata->weapon_exp[14] = x15;
               ch->pcdata->weapon_exp[15] = x16;
                ch->pcdata->weapon_exp[16] = x17;
               ch->pcdata->weapon_exp[17] = x18;
                ch->pcdata->weapon_exp[18] = x19;
               ch->pcdata->weapon_exp[19] = x20;
                fMatch = TRUE;
                break;
            }
            KEY( "Weight",        ch->weight,   fread_number( fp ) );
	    KEY( "Wererace",	ch->pcdata->were_race,	fread_string( fp ) );
	    KEY( "Wimpy",	ch->wimpy,		fread_number( fp ) );
	    KEY( "WizInvis",	ch->pcdata->wizinvis,	fread_number( fp ) );
	    break;
	} /* switch */

/*	if ( !fMatch )
	{
	    sprintf( buf, "Fread_char: no match: %s", word );
	    bug( buf, 0 );
	} */
    } /* for (;;) */

	if (!ch->speed) ch->speed = 100;
}


void fread_obj( CHAR_DATA *ch, FILE *fp, sh_int os_type )
{
    OBJ_DATA *obj;
    char *word;
    int iNest;
    bool fMatch;
    bool fNest;
    bool fVnum;
    ROOM_INDEX_DATA *room = NULL;

    if ( ch )
	room = ch->in_room;
    CREATE( obj, OBJ_DATA, 1 );
    obj->count		= 1;
    obj->wear_loc	= -1;
    obj->weight		= 1;
	obj->condition	= 100;
	obj->size	= 0;
    if ( ch )
	obj->size	= ch->height;

    fNest		= TRUE;		/* Requiring a Nest 0 is a waste */
    fVnum		= TRUE;
    iNest		= 0;

    for ( ; ; )
    {
	word   = feof( fp ) ? "End" : fread_word( fp );
	fMatch = FALSE;

	switch ( UPPER(word[0]) )
	{
	case '*':
	    fMatch = TRUE;
	    fread_to_eol( fp );
	    break;

	case 'A':
	    KEY( "ActionDesc", obj->action_desc, 	fread_string( fp ) );
	    if ( !strcmp( word, "Affect" ) || !strcmp( word, "AffectData" ) )
	    {
		AFFECT_DATA *paf;
		int pafmod;

		CREATE( paf, AFFECT_DATA, 1 );
		if ( !strcmp( word, "Affect" ) )
		{
		    paf->type	= fread_number( fp );
		}
		else
		{
		    int sn;

		    sn = skill_lookup( fread_word( fp ) );
		    if ( sn < 0 )
			bug( "Fread_obj: unknown skill.", 0 );
		    else
			paf->type = sn;
		}
		paf->duration	= fread_number( fp );
		pafmod		= fread_number( fp );
		paf->location	= fread_number( fp );
		paf->bitvector	= fread_bitvector( fp );
		if ( paf->location == APPLY_WEAPONSPELL
		||   paf->location == APPLY_WEARSPELL
		||   paf->location == APPLY_STRIPSN
		||   paf->location == APPLY_REMOVESPELL
		||   paf->location == APPLY_RECURRINGSPELL )
		  paf->modifier		= slot_lookup( pafmod );
		else
		  paf->modifier		= pafmod;

		/* convert over old eq -keo */
		if (paf->location == APPLY_AC) {
		  if (paf->modifier == -5) {
			paf->location = APPLY_HITROLL;
			paf->modifier = 1;
		  } else if (paf->modifier < 0) {
		    paf->modifier = abs(paf->modifier / 10);
		  } else if (paf->modifier == 0) {
		    paf->modifier = 1;
		  }
		}
		LINK(paf, obj->first_affect, obj->last_affect, next, prev );
		fMatch				= TRUE;
		break;
	    }
	    break;

	case 'C':
	    KEY( "Cost",	obj->cost,		fread_number( fp ) );
	    KEY( "Count",	obj->count,		fread_number( fp ) );
		KEY( "Condition", obj->condition, fread_number(fp) );
		break;

	case 'D':
	    KEY( "Description",	obj->description,	fread_string( fp ) );
	    break;

	case 'E':
	    KEY( "ExtraFlags",	obj->extra_flags,	fread_bitvector( fp ) );

	    if ( !strcmp( word, "ExtraDescr" ) )
	    {
		EXTRA_DESCR_DATA *ed;

		CREATE( ed, EXTRA_DESCR_DATA, 1 );
		ed->keyword		= fread_string( fp );
		ed->description		= fread_string( fp );
		LINK(ed, obj->first_extradesc, obj->last_extradesc, next, prev );
		fMatch 				= TRUE;
	    }

	    if ( !strcmp( word, "End" ) )
	    {
		if ( !fNest || !fVnum || !obj->pIndexData)
		{
/*		    if ( obj->name )
			sprintf ( buf, "Fread_obj: %s incomplete object.",
				obj->name );
		    else
			sprintf ( buf, "Fread_obj: incomplete object." );
		    bug( buf, 0 );
*/		    if ( obj->name )
		      STRFREE( obj->name        );
		    if ( obj->description )
		      STRFREE( obj->description );
		    if ( obj->short_descr )
		      STRFREE( obj->short_descr );
		    DISPOSE( obj );
		    return;
		}
		else
		{
		    sh_int wear_loc = obj->wear_loc;

		    if ( !obj->name )
			obj->name = QUICKLINK( obj->pIndexData->name );
		    if ( !obj->description )
			obj->description = QUICKLINK( obj->pIndexData->description );
		    if ( !obj->short_descr )
			obj->short_descr = QUICKLINK( obj->pIndexData->short_descr );
		    if ( !obj->action_desc )
			obj->action_desc = QUICKLINK( obj->pIndexData->action_desc );
		    LINK(obj, first_object, last_object, next, prev );
		    obj->pIndexData->count += obj->count;
		    if ( !obj->serial )
		    {
			cur_obj_serial = UMAX((cur_obj_serial + 1 ) & (BV30-1), 1);
			obj->serial = obj->pIndexData->serial = cur_obj_serial;
		    }
		    if ( fNest )
		      rgObjNest[iNest] = obj;
		    numobjsloaded += obj->count;
		    ++physicalobjects;
		    if ( file_ver > 1 || obj->wear_loc < -1
		    ||   obj->wear_loc >= MAX_WEAR )
		      obj->wear_loc = -1;
			if (os_type == OS_GROUND && room) {
				obj_to_room(obj, room);
			}
		    else if ( iNest == 0 || rgObjNest[iNest] == NULL )
		    {
			int slot = -1;
			bool reslot = FALSE;

			if ( file_ver > 1
			&&   wear_loc > -1
			&&   wear_loc < MAX_WEAR )
			{
			   int x;

			   for ( x = 0; x < MAX_LAYERS; x++ )
			      if ( !save_equipment[wear_loc][x] )
			      {
				  save_equipment[wear_loc][x] = obj;
				  slot = x;
				  reslot = TRUE;
				  break;
			      }
			   if ( x == MAX_LAYERS )
				bug( "Fread_obj: too many layers %d", wear_loc );
			}
			obj = obj_to_char( obj, ch );
			if ( reslot && slot != -1 )
			  save_equipment[wear_loc][slot] = obj;
		    }
		    else
		    {
			if ( rgObjNest[iNest-1] )
			{
			   separate_obj( rgObjNest[iNest-1] );
			   if (os_type != OS_GEM) {
			      obj = obj_to_obj( obj, rgObjNest[iNest-1] );
			   } else {
			      rgObjNest[iNest-1]->gem = obj;
				obj->in_obj = rgObjNest[iNest-1];
			   }
			}
			else
			   bug( "Fread_obj: nest layer missing %d", iNest-1 );
		    }
		    if ( fNest )
		      rgObjNest[iNest] = obj;
		    return;
		}
	    }
	    break;

	case 'I':
	    KEY( "ItemType",	obj->item_type,		fread_number( fp ) );
	    break;

	case 'M':
		KEY("Mana", obj->mana, fread_number(fp));
		KEY("Material", obj->material, material_lookup(fread_number(fp)));
		break;
	case 'N':
	    KEY( "Name",	obj->name,		fread_string( fp ) );

	    if ( !strcmp( word, "Nest" ) )
	    {
		iNest = fread_number( fp );
		if ( iNest < 0 || iNest >= MAX_NEST )
		{
		    bug( "Fread_obj: bad nest %d.", iNest );
		    iNest = 0;
		    fNest = FALSE;
		}
		fMatch = TRUE;
	    }
	    break;
	    
	case 'O':
		KEY( "ObjBy", obj->obj_by, fread_string(fp) );
		break;

	case 'P':
	    KEY( "PartFlags", obj->parts, fread_bitvector(fp));
		break;

	case 'R':
	    KEY( "RawMana", obj->raw_mana, fread_number(fp));
	    KEY( "Room", room, get_room_index(fread_number(fp)) );
		break;

	case 'S':
	    KEY( "ShortDescr",	obj->short_descr,	fread_string( fp ) );

	    if ( !strcmp( word, "Spell" ) )
	    {
		int iValue;
		int sn;

		iValue = fread_number( fp );
		sn     = skill_lookup( fread_word( fp ) );
		if ( iValue < 0 || iValue > 5 )
		    bug( "Fread_obj: bad iValue %d.", iValue );
		else if ( sn < 0 )
		    bug( "Fread_obj: unknown skill.", 0 );
		else
		    obj->value[iValue] = sn;
		fMatch = TRUE;
		break;
	    }

		KEY( "Size", obj->size, fread_number(fp));
		break;

	case 'T':
	    KEY( "Timer",	obj->timer,		fread_number( fp ) );
	    break;

	case 'V':
	    if ( !strcmp( word, "Values" ) )
	    {
		int x1,x2,x3,x4,x5,x6,x7;
		char *ln = fread_line( fp );

		x1=x2=x3=x4=x5=x6=0;
		sscanf( ln, "%d %d %d %d %d %d %d",
		&x1, &x2, &x3, &x4, &x5, &x6, &x7 );
		/* clean up some garbage */
/*		if ( file_ver < 3 )
		   x5=x6=x7=0;
*/
		obj->value[0]	= x1;
		obj->value[1]	= x2;
		obj->value[2]	= x3;
		obj->value[3]	= x4;
		obj->value[4]	= x5;
		obj->value[5]	= x6;
		obj->value[6]	= x7;
		fMatch		= TRUE;
		break;
	    }

	    if ( !strcmp( word, "Vnum" ) )
	    {
		int vnum;

		vnum = fread_number( fp );
		/*  bug( "Fread_obj: bad vnum %d.", vnum );  */
		if ( ( obj->pIndexData = get_obj_index( vnum ) ) == NULL )
		    fVnum = FALSE;
		else
		{
		    fVnum = TRUE;
		    obj->cost = obj->pIndexData->cost;
		    obj->weight = obj->pIndexData->weight;
		    obj->item_type = obj->pIndexData->item_type;
		    obj->extra_flags = obj->pIndexData->extra_flags;
		    obj->parts = obj->pIndexData->parts;
		}
		fMatch = TRUE;
		break;
	    }
	    break;

	case 'W':
	    KEY( "WearLoc",	obj->wear_loc,		fread_number( fp ) );
	    KEY( "Weight",	obj->weight,		fread_number( fp ) );
		break;

	}

	if ( !fMatch )
	{
	    EXTRA_DESCR_DATA *ed;
	    AFFECT_DATA *paf;

	    bug( "Fread_obj: no match.", 0 );
	    bug( word, 0 );
	    fread_to_eol( fp );
	    if ( obj->name )
		STRFREE( obj->name        );
	    if ( obj->description )
		STRFREE( obj->description );
	    if ( obj->short_descr )
		STRFREE( obj->short_descr );
	    while ( (ed=obj->first_extradesc) != NULL )
	    {
		STRFREE( ed->keyword );
		STRFREE( ed->description );
		UNLINK( ed, obj->first_extradesc, obj->last_extradesc, next, prev );
		DISPOSE( ed );
	    }
	    while ( (paf=obj->first_affect) != NULL )
	    {
		UNLINK( paf, obj->first_affect, obj->last_affect, next, prev );
		DISPOSE( paf );
	    }
	    DISPOSE( obj );
	    return;
	}
    }
}

void fread_alias( CHAR_DATA *ch, FILE *fp )
{
    ALIAS_DATA *alias;
    char       *word;
    bool        fMatch;

    CREATE( alias, ALIAS_DATA, 1 );

    for ( ; ; )
    {
	word   = feof( fp ) ? "End" : fread_word( fp );
	fMatch = FALSE;

	switch ( UPPER(word[0]) )
	{
	case '*':
	    fMatch = TRUE;
	    fread_to_eol( fp );
	    break;

	case 'C':
	    KEY( "Commands",    alias->alias,           fread_string( fp ) );
	    break;

	case 'E':
	    if ( !strcmp( word, "End" ) )
	    {
                if ( !alias->name || !alias->alias )
                {
                    bug( "fread_alias: %s%s%s", alias->name ? "" : "NULL alias->name",
                        ( !alias->name && !alias->alias ) ? " and " : "NULL alias->alias" );
		    DISPOSE( alias );
		    return;
		}
		else
		{
                   /* bug( "Debug: fread_alias: %s    %s", alias->name, alias->alias ); */
		    LINK( alias, ch->pcdata->first_alias, ch->pcdata->last_alias, next, prev );
		    return;
		}
	    }
	    break;

	case 'N':
	    KEY( "Name",        alias->name,            fread_string( fp ) );
            break;

	}

	if ( !fMatch )
	{
	    bug( "Fread_obj: no match." );
	    bug( word );
	    fread_to_eol( fp );
	    DISPOSE( alias );
	    return;
	}
    }
}

void set_alarm( long seconds )
{
#ifdef WIN32
    kill_timer ();    /* kill old timer */
    timer_code = timeSetEvent(seconds * 1000L, 1000, alarm_handler, 0, TIME_PERIODIC);
#else
    alarm( seconds );
#endif
}

/*
 * Based on last time modified, show when a player was last on	-Thoric
 */
void do_last( CHAR_DATA *ch, char *argument )
{
    char buf [MAX_STRING_LENGTH];
    char arg [MAX_INPUT_LENGTH];
    char name[MAX_INPUT_LENGTH];
    struct stat fst;

    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Usage: last <playername>\n\r", ch );
	return;
    }
    strcpy( name, capitalize(arg) );
    sprintf( buf, "%s%c/%s", PLAYER_DIR, tolower(arg[0]), name );
    if ( stat( buf, &fst ) != -1 )
      sprintf( buf, "%s was last on: %s\r", name, ctime( &fst.st_mtime ) );
    else
      sprintf( buf, "%s was not found.\n\r", name );
   send_to_char( buf, ch );
}

/*
 * Added support for removeing so we could take out the write_corpses
 * so we could take it out of the save_char_obj function. --Shaddai
 */

void write_corpses( CHAR_DATA *ch, char *name, OBJ_DATA *objrem )
{
  FILE *fp = NULL;
  
  /* Name and ch support so that we dont have to have a char to save their
     corpses.. (ie: decayed corpses while offline) */
  if ( ch && IS_NPC(ch) )
  {
    bug( "Write_corpses: writing NPC corpse.", 0 );
    return;
  }
  if ( ch )
    name = ch->name;
  /* Go by vnum, less chance of screwups. -- Altrag */
/*  for ( corpse = first_object; corpse; corpse = corpse->next )
    if ( corpse->pIndexData->vnum == OBJ_VNUM_CORPSE_PC &&
         corpse->in_room != NULL &&
        !str_cmp(corpse->short_descr+14, name) &&
	objrem != corpse )
    {
      if ( !fp )
      {
        char buf[127];
        
        sprintf(buf, "%s%s", CORPSE_DIR, capitalize(name));
        if ( !(fp = fopen(buf, "w")) )
        {
          bug( "Write_corpses: Cannot open file.", 0 );
          perror(buf);
          return;
        }
      }
    }
*/
  if ( fp )
  {
    fprintf(fp, "#END\n\n");
    fclose(fp);
  }
  else
  {
    char buf[127];
    
    sprintf(buf, "%s%s", CORPSE_DIR, capitalize(name));
    remove(buf);
  }
  return;
}

void load_corpses( void )
{
}

/*
 * This will write one mobile structure pointed to be fp --Shaddai
 */

void fwrite_mobile( FILE *fp, CHAR_DATA *mob )
{
  if ( !IS_NPC( mob ) || !fp )
	return;
  fprintf( fp, "#MOBILE\n" );
  fprintf( fp, "Vnum	%d\n", mob->pIndexData->vnum );
  if ( mob->in_room ) {
	  if (xIS_SET(mob->act, ACT_SENTINEL)) {
		  /* Sentinel mobs get stamped with a "home room" when they are created
		  by create_mobile(), so we need to save them in their home room regardless
		  of where they are right now, so they will go to their home room when they
		  enter the game from a reboot or copyover -- Scion */
		  fprintf( fp, "Room	%d\n", mob->home_room );
	  } else {
		  fprintf( fp, "Room	%d\n", 
       		(  mob->in_room == get_room_index( ROOM_VNUM_LIMBO )
        		&& mob->was_in_room )
            		? mob->was_in_room->vnum
            		: mob->in_room->vnum );
	  }
  }
  if ( QUICKMATCH( mob->name, mob->pIndexData->player_name) == 0 )
        fprintf( fp, "Name     %s~\n", mob->name );
  if ( QUICKMATCH( mob->short_descr, mob->pIndexData->short_descr) == 0 )
  	fprintf( fp, "Short	%s~\n", mob->short_descr );
  if ( QUICKMATCH( mob->description, mob->pIndexData->description) == 0 )
  	fprintf( fp, "Description %s~\n", mob->description );
  fprintf( fp, "Gold %ld\n", mob->gold );
  fprintf( fp, "Flags %s\n",   print_bitvector(&mob->act) );
	/* This is needed for generic mobs */
        fprintf( fp, "AttrPerm     %d %d %d %d %d %d %d\n",
            mob->perm_str,
            mob->perm_int,
            mob->perm_wis,
            mob->perm_dex,
            mob->perm_con,
            mob->perm_cha,
            mob->perm_lck );
	fprintf(fp, "Part	%d\n", mob->xflags);
  if ( mob->first_carrying )
	fwrite_obj( mob, mob->last_carrying, fp, 0, OS_CARRY );
  fprintf( fp, "EndMobile\n\n" );
  return;
}

/*
 * This will read one mobile structure pointer to by fp --Shaddai
 */
CHAR_DATA *  fread_mobile( FILE *fp )
{
  CHAR_DATA *mob = NULL;
  char *word;
  bool fMatch;
  int inroom = 0;
  char *line;
  ROOM_INDEX_DATA *pRoomIndex = NULL;
  int x1, x2, x3, x4, x5, x6, x7;

  word   = feof( fp ) ? "EndMobile" : fread_word( fp );
  if ( !strcmp(word, "Vnum") )
  {
    int vnum;
    
    vnum = fread_number( fp );
    mob = create_mobile( get_mob_index(vnum) );
    if ( !mob )
    {
	for ( ; ; ) {
	  word   = feof( fp ) ? "EndMobile" : fread_word( fp );
	  /* So we don't get so many bug messages when something messes up
	   * --Shaddai 
	   */
	  if ( !strcmp( word, "EndMobile" ) )
		break;
	}
	bug("Fread_mobile: No index data for vnum %d", vnum );
	return NULL;
	}
  }
  else
  {
	for ( ; ; ) {
	  word   = feof( fp ) ? "EndMobile" : fread_word( fp );
	  /* So we don't get so many bug messages when something messes up
	   * --Shaddai 
	   */
	  if ( !strcmp( word, "EndMobile" ) )
		break;
        }
	extract_char(mob, TRUE);
	bug("Fread_mobile: Vnum not found", 0 );
	return NULL;
  }
  for ( ; ;) {
       word   = feof( fp ) ? "EndMobile" : fread_word( fp );
       fMatch = FALSE; 
       switch ( UPPER(word[0]) ) {
	case '*':
           fMatch = TRUE;
           fread_to_eol( fp );
           break;  
	case '#':
		if ( !strcmp( word, "#OBJECT" ) )
			fread_obj ( mob, fp, OS_CARRY );
		else if ( !str_cmp(word, "#GEM" ) )
			fread_obj ( mob, fp, OS_GEM );
	case 'A':
                if ( !strcmp( word, "AttrPerm" ) )
            {
                line = fread_line( fp );
                x1=x2=x3=x4=x5=x6=x7=0;
                sscanf( line, "%d %d %d %d %d %d %d",
                      &x1, &x2, &x3, &x4, &x5, &x6, &x7 );
                mob->perm_str = x1;
                mob->perm_int = x2;
                mob->perm_wis = x3;
                mob->perm_dex = x4;
                mob->perm_con = x5;
                mob->perm_cha = x6;
                mob->perm_lck = x7;
                fMatch = TRUE;
                break;
            }
		break;
	case 'D':
		KEY( "Description", mob->description, fread_string(fp));
		break;
	case 'E':
		if ( !strcmp( word, "EndMobile" ) )
		{
		if ( inroom == 0 )
			inroom = ROOM_VNUM_NEXUS;
		pRoomIndex = get_room_index( inroom );
		if ( !pRoomIndex )
			pRoomIndex = get_room_index( ROOM_VNUM_NEXUS );
		char_to_room(mob, pRoomIndex);
		return mob;
		} 
		if (!strcmp( word, "End" ) ) /* End of object, need to ignore this.
											  sometimes they creep in there somehow -- Scion */
				fMatch=TRUE; /* Trick the system into thinking it matched something */
		break;
 	case 'F':
		KEY( "Flags", mob->act, fread_bitvector(fp));
		break;
	case 'G':
		KEY( "Gold", mob->gold, fread_number(fp));
		break;
	case 'N':
		KEY( "Name", mob->name, fread_string( fp ) );
		break;
	case 'P':
		KEY( "Position", mob->position, fread_number( fp ) );
		KEY( "Part", mob->xflags, fread_number( fp ) );
		break;
	case 'R':
		KEY( "Room",  inroom, fread_number(fp));
		break;
	case 'S':
		KEY( "Short", mob->short_descr, fread_string(fp));
		break;
	}
	if ( !fMatch && strcmp(word, "End"))
	{
	   bug ( "Fread_mobile: no match.", 0 );
	   bug ( word, 0 );
	}
  }
  return NULL;
}

/*
 * This will write in the saved mobile for a char --Shaddai
 */
void write_char_mobile( CHAR_DATA *ch , char *argument )
{
  FILE *fp;
  CHAR_DATA *mob;
  char buf[MAX_STRING_LENGTH];

  if ( IS_NPC( ch ) || !ch->pcdata->pet )
	return;

  fclose( fpReserve );
  if ( (fp = fopen( argument, "w")) == NULL )
  {
	sprintf(buf, "Write_char_mobile: couldn't open %s for writing!\n\r", 
		argument );
	bug(buf, 0 );
	fpReserve = fopen( NULL_FILE, "r" );
	return;
  }
  mob = ch->pcdata->pet;
  xSET_BIT( mob->affected_by, AFF_CHARM );
  fwrite_mobile( fp, mob );
  fclose( fp );
  fpReserve = fopen( NULL_FILE, "r" );
  return;
}

/*
 * This will read in the saved mobile for a char --Shaddai
 */

void read_char_mobile( char *argument )
{
  FILE *fp;
  CHAR_DATA *mob;
  char buf[MAX_STRING_LENGTH];

  fclose( fpReserve );
  if ( (fp = fopen( argument, "r")) == NULL )
  {
	sprintf(buf, "Read_char_mobile: couldn't open %s for reading!\n\r", 
		argument );
	bug(buf, 0 );
	fpReserve = fopen( NULL_FILE, "r" );
	return;
  }
  mob = fread_mobile( fp );
  fclose( fp );
  fpReserve = fopen( NULL_FILE, "r" );
  return;
}

/* Return the vnum the obj is in, regardless of being carried or inside containers. -- Scion */
int get_obj_room_vnum_recursive(OBJ_DATA *obj) {
	if (!obj)
		return ROOM_VNUM_LIMBO;
	
	if (obj->in_obj) {
		return get_obj_room_vnum_recursive(obj->in_obj);
	}
	else if (obj->carried_by) {
		if (obj->carried_by->in_room) {
			return obj->carried_by->in_room->vnum;
		}
		else {
			bug("get_obj_room_vnum_recursive: Char \"%s\" not in room?!",obj->carried_by->name);
			return ROOM_VNUM_LIMBO;
		}
	} else if (obj->in_room) {
		return obj->in_room->vnum;
	}
	else {
		bug ("get_obj_room_vnum_recursive: obj isn't carried, inside containers, or inside a room!",0);
		bug ("putting in limbo...",0);
		obj_to_room(obj, get_room_index(ROOM_VNUM_LIMBO));
		return ROOM_VNUM_LIMBO;
	}
}


/*
 * Save the world's objects and mobs in their current positions -- Scion
 */
void save_world( CHAR_DATA *ch)
{
    FILE *mobfp;
	FILE *objfp;
	int mobfile=0;
	int objfile=0;
    char filename[256];
	CHAR_DATA *rch;
	OBJ_DATA *obj;

    sprintf( filename, "%s%s", SYSTEM_DIR, MOB_FILE);
    if ( ( mobfp = fopen( filename, "w" ) ) == NULL ) {
		bug( "save_world: fopen mob file", 0 );
		perror( filename );
    } else
		mobfile++;
	
	sprintf( filename, "%s%s", SYSTEM_DIR, OBJ_FILE);
	if ( ( objfp = fopen( filename, "w" ) ) == NULL ) {
		bug("save_world: fopen obj file", 0 );
		perror( filename );
	} else
		objfile++;

	if (objfile) {
		for ( obj = first_object; obj; obj = obj->next ) {
			/* Objects that are in inventories get written in fwrite_mob, or to a player's pfile */
			if (IS_OBJ_STAT( obj, ITEM_PROTOTYPE )
				|| (!obj->in_room) /* Don't keep objs that aren't in rooms */
				|| (obj->carried_by) /* Carried objs save on the char that's carrying them */
				|| (obj->in_obj) /* Don't keep objs in other objs.. they save when their container saves */
				|| IS_SET(obj->in_room->room_flags, ROOM_DONATION))
				continue;
			fwrite_obj(NULL, obj, objfp, 0, OS_GROUND);
		}
		fprintf(objfp, "#END");
		fclose(objfp);
	}
	
	if (mobfile) {
		for (rch = first_char; rch; rch = rch->next ) {
			if (!IS_NPC(rch) || rch==supermob || xIS_SET(rch->act, ACT_PROTOTYPE) || xIS_SET(rch->act, ACT_PET))
				continue;
			else
				fwrite_mobile(mobfp, rch);
		}
		fprintf(mobfp, "#END");
		fclose(mobfp);
	}
}

void load_world(CHAR_DATA *ch) {
	FILE *mobfp;
	FILE *objfp;
	char filename[256];
	char *word;
	int done = 0;
	int mobfile = 0;
	int objfile = 0;

	sprintf( filename, "%s%s", SYSTEM_DIR, MOB_FILE);
    if ( ( mobfp = fopen( filename, "r" ) ) == NULL ) {
		bug( "load_world: fopen mob file", 0 );
		perror( filename );
		return;
    } else
		mobfile++;

	sprintf( filename, "%s%s", SYSTEM_DIR, OBJ_FILE);
	if ( ( objfp = fopen( filename, "r" ) ) == NULL ) {
		bug( "load_world: fopen obj file", 0 );
		perror( filename );
		return;
	} else
		objfile++;

	if (mobfile) {
		while(done==0) {
			if (feof(mobfp))
				done++;
			else {
				word = fread_word(mobfp);
				if (str_cmp(word, "#END"))
					fread_mobile( mobfp );
				else
					done++;
			}
			
		}
		fclose(mobfp);
	}
	
	done = 0;

	if (objfile) {
		while (done==0) {
			if (feof(objfp))
				done++;
			else {
				word = fread_word(objfp);
				if (str_cmp(word, "#END"))
					fread_obj(NULL, objfp, OS_GROUND);
				else
					done++;
			}
			
		}
		fclose(objfp);
	}
}