kbkmud/player/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Thanks to abaddon for proof-reading our comm.c and pointing out bugs.  *
 *  Any remaining bugs are, of course, our work, not his.  :)              *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

/***************************************************************************
*	ROM 2.4 is copyright 1993-1996 Russ Taylor			   *
*	ROM has been brought to you by the ROM consortium		   *
*	    Russ Taylor (rtaylor@pacinfo.com)				   *
*	    Gabrielle Taylor (gtaylor@pacinfo.com)			   *
*	    Brian Moore (rom@rom.efn.org)				   *
*	By using this code, you have agreed to follow the terms of the	   *
*	ROM license, in the file Tartarus/doc/rom.license                  *
***************************************************************************/

/***************************************************************************
*       Tartarus code is copyright (C) 1997-1998 by Daniel Graham          *
*	In using this code you agree to comply with the Tartarus license   *
*       found in the file /Tartarus/doc/tartarus.doc                       *
***************************************************************************/
/**************************************************************************
 *  File: olc_save.c                                                       *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 *                                                                         *
 *  This code was freely distributed with the The Isles 1.1 source code,   *
 *  and has been used here for OLC - OLC would not be what it is without   *
 *  all the previous coders who released their source code.                *
 *                                                                         *
 ***************************************************************************/
/* OLC_SAVE.C
 * This takes care of saving all the .are information.
 * Notes:
 * -If a good syntax checker is used for setting vnum ranges of areas
 *  then it would become possible to just cycle through vnums instead
 *  of using the iHash stuff and checking that the room or reset or
 *  mob etc is part of that area.
 */

#include "include.h"

#define DIF(a,b) (~((~a)|(b)))

/*
 *  Verbose writes reset data in plain english into the comments
 *  section of the resets.  It makes areas considerably larger but
 *  may aid in debugging.
 */

/* #define VERBOSE */

/*****************************************************************************
 Name:		fix_string
 Purpose:	Returns a string without \r and ~.
 ****************************************************************************/
char *fix_string( const char *str )
{
    static char strfix[MAX_STRING_LENGTH * 2];
    int i;
    int o;

    if ( str == NULL )
        return '\0';

    for ( o = i = 0; str[i+o] != '\0'; i++ )
    {
        if (str[i+o] == '\r' || str[i+o] == '~')
            o++;
        strfix[i] = str[i+o];
    }
    strfix[i] = '\0';
    return strfix;
}



/*****************************************************************************
 Name:		save_area_list
 Purpose:	Saves the listing of files to be loaded at startup.
 Called by:	do_asave(olc_save.c).
 ****************************************************************************/
void save_area_list()
{
    FILE *fp;
    AREA_DATA *pArea;
    extern HELP_AREA *had_list;
    HELP_AREA *ha;

    if ( ( fp = fopen( "area.lst", "w" ) ) == NULL )
    {
	bug( "Save_area_list: fopen", 0 );
	perror( "area.lst" );
    }
    else
    {
        fprintf (fp, "social.are\n"); /* Add our socials to the list */
	/*
	 * Add any help files that need to be loaded at
	 * startup to this section.
	 */
        for (ha = had_list; ha; ha = ha->next)
            if (ha->area == NULL)
                fprintf (fp, "%s\n", ha->filename);

	for( pArea = area_first; pArea; pArea = pArea->next )
	{
	    fprintf( fp, "%s\n", pArea->file_name );
	}

	fprintf( fp, "$\n" );
	fclose( fp );
    }

    return;
}


/*
 * ROM OLC
 * Used in save_mobile and save_object below.  Writes
 * flags on the form fread_flag reads.
 * 
 * buf[] must hold at least 32+1 characters.
 *
 * -- Hugin
 */
char *fwrite_flag( long flags, char buf[] )
{
    char offset;
    char *cp;

    buf[0] = '\0';

    if ( flags == 0 )
    {
	strcpy( buf, "0" );
	return buf;
    }

    /* 32 -- number of bits in a long */

    for ( offset = 0, cp = buf; offset < 32; offset++ )
	if ( flags & ( (long)1 << offset ) )
	{
	    if ( offset <= 'Z' - 'A' )
		*(cp++) = 'A' + offset;
	    else
		*(cp++) = 'a' + offset - ( 'Z' - 'A' + 1 );
	}

    *cp = '\0';

    return buf;
}


/*****************************************************************************
 Name:		save_mobile
 Purpose:	Save one mobile to file, new format -- Hugin
 Called by:	save_mobiles (below).
 ****************************************************************************/
void save_mobile( FILE *fp, MOB_INDEX_DATA *pMobIndex )
{
    return;
}

/*****************************************************************************
 Name:		save_mobiles
 Purpose:	Save #MOBILES secion of an area file.
 Called by:	save_area(olc_save.c).
 Notes:         Changed for ROM OLC.
 ****************************************************************************/
void save_mobiles( FILE *fp, AREA_DATA *pArea )
{
    int i;
    MOB_INDEX_DATA *pMob;

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

    for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
    {
	if ( (pMob = get_mob_index( i )) )
	    save_mobile( fp, pMob );
    }

    fprintf( fp, "#0\n\n\n\n" );
    return;
}





/*****************************************************************************
 Name:		save_object
 Purpose:	Save one object to file.
                new ROM format saving -- Hugin
 Called by:	save_objects (below).
 ****************************************************************************/
