/
bin/95/
docs/DM/
docs/creatures/
docs/objects/
docs/rooms/
docs/utils/
help/
log/
objmon/ddesc/
player/
post/
rooms/
util/
util/fing/
util/italk/
util/lev-reset/
util/lib/
util/list/
util/msg/
util/tdel/
util/vote/
util/wtfix/
/***************************************************************************
*  Mordor Database Utilities:
*	These functions allow for read/write access to Mordor MUD
*  database files.
*
*	(c) 1996 Brett Vickers & Brooke Paul
*/

#include "mstruct.h"
#include "mextern.h"
#include "utils.h"

/**********************************************************************/
/*				count_obj			      */
/**********************************************************************/

/* Return the total number of objects contained within an object.  */
/* If perm_only != 0, then only the permanent objects are counted. */

int count_obj(obj_ptr, perm_only)
object 	*obj_ptr;
char 	perm_only;
{
	otag	*op;
	int	total=0;

	op = obj_ptr->first_obj;
	while(op) {
		if(!perm_only || (perm_only && (F_ISSET(op->obj, OPERMT) || 
		   F_ISSET(op->obj, OPERM2))))
			total++;
		op = op->next_tag;
	}
	return(total);
}

/**********************************************************************/
/*				write_obj			      */
/**********************************************************************/

/* Save an object to a file that has already been opened and positioned. */
/* This function recursively saves the items that are contained inside   */
/* the object as well.  If perm_only != 0 then only permanent objects	 */
/* within the object are saved with it.					 */

int write_obj(fd, obj_ptr, perm_only)
int 	fd;
object 	*obj_ptr;
char 	perm_only;
{
	int 	n, cnt, cnt2=0, error=0;
	otag	*op;

	n = write(fd, obj_ptr, sizeof(object));
	if(n < sizeof(object))
		merror("write_obj", FATAL);
	
	cnt = count_obj(obj_ptr, perm_only);
	n = write(fd, &cnt, sizeof(int));
	if(n < sizeof(int))
		merror("write_obj", FATAL);

	if(cnt > 0) {
		op = obj_ptr->first_obj;
		while(op) {
			if(!perm_only || (perm_only && 
			   (F_ISSET(op->obj, OPERMT) || 
			   F_ISSET(op->obj, OPERM2)))) {
				if(write_obj(fd, op->obj, perm_only) < 0)
					error = 1;
				cnt2++;
			}
			op = op->next_tag;
		}
	}

	if(cnt != cnt2 || error)
		return(-1);
	else
		return(0);

}

/**********************************************************************/
/*				count_inv			      */
/**********************************************************************/

/* Returns the number of objects a creature has in his inventory. */
/* If perm_only != 0 then only those objects which are permanent  */
/* will be counted.						  */

int count_inv(crt_ptr, perm_only)
creature 	*crt_ptr;
char 		perm_only;
{
	otag	*op;
	int	total=0;

	op = crt_ptr->first_obj;
	while(op) {
		if(!perm_only || (perm_only && (F_ISSET(op->obj, OPERMT) || 
		   F_ISSET(op->obj, OPERM2)))) 
			total++;
		op = op->next_tag;
	}
	return(total);
}

/**********************************************************************/
/*				write_crt			      */
/**********************************************************************/

/* Save a creature to an already open and positioned file.  This function */
/* also saves all the items the creature is holding.  If perm_only != 0   */
/* then only those items which the creature is carrying that are 	  */
/* permanent will be saved.						  */

int write_crt(fd, crt_ptr, perm_only)
int 		fd;
creature 	*crt_ptr;
char 		perm_only;
{
	int 	n, cnt, cnt2=0, error=0;
	otag	*op;

	n = write(fd, crt_ptr, sizeof(creature));
	if(n < sizeof(creature))
		merror("write_crt", FATAL);

	cnt = count_inv(crt_ptr, perm_only);
	n = write(fd, &cnt, sizeof(int));
	if(n < sizeof(int))
		merror("write_crt", FATAL);

	if(cnt > 0) {
		op = crt_ptr->first_obj;
		while(op) {
			if(!perm_only || (perm_only && 
			   (F_ISSET(op->obj, OPERMT) || 
			   F_ISSET(op->obj, OPERM2)))) {
				if(write_obj(fd, op->obj, perm_only) < 0)
					error = 1;
				cnt2++;
			}
			op = op->next_tag;
		}
	}

	if(cnt != cnt2 || error)
		return(-1);
	else
		return(0);
}

