Argila2.0/
Argila2.0/pp/
Argila2.0/pp/lib/save/objs/g/
Argila2.0/pp/lib/save/player/g/
Argila2.0/pp/regions/
Argila2.0/pp/regions/Lscripts/
Argila2.0/pp/src/lib/
/** 
*	\file save.c
*	Provides services for saving and retrieving game data 
*
*	The purpose of this module is provide utilities and functionality for
*	saveing, writing, reading and loading of game date, including rooms, mobs,
*	objects, and players. Some statistics are also calculated here.
*
*	Copyright 2005, Mary C. Huston, All rights reserved.
*	Copyright (C) 2004, Shadows of Isildur: Traithe	
*
*	The program(s) may be used and/or copied only with written
*	permission or in accordance with the terms and conditions
*	stipulated in the license from DIKU GAMMA (0.0) and SOI.
*
*	\author Mary Huston
*	\author Email:  auroness@gmail.com
*
******************************************************************************
*/

#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <stdlib.h>

#include "structs.h"
#include "utils.h"
#include "protos.h"
#include "decl.h"


#define POSSESS_UNDEF   0
#define	POSSESS_CARRY	1
#define POSSESS_WEAR	2
#define POSSESS_ROOM	3

static int		last_wc = POSSESS_UNDEF;
static int		last_eqloc;
static int		last_eqlev;
static int		file_eof_found = 0;
static int		save_stop_obj_processing = 0;

int				load_char_objects;

extern int fread_number (FILE *fp);
extern char *fread_word (FILE *fp);

void write_char_data ( CHAR_DATA *ch, FILE *fp );
void write_obj_data ( OBJ_DATA *obj,
		      		char *wc,
		      		int pos,
		      		int objstack,
		      		FILE *fp );
int load_player (char *name, CHAR_DATA *ch, int load_type);
void read_obj_list (int cur_wc,
                    int cur_eqloc,
                    int cur_eqlev,
				    CHAR_DATA *ch,
					OBJ_DATA *holder,
					FILE *fp,
					int room_num);
OBJ_DATA *fread_obj (FILE *fp);
void read_aliases (CHAR_DATA *ch, FILE *fp);

char *unspace (char *s)
{
	char	*result;
	char	*orig;

	if ( !s ) {
		((int *) -1) [0] = 1;
	}

	if ( *s != ' ' )
		return s;

	orig = s;

	result = malloc (strlen (s) + 1);

    while (s && *s == ' ')
       s++;

	strcpy (result, s);

	mem_free (orig);

    return result;
}

void fwrite_a_obj (OBJ_DATA *obj, FILE *fp)
{
	int				affect_count = 0;
	int				modifiers = 1;
	AFFECTED_TYPE	*af = NULL;
	WOUND_DATA		*wound;
	OBJECT_DAMAGE		*damage;
	LODGED_OBJECT_INFO	*lodged;
	OBJ_DATA		*proto = NULL;
	TRIGGER_DATA	*trig = NULL;
	proto = vtoo (obj->virtual);

	if ( !proto )
		return;

	for ( af = obj->xaffected; af; af = af->next ) {

		if ( af->a.spell.location ) {
			affect_count++;
			continue;
		}
	}
	
	if ( obj->omote_str )
		modifiers++;

	if ( obj->loaded )
		modifiers += 1;

	for ( wound = obj->wounds; wound; wound = wound->next ) {
		modifiers++;
	}

	for ( damage = obj->damage; damage; damage = damage->next ) {
		modifiers++;
	}

	for ( lodged = obj->lodged; lodged; lodged = lodged->next ) {
		modifiers++;
	}

	if ( obj->size )
		modifiers++;

	if ( obj->count > 1 )
		modifiers++;

	if ( obj->obj_flags.extra_flags )
		modifiers++;

	if ( obj->obj_flags.type_flag == ITEM_DRINKCON )
		modifiers++;

	if ( obj->obj_timer )		/* obj_flags.timer */
		modifiers++;

	if (obj->clock && (obj->morphto >= 0) && obj->morphTime)
		modifiers +=3;

	if ( obj->book_title && obj->title_skill )
		modifiers += 4;

	if ( obj->var_color && str_cmp (obj->var_color, "none") )
		modifiers++;

	if ( obj->item_wear )
		modifiers++;

	if ( obj->obj_flags.type_flag != ITEM_DRINKCON ) {

		if(proto->name && obj->name && *obj->name)
		  if ( strcmp (obj->name, proto->name) )
			modifiers++;

		if(proto->short_description && obj->short_description && *obj->short_description)
		  if ( strcmp (obj->short_description, proto->short_description) )
			modifiers++;

		if(proto->description && obj->description && *obj->description)
		  if ( strcmp (obj->description, proto->description) )
			modifiers++;

		if(proto->full_description && obj->full_description && *obj->full_description)
		  if ( strcmp (obj->full_description, proto->full_description) )
			modifiers++;
		
	}

	if ( IS_SET(proto->obj_flags.extra_flags, ITEM_MASK) && proto->obj_flags.type_flag == ITEM_ARMOR && obj->desc_keys && strlen(obj->desc_keys) > 1 ) {
		if ( !proto->desc_keys && obj->desc_keys )
			modifiers++;
		else if ( strcmp (obj->desc_keys, proto->desc_keys) )
			modifiers++;
	}

	if ( IS_SET(proto->obj_flags.extra_flags, ITEM_MASK) && proto->obj_flags.type_flag == ITEM_WORN && obj->desc_keys && strlen(obj->desc_keys) > 1 ) {
		if ( strcmp (obj->desc_keys, proto->desc_keys) )
			modifiers++;
	}

	if ( obj->coldload_id )
		modifiers++;

    	fprintf (fp, "Id       %d %d %d\n", obj->virtual, affect_count, modifiers);

	if ( obj->coldload_id )
		fprintf (fp, "coldload       %d\n", obj->coldload_id);

	if ( obj->obj_flags.type_flag != ITEM_DRINKCON ) {

		if(proto->name && obj->name && *obj->name)
		  if ( strcmp (obj->name, proto->name) )
			fprintf (fp, "name %s~\n", obj->name);

		if(proto->short_description && obj->short_description && *obj->short_description)
		  if ( strcmp (obj->short_description, proto->short_description) )
			fprintf (fp, "short %s~\n", obj->short_description);

		if(proto->description && obj->description && *obj->description)
		  if ( strcmp (obj->description, proto->description) )
			fprintf (fp, "long %s~\n", obj->description);

		if(proto->full_description && obj->full_description && *obj->full_description )
		  if ( strcmp (obj->full_description, proto->full_description) )
			fprintf (fp, "full %s~\n", obj->full_description);

		if ( IS_SET(proto->obj_flags.extra_flags, ITEM_MASK) && (proto->obj_flags.type_flag == ITEM_WORN || proto->obj_flags.type_flag == ITEM_ARMOR) && obj->desc_keys && strlen(obj->desc_keys) > 1 )
			if ( strcmp (obj->desc_keys, proto->desc_keys) )
				fprintf (fp, "desc_keys %s~\n", obj->desc_keys);
	}

	if ( obj->book_title && obj->title_skill ) {
		fprintf (fp, "book_title     %s~\n", obj->book_title);
		fprintf (fp, "title_skill    %d\n", obj->title_skill);
		fprintf (fp, "title_language %d\n", obj->title_language);
		fprintf (fp, "title_script   %d\n", obj->title_script);
	}

	if ( obj->loaded )
		fprintf (fp, "loaded %d\n", obj->loaded->virtual);

	if ( obj->obj_flags.extra_flags )
		fprintf (fp, "extraflags %d\n", obj->obj_flags.extra_flags);

	if ( obj->item_wear )
		fprintf (fp, "itemwear %d\n", obj->item_wear);

	fprintf (fp, "values %d %d %d %d %d %d\n", obj->o.od.value [0],
	obj->o.od.value [1], obj->o.od.value [2], obj->o.od.value [3],
	obj->o.od.value [4], obj->o.od.value [5]);

	if ( obj->obj_flags.type_flag == ITEM_DRINKCON )
		fprintf (fp, "weight   %d\n", obj->obj_flags.weight);

	if ( obj->size )
		fprintf (fp, "size     %d\n", obj->size);

	if ( obj->count > 1 )
		fprintf (fp, "count    %d\n", obj->count);

	if ( obj->obj_timer )
		fprintf (fp, "timer    %d\n", obj->obj_timer);

	if(obj->clock && (obj->morphto >= 0) && obj->morphTime) {
		fprintf(fp, "clock	%d\n", obj->clock);
		fprintf(fp, "morphto	%d\n", obj->morphto);
		fprintf(fp, "morphTime	%d\n", obj->morphTime);
	}

	if ( obj->var_color && str_cmp (obj->var_color, "none") )
		fprintf (fp, "VarColor  %s~\n", obj->var_color);

	if ( obj->omote_str ) {
		fprintf(fp, "OmoteStr   %s~\n", obj->omote_str);
	}

	if ( obj->wounds ) {
		for ( wound = obj->wounds; wound; wound = wound->next )
                	fprintf (fp, "Wound      %s %s %s %s %d %d %d %d %d %d %d\n",
                                     wound->location, wound->type, wound->severity, wound->name,
                                     wound->damage, wound->bleeding, wound->poison,
                                     wound->infection, wound->healerskill, wound->lasthealed,
                                     wound->lastbled);

	}

	if ( obj->damage ) {
		for ( damage = obj->damage; damage; damage = damage->next ) {
			fprintf (fp, "Damage     %s %s %s %d\n", damage->type, damage->name, damage->severity, damage->damage);
		}
	}

	if ( obj->lodged ) {
		for ( lodged = obj->lodged; lodged; lodged = lodged->next )
			fprintf (fp, "Lodged     %s %d\n", lodged->location, lodged->vnum);
	}

	for ( af = obj->xaffected; af; af = af->next ) {
		if ( af->a.spell.location ) {
			fprintf (fp, "Afflocmod %d %d %d %d %d %d %d\n",
				af->a.spell.location,
				af->a.spell.modifier,
				af->a.spell.duration,
				af->a.spell.bitvector,
				af->a.spell.t,
				af->a.spell.sn,
				af->type);
			continue;
		}
	}
/** Lua functions **/
	for ( trig = obj->triggers; trig; trig = trig->next ){
		if (obj->triggers){
			fprintf (fp, "Prog\n%d\n%s:%s\n",
						trig->type,
						trig->script,
						trig->func);
		}
	}
/** end lua functions **/
	return;
}