void save_object( FILE *fp, OBJ_INDEX_DATA *pObjIndex )
{
    AFFECT_DATA *pAf;
    EXTRA_DESCR_DATA *pEd;
    char buf[MAX_STRING_LENGTH];

    fprintf( fp, "#%ld\n",    pObjIndex->vnum );
    fprintf( fp, "%s~\n",    pObjIndex->name );
    fprintf( fp, "%s~\n",    pObjIndex->short_descr );
    fprintf( fp, "%s~\n",    fix_string( pObjIndex->description ) );
    fprintf( fp, "%s~\n",    pObjIndex->material->name );
    fprintf( fp, "%s ",      item_name(pObjIndex->item_type));
    save_bitmask(&pObjIndex->extra_flags, fp);
    fprintf( fp, "%s\n",     fwrite_flag( pObjIndex->wear_flags,  buf ) );

/*
 *  Using fwrite_flag to write most values gives a strange
 *  looking area file, consider making a case for each
 *  item type later.
 */

    switch ( pObjIndex->item_type )
    {
        default:
	    fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[0], buf ) );
	    fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[1], buf ) );
	    fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[2], buf ) );
	    fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[3], buf ) );
	    fprintf( fp, "%s\n", fwrite_flag( pObjIndex->value[4], buf ) );
	    break;

        case ITEM_LIGHT:
	    fprintf( fp, "0 0 %ld 0 0\n",
		     pObjIndex->value[2] < 1 ? 999  /* infinite */
		     : pObjIndex->value[2] );
	    break;

        case ITEM_MONEY:
            fprintf( fp, "%ld 0 0 0 0\n",
                     pObjIndex->value[0] );
            break;
            
        case ITEM_DRINK_CON:
            fprintf( fp, "%ld %ld '%s' %ld 0\n",
                     pObjIndex->value[0],
                     pObjIndex->value[1],
                     liq_table[pObjIndex->value[2]].liq_name,
/*                   fwrite_flag( pObjIndex->value[3], buf ) ); */
		     pObjIndex->value[3]);
            break;
                    
	case ITEM_FOUNTAIN:
	    fprintf( fp, "%ld %ld '%s' 0 0\n",
	             pObjIndex->value[0],
	             pObjIndex->value[1],
	             liq_table[pObjIndex->value[2]].liq_name);
	    break;
	    
        case ITEM_CONTAINER:
            fprintf( fp, "%ld %s %ld %ld %ld\n",
                     pObjIndex->value[0],
                     fwrite_flag( pObjIndex->value[1], buf ),
                     pObjIndex->value[2],
                     pObjIndex->value[3],
                     pObjIndex->value[4]);
            break;
            
        case ITEM_FOOD:
            fprintf( fp, "%ld %ld 0 %s 0\n",
                     pObjIndex->value[0],
                     pObjIndex->value[1],
                     fwrite_flag( pObjIndex->value[3], buf ) );
            break;
            
        case ITEM_PORTAL:
            fprintf( fp, "%ld %s %s %ld 0\n",
                     pObjIndex->value[0],
                     fwrite_flag( pObjIndex->value[1], buf ),
                     fwrite_flag( pObjIndex->value[2], buf ),
                     pObjIndex->value[3]);
            break;
            
        case ITEM_FURNITURE:
            fprintf( fp, "%ld %ld %s %ld %ld\n",
                     pObjIndex->value[0],
                     pObjIndex->value[1],
                     fwrite_flag( pObjIndex->value[2], buf),
                     pObjIndex->value[3],
                     pObjIndex->value[4]);
            break;
            
        case ITEM_WEAPON:
            fprintf( fp, "%s %ld %ld %s %s\n",
                     weapon_name(pObjIndex->value[0]),
                     pObjIndex->value[1],
                     pObjIndex->value[2],
                     attack_table[pObjIndex->value[3]].name,
                     fwrite_flag( pObjIndex->value[4], buf ) );
            break;
            
        case ITEM_ARMOR:
            fprintf( fp, "%ld %ld %ld %ld %ld\n",
                     pObjIndex->value[0],
                     pObjIndex->value[1],
                     pObjIndex->value[2],
                     pObjIndex->value[3],
                     pObjIndex->value[4]);
            break;
            
        case ITEM_PILL:
        case ITEM_POTION:
        case ITEM_SCROLL:
	    fprintf( fp, "%ld '%s' '%s' '%s' '%s'\n",
		     pObjIndex->value[0] > 0 ? /* no negative numbers */
		     pObjIndex->value[0]
		     : 0,
		     pObjIndex->value[1] != -1 ?
		     skill_table[pObjIndex->value[1]].name
		     : "",
		     pObjIndex->value[2] != -1 ?
		     skill_table[pObjIndex->value[2]].name
		     : "",
		     pObjIndex->value[3] != -1 ?
		     skill_table[pObjIndex->value[3]].name
		     : "",
		     pObjIndex->value[4] != -1 ?
		     skill_table[pObjIndex->value[4]].name
		     : "");
	    break;

        case ITEM_STAFF:
        case ITEM_WAND:
	    fprintf( fp, "%ld ", pObjIndex->value[0] );
	    fprintf( fp, "%ld ", pObjIndex->value[1] );
	    fprintf( fp, "%ld '%s' 0\n",
		     pObjIndex->value[2],
		     pObjIndex->value[3] != -1 ?
		       skill_table[pObjIndex->value[3]].name
		       : 0 );
	    break;
    }

    fprintf( fp, "%d ", pObjIndex->level );
    fprintf( fp, "%d ", pObjIndex->weight );
    fprintf( fp, "%d ", pObjIndex->cost );
    fprintf( fp, "%c\n", 'p' );

    for( pAf = pObjIndex->affected; pAf; pAf = pAf->next )
    {
	if (pAf->where == TO_OBJECT || pAf->bitvector == 0)
	        fprintf( fp, "A\n%d %d\n",  pAf->location, pAf->modifier );
	else
	{
		fprintf( fp, "F\n" );
	
		switch(pAf->where)
		{
			case TO_AFFECTS:
				fprintf( fp, "A " );
				break;
			case TO_IMMUNE:
				fprintf( fp, "I " );
				break;
			case TO_RESIST:
				fprintf( fp, "R " );
				break;
			case TO_VULN:
				fprintf( fp, "V " );
				break;
			default:
				bug( "olc_save: Invalid Affect->where", 0);
				break;
		}
		
		fprintf( fp, "%d %d %s\n", pAf->location, pAf->modifier,
				fwrite_flag( pAf->bitvector, buf ) );
	}
    }

    for( pEd = pObjIndex->extra_descr; pEd; pEd = pEd->next )
    {
        fprintf( fp, "E\n%s~\n%s~\n", pEd->keyword,
		 fix_string( pEd->description ) );
    }

    if ( pObjIndex->cabal )
	{
	fprintf( fp, "C\n%d\n", pObjIndex->cabal );
	}

    if ( pObjIndex->limtotal )
	{
	fprintf( fp, "L\n%d\n", pObjIndex->limtotal );
	}

    if ( pObjIndex->restrict_flags )
	{
	fprintf( fp, "R\n%s\n",      fwrite_flag( pObjIndex->restrict_flags, buf ) );
	}

    return;
}
 



/*****************************************************************************
 Name:		save_objects
 Purpose:	Save #OBJECTS section of an area file.
 Called by:	save_area(olc_save.c).
 Notes:         Changed for ROM OLC.
 ****************************************************************************/
void save_objects( FILE *fp, AREA_DATA *pArea )
{
    int i;
    OBJ_INDEX_DATA *pObj;

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

    for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
    {
	if ( (pObj = get_obj_index( i )) )
	    save_object( fp, pObj );
    }

    fprintf( fp, "#0\n\n\n\n" );
    return;
}
 