/**********************************************************************/
/*				count_mon			      */
/**********************************************************************/

/* Returns the number of monsters in a given room.  If perm_only is */
/* nonzero, then only the number of permanent monsters in the room  */
/* is returned.							    */

int count_mon(rom_ptr, perm_only)
room 	*rom_ptr;
char 	perm_only;
{
	ctag	*cp;
	int	total=0;

	cp = rom_ptr->first_mon;
	while(cp) {
		if(!perm_only || (perm_only && F_ISSET(cp->crt, MPERMT)))
			total++;
		cp = cp->next_tag;
	}
	return(total);
}

/**********************************************************************/
/*				count_ite			      */
/**********************************************************************/

/* Returns the number of items in the room.  If perm_only is nonzero */
/* then only the number of permanent items in the room is returned.  */

int count_ite(rom_ptr, perm_only)
room 	*rom_ptr;
char 	perm_only;
{
	otag 	*op;
	int	total=0;

	op = rom_ptr->first_obj;
	while(op) {
		if(!perm_only || (perm_only && (F_ISSET(op->obj, OPERMT) ||
		   F_ISSET(op->obj, OPERM2))))
			total++;
		op = op->next_tag;
	}
	return(total);
}

/**********************************************************************/
/*				count_ext			      */
/**********************************************************************/

/* Returns the number of exits in the room */

int count_ext(rom_ptr)
room 	*rom_ptr;
{
	xtag	*xp;
	int	total = 0;

	xp = rom_ptr->first_ext;
	while(xp) {
		total++;
		xp = xp->next_tag;
	}
	return(total);
}

/**********************************************************************/
/*				count_ply			      */
/**********************************************************************/

/* Returns the number of players in the room */

int count_ply(rom_ptr)
room 	*rom_ptr;
{
	ctag	*pp;
	int	total = 0;

	pp = rom_ptr->first_ply;
	while(pp) {
		total++;
		pp = pp->next_tag;
	}
	return(total);
}

/**********************************************************************/
/*				write_rom			      */
/**********************************************************************/

/* Saves the room pointed to by rom_ptr with all its contents.  Its */
/* contents include exits, descriptions, items and monsters.  If    */
/* perm_only is nonzero, then only items and monsters in the room   */
/* which are permanent will be saved.				    */

int write_rom(fd, rom_ptr, perm_only)
int 	fd;
room 	*rom_ptr;
char 	perm_only;
{
	int 	n, cnt, error=0;
	xtag	*xp;
	ctag	*cp;
	otag	*op;

	n = write(fd, rom_ptr, sizeof(room));
	if(n < sizeof(room))
		merror("write_rom", FATAL);

	cnt = count_ext(rom_ptr);
	n = write(fd, &cnt, sizeof(int));
	if(n < sizeof(int))
		merror("write_rom", FATAL);

	xp = rom_ptr->first_ext;
	while(xp) {
		n = write(fd, xp->ext, sizeof(exit_));
		if(n < sizeof(exit_))
			merror("write_rom", FATAL);
		xp = xp->next_tag;
	}

	cnt = count_mon(rom_ptr, perm_only);
	n = write(fd, &cnt, sizeof(int));
	if(n < sizeof(int))
		merror("write_rom", FATAL);

	cp = rom_ptr->first_mon;
	while(cp) {
		if(!perm_only || (perm_only && F_ISSET(cp->crt, MPERMT)))
			if(write_crt(fd, cp->crt, 0) < 0)
				error = 1;
		cp = cp->next_tag;
	}

	cnt = count_ite(rom_ptr, perm_only);
	n = write(fd, &cnt, sizeof(int));
	if(n < sizeof(int))
		merror("write_rom", FATAL);

	op = rom_ptr->first_obj;
	while(op) {
		if(!perm_only || (perm_only && (F_ISSET(op->obj, OPERMT) ||
		   F_ISSET(op->obj, OPERM2))))
			if(write_obj(fd, op->obj, perm_only) < 0)
				error = 1;
		op = op->next_tag;
	}

	if(!rom_ptr->short_desc)
		cnt = 0;
	else
		cnt = strlen(rom_ptr->short_desc) + 1;
	n = write(fd, &cnt, sizeof(int));
	if(n < sizeof(int))
		merror("write_rom", FATAL);

	if(cnt) {
		n = write(fd, rom_ptr->short_desc, cnt);
		if(n < cnt)
			merror("write_rom", FATAL);
	}

	if(!rom_ptr->long_desc)
		cnt = 0;
	else
		cnt = strlen(rom_ptr->long_desc) + 1;
	n = write(fd, &cnt, sizeof(int));
	if(n < sizeof(int))
		merror("write_rom", FATAL);

	if(cnt) {
		n = write(fd, rom_ptr->long_desc, cnt);
		if(n < cnt)
			merror("write_rom", FATAL);
	}

	if(!rom_ptr->obj_desc)
		cnt = 0;
	else
		cnt = strlen(rom_ptr->obj_desc) + 1;
	n = write(fd, &cnt, sizeof(int));
	if(n < sizeof(int))
		merror("write_rom", FATAL);

	if(cnt) {
		n = write(fd, rom_ptr->obj_desc, cnt);
		if(n < cnt)
			merror("write_rom", FATAL);
	}

	if(error)
		return(-1);
	else
		return(0);
}

