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

/***************************************************************************
 * save.c: Handles saves to data files																	   *
 ***************************************************************************/
 
#include <sys/stat.h>
#include "mud.h"

/*
	Array of containers read for proper re-nesting of objects.
*/

#define MAX_NEST	10
static	OBJ_DATA *	rgObjNest	[MAX_NEST];

/*
	The object version number is saved in the pfiles, if someone logs
	in with a non matching version number all the objects carried by
	that person will be purged, if you ever need to use this it would
	be smart to also add the version check to the quest bits of players,
	so the kids can get some new gear - Scandum
*/

/*
	Local functions.
*/

int			total_language( CHAR_DATA *);
void			save_account	args( ( DESCRIPTOR_DATA *d ) );
void			fwrite_char		args( ( CHAR_DATA *ch, FILE *fp ) );
void			fwrite_mobile	args( ( CHAR_DATA *mob, FILE *fp ) );
void			fwrite_obj		args( ( CHAR_DATA *ch, OBJ_DATA *obj, FILE *fp, char iNest ) );
void			fread_char		args( ( CHAR_DATA *ch, FILE *fp ) );
void			fread_account	args( ( ACCOUNT_DATA *acct, FILE *fp ) );
CHAR_DATA	* fread_mobile	args( ( FILE *fp ) );
void			fread_obj			args( ( CHAR_DATA *ch, FILE *fp ) );
bool			is_valid_file		args( ( CHAR_DATA *ch, FILE *fp ) );
void			fwrite_poison_data( POISON_DATA *, FILE *);
POISON_DATA	*fread_poison_data( FILE *);


lg_int encrypt64( char *str )
{
	lg_int h;

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

	for (h = 0 ; *str != 0 ; str++)
	{
		h = (h << 7) + *str;
	}

	pop_call();
	return h;
}

void	add_pvnum( CHAR_DATA *ch )
{
	PVNUM_DATA *pvnum;

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

	if (ch->pcdata->pvnum && pvnum_index[ch->pcdata->pvnum] == NULL)
	{
		ALLOCMEM(pvnum, PVNUM_DATA, 1);

		pvnum->name = STRALLOC(capitalize_name(ch->name));
		pvnum->date = mud->current_time;
		SET_BIT(pvnum->flags, PVNUM_AUTH_NAME);

		pvnum_index[ch->pcdata->pvnum] = pvnum;
	}
	pop_call();
	return;
}

int find_free_pvnum()
{
	int cnt;

	push_call("find_free_pvnum()");

	for (cnt = 100 ; cnt < MAX_PVNUM / 2 ; cnt++)
	{
		if (pvnum_index[cnt] == NULL)
		{
			pop_call();
			return cnt;
		}
	}
	log_printf("find_free_pvnum: no free pvnum index found: removing deleted players");

	for (cnt = 100 ; cnt < MAX_PVNUM ; cnt++)
	{
		if (pvnum_index[cnt] == NULL)
		{
			continue;
		}
		if (IS_SET(pvnum_index[cnt]->flags, PVNUM_DELETED))
		{
			STRFREE(pvnum_index[cnt]->name);
			FREEMEM(pvnum_index[cnt]);
		}
	}

	for (cnt = 100 ; cnt < MAX_PVNUM ; cnt++)
	{
		if (pvnum_index[cnt] == NULL)
		{
			pop_call();
			return cnt;
		}
	}
	log_printf("find_free_pvnum: no free pvnum index found");

	pop_call();
	return 0;
}

/*
	Save a character and inventory.
*/

void save_char_obj(CHAR_DATA *ch, int which_type)
{
	PET_DATA *pet;
	char strsave[MAX_INPUT_LENGTH], strtemp[MAX_INPUT_LENGTH];
	char logfile[250];
	char cap_name[30];
	FILE *fp, *logfp;
	ROOM_INDEX_DATA *troom;
	bool IS_DESC;

	push_call("save_char_obj(%p,%p)",ch,which_type);

	if (IS_NPC(ch))
	{
		pop_call();
		return;
	}

	IS_DESC = is_desc_valid( ch );

	if ( IS_DESC && ch->desc->original != NULL )
	{
		send_to_char( "You can't save out of body!\n\r", ch);
		pop_call();
		return;
	}

	troom = ch->in_room;

	if (troom == NULL)
	{
		log_printf("Save_char_obj: char was not in a room");

		pop_call();
		return;
	}

	if (IS_SET(troom->room_flags, ROOM_NO_SAVE))
	{
		char_from_room( ch );
		char_to_room( ch, ROOM_VNUM_TEMPLE, FALSE );
	}

	strcpy( cap_name, capitalize_name( ch->name ) );

	if (which_type == NORMAL_SAVE)
	{
		sprintf(strsave,"%s/%c/%s",     PLAYER_DIR, tolower(cap_name[0]), cap_name);
		sprintf(strtemp,"%s/%c/temp.%s",PLAYER_DIR, tolower(cap_name[0]), cap_name);
	}
	else
	{
		sprintf(strsave, "%s/%c/bak/%s",      PLAYER_DIR, tolower(cap_name[0]), cap_name);
		sprintf(strtemp, "%s/%c/bak/temp.%s", PLAYER_DIR, tolower(cap_name[0]), cap_name);
	}

	close_reserve();
/*
	Save char to "temp.name" then rename to "name" after all done for safety
*/
	sprintf(logfile, "%s/%c/%s.log", PLAYER_DIR, tolower(cap_name[0]), cap_name);

	logfp = my_fopen(logfile,"w",FALSE);

	if (logfp == NULL)
	{
		log_printf("Could _NOT_ open logfile to log the saving of %s\n\r.",cap_name);
		print_errno(errno);
	}

	if (remove( strtemp ) != 0)
	{
		if (errno != ENOENT) /* if there was no temp file there's no prob */
		{
			log_printf("save_char_obj: could not remove %s.", strtemp);
			print_errno(errno);
		}
	}

	fp = my_fopen( strtemp, "w", FALSE ) ;

	if ( fp == NULL )
	{
		log_printf("Save_char_obj: could not my_fopen file.");
		perror( strsave );
		send_to_char( "Through some wierd game error, your character did not save.\n\r", ch);
		open_reserve();

		pop_call();
		return;
	}

	if (logfp) /* if the logfile is opened correctly */
	{
		fprintf(logfp, "Removed old backup and opened a new tempfile successfully.\n");
	}

	{
		fwrite_char( ch, fp );

		if (logfp)
		{
			fprintf(logfp,"Wrote character information successfully. (fwrite_char)\n");
		}

		if (ch->pcdata->corpse && get_room_index(ch->pcdata->corpse_room))
		{
			obj_to_char(ch->pcdata->corpse, ch);
		}

		if (ch->pcdata->cart && get_room_index(ch->pcdata->cart_room))
		{
			obj_to_char(ch->pcdata->cart, ch);
		}

		if (ch->first_carrying != NULL)
		{
			if (logfp)
			{
				fprintf(logfp,"Starting to write ch->first_carrying (%p) to file.\n",ch->first_carrying);
			}
			fwrite_obj( ch, ch->first_carrying, fp, 0 );
		}
		if (ch->pcdata->corpse && get_room_index(ch->pcdata->corpse_room))
		{
			obj_to_room(ch->pcdata->corpse, ch->pcdata->corpse_room);
		}
		if (ch->pcdata->cart && get_room_index(ch->pcdata->cart_room))
		{
			obj_to_room(ch->pcdata->cart, ch->pcdata->cart_room);
		}
		for (pet = mud->f_pet ; pet ; pet = pet->next)
		{
			if (pet->ch->master == ch)
			{
				if (IS_SET(pet->ch->act, ACT_PET))
				{
					fwrite_mobile( pet->ch, fp );
				}
			}
		}
 		fprintf( fp, "#END %s\n", ch->name );
		if (logfp)
		{
			fprintf(logfp,"Save successfull\n");
		}
	}

	if (ftell(fp) < (long)100)
	{
		my_fclose( fp );
		send_to_char("Oops, file system full! tell one of the Gods!\n\r",ch);
		log_string("File system full!!!\n\r");
	}
	else
	{
		my_fclose( fp );

		fp = my_fopen( strtemp, "r",FALSE ) ;

		if (!is_valid_file(ch, fp))
		{
			my_fclose( fp );
			log_printf("SAVE not valid for %s", ch->name );
			log_printf("Filesystem unstable, while saving %s", strtemp);
			send_to_char( "The file system has become unstable.  Please inform the Gods.\n\r", ch);
			remove( strtemp );
		}
		else
		{
			my_fclose( fp );

			if (remove(strsave) != 0)
			{
				if (errno != ENOENT)
				{
					log_printf("save_char_obj: (2nd) could not remove %s.", strsave);
					print_errno(errno);
				}
			}

			if (rename( strtemp, strsave ) != 0)
			{
				log_printf("Could not rename %s to %s.", strtemp, strsave);
				print_errno(errno);
			}
		}
	}

	if (logfp)
	{
		fprintf(logfp,"All done right.\n");
		fflush(logfp);
		my_fclose(logfp);
		remove( logfile );
	}

	open_reserve();

	ch->pcdata->last_saved = mud->current_time;

	// add account saving - Kregor
	if (IS_DESC && ch->desc->account)
		save_account(ch->desc);

	/* restore char to proper room if in NO_SAVE room */

	if (ch->in_room != troom)
	{
		char_from_room(ch);
		char_to_room(ch, troom->vnum, FALSE);
	}

	pop_call();
	return;
}

void fix_object_bits(CHAR_DATA *ch, OBJ_DATA *obj)
{
	push_call("fix_object_bits(%p,%p)",ch,obj);

	while (obj != NULL)
	{
		if (obj->first_content != NULL)
		{
			fix_object_bits(ch, obj->first_content);
		}

		if (!IS_SET(obj->extra_flags, ITEM_MODIFIED))
		{
			obj = obj->next_content;
			continue;
		}
		if (IS_SET(obj->pIndexData->extra_flags, ITEM_MAGIC)
		&& !IS_SET(obj->extra_flags,ITEM_MAGIC))
		{
			SET_BIT(obj->extra_flags,ITEM_MAGIC);
		}
		if (IS_SET(obj->pIndexData->extra_flags, ITEM_EVIL)
		&& !IS_SET(obj->extra_flags, ITEM_EVIL))
		{
			SET_BIT(obj->extra_flags,ITEM_EVIL);
		}
		if (IS_SET(obj->pIndexData->extra_flags, ITEM_CHAOTIC)
		&& !IS_SET(obj->extra_flags, ITEM_CHAOTIC))
		{
			SET_BIT(obj->extra_flags,ITEM_CHAOTIC);
		}
		if (IS_SET(obj->pIndexData->extra_flags, ITEM_LAWFUL)
		&& !IS_SET(obj->extra_flags, ITEM_LAWFUL))
		{
			SET_BIT(obj->extra_flags,ITEM_LAWFUL);
		}
		if (IS_SET(obj->pIndexData->extra_flags, ITEM_UNCONCERNED)
		&& !IS_SET(obj->extra_flags, ITEM_UNCONCERNED))
		{
			SET_BIT(obj->extra_flags,ITEM_UNCONCERNED);
		}
		if (IS_SET(obj->pIndexData->extra_flags,ITEM_GOOD)
		&& !IS_SET(obj->extra_flags,ITEM_GOOD))
		{
			SET_BIT(obj->extra_flags,ITEM_GOOD);
		}
		if (IS_SET(obj->pIndexData->extra_flags,ITEM_NEUTRAL)
		&& !IS_SET(obj->extra_flags,ITEM_NEUTRAL))
		{
			SET_BIT(obj->extra_flags, ITEM_NEUTRAL);
		}
		if (IS_SET(obj->pIndexData->extra_flags, ITEM_INVENTORY)
		&& !IS_SET(obj->extra_flags,ITEM_INVENTORY))
		{
			SET_BIT(obj->extra_flags,ITEM_INVENTORY);
		}
		obj = obj->next_content;
	}
	pop_call();
	return;
}