/*****************************************************************************
 Name:		save_rooms
 Purpose:	Save #ROOMS section of an area file.
 Called by:	save_area(olc_save.c).
 ****************************************************************************/
void save_rooms( FILE *fp, AREA_DATA *pArea )
{
    ROOM_INDEX_DATA *pRoomIndex;
    EXTRA_DESCR_DATA *pEd;
    EXIT_DATA *pExit;
    int iHash;
    int door;
    char buf[MAX_STRING_LENGTH];

    fprintf( fp, "#ROOMS\n" );
    for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
    {
        for( pRoomIndex = room_index_hash[iHash]; pRoomIndex; pRoomIndex = pRoomIndex->next )
        {
            if ( pRoomIndex->area == pArea )
            {
                fprintf( fp, "#%ld\n",		pRoomIndex->vnum );
                fprintf( fp, "%s~\n",		pRoomIndex->name );
                fprintf( fp, "%s~\n",		fix_string( pRoomIndex->description ) );
		fprintf( fp, "0 " );
                fprintf( fp, "%d ",		pRoomIndex->room_flags );
                fprintf( fp, "%d\n",		pRoomIndex->sector_type );

                for ( pEd = pRoomIndex->extra_descr; pEd;
                      pEd = pEd->next )
                {
                    fprintf( fp, "E\n%s~\n%s~\n", pEd->keyword,
                                                  fix_string( pEd->description ) );
                }

		for ( door = 0; door <MAX_DIR; door++ )
    		{
      		    if ((pExit = pRoomIndex->exit[door]) && (pExit->u1.to_room ))
      	 	    {
        		fprintf( fp, "D%ld\n",		pExit->orig_door );
        		fprintf( fp, "%s~\n",		fix_string( pExit->description));
        		fprintf( fp, "%s~\n",		pExit->keyword );
        		fprintf( fp, "%s %ld %ld\n",	fwrite_flag(pExit->rs_flags, buf),
				pExit->key, pExit->u1.to_room->vnum );
      		    }
    		}

		if (pRoomIndex->mana_rate != 100 || pRoomIndex->heal_rate != 100)
		    fprintf ( fp, "M %d H %d\n",pRoomIndex->mana_rate, pRoomIndex->heal_rate);
		 			     
		if (pRoomIndex->owner && str_cmp(pRoomIndex->owner,""))
		    fprintf ( fp, "O %s~\n" , pRoomIndex->owner );

		if (pRoomIndex->cabal)
		    fprintf( fp, "C\n%s~\n", cabal_table[pRoomIndex->cabal].name);

		fprintf( fp, "S\n" );
            }
        }
    }
    fprintf( fp, "#0\n\n\n\n" );
    return;
}



/*****************************************************************************
 Name:		save_specials
 Purpose:	Save #SPECIALS section of area file.
 Called by:	save_area(olc_save.c).
 ****************************************************************************/