/**********************************************************************/
/*				read_obj			      */
/**********************************************************************/

/* Loads the object from the open and positioned file described by fd */
/* and also loads every object which it might contain.  Returns -1 if */
/* there was an error.						      */

int read_obj(fd, obj_ptr)
int 	fd;
object 	*obj_ptr;
{
	int 		n, cnt, error=0;
	otag		*op;
	otag		**prev;
	object 		*obj;

	n = read(fd, obj_ptr, sizeof(object));
	if(n < sizeof(object))
		error = 1;

	obj_ptr->first_obj = 0;
	obj_ptr->parent_obj = 0;
	obj_ptr->parent_rom = 0;
	obj_ptr->parent_crt = 0;
	if(obj_ptr->shotscur > obj_ptr->shotsmax)
		obj_ptr->shotscur = obj_ptr->shotsmax;

	n = read(fd, &cnt, sizeof(int));
	if(n < sizeof(int)) {
		error = 1;
		cnt = 0;
	}

	prev = &obj_ptr->first_obj;
	while(cnt > 0) {
		cnt--;
		op = (otag *)malloc(sizeof(otag));
		if(op) {
			obj = (object *)malloc(sizeof(object));
			if(obj) {
				if(read_obj(fd, obj) < 0)
					error = 1;
				obj->parent_obj = obj_ptr;
				op->obj = obj;
				op->next_tag = 0;
				*prev = op;
				prev = &op->next_tag;
			}
			else
				merror("read_obj", FATAL);
		}
		else
			merror("read_obj", FATAL);
	}

	if(error)
		return(-1);
	else
		return(0);
}

/**********************************************************************/
/*				read_crt			      */
/**********************************************************************/

/* Loads a creature from an open and positioned file.  The creature is */
/* loaded at the mem location specified by the second parameter.  In   */
/* addition, all the creature's objects have memory allocated for them */
/* and are loaded as well.  Returns -1 on fail.			       */

int read_crt(fd, crt_ptr)
int 		fd;
creature 	*crt_ptr;
{
	int 		n, cnt, error=0;
	otag		*op;
	otag		**prev;
	object 		*obj;

	n = read(fd, crt_ptr, sizeof(creature));
	if(n < sizeof(creature))
		error = 1;

	crt_ptr->first_obj = 0;
	crt_ptr->first_fol = 0;
	crt_ptr->first_enm = 0;
	crt_ptr->parent_rom = 0;
	crt_ptr->following = 0;
	for(n=0; n<20; n++)
		crt_ptr->ready[n] = 0;
	if(crt_ptr->mpcur > crt_ptr->mpmax)
		crt_ptr->mpcur = crt_ptr->mpmax;
	if(crt_ptr->hpcur > crt_ptr->hpmax)
		crt_ptr->hpcur = crt_ptr->hpmax;

	n = read(fd, &cnt, sizeof(int));
	if(n < sizeof(int)) {
		error = 1;
		cnt = 0;
	}

	prev = &crt_ptr->first_obj;
	while(cnt > 0) {
		cnt--;
		op = (otag *)malloc(sizeof(otag));
		if(op) {
			obj = (object *)malloc(sizeof(object));
			if(obj) {
				if(read_obj(fd, obj) < 0) {
					printf("error 3\n");
					error = 1;
				}
				obj->parent_crt = crt_ptr;
				op->obj = obj;
				op->next_tag = 0;
				*prev = op;
				prev = &op->next_tag;
			}
			else
				merror("read_crt", FATAL);
		}
		else
			merror("read_crt", FATAL);
	}

	if(error)
		return(-1);
	else
		return(0);
}