void write_obj_data (OBJ_DATA *obj, char *wc, int pos, int objstack, FILE *fp)
{
    if ( !obj )
       return;

	if ( !vtoo (obj->virtual) )
		return;

	if ( obj->virtual == LEANTO_OBJ_VNUM )		/* Leantos. */
		return;

    fprintf (fp, "%s %d %d\n", wc, pos, objstack);

	/* Save object */

    fwrite_a_obj (obj, fp);

        /* Save everything this object contains */

    if ( obj->contains )
       write_obj_data (obj->contains, wc, pos, objstack + 1, fp);

	/* Save the next object in the list */

    if ( (obj->location == -1 && obj->next_content && obj != obj->next_content ) )
       write_obj_data (obj->next_content, wc, pos, objstack, fp);

    if ( obj->next_content && obj->next_content == obj )
	obj->next_content = NULL;

	return;
}

OBJ_DATA *fread_obj (FILE *fp)
{
	int			obj_vnum = 0;
	int			affect_count = 0;
	int			modifiers = 0;
	int			i, page = 0;
	int			old_money = 0;
	char			*p = NULL;
	OBJ_DATA		*obj = NULL;
	OBJ_DATA		*tobj = NULL;
	WRITING_DATA	*writing = NULL;
	AFFECTED_TYPE	*af = NULL;
	AFFECTED_TYPE	*taf = NULL;
	WOUND_DATA		*wound = NULL;
	OBJECT_DAMAGE		*damage = NULL;
	LODGED_OBJECT_INFO	*lodged = NULL;
	TRIGGER_DATA		*trig = NULL;
	char			*temp_arg = NULL;

	if ( strcmp (p = fread_word (fp), "Id") ) {
		abort();
	}

	obj_vnum = fread_number (fp);	
	affect_count = fread_number (fp);
    
	if ( !(obj = load_object (obj_vnum)) ) {
		if ( !(obj = load_object (666)) ) {
			if ( !obj ) {
				return NULL;
			}
		}
	}

		/* Remove prototype affects */

	while ( (af = obj->xaffected) ) {
		obj->xaffected = af->next;
		mem_free (af);
	}

	fscanf (fp, "%d", &modifiers);

	for ( ; modifiers; modifiers-- ) {

		p = fread_word (fp);

		if ( !strcmp (p, "name") ) {
			fgetc (fp);
			obj->name = fread_string (fp);
		} 
		else if ( !strcmp (p, "short") ) {
			fgetc (fp);
			obj->short_description = fread_string (fp);
		} 
		else if ( !strcmp (p, "loaded") ) {
			obj->loaded = vtoo(fread_number(fp));
		} 
		else if ( !strcmp (p, "coldload") ) {
			obj->coldload_id = fread_number(fp);
		} 
		else if ( !strcmp (p, "extraflags") ) {
			obj->obj_flags.extra_flags = fread_number(fp);
		} 
		else if ( !strcmp (p, "itemwear") ) {
			obj->item_wear = fread_number(fp);
		} 
		else if ( !strcmp (p, "long") ) {
			fgetc (fp);
			obj->description = fread_string (fp);
		} 
		else if ( !strcmp (p, "full") ) {
			fgetc (fp);
			obj->full_description = fread_string (fp);
		} 
		else if ( !strcmp (p, "values") ) {
			obj->o.od.value [0] = fread_number (fp);
			obj->o.od.value [1] = fread_number (fp);
			obj->o.od.value [2] = fread_number (fp);
			obj->o.od.value [3] = fread_number (fp);
			obj->o.od.value [4] = fread_number (fp);
			obj->o.od.value [5] = fread_number (fp);
			if ( GET_ITEM_TYPE (obj) == ITEM_BOOK || GET_ITEM_TYPE (obj) == ITEM_PARCHMENT )
				writing = obj->writing;
		}
		else if ( !strcmp (p, "weight") )
			obj->obj_flags.weight = fread_number (fp);
		
		else if ( !strcmp (p, "size") )
			obj->size = fread_number (fp);
		
		else if ( !strcmp (p, "count") )
			obj->count = fread_number (fp);
		
		else if ( !str_cmp (p, "timer") )
			obj->obj_timer = fread_number(fp);
		
		else if ( !strcmp (p, "clock") )
			obj->clock = fread_number (fp);
		
		else if ( !strcmp (p, "morphTime") )
			obj->morphTime = fread_number (fp);
		
		else if ( !strcmp (p, "morphto") )
			obj->morphto = fread_number (fp);
		
		else if ( !strcmp (p, "VarColor") ){
			temp_arg = fread_string(fp);
			obj->var_color = unspace(temp_arg);
		}
		
		else if ( !strcmp (p, "book_title") ){
			temp_arg = fread_string(fp);
			obj->book_title = unspace(temp_arg);
		}
		
		else if ( !str_cmp (p, "title_skill") )
			obj->title_skill = fread_number(fp);
		
		else if ( !str_cmp (p, "title_script") )
			obj->title_script = fread_number(fp);
		
		else if ( !str_cmp (p, "title_language") )
			obj->title_language = fread_number(fp);
		
		else if ( !strcmp (p, "page:") ) {
			if ( GET_ITEM_TYPE (obj) == ITEM_BOOK )
				obj->o.od.value[1] = 0;
			else 
				obj->o.od.value[0] = 0;
			writing = obj->writing;
			page = fread_number (fp);
			for ( i = 1; i; i++ ) {
				if ( i == page )
					break;
				else  writing = writing->next_page;
			}
		}
		
		else if ( !strcmp (p, "message:") ) {
			if ( GET_ITEM_TYPE (obj) == ITEM_BOOK )
				obj->o.od.value[1] = 0;
			else
				obj->o.od.value[0] = 0;
			
			fgetc (fp);
			writing->message = fread_string(fp);
		}
		
		else if ( !strcmp (p, "author:") ) {
			if ( GET_ITEM_TYPE (obj) == ITEM_BOOK )
				obj->o.od.value[1] = 0;
			else
				obj->o.od.value[0] = 0;
			
			fgetc (fp);
			writing->author = fread_string(fp);
		}
		
		else if ( !strcmp (p, "date:") ) {
			if ( GET_ITEM_TYPE (obj) == ITEM_BOOK )
				obj->o.od.value[1] = 0;
			else
				obj->o.od.value[0] = 0;
			
			fgetc (fp);
			writing->date = fread_string(fp);
		}
		
		else if ( !strcmp (p, "language:") )
			writing->language = fread_number (fp);
		
		else if ( !strcmp (p, "script:") )
			writing->script = fread_number (fp);
		
		else if ( !strcmp (p, "ink:") ) {
			if ( GET_ITEM_TYPE (obj) == ITEM_BOOK )
				obj->o.od.value[1] = 0;
			else
				obj->o.od.value[0] = 0;
			
			fgetc (fp);
			writing->ink = fread_string(fp);
		}
		
		else if ( !strcmp (p, "skill:") )
			writing->skill = fread_number(fp);
		
		else if ( !strcmp (p, "desc_keys") ) {
			fgetc (fp);
			obj->desc_keys = fread_string (fp);
		}
		
		else if ( !strcmp (p, "OmoteStr") ) {
			temp_arg = fread_string(fp);
			obj->omote_str = unspace(temp_arg);
		} 
		
		else if ( !strcmp (p, "Wound") ) {
			if ( !obj->wounds ) {
				CREATE (obj->wounds, WOUND_DATA, 1);
				wound = obj->wounds;
				obj->wounds->next = NULL;
			}
			else {
				CREATE (wound->next, WOUND_DATA, 1);
				wound = wound->next;
				wound->next = NULL;
			}
			temp_arg = fread_word(fp);
			wound->location = add_hash (temp_arg);
		
			temp_arg = fread_word(fp);
			wound->type = add_hash(temp_arg);
			
			temp_arg = fread_word(fp);
			wound->severity = add_hash (temp_arg);
			
			temp_arg = fread_word(fp);
			wound->name = add_hash(temp_arg);
			wound->damage = fread_number(fp);
			wound->bleeding = fread_number(fp);
			wound->poison = fread_number(fp);
			wound->infection = fread_number(fp);
			wound->healerskill = fread_number(fp);
			wound->lasthealed = fread_number(fp);
			wound->lastbled = fread_number(fp);
		} 
		
		else if ( !strcmp (p, "Damage") ) {
			if ( !obj->damage ) {
				CREATE (obj->damage, OBJECT_DAMAGE, 1);
				damage = obj->damage;
				damage->next = NULL;
			}
			else {
				CREATE (damage->next, OBJECT_DAMAGE, 1);
				damage = damage->next;
				damage->next = NULL;
			}
			temp_arg = fread_word(fp);
			damage->type = str_dup (temp_arg);
		
			temp_arg = fread_word(fp);
			damage->name = str_dup (temp_arg);
			
			temp_arg = fread_word(fp);
			damage->severity = str_dup (temp_arg);
			damage->damage = fread_number(fp);
		} 
		
		else if ( !strcmp (p, "Lodged") ) {
			if ( !obj->lodged ) {
				CREATE (obj->lodged, LODGED_OBJECT_INFO, 1);
				lodged = obj->lodged;
				obj->lodged->next = NULL;
			}
			else {
				CREATE (lodged->next, LODGED_OBJECT_INFO, 1);
				lodged = lodged->next;
				lodged->next = NULL;
			}
			temp_arg = fread_word(fp);
			lodged->location = add_hash(temp_arg);
			lodged->vnum = fread_number(fp);
		}
	}

	if ( old_money ) {
		obj->count = obj->o.od.value [0];
		obj->o.od.value [0] = 0;
	}

	  	/* read_object probably created associated some affects with the
           new object.  Lets erase all those and put in saved affects */

	for ( i = 0; obj && i < affect_count; i++ ) {
		temp_arg = fread_word (fp);
		if ( !strcmp (temp_arg, "Afflocmod") ) {

			CREATE (af, AFFECTED_TYPE, 1);
	
			af->next		= NULL;
	
			fscanf (fp, "%d %d %d %d %d %d %d\n",
					&af->a.spell.location,
					&af->a.spell.modifier,
					&af->a.spell.duration,
					&af->a.spell.bitvector,
					&af->a.spell.t,
					&af->a.spell.sn,
					&af->type);
	
			if ( !obj->xaffected ){
				obj->xaffected = af;
			}
			else {
				taf = obj->xaffected;
			
				while ( taf->next )
					taf = taf->next;
			
				taf->next = af;
			}
		}
		
		/**** for lua functions  **/
	
		if ( !strcmp (p, "Prog") ) {
			if ( !obj->triggers ) {
				CREATE (obj->triggers, TRIGGER_DATA, 1);
				trig = obj->triggers;
				obj->triggers->next = NULL;
			}
			else {
				CREATE (trig->next, TRIGGER_DATA, 1);
				trig = trig->next;
				trig->next = NULL;
			}
			trig->type = fread_number(fp);
			temp_arg = fread_word(fp);
			trig->script = add_hash(temp_arg);
			temp_arg = fread_word(fp);
			trig->func = add_hash(temp_arg);
		}
	/** end lua functions **/
	
	}

	
	if ( GET_ITEM_TYPE (obj) == ITEM_DRINKCON ||                                
         GET_ITEM_TYPE (obj) == ITEM_LIGHT ||                                   
         GET_ITEM_TYPE (obj) == ITEM_FOUNTAIN )
        if ( !(tobj = vtoo (obj->o.drinkcon.liquid)) ||                         
             GET_ITEM_TYPE (tobj) != ITEM_FLUID )
			obj->o.drinkcon.liquid = vtoo (obj->virtual)->o.drinkcon.liquid;

	if ( !IS_SET (obj->obj_flags.extra_flags, ITEM_NEWSKILLS) )
		update_weapon_skills (obj);

	/* Record what object previously was */

	if ( obj->virtual == 666 )
		obj->o.od.value[0] = obj_vnum;

    return obj;
}