void save_specials( FILE *fp, AREA_DATA *pArea )
{
    int iHash;
    MOB_INDEX_DATA *pMobIndex;
    
    fprintf( fp, "#SPECIALS\n" );

    for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
    {
        for( pMobIndex = mob_index_hash[iHash]; pMobIndex; pMobIndex = pMobIndex->next )
        {
            if ( pMobIndex && pMobIndex->area == pArea && pMobIndex->spec_fun )
            {
#if defined( VERBOSE )
                fprintf( fp, "M %ld %s Load to: %s\n", pMobIndex->vnum,
                                                      spec_name( pMobIndex->spec_fun ),
                                                      pMobIndex->short_descr );
#else
                fprintf( fp, "M %ld %s\n", pMobIndex->vnum,
                              spec_name( pMobIndex->spec_fun ) );
#endif
            }
        }
    }

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



/*
 * This function is obsolete.  It it not needed but has been left here
 * for historical reasons.  It is used currently for the same reason.
 *
 * I don't think it's obsolete in ROM -- Hugin.
 */
void save_door_resets( FILE *fp, AREA_DATA *pArea )
{
    int iHash;
    ROOM_INDEX_DATA *pRoomIndex;
    EXIT_DATA *pExit;
    int door;

    for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
    {
        for( pRoomIndex = room_index_hash[iHash]; pRoomIndex; pRoomIndex = pRoomIndex->next )
        {
            if ( pRoomIndex->area == pArea )
            {
                for( door = 0; door < MAX_DIR; door++ )
                {
                    if ( ( pExit = pRoomIndex->exit[door] )
                    && pExit->u1.to_room 
                    && ( IS_SET( pExit->rs_flags, EX_CLOSED )
                    || IS_SET( pExit->rs_flags, EX_LOCKED ) ) )
		    {	
			fprintf( fp, "D 0 %ld %ld %d\n", 
				pRoomIndex->vnum,
				pExit->orig_door,
				IS_SET( pExit->rs_flags, EX_LOCKED) ? 2 : 1 );
		    }
		}
	    }
	}
    }
    return;
}




/*****************************************************************************
 Name:		save_resets
 Purpose:	Saves the #RESETS section of an area file.
 Called by:	save_area(olc_save.c)
 ****************************************************************************/
void save_resets( FILE *fp, AREA_DATA *pArea )
{
    RESET_DATA *pReset;
    MOB_INDEX_DATA *pLastMob = NULL;
    OBJ_INDEX_DATA *pLastObj;
    ROOM_INDEX_DATA *pRoom;
    char buf[MAX_STRING_LENGTH];
    int iHash;

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

    save_door_resets( fp, pArea );

    for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
    {
        for( pRoom = room_index_hash[iHash]; pRoom; pRoom = pRoom->next )
        {
            if ( pRoom->area == pArea )
	    {
    for ( pReset = pRoom->reset_first; pReset; pReset = pReset->next )
    {
	switch ( pReset->command )
	{
	default:
	    bug( "Save_resets: bad command %c.", pReset->command );
	    break;

#if defined( VERBOSE )
	case 'M':
            pLastMob = get_mob_index( pReset->arg1 );
	    fprintf( fp, "M 0 %d %d %d %d Load %s\n", 
	        pReset->arg1,
                pReset->arg2,
                pReset->arg3,
		pReset->arg4,
                pLastMob->short_descr );
            break;

	case 'O':
            pLastObj = get_obj_index( pReset->arg1 );
            pRoom = get_room_index( pReset->arg3 );
	    fprintf( fp, "O 0 %d 0 %d %s loaded to %s\n", 
	        pReset->arg1,
                pReset->arg3,
                capitalize(pLastObj->short_descr),
                pRoom->name );
            break;

	case 'P':
            pLastObj = get_obj_index( pReset->arg1 );
	    fprintf( fp, "P 0 %d %d %d %d %s put inside %s\n", 
	        pReset->arg1,
	        pReset->arg2,
                pReset->arg3,
                pReset->arg4,
                capitalize(get_obj_index( pReset->arg1 )->short_descr),
                pLastObj->short_descr );
            break;

	case 'G':
	    fprintf( fp, "G 0 %ld 0 %s is given to %s\n",
	        pReset->arg1,
	        capitalize(get_obj_index( pReset->arg1 )->short_descr),
                pLastMob ? pLastMob->short_descr : "!NO_MOB!" );
            if ( !pLastMob )
            {
                sprintf( buf, "Save_resets: !NO_MOB! in [%s]", pArea->file_name );
                bug( buf, 0 );
            }
            break;

	case 'E':
	    fprintf( fp, "E 0 %ld 0 %ld %s is loaded %s of %s\n",
	        pReset->arg1,
                pReset->arg3,
                capitalize(get_obj_index( pReset->arg1 )->short_descr),
                flag_string( wear_loc_strings, pReset->arg3 ),
                pLastMob ? pLastMob->short_descr : "!NO_MOB!" );
            if ( !pLastMob )
            {
                sprintf( buf, "Save_resets: !NO_MOB! in [%s]", pArea->file_name );
                bug( buf, 0 );
            }
            break;

	case 'D':
            break;

	case 'R':
            pRoom = get_room_index( pReset->arg1 );
	    fprintf( fp, "R 0 %ld %ld Randomize %s\n", 
	        pReset->arg1,
                pReset->arg2,
                pRoom->name );
            break;
            }
#endif
#if !defined( VERBOSE )
	case 'M':
            pLastMob = get_mob_index( pReset->arg1 );
	    fprintf( fp, "M 0 %ld %ld %ld %ld\n", 
	        pReset->arg1,
                pReset->arg2,
                pReset->arg3,
                pReset->arg4 );
            break;

	case 'O':
            pLastObj = get_obj_index( pReset->arg1 );
            pRoom = get_room_index( pReset->arg3 );
	    fprintf( fp, "O 0 %ld 0 %ld\n", 
	        pReset->arg1,
                pReset->arg3 );
            break;

	case 'P':
            pLastObj = get_obj_index( pReset->arg1 );
	    fprintf( fp, "P 0 %ld %ld %ld %ld\n", 
	        pReset->arg1,
	        pReset->arg2,
                pReset->arg3,
                pReset->arg4 );
            break;

	case 'G':
	    fprintf( fp, "G 0 %ld 0\n", pReset->arg1 );
            if ( !pLastMob )
            {
                sprintf( buf,
                    "Save_resets: !NO_MOB! in [%s]", pArea->file_name );
                bug( buf, 0 );
            }
            break;

	case 'E':
	    fprintf( fp, "E 0 %ld 0 %ld\n",
	        pReset->arg1,
                pReset->arg3 );
            if ( !pLastMob )
            {
                sprintf( buf,
                    "Save_resets: !NO_MOB! in [%s]", pArea->file_name );
                bug( buf, 0 );
            }
            break;

	case 'D':
            break;

	case 'R':
            pRoom = get_room_index( pReset->arg1 );
	    fprintf( fp, "R 0 %ld %ld\n", 
	        pReset->arg1,
                pReset->arg2 );
            break;
            }
#endif
        }
	    }	/* End if correct area */
	}	/* End for pRoom */
    }	/* End for iHash */
    fprintf( fp, "S\n\n\n\n" );
    return;
}



/*****************************************************************************
 Name:		save_shops
 Purpose:	Saves the #SHOPS section of an area file.
 Called by:	save_area(olc_save.c)
 ****************************************************************************/