/**********************************************************************/
/*				read_rom			      */
/**********************************************************************/

/* Loads a room from an already open and positioned file into the memory */
/* pointed to by the second parameter.  Also loaded are all creatures,   */
/* exits, objects and descriptions for the room.  -1 is returned upon    */
/* failure.								 */

int read_rom(fd, rom_ptr)
int 	fd;
room 	*rom_ptr;
{
	int 		n, cnt, error=0;
	xtag		*xp;
	xtag		**xprev;
	exit_		*ext;
	ctag		*cp;
	ctag		**cprev;
	creature	*crt;
	otag		*op;
	otag		**oprev;
	object 		*obj;
	char		*sh, *lo, *ob;

	n = read(fd, rom_ptr, sizeof(room));
	if(n < sizeof(room))
		error = 1;

	rom_ptr->short_desc = 0;
	rom_ptr->long_desc  = 0;
	rom_ptr->obj_desc   = 0;
	rom_ptr->first_ext = 0;
	rom_ptr->first_obj = 0;
	rom_ptr->first_mon = 0;
	rom_ptr->first_ply = 0;

	n = read(fd, &cnt, sizeof(int));
	if(n < sizeof(int)) {
		error = 1;
		cnt = 0;
	}

	/* Load the exits */

	xprev = &rom_ptr->first_ext;
	while(cnt > 0) {
		cnt--;
		xp = (xtag *)malloc(sizeof(xtag));
		if(xp) {
			ext = (exit_ *)malloc(sizeof(exit_));
			if(ext) {
				n = read(fd, ext, sizeof(exit_));
				if(n < sizeof(exit_))
					error = 1;
				xp->ext = ext;
				xp->next_tag = 0;
				*xprev = xp;
				xprev = &xp->next_tag;
			}
			else
				merror("read_rom", FATAL);
		}
		else
			merror("read_rom", FATAL);
	}

	/* Read the monsters */

	n = read(fd, &cnt, sizeof(int));
	if(n < sizeof(int)) {
		error = 1;
		cnt = 0;
	}

	cprev = &rom_ptr->first_mon;
	while(cnt > 0) {
		cnt--;
		cp = (ctag *)malloc(sizeof(ctag));
		if(cp) {
			crt = (creature *)malloc(sizeof(creature));
			if(crt) {
				if(read_crt(fd, crt) < 0)
					error = 1;
				crt->parent_rom = rom_ptr;
				cp->crt = crt;
				cp->next_tag = 0;
				*cprev = cp;
				cprev = &cp->next_tag;
			}
			else
				merror("read_rom", FATAL);
		}
		else
			merror("read_rom", FATAL);
	}

	/* Read the items */

	n = read(fd, &cnt, sizeof(int));
	if(n < sizeof(int)) {
		error = 1;
		cnt = 0;
	}

	oprev = &rom_ptr->first_obj;
	while(cnt > 0) {
		cnt--;
		op = (otag *)malloc(sizeof(otag));
		if(op) {
			obj = (object *)malloc(sizeof(object));
			if(obj) {
				if(read_obj(fd, obj) < 0)
					error = 1;
				obj->parent_rom = rom_ptr;
				op->obj = obj;
				op->next_tag = 0;
				*oprev = op;
				oprev = &op->next_tag;
			}
			else
				merror("read_rom", FATAL);
		}
		else
			merror("read_rom", FATAL);
	}

	/* Read the descriptions */

	n = read(fd, &cnt, sizeof(int));
	if(n < sizeof(int)) {
		error = 1;
		cnt = 0;
	}

	if(cnt) {
		sh = (char *)malloc(cnt);
		if(sh) {
			n = read(fd, sh, cnt);
			if(n < cnt)
				error = 1;
			rom_ptr->short_desc = sh;
		}
		else
			merror("read_rom", FATAL);
	}

	n = read(fd, &cnt, sizeof(int));
	if(n < sizeof(int)) {
		error = 1;
		cnt = 0;
	}

	if(cnt) {
		lo = (char *)malloc(cnt);
		if(lo) {
			n = read(fd, lo, cnt);
			if(n < cnt)
				error = 1;
			rom_ptr->long_desc = lo;
		}
		else
			merror("read_rom", FATAL);
	}

	n = read(fd, &cnt, sizeof(int));
	if(n < sizeof(int)) {
		error = 1;
		cnt = 0;
	}

	if(cnt) {
		ob = (char *)malloc(cnt);
		if(ob) {
			n = read(fd, ob, cnt);
			if(n < cnt)
				error = 1;
			rom_ptr->obj_desc = ob;
		}
		else
			merror("read_rom", FATAL);
	}

	if(error)
		return(-1);
	else
		return(0);
}