void fwrite_char( CHAR_DATA *ch, FILE *fp )
{
	AFFECT_DATA *paf;
	DISEASE_DATA *dis;
	CRIME_DATA *pcr;
	bool IS_DESC;
	int sn;
	int cnt;

	push_call("fwrite_char(%p,%p)",ch,fp);

	IS_DESC = is_desc_valid( ch );

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

	fprintf( fp, "Version  %d\n",  PLAYER_VERSION);
	fprintf( fp, "Login    %s~\n", ch->pcdata->host);
	fprintf( fp, "Player   %s~\n", ch->pcdata->account);

	fprintf( fp, "S_Descr  %s~\n", ch->short_descr);
	fprintf( fp, "L_Descr  %s~\n", ch->long_descr);
	fprintf( fp, "E_Descr  %s~\n", fixer(ch->description));
	if (ch->pcdata->bio && ch->pcdata->bio[0] != '\0')
	{
		fprintf( fp, "Bio      %s~\n", fixer(ch->pcdata->bio));
	}
	if (ch->pcdata->adjective && ch->pcdata->adjective[0] != '\0')
	{
		fprintf( fp, "Adject   %s~\n", fixer(ch->pcdata->adjective));
	}

	if (ch->pcdata->first_record)
	{
		for (pcr = ch->pcdata->first_record ; pcr ; pcr = pcr->next)
		{
			fprintf( fp, "Crime_Data\n");
			fprintf( fp, "%s~\n", fixer(pcr->crime_record));
			fprintf( fp, "%s~\n", pcr->arrester);
			fprintf( fp, "%ld\n", pcr->date);
			fprintf( fp, "%d\n",  pcr->level);
			fprintf( fp, "%d\n",  pcr->jailtime);
			fprintf( fp, "%d\n",  pcr->released);
			fprintf( fp, "%s~\n", pcr->releaser);
		}
	}
	fprintf( fp, "Level    %d\n",	ch->level			);
	fprintf( fp, "LostLevel %d\n",	ch->lost_levels		);
	fprintf( fp, "Sex      "	);
	break_bits( fp, ch->sex, "SEX_", TRUE);
	fprintf( fp, "\n"	);
	fprintf( fp, "Class    ");
	break_bits( fp, ch->class, "CLASS_", TRUE);
	fprintf( fp, "\n"	);
	fprintf( fp, "Race     "	);
	break_bits( fp, ch->race, "RACE_", TRUE);
	fprintf( fp, "\n"	);
	fprintf( fp, "Size     "	);
	break_bits( fp, ch->size, "SIZE_", TRUE);
	fprintf( fp, "\n"	);
	fprintf( fp, "Height   %d\n",	ch->height			);
	fprintf( fp, "Weight   %d\n",	ch->weight			);

	if (get_room_index(ch->pcdata->was_in_room) && IS_SET(ch->in_room->room_flags, ROOM_NO_SAVE))
	{
		fprintf( fp, "Room     %u\n",	ch->pcdata->was_in_room);
	}
	else
	{
		fprintf( fp, "Room     %u\n", ch->in_room->vnum);
	}

	if (ch->pcdata->corpse)
	{
		fprintf( fp, "C_Room   %u\n", ch->pcdata->corpse_room	);
	}
	if (ch->pcdata->cart)
	{
		fprintf( fp, "CartRoom %u\n", ch->pcdata->cart_room	);
	}

	fprintf( fp, "LastRoom %d\n",	ch->pcdata->last_real_room	);
	fprintf( fp, "Language %d\n",	ch->language		);
	fprintf( fp, "Speak    %d\n",	ch->speak			);
	for(cnt = 0 ; cnt < MAX_DOMAIN ; cnt++)
	{
		if (!ch->pcdata->domain[cnt])
			continue;
		fprintf (fp, "Domains    ");
		break_bits( fp, cnt, "DOMAIN_", TRUE);
		fprintf( fp, " 1\n"	);
	}
	fprintf( fp, "Created  %d\n",	ch->pcdata->created 			);
	fprintf( fp, "Played   %d\n",	ch->pcdata->played 			);
	fprintf( fp, "K_Played %d\n",	ch->pcdata->killer_played	);
	fprintf( fp, "O_Played %d\n",	ch->pcdata->outcast_played	);
	fprintf( fp, "HpMaMv   %d %d %d %d %d %d\n", ch->hit, ch->max_hit, 0, 0, ch->move, ch->max_move );
	for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
	{
		if (ch->mana[cnt] > 0)
		{
			fprintf( fp, "Mana      "	);
			break_bits( fp, cnt, "CLASS_", TRUE);
			fprintf( fp, " %d\n", ch->mana[cnt]	);
		}
	}
	for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
	{
		if (ch->max_mana[cnt] > 0)
		{
			fprintf( fp, "MaxMana   "	);
			break_bits( fp, cnt, "CLASS_", TRUE);
			fprintf( fp, " %d\n", ch->max_mana[cnt]	);
		}
	}
	fprintf( fp, "Gold     %d\n",	ch->gold );
	fprintf( fp, "Nonlethal %d\n",	ch->nonlethal );
	fprintf( fp, "Bank     %d\n",	ch->pcdata->bank	);
	fprintf( fp, "Exp      %d\n",	ch->pcdata->exp );
	fprintf( fp, "Ansi     %d\n",	ch->pcdata->ansi );
	fprintf( fp, "Vt100    %d\n", ch->pcdata->vt100 ? 2 : 0 );
	fprintf( fp, "Act      %lld\n", ch->act);
	fprintf( fp, "Affects1 "	);
	break_bits( fp, ch->affected_by, "AFF_", FALSE);
	fprintf( fp, "\n"	);
	fprintf( fp, "Affects2 "	);
	break_bits( fp, ch->affected2_by, "AFF2_", FALSE);
	fprintf( fp, "\n"	);
	fprintf( fp, "Practice %d\n",	ch->pcdata->practice	);
	fprintf( fp, "Statpts  %d\n",	ch->pcdata->stat_pts	);
	fprintf( fp, "Featpts  %d\n",	ch->pcdata->feat_pts	);
	fprintf( fp, "SpellBns %d\n",	ch->pcdata->bonus_spells);

	for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
	{
		if (ch->pcdata->bonus_feat[cnt] > 0)
		{
			fprintf( fp, "FeatBonus "	);
			break_bits( fp, cnt, "CLASS_", TRUE);
			fprintf( fp, " %d\n", ch->pcdata->bonus_feat[cnt]	);
		}
	}

	fprintf( fp, "Align    %d\n",	ch->alignment			);
	fprintf( fp, "Ethos    %d\n",	ch->ethos			);
	fprintf( fp, "Function %d\n",	ch->pcdata->functions	);
	fprintf( fp, "Channel  %d\n", ch->pcdata->channel		);

	if (ch->pcdata->clan && ch->pcdata->clan_name[0] != '\0')
	{
		fprintf( fp, "ClanName %s~\n", ch->pcdata->clan_name	);
	}
	if (ch->pcdata->clan_pledge[0] != '\0')
	{
		fprintf( fp, "ClanPled %s~\n", ch->pcdata->clan_pledge	);
	}
	if (ch->pcdata->clan_position != 0)
	{
		fprintf( fp, "ClanPosi %d\n", ch->pcdata->clan_position);
	}
	if (ch->pcdata->last_connect != mud->current_time)
	{
		fprintf( fp, "LastTime %d\n",		(int) mud->current_time	);

	}
	else
	{
		fprintf( fp, "LastTime %ld\n",		ch->pcdata->last_time	);
	}
	fprintf( fp, "Playtime %ld\n",		(int) mud->current_time - ch->pcdata->last_connect);
	fprintf( fp, "Jailtime %ld\n",		ch->pcdata->jailtime	);
	fprintf( fp, "Jaildate %d\n",		ch->pcdata->jaildate	);
	fprintf( fp, "MailAddy %s~\n",	ch->pcdata->mail_address	);
	fprintf( fp, "HtmlAddy %s~\n",	ch->pcdata->html_address	);
	if (ch->pcdata->password != 0)
	{
		fprintf( fp, "Psw      %lld\n",	ch->pcdata->password);
	}
	else
	{
		fprintf( fp, "Password %s~\n",	ch->pcdata->pwd	);
	}
	fprintf( fp, "Bamfin   %s~\n",	ch->pcdata->bamfin		);
	fprintf( fp, "Bamfout  %s~\n",	ch->pcdata->bamfout		);
	fprintf( fp, "Title    %s~\n",	ch->pcdata->title		);
	fprintf( fp, "AttrPerm %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);
	fprintf( fp, "AttrMod  %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 );
	fprintf( fp, "DrFuThAi %d %d %d %d\n",		ch->pcdata->condition[0], ch->pcdata->condition[1], ch->pcdata->condition[2], ch->pcdata->condition[3]);

	for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
	{
		if (ch->mclass[cnt] > 0)
		{
			fprintf( fp, "Mclass   "	);
			break_bits( fp, cnt, "CLASS_", TRUE);
			fprintf( fp, " %d\n", ch->mclass[cnt]	);
		}
	}

	for (cnt = 0 ; cnt < MAX_PVNUM ; cnt++)
	{
		if (ch->pcdata->greeted[cnt])
			fprintf( fp, "Greeted  %d %d\n",	cnt, ch->pcdata->greeted[cnt]	);
	}

	for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
	{
		if (skill_table[sn].skilltype != FSKILL_NONE && ch->learned[sn] > 0)
		{
			fprintf( fp, "Skill    %d '%s'\n", ch->learned[sn], skill_table[sn].name );
		}
	}

	for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
	{
		if (skill_table[sn].skilltype != FSKILL_NONE && ch->imbued[sn] > 0)
		{
			fprintf( fp, "Imbued   %d '%s'\n", ch->imbued[sn], skill_table[sn].name );
		}
	}

	for (cnt = 0 ; sn < MAX_APPLY ; cnt++)
	{
		if (ch->absorption[cnt] > 0)
		{
			fprintf( fp, "Absorb   %d", ch->absorption[sn] );
			break_bits( fp, cnt, "APPLY_", TRUE);
			fprintf( fp, " %d\n", ch->absorption[cnt]	);
		}
	}

	for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
	{
		if (skill_table[sn].skilltype != FSKILL_NONE && ch->uses[sn] > 0)
		{
			fprintf( fp, "Uses     %d '%s'\n", ch->uses[sn], skill_table[sn].name );
		}
	}

	for (cnt = 0 ; cnt < RACE_ENEMY_MAX ; cnt++)
	{
		if (ch->pcdata->race_enemy[cnt] > 0)
		{
			fprintf( fp, "RaceFoe  %d %d\n", cnt, ch->pcdata->race_enemy[cnt] );
		}
	}

	for (cnt = 0 ; cnt < MAX_VNUM ; cnt++)
	{
		if (ch->pcdata->found_dir[cnt] > 0)
		{
			fprintf( fp, "FoundDir %d %d\n", cnt, ch->pcdata->found_dir[cnt] );
		}
	}

	for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
	{
		if (skill_table[sn].skilltype != FSKILL_NONE && ch->pcdata->prepared[sn] > 0)
		{
			fprintf( fp, "Prepd    %d '%s'\n", ch->pcdata->prepared[sn], skill_table[sn].name );
		}
	}

	for (sn = 0 ; sn < MAX_AREA ; sn++)
	{
		if (ch->pcdata->quest[sn])
		{
			fprintf(fp, "Qstb %d %3d ", MAX_QUEST_BYTES, sn);

			for (cnt = 0 ; cnt < MAX_QUEST_BYTES ; cnt++)
			{
				fprintf(fp, "%d ", ch->pcdata->quest[sn][cnt]);
			}
			fprintf(fp, "\n");
		}
	}

	for (cnt = 0 ; cnt < MAX_VNUM ; cnt++)
	{
		if (ch->pcdata->theft_grudge[cnt] > 0)
		{
			fprintf( fp, "GrudgeTh %d %d\n", cnt, ch->pcdata->theft_grudge[cnt] );
		}
	}

	for (cnt = 0 ; cnt < MAX_VNUM ; cnt++)
	{
		if (ch->pcdata->murder_grudge[cnt] > 0)
		{
			fprintf( fp, "GrudgeMd %d %d\n", cnt, ch->pcdata->murder_grudge[cnt] );
		}
	}

	for (cnt = 0 ; cnt <= ch->level ; cnt++)
	{
		if (ch->pcdata->class_level[cnt] > 0)
		{
			fprintf( fp, "ClassLvl  %d ", cnt	);
			break_bits( fp, ch->pcdata->class_level[cnt], "CLASS_", TRUE);
			fprintf( fp, " \n" );
		}
	}

	for (cnt = 0 ; cnt <= ch->level ; cnt++)
	{
		if (ch->pcdata->hit_level[cnt] > 0)
		{
			fprintf( fp, "HPLevel  %d %d\n",	cnt, ch->pcdata->hit_level[cnt]	);
		}
	}

	for (cnt = 0 ; cnt <= ch->level ; cnt++)
	{
		if (ch->pcdata->move_level[cnt] > 0)
		{
			fprintf( fp, "MvLevel  %d %d\n",	cnt, ch->pcdata->move_level[cnt]	);
		}
	}

	for (cnt = 0 ; cnt <= ch->level ; cnt++)
	{
		if (ch->pcdata->pract_level[cnt] > 0)
		{
			fprintf( fp, "PractLvl %d %d\n",	cnt, ch->pcdata->pract_level[cnt]	);
		}
	}

	if (!IS_IMMORTAL(ch))
	{
		for (cnt = 0 ; cnt <= ch->level ; cnt++)
		{
			for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
			{
				if (skill_table[sn].name != NULL && ch->pcdata->skill_level[cnt][sn] > 0)
				{
					fprintf( fp, "SkillLvl %d %d '%s'\n", cnt, ch->pcdata->skill_level[cnt][sn], skill_table[sn].name );
				}
			}
		}
	}

	fprintf( fp, "Speed    %d\n",		ch->speed);
	fprintf( fp, "Prev_hrs %d\n", 	ch->pcdata->previous_hours);
	fprintf( fp, "Tactical %d\n", 	ch->pcdata->tactical_mode);
	fprintf( fp, "Compass  %d\n",		(int) ch->pcdata->compass_width);

	if (IS_IMMORTAL(ch))
	{
		if (ch->pcdata->a_range_lo && ch->pcdata->a_range_hi)
		{
			fprintf( fp, "A_Range  %d %d\n", ch->pcdata->a_range_lo, ch->pcdata->a_range_hi);
		}
	}

	fprintf( fp, "Pvnum    %d\n",		ch->pcdata->pvnum);
	fprintf( fp, "Vt100_T  %d\n",		ch->pcdata->vt100_type );
	fprintf( fp, "Vt100_F  %d\n",		ch->pcdata->vt100_flags );
	fprintf( fp, "Portsize %d\n",		ch->pcdata->port_size );
	fprintf( fp, "Prompt   %s~\n",	ch->pcdata->prompt_layout);
	fprintf( fp, "Spam     %d\n",		ch->pcdata->spam );
	fprintf( fp, "Clock    %d\n",		ch->pcdata->clock);
	fprintf( fp, "Recall   %d\n",		ch->pcdata->recall);
	fprintf( fp, "Reputation  %d\n",	ch->pcdata->reputation);

	for (cnt = 0 ; cnt <= MAX_WAYPOINT ; cnt++)
	{
		if (ch->pcdata->waypoint[cnt])
			fprintf( fp, "Waypoint %d %d\n",	cnt, ch->pcdata->waypoint[cnt]	);
	}

	fprintf( fp, "Death    %d\n",		ch->pcdata->death_room);
	fprintf( fp, "Whichgod %d\n",		ch->god);
	fprintf( fp, "Blocking %s~\n",	ch->pcdata->block_list);
	fprintf( fp, "AutoComm %s~\n",	ch->pcdata->auto_command);
	fprintf( fp, "AutoMode %d\n",		ch->pcdata->auto_flags);
	fprintf( fp, "AuthedBy %s~\n",	ch->pcdata->authed_by);

	fprintf( fp, "LastNote %d\n",		ch->pcdata->last_note );

	for (cnt = 0 ; cnt < MAX_TOPIC ; cnt++)
	{
		fprintf( fp, "Topic    %d %d\n",	cnt, ch->pcdata->topic_stamp[cnt]);
	}

	for (cnt = 0 ; cnt < COLOR_MAX ; cnt++)
	{
		fprintf( fp, "Color    %2d %2d\n",	cnt, ch->pcdata->color[cnt]);
	}

	for (cnt = 0 ; cnt < MAX_ALIAS ; cnt++)
	{
		if (ch->pcdata->alias[cnt][0]!='\0')
		{
			fprintf( fp, "Alias    %s~%s~\n", ch->pcdata->alias_c[cnt], ch->pcdata->alias[cnt]);
		}
	}
	for (paf = ch->first_affect ; paf != NULL ; paf = paf->next)
	{
		if (!valid_skill(paf->type))
		{
			log_printf("save_char_obj: bad affect type: %d", paf->type);
			continue;
		}
		fprintf(fp, "AffectData '%s' %d %d %d %d %lld %d %s\n", skill_table[paf->type].name,	paf->duration,	paf->modifier,	paf->location,	paf->bittype,	paf->bitvector, paf->level, paf->caster);
	}

	for (dis = ch->first_disease ; dis != NULL ; dis = dis->next)
	{
		if (dis->type < 0 || dis->type >= MAX_DISEASE)
		{
			log_printf("save_char_obj: bad disease type: %d", dis->type);
			continue;
		}
		fprintf(fp, "DiseaseData %d %d %d %d\n",
			dis->type, dis->incubation, dis->dc, dis->saves);
	}

	fprintf( fp, "Critical %d\n",	ch->critical_hit_by	);

	if (ch->poison != NULL)
	{
		fwrite_poison_data( ch->poison, fp );
	}

	fprintf( fp, "PK_ATTACKS %d\n", MAX_PK_ATTACKS );

	for (cnt = 0 ; cnt < MAX_PK_ATTACKS ; cnt++)
	{
		fprintf( fp, "%d %d %s~\n", ch->pcdata->last_pk_attack_time[cnt], ch->pcdata->last_pk_attack_pvnum[cnt], ch->pcdata->last_pk_attack_name[cnt]);
	}

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

void load_clan_pit( FILE *fp )
{
	OBJ_INDEX_DATA *pit;
	char letter, loop, *word;

	push_call("fread_clanpit(void)");

	word         = fread_word(fp);
	pit          = obj_index[atol(word)];
	rgObjNest[0] = pit->first_instance;

	for (loop = TRUE ; loop ; )
	{
		letter = fread_letter(fp);

		if (letter != '#')
		{
			log_printf("fread_clan_pit: # not found. Word was '%c%s'", letter, fread_word(fp));
			break;
		}

		word = fread_word(fp);

		switch (word[0])
		{
			case 'O':
				fread_obj(NULL, fp);
				break;

			case 'E':
				loop = FALSE;
				break;

			default:
				log_printf("fread_clan_pit: bad section.");
				loop = FALSE;
				break;
		}
	}
	pop_call();
	return;
}

void save_clan_pit(CLAN_DATA *clan, FILE *fp )
{
	ROOM_INDEX_DATA *location;
	OBJ_DATA *pit;

	push_call("save_clan_pits(void)");

	if ((location = get_room_index(clan->store)) == NULL)
	{
		pop_call();
		return;
	}

	for (pit = location->first_content ; pit ; pit = pit->next_content)
	{
		if (pit->pIndexData->creator_pvnum == clan->founder_pvnum && pit->item_type == ITEM_CONTAINER)
		{
			break;
		}
	}
	if (pit == NULL)
	{
		pop_call();
		return;
	}
	fprintf( fp, "#PIT %d\n\n", pit->pIndexData->vnum);

	fwrite_obj(NULL, pit->first_content, fp, 1);

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

	pop_call();
	return;
}

/*
	Write an object and its first_content.

	Increased speed, no more naughty recursion, objects in unsaved
	containers go to inventory - Scandum april 2002
*/

void fwrite_obj( CHAR_DATA *ch, OBJ_DATA *obj, FILE *fp, char iNest )
{
	AFFECT_DATA *paf;
	DISEASE_DATA *dis;
	int sn;

	push_call("fwrite_obj(%p,%p,%p,%p)",ch,obj,fp,iNest);

	while (obj)
	{
		if (obj->reset || IS_SET(obj->extra_flags, ITEM_NOT_VALID))
		{
			if (obj->first_content != NULL)
			{
				fwrite_obj(ch, obj->first_content, fp, iNest);
			}
			obj = obj->next_content;
			continue;
		}
		else
		{
			fprintf( fp, "#OBJECT\n" );

			if (iNest)
			{
				fprintf(fp, "Nest %d\n", iNest);
			}
			else if (obj->wear_loc != WEAR_NONE)
			{
				fprintf(fp, "WearLoc %s\n", broken_bits(obj->wear_loc, "WEAR_", TRUE));
			}
			if (ch == NULL && iNest == 0)
			{
				fprintf(fp, "InRoom  %d\n", obj->in_room->vnum);
			}			

			/*
			if (!IS_SET(obj->extra_flags, ITEM_MODIFIED) && obj->first_content == NULL
			&& obj->item_type != ITEM_CONTAINER	&& obj->item_type != ITEM_SHEATH
			&& obj->item_type != ITEM_QUIVER && obj->item_type != ITEM_CART && obj->item_type != ITEM_SPELLPOUCH
			&& obj->hit_points == obj->pIndexData->hit_points )
			{
				fprintf(fp, "BasicVnum %d\n", obj->pIndexData->vnum);
			}
			else*/
			{
				/*
					Compact, latest mode for non-basic objects
				*/

				fprintf(fp, "Compact\n");

				fprintf(fp, "%d\n", obj->pIndexData->vnum);

				break_bits( fp, obj->extra_flags, "FLAG_", FALSE);

				fprintf( fp, " %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
					obj->wear_flags,
					obj->item_type,
					obj->weight,
					obj->level,
					obj->timer,
					obj->cost,
					obj->owned_by,
					obj->value[0],
					obj->value[1],
					obj->value[2],
					obj->value[3],
					obj->value[4],
					obj->value[5],
					obj->value[6],
					obj->value[7],
					obj->material,
					obj->hit_points,
					obj->size);

				if (obj->obj_quest)
				{
					int cnt;

					fprintf(fp, "%d ", MAX_QUEST_BYTES);
					for (cnt = 0 ; cnt < MAX_QUEST_BYTES ; cnt++)
					{
						fprintf(fp, "%d ", obj->obj_quest[cnt]);
					}
					fprintf(fp, "\n");
				}
				else
				{
					fprintf(fp, "0\n");
				}

				/*
				 * End of Compact mode, Emud only checks non basic objects - Scandum
				 */
				if (obj->name != obj->pIndexData->name)
				{
					fprintf(fp, "Name %s~\n", obj->name);
				}

				if (obj->short_descr != obj->pIndexData->short_descr)
				{
					fprintf(fp, "Short %s~\n", obj->short_descr);
				}

				if (obj->long_descr != obj->pIndexData->long_descr)
				{
					fprintf(fp, "Long %s~\n", obj->long_descr);
				}

				if (obj->description != obj->pIndexData->description)
				{
					fprintf(fp, "Desc %s~\n", obj->description);
				}
				
				if (obj->identified == TRUE)
					fprintf( fp, "Identified %d\n", 1);

				switch ( obj->item_type )
				{
					case ITEM_SPELLBOOK:
						for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
						{
							if (!is_spell(sn))
								continue;
							if (obj->scribed[sn] > 0)
								fprintf( fp, "Scribed '%s'\n", skill_table[obj->scribed[sn]].name);
						}
						break;
					case ITEM_POTION:
					case ITEM_SCROLL:
					case ITEM_PILL:
						if (obj->value[1] > 0)
						{
							fprintf( fp, "Spell 1 '%s'\n", skill_table[obj->value[1]].name );
						}
						if ( obj->value[2] > 0 )
						{
							fprintf( fp, "Spell 2 '%s'\n", skill_table[obj->value[2]].name );
						}
						if ( obj->value[3] > 0 )
						{
							fprintf( fp, "Spell 3 '%s'\n", skill_table[obj->value[3]].name );
						}
						break;

					case ITEM_PIECE:
						if (obj->value[3] > 0)
						{
							fprintf( fp, "Skill 3 '%s'\n", skill_table[obj->value[3]].name );
						}
						break;

					case ITEM_COMPONENT:
						if (obj->value[1] > 0)
						{
							fprintf( fp, "Uses   %d\n", obj->value[0] );
						}
						if ( obj->value[2] > 0 )
						{
							fprintf( fp, "Poison %d\n", obj->value[1] );
						}
						if ( obj->value[3] > 0 )
						{
							fprintf( fp, "Herb   %d\n", obj->value[2] );
						}
						break;

					case ITEM_STAFF:
					case ITEM_WAND:
						if ( obj->value[3] > 0 )
						{
							fprintf( fp, "Spell 3 '%s'\n", skill_table[obj->value[3]].name );
						}
						if ( obj->value[4] > 0 )
						{
							fprintf( fp, "Spell 4 '%s'\n", skill_table[obj->value[3]].name );
						}
						if ( obj->value[5] > 0 )
						{
							fprintf( fp, "Spell 5 '%s'\n", skill_table[obj->value[3]].name );
						}
						if ( obj->value[6] > 0 )
						{
							fprintf( fp, "Spell 6 '%s'\n", skill_table[obj->value[3]].name );
						}
						break;
				}
				for (paf = obj->first_affect ; paf ; paf = paf->next )
				{
					if (!valid_skill(paf->type))
					{
						log_printf("fwrite_obj: Bad affect: %d", paf->type);
						continue;
					}
					fprintf( fp, "AffectData '%s' %d %d %d %d %lld %d %s\n", skill_table[paf->type].name, paf->duration, paf->modifier, paf->location, paf->bittype, paf->bitvector, paf->level, paf->caster );
				}
				for (dis = obj->first_disease ; dis ; dis = dis->next )
				{
					if (dis->type < 0 || dis->type >= MAX_DISEASE)
					{
						log_printf("fwrite_obj: Bad disease: %d", dis->type);
						continue;
					}
					fprintf(fp, "DiseaseData %d %d %d %d\n",
						dis->type, dis->incubation, dis->dc, dis->saves);
				}
				if (obj->poison != NULL)
				{
					fwrite_poison_data( obj->poison, fp );
				}
			}
			fprintf( fp, "RefKey %lld\nEnd\n\n", obj->obj_ref_key);
		}

		if (obj->first_content != NULL)
		{
			fwrite_obj( ch, obj->first_content, fp, iNest + 1 );
		}
		obj = obj->next_content;
	}
	pop_call();
	return;
}

/*
 * Borrowed from AFKMud's pet saving code - Kregor 7/13/07
 * This will write one mobile structure to file --Shaddai
 *	Edited by Tarl 5 May 2002 to allow pets to load equipment.
 */
void fwrite_mobile( CHAR_DATA * mob, FILE * fp )
{
	AFFECT_DATA *paf;
	DISEASE_DATA *dis;
	OBJ_DATA *obj;
	int cnt, sn;
	
	push_call("fwrite_mobile(%p,%p)",mob,fp);

	if( !IS_NPC( mob ) || !fp )
	{
		pop_call();
		return;
	}

	fprintf( fp, "#MOBILE\n" );
	fprintf( fp, "Vnum        %d\n", mob->pIndexData->vnum );
	fprintf( fp, "Level       %d\n", mob->level );
	fprintf( fp, "LostLevel   %d\n", mob->lost_levels );
	fprintf( fp, "Race     "	);
	break_bits( fp, mob->race, "RACE_", TRUE);
	fprintf( fp, "\n"	);
	fprintf( fp, "Sex      "	);
	break_bits( fp, mob->sex, "SEX_", TRUE);
	fprintf( fp, "\n"	);
	if( mob->in_room )
		fprintf( fp, "Room         %d\n", mob->in_room->vnum );
	else
		fprintf( fp, "Room        %d\n", ROOM_VNUM_TEMPLE );
	if( mob->name && mob->pIndexData->player_name && strcasecmp( mob->name, mob->pIndexData->player_name ) )
		fprintf( fp, "Name        %s~\n", mob->name );
	if( mob->short_descr && mob->pIndexData->short_descr && strcasecmp( mob->short_descr, mob->pIndexData->short_descr ) )
		fprintf( fp, "Short       %s~\n", mob->short_descr );
	if( mob->long_descr && mob->pIndexData->long_descr && strcasecmp( mob->long_descr, mob->pIndexData->long_descr ) )
		fprintf( fp, "Long        %s~\n", mob->long_descr );
	if( mob->description && mob->pIndexData->description && strcasecmp( mob->description, mob->pIndexData->description ) )
		fprintf( fp, "Description %s~\n", fixer(mob->description) );
	fprintf( fp, "Position    %d\n", mob->position );
	fprintf( fp, "Act         " );
	break_bits( fp, mob->act, "ACT_", FALSE);
	fprintf( fp, "\n"	);
	fprintf( fp, "AffectedBy  "	);
	break_bits( fp, mob->affected_by, "AFF_", FALSE);
	fprintf( fp, "\n"	);
	fprintf( fp, "Affected2By %lld\n", mob->affected2_by );
	fprintf( fp, "Armor       %d\n", mob->armor );
	fprintf( fp, "NatArmor    %d\n", mob->nat_armor );
	fprintf( fp, "AttrPerm    %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);
	fprintf( fp, "AttrMod     %d %d %d %d %d %d\n",	mob->mod_str,  mob->mod_int,  mob->mod_wis,  mob->mod_dex, mob->mod_con, mob->mod_cha );

	fprintf( fp, "HpManaMove  %d %d %d %d %d %d\n",
		mob->hit, mob->max_hit, 0, 0, mob->move, mob->max_move );

	for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
	{
		if (mob->mana[cnt] > 0)
		{
			fprintf( fp, "Mana      "	);
			break_bits( fp, cnt, "CLASS_", TRUE);
			fprintf( fp, " %d\n", mob->mana[cnt]	);
		}
	}
	for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
	{
		if (mob->max_mana[cnt] > 0)
		{
			fprintf( fp, "MaxMana   "	);
			break_bits( fp, cnt, "CLASS_", TRUE);
			fprintf( fp, " %d\n", mob->max_mana[cnt]	);
		}
	}

	fprintf( fp, "Nonlethal   %d\n", mob->nonlethal );

	for (paf = mob->first_affect ; paf != NULL ; paf = paf->next)
	{
		if (!valid_skill(paf->type))
		{
			log_printf("fwrite_mobile: bad affect type: %d", paf->type);
			continue;
		}
		fprintf(fp, "AffectData '%s' %d %d %d %d %lld %d %s\n", skill_table[paf->type].name,	paf->duration,	paf->modifier,	paf->location,	paf->bittype,	paf->bitvector, paf->level, paf->caster);
	}
	for (dis = mob->first_disease ; dis != NULL ; dis = dis->next)
	{
		if (dis->type < 0 || dis->type >= MAX_DISEASE)
		{
			log_printf("fwrite_mobile: bad disease type: %d", dis->type);
			continue;
		}
		fprintf(fp, "DiseaseData %d %d %d %d\n",
			dis->type, dis->incubation, dis->dc, dis->saves);
	}

	for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
	{
		if (mob->mclass[cnt] > 0)
		{
			fprintf( fp, "Mclass   "	);
			break_bits( fp, cnt, "CLASS_", TRUE);
			fprintf( fp, " %d\n", mob->mclass[cnt]	);
		}
	}

	for (sn = 0 ; skill_table[sn].name != '\0' ; sn++)
	{
		if (mob->learned[sn] > 0)
		{
			fprintf( fp, "Skill    %d '%s'\n", mob->learned[sn], skill_table[sn].name );
		}
	}

	if( (obj = mob->first_carrying) != NULL )
	{
		fwrite_obj( mob, mob->first_carrying, fp, 0 );
	}

	fprintf( fp, "%s", "EndMobile\n\n" );
	pop_call();
	return;
}


/*
	Load a char and inventory into a new ch structure.
*/

bool load_char_obj( DESCRIPTOR_DATA *d, char *name )
{
	static PC_DATA pcdata_zero;
	char strsave[MAX_INPUT_LENGTH];
	OBJ_DATA	*obj;
	CHAR_DATA *ch, *mob;
	AFFECT_DATA *paf;					
	FILE *fp;
	bool found, loop;
	sh_int cnt, lvl;

	push_call("load_char_obj(%p,%p)",d,name);

	if (name == NULL || *name == '\0')
	{
		pop_call();
		return( FALSE );
	}

	ALLOCMEM(ch, CHAR_DATA, 1 );
 	clear_char( ch );
	ALLOCMEM( ch->pcdata, PC_DATA, 1 );
	*ch->pcdata					= pcdata_zero;
	d->character				= ch;
	ch->desc						= d;

	ch->name									= STRALLOC(capitalize(name));
	ch->short_descr						= STRALLOC( "" );
	ch->description						= STRALLOC( "" );
	ch->pcdata->bio						= STRALLOC( "" );
	ch->long_descr						= STRALLOC( "" );
	ch->pcdata->adjective			= STRALLOC( "" );
	ch->pcdata->pose					= STRALLOC( "" );
	ch->pcdata->disguise			= STRALLOC( "" );
	ch->pcdata->disguise_descr = STRALLOC( "" );

	ch->pcdata->host					= STRALLOC( "" );
	ch->pcdata->mail_address	= STRALLOC( "" );
	ch->pcdata->html_address	= STRALLOC( "" );
	ch->pcdata->clan_name			= STRALLOC( "" );
	ch->pcdata->block_list		= STRALLOC( "" );
	ch->pcdata->title					= STRALLOC( "" );
	ch->pcdata->auto_command	= STRALLOC( "" );
	ch->pcdata->bamfin				= STRALLOC( "" );
	ch->pcdata->bamfout				= STRALLOC( "" );
	ch->pcdata->pwd						= STRALLOC( "" );
	ch->pcdata->practice			= 0;

	for (lvl = 0 ; lvl < MAX_LEVEL ; lvl++)
	{
		ch->pcdata->class_level[lvl] = 0;
		ch->pcdata->hit_level[lvl] = 0;
		ch->pcdata->move_level[lvl] = 0;
		ch->pcdata->pract_level[lvl] = 0;
		for (cnt = 0 ; skill_table[cnt].name != '\0' ; cnt++)
			ch->pcdata->skill_level[lvl][cnt] = 0;
	}

	ch->pcdata->compass_width	= 6;

	if (d->descriptor != -999)
	{
		ch->act							= PLR_AUTOEXIT|PLR_EXP_TO_LEVEL;
		ch->pcdata->channel	= CHANNEL_CHAT|CHANNEL_QUESTION;
		ch->pcdata->condition[COND_THIRST]	= 48;
		ch->pcdata->condition[COND_FULL]		= 48;
		ch->pcdata->condition[COND_AIR]			= get_curr_con(ch) * 2;
		ch->pcdata->reputation							= 10;

		ch->pcdata->last_time				= mud->current_time;
		ch->pcdata->spam						= SPAM_DICE_ROLLS;
		ch->pcdata->tactical_mode		= 6;

		// add account in at player load - Kregor
		if (d->account)
		{
			ch->pcdata->account				= STRALLOC(d->account->player_name);
			d->account->ch						= ch;
		}
		ch->pcdata->edit_buf				= STRDUPE(str_empty);
		ch->pcdata->prompt_layout		= STRALLOC( "{078}<$c$h{078}hp $c$m{078}m $c$v{078}mv $c$X{078}xp> <{178}$e{078}> ($c$l{078}) ($c$L{078}) {300}" );
		ch->pcdata->subprompt				= STRDUPE(str_empty);
		ch->pcdata->tracking				= NULL;
		ch->desc->port_size					= 4096;
		ch->pcdata->port_size				= 4096;
		ch->pcdata->death_room			= ROOM_VNUM_SCHOOL;

		ch->pcdata->clan_pledge			= STRDUPE(str_empty);
		ch->pcdata->vt100_type			= 8024;
		ch->pcdata->vt100_flags			= VT102_FAST|VT100_HIGHLIGHT|VT100_BOLD|VT100_BEEP|VT100_UNDERLINE|VT100_FLASH|VT100_REVERSE;
		ch->pcdata->recall					= ROOM_VNUM_SCHOOL;
		ch->pcdata->scroll_buf[0]		= '\0';

		for (cnt = 0 ; cnt < COLOR_MAX ; cnt++)
		{
			ch->pcdata->color[cnt] = 7 + 8 * 10;
		}

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

		for (cnt = 0 ; cnt < MAX_WEAR ; cnt++)
		{
			ch->pcdata->tattoo[cnt] = STRDUPE(str_empty);
		}
	}

	ch->pcdata->last_real_room		= ROOM_VNUM_TEMPLE;

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

	for (cnt = 0 ; cnt < 26 ; cnt++)
	{
		ch->pcdata->back_buf[cnt] = STRALLOC("\r");
	}

	found = FALSE;

	close_reserve();

	sprintf(strsave, "%s/%c/%s", PLAYER_DIR, tolower(name[0]), capitalize_name(name));

	fp = my_fopen(strsave, "r" , TRUE);

	if (fp != NULL)
	{
		int iNest;

		for (iNest = 0 ; iNest < MAX_NEST ; iNest++)
		{
			rgObjNest[iNest] = NULL;
		}
		if (d->descriptor != -999 && d->descriptor != -998)
		{
			log_god_printf("Loading character file: %s D%d", name, d->descriptor);
		}

		if (!is_valid_file(ch, fp))
		{
			log_printf("Erasing invalid file: %s", name);

			delete_player(ch);

			pop_call();
			return(load_char_obj(d, name));
		}

		found = TRUE;
		loop  = TRUE;

		while (loop)
		{
			char letter;
			char *word;

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

			if ( letter != '#' )
			{
				log_printf("Load_char_obj: # not found.  word was '%c%s'", letter, fread_word( fp ));
				loop = FALSE;
			}

			word = fread_word( fp );

			switch (word[0])
			{
				case 'O':
					fread_obj(ch, fp);
					break;

				case 'P':
					fread_char (ch, fp);

					if (d->descriptor == -999)
					{
						loop = FALSE;
					}
					if (strcasecmp(ch->name, name))
					{
						log_printf("Incorrect name. #END on %s", name );
						loop = FALSE;
					}
					break;

				case 'M':
					mob = NULL;
					mob = fread_mobile( fp );
					if( mob )
					{
						add_follower( mob, ch );
						for (obj = mob->first_carrying ; obj ; obj = obj->next_content)
						{
							if (IS_WORN(obj))
							{
								for (paf = obj->first_affect ; paf ; paf = paf->next)
								{
									switch(paf->location)
									{
										case APPLY_SEX:
											break;
										default:
											affect_modify(mob, paf, TRUE);
											break;
									}
								}
							}
						}
						for (paf = mob->first_affect ; paf ; paf = paf->next)
						{
							switch(paf->location)
							{
								case APPLY_SEX:
									break;
								default:
									affect_modify(mob, paf, TRUE);
									break;
							}
						}
					}
					break;
				
				case 'E':
					loop = FALSE;
					break;

				default:
					log_printf("Load_char_obj: bad section.");
					loop = FALSE;
					break;
			}
		}
		
		if (ch->pcdata->corpse_room)
		{
			for (obj = ch->first_carrying ; obj ; obj = obj->next_content)
			{
				if (obj->item_type == ITEM_CORPSE_PC)
				{
					ch->pcdata->corpse = obj;
				}
			}
		}

		if (ch->pcdata->cart_room)
		{
			for (obj = ch->first_carrying ; obj ; obj = obj->next_content)
			{
				if (obj->item_type == ITEM_CART)
				{
					ch->pcdata->cart = obj;
				}
			}
		}

		if (fp != NULL)
		{
			my_fclose( fp );
		}
	}

	open_reserve();

	/*
		Fix up a few flags -    Chaos 10/1/95
	*/

	if (d->descriptor == -999)
	{
		pop_call();
		return found;
	}

	ch->pcdata->last_saved = mud->current_time;

	if (ch->level >= MAX_LEVEL)
	{
		if (!IS_GOD(ch))
		{
			SET_BIT(pvnum_index[ch->pcdata->pvnum]->flags, PVNUM_DENIED);
		}
		else
		{
			REMOVE_BIT(pvnum_index[ch->pcdata->pvnum]->flags, PVNUM_DENIED);
		}
	}
	
	if (!is_string(ch->pcdata->account))
	{
		if (!d->account)
		{
			log_printf("load_char_obj: character loading outside an account!");
		}
		else
		{
			log_printf("load_char_obj: character with no account. Fixing...");
			ch->pcdata->account = STRALLOC(d->account->player_name);
		}
	}

	if (ch->size <= 0 || ch->size > 9)
		ch->size = race_table[ch->race].size;
		
	if (ch->pcdata->reputation <= 0)
		ch->pcdata->reputation = 10;

	/*
		Check for illegal items, fix bits - Order 7/3/1995
	*/
	fix_object_bits(ch, ch->first_carrying);

	char_reset( ch );
	pop_call();
	return found;
}


/*
	Read in a char.
*/

void fread_char( CHAR_DATA *ch, FILE *fp )
{
	char *word;
	char *line;
	bool fMatch;
	sh_int cnt, tst;
	int x1, x2, x3, x4, x5, x6;

	push_call("fread_char(%p,%p)",ch,fp);

	if (ch == NULL)
	{
		log_printf("Attempt to load a NULL character.");
		pop_call();
		return;
	}

	if (ch->pcdata == NULL)
	{
		log_printf("Attempting to load a player with no pcdata!\n");
		pop_call();
		return;
	}

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

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

			case 'A':
				NKEY("Account",		ch->pcdata->bank,					fread_number(fp));
				NKEY("Act",				ch->act,									fread_number(fp));
				SKEY("Adject",		ch->pcdata->adjective,		fread_string(fp));
				NKEY("Ansi",			ch->pcdata->ansi,					fread_number(fp));
				NKEY("Affects1",	ch->affected_by,					fread_number(fp));
				NKEY("Affects2",	ch->affected2_by,					fread_number(fp));
				NKEY("Align",			ch->alignment,						fread_number(fp));
				NKEY("AutoMode",	ch->pcdata->auto_flags,		fread_number(fp));
				SKEY("AutoComm",	ch->pcdata->auto_command,	fread_string(fp));
				SKEY("AuthedBy",	ch->pcdata->auto_command,	fread_string(fp));
				AKEY("Absorb",		ch->absorption,						fread_number(fp));

				/* Here to get rid of an old tag */
				if ( !strcasecmp( word, "AddLangs" ) )
				{
					fread_number( fp );
					fMatch = TRUE;
					break;
				}
				if ( !strcasecmp( word, "AcMaxMana" ) )
				{
					fread_number( fp );
					fread_number( fp );
					fMatch = TRUE;
					break;
				}
				if ( !strcasecmp( word, "Actuals" ) )
				{
					fread_number( fp );
					fread_number( fp );
					fread_number( fp );
					fMatch = TRUE;
					break;
				}
				if (!strcmp(word, "AffectData"))
				{
					AFFECT_DATA paf;
					int sn;

					sn = skill_lookup(fread_word(fp));

					if (sn < 0)
					{
						log_string("fread_obj: unknown skill.");
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_word( fp );
					}
					else
					{
						paf.type = sn;
						paf.duration	 = fread_number( fp );
						paf.modifier	 = fread_number( fp );
						paf.location	 = fread_number( fp );
						paf.bittype    = fread_number( fp );
						paf.bitvector  = fread_number( fp );
						paf.level      = fread_number( fp );
						paf.caster		 = STRALLOC(fread_word( fp ));
	
						affect_to_char(NULL, ch, &paf);
					}
					fMatch = TRUE;
					break;
				}
				if (!strcmp(word, "AffectData1"))
				{
					AFFECT_DATA paf;
					int sn;

					sn = skill_lookup(fread_word(fp));

					if (sn < 0)
					{
						log_string("fread_obj: unknown skill.");
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_word( fp );
					}
					else
					{
						paf.type = sn;
						paf.duration	 = fread_number( fp );
						paf.modifier	 = fread_number( fp );
						paf.location	 = fread_number( fp );
						paf.bittype    = fread_number( fp );
						paf.bitvector  = fread_number( fp );
						paf.level      = fread_number( fp );
						paf.caster		 = STRALLOC(fread_word( fp ));
	
						affect_to_char(NULL, ch, &paf);
					}
					fMatch = TRUE;
					break;
				}

				if ( !strcasecmp( word, "AttrMod"  ) )
				{
					line = fread_line( fp );
					x1=x2=x3=x4=x5=x6=0;
					sscanf( line, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 );
					ch->mod_str = x1;
					ch->mod_int = x2;
					ch->mod_wis = x3;
					ch->mod_dex = x4;
					ch->mod_con = x5;
					ch->mod_cha = x6;
					fMatch = TRUE;
					break;
				}

				if ( !strcasecmp( word, "AttrPerm" ) )
				{
					line = fread_line( fp );
					x1=x2=x3=x4=x5=x6=13;
					sscanf( line, "%d %d %d %d %d %d",  &x1, &x2, &x3, &x4, &x5, &x6 );
					ch->perm_str = x1;
					ch->perm_int = x2;
					ch->perm_wis = x3;
					ch->perm_dex = x4;
					ch->perm_con = x5;
					ch->perm_cha = x6;
					fMatch = TRUE;
					break;
				}

				if ( !strcmp( word, "Alias" ) )
				{
					tst=0;
					for (cnt = 0 ; cnt < MAX_ALIAS && tst == 0 ; cnt++)
					{
						if (ch->pcdata->alias[cnt][0]=='\0')
						{
							tst=1;
							STRFREE (ch->pcdata->alias[cnt] );
							STRFREE (ch->pcdata->alias_c[cnt] );
							ch->pcdata->alias_c[cnt]=fread_string( fp ) ;
							ch->pcdata->alias[cnt]=fread_string( fp ) ;
						}
					}
					if (tst==0)
					{
						char *ptx1;
						ptx1 = fread_string( fp );
						STRFREE (ptx1 );
						ptx1 = fread_string( fp );
						STRFREE (ptx1 );
					}
					fMatch = TRUE;
					break;
				}

				if (!strcmp( word, "A_Range" ) )
				{
					ch->pcdata->a_range_lo = fread_number(fp);
					ch->pcdata->a_range_hi = fread_number(fp);
					fMatch = TRUE;
					break;
				}
				break;

			case 'B':
				if (!strcasecmp(word, "BAB"))
				{
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				NKEY("Bank",			ch->pcdata->bank,					fread_number(fp));
				SKEY("Bamfin",		ch->pcdata->bamfin,				fread_string(fp));
				SKEY("Bamfout",		ch->pcdata->bamfout,			fread_string(fp));
				SKEY("Blocking",	ch->pcdata->block_list,		fread_string(fp));
				SKEY("Bio",				ch->pcdata->bio,					fread_string(fp));
				break;

			case 'C':
				AKEY("Color",			ch->pcdata->color,				fread_number(fp));
				AKEY("Colorc",		ch->pcdata->color,				fread_number(fp));
				SKEY("ClanName",	ch->pcdata->clan_name,		fread_string(fp));
				SKEY("ClanPled",	ch->pcdata->clan_pledge,	fread_string(fp));
				NKEY("Channel",		ch->pcdata->channel,			fread_number(fp));
				NKEY("ClanPosi",	ch->pcdata->clan_position,fread_number(fp));
				NKEY("Class",			ch->class,								fread_number(fp));
				NKEY("Critical",	ch->critical_hit_by,			fread_number(fp));
				NKEY("Clock",			ch->pcdata->clock,				fread_number(fp));
				NKEY("Compass",		ch->pcdata->compass_width,fread_number(fp));
				NKEY("Created",		ch->pcdata->created,			fread_number(fp));
				AKEY("ClassLvl",	ch->pcdata->class_level,	fread_number(fp));
				NKEY("CartRoom",	ch->pcdata->cart_room,		fread_number(fp));
				NKEY("C_Room",		ch->pcdata->corpse_room,	fread_number(fp));

				if (!strcasecmp(word, "Crime_Data"))
				{
					CRIME_DATA *pcr;

					ALLOCMEM(pcr, CRIME_DATA, 1);

					pcr->crime_record	= fread_string(fp);
					pcr->arrester		= fread_string(fp);
					pcr->date			= fread_number(fp);
					pcr->level		= fread_number(fp);
					pcr->jailtime		= fread_number(fp);
					pcr->released		= fread_number(fp);
					pcr->releaser		= fread_string(fp);

					LINK(pcr, ch->pcdata->first_record, ch->pcdata->last_record, next, prev );
					fMatch = TRUE;
					break;
				}
				break;

			case 'D':
				NKEY("Death",			ch->pcdata->death_room,		fread_number(fp));
				AKEY("Domains",   ch->pcdata->domain,				fread_number(fp));
				SKEY("Domain",		ch->desc->host,						fread_string(fp));

				if ( !strcasecmp( word, "DrFuTh" ) )
				{
					line = fread_line( fp );
					sscanf( line, "%d %d %d", &x1, &x2, &x3 );
					ch->pcdata->condition[0] = x1;
					ch->pcdata->condition[1] = x2;
					ch->pcdata->condition[2] = x3;
					fMatch = TRUE;
					break;
				}
				if ( !strcasecmp( word, "DrFuThAi" ) )
				{
					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;
				}
				if (!strcasecmp(word, "DiseaseData"))
				{
					DISEASE_DATA *dis;

					ALLOCMEM(dis, DISEASE_DATA, 1);
					dis->type				 = fread_number( fp );
					dis->incubation	 = fread_number( fp );
					dis->dc					 = fread_number( fp );
					dis->saves			 = fread_number( fp );

					LINK(dis, ch->first_disease, ch->last_disease, next, prev );
					fMatch = TRUE;
					break;
				}
				break;

			case 'E':
				SKEY("E_Descr",		ch->description,		fread_string(fp));
				if ( !strcasecmp( word, "Enemies" ) )
				{
					fread_number( fp );
					fMatch = TRUE;
					break;
				}

				if ( !strcasecmp( word, "End" ) )
				{
					/*
						ENDLOAD     Chaos  10/11/93
					*/
					if (ch->pcdata->clan_name[0] != '\0')
					{
						if (get_clan(ch->pcdata->clan_name) != NULL)
						{
							ch->pcdata->clan = get_clan(ch->pcdata->clan_name);
						}
						else
						{
							RESTRING(ch->pcdata->clan_name, "");
							ch->pcdata->clan = NULL;
						}
					}
					if (ch->pcdata->vt100_type / 100 < 80 || ch->pcdata->vt100_type / 100 > MAX_TACTICAL_COL)
					{
						ch->pcdata->vt100_type = 8024;
					}
					ch->desc->port_size		= ch->pcdata->port_size;
					ch->position			= POS_STANDING;

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

					if (ch->hit < 0)
					{
						ch->hit = 1;
					}
					if (ch->level < LEVEL_IMMORTAL)
					{
						if (IS_SET(ch->act, PLR_WIZINVIS))
						{
							REMOVE_BIT(ch->act, PLR_WIZINVIS);
						}
						if (IS_SET(ch->act, PLR_WIZCLOAK))
						{
							REMOVE_BIT(ch->act, PLR_WIZCLOAK);
						}
						if (IS_SET(ch->act, PLR_HOLYLIGHT))
						{
							REMOVE_BIT(ch->act, PLR_HOLYLIGHT);
						}
					}
					if (!IS_GOD(ch) && !PLR_FUNCTION(ch, FUNCTION_BUILDER|FUNCTION_BETA_TESTER))
					{
						if (IS_SET(ch->act, PLR_BUILDLIGHT))
						{
							REMOVE_BIT(ch->act, PLR_BUILDLIGHT);
						}
					}

					if (ch->act < 0)
					{
						ch->act = 0;
					}

					add_pvnum(ch);

					REMOVE_BIT(pvnum_index[ch->pcdata->pvnum]->flags, PVNUM_DELETED);

					if (get_room_index(ch->pcdata->recall) == NULL)
					{
						ch->pcdata->recall = ROOM_VNUM_TEMPLE;
					}
					if (get_room_index(ch->pcdata->death_room) == NULL)
					{
						ch->pcdata->death_room = ROOM_VNUM_TEMPLE;
					}
					if (get_room_index(ch->pcdata->was_in_room) == NULL)
					{
						ch->pcdata->was_in_room = ROOM_VNUM_TEMPLE;
					}
					ch->in_room = get_room_index(ch->pcdata->was_in_room);
					pop_call();
					return;
				}

				NKEY("Ethos",			ch->ethos,								fread_number(fp));
				NKEY("Exp",				ch->pcdata->exp,					fread_number(fp));
				break;

			case 'F':
				NKEY("Featpts",		ch->pcdata->feat_pts,			fread_number(fp));
				AKEY("FeatBonus",	ch->pcdata->bonus_feat,		fread_number(fp));
				NKEY("Function",	ch->pcdata->functions,		fread_number(fp));
				if (!strcasecmp(word, "Fort"))
				{
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				AKEY("FoundDir",	ch->pcdata->found_dir,		fread_number(fp));
				if (!strcasecmp( word, "FaithFoe" ) )
				{
					fread_number(fp);
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				break;

			case 'G':
				NKEY("Gold",			ch->gold,									fread_number(fp));
				AKEY("Greeted",		ch->pcdata->greeted,			fread_number(fp));
				AKEY("GrudgeTh",	ch->pcdata->theft_grudge,	fread_number(fp));
				AKEY("GrudgeMd",	ch->pcdata->murder_grudge,fread_number(fp));
				break;

			case 'H':
				NKEY("Height",		ch->height,								fread_number(fp));
				AKEY("HPLevel",		ch->pcdata->hit_level,		fread_number(fp));
				SKEY("HtmlAddy",	ch->pcdata->html_address,	fread_string(fp));

				if (!strcasecmp( word, "History" ) )
				{
					fread_number(fp);
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				if (!strcasecmp( word, "HpMaMv" ) )
				{
					ch->hit		= fread_number(fp);
					ch->max_hit	= fread_number(fp);
					fread_number(fp);
					fread_number(fp);
					ch->move		= fread_number(fp);
					ch->max_move	= fread_number(fp);
					fMatch = TRUE;
					break;
				}
				break;

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

					value = fread_number( fp );

					value = URANGE(0, value, 99);

					sn = skill_lookup( fread_word( fp ) );

					if (sn < 0)
					{
						bug("Fread_char: %s - unknown skill.", ch->name);
					}
					else
					{
						ch->imbued[sn] = value;
					}
					fMatch = TRUE;
				}
				break;
			
			case 'J':
				NKEY("Jaildate",   ch->pcdata->jaildate,				fread_number( fp ) );
				NKEY("Jailtime",   ch->pcdata->jailtime,				fread_number( fp ) );
				break;

			case 'K':
				NKEY("K_Played",	ch->pcdata->killer_played,		fread_number(fp));
				break;

			case 'L':
				NKEY("Level",			ch->level,										fread_number(fp));
				NKEY("LostLevel", ch->lost_levels,							fread_number(fp));
				SKEY("L_Descr",		ch->long_descr,								fread_string(fp));
				NKEY("Language",  ch->language,									fread_number(fp));
				NKEY("LastNote",  ch->pcdata->last_note,				fread_number(fp));
				SKEY("Login",			ch->pcdata->host,							fread_string(fp));
				NKEY("LastTime",	ch->pcdata->last_time,				fread_number(fp));
				NKEY("LastRoom",	ch->pcdata->last_real_room,		fread_number(fp));
				break;

			case 'M':
				AKEY("Mclass",		ch->mclass,										fread_number(fp));
				SKEY("MailAddy",	ch->pcdata->mail_address,			fread_string(fp));
				AKEY("Mana",			ch->mana, fread_number(fp));
				AKEY("MaxMana",		ch->max_mana, fread_number(fp));
				AKEY("MvLevel",		ch->pcdata->move_level,				fread_number(fp));
				break;

			case 'N':
				NKEY("Nonlethal",		ch->nonlethal,							fread_number(fp));
				break;

			case 'O':
				NKEY("O_Played",	ch->pcdata->outcast_played,		fread_number(fp));
				break;

			case 'P':
				NKEY("Psw",					ch->pcdata->password,				fread_number(fp));
				SKEY("Password",		ch->pcdata->pwd,						fread_string(fp));
				NKEY("Played",			ch->pcdata->played,					fread_number(fp));
				SKEY("Player",			ch->pcdata->account,				fread_string(fp));
				NKEY("Practice",		ch->pcdata->practice,				fread_number(fp));
				NKEY("Prev_hrs",		ch->pcdata->previous_hours,	fread_number(fp));
				NKEY("Portsize",		ch->pcdata->port_size,			fread_number(fp));
				SKEY("Prompt",			ch->pcdata->prompt_layout,	fread_string(fp));
				NKEY("Pvnum",				ch->pcdata->pvnum,					fread_number(fp));
				AKEY("PractLvl",		ch->pcdata->pract_level,		fread_number(fp));

				if (!strcmp(word, "PK_ATTACKS"))
				{
					int cnt2;

					cnt = fread_number(fp);

					for (cnt2 = 0 ; cnt2 < cnt ; cnt2++)
					{
						if (cnt2 >= MAX_PK_ATTACKS)
						{
							fread_number(fp);
							fread_number(fp);
							fread_string(fp);
						}
						else
						{
							ch->pcdata->last_pk_attack_time[cnt2]	= fread_number(fp);
							ch->pcdata->last_pk_attack_pvnum[cnt2]	= fread_number(fp);
							STRFREE(ch->pcdata->last_pk_attack_name[cnt2]);
							ch->pcdata->last_pk_attack_name[cnt2]	= fread_string(fp);
						}
					}
					fMatch = TRUE;
					break;
				}
				if (!strcmp( word, "POISON_DATA" ) )
				{
					POISON_DATA *pd;
					pd = fread_poison_data( fp );
					if (pd != NULL && ch->poison != NULL)
					{
						pd->next = ch->poison;
						ch->poison = pd;
					}
					else if (pd != NULL)
					{
						ch->poison = pd;
					}
					fMatch = TRUE;
					break;
				}
				if (!strcmp(word, "Playtime"))
				{
					ch->pcdata->played += fread_number(fp);
					fMatch = TRUE;
					break;
				}
				if ( !strcasecmp( word, "Prepd" ) )
				{
					int sn;
					int value;

					value = fread_number( fp );

					value = URANGE(0, value, 99);

					sn = skill_lookup( fread_word( fp ) );

					if (sn < 0)
					{
						bug("Fread_char: %s - unknown skill.", ch->name);
					}
					else
					{
						ch->pcdata->prepared[sn] = value;
					}
					fMatch = TRUE;
				}
				break;
				
			case 'Q':
				if (!strcasecmp(word, "Qstb"))
				{
					int qn, byt;
					byt = fread_number( fp );
					qn  = fread_number( fp );
					ALLOCMEM(ch->pcdata->quest[qn], bool, MAX_QUEST_BYTES);
					for (cnt = 0 ; cnt < byt ; cnt++)
					{
						ch->pcdata->quest[qn][cnt] = fread_number( fp );
					}
					fMatch = TRUE;
				}
				break;

			case 'R':
				NKEY("Race",				ch->race,										fread_number(fp));
				NKEY("Recall",			ch->pcdata->recall,					fread_number(fp));
				NKEY("Reputation",	ch->pcdata->reputation,			fread_number(fp));
				if (!strcasecmp(word, "Reflex"))
				{
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				NKEY("Room",				ch->pcdata->was_in_room,		fread_number(fp));
				AKEY("RaceFoe",			ch->pcdata->race_enemy,			fread_number(fp));
				break;

			case 'S':
				NKEY("Sex",					ch->sex,										fread_number(fp));
				NKEY("Size",				ch->size,										fread_number(fp));
				SKEY("S_Descr",			ch->short_descr,						fread_string(fp));
				NKEY("Speed",     	ch->speed,									fread_number(fp));
				NKEY("Speak",     	ch->speak,									fread_number(fp));
				NKEY("Spam",      	ch->pcdata->spam,						fread_number(fp));
				NKEY("Statpts",			ch->pcdata->stat_pts,				fread_number(fp));
				if (!strcasecmp( word, "School" ) )
				{
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				if (!strcasecmp( word, "StyleMnk" ) )
				{
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				if (!strcasecmp( word, "StyleRgr" ) )
				{
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				NKEY("SpellBns",		ch->pcdata->bonus_spells,			fread_number(fp));
				if ( !strcasecmp( word, "Skill" ) )
				{
					int sn;
					int value;

					value = fread_number( fp );

					sn = skill_lookup( fread_word( fp ) );

					if (sn < 0)
					{
						bug("Fread_char: %s - unknown skill.", ch->name);
					}
					else
					{
						ch->learned[sn] = value;
					}
					fMatch = TRUE;
				}

				if ( !strcasecmp( word, "SkillLvl" ) )
				{
					int sn, cnt, value;

					cnt		= fread_number( fp );
					value = fread_number( fp );
					sn 		= skill_lookup( fread_word( fp ) );

					if (sn < 0)
					{
						bug("Fread_char: %s - unknown skill.", ch->name);
					}
					else
					{
						ch->pcdata->skill_level[cnt][sn] = value;
					}
					fMatch = TRUE;
				}
				break;

			case 'T':
				if (!strcasecmp( word, "Trust" ) )
				{
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				AKEY("Topic",			ch->pcdata->topic_stamp,			fread_number( fp ) );
				NKEY("Tactical",	ch->pcdata->tactical_mode,		fread_number( fp ) );
				if (!strcasecmp( word, "TactIndx" ) )
				{
					fread_string(fp);
					fMatch = TRUE;
					break;
				}

				if (!strcasecmp(word, "Title"))
				{
					STRFREE(ch->pcdata->title);
					ch->pcdata->title = fread_string(fp);
					set_title(ch, ch->pcdata->title);

					fMatch = TRUE;
					break;
				}
				break;

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

					value = fread_number( fp );

					value = URANGE(0, value, 99);

					sn = skill_lookup( fread_word( fp ) );

					if (sn < 0)
					{
						bug("Fread_char: %s - unknown skill.", ch->name);
					}
					else
					{
						ch->uses[sn] = value;
					}
					fMatch = TRUE;
				}
				break;

			case 'V':
				NKEY("Version",		ch->pcdata->version,					fread_number(fp));
				NKEY("Vt100",     ch->pcdata->vt100,						fread_number(fp));
				NKEY("Vt100_T",		ch->pcdata->vt100_type,				fread_number(fp));
				NKEY("Vt100_F",		ch->pcdata->vt100_flags,			fread_number(fp));
				break;

			case 'W':
				AKEY("Waypoint",	ch->pcdata->waypoint,					fread_number(fp));
				NKEY("Weight",		ch->weight,										fread_number(fp));
				NKEY("Whichgod",	ch->god,											fread_number(fp));
				if (!strcasecmp(word, "Will"))
				{
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				if (!strcasecmp( word, "Wimpy" ) )
				{
					fread_number(fp);
					fMatch = TRUE;
					break;
				}
				break;
		}

		if ( !fMatch )
		{
			bug("fread_char: no match: (word) %s (line) %s", word, fread_line(fp));
		}
	}
	log_printf("do_pload: Got this far!");
	
	pop_call();
	return;
}

void fread_obj( CHAR_DATA *ch, FILE *fp )
{
	OBJ_DATA *obj;
	char *word;
	int BasicVnum, WearLoc, InRoom;
	bool fMatch, iNest;

	push_call("fread_obj(%p,%p)",ch,fp);

	BasicVnum	= 0;
	WearLoc		= WEAR_NONE;
	iNest			= 0;

	ALLOCMEM(obj, OBJ_DATA, 1);

	obj->pIndexData		= obj_index[OBJ_VNUM_MUSHROOM];

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

		switch ( UPPER(word[0]) )
		{
			case 'A':
				if (!strcmp(word, "AffectData"))
				{
					AFFECT_DATA paf;
					int sn;

					sn = skill_lookup(fread_word(fp));

					if (sn < 0)
					{
						log_string("fread_obj: unknown skill.");
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_word( fp );
					}
					else
					{
						paf.type = sn;
						paf.duration	 = fread_number( fp );
						paf.modifier	 = fread_number( fp );
						paf.location	 = fread_number( fp );
						paf.bittype    = fread_number( fp );
						paf.bitvector  = fread_number( fp );
						paf.level      = fread_number( fp );
						paf.caster		 = STRALLOC(fread_word( fp ));
	
						affect_to_obj(NULL, obj, &paf);
					}
					fMatch = TRUE;
					break;
				}

				if (!strcmp(word, "AffectData1"))
				{
					AFFECT_DATA paf;
					int sn;

					sn = skill_lookup(fread_word(fp));

					if (sn < 0)
					{
						log_string("fread_obj: unknown skill.");
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_word( fp );
					}
					else
					{
						paf.type = sn;
						paf.duration	 = fread_number( fp );
						paf.modifier	 = fread_number( fp );
						paf.location	 = fread_number( fp );
						paf.bittype    = fread_number( fp );
						paf.bitvector  = fread_number( fp );
						paf.level      = fread_number( fp );
						paf.caster		 = STRALLOC(fread_word( fp ));
	
						affect_to_obj(NULL, obj, &paf);
					}
					fMatch = TRUE;
					break;
				}
				break;

			case 'B':
				NKEY("BasicVnum", 	BasicVnum,		fread_number( fp ) );
				break;

			case 'C':
				if (!strcmp(word, "Compact"))
				{
					int byt, cnt, vnum;

					fread_to_eol( fp );

					vnum = fread_number(fp);

					if ((obj->pIndexData = get_obj_index(vnum)) == NULL)
					{
						if (IS_SET(mud->flags, MUD_EMUD_REALGAME))
						{
							log_printf("fread_obj: bad vnum %d.", vnum);
						}
						obj->pIndexData = obj_index[OBJ_VNUM_MUSHROOM];
					}
					obj->extra_flags	= fread_number( fp );
					obj->wear_flags	= fread_number( fp );
					obj->item_type	= fread_number( fp );
					obj->weight			= fread_number( fp );
					obj->level			= fread_number( fp );
					obj->timer			= fread_number( fp );
					obj->cost				= fread_number( fp );
					obj->owned_by		= fread_number( fp );
					obj->value[0]		= fread_number( fp );
					obj->value[1]		= fread_number( fp );
					obj->value[2]		= fread_number( fp );
					obj->value[3]		= fread_number( fp );
					obj->value[4]		= fread_number( fp );
					obj->value[5]		= fread_number( fp );
					obj->value[6]		= fread_number( fp );
					obj->value[7]		= fread_number( fp );
					obj->material		= fread_number( fp );
					obj->hit_points	= fread_number( fp );
					obj->size				= fread_number( fp );

					byt 				= fread_number( fp );
					if (byt != 0)
					{
						ALLOCMEM( obj->obj_quest, unsigned char, MAX_QUEST_BYTES );
						for (cnt = 0 ; cnt < byt ; cnt++)
						{
							obj->obj_quest[cnt] = fread_number( fp );
						}
					}
					fMatch = TRUE;
					break;
				}
				break;

			case 'D':
				SKEY("Desc",		obj->description,	fread_string( fp ) );
				if (!strcmp(word, "DiseaseData"))
				{
					DISEASE_DATA *dis;

					ALLOCMEM(dis, DISEASE_DATA, 1);
					dis->type				 = fread_number( fp );
					dis->incubation	 = fread_number( fp );
					dis->dc					 = fread_number( fp );
					dis->saves			 = fread_number( fp );

					LINK (dis, obj->first_disease, obj->last_disease, next, prev);
					fMatch = TRUE;
					break;
				}
				break;

			case 'E':
				if (!strcmp(word, "End"))
				{
					if (BasicVnum == 0)
					{
						if (obj->owned_by 		== 0
						&&  obj->first_affect	== NULL
						&&	obj->item_type		== obj->pIndexData->item_type
						&&	obj->extra_flags	== obj->pIndexData->extra_flags
						&&	obj->wear_flags		== obj->pIndexData->wear_flags
						&&  obj->value[0] 		== obj->pIndexData->value[0]
						&&  obj->value[1] 		== obj->pIndexData->value[1]
						&&  obj->value[2] 		== obj->pIndexData->value[2]
						&&  obj->value[3] 		== obj->pIndexData->value[3]
						&&  obj->value[4] 		== obj->pIndexData->value[4]
						&&  obj->value[5] 		== obj->pIndexData->value[5]
						&&  obj->value[6] 		== obj->pIndexData->value[6]
						&&  obj->value[7] 		== obj->pIndexData->value[7]
						&&  obj->weight 			== obj->pIndexData->weight
						&&  obj->material 		== obj->pIndexData->material
						&&  obj->hit_points 	== obj->pIndexData->hit_points
						&&  obj->size				 	== obj->pIndexData->size
						&&  obj->timer        == 0
						&&  obj->obj_quest		== NULL
						&&  obj->poison				== NULL
						&&  obj->short_descr	== NULL)
						{
							REMOVE_BIT(obj->extra_flags, ITEM_MODIFIED);
						}
						else
						{
							SET_BIT(obj->extra_flags, ITEM_MODIFIED);
						}
					}
					else
					{
						OBJ_INDEX_DATA *pObjIndex;

						if ((pObjIndex = get_obj_index(BasicVnum)) == NULL)
						{
							if (IS_SET(mud->flags, MUD_EMUD_REALGAME))
							{
								log_printf("fread_obj: bad vnum %d.", BasicVnum);
							}
							BasicVnum	= OBJ_VNUM_MUSHROOM;
							pObjIndex	= get_obj_index(BasicVnum);
						}
						obj->pIndexData		= pObjIndex;

						obj->level				= pObjIndex->level;

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

					/*
						Special chains of the Gods
					*/

					if (BasicVnum == 0)
					{
						if (obj->level <= 0 || obj->level < obj->pIndexData->level)
						{
							obj->level = obj->pIndexData->level;
						}

						if (obj->name == NULL)
						{
							STRFREE( obj->name );
							obj->name = STRDUPE(obj->pIndexData->name);
						}
						if (obj->short_descr == NULL)
						{
							STRFREE( obj->short_descr );
							obj->short_descr = STRDUPE(obj->pIndexData->short_descr);
						}
						if (obj->long_descr == NULL)
						{
							STRFREE( obj->long_descr );
							obj->long_descr = STRDUPE(obj->pIndexData->long_descr);
						}
						if (obj->description == NULL)
						{
							STRFREE( obj->description );
							obj->description = STRDUPE(obj->pIndexData->description);
						}

						if (strcasecmp(obj->name, obj->pIndexData->name)
						||	strcasecmp(obj->short_descr, obj->pIndexData->short_descr)
						||	strcasecmp(obj->long_descr, obj->pIndexData->long_descr)
						||	strcasecmp(obj->description, obj->pIndexData->description))
						{
							SET_BIT(obj->extra_flags, ITEM_MODIFIED);
						}
					}
					obj->wear_loc    = WearLoc;
					rgObjNest[iNest] = obj;

					if (iNest == 0)
					{
						if (ch != NULL)
							obj_to_char(obj, ch);
						else
							obj_to_room(obj, InRoom);
					}
					else
					{
						obj_to_obj(obj, rgObjNest[iNest-1]);
					}

					LINK(obj, mud->f_obj, mud->l_obj, next, prev);
					LINK(obj, obj->pIndexData->first_instance, obj->pIndexData->last_instance, next_instance, prev_instance);
					add_obj_ref_hash( obj );

					mud->total_obj++;
					obj->pIndexData->total_objects++;

					pop_call();
					return;
				}
				break;

			case 'H':
				NKEY("Herb",		obj->value[2],	fread_number(fp));
				break;

			case 'I':
				NKEY("InRoom",		InRoom,	fread_number(fp));
				NKEY("Identified",	obj->identified,	fread_number(fp));
				break;

			case 'L':
				SKEY("Long",		obj->long_descr,	fread_string(fp));
				break;

			case 'N':
				NKEY("Nest",		iNest,			fread_number(fp));
				SKEY("Name",		obj->name,		fread_string(fp));
				break;

			case 'P':
				NKEY("Poison",		obj->value[1],	fread_number(fp));
				if (!strcmp(word, "POISON_DATA"))
				{
					POISON_DATA *pd;
					pd = fread_poison_data( fp );

					if (pd != NULL)
					{
						if (obj->poison != NULL)
						{
							pd->next = obj->poison;
							obj->poison = pd;
						}
						else	if (pd != NULL)
						{
							obj->poison = pd;
						}
					}
					fMatch = TRUE;
					break;
				}
				break;

			case 'R':
				NKEY("RefKey",	obj->obj_ref_key,	fread_number(fp));
				break;

			case 'S':
				SKEY("Short",		obj->short_descr,	fread_string(fp));
				if (!strcasecmp(word, "Scribed"))
				{
					int sn;
					
					if ((sn = skill_lookup(fread_word(fp))) == -1)
					{
						log_string("Fread_obj(Scribed): unknown skill.");
					}
					else
					{
						obj->scribed[sn] = 1;
					}
					fMatch = TRUE;
					break;
				}
				if ( !strcasecmp( word, "Spell" ) )
				{
					int iValue, sn;

					iValue	= fread_number( fp );
					sn		= skill_lookup( fread_word( fp ) );
					if (iValue < 1 || iValue > 7)
					{
						log_printf("Fread_obj(Spell): bad iValue %d.", iValue );
					}
					else if (sn < 0)
					{
						log_string("Fread_obj: unknown skill.");
					}
					else
					{
						obj->value[iValue] = sn;
					}
					fMatch = TRUE;
					break;
				}
				if ( !strcasecmp( word, "Skill" ) )
				{
					int iValue, sn;

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

			case 'U':
				NKEY("Uses",		obj->value[0],	fread_number(fp));
				break;

			case 'W':
				NKEY("WearLoc",	WearLoc,		fread_number(fp));
				break;
		}
		if (!fMatch)
		{
			fread_to_eol( fp );
			log_printf("Fread_obj: no match: %s", word);
		}
	}
}


/*
 * Borrowed from AFKMud's pet saving code - Kregor 7/13/07
 * This will read one mobile structure from file - Shaddai
 *	Edited by Tarl 5 May 2002 to allow pets to load equipment.
 */
CHAR_DATA *fread_mobile( FILE * fp )
{
	CHAR_DATA *mob = NULL;
	const char *word;
	bool fMatch;
	char *line;
	int inroom = 0, cnt, x1, x2, x3, x4, x5, x6;
	MOB_INDEX_DATA *pMobIndex = NULL;

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

	word = feof( fp ) ? "EndVendor" : fread_word( fp );

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

		vnum = fread_number( fp );
		pMobIndex = get_mob_index( vnum );
		if( !pMobIndex )
		{
			for( ;; )
			{
				word = feof( fp ) ? "EndVendor" : fread_word( fp );

				if( !strcasecmp( word, "EndMobile" ) )
					break;
			}
			bug( "Fread_mobile: No index data for vnum %d", vnum );
			pop_call();
			return NULL;
		}
		mob = create_mobile( pMobIndex );
	}
	else
	{
		for( ;; )
		{
			word = feof( fp ) ? "EndVendor" : fread_word( fp );
			/*
			 * So we don't get so many bug messages when something messes up
			 * * --Shaddai
			 */
			if( !strcasecmp( word, "EndMobile" ) )
				break;
		}
		extract_char( mob );
		bug( "%s: Vnum not found",0 );
		pop_call();
		return NULL;
	}

	for( ;; )
	{
		word = feof( fp ) ? "EndVendor" : fread_word( fp );

		fMatch = FALSE;
		switch ( UPPER( word[0] ) )
		{
			case '*':
				fMatch = TRUE;
				fread_to_eol( fp );
				break;
			case 'A':
				if (!strcmp(word, "AffectData"))
				{
					AFFECT_DATA paf;
					int sn;

					sn = skill_lookup(fread_word(fp));

					if (!valid_skill(sn))
					{
						log_string("fread_obj: unknown skill.");
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_number( fp );
						fread_word( fp );
					}
					else
					{
						paf.type = sn;
						paf.duration	 = fread_number( fp );
						paf.modifier	 = fread_number( fp );
						paf.location	 = fread_number( fp );
						paf.bittype    = fread_number( fp );
						paf.bitvector  = fread_number( fp );
						paf.level      = fread_number( fp );
						paf.caster		 = STRALLOC(fread_word( fp ));
	
						affect_to_char(NULL, mob, &paf);
					}
					fMatch = TRUE;
					break;
				}
				NKEY( "Act", mob->act, fread_number( fp ) );
				NKEY( "AffectedBy", mob->affected_by, fread_number( fp ) );
				NKEY( "Affected2By", mob->affected2_by, fread_number( fp ) );
				NKEY( "Armor", mob->armor, fread_number( fp ) );
				if ( !strcasecmp( word, "AttrMod"  ) )
				{
					line = fread_line( fp );
					x1=x2=x3=x4=x5=x6=0;
					sscanf( line, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 );
					mob->mod_str = x1;
					mob->mod_int = x2;
					mob->mod_wis = x3;
					mob->mod_dex = x4;
					mob->mod_con = x5;
					mob->mod_cha = x6;
					fMatch = TRUE;
					break;
				}

				if ( !strcasecmp( word, "AttrPerm" ) )
				{
					line = fread_line( fp );
					x1=x2=x3=x4=x5=x6=13;
					sscanf( line, "%d %d %d %d %d %d",  &x1, &x2, &x3, &x4, &x5, &x6 );
					mob->perm_str = x1;
					mob->perm_int = x2;
					mob->perm_wis = x3;
					mob->perm_dex = x4;
					mob->perm_con = x5;
					mob->perm_cha = x6;
					fMatch = TRUE;
					break;
				}

				break;

			case 'D':
				SKEY( "Description", mob->description, fread_string( fp ) );
				if (!strcasecmp(word, "DiseaseData"))
				{
					DISEASE_DATA *dis;

					ALLOCMEM(dis, DISEASE_DATA, 1);
					dis->type				 = fread_number( fp );
					dis->incubation	 = fread_number( fp );
					dis->dc					 = fread_number( fp );
					dis->saves			 = fread_number( fp );

					LINK(dis, mob->first_disease, mob->last_disease, next, prev );
					fMatch = TRUE;
					break;
				}
				break;

			case 'E':
				if( !strcasecmp( word, "EndMobile" ) )
				{
					if( inroom == 0 )
						inroom = ROOM_VNUM_TEMPLE;
					if( room_index[inroom] == NULL )
						inroom = ROOM_VNUM_LIMBO;
					char_to_room( mob, inroom, TRUE );
					act( "$n has entered the game.", mob, NULL, NULL, TO_ROOM);
					/*
						Check for illegal items, fix bits - Order 7/3/1995
					*/
					fix_object_bits(mob, mob->first_carrying);
				
					char_reset( mob );

					pop_call();
					return mob;
				}
				break;

			case 'H':
				if( !strcasecmp( word, "HpManaMove" ) )
				{
					mob->hit = fread_number( fp );
					mob->max_hit = fread_number( fp );
					fread_number( fp );
					fread_number( fp );
					mob->move = fread_number( fp );
					mob->max_move = fread_number( fp );
					fMatch = TRUE;
					break;
				}
				break;

			case 'L':
				NKEY( "Level", mob->level, fread_number( fp ) );
				NKEY( "LostLevel", mob->lost_levels, fread_number( fp ) );
				SKEY( "Long", mob->long_descr, fread_string( fp ) );
				break;

			case 'M':
				AKEY( "Mclass", mob->mclass, fread_number( fp ) );
				AKEY(	"Mana",			mob->mana, fread_number(fp));
				AKEY(	"MaxMana",	mob->max_mana, fread_number(fp));
				break;

			case 'N':
				SKEY( "Name", mob->name, fread_string( fp ) );
				NKEY("Nonlethal", mob->nonlethal, fread_number(fp));
				NKEY( "NatArmor", mob->nat_armor, fread_number( fp ) );
				break;

			case 'P':
				NKEY( "Position", mob->position, fread_number( fp ) );
				break;

			case 'R':
				NKEY( "Room", inroom, fread_number( fp ) );
				NKEY( "Race", mob->race, fread_number( fp ) );
				break;

			case 'S':
				NKEY( "Sex", mob->sex, fread_number( fp ) );
				SKEY( "Short", mob->short_descr, fread_string( fp ) );
				if ( !strcasecmp( word, "Skill" ) )
				{
					int sn;
					int value;

					value = fread_number( fp );

					sn = skill_lookup( fread_word( fp ) );

					if (sn < 0)
					{
						bug("Fread_char: %s - unknown skill.", mob->name);
					}
					else
					{
						mob->learned[sn] = value;
					}
					fMatch = TRUE;
				}
				break;
		}
		if( !strcasecmp( word, "#OBJECT" ) )
		{
			fread_obj( mob, fp );
			fMatch = TRUE;
		}
		if( !fMatch )
		{
			bug( "%s: no match: %s", word );
			fread_to_eol( fp );
		}
	}
}


/*
	This routine makes sure that files are not cross linked of chopped
	Chaos  - 5/30/96
*/

bool is_valid_file( CHAR_DATA *ch, FILE *fp )
{
	char buf[MAX_INPUT_LENGTH];
	sh_int cnt, cf;

	push_call("is_valid_File(%p,%p)",ch,fp);

	cf  = ' ';
	cnt = 0;

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

	if (cnt == -50)
	{
		log_printf("Didn't find an #END on %s", ch->name);
		rewind( fp );
		pop_call();
		return( FALSE );
	}

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

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

	if (str_prefix("#END ", buf))
	{
		log_printf("Didn't find an #END on %s", ch->name);
		rewind( fp );
		pop_call();
		return( FALSE );
	}

	if (!strcasecmp(ch->name, &buf[5]))
	{
		rewind( fp );
		pop_call();
		return( TRUE );
	}

	log_printf("Cross linked file %s on %s", buf, ch->name );
	rewind( fp );
	pop_call();
	return( FALSE );
}

int total_language( CHAR_DATA *ch )
{
	int total, cnt;

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

	for (total = 0, cnt = 0 ; cnt < MAX_RACE ; cnt++)
	{
		if (IS_SET(ch->language, SHIFT(cnt)))
		{
			total++;
		}
	}
	pop_call();
	return( total );
}

/*
	Let's save that poison data   -  Chaos 4/20/99
*/

void fwrite_poison_data( POISON_DATA *pd, FILE *fp )
{
	push_call("fwrite_poison_data(%p,%p)",pd,fp);

	fprintf( fp, "POISON_DATA 1 %d %d %d %d %d\n",
		(int) pd->type,
		pd->dc,
		pd->constant_duration,
		pd->owner,
		pd->poisoner );

	if (pd->next != NULL)
	{
		fwrite_poison_data( pd->next, fp );
	}
	pop_call();
	return;
}

POISON_DATA *fread_poison_data( FILE *fp )
{
	POISON_DATA *pd;
	int ptype;

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

	ALLOCMEM( pd, POISON_DATA, 1 );

	if ((ptype = fread_number( fp )) == 1)
	{
		pd->type			= (sh_int)fread_number(fp);
		pd->dc				= fread_number(fp);
		pd->constant_duration	= fread_number(fp);
		pd->owner			= fread_number(fp);
		pd->poisoner	= fread_number(fp);
		pd->next			= NULL;

		pop_call();
		return( pd );
	}
	else
	{
		fread_to_eol( fp );
	}

	FREEMEM( pd );

	pop_call();
	return( NULL );
}

/*
	Hypnos 20020326: Check player directories
*/

int check_dirs( void )
{
	int  i, dir;
	char	tempbuf[320];

	push_call("check_dirs()");

	dir = 0;

	if (mkdir(PLAYER_DIR, XX_DIRMASK) == -1)
	{
		if (errno != EEXIST)
		{
			pop_call();
			return -1;
		}
	}
	else
	{
		dir++;
	}

	for (i = 0 ; i < 26 ; i++)
	{
		sprintf(tempbuf, "%s/%c", PLAYER_DIR, 'a' + i);

		if (mkdir(tempbuf, XX_DIRMASK) == -1)
		{
			if (errno != EEXIST)
			{
				pop_call();
				return -1;
			}
		}
		else
		{
			dir++;
		}

		sprintf(tempbuf, "%s/%c/dmp", PLAYER_DIR, 'a' + i);
	
		if (mkdir(tempbuf, XX_DIRMASK) == -1)
		{
			if (errno != EEXIST)
			{
				pop_call();
				return -1;
			}
		}
		else
		{
			dir++;
		}
	
		sprintf(tempbuf, "%s/%c/del", PLAYER_DIR, 'a' + i);
	
		if (mkdir(tempbuf, XX_DIRMASK) == -1)
		{
			if (errno != EEXIST)
			{
				pop_call();
				return -1;
			}
		}
		else
		{
			dir++;
		}
	
		sprintf(tempbuf, "%s/%c/bak", PLAYER_DIR, 'a' + i);
	
		if (mkdir(tempbuf, XX_DIRMASK) == -1)
		{
			if (errno != EEXIST)
			{
				pop_call();
				return -1;
			}
		}
		else
		{
			dir++;
		}
	}

	pop_call();
	return dir;
}

/*
 * Inspired by Locker Code by Aidan 5/4/2006
 * immortal@chaos-ascending.com 
 * severely modified for existing obj read and write codes.
 */ 
void save_lockers( )
{
	FILE *LockerFile;
	ROOM_INDEX_DATA *room;
	OBJ_DATA *obj = NULL;
	int vnum;
	
	/* Close the reserve file */
	fclose(fpReserve);
	/* Open the Locker File for saving */
	LockerFile = my_fopen(LOCKER_FILE, "w", TRUE);

	/* Okay, lets loop through all of the rooms on the game */
	for(vnum = 0; vnum < MAX_VNUM; vnum++)
	{
		if((room = get_room_index(vnum)) != NULL)
		{
			/* Is this a storeroom? */
			if(!IS_SET(room->room_flags, ROOM_CLANSTOREROOM))
				continue;
			if ((obj = room->first_content) != NULL)
				fwrite_obj(NULL,obj,LockerFile,0);
		}
	}

	fprintf(LockerFile,"#END\n");

	fclose(LockerFile);
	fpReserve = my_fopen(NULL_FILE, "r", FALSE);
	return;
}

void load_lockers( )
{
	FILE *LockerFile;
	char letter;
	char *word;

	fclose(fpReserve);
	if((LockerFile = my_fopen(LOCKER_FILE, "r", FALSE)) == NULL)
	{
		log_string("No locker file found.");
		fclose(LockerFile);
		fpReserve = my_fopen(NULL_FILE,"r",FALSE);
		return;
	}

	for( ; ; )
	{
		letter = fread_letter(LockerFile);

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

		word = fread_word(LockerFile);

		if(!strcasecmp(word,"OBJECT"))
			fread_obj(NULL, LockerFile);
		else if(!strcasecmp(word,"END"))
			break;
		else
		{
			bug("Load_Lockers: bad section.",0);
			break;
		}
	}
	fclose(LockerFile);
	fpReserve = my_fopen(NULL_FILE,"r",FALSE);
	return;
}


/**************************************************
 * start new account stuff - Kregor
 */
/*
 * initialize a new account, load in
 * saved account info if available bilink
 * with player decriptor - Kregor
 */
bool add_account( DESCRIPTOR_DATA *d, char *name )
{
	ACCOUNT_DATA *acct;
	FILE *fp;
	char strload[MAX_INPUT_LENGTH];
	bool found = FALSE;
	int cnt;

	push_call("add_account(%p,%p)",d,name);

	ALLOCMEM(acct, ACCOUNT_DATA, 1);
	d->account = acct;
	acct->desc = d;

	acct->player_name = STRALLOC(name);
	acct->pwd = STRALLOC("");
	acct->rp_points = 0;
	acct->last_connect = 0;
	acct->last_time = 0;
	acct->functions = 0;
	
	for (cnt = 0 ; cnt < MAX_PC ; cnt++)
	{
		acct->character[cnt] = 0;
	}
	
	close_reserve();

	sprintf(strload, "%s/%c/%s", ACCOUNT_DIR, tolower(name[0]), capitalize_name(name));

	if ((fp = my_fopen(strload, "r" , TRUE)) != NULL)
	{
		found = TRUE;
		fread_account(acct, fp);
		my_fclose(fp);
	}

	open_reserve();
	
	acct->desc = d;
	d->account = acct;

	mud->total_acct++;

	LINK(acct, mud->f_acct, mud->l_acct, next, prev);

	pop_call();
	return found;
}

/*
 * close an open account and free memory - Kregor
 */
void free_account( ACCOUNT_DATA *acct )
{
	push_call("free_account(%p)",acct);
	
	acct->desc->account = NULL;
	acct->desc = NULL;
	acct->ch = NULL;

	if ((acct->prev == NULL && acct != mud->f_acct)
	||  (acct->next == NULL && acct != mud->l_acct))
	{
		log_printf("UNLINK ERROR unlinking account %s.", acct->player_name);
	}
	else
	{
		UNLINK(acct, mud->f_acct, mud->l_acct, next, prev);
	}
	
	mud->total_acct--;

	STRFREE(acct->player_name);

	FREEMEM(acct);
	
	pop_call();
	return;
}


void fread_account( ACCOUNT_DATA *acct, FILE *fp )
{
	char *word;
	bool fMatch;
	sh_int cnt;

	push_call("fread_account(%p,%p)",acct,fp);

	if (acct == NULL)
	{
		log_printf("Attempt to load a NULL account.");
		pop_call();
		return;
	}

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

		fMatch = FALSE;

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

			case 'A':
				NKEY("Ansi",			acct->ansi,						fread_number(fp));
				break;

			case 'C':
				AKEY("Chars",		  acct->character,			fread_number(fp));
				break;

			case 'E':
				if ( !strcasecmp( word, "End" ) )
				{
					pop_call();
					return;
				}
				break;

			case 'F':
				NKEY("Function",	acct->functions,			fread_number(fp));
				break;

			case 'L':
				NKEY("LastTime",	acct->last_time,			fread_number(fp));
				break;

			case 'N':
				SKEY("Name",			acct->player_name,		fread_string(fp));

			case 'P':
				NKEY("Psw",				acct->password,				fread_number(fp));
				NKEY("Played",		acct->played,					fread_number(fp));
				if (!strcmp(word, "Playtime"))
				{
					acct->played += fread_number(fp);
					fMatch = TRUE;
					break;
				}
				break;

			case 'R':
				NKEY("RPPoints",	acct->rp_points,			fread_number(fp));
				break;

			case 'V':
				NKEY("Vt100",			acct->vt100,					fread_number(fp));
				break;
		}
		if ( !fMatch )
		{
			bug("fread_account: no match: (word) %s (line) %s", word, fread_line(fp));
		}
	}
	pop_call();
	return;
}


void fwrite_acct( ACCOUNT_DATA *acct, FILE *fp )
{
	int cnt;

	push_call("fwrite_acct(%p,%p)",acct,fp);

	fprintf( fp, "Name     %s~\n", 	acct->player_name);
	fprintf( fp, "Function "	);
	break_bits( fp, acct->functions, "FUNCTION_", TRUE);
	fprintf( fp, "\n"	);
	fprintf( fp, "Psw      %lld\n",	acct->password);
	fprintf( fp, "Played   %d\n",		acct->played);
	fprintf( fp, "Ansi     %d\n",		acct->ansi);
	fprintf( fp, "Vt100    %d\n", 	acct->vt100 ? 2 : 0);

	if (acct->ch && acct->ch->pcdata->last_connect != mud->current_time)
	{
		fprintf( fp, "LastTime %d\n",		(int) mud->current_time	);
	}
	else
	{
		fprintf( fp, "LastTime %ld\n",		acct->last_time	);
	}
	fprintf( fp, "Playtime %ld\n",		acct->ch ? (int) mud->current_time - acct->ch->pcdata->last_connect : 0);
	fprintf( fp, "RPPoints %d\n",		acct->rp_points);

	for (cnt = 0 ; cnt < MAX_PC ; cnt++)
	{
		if (acct->character[cnt] > 0)
		{
			fprintf( fp, "Chars     %d %d\n", cnt, acct->character[cnt]	);
		}
	}

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


/*
 * Calls the account file to save
 * call this function in save_char_obj
 * in order to use safeguards - Kregor
 */
void save_account( DESCRIPTOR_DATA *d )
{
	char strsave[MAX_INPUT_LENGTH], strtemp[MAX_INPUT_LENGTH];
	char logfile[250];
	char cap_name[30];
	FILE *fp, *logfp;

	push_call("save_char_obj(%p)",d);
		
	strcpy( cap_name, capitalize_name( d->account->player_name ) );

	sprintf(strsave,"%s/%c/%s",     ACCOUNT_DIR, tolower(cap_name[0]), cap_name);
	sprintf(strtemp,"%s/%c/temp.%s",ACCOUNT_DIR, tolower(cap_name[0]), cap_name);

	close_reserve();

// 	log_printf("save account, %s.", cap_name);
	/*
		Save char to "temp.name" then rename to "name" after all done for safety
	*/
	sprintf(logfile, "%s/%c/%s.log", ACCOUNT_DIR, tolower(cap_name[0]), cap_name);

	logfp = my_fopen(logfile,"w",FALSE);

	if (logfp == NULL)
	{
		log_printf("Could _NOT_ open logfile to log the saving of %s\n\r.",cap_name);
		print_errno(errno);
	}

	if (remove( strtemp ) != 0)
	{
		if (errno != ENOENT) /* if there was no temp file there's no prob */
		{
			log_printf("save_account: could not remove %s.", strtemp);
			print_errno(errno);
		}
	}

	fp = my_fopen( strtemp, "w", FALSE ) ;

	if ( fp == NULL )
	{
		log_printf("Save_account: could not my_fopen file.");
		perror( strsave );
		write_to_buffer(d, "Through some wierd game error, your account did not save.\n\r", 1000000);
		open_reserve();

		pop_call();
		return;
	}

	if (logfp) /* if the logfile is opened correctly */
	{
		fprintf(logfp, "Removed old backup and opened a new tempfile successfully.\n");
	}

	fwrite_acct( d->account, fp );

	if (logfp)
	{
		fprintf(logfp,"Wrote account information successfully. (fwrite_acct)\n");
	}

	if (ftell(fp) < (long)100)
	{
		my_fclose( fp );
		write_to_buffer(d, "Oops, file system full! tell an admin!\n\r", 1000000);
		log_string("File system full!!!\n\r");
	}
	else
	{
		my_fclose( fp );

		if (remove(strsave) != 0)
		{
			if (errno != ENOENT)
			{
				log_printf("save_account: (2nd) could not remove %s.", strsave);
				print_errno(errno);
			}
		}

		if (rename( strtemp, strsave ) != 0)
		{
			log_printf("Could not rename %s to %s.", strtemp, strsave);
			print_errno(errno);
		}
	}

	if (logfp)
	{
		fprintf(logfp,"All done right.\n");
		fflush(logfp);
		my_fclose(logfp);
		remove( logfile );
	}

	open_reserve();

	d->account->last_saved = mud->current_time;

	pop_call();
	return;
}