void save_shops( FILE *fp, AREA_DATA *pArea )
{
    SHOP_DATA *pShopIndex;
    MOB_INDEX_DATA *pMobIndex;
    int iTrade;
    int iHash;
    
    fprintf( fp, "#SHOPS\n" );

    for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
    {
        for( pMobIndex = mob_index_hash[iHash]; pMobIndex; pMobIndex = pMobIndex->next )
        {
            if ( pMobIndex && pMobIndex->area == pArea && pMobIndex->pShop )
            {
                pShopIndex = pMobIndex->pShop;

                fprintf( fp, "%d ", pShopIndex->keeper );
                for ( iTrade = 0; iTrade < MAX_TRADE; iTrade++ )
                {
                    if ( pShopIndex->buy_type[iTrade] != 0 )
                    {
                       fprintf( fp, "%d ", pShopIndex->buy_type[iTrade] );
                    }
                    else
                       fprintf( fp, "0 ");
                }
                fprintf( fp, "%d %d ", pShopIndex->profit_buy, pShopIndex->profit_sell );
                fprintf( fp, "%d %d\n", pShopIndex->open_hour, pShopIndex->close_hour );
            }
        }
    }

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

void save_helps (FILE * fp, HELP_AREA * ha)
{
    HELP_DATA *help = ha->first;

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

    for (; help; help = help->next_area)
    {
        fprintf (fp, "%d %s~\n", help->level, help->keyword);
        fprintf (fp, "%s~\n\n", fix_string (help->text));
    }

    fprintf (fp, "-1 $~\n\n");

    ha->changed = FALSE;

    return;
}

void save_other_helps (CHAR_DATA * ch)
{
    extern HELP_AREA *had_list;
    HELP_AREA *ha;
    FILE *fp;

    for (ha = had_list; ha; ha = ha->next)
        if (ha->changed == TRUE)
        {
            fp = fopen (ha->filename, "w");

            if (!fp)
            {
                perror (ha->filename);
                return;
            }

            save_helps (fp, ha);

            if (ch)
                printf_to_char (ch, "%s\n\r", ha->filename);

            fprintf (fp, "#$\n");
            fclose (fp);
        }

    return;
}

void write_iprog( FILE *fp, OBJ_INDEX_DATA *pObj )
{
		if(IS_SET(pObj->progtypes, IPROG_WEAR))
			fprintf(fp,"I %ld wear_prog %s\n", pObj->vnum, pObj->iprogs->wear_name);
		if(IS_SET(pObj->progtypes, IPROG_REMOVE))
			fprintf(fp,"I %ld remove_prog %s\n", pObj->vnum, pObj->iprogs->remove_name);
		if(IS_SET(pObj->progtypes, IPROG_DROP))
			fprintf(fp,"I %ld drop_prog %s\n", pObj->vnum, pObj->iprogs->drop_name);
		if(IS_SET(pObj->progtypes, IPROG_SAC))
			fprintf(fp,"I %ld sac_prog %s\n", pObj->vnum, pObj->iprogs->sac_name);
		if(IS_SET(pObj->progtypes, IPROG_GIVE))
			fprintf(fp,"I %ld give_prog %s\n", pObj->vnum, pObj->iprogs->give_name);
		if(IS_SET(pObj->progtypes, IPROG_GREET))
			fprintf(fp,"I %ld greet_prog %s\n", pObj->vnum, pObj->iprogs->greet_name);
		if(IS_SET(pObj->progtypes, IPROG_FIGHT))
			fprintf(fp,"I %ld fight_prog %s\n", pObj->vnum, pObj->iprogs->fight_name);
		if(IS_SET(pObj->progtypes, IPROG_DEATH))
			fprintf(fp,"I %ld death_prog %s\n", pObj->vnum, pObj->iprogs->death_name);
		if(IS_SET(pObj->progtypes, IPROG_SPEECH))
			fprintf(fp,"I %ld speech_prog %s\n", pObj->vnum, pObj->iprogs->speech_name);
		if(IS_SET(pObj->progtypes, IPROG_ENTRY))
			fprintf(fp,"I %ld entry_prog %s\n", pObj->vnum, pObj->iprogs->entry_name);
		if(IS_SET(pObj->progtypes, IPROG_GET))
			fprintf(fp,"I %ld get_prog %s\n", pObj->vnum, pObj->iprogs->get_name);
		if(IS_SET(pObj->progtypes, IPROG_PULSE))
			fprintf(fp,"I %ld pulse_prog %s\n", pObj->vnum, pObj->iprogs->pulse_name);
		if(IS_SET(pObj->progtypes, IPROG_INVOKE))
			fprintf(fp,"I %ld invoke_prog %s\n", pObj->vnum, pObj->iprogs->invoke_name);
}

void write_mprog( FILE *fp, MOB_INDEX_DATA *pMob )
{
			if(IS_SET(pMob->progtypes, MPROG_BRIBE))
				fprintf(fp,"M %ld bribe_prog %s\n", pMob->vnum, pMob->mprogs->bribe_name);
			if(IS_SET(pMob->progtypes, MPROG_ENTRY))
				fprintf(fp,"M %ld entry_prog %s\n", pMob->vnum, pMob->mprogs->entry_name);
			if(IS_SET(pMob->progtypes, MPROG_GREET))
				fprintf(fp,"M %ld greet_prog %s\n", pMob->vnum, pMob->mprogs->greet_name);
			if(IS_SET(pMob->progtypes, MPROG_GIVE))
				fprintf(fp,"M %ld give_prog %s\n", pMob->vnum, pMob->mprogs->give_name);
			if(IS_SET(pMob->progtypes, MPROG_FIGHT))
				fprintf(fp,"M %ld fight_prog %s\n", pMob->vnum, pMob->mprogs->fight_name);
			if(IS_SET(pMob->progtypes, MPROG_DEATH))
				fprintf(fp,"M %ld death_prog %s\n", pMob->vnum, pMob->mprogs->death_name);
			if(IS_SET(pMob->progtypes, MPROG_PULSE))
				fprintf(fp,"M %ld pulse_prog %s\n", pMob->vnum, pMob->mprogs->pulse_name);
			if(IS_SET(pMob->progtypes, MPROG_SPEECH))
				fprintf(fp,"M %ld speech_prog %s\n", pMob->vnum, pMob->mprogs->speech_name);
			if(IS_SET(pMob->progtypes, MPROG_ATTACK))
				fprintf(fp,"M %ld attack_prog %s\n", pMob->vnum, pMob->mprogs->attack_name);
			if(IS_SET(pMob->progtypes, MPROG_MOVE))
				fprintf(fp,"M %ld move_prog %s\n", pMob->vnum, pMob->mprogs->move_name);
			if(IS_SET(pMob->progtypes, MPROG_REQUEST))
				fprintf(fp,"M %ld request_prog %s\n", pMob->vnum, pMob->mprogs->request_name);
} 

void write_rprog( FILE *fp, ROOM_INDEX_DATA *pRoom )
{
                if(IS_SET(pRoom->progtypes, RPROG_SPEECH))
                        fprintf(fp,"R %ld speech_prog %s\n", pRoom->vnum, pRoom->rprogs->speech_name);
                if(IS_SET(pRoom->progtypes, RPROG_ENTRY))
                        fprintf(fp,"R %ld entry_prog %s\n", pRoom->vnum, pRoom->rprogs->entry_name);

}

void save_improgs( FILE *fp, AREA_DATA *pArea )
{
    int i;
    OBJ_INDEX_DATA *pObj;
    MOB_INDEX_DATA *pMob;
    ROOM_INDEX_DATA *pRoom;

    fprintf(fp, "#IMPROGS\n");
    for ( i = pArea->min_vnum ; i <= pArea->max_vnum ; i++)
    {
	if ( (pObj = get_obj_index( i )))
	    write_iprog(fp, pObj);
    }
    for ( i = pArea->min_vnum ; i <= pArea->max_vnum ; i++)
    {
	if ( (pMob = get_mob_index( i )))
	    write_mprog(fp, pMob);
    }
    for ( i = pArea->min_vnum ; i <= pArea->max_vnum ; i++)
    {
        if ( (pRoom = get_room_index( i )))
            write_rprog(fp, pRoom);
    }
    fprintf(fp, "E\n\n\n\n");
    return;
}

/*****************************************************************************
 Name:		save_area
 Purpose:	Save an area, note that this format is new.
 Called by:	do_asave(olc_save.c).
 ****************************************************************************/
void save_area( AREA_DATA *pArea )
{
    FILE *fp;

    fclose( fpReserve );
    if ( !( fp = fopen( pArea->file_name, "w" ) ) )
    {
	bug( "Open_area: fopen", 0 );
	perror( pArea->file_name );
    }

    fprintf( fp, "#AREADATA\n" );
    fprintf( fp, "Name %s~\n",        pArea->name );
    fprintf( fp, "Builders %s~\n",        fix_string( pArea->builders ) );
    fprintf( fp, "VNUMs %ld %ld\n",      pArea->min_vnum, pArea->max_vnum );
    fprintf( fp, "Credits %s~\n",	 pArea->credits );
    fprintf( fp, "Security %d\n",         pArea->security );
    fprintf( fp, "Xplore %d\n", 	pArea->explore);
    fprintf( fp, "End\n\n\n\n" );

    save_mobiles_new( fp, pArea );
    save_objects_new( fp, pArea );
    save_rooms_new( fp, pArea );
    save_specials( fp, pArea );
    save_resets( fp, pArea );
    save_shops( fp, pArea );
    save_improgs( fp, pArea );
    

    if (pArea->helps && pArea->helps->first)
        save_helps (fp, pArea->helps);

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

    fclose( fp );
    fpReserve = fopen( NULL_FILE, "r" );
    return;
}


/*****************************************************************************
 Name:		do_asave
 Purpose:	Entry point for saving area data.
 Called by:	interpreter(interp.c)
 ****************************************************************************/
void do_asave( CHAR_DATA *ch, char *argument )
{
    char arg1 [MAX_INPUT_LENGTH];
    AREA_DATA *pArea;
    FILE *fp;
    int value;

    fp = NULL;

    if ( !ch )       /* Do an autosave */
    {
	save_area_list();
	for( pArea = area_first; pArea; pArea = pArea->next )
	{
	    save_area( pArea );
	    REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
	}
	return;
    }
    smash_tilde( argument );
    strcpy( arg1, argument );
    if ( arg1[0] == '\0' )
    {
    send_to_char( "Syntax:\n\r", ch );
    send_to_char( "  asave <vnum>   - saves a particular area\n\r",	ch );
    send_to_char( "  asave list     - saves the area.lst file\n\r",	ch );
    send_to_char( "  asave area     - saves the area being edited\n\r",	ch );
    send_to_char( "  asave changed  - saves all changed zones\n\r",	ch );
    send_to_char( "  asave world    - saves the world! (db dump)\n\r",	ch );
    send_to_char( "\n\r", ch );
        return;
    }

    /* Snarf the value (which need not be numeric). */
    value = atoi( arg1 );
    if ( !( pArea = get_area_data( value ) ) && is_number( arg1 ) )
    {
	send_to_char( "That area does not exist.\n\r", ch );
	return;
    }
    /* Save area of given vnum. */
    /* ------------------------ */

    if ( is_number( arg1 ) )
    {
	if ( !IS_BUILDER( ch, pArea ) )
	{
	    send_to_char( "You are not a builder for this area.\n\r", ch );
	    return;
	}
	save_area_list();
	save_area( pArea );
	return;
    }
    /* Save the world, only authorized areas. */
    /* -------------------------------------- */

    if ( !str_cmp( "world", arg1 ) )
    {
	save_area_list();
	for( pArea = area_first; pArea; pArea = pArea->next )
	{
	    /* Builder must be assigned this area. */
	    if ( !IS_BUILDER( ch, pArea ) )
		continue;	  

	    save_area( pArea );
	    REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
	}
	send_to_char( "You saved the world.\n\r", ch );

        save_other_helps (NULL);

	return;
    }

    /* Save changed areas, only authorized areas. */
    /* ------------------------------------------ */

    if ( !str_cmp( "changed", arg1 ) )
    {
	char buf[MAX_INPUT_LENGTH];

	save_area_list();

	send_to_char( "Saved zones:\n\r", ch );
	sprintf( buf, "None.\n\r" );

	for( pArea = area_first; pArea; pArea = pArea->next )
	{
	    /* Builder must be assigned this area. */
	    if ( !IS_BUILDER( ch, pArea ) )
		continue;

	    /* Save changed areas. */
	    if ( IS_SET(pArea->area_flags, AREA_CHANGED) )
	    {
		save_area( pArea );
		sprintf( buf, "%24s - '%s'\n\r", pArea->name, pArea->file_name );
		send_to_char( buf, ch );
		REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
	    }
        }

        save_other_helps (ch);

	if ( !str_cmp( buf, "None.\n\r" ) )
	    send_to_char( buf, ch );
        return;
    }

    /* Save the area.lst file. */
    /* ----------------------- */
    if ( !str_cmp( arg1, "list" ) )
    {
	save_area_list();
	return;
    }

    /* Save area being edited, if authorized. */
    /* -------------------------------------- */
    if ( !str_cmp( arg1, "area" ) )
    {
	/* Is character currently editing. */
	if ( ch->desc->editor == 0 )
	{
	    send_to_char( "You are not editing an area, "
		"therefore an area vnum is required.\n\r", ch );
	    return;
	}
	
	/* Find the area to save. */
	switch (ch->desc->editor)
	{
	    case ED_AREA:
		pArea = (AREA_DATA *)ch->desc->pEdit;
		break;
	    case ED_ROOM:
		pArea = ch->in_room->area;
		break;
	    case ED_OBJECT:
		pArea = ( (OBJ_INDEX_DATA *)ch->desc->pEdit )->area;
		break;
	    case ED_MOBILE:
		pArea = ( (MOB_INDEX_DATA *)ch->desc->pEdit )->area;
		break;
	    default:
		pArea = ch->in_room->area;
		break;
	}

	if ( !IS_BUILDER( ch, pArea ) )
	{
	    send_to_char( "You are not a builder for this area.\n\r", ch );
	    return;
	}

	save_area_list();
	save_area( pArea );
	REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
	send_to_char( "Area saved.\n\r", ch );
	return;
    }
  
    /* Show correct syntax. */
    /* -------------------- */
    if (ch)
    do_asave( ch, "" );
 
    return;
}

void fwrite_area( AREA_DATA *pArea )
{
	FILE *fp;

	fclose( fpReserve );
    	if ( !( fp = fopen( pArea->file_name, "w" ) ) )
    	{
        	bug( "Open_area: fopen", 0 );
        	perror( pArea->file_name );
    	}

    	fprintf( fp, "#NEWAREA\n" );
    	fprintf( fp, "NAME   %s~\n",		pArea->name );
    	fprintf( fp, "BUILDR %s~\n",        	fix_string( pArea->builders ) );
    	fprintf( fp, "VNUMS  %ld %ld\n",	pArea->min_vnum, pArea->max_vnum );
    	fprintf( fp, "CREDIT %s~\n",        	pArea->credits );
    	fprintf( fp, "SEC    %d\n",         	pArea->security );
    	fprintf( fp, "XPLORE %d\n",         	pArea->explore);
    	fprintf( fp, "End\n\n\n\n" );

    	save_mobiles( fp, pArea );
    	save_objects( fp, pArea );
    	save_rooms( fp, pArea );
    	save_specials( fp, pArea );
    	save_resets( fp, pArea );
    	save_shops( fp, pArea );
    	save_improgs( fp, pArea );

    	if (pArea->helps && pArea->helps->first)
        	save_helps (fp, pArea->helps);

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

    	fclose( fp );
    	fpReserve = fopen( NULL_FILE, "r" );
    	return;
}

void fwrite_mob( FILE *fp, MOB_INDEX_DATA *pMobIndex )
{
        sh_int race = pMobIndex->race;
        char buf[MSL];

        fprintf( fp, "#%ld\n",                  pMobIndex->vnum );
        fprintf( fp, "NAME  %s~\n",             pMobIndex->player_name );
        fprintf( fp, "SHORT %s~\n",             pMobIndex->short_descr );
        fprintf( fp, "LONG  %s~\n",             fix_string( pMobIndex->long_descr ) );
        fprintf( fp, "DESCR\n%s~\n",            fix_string( pMobIndex->description) );
        fprintf( fp, "RACE  %s~\n",             race_table[race].name );
        fprintf( fp, "ACT   %s\n",              fwrite_flag( pMobIndex->act, buf ) );
	fprintf( fp, "AFF   %s\n",              fwrite_flag( pMobIndex->affected_by, buf ) );
        fprintf( fp, "OFF   %s\n",              fwrite_flag( pMobIndex->off_flags, buf ) );
        fprintf( fp, "IMM   %s\n",              fwrite_flag( pMobIndex->imm_flags, buf ) );
        fprintf( fp, "RES   %s\n",              fwrite_flag( pMobIndex->res_flags, buf ) );
        fprintf( fp, "VULN  %s\n",              fwrite_flag( pMobIndex->vuln_flags, buf ) );
	fprintf( fp, "WSPEC %s\n",		fwrite_flag( pMobIndex->extended_flags, buf ) );
        fprintf( fp, "ALIGN %d\n",              pMobIndex->alignment);
        fprintf( fp, "GROUP %d\n",              pMobIndex->group);
        fprintf( fp, "LEVEL %d\n",              pMobIndex->level );
        fprintf( fp, "HROLL %d\n",              pMobIndex->hitroll );
        fprintf( fp, "ENHA  %.2f%%\n",          pMobIndex->enhancedDamMod );
		fprintf( fp, "MATER %s~\n",				pMobIndex->material ? pMobIndex->material : "none" );
        fprintf( fp, "HDICE %dd%d+%d\n",        pMobIndex->hit[DICE_NUMBER], pMobIndex->hit[DICE_TYPE], pMobIndex->hit[DICE_BONUS] );
        fprintf( fp, "MDICE %dd%d+%d\n",        pMobIndex->mana[DICE_NUMBER], pMobIndex->mana[DICE_TYPE], pMobIndex->mana[DICE_BONUS] );
        fprintf( fp, "DDICE %dd%d+%d\n",        pMobIndex->damage[DICE_NUMBER], pMobIndex->damage[DICE_TYPE], pMobIndex->damage[DICE_BONUS] );
		fprintf( fp, "REGEN %d\n",				pMobIndex->regen_rate );
        fprintf( fp, "DTYPE %s\n",              attack_table[pMobIndex->dam_type].name );
        fprintf( fp, "AC    %d %d %d %d\n",     pMobIndex->ac[AC_PIERCE] / 10, pMobIndex->ac[AC_BASH]   / 10,
                                                pMobIndex->ac[AC_SLASH]  / 10, pMobIndex->ac[AC_EXOTIC] / 10 );
        fprintf( fp, "POS   %s %s\n",           position_table[pMobIndex->start_pos].short_name, position_table[pMobIndex->default_pos].short_name );
        fprintf( fp, "SEX   %s\n",              sex_table[pMobIndex->sex].name );
        fprintf( fp, "GOLD  %ld\n",             pMobIndex->wealth );
        fprintf( fp, "FORM  %s\n",              fwrite_flag( pMobIndex->form,  buf ) );
        fprintf( fp, "PARTS %s\n",              fwrite_flag( pMobIndex->parts, buf ) );
        fprintf( fp, "SIZE  %s\n",              size_table[pMobIndex->size].name );
        fprintf( fp, "DMOD  %d\n",              pMobIndex->dam_mod);
	fprintf( fp, "AMOD  %d\n",		pMobIndex->numAttacks);
	fprintf( fp, "QUEST %ld\n",		pMobIndex->quest_credit_reward);
        if ( pMobIndex->cabal )
                fprintf( fp, "CABAL %s\n",     cabal_table[pMobIndex->cabal].name);
        fprintf( fp, "End\n\n" );
        return;
}

void fwrite_object( FILE *fp, OBJ_INDEX_DATA *pObjIndex )
{
	AFFECT_DATA *pAf;
	EXTRA_DESCR_DATA *pEd;
	char buf[MSL];

	fprintf( fp, "#%ld\n",		pObjIndex->vnum );
	fprintf( fp, "NAME   %s~\n",	pObjIndex->name );
	fprintf( fp, "SHORT  %s~\n",	pObjIndex->short_descr );
	fprintf( fp, "DESCR \n%s~\n",	fix_string( pObjIndex->description ) );
	fprintf( fp, "MAT    %s~\n",	pObjIndex->material->name );
	fprintf( fp, "TYPE   %s ",	item_name(pObjIndex->item_type));

	switch ( pObjIndex->item_type )
	{
	  default:
		fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[0], buf ) );
		fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[1], buf ) );
		fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[2], buf ) );
		fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[3], buf ) );
		fprintf( fp, "%s\n", fwrite_flag( pObjIndex->value[4], buf ) );
		break;

	  case ITEM_DRINK_CON:
	  case ITEM_FOUNTAIN:
		fprintf( fp, "%ld %ld '%s' %ld %ld\n",
		pObjIndex->value[0],
		pObjIndex->value[1],
		liq_table[pObjIndex->value[2]].liq_name,
		pObjIndex->value[3],
		pObjIndex->value[4]);
		break;

	  case ITEM_CONTAINER:
		fprintf( fp, "%ld %s %ld %ld %ld\n",
		pObjIndex->value[0],
		fwrite_flag( pObjIndex->value[1], buf ),
		pObjIndex->value[2],
		pObjIndex->value[3],
		pObjIndex->value[4]);
		break;

	  case ITEM_WEAPON:
		fprintf( fp, "%s %ld %ld %s %s\n",
		weapon_name(pObjIndex->value[0]),
		pObjIndex->value[1],
		pObjIndex->value[2],
		attack_table[pObjIndex->value[3]].name,
		fwrite_flag( pObjIndex->value[4], buf ) );
		break;

	  case ITEM_PILL:
	  case ITEM_POTION:
	  case ITEM_SCROLL:
		fprintf( fp, "%ld '%s' '%s' '%s' '%s'\n",
		pObjIndex->value[0] > 0 ? /* no negative numbers */ pObjIndex->value[0] : 0,
		pObjIndex->value[1] != -1 ? skill_table[pObjIndex->value[1]].name : "",
		pObjIndex->value[2] != -1 ? skill_table[pObjIndex->value[2]].name : "",
		pObjIndex->value[3] != -1 ? skill_table[pObjIndex->value[3]].name : "",
		pObjIndex->value[4] != -1 ? skill_table[pObjIndex->value[4]].name : "");
		break;

	  case ITEM_STAFF:
	  case ITEM_WAND:
		fprintf( fp, "%ld %ld %ld '%s' %ld\n",
		pObjIndex->value[0],
		pObjIndex->value[1],
		pObjIndex->value[2],
		pObjIndex->value[3] != -1 ? skill_table[pObjIndex->value[3]].name : "",
		pObjIndex->value[4] );
		break;
	}

	fprintf( fp, "EXTRA  ");
	save_bitmask(&pObjIndex->extra_flags, fp);
	fprintf( fp, "WEAR   %s\n",	fwrite_flag( pObjIndex->wear_flags,  buf ) );
	fprintf( fp, "LEVEL  %d\n", 	pObjIndex->level );
	fprintf( fp, "WEIGHT %d\n", 	pObjIndex->weight );
	fprintf( fp, "COST   %d\n", 	pObjIndex->cost );

	fprintf( fp, "COND   %d\n", pObjIndex->condition );

	for( pAf = pObjIndex->affected; pAf; pAf = pAf->next )
	{
		fprintf( fp, "Affect " );
		if (pAf->where == TO_OBJECT || pAf->bitvector == 0)
			fprintf( fp, "O %d %d 0\n",  pAf->location, pAf->modifier );
		else
		{
			switch(pAf->where)
			{
				case TO_AFFECTS:	fprintf( fp, "A " );	break;
			  	case TO_IMMUNE:		fprintf( fp, "I " );	break;
			  	case TO_RESIST:		fprintf( fp, "R " );	break;
			  	case TO_VULN:		fprintf( fp, "V " );	break;
			  	default: 		bug( "olc_save: Invalid Affect->where", 0);	break;
			}
			fprintf( fp, "%d %d %s\n", pAf->location, pAf->modifier, fwrite_flag( pAf->bitvector, buf ) );
		}
	}

	for( pEd = pObjIndex->extra_descr; pEd; pEd = pEd->next )
	{
		fprintf( fp, "EDESC %s~\n%s~\n", pEd->keyword,fix_string( pEd->description ) );
	}

    	if ( pObjIndex->cabal )
        	fprintf( fp, "CABAL  %d\n",	pObjIndex->cabal );

    	if ( pObjIndex->limtotal )
        	fprintf( fp, "LIMIT  %d\n",	pObjIndex->limtotal );

    	if ( pObjIndex->restrict_flags )
        	fprintf( fp, "RESTR  %s\n",	fwrite_flag( pObjIndex->restrict_flags, buf ) );

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