/**********************************************************************/
/*				free_obj			      */
/**********************************************************************/

/* This function is called to release the object pointed to by the first */
/* parameter from memory.  All objects contained within it are also      */
/* released from memory.  */

void free_obj(obj_ptr)
object	*obj_ptr;
{
	otag	*op, *temp;

	op = obj_ptr->first_obj;
	while(op) {
		temp = op->next_tag;
		free_obj(op->obj);
		free(op);
		op = temp;
	}
	free(obj_ptr);
}

/**********************************************************************/
/*				free_crt			      */
/**********************************************************************/

/* This function releases the creature pointed to by the first parameter */
/* from memory.  All items that creature has readied or carries will     */
/* also be released. */

void free_crt(crt_ptr)
creature	*crt_ptr;
{
	otag	*op, *temp;

	op = crt_ptr->first_obj;
	while(op) {
		temp = op->next_tag;
		free_obj(op->obj);
		free(op);
		op = temp;
	}

	free(crt_ptr);
}

/**********************************************************************/
/*				free_rom			      */
/**********************************************************************/

/* This function releases the a room and its contents from memory.  The */
/* function is passed the room's pointer as its parameter.  The exits,  */
/* descriptions, objects and monsters are all released from memory.     */

void free_rom(rom_ptr)
room	*rom_ptr;
{
	xtag 	*xp, *xtemp;
	otag	*op, *otemp;
	ctag	*cp, *ctemp;

	free(rom_ptr->short_desc);
	free(rom_ptr->long_desc);
	free(rom_ptr->obj_desc);

	xp = rom_ptr->first_ext;
	while(xp) {
		xtemp = xp->next_tag;
		free(xp->ext);
		free(xp);
		xp = xtemp;
	}

	op = rom_ptr->first_obj;
	while(op) {
		otemp = op->next_tag;
		free_obj(op->obj);
		free(op);
		op = otemp;
	}

	cp = rom_ptr->first_mon;
	while(cp) {
		ctemp = cp->next_tag;
		free_crt(cp->crt);
		free(cp);
		cp = ctemp;
	}

	free(rom_ptr);

}

int load_rom_from_file(num, rom_ptr)
int     num;
room    **rom_ptr;
{
        int fd;
        long n;
        char file[80];

        *rom_ptr = (room *)malloc(sizeof(room));
        if(!*rom_ptr)
                merror("load_from_file", FATAL);
        zero(*rom_ptr, sizeof(room));

        sprintf(file, "%s/r%05d", ROOMPATH, num);
        fd = open(file, O_RDONLY | O_BINARY, 0);
        if(fd < 0)
                return(-1);
        n = read_rom(fd, *rom_ptr);
        if(n < 0) {
                close(fd);
                return(-1);   
        }
        close(fd);

        return(0);
}

void merror(str, errtype)
char    *str;
int     errtype;
{
        printf("Error: %s\n", str);
        if(errtype == FATAL)
                exit(-1);
}

void zero(ptr, size)
void    *ptr;
int     size;
{
        char    *chptr;
        int     i;
        
        chptr = (char *)ptr;
        for(i=0; i<size; i++)
                chptr[i] = 0;
}
int load_crt_from_file(num, crt_ptr)
int             num;
creature        **crt_ptr;
{
        int fd;
        long n;
        char file[80];
                        
        *crt_ptr = (creature *)malloc(sizeof(creature));
        if(!*crt_ptr)
                merror("load_from_file", FATAL);
        zero(*crt_ptr, sizeof(creature));

        sprintf(file, "%s/m%02d", MONPATH, num/MFILESIZE);
        fd = open(file, O_RDONLY | O_BINARY, 0);
        if(fd < 0)
                return(-1);
        n = lseek(fd, (long)((num%MFILESIZE)*sizeof(creature)), 0);
        if(n < 0L) {
                close(fd);
                return(-1);
        }
        n = read(fd, *crt_ptr, sizeof(creature));
        if(n < sizeof(creature)) {
                close(fd);
                return(-1);
        }
        close(fd);

        return(0);   
}