int fread_look_obj_header (int *wc, int *eqloc, int *eqlev, FILE *fp)
{
    char		*ptr = NULL;

    if ( last_wc != POSSESS_UNDEF ) {
       *wc = last_wc;
       *eqloc = last_eqloc;
       *eqlev = last_eqlev;
       return (1);
    }

    if ( file_eof_found || save_stop_obj_processing )
       return (0);

    ptr = fread_word (fp);

    if ( *ptr == '\0' ) 	/* Probably the end of file mark */
       return (0);

    else if ( !strcmp (ptr, "CARRY") )
       *wc = POSSESS_CARRY;

    else if ( !strcmp (ptr, "WEAR") )
       *wc = POSSESS_WEAR;

	else if ( !strcmp (ptr, "ROOM") )
		*wc = POSSESS_ROOM;

    else if ( !strcmp (ptr, "DONE") ) {
		save_stop_obj_processing = 1;
		return (0);
	}
       
    else if ( !strcmp (ptr, "END") ) {
       file_eof_found = 1;
       return (0);
    }

    else
       return (0);

    *eqloc = fread_number (fp);
    *eqlev = fread_number (fp);

    last_wc = *wc;
    last_eqloc = *eqloc;
    last_eqlev = *eqlev;

    return (1);
}

void read_obj_list (int cur_wc, int cur_eqloc, int cur_eqlev, CHAR_DATA *ch,
					OBJ_DATA *holder, FILE *fp, int room_num)
{
	int				eqloc = 0;
	int				eqlev = 0;
	int				wc = 0;
	OBJ_DATA		*obj = NULL;

	while (1) {

		if ( !fread_look_obj_header (&wc, &eqloc, &eqlev, fp) )
			return;

		if ( cur_eqlev > eqlev )
			return;

                if ( (cur_wc != wc || cur_eqloc != eqloc) && eqloc != -1 && eqloc != WEAR_PRIM && eqloc != WEAR_SEC && eqloc != WEAR_BOTH ) {
                       	return;
                }

		if ( (cur_eqlev < eqlev) )
			read_obj_list (wc, eqloc, eqlev, ch, obj, fp, room_num);
		else {
			last_wc = POSSESS_UNDEF;

		obj = fread_obj (fp);

		if ( !obj ) return;
		else if ( holder ) {
			if ( ch )		/* All non-player-held books handled by load_all_writing(); */
				load_writing(obj);
			obj_to_obj (obj, holder);
		}
		else if ( wc == POSSESS_ROOM ) {
			if ( !vtor (room_num) )
				printf ("Room %d does not exist for object %d.\n",
						room_num, obj->virtual);
			else
				obj_to_room (obj, room_num);
		} else if ( cur_eqloc == -1 ) {
			obj->in_room = NOWHERE;
			if ( ch )
				load_writing(obj);
			obj_to_char (obj, ch);
			if ( eqloc == WEAR_PRIM || eqloc == WEAR_SEC || eqloc == WEAR_BOTH )
				equip_char (ch, obj, eqloc);
		}
		else {
			if ( ch )
				load_writing(obj);
			obj->carried_by = ch;
			obj->in_room = NOWHERE;
			equip_char (ch, obj, eqloc);
		}

		}  /* cur_eqlev < eqlev */
	} /* while (1) */
	return;
}

OBJ_DATA *get_equipped (CHAR_DATA *ch, int location)
{
        OBJ_DATA        *obj = NULL;
        
        for ( obj = ch->equip; obj; obj = obj->next_content )
        	if ( obj->location == location )
                	return obj;

        return NULL;
}