void fwrite_room( FILE *fp, ROOM_INDEX_DATA *pRoomIndex )
{
	EXTRA_DESCR_DATA *pEd;
	EXIT_DATA *pExit;
	int door;
	char buf[MAX_STRING_LENGTH];

	fprintf( fp, "#%ld\n",		pRoomIndex->vnum );
	fprintf( fp, "NAME   %s~\n",	pRoomIndex->name );
	fprintf( fp, "DESCR\n%s~\n",	fix_string( pRoomIndex->description ) );
	fprintf( fp, "FLAGS  %d\n",	pRoomIndex->room_flags );
	fprintf( fp, "Sect   %d\n",	pRoomIndex->sector_type );

	for ( pEd = pRoomIndex->extra_descr; pEd; pEd = pEd->next )
	  	fprintf( fp, "EDESC  %s~\n%s~\n", pEd->keyword, fix_string( pEd->description ) );

	for ( door = 0; door <MAX_DIR; door++ )
	{
		if ((pExit = pRoomIndex->exit[door]) && (pExit->u1.to_room ))
		{
			// OLC is making some doors not doors anymore, but leaving them closed. Quick hack until the problem is identified. - Tracerah (4/17/09)
			if (IS_SET(pExit->rs_flags, EX_CLOSED) && !IS_SET(pExit->rs_flags, EX_ISDOOR)) {
				SET_BIT(pExit->rs_flags, EX_ISDOOR);
			}

			fprintf( fp, "DOOR %ld\n",	pExit->orig_door );
                        fprintf( fp, "%s~\n",		fix_string( pExit->description));
                        fprintf( fp, "%s~\n",           pExit->keyword );
                        fprintf( fp, "%s %ld %ld\n",    fwrite_flag(pExit->rs_flags, buf), pExit->key, pExit->u1.to_room->vnum );
		}
	}


	if (pRoomIndex->mana_rate != 100 || pRoomIndex->heal_rate != 100)
	  	fprintf ( fp, "MHRATE %d %d\n",	pRoomIndex->mana_rate, pRoomIndex->heal_rate);

	if (pRoomIndex->cabal)
		fprintf( fp, "CABAL  %s~\n",	cabal_table[pRoomIndex->cabal].name);

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

void save_rooms_new( FILE *fp, AREA_DATA *pArea )
{
	int i;
	ROOM_INDEX_DATA *pRoom;

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

	for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
	{
	  if ( (pRoom = get_room_index( i )) )
		fwrite_room( fp, pRoom );
	}
	fprintf( fp, "#0\n\n\n\n" );
	return;
}

void save_objects_new( FILE *fp, AREA_DATA *pArea )
{
	int i;
	OBJ_INDEX_DATA *pObj;

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

	for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
	{
	  if ( (pObj = get_obj_index( i )) )
		fwrite_object( fp, pObj );
	}
	fprintf( fp, "#0\n\n\n\n" );
	return;
}

void save_mobiles_new( FILE *fp, AREA_DATA *pArea )
{
	int i;
	MOB_INDEX_DATA *pMob;

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

	for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
	{
	  if ( (pMob = get_mob_index( i )) )
		fwrite_mob( fp, pMob );
	}
	fprintf( fp, "#0\n\n\n\n" );
	return;
}