int load_obj_from_file(num, obj_ptr)
int     num;
object  **obj_ptr;
{
        int fd;
        long n;
        char file[80];
                        
        *obj_ptr = (object *)malloc(sizeof(object));
        if(!*obj_ptr)
                merror("load_from_file", FATAL);
        zero(*obj_ptr, sizeof(object));

        sprintf(file, "%s/o%02d", OBJPATH, num/OFILESIZE);
        fd = open(file, O_RDONLY | O_BINARY, 0);
        if(fd < 0)
                return(-1);
        n = lseek(fd, (long)((num%OFILESIZE)*sizeof(object)), 0);
        if(n < 0L) {
                close(fd);
                return(-1);
        }   
        n = read(fd, *obj_ptr, sizeof(object));
        if(n < sizeof(object)) {
                close(fd);
                return(-1);
        }
        close(fd);

        return(0);   
}

int save_rom_to_file(num, rom_ptr)
int     num;
room    *rom_ptr;
{
        int fd;
        long n; 
        char file[80];

        sprintf(file, "%s/r%05d", ROOMPATH, num);
        unlink(file);
        fd = open(file, O_RDWR | O_CREAT | O_BINARY, ACC);
        if(fd < 0)
                return(-1);

        n = write_rom(fd, rom_ptr);
        if(n < 0) {
                close(fd);
                return(-1);
        }
        close(fd);

        return(0);
}

void posit(x, y)
int x,y;
{
        printf("%c[%d;%df", 27, x, y);
}

void clearscreen()
{
        printf("%c[2J",27);
}

void spin(x)
{
	switch(x) {
    
				case 1:
                                        posit(8,10); printf("| \n");
                                        break;

                                case 2:
                                        posit(8,10); printf("/ \n");
                                        break;

				
				case 3:
					posit(8,10); printf("\\ \n");
					break;

				default:
					posit(8,10); printf("- \n");
					break;
	}
}

void message(str)
char	str[80];
{
static int count=0;
       int len, loc;


	if(strlen(str)<79) {
		len=79-strlen(str);
		while(len) {
			strcat(str, " ");
			len -= 1;
		}
	}
	count++;
	if(count>10)
		count=-1;
	loc = count+13;
	posit(loc, 10);
	printf("%s", str);
}

int load_ply_from_file(str, ply_ptr)
char            *str;
creature        **ply_ptr;
{
        int fd;
        long n;
        char file[80];
#ifdef COMPRESS
        char *a_buf, *b_buf;
        int size;
#endif

        *ply_ptr = (creature *)malloc(sizeof(creature));
        if(!*ply_ptr)
                merror("load_from_file", FATAL);
        zero(*ply_ptr, sizeof(creature));
        sprintf(file, "%s/%s", PLAYERPATH, str);  
        fd = open(file, O_RDONLY | O_BINARY, 0);
        if(fd < 0)
                return(-1);

#ifdef COMPRESS
        a_buf = (char *)malloc(30000);
        if(!a_buf) merror(FATAL, "Memory allocation");
        size = read(fd, a_buf, 30000);
        if(size >= 30000) merror(FATAL, "Player too large");
        if(size < 1) {
                close(fd);
                return(-1);
        }
        b_buf = (char *)malloc(80000);
        if(!b_buf) merror(FATAL, "Memory allocation");
        n = uncompress(a_buf, b_buf, size);
        if(n > 80000) merror(FATAL, "Player too large");
        n = read_crt_from_mem(b_buf, *ply_ptr, 0);
        free(a_buf);
        free(b_buf);
#else
        n = read_crt(fd, *ply_ptr);
        if(n < 0) {
                close(fd);
                return(-1);
        }
#endif

        close(fd);
                
        return(0);
}


/************************************************************************/
/*				write_crt_to_mem			*/
/************************************************************************/

/* Save a creature to memory.  This function 				*/
/* also saves all the items the creature is holding.  If perm_only != 0 */
/* then only those items which the creature is carrying that are	*/
/* permanent will be saved.						*/