void write_obj_suppliment (CHAR_DATA *ch, FILE *fp)
{
	int		i = 0;
	OBJ_DATA 	*temp_obj = NULL;

	if ( ch->right_hand ) {
		write_obj_data (ch->right_hand, "CARRY", ch->right_hand->location, 0, fp);
	}

	if ( ch->left_hand ) {
		write_obj_data (ch->left_hand, "CARRY", ch->left_hand->location, 0, fp);
	}

	for ( i = 0; i < MAX_WEAR; i++ ) {
		if ( i == WEAR_PRIM || i == WEAR_BOTH || i == WEAR_SEC || i == WEAR_SHIELD )
			continue;
		
		temp_obj = get_equipped (ch, i);
		write_obj_data (temp_obj, "WEAR", i, 0, fp);
	}

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

void read_obj_suppliment (CHAR_DATA *ch, FILE *fp)
{
	int		i = 0;

    file_eof_found = 0;
	save_stop_obj_processing = 0;
    last_wc = POSSESS_UNDEF;
	load_char_objects = 1;			/* Global variable */

    ch->right_hand = NULL;
	ch->left_hand = NULL;
	ch->equip = NULL;

    read_obj_list (POSSESS_CARRY, -1, 0, ch, NULL, fp, 0);

    for (i = 0; i < MAX_WEAR; i++) {
	if ( i == WEAR_PRIM || i == WEAR_SEC || i == WEAR_BOTH )
		continue;
       read_obj_list (POSSESS_WEAR, i, 0, ch, NULL, fp, 0);
	}

	load_char_objects = 0;
	return;
}

#define		TYPE_STRING			1
#define		TYPE_INT			2
#define		TYPE_SKILL			3
#define		TYPE_END			5
#define		TYPE_AFFECT			6
#define		TYPE_SHORTINT		7
#define		TYPE_DREAM			8
#define		TYPE_OBSOLETE		9
#define		TYPE_LONG			10
#define		TYPE_SUBCRAFT		11
#define		TYPE_ALIAS			12
#define		TYPE_WOUND			13
#define		TYPE_STORED_PC		14
#define		TYPE_LODGED			15
#define		TYPE_SPELL			16
#define		TYPE_CHARM			17
#define		TYPE_VOICE			18
#define		TYPE_HOODED			19
#define		TYPE_NANNY			21
#define		TYPE_APPCOST		22
#define		TYPE_ROLE			23
#define		TYPE_ROLE_SUMMARY	24
#define		TYPE_ROLE_BODY		25
#define		TYPE_ROLE_DATE		26
#define		TYPE_ROLE_POSTER	27
#define		TYPE_ROLE_COST		28
#define		TYPE_MAIL_MESSAGE	29
#define		TYPE_IP				30
#define		TYPE_AFFECTEDBY		31
#define		TYPE_NEWSLETTER		32
#define		TYPE_OWNER			33
#define		TYPE_STABLED		34
#define		TYPE_HAS_INV		35
#define		TYPE_SPAWN			36
#define		TYPE_MOUNT			37
#define		TYPE_RESET			38
#define		TYPE_RESETZ			39
#define		TYPE_DONE			40


struct key_data {
	char		key [14];
	int			key_type;
	void		*ptr;
};

CHAR_DATA *load_char (CHAR_DATA *ch, char *name)
{
	int					i = 0;
	int					n = 0;
	int					sn = 0;
	int					last_key = 0;
	int					num_keys = 0;
	int					clan1 = 0;
	int					clan2 = 0;
	char				*p = NULL;
	char				*p2 = NULL;
	FILE				*fp = NULL;
	AFFECTED_TYPE		*af = NULL;
	DREAM_DATA			*dream = NULL;
	DREAM_DATA			*dream_list = NULL;
	CHAR_DATA			*tch = NULL;
	SUBCRAFT_HEAD_DATA	*craft = NULL;
	ALIAS_DATA			*current_alias = NULL;
	ALIAS_DATA			*alias = NULL;
	LODGED_OBJECT_INFO		*lodged = NULL;
	LODGED_OBJECT_INFO		*tmplodged = NULL;
	CHARM_DATA			*ench = NULL;
	CHARM_DATA			*tmpench = NULL;
	WOUND_DATA			*wound = NULL;
	WOUND_DATA			*tmpwound = NULL;
	char				current_alias_name [MAX_STRING_LENGTH] = { '\0' };
	char				buf [MAX_STRING_LENGTH] = { '\0' };
	char				buf2 [MAX_STRING_LENGTH] = { '\0' };
	char				*temp_arg = NULL;

	struct key_data key_table [] = {
		{ "Keywords",	TYPE_STRING,	NULL },
		{ "Account",	TYPE_STRING,	NULL },
		{ "Description",TYPE_STRING,	NULL },
		{ "Short",		TYPE_STRING,	NULL },
		{ "Long",		TYPE_STRING,	NULL },
		{ "Msg",		TYPE_STRING,	NULL },
		{ "CreateCom",	TYPE_STRING,	NULL },
		{ "Email",		TYPE_STRING,	NULL },
		{ "CreateState",TYPE_INT,		NULL },
		{ "Level",      TYPE_INT, 		NULL },
		{ "Sex",        TYPE_INT, 		NULL },
		{ "Clan",		TYPE_INT,		NULL },
		{ "Deity",		TYPE_INT,		NULL },
		{ "Height",     TYPE_INT, 		NULL },
		{ "Frame",      TYPE_INT, 		NULL },
		{ "Race",		TYPE_INT,		NULL },
		{ "Room",       TYPE_INT, 		NULL },
		{ "Str",        TYPE_INT, 		NULL },
		{ "Int",        TYPE_INT, 		NULL },
		{ "Wil",        TYPE_INT, 		NULL },
   		{ "Con",        TYPE_INT, 		NULL },
   		{ "Dex",        TYPE_INT, 		NULL },
   		{ "Aur",        TYPE_INT, 		NULL },
		{ "Agi",		TYPE_INT,		NULL },
		{ "StartStr",   TYPE_INT, 		NULL },
		{ "StartInt",   TYPE_INT, 		NULL },
		{ "StartWil",   TYPE_INT, 		NULL },
   		{ "StartCon",   TYPE_INT, 		NULL },
   		{ "StartDex",   TYPE_INT, 		NULL },
   		{ "StartAur",   TYPE_INT, 		NULL },
		{ "StartAgi",	TYPE_INT,		NULL },
   		{ "Played",     TYPE_LONG, 		NULL },
   		{ "Birth",      TYPE_INT, 		NULL },
   		{ "Time",       TYPE_INT, 		NULL },
   		{ "Cond0",      TYPE_INT, 		NULL },
   		{ "Cond1",      TYPE_INT, 		NULL },
   		{ "Cond2",      TYPE_INT, 		NULL },
		{ "Offense",	TYPE_SHORTINT,	NULL },
		{ "Clan_2",		TYPE_INT,		NULL },
		{ "PPoints",	TYPE_INT,		NULL },
		{ "Hit",		TYPE_INT,		NULL },
		{ "NatAttType",	TYPE_INT,		NULL },
		{ "Move",		TYPE_INT,		NULL },
		{ "Maxmove",	TYPE_INT,		NULL },
		{ "Circle",		TYPE_INT,		NULL },
		{ "FightMode",	TYPE_INT,		NULL },
		{ "Color",		TYPE_INT,		NULL },
		{ "Speaks",		TYPE_INT,		NULL },
		{ "Nightmare",	TYPE_INT,		NULL },
		{ "Flags",		TYPE_INT,		NULL },
		{ "PlrFlags",	TYPE_INT,		NULL },
		{ "Talents",	TYPE_INT,		NULL },
		{ "BoatVnum",	TYPE_INT,		NULL },
		{ "Speed",		TYPE_INT,		NULL },
		{ "MountSpeed", TYPE_INT,		NULL },
		{ "Common",		TYPE_INT,		NULL },
		{ "LastPCMsg",  TYPE_INT,		NULL },
		{ "LastStaffM", TYPE_INT,		NULL },
		{ "SleepNeeded",TYPE_INT,		NULL },
		{ "LastLogon",  TYPE_INT,		NULL },
		{ "LastLogoff", TYPE_INT,		NULL },
		{ "LastDis",	TYPE_INT,		NULL },
		{ "LastConnect",TYPE_INT,		NULL },
		{ "LastDied",   TYPE_INT,		NULL },
		{ "Autotoll",	TYPE_INT,		NULL },
		{ "ColdloadID", TYPE_INT,		NULL },
		{ "ImmEnter",	TYPE_STRING,	NULL },
		{ "ImmLeave",	TYPE_STRING,	NULL },
		{ "SiteLie",	TYPE_STRING,	NULL },
		{ "Clans",		TYPE_STRING,	NULL },
		{ "Dream",		TYPE_DREAM,		NULL },
		{ "Dreamed",	TYPE_DREAM,		NULL },
		{ "StaffNotes",	TYPE_INT,		NULL },
		{ "Age",		TYPE_INT,		NULL },
		{ "Intoxication", TYPE_INT,		NULL },
		{ "Hunger",		TYPE_INT,		NULL },
		{ "Thirst",		TYPE_INT,		NULL },
		{ "Totem",		TYPE_INT,		NULL },
		{ "Damage",		TYPE_INT,		NULL },
		{ "LastRegen",	TYPE_INT,		NULL },
		{ "LastRoom",	TYPE_INT,		NULL },
		{ "Harness",	TYPE_INT,		NULL },
		{ "MaxHarness",	TYPE_INT,		NULL },
		{ "Wound",		TYPE_WOUND,		NULL },
		{ "Spell",		TYPE_SPELL,		NULL },
		{ "Charm",		TYPE_CHARM,		NULL },
		{ "VoiceStr",	TYPE_VOICE,		NULL },
		{ "NannyState",	TYPE_NANNY,		NULL },
		{ "AppCost",	TYPE_APPCOST,	NULL },
		{ "Role",		TYPE_ROLE,		NULL },
		{ "RoleSummary",	TYPE_ROLE_SUMMARY,	NULL },
		{ "RoleBody",	TYPE_ROLE_BODY,	NULL },
		{ "RoleDate",	TYPE_ROLE_DATE,	NULL },
		{ "RolePoster",	TYPE_ROLE_POSTER,	NULL },
		{ "RoleCost",	TYPE_ROLE_COST,	NULL },
		{ "Lodged",		TYPE_LODGED,	NULL },
		{ "Skill",		TYPE_SKILL,		NULL },
		{ "Affect",		TYPE_AFFECT,	NULL },
		{ "AffectedBy",	TYPE_AFFECTEDBY,		NULL },
		{ "Subcraft",	TYPE_SUBCRAFT,	NULL },
		{ "IsHooded",	TYPE_HOODED,	NULL },
		{ "Alias",		TYPE_ALIAS,		NULL },
		{ "End",		TYPE_END,		NULL },
		{ "\0",			TYPE_INT,		NULL }
	};

	if ( !isalpha (*name) ) {
		return NULL;
	}

	key_table [n++].ptr = &ch->name;
	key_table [n++].ptr = &ch->pc->account;
	key_table [n++].ptr = &ch->description;
	key_table [n++].ptr = &ch->short_descr;
	key_table [n++].ptr = &ch->long_descr;
	key_table [n++].ptr = &ch->pc->msg;
	key_table [n++].ptr = &ch->pc->creation_comment;
	key_table [n++].ptr = &ch->pc->email_address;
	key_table [n++].ptr = &ch->pc->create_state;
	key_table [n++].ptr = &ch->pc->level;
	key_table [n++].ptr = &ch->sex;
	key_table [n++].ptr = &clan1;
	key_table [n++].ptr = &ch->deity;
	key_table [n++].ptr = &ch->height;
	key_table [n++].ptr = &ch->frame;
	key_table [n++].ptr = &ch->race;
	key_table [n++].ptr = &ch->in_room;
	key_table [n++].ptr = &ch->str;
	key_table [n++].ptr = &ch->intel;
	key_table [n++].ptr = &ch->wil;
   	key_table [n++].ptr = &ch->con;
   	key_table [n++].ptr = &ch->dex;
   	key_table [n++].ptr = &ch->aur;
	key_table [n++].ptr = &ch->agi;
	key_table [n++].ptr = &ch->pc->start_str;
	key_table [n++].ptr = &ch->pc->start_intel;
	key_table [n++].ptr = &ch->pc->start_wil;
   	key_table [n++].ptr = &ch->pc->start_con;
   	key_table [n++].ptr = &ch->pc->start_dex;
   	key_table [n++].ptr = &ch->pc->start_aur;
	key_table [n++].ptr = &ch->pc->start_agi;
   	key_table [n++].ptr = &ch->time.played;
   	key_table [n++].ptr = &ch->time.birth;
   	key_table [n++].ptr = &ch->time.logon;
   	key_table [n++].ptr = &ch->intoxication;
   	key_table [n++].ptr = &ch->hunger;
   	key_table [n++].ptr = &ch->thirst;
	key_table [n++].ptr = &ch->offense;
	key_table [n++].ptr = &clan2;
	key_table [n++].ptr = &ch->ppoints;
	key_table [n++].ptr = &ch->hit;
	key_table [n++].ptr = &ch->nat_attack_type;
	key_table [n++].ptr = &ch->move;
	key_table [n++].ptr = &ch->max_move;
	key_table [n++].ptr = &ch->circle;
	key_table [n++].ptr = &ch->fight_mode;
	key_table [n++].ptr = &ch->color;
	key_table [n++].ptr = &ch->speaks;
	key_table [n++].ptr = &ch->nightmare;
	key_table [n++].ptr = &ch->flags;
	key_table [n++].ptr = &ch->plr_flags;
	key_table [n++].ptr = &ch->psionic_talents;
	key_table [n++].ptr = &ch->pc->boat_virtual;
	key_table [n++].ptr = &ch->speed;
	key_table [n++].ptr = &ch->pc->mount_speed;
	key_table [n++].ptr = &ch->pc->common;
	key_table [n++].ptr = &ch->pc->last_global_pc_msg;
	key_table [n++].ptr = &ch->pc->last_global_staff_msg;
	key_table [n++].ptr = &ch->pc->sleep_needed;
	key_table [n++].ptr = &ch->pc->last_logon;
	key_table [n++].ptr = &ch->pc->last_logoff;
	key_table [n++].ptr = &ch->pc->last_disconnect;
	key_table [n++].ptr = &ch->pc->last_connect;
	key_table [n++].ptr = &ch->pc->last_died;
	key_table [n++].ptr = &ch->pc->auto_toll;
	key_table [n++].ptr = &ch->coldload_id;
	key_table [n++].ptr = &ch->pc->imm_enter;
	key_table [n++].ptr = &ch->pc->imm_leave;
	key_table [n++].ptr = &ch->pc->site_lie;
	key_table [n++].ptr = &ch->clans;
	key_table [n++].ptr = &ch->pc->dreams;
	key_table [n++].ptr = &ch->pc->dreamed;
	key_table [n++].ptr = &ch->pc->staff_notes;
	key_table [n++].ptr = &ch->age;
	key_table [n++].ptr = &ch->intoxication;
	key_table [n++].ptr = &ch->hunger;
	key_table [n++].ptr = &ch->thirst;
	key_table [n++].ptr = &ch->idol;
	key_table [n++].ptr = &ch->damage;
	key_table [n++].ptr = &ch->lastregen;
	key_table [n++].ptr = &ch->was_in_room;
	key_table [n++].ptr = &ch->harness;
	key_table [n++].ptr = &ch->max_harness;
	key_table [n++].ptr = &ch->voice_str;
	key_table [n++].ptr = NULL;			/* Nanny State */
	key_table [n++].ptr = NULL;			/* Role Flag */
	key_table [n++].ptr = NULL;			/* Special Role (Summary)*/
	key_table [n++].ptr = NULL;			/* Role Body */
	key_table [n++].ptr = NULL;			/* Role Date */
	key_table [n++].ptr = NULL;			/* Role Poster */
	key_table [n++].ptr = NULL;			/* Role Cost */
	key_table [n++].ptr = NULL;			/* App Cost */
	key_table [n++].ptr = NULL;			/* Skill */
	key_table [n++].ptr = NULL;			/* Voice */
	key_table [n++].ptr = NULL;			/* Spell */
	key_table [n++].ptr = NULL;			/* Affect */
	key_table [n++].ptr = NULL;			/* AffectedBy */
	key_table [n++].ptr = NULL;			/* Subcraft */
	key_table [n++].ptr = NULL;			/* Wound */
	key_table [n++].ptr = NULL;			/* CHARM */
	key_table [n++].ptr = NULL;			/* Lodged */
	key_table [n++].ptr = NULL;			/* Alias */
	key_table [n++].ptr = NULL;			/* End */

	GET_NAME (ch) = str_dup (name);

	snprintf (buf, MAX_STRING_LENGTH,  "save/player/%c/%s", tolower (*name), CAP (name));

	if ( !(fp = fopen (buf, "r")) ) {
		return NULL;
	}

	ch->pc->msg = NULL;
	ch->pc->creation_comment = NULL;
	ch->pc->email_address = NULL;
	ch->pc->site_lie = NULL;
	ch->deleted = 0;
	ch->hour_affects = NULL;
	ch->wounds = NULL;
	ch->lodged = NULL;
	ch->subdue = NULL;

	ch->tmp_str    = 0;
	ch->tmp_intel	= 0;
	ch->tmp_dex	= 0;
	ch->tmp_wil	= 0;
	ch->tmp_con	= 0;
	ch->tmp_aur	= 0;
	ch->tmp_agi = 0;

	ch->str 	= 0;
	ch->intel	= 0;
	ch->dex		= 0;
	ch->wil		= 0;
	ch->con		= 0;
	ch->aur		= 0;
	ch->agi		= 0;

	ch->clans = str_dup ("");

	for ( i = 0; i < MAX_SKILLS; i++ ) {
		ch->pc->skills [i] = 0;
		ch->skills [i] = 0;
	}

	for ( num_keys = 0; *key_table [num_keys].key; )
		num_keys++;

	for ( ; !feof (fp); ) {

		if ( !(p = fread_word (fp)) ) {
			fclose (fp);
			free_char (ch);
			return NULL;
		}

		if ( !str_cmp (p, "Defense") ) {
			fread_number (fp);
			continue;
		}

		for ( i = last_key;
			  i < last_key + num_keys &&
				str_cmp (key_table [i % num_keys].key, p);)
			i++;

		i = i % num_keys;

		if ( str_cmp (key_table [i].key, p) ) {
			continue;
		}

		if ( key_table [i].key_type == TYPE_SKILL ||
			 key_table [i].key_type == TYPE_AFFECT ||
			 key_table [i].key_type == TYPE_WOUND ||
			 key_table [i].key_type == TYPE_SPELL ||
			 key_table [i].key_type == TYPE_LODGED ||
			 key_table [i].key_type == TYPE_VOICE ||
			 key_table [i].key_type == TYPE_HOODED ||
			 key_table [i].key_type == TYPE_NANNY ||
			 key_table [i].key_type == TYPE_ROLE ||
			 key_table [i].key_type == TYPE_ROLE_SUMMARY ||
			 key_table [i].key_type == TYPE_ROLE_BODY ||
			 key_table [i].key_type == TYPE_ROLE_DATE ||
			 key_table [i].key_type == TYPE_ROLE_POSTER ||
			 key_table [i].key_type == TYPE_ROLE_COST ||
			 key_table [i].key_type == TYPE_AFFECTEDBY ||
			 key_table [i].key_type == TYPE_APPCOST )
			last_key = i;
		else
			last_key = i + 1;

		if ( key_table [i].key_type == TYPE_INT )
			* (int *) key_table [i].ptr = fread_number (fp);

		else if ( key_table [i].key_type == TYPE_SHORTINT )
			* (shortint *) key_table [i].ptr = fread_number (fp);

		else if ( key_table [i].key_type == TYPE_STRING ){
			temp_arg = fread_string (fp);
			* (char **) key_table [i].ptr = unspace (temp_arg);
		}

		else if ( key_table [i].key_type == TYPE_LONG )
			* (long *) key_table [i].ptr = fread_number (fp);

		else if ( key_table [i].key_type == TYPE_OBSOLETE )
			sn = fread_number (fp);

		else if ( key_table [i].key_type == TYPE_ROLE_SUMMARY ) {
			CREATE (ch->pc->special_role, ROLE_DATA, 1);
			temp_arg = fread_string(fp);
			ch->pc->special_role->summary = unspace(temp_arg);
		}

		else if ( key_table [i].key_type == TYPE_ROLE_BODY ) {
			temp_arg = fread_string(fp);
			ch->pc->special_role->body = unspace(temp_arg);
		}

		else if ( key_table [i].key_type == TYPE_ROLE_DATE ) {
			temp_arg = fread_string(fp);
			ch->pc->special_role->date = unspace(temp_arg);
		}

		else if ( key_table [i].key_type == TYPE_AFFECTEDBY ) {
			ch->affected_by = fread_number(fp);
		}

		else if ( key_table [i].key_type == TYPE_ROLE_POSTER ) {
			temp_arg = fread_string(fp);
			ch->pc->special_role->poster = unspace(temp_arg);
		}

		else if ( key_table [i].key_type == TYPE_ROLE_COST ) {
			ch->pc->special_role->cost = fread_number(fp);
		}

		else if ( key_table [i].key_type == TYPE_END ) {

			ch->tmp_str	 = ch->str;
			ch->tmp_dex	 = ch->dex;
			ch->tmp_intel 	 = ch->intel;
			ch->tmp_wil	 = ch->wil;
			ch->tmp_con	 = ch->con;
			ch->tmp_aur	 = ch->aur;
			ch->tmp_agi  = ch->agi;

			GET_MAX_MOVE (ch) = calc_lookup (ch, REG_MISC, MISC_MAX_MOVE);

			REMOVE_BIT (ch->flags, FLAG_ENTERING);
			REMOVE_BIT (ch->flags, FLAG_LEAVING);

			ch->max_hit = 50 + GET_CON (ch) * CONSTITUTION_MULTIPLIER;

			fclose (fp);

			if ( ch->pc->boat_virtual ) {
				for ( tch = character_list; tch; tch = tch->next ) {
					if ( tch->deleted )
						continue;
					if ( IS_NPC (tch) &&
						 tch->mob->virtual == ch->pc->boat_virtual ) {
						ch->vehicle = tch;
						break;
					}
				}

				if ( !ch->vehicle ) {
					ch->pc->boat_virtual = 0;
					ch->in_room = BOAT_ROOM;
				}
			}

			if ( get_affect (ch, MAGIC_AFFECT_SLEEP) )
				GET_POS (ch) = SLEEP;

			if ( !ch->coldload_id )
				ch->coldload_id = get_next_coldload_id (1);

			fix_offense (ch);

			p = ch->clans;
			p2 = p;
			ch->clans = str_dup ("");

			while ( 1 ) {

				p = one_argument (p, buf);		/* flags     */
				p = one_argument (p, buf2);		/* clan name */

				if ( !*buf2 )
					break;

				add_clan_id (ch, buf2, buf);
			}

			mem_free (p2);

			if ( clan1 ) {
				snprintf (buf, MAX_STRING_LENGTH,  "%d", clan1);
				add_clan_id (ch, buf,
					GET_FLAG (ch, FLAG_LEADER_1) ? "leader" : "member");
			}

			if ( clan2 ) {
				snprintf (buf, MAX_STRING_LENGTH,  "%d", clan2);
				add_clan_id (ch, buf,
					GET_FLAG (ch, FLAG_LEADER_2) ? "leader" : "member");
			}

			REMOVE_BIT (ch->flags, FLAG_LEADER_1);
			REMOVE_BIT (ch->flags, FLAG_LEADER_2);

			ch->time.logon = time (0);

			return ch;
		}

		else if ( key_table [i].key_type == TYPE_NANNY )
			ch->pc->nanny_state = fread_number(fp);

		else if ( key_table [i].key_type == TYPE_APPCOST )
			ch->pc->app_cost = fread_number(fp);

		else if ( key_table [i].key_type == TYPE_ROLE )
			ch->pc->role = fread_number(fp);

		else if ( key_table [i].key_type == TYPE_SKILL ) {
			p = fread_word (fp);
			sn = skill_index_lookup (p);

			if ( sn == -1 )
				sn = skill_index_lookup (p);

			else if ( sn > MAX_SKILLS )
				printf ("Skill Num # %d (learned %d) out of range.\n",
						sn, fread_number (fp));
			else {
				ch->skills [sn] = fread_number (fp);
				ch->pc->skills [sn] = ch->skills [sn];
			}
		}

		else if ( key_table [i].key_type == TYPE_AFFECT ) {

			af = (AFFECTED_TYPE *)alloc (sizeof (AFFECTED_TYPE), 13);

			fscanf (fp, "%d %d %d %d %d %d %d\n",
							&af->type,
							&af->a.spell.duration,
							&af->a.spell.modifier,
							&af->a.spell.location,
							&af->a.spell.bitvector,
							&af->a.spell.sn,
							&af->a.spell.t);
			af->next		= NULL;

			if ( af->a.spell.location <= APPLY_CON )
				affect_to_char (ch, af);
				
			else if ( af->a.spell.location >= FIRST_APPLY_SKILL &&
					  af->a.spell.location <= LAST_APPLY_SKILL )
				affect_to_char (ch, af);
				
			else {
				af->next = ch->hour_affects;
				ch->hour_affects = af;
			}
		}

		else if ( key_table [i].key_type == TYPE_HOODED ) {
			SET_BIT (ch->affected_by, AFF_HOODED);
		}

		else if ( key_table [i].key_type == TYPE_SUBCRAFT ) {

			p = fread_word (fp);

			for ( craft = crafts;
				  craft && str_cmp (craft->subcraft_name, p);
				  craft = craft->next )
				;

			if ( !craft ) {
				continue;
			}

		    for ( i = CRAFT_FIRST; i <= CRAFT_LAST; i++ )
				if ( !get_affect (ch, i) )
					break;

			if ( i > CRAFT_LAST ) {
				continue;
			}

			magic_add_affect (ch, i, -1, 0, 0, 0, 0);

			af = get_affect (ch, i);

			af->a.craft = (struct affect_craft_type *)alloc (sizeof (struct affect_craft_type), 23);

			af->a.craft->subcraft = craft;
		}

		else if ( key_table [i].key_type == TYPE_VOICE ) {
			temp_arg = fread_string(fp);
			ch->voice_str = unspace(temp_arg);
		}

		else if ( key_table [i].key_type == TYPE_SPELL ) {
			continue;
		}

		else if ( key_table [i].key_type == TYPE_CHARM ) {
			ench =  (CHARM_DATA *)alloc ((int)sizeof (CHARM_DATA), 36);
			ench->next = NULL;

			ench->name = fread_string(fp);
			ench->original_hours = fread_number(fp);
			ench->current_hours = fread_number(fp);
			ench->power_source = fread_number(fp);
			ench->caster_skill = fread_number(fp);

			if ( !ch->charms )
				ch->charms = ench;
			else {
				tmpench = ch->charms;
				while ( tmpench->next )
					tmpench = tmpench->next;
				tmpench->next = ench;
			}
		}

		else if ( key_table [i].key_type == TYPE_WOUND ) {
			CREATE (wound, WOUND_DATA, 1);
			wound->next		= NULL;
			
			temp_arg = fread_word(fp);
			wound->location = add_hash(temp_arg);
			
			temp_arg = fread_word(fp);
			wound->type = add_hash(temp_arg);
			
			temp_arg = fread_word(fp);
			wound->severity = add_hash(temp_arg);
			
			temp_arg = fread_word(fp);
			wound->name = add_hash(temp_arg);
			
			wound->damage = fread_number(fp);
			wound->bleeding = fread_number(fp);
			wound->poison = fread_number(fp);
			wound->infection = fread_number(fp);
			wound->healerskill = fread_number(fp);
			wound->lasthealed = fread_number(fp);
			wound->lastbled = fread_number(fp);

			if ( !ch->wounds )
				ch->wounds = wound;
			else {
				tmpwound = ch->wounds;
				while ( tmpwound->next )
					tmpwound = tmpwound->next;
				tmpwound->next = wound;
			}

		}
		
		else if ( key_table [i].key_type == TYPE_LODGED ) {
			lodged = (LODGED_OBJECT_INFO *)alloc ((int)sizeof (LODGED_OBJECT_INFO), 36);
			lodged->next		= NULL;
			
			temp_arg = fread_word(fp);
			lodged->location = add_hash(temp_arg);
			lodged->vnum = fread_number(fp);

			if ( !ch->lodged )
				ch->lodged = lodged;
			else {
				tmplodged = ch->lodged;
				while ( tmplodged->next )
					tmplodged = tmplodged->next;
				tmplodged->next = lodged;
			}

		}
		
		else if ( key_table [i].key_type == TYPE_DREAM ) {

			CREATE (dream, DREAM_DATA, 1);
			temp_arg = fread_string (fp);
			dream->dream = unspace (temp_arg);
			dream->next  = NULL;

			if ( * (DREAM_DATA **) key_table [i].ptr == NULL )
				* (DREAM_DATA **) key_table [i].ptr = dream;

			else {
				dream_list = * (DREAM_DATA **) key_table [i].ptr;

				while ( dream_list->next != NULL )
					dream_list = dream_list->next;

				dream_list->next = dream;
			}
		}

		else if ( key_table [i].key_type == TYPE_ALIAS ) {

			temp_arg = fread_word(fp);
			strcpy (buf, temp_arg);

			if ( !str_cmp (buf, current_alias_name) ) {
				for ( alias = current_alias;
					  alias->next_line;
					  alias = alias->next_line )
					;
				alias->next_line = (ALIAS_DATA *)alloc ((int)sizeof (ALIAS_DATA), 28);
				alias = alias->next_line;
			}

			else {
				strcpy (current_alias_name, buf);

				alias = (ALIAS_DATA *)alloc ((int)sizeof (ALIAS_DATA), 28);
				alias->command = str_dup (current_alias_name);

				if ( !ch->pc->aliases )
					ch->pc->aliases = alias;
				else
					current_alias->next_alias = alias;

				current_alias = alias;
			}

			p = strcpy (buf, fgets (buf, MAX_STRING_LENGTH, fp));
			buf [strlen (buf) - 1] = '\0';

			while ( *p == ' ' || *p == '\t' )
				p++;

			alias->line = str_dup (p);
		}
	}

	fclose (fp);

	free_char (ch);
	return NULL;
}

int save_char (CHAR_DATA *ch, int save_objs)
{
	if ( IS_NPC (ch) || IS_SET (ch->flags, FLAG_GUEST) || !ch->tname || !*ch->tname ) {
		return 1;
	}

	save_char_mysql (ch);

	if ( save_objs )
		save_char_objs (ch, ch->tname);

	if ( ch->room )
		save_attached_mobiles (ch, 0);

	return 0;
}

void load_online_stats (void)
{
	FILE		*fp = NULL;

	if ( !(fp = fopen("online_stats", "r")) ) {
		system_log("Error opening online_stats!", TRUE);
		return;
	}

	fscanf (fp, "%d\n", &count_max_online);
	max_online_date = fread_string(fp);

	fclose (fp);
	return;
}

void load_leantos (void)
{
	FILE		*fp = NULL;
	OBJ_DATA	*obj = NULL;
	char		buf [MAX_STRING_LENGTH] = {'\0'};
	int			toroom = 0;
	int			inroom = 0;
    struct room_prog        *t, *old, *tmp;

	if ( !(fp = fopen("../regions/leantos", "r")) )
		return;

	while ( !feof (fp) ) {
		fscanf (fp, "leanto from room %d to room %d\n", &inroom, &toroom);
		obj = load_object(LEANTO_OBJ_VNUM);
		obj_to_room (obj, inroom);
		snprintf (buf, MAX_STRING_LENGTH,  "vstr You enter the lean-to.\nostr %%n enters the lean-to.\natecho %d %%n enters the lean-to.\ntrans %d\natlook %d\n", toroom, toroom, toroom);
                CREATE (t, struct room_prog,1);
                t->next = NULL;
                t->command = add_hash ("enter");
                t->keys = add_hash ("lean-to leanto");
                t->prog = add_hash (buf);
                if ( !vtor (inroom)->prg) {
                        vtor (inroom)->prg = t;
                } else {
                        old = vtor (inroom)->prg;
                        tmp = old;
                        while ( tmp ) {
                                old = tmp;
                                tmp = tmp->next;
                        }
                        old->next = t;
                }
	}

	fclose(fp);
	return;
}		

void load_mobiles (void)
{
	CHAR_DATA	*mob = NULL;
	WOUND_DATA	*wound = NULL;
	WOUND_DATA	*tmpwound = NULL;
	FILE		*fp = NULL;
	FILE		*op = NULL;
	char		*key = NULL;
	char		name[MAX_STRING_LENGTH] = {'\0'};
	char		location[MAX_STRING_LENGTH] = {'\0'};
	char		severity[MAX_STRING_LENGTH] = {'\0'};
	char		type[MAX_STRING_LENGTH] = {'\0'};
	char 		buf[MAX_STRING_LENGTH] = {'\0'};
	char		line[MAX_STRING_LENGTH] = {'\0'};
	char		*temp_arg = NULL;
	char		*temp_hold = NULL;
	int			i = 0;
	int			num = 0;
	int			to_room = 0;
	int			sn = 0;


	for ( i = 0; i <= 99; i++ ) {
		snprintf (buf, MAX_STRING_LENGTH,  "save/mobiles/mobs.%d", i);
		if ( !(fp = fopen(buf, "r+")) )
			continue;
		
		for ( ; !feof(fp) ; ) {
			key = fread_word(fp);
			if ( !str_cmp (key, "END") ) {
				if ( mob ) {
					SET_BIT (mob->act, ACT_STAYPUT);
					char_to_room (mob, to_room);
					if ( !mob->room ) {
						extract_char (mob);
					}
					mob = NULL;
				}
			}
			
			else if ( !str_cmp (key, "Keywords") ) {
				temp_arg = fread_string(fp);
				temp_hold = unspace(temp_arg);
				mob->name = temp_hold;
			}
			else if ( !str_cmp (key, "Owner") ) {
				temp_arg = fread_string(fp);
				temp_hold = unspace(temp_arg);
				mob->mob->owner = temp_hold;
			}
			else if ( !str_cmp (key, "SDesc") ) {
				temp_arg = fread_string(fp);
				temp_hold = unspace(temp_arg);
				mob->short_descr = temp_hold;
			}
			else if ( !str_cmp (key, "Skill") ) {
				key = fread_word(fp);
				sn = skill_index_lookup (key);
				
				if ( sn == -1 )
					sn = skill_index_lookup (key);
				if ( sn == -1 )
					continue;
				if ( sn > MAX_SKILLS )
					continue;
				else mob->skills [sn] = fread_number(fp);
			}
			else if ( !str_cmp (key, "LDesc") ) {
				temp_arg = fread_string(fp);
				temp_hold = unspace(temp_arg);
				mob->long_descr = temp_hold;
			}
			else if ( !str_cmp (key, "DatabaseNumber") ) {
				num = fread_number(fp);
				mob = new_char (0);
				mob = load_mobile (num);
			}
			else if ( !str_cmp (key, "ColdloadID") ) {
				num = fread_number(fp);
				mob->coldload_id = num;
			}
			else if ( !str_cmp (key, "CurrentRoom") ) {
				num = fread_number(fp);
				to_room = num;
			}
			else if ( !str_cmp (key, "SpawnLocation") ) {
				num = fread_number(fp);
				mob->mob->spawnpoint = num;
			}

			else if ( !str_cmp (key, "Wound") ) {
				CREATE (wound, WOUND_DATA, 1);
				wound->next = NULL;
				temp_arg = fread_string(fp);
				temp_hold = unspace(temp_arg);
				sscanf (line, "Wound              %s %s %s %s %d %d %d %d %d %d %d\n",
					location, type, severity, name,
					&wound->damage, &wound->bleeding, &wound->poison,
					&wound->infection, &wound->healerskill, &wound->lasthealed,
					&wound->lastbled);
				wound->location = add_hash(temp_hold);
				wound->type = add_hash(temp_hold);
				wound->severity = add_hash(temp_hold);
				wound->name = add_hash(temp_hold);
				wound->damage = fread_number(fp);
				wound->bleeding = fread_number(fp);
				wound->poison = fread_number(fp);
				wound->infection = fread_number(fp);
				wound->healerskill = fread_number(fp);
				wound->lasthealed = fread_number(fp);
				wound->lastbled = fread_number(fp);
				if ( !mob->wounds )
					mob->wounds = wound;
				else {
					tmpwound = mob->wounds;
					while ( tmpwound->next )
						tmpwound = tmpwound->next;
					tmpwound->next = wound;
				}
			}
			else if ( !str_cmp (key, "HasInventory") ) {
				op = NULL;
				*buf = '\0';
				snprintf (buf, MAX_STRING_LENGTH,  "save/mobiles/inventory/%d", mob->coldload_id);
				if ( !(op = fopen(buf, "r+")) )
					continue;
				read_obj_suppliment (mob, op);
				fclose (op);
			}
			else if ( !str_cmp (key, "IsHooded") ) {
				SET_BIT (mob->affected_by, AFF_HOODED);
			}
			else if ( !str_cmp (key, "ENDFILE") )
				break;
			else continue;
		}
		fclose (fp);
	}
	return;
}

void save_player_rooms (void)
{
	FILE		*fp = NULL;
	ROOM_DATA	*room = NULL;
	char		buf [MAX_STRING_LENGTH] = {'\0'};

        for ( room = full_room_list; room; room = room->lnext ) {
        	if ( room->psave_loaded && room->contents ) {
            	snprintf (buf, MAX_STRING_LENGTH,  "save/rooms/%d", room->virtual);
				fp = fopen (buf, "w");
            	if ( !fp )
                	continue;
                    
                write_obj_data (room->contents, "ROOM", 0, 0, fp);
				fprintf (fp, "DONE\n");
                fclose (fp);
            }
		
			else if ( room->psave_loaded && !room->contents ) {
				snprintf (buf, MAX_STRING_LENGTH,  "save/rooms/%d", room->virtual);
				unlink (buf);
			}
        }
    return;
}

void do_saverooms (CHAR_DATA *ch, char *argument, int cmd)
{
	save_player_rooms ();
	send_to_char ("Ok.\n\r", ch);
	return;
}

void load_save_rooms (void)
{
	int			room_num = 0;
	int			line_no = 1;
	int			rooms = 0;
	int			room_obj_count = 0;
	OBJ_DATA	*obj = NULL;
	FILE		*rp = NULL;
	char		buf [MAX_STRING_LENGTH] = {'\0'};


	if ( !(rp = fopen ("save_rooms", "r")) ) {
		perror ("save_rooms");
		return;
	}

	file_eof_found = 0;
	save_stop_obj_processing = 0;
    	last_wc = POSSESS_UNDEF;

	while (1) {
		if ( !fgets (buf, 81, rp) ) {
			perror ("save_rooms");
			fclose (rp);
			return;
		}

		if ( !str_cmp (buf, "\n") )
			continue;

		line_no++;

		if ( *buf == '#' ) {

			rooms++;

			sscanf (buf, "#%d", &room_num);

			save_stop_obj_processing = 0;

			read_obj_list (POSSESS_ROOM, 0, 0, NULL, NULL, rp, room_num);

			if ( vtor (room_num) ) {

				for ( room_obj_count = 0, obj = vtor (room_num)->contents;
					  obj;
					  obj = obj->next_content )
					room_obj_count++;
			}
		}

		else if ( !str_cmp (buf, "END\n") ) {
			snprintf (buf, MAX_STRING_LENGTH,  "Save rooms restored:  %d", rooms);
			break;
		}

		else
			printf ("Unexpected line: %s\n", buf);
	}

	fclose (rp);
	return;
}

void load_save_room (ROOM_DATA *room)
{
	FILE		*rp = NULL;
	char		buf [MAX_STRING_LENGTH] = {'\0'};

	if ( !room || room->psave_loaded )
		return;

	room->psave_loaded = 1;

	snprintf (buf, MAX_STRING_LENGTH,  "save/rooms/%d", room->virtual);

	if ( !(rp = fopen (buf, "r")) ) {
		return;
	}

	file_eof_found = 0;
	save_stop_obj_processing = 0;
    	last_wc = POSSESS_UNDEF;

	read_obj_list (POSSESS_ROOM, 0, 0, NULL, NULL, rp, room->virtual);

	fclose (rp);
	
	return;
}

CHAR_DATA *load_saved_mobiles (CHAR_DATA *ch, char *name)
{
	int			virtual = 0;
	CHAR_DATA	*mob = NULL;
	CHAR_DATA	*last_mob = NULL;
	CHAR_DATA	*return_mob = NULL;
	FILE		*fp = NULL;
	char		buf [MAX_STRING_LENGTH] = {'\0'};
	char		hookup [MAX_STRING_LENGTH] = {'\0'};

	if ( !(fp = fopen (name, "r")) ) {
		return NULL;
	}

	last_mob = ch;

	while ( fgets (buf, 256, fp) ) {

		if ( *buf == ' ' || *buf == '\n' )
			(void)fgets (buf, 255, fp);

		if ( sscanf (buf, "%d %s", &virtual, hookup) != 2 ) {
			fclose (fp);
			return return_mob;
		}

		mob = load_a_saved_mobile (virtual, fp, TRUE);

		if ( !return_mob )
			return_mob = mob;

		char_to_room (mob, mob->in_room);

		if ( last_mob ){
			if ( !str_cmp (hookup, "HITCH") ){
				hitch_char (last_mob, mob);
			}
			else if ( !str_cmp (hookup, "RIDE") ) {
				last_mob->mount = mob;
				mob->mount = last_mob;
			}
		}
		last_mob = mob;
	}

	fclose (fp);

	return return_mob;
}

CHAR_DATA *load_a_saved_mobile (int virtual, FILE *fp, bool stable)
{
	int				i = 0; /* indices */
	int				n = 0;
	int				sn = 0;
	int				last_key = 0;
	int				num_keys = 0;
	int				stabled = 0;
	int				checks = 0;
	struct time_info_data		healing_time;
	char			*p = NULL; /* words */
	char			*p2 = NULL;
	char			buf [MAX_STRING_LENGTH] = {'\0'};
	char			buf2 [MAX_STRING_LENGTH] = {'\0'};
	AFFECTED_TYPE	*af = NULL;
	CHAR_DATA		*mob = NULL;
	CHAR_DATA		*tch = NULL;
	WOUND_DATA		*wound = NULL;
	WOUND_DATA		*tmpwound = NULL;
	LODGED_OBJECT_INFO	*lodged = NULL;
	LODGED_OBJECT_INFO	*tmplodged = NULL;
	char			*temp_arg = NULL;

	struct key_data key_table [] = {
		{ "Room",       TYPE_INT, 		NULL },
		{ "SDesc",		TYPE_STRING,		NULL },
		{ "LDesc",		TYPE_STRING,		NULL },
		{ "Keys",		TYPE_STRING,		NULL },
		{ "FightMode",	TYPE_INT,		NULL },
		{ "Clans",		TYPE_STRING,	NULL },
		{ "ColdloadId",	TYPE_INT,		NULL },
		{ "Flags",      TYPE_INT,		NULL },
		{ "Moves",		TYPE_INT,		NULL },
		{ "Hits",		TYPE_INT,		NULL },
		{ "Speaks",		TYPE_INT,		NULL },
		{ "AffectedBy",	TYPE_INT,		NULL },
		{ "Position",	TYPE_INT,		NULL },
		{ "Act",		TYPE_INT,		NULL },
   		{ "Cond0",      TYPE_INT, 		NULL },
   		{ "Cond1",      TYPE_INT, 		NULL },
   		{ "Cond2",      TYPE_INT, 		NULL },
		{ "Sex",        TYPE_INT, 		NULL },
		{ "Height",     TYPE_INT, 		NULL },
		{ "Frame",      TYPE_INT, 		NULL },
		{ "AccessFlags",TYPE_INT,		NULL },
		{ "SpawnLocation",	TYPE_SPAWN,	NULL },
		{ "Rider",		TYPE_MOUNT,	NULL },
		{ "Mount",		TYPE_MOUNT,	NULL },
		{ "ResetCmd",		TYPE_RESET,	NULL },
		{ "ResetZone",		TYPE_RESETZ,	NULL },
		{ "Skill",		TYPE_SKILL,		NULL },
		{ "Owner",		TYPE_OWNER,		NULL },
		{ "Stabled",		TYPE_STABLED,		NULL },
		{ "Affect",		TYPE_AFFECT,	NULL },
		{ "Wound",		TYPE_WOUND,		NULL },
		{ "Lodged",		TYPE_LODGED,		NULL },
		{ "HasInventory",	TYPE_HAS_INV,		NULL },
		{ "DONE",		TYPE_DONE,		NULL },
		{ "End",		TYPE_END,		NULL },
		{ "\0",			TYPE_INT,		NULL }
	};

	if ( !(mob = load_mobile (virtual)) ) {
		return NULL;
	}

	key_table [n++].ptr = &mob->in_room;
	key_table [n++].ptr = &mob->short_descr;
	key_table [n++].ptr = &mob->long_descr;
	key_table [n++].ptr = &mob->name;
	key_table [n++].ptr = &mob->fight_mode;
	key_table [n++].ptr = &mob->clans;
	key_table [n++].ptr = &mob->coldload_id;
	key_table [n++].ptr = &mob->flags;
	key_table [n++].ptr = &mob->move;
	key_table [n++].ptr = &mob->hit;
	key_table [n++].ptr = &mob->speaks;
	key_table [n++].ptr = &mob->affected_by;
	key_table [n++].ptr = &mob->position;
	key_table [n++].ptr = &mob->act;
	key_table [n++].ptr = &mob->intoxication;
	key_table [n++].ptr = &mob->hunger;
	key_table [n++].ptr = &mob->thirst;
	key_table [n++].ptr = &mob->sex;
	key_table [n++].ptr = &mob->height;
	key_table [n++].ptr = &mob->frame;
	key_table [n++].ptr = &mob->mob->access_flags;
	key_table [n++].ptr = NULL;
	key_table [n++].ptr = NULL;
	key_table [n++].ptr = NULL;
	key_table [n++].ptr = NULL;
	key_table [n++].ptr = NULL;
	key_table [n++].ptr = NULL;

	for ( num_keys = 0; *key_table [num_keys].key; )
		num_keys++;

	for ( ; !feof (fp);) {

		if ( !(p = fread_word (fp)) ) {
			free_char (mob);
			return NULL;
		}

		for ( i = last_key;
			  i < last_key + num_keys &&
				str_cmp (key_table [i % num_keys].key, p);)
			i++;

		i = i % num_keys;

		if ( str_cmp (key_table [i].key, p) ) {
			continue;
		}

		if ( key_table [i].key_type == TYPE_SKILL ||
			 key_table [i].key_type == TYPE_AFFECT ||
			 key_table [i].key_type == TYPE_WOUND ||
			 key_table [i].key_type == TYPE_LODGED ||
			 key_table [i].key_type == TYPE_OWNER ||
			 key_table [i].key_type == TYPE_STABLED ||
			 key_table [i].key_type == TYPE_HAS_INV ||
			 key_table [i].key_type == TYPE_SPAWN ||
			 key_table [i].key_type == TYPE_RESET ||
			 key_table [i].key_type == TYPE_RESETZ ||
			 key_table [i].key_type == TYPE_MOUNT )
			last_key = i;
		else
			last_key = i + 1;

		if ( key_table [i].key_type == TYPE_INT )
			* (int *) key_table [i].ptr = fread_number (fp);

		else if ( key_table [i].key_type == TYPE_SHORTINT )
			* (shortint *) key_table [i].ptr = fread_number (fp);

		else if ( key_table [i].key_type == TYPE_STRING ){
			temp_arg = fread_string(fp);
			* (char **) key_table [i].ptr = unspace (temp_arg);
		}

		else if ( key_table [i].key_type == TYPE_LONG )
			* (long *) key_table [i].ptr = fread_number (fp);

		else if ( key_table [i].key_type == TYPE_OBSOLETE )
			sn = fread_number (fp);

		else if ( key_table [i].key_type == TYPE_SPAWN )
			mob->mob->spawnpoint = fread_number(fp);

		else if ( key_table [i].key_type == TYPE_RESET )
			mob->mob->reset_cmd = fread_number(fp);

		else if ( key_table [i].key_type == TYPE_RESETZ )
			mob->mob->reset_zone = fread_number(fp);

		else if ( key_table [i].key_type == TYPE_STABLED ) {
			stabled = fread_number(fp);
			if ( !stable )
				continue;
			healing_time = real_time_passed (time(0) - stabled, 0);
			checks = ( healing_time.day * 12 );
			checks += ( healing_time.hour / 2 );
			for ( wound = mob->wounds; wound; wound = tmpwound ) {
				tmpwound = wound->next;
				for ( i = 0; i < checks; i++ )
						natural_healing_check(mob, wound);
			}
		}
		else if ( key_table [i].key_type == TYPE_HAS_INV )
			read_obj_suppliment (mob, fp);

		else if ( key_table [i].key_type == TYPE_SKILL ) {
			p = fread_word (fp);
			sn = skill_index_lookup (p);

			if ( sn == -1 )
				sn = skill_index_lookup (p);

			if ( sn == -1 ) {
				return NULL;
			}

			if ( sn > MAX_SKILLS )
				printf ("Skill Num # %d (learned %d) out of range.\n",
						sn, fread_number (fp));
			else
				mob->skills [sn] = fread_number (fp);
		}

		else if ( key_table [i].key_type == TYPE_OWNER ) {
			temp_arg = fread_string(fp);
			mob->mob->owner = unspace(temp_arg);
		}

		else if ( key_table [i].key_type == TYPE_AFFECT ) {

			af = (AFFECTED_TYPE *)alloc (sizeof (AFFECTED_TYPE), 13);

			fscanf (fp, "%d %d %d %d %d %d %d\n",
							&af->type,
							&af->a.spell.duration,
							&af->a.spell.modifier,
							&af->a.spell.location,
							&af->a.spell.bitvector,
							&af->a.spell.sn,
							&af->a.spell.t);
			af->next		= NULL;

			affect_to_char (mob, af);
		}

		else if ( key_table [i].key_type == TYPE_MOUNT ) {
			if ( !(tch = get_char_id (fread_number(fp))) )
				continue;
			if ( mob->mount || tch->mount )
				continue;
			tch->mount = mob;
			mob->mount = tch;
		}

        else if ( key_table [i].key_type == TYPE_WOUND ) {
			CREATE (wound, WOUND_DATA, 1);
            wound->next             = NULL;
			
			temp_arg = fread_word(fp);
			wound->location = add_hash(temp_arg);
			
			temp_arg = fread_word(fp);
			wound->type = add_hash(temp_arg);
			
			temp_arg = fread_word(fp);
			wound->severity = add_hash(temp_arg);
			
			temp_arg = fread_word(fp);
			wound->name = add_hash(temp_arg);
			wound->damage = fread_number(fp);
			wound->bleeding = fread_number(fp);
			wound->poison = fread_number(fp);
			wound->infection = fread_number(fp);
			wound->healerskill = fread_number(fp);
			wound->lasthealed = fread_number(fp);
			wound->lastbled = fread_number(fp);
					
			if ( !mob->wounds )
					mob->wounds = wound;
			else {
					tmpwound = mob->wounds;
					while ( tmpwound->next )
							tmpwound = tmpwound->next;
					tmpwound->next = wound;
			}
		}		

		else if ( key_table [i].key_type == TYPE_LODGED ) {
			lodged = (LODGED_OBJECT_INFO *)alloc ((int)sizeof (LODGED_OBJECT_INFO), 36);
			lodged->next		= NULL;

			temp_arg = fread_word(fp);
			lodged->location = add_hash(temp_arg);
			lodged->vnum = fread_number(fp);

			if ( !mob->lodged )
				mob->lodged = lodged;
			else {
				tmplodged = mob->lodged;
				while ( tmplodged->next )
					tmplodged = tmplodged->next;
				tmplodged->next = lodged;
			}

		}

		else if ( key_table [i].key_type == TYPE_DONE ) {

			REMOVE_BIT (mob->flags, FLAG_ENTERING);
			REMOVE_BIT (mob->flags, FLAG_LEAVING);

			fix_offense (mob);

			if ( get_affect (mob, MAGIC_AFFECT_SLEEP) )
				GET_POS (mob) = SLEEP;

			mob->time.logon = time (0);

			return mob;
		}

		else if ( key_table [i].key_type == TYPE_END ) {
                        p = mob->clans;
                        p2 = p;
                        mob->clans = str_dup ("");

                        while ( 1 ) {

                                p = one_argument (p, buf);              /* flags     */
                                p = one_argument (p, buf2);             /* clan name */

                                if ( !*buf2 )
                                        break;

                                add_clan_id (mob, buf2, buf);
                        }

                        mem_free (p2);
                       
			return mob;
		}
	}

	free_char (mob);

	return NULL;
}

void save_mobile (CHAR_DATA *mob, FILE *fp, char *save_reason, int extract)
{
	AFFECTED_TYPE	*af = NULL;
	int				i = 0;
	WOUND_DATA		*wound = NULL;
	LODGED_OBJECT_INFO	*lodged = NULL;

	if ( !IS_NPC (mob) )
		return;

	fprintf (fp, "%d %s\n", mob->mob->virtual, save_reason);

	fprintf (fp, "Room             %d\n", mob->in_room);
	fprintf (fp, "SDesc            %s~\n", mob->short_descr);
	fprintf (fp, "LDesc            %s~\n", mob->long_descr);
	fprintf (fp, "Keys             %s~\n", mob->name);
	fprintf (fp, "Fightmode        %d\n", mob->fight_mode);
	fprintf (fp, "Clans            %s~\n", mob->clans);
	fprintf (fp, "ColdloadId       %d\n", mob->coldload_id);
	fprintf (fp, "Flags            %d\n", mob->flags);
	fprintf (fp, "Moves            %d\n", mob->move);
	fprintf (fp, "Hits             %d\n", mob->hit);
	fprintf (fp, "Speaks           %d\n", mob->speaks);
	fprintf (fp, "AffectedBy       %ld\n", mob->affected_by);
	fprintf (fp, "Position         %d\n", mob->position);
	fprintf (fp, "Act              %ld\n", mob->act);
	fprintf (fp, "Cond0            %d\n", mob->intoxication);
	fprintf (fp, "Cond1            %d\n", mob->hunger);
	fprintf (fp, "Cond2            %d\n", mob->thirst);
	fprintf (fp, "Sex              %d\n", mob->sex);
	fprintf (fp, "Height           %d\n", mob->height);
	fprintf (fp, "Frame            %d\n", mob->frame);
	fprintf (fp, "AccessFlags      %d\n", mob->mob->access_flags);
	fprintf (fp, "SpawnLocation    %d\n", mob->mob->spawnpoint);
	fprintf (fp, "ResetCmd         %d\n", mob->mob->reset_cmd);
	fprintf (fp, "ResetZone        %d\n", mob->mob->reset_zone);

	if ( IS_RIDEE (mob) && IS_NPC (mob->mount) )
		fprintf (fp, "Rider            %d\n", mob->mount->coldload_id);

	if ( IS_RIDER (mob) && IS_NPC (mob->mount) )
		fprintf (fp, "Mount            %d\n", mob->mount->coldload_id);

	for ( i = 1; i <= LAST_SKILL; i++ ) {
		if ( mob->skills [i] )
			fprintf (fp, "Skill %s %d\n", skill_data[i].skill_name, mob->skills[i]);
	}

	if ( mob->mob->owner )
		fprintf (fp, "Owner            %s~\n", mob->mob->owner);

    for ( af = mob->hour_affects; af; af = af->next )
        if ( (af->type < MAGIC_CLAN_MEMBER_BASE ||
              af->type > MAGIC_CLAN_OMNI_BASE + MAX_CLANS) &&
			 af->type != MAGIC_CLAN_NOTIFY &&
             af->type != MAGIC_NOTIFY &&
             af->type != MAGIC_WATCH1 &&
             af->type != MAGIC_WATCH2 &&
             af->type != MAGIC_WATCH3 &&
			 af->type != MAGIC_GUARD )
            fprintf (fp, "Affect       %d %d %d %d %d %d %d\n",
                        af->type, 
						af->a.spell.duration,
						af->a.spell.modifier,
						af->a.spell.location,
                        af->a.spell.bitvector,
						af->a.spell.sn,
						af->a.spell.t);

        for ( wound = mob->wounds; wound; wound = wound->next ){
        	fprintf (fp, "Wound        %s %s %s %s %d %d %d %d %d %d %d\n",
            	wound->location,
				wound->type,
				wound->severity,
				wound->name,
				wound->damage,
				wound->bleeding,
				wound->poison,
				wound->infection,
				wound->healerskill,
				wound->lasthealed,
				wound->lastbled);
        }


	for ( lodged = mob->lodged; lodged; lodged = lodged->next )
		fprintf (fp, "Lodged        %s %d\n", lodged->location, lodged->vnum);

	if ( mob->equip || mob->right_hand || mob->left_hand ) {
		fprintf (fp, "HasInventory\n");
		write_obj_suppliment (mob, fp);
	}

	fprintf (fp, "Done\n");

	if ( IS_HITCHER (mob) )
		save_mobile (mob->hitchee, fp, "HITCH", extract);
	else
		fprintf (fp, "End\n");

	if ( extract )
		extract_char (mob);
	
	return;
}

void save_attached_mobiles (CHAR_DATA *ch, int extract)
{
	FILE		*fp = NULL;
	char		save_name [MAX_STRING_LENGTH] = {'\0'};

	snprintf (save_name, MAX_STRING_LENGTH, "save/player/%c/%s.a", tolower (*ch->tname), ch->tname);

	if ( !(fp = fopen (save_name, "w")) ) {
		return;
	}

	if ( !IS_HITCHER (ch) && !IS_RIDER (ch) )
		fprintf (fp, "end\n");

	if ( IS_HITCHER (ch) )
		save_mobile (ch->hitchee, fp, "HITCH", extract);

	if ( IS_RIDER (ch) )
		save_mobile (ch->mount, fp, "RIDE", extract);

	fclose (fp);
	return;
}