int write_crt_to_mem(buf, crt_ptr, perm_only)
char		*buf;
creature 	*crt_ptr;
char 		perm_only;
{
	int 	n, cnt, cnt2=0, error=0;
	char	*bufstart;
	otag	*op;

	bufstart = buf;

	memcpy(buf, crt_ptr, sizeof(creature));
	buf += sizeof(creature);

	cnt = count_inv(crt_ptr, perm_only);
	memcpy(buf, &cnt, sizeof(int));
	buf += sizeof(int);

	if(cnt > 0) {
		op = crt_ptr->first_obj;
		while(op) {
			if(!perm_only || (perm_only && 
			   (F_ISSET(op->obj, OPERMT) || 
			   F_ISSET(op->obj, OPERM2)))) {
				if((n = write_obj_to_mem(buf, op->obj,
				    perm_only)) < 0)
					error = 1;
				else
					buf += n;
				cnt2++;
			}
			op = op->next_tag;
		}
	}

	if(cnt != cnt2 || error)
		return(-1);
	else
		return(buf - bufstart);
}

/************************************************************************/
/*				read_crt_from_mem			*/
/************************************************************************/

/* Loads a creature from memory & returns bytes read.  The creature is	*/
/* loaded at the mem location specified by the second parameter.  In	*/
/* addition, all the creature's objects have memory allocated for them	*/
/* and are loaded as well.  Returns -1 on fail.				*/

int read_crt_from_mem(buf, crt_ptr)
char		*buf;
creature 	*crt_ptr;
{
	int 		n, cnt, error=0;
	char		*bufstart;
	otag		*op;
	otag		**prev;
	object 		*obj;

	bufstart = buf;

	memcpy(crt_ptr, buf, sizeof(creature));
	buf += sizeof(creature);

	crt_ptr->first_obj = 0;
	crt_ptr->first_fol = 0;
	crt_ptr->first_enm = 0;
	crt_ptr->parent_rom = 0;
	crt_ptr->following = 0;
	for(n=0; n<20; n++)
		crt_ptr->ready[n] = 0;
	if(crt_ptr->mpcur > crt_ptr->mpmax)
		crt_ptr->mpcur = crt_ptr->mpmax;
	if(crt_ptr->hpcur > crt_ptr->hpmax)
		crt_ptr->hpcur = crt_ptr->hpmax;

	memcpy(&cnt, buf, sizeof(int));
	buf += sizeof(int);

	prev = &crt_ptr->first_obj;
	while(cnt > 0) {
		cnt--;
		op = (otag *)malloc(sizeof(otag));
		if(op) {
			obj = (object *)malloc(sizeof(object));
			if(obj) {
				if((n = read_obj_from_mem(buf, obj)) < 0)
					error = 1;
				else
					buf += n;
				obj->parent_crt = crt_ptr;
				op->obj = obj;
				op->next_tag = 0;
				*prev = op;
				prev = &op->next_tag;
			}
			else
				merror("read_crt", FATAL);
		}
		else
			merror("read_crt", FATAL);
	}

	if(error)
		return(-1);
	else
		return(buf - bufstart);
}

/************************************************************************/
/*				write_obj_to_mem			*/
/************************************************************************/

/* Save an object to a block of memory.					*/
/* This function recursively saves the items that are contained inside	*/
/* the object as well.  If perm_only != 0 then only permanent objects	*/
/* within the object are saved with it.  This function returns the	*/
/* number of bytes that were written.					*/

int write_obj_to_mem(buf, obj_ptr, perm_only)
char	*buf;
object 	*obj_ptr;
char 	perm_only;
{
	int 	n, cnt, cnt2=0, error=0;
	char	*bufstart;
	otag	*op;

	bufstart = buf;

	memcpy(buf, obj_ptr, sizeof(object));
	buf += sizeof(object);
	
	cnt = count_obj(obj_ptr, perm_only);
	memcpy(buf, &cnt, sizeof(int));
	buf += sizeof(int);

	if(cnt > 0) {
		op = obj_ptr->first_obj;
		while(op) {
			if(!perm_only || (perm_only && 
			   (F_ISSET(op->obj, OPERMT) || 
			   F_ISSET(op->obj, OPERM2)))) {
				if((n = write_obj_to_mem(buf, 
				    op->obj, perm_only)) < 0)
					error = 1;
				else
					buf += n;
				cnt2++;
			}
			op = op->next_tag;
		}
	}

	if(cnt != cnt2 || error)
		return(-1);
	else
		return(buf - bufstart);

}

/************************************************************************/
/*				read_obj_from_mem			*/
/************************************************************************/

/* Loads the object from memory, returns the number of bytes read,	*/
/* and also loads every object which it might contain.  Returns -1 if	*/
/* there was an error.							*/

int read_obj_from_mem(buf, obj_ptr)
char	*buf;
object 	*obj_ptr;
{
	int 		n, cnt, error=0;
	char		*bufstart;
	otag		*op;
	otag		**prev;
	object 		*obj;

	bufstart = buf;

	memcpy(obj_ptr, buf, sizeof(object));
	buf += sizeof(object);

	obj_ptr->first_obj = 0;
	obj_ptr->parent_obj = 0;
	obj_ptr->parent_rom = 0;
	obj_ptr->parent_crt = 0;
	if(obj_ptr->shotscur > obj_ptr->shotsmax)
		obj_ptr->shotscur = obj_ptr->shotsmax;

	memcpy(&cnt, buf, sizeof(int));
	buf += sizeof(int);

	prev = &obj_ptr->first_obj;
	while(cnt > 0) {
		cnt--;
		op = (otag *)malloc(sizeof(otag));
		if(op) {
			obj = (object *)malloc(sizeof(object));
			if(obj) {
				if((n = read_obj_from_mem(buf, obj)) < 0)
					error = 1;
				else
					buf += n;
				obj->parent_obj = obj_ptr;
				op->obj = obj;
				op->next_tag = 0;
				*prev = op;
				prev = &op->next_tag;
			}
			else
				merror("read_obj", FATAL);
		}
		else
			merror("read_obj", FATAL);
	}

	if(error)
		return(-1);
	else
		return(buf - bufstart);
}

int save_obj_to_file(num, obj_ptr)
int     num;
object  *obj_ptr;
{
        int fd;
        long n;
        char file[80];

        sprintf(file, "%s/o%02d", OBJPATH, num/OFILESIZE);
        fd = open(file, O_RDWR | O_BINARY, 0);
        if(fd < 0) {
                fd = open(file, O_RDWR | O_CREAT | O_BINARY, ACC);
                if(fd < 0)
                        return(-1);
        }
        n = lseek(fd, (long)((num%OFILESIZE)*sizeof(object)), 0);
        if(n < 0L) {
                close(fd);
                return(-1);
        }
        n = write(fd, obj_ptr, sizeof(object));
        if(n < sizeof(object)) {
                close(fd);
                return(-1);
        }
        close(fd);

        return(0);
}

int save_crt_to_file(num, crt_ptr)
int             num;
creature        *crt_ptr;
{
        int fd;
        long n;
        char file[80];

        sprintf(file, "%s/m%02d", MONPATH, num/MFILESIZE);
        fd = open(file, O_RDWR | O_BINARY, 0);
        if(fd < 0) {
                fd = open(file, O_RDWR | O_CREAT | O_BINARY, ACC);
                if(fd < 0)
                        return(-1);
        }
        n = lseek(fd, (long)((num%MFILESIZE)*sizeof(creature)), 0);
        if(n < 0L) {
                close(fd);
                return(-1);
        }
        n = write(fd, crt_ptr, sizeof(creature));
        if(n < sizeof(creature)) {
                close(fd);
                return(-1);
        }
        close(fd);

        return(0);
}

int save_ply_to_file(str, ply_ptr)
char            *str;
creature        *ply_ptr;
{
        int fd;
        long n;
        char file[80];
#ifdef COMPRESS
        char *a_buf, *b_buf;
        int size;
#endif

        sprintf(file, "%s/%s", PLAYERPATH, str);
        unlink(file);
        fd = open(file, O_RDWR | O_CREAT | O_BINARY, ACC);
        if(fd < 0)
                return(-1);

#ifdef COMPRESS
        a_buf = (char *)malloc(80000);
        if(!a_buf) merror(FATAL, "Memory allocation");
        n = write_crt_to_mem(a_buf, ply_ptr, 0);
        if(n > 80000) merror(FATAL, "Player too large");
        b_buf = (char *)malloc(n);
        if(!b_buf) merror(FATAL, "Memory allocation");
        size = compress(a_buf, b_buf, n);
        n = write(fd, b_buf, size);
        free(a_buf);
        free(b_buf);
#else
        n = write_crt(fd, ply_ptr, 0);
        if(n < 0) {
                close(fd);
                return(-1);
        }
#endif

        close(fd);

        return(0);
}