bast/
bast/area/
bast/backup/
bast/clans/
bast/doc/MSP/
bast/doc/OLC11/
bast/doc/OLC11/doc/
bast/doc/OLC11/options/
bast/log/
bast/mobprogs/
bast/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.                              *
 *                                                                         *
 *  Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, David   *
 *  Love, Guilherme 'Willie' Arnold, and Mitchell Tse.                     *
 *                                                                         *
 *  EnvyMud 2.0 improvements copyright (C) 1995 by Michael Quan and        *
 *  Mitchell Tse.                                                          *
 *                                                                         *
 *  EnvyMud 2.2 improvements copyright (C) 1996, 1997 by Michael Quan.     *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  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.                *
 ***************************************************************************/

#if defined( macintosh )
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "olc.h"



/*
 * Removes the tildes and carriage returns from a string.
 * Used for player-entered strings that go into disk files.
 */
char *fix_string( const char *str )
{
    static char strfix [4*MAX_STRING_LENGTH];
    int         i;
    int         o;

    if ( !str )
	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;
}


void save_area_list( )
{
    FILE      *fp;
    AREA_DATA *pArea;
    char       strsave [ MAX_INPUT_LENGTH ];

    fclose( fpReserve );

    sprintf( strsave, "%s%s", AREA_DIR, AREA_LIST );

    if ( !( fp = fopen( strsave, "w" ) ) )
    {
	bug( "Save_area_list: fopen", 0 );
	perror( AREA_LIST );
    }
    else
    {
	/* add any help files to be loaded at startup to this section */
	fprintf( fp, "help.are\n"	);
	fprintf( fp, "olc.hlp\n"	);

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

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

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


void save_mobiles( FILE *fp, AREA_DATA *pArea )
{
    MOB_INDEX_DATA *pMobIndex;
    int             vnum;

    fprintf( fp, "#MOBILES\n" );
    for ( vnum = pArea->low_m_vnum; vnum <= pArea->hi_m_vnum; vnum++ )
    {
	if ( !( pMobIndex = get_mob_index( vnum ) )
	    ||  pMobIndex->area != pArea )
	    continue;

	fprintf( fp, "#%d\n",	pMobIndex->vnum			     );
	fprintf( fp, "%s~\n",	pMobIndex->player_name		     );
	fprintf( fp, "%s~\n",	pMobIndex->short_descr		     );
	fprintf( fp, "%s~\n",	fix_string( pMobIndex->long_descr  ) );
	fprintf( fp, "%s~\n",	fix_string( pMobIndex->description ) );
	fprintf( fp, "%d ",	pMobIndex->act			     );
        // OLC does not yet support multiple bitvectors - Veygoth
	fprintf( fp, "%d ",	pMobIndex->affected_by[0]            );
	fprintf( fp, "%d S\n",	pMobIndex->alignment		     );
	fprintf( fp, "%d ",	pMobIndex->level		     );
	fprintf( fp, "%d ",	0 );
	fprintf( fp, "%d ",	0 );
	fprintf( fp, "%dd%d+%d ",
				0,
				0,
				0		     );
	fprintf( fp, "%dd%d+%d\n",
				0,
				0,
				0		     );
	fprintf( fp, "%d ",	0		     );
	fprintf( fp, "0\n0 "					     );
	fprintf( fp, "%s~ ",	race_table[pMobIndex->race].name     );
	fprintf( fp, "%d\n",	pMobIndex->sex			     );

	/*
	 * This is responsible for writing MOBprograms in_file.
	 * By Farix of Oz.
	 */
	if ( pMobIndex->mobprogs )
	{
	    MPROG_DATA *mPtr;

	    for ( mPtr = pMobIndex->mobprogs; mPtr; mPtr = mPtr->next )
	    {
		fprintf( fp, ">%s ",	mprog_type_to_name( mPtr->type ) );
		fprintf( fp, "%s~\n",	mPtr->arglist			 );
		fprintf( fp, "%s~\n",	fix_string( mPtr->comlist )	 );
	    }
	    fprintf( fp, "|\n" );

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

    return;
}


void new_save_objects( FILE *fp, AREA_DATA *pArea )
{
    EXTRA_DESCR_DATA *pEd;
    OBJ_INDEX_DATA   *pObjIndex;
    AFFECT_DATA      *pAf;
    int               vnum;

    fprintf( fp, "#NEWOBJECTS\n" );
    for ( vnum = pArea->low_o_vnum; vnum <= pArea->hi_o_vnum; vnum++ )
    {
	if ( !( pObjIndex = get_obj_index( vnum ) )
	    ||  pObjIndex->area != pArea )
	    continue;

	fprintf( fp, "#%d\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, "~\n"					       );
	fprintf( fp, "%d ",	  pObjIndex->item_type		       );
	fprintf( fp, "%d ",	  pObjIndex->extra_flags[0]	       );
	fprintf( fp, "%d\n",	  pObjIndex->wear_flags		       );

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

	case TYPE_PILL:
	case TYPE_POTION:
	case TYPE_SCROLL: fprintf( fp, "%d~ %s~ %s~ %s~ %s~\n",
				  pObjIndex->value[0],
				  pObjIndex->value[1] != -1 ?
				  spells_table[pObjIndex->value[1]].name : " ",
				  pObjIndex->value[2] != -1 ?
				  spells_table[pObjIndex->value[2]].name : " ",
				  pObjIndex->value[3] != -1 ?
				  spells_table[pObjIndex->value[3]].name : " ",
				  pObjIndex->value[4] != -1 ?
				  spells_table[pObjIndex->value[4]].name : " " );
			  break;

	case TYPE_WAND:
	case TYPE_STAFF:  fprintf( fp, "%d~ %d~ %d~ %s~ %d~\n",
				  pObjIndex->value[0],
				  pObjIndex->value[1],
				  pObjIndex->value[2],
				  pObjIndex->value[3] != -1 ?
				  spells_table[pObjIndex->value[3]].name : " ",
				  pObjIndex->value[4] );
			  break;
	}
	fprintf( fp, "%d ",	  pObjIndex->weight );
	fprintf( fp, "%d 0\n",	  pObjIndex->cost   );

        // Olc does not yet support multiple bitvectors -- Veygoth
	for ( pAf = pObjIndex->affected; pAf; pAf = pAf->next )
	{
	    fprintf( fp, "A\n%d %d %d\n",
				  pAf->location,
				  pAf->modifier,
				  pAf->bitvector[0] );
	}

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

    return;
}


void save_rooms( FILE *fp, AREA_DATA *pArea )
{
    EXTRA_DESCR_DATA *pEd;
    ROOM_INDEX_DATA  *pRoomIndex;
    EXIT_DATA        *pExit;
    int               vnum;
    int               door;

    fprintf( fp, "#BASTROOMS\n" );
    for ( vnum = pArea->low_r_vnum; vnum <= pArea->hi_r_vnum; vnum++ )
    {
	if ( !( pRoomIndex = get_room_index( vnum ) )
	    ||  pRoomIndex->area != pArea )
	    continue;

	fprintf( fp, "#%d\n",	pRoomIndex->vnum		      );
	fprintf( fp, "%s~\n",	pRoomIndex->name		      );
	fprintf( fp, "%s~\n",	fix_string( pRoomIndex->description ) );
	fprintf( fp, "0 "					      );
	fprintf( fp, "%d ",	pRoomIndex->orig_room_flags	      );
	fprintf( fp, "%d\n",	pRoomIndex->sector_type		      );

        if( pRoomIndex->fall_chance )
        {
            fprintf( fp, "F\n%d\n", pRoomIndex->fall_chance );
        }

	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] ) )
		continue;

	    fprintf( fp, "D%d\n",  door				      );
	    fprintf( fp, "%s~\n",  fix_string( pExit->description )   );
	    fprintf( fp, "%s~\n",  pExit->keyword		      );
	    fprintf( fp, "%d %d %d\n",
				   pExit->rs_flags,
				   pExit->key,
				   pExit->to_room
				   ? pExit->to_room->vnum : 0	      );
	}
	fprintf( fp, "S\n" );

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

    return;
}


void save_specials( FILE *fp, AREA_DATA *pArea )
{
    MOB_INDEX_DATA *pMobIndex;
    OBJ_INDEX_DATA *pObjIndex;
    int             vnum;

    fprintf( fp, "#SPECIALS\n" );
    for ( vnum = pArea->low_m_vnum; vnum <= pArea->hi_m_vnum; vnum++ )
    {
	if ( !( pMobIndex = get_mob_index( vnum ) )
	    ||  pMobIndex->area != pArea
	    || !pMobIndex->spec_fun )
	    continue;

	fprintf( fp, "M %d %s\n",
		pMobIndex->vnum,
		spec_mob_string( pMobIndex->spec_fun ) );
    }

    for ( vnum = pArea->low_o_vnum; vnum <= pArea->hi_o_vnum; vnum++ )
    {
	if ( !( pObjIndex = get_obj_index( vnum ) )
	    ||  pObjIndex->area != pArea
	    || !pObjIndex->spec_fun )
	    continue;

	fprintf( fp, "O %d %s\n",
		pObjIndex->vnum,
		spec_obj_string( pObjIndex->spec_fun ) );
    }
    fprintf( fp, "S\n\n\n" );

    return;
}


/* New formating thanks to Rac */
void vsave_specials( FILE *fp, AREA_DATA *pArea )
{
    MOB_INDEX_DATA *pMobIndex;
    OBJ_INDEX_DATA *pObjIndex;
    int             vnum;

    fprintf( fp, "#SPECIALS\n" );
    for ( vnum = pArea->low_m_vnum; vnum <= pArea->hi_m_vnum; vnum++ )
    {
	if ( !( pMobIndex = get_mob_index( vnum ) )
	    ||  pMobIndex->area != pArea
	    || !pMobIndex->spec_fun )
	    continue;

	fprintf( fp, "M %5d %-30s \t* %s\n",
		pMobIndex->vnum,
		spec_mob_string( pMobIndex->spec_fun ),
		pMobIndex->short_descr );
    }

    for ( vnum = pArea->low_o_vnum; vnum <= pArea->hi_o_vnum; vnum++ )
    {
	if ( !( pObjIndex = get_obj_index( vnum ) )
	    ||  pObjIndex->area != pArea
	    || !pObjIndex->spec_fun )
	    continue;

	fprintf( fp, "O %5d %-30s \t* %s\n",
		pObjIndex->vnum,
		spec_obj_string( pObjIndex->spec_fun ),
		pObjIndex->short_descr );
    }
    fprintf( fp, "S\n\n\n" );

    return;
}


/* Written by: Maniac */
void save_games( FILE *fp, AREA_DATA *pArea )
{
    MOB_INDEX_DATA *pMobIndex;
    GAME_DATA      *pGameIndex;
    int             vnum;

    fprintf( fp, "#GAMES\n" );
    for ( vnum = pArea->low_m_vnum; vnum <= pArea->hi_m_vnum; vnum++ )
    {
	if ( !( pMobIndex = get_mob_index( vnum ) )
	    ||  pMobIndex->area != pArea
	    || !pMobIndex->pGame )
	    continue;

	pGameIndex = pMobIndex->pGame;

	fprintf( fp, "M %d %s %d %d %d\n",
		pGameIndex->croupier,
		game_string( pGameIndex->game_fun ),
		pGameIndex->bankroll,
		pGameIndex->max_wait,
		pGameIndex->cheat );
    }
    fprintf( fp, "S\n\n\n" );

    return;
}


/* Written by: Maniac */
void vsave_games( FILE *fp, AREA_DATA *pArea )
{
    MOB_INDEX_DATA *pMobIndex;
    GAME_DATA      *pGameIndex;
    int             vnum;

    fprintf( fp, "#GAMES\n" );
    for ( vnum = pArea->low_m_vnum; vnum <= pArea->hi_m_vnum; vnum++ )
    {
	if ( !( pMobIndex = get_mob_index( vnum ) )
	    ||  pMobIndex->area != pArea
	    || !pMobIndex->pGame )
	    continue;

	pGameIndex = pMobIndex->pGame;

	fprintf( fp, "M %5d %-30s %10d %3d %1d\t* %s\n",
		pGameIndex->croupier,
		game_string( pGameIndex->game_fun ),
		pGameIndex->bankroll,
		pGameIndex->max_wait,
		pGameIndex->cheat,
		pMobIndex->short_descr );
    }
    fprintf( fp, "S\n\n\n" );

    return;
}


/* New format thanks to Rac */
void save_resets( FILE *fp, AREA_DATA *pArea )
{
    ROOM_INDEX_DATA *pRoomIndex;
    MOB_INDEX_DATA  *pLastMob	= NULL;
    OBJ_INDEX_DATA  *pLastObj;
    RESET_DATA      *pReset;
    char             buf	[MAX_STRING_LENGTH];
    int              vnum;

    fprintf( fp, "#RESETS\n" );
    for ( vnum = pArea->low_r_vnum; vnum <= pArea->hi_r_vnum; vnum++ )
    {
	if ( !( pRoomIndex = get_room_index( vnum ) )
	    ||  pRoomIndex->area != pArea )
	    continue;

	for ( pReset = pRoomIndex->reset_first; pReset; pReset = pReset->next )
	{
	    switch ( pReset->command )
	    {
	    default:	bug( "Save_resets: bad command %c.", pReset->command );
			break;

	    case 'M':	pLastMob = get_mob_index( pReset->arg1 );
			fprintf( fp, "M 0 %d %d %d\n",
				pReset->arg1,
				pReset->arg2,
				pReset->arg3 );
			break;

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

	    case 'P':	pLastObj = get_obj_index( pReset->arg3 );
			fprintf( fp, "P 0 %d 0 %d\n",
				pReset->arg1,
				pReset->arg3 );
			if ( !pLastObj )
			{
			    sprintf( buf, "Save_resets: !NO_OBJ! in [%s]",
				    pArea->filename );
			    bug( buf, 0 );
			}
			break;

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

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

	    case 'D':	break;

	    case 'R':	fprintf( fp, "R 0 %d %d\n",
				pReset->arg1,
				pReset->arg2 );
			break;
	    }
	}
    }
    fprintf( fp, "S\n\n\n" );

    return;
}


/* New format thanks to Rac */
void vsave_resets( FILE *fp, AREA_DATA *pArea )
{
    ROOM_INDEX_DATA *pRoomIndex;
    MOB_INDEX_DATA  *pLastMob	= NULL;
    OBJ_INDEX_DATA  *pLastObj	= NULL;
    RESET_DATA      *pReset;
    char             buf	[MAX_STRING_LENGTH];
    int              vnum;

    fprintf( fp, "#RESETS\n" );
    for ( vnum = pArea->low_r_vnum; vnum <= pArea->hi_r_vnum; vnum++ )
    {
	if ( !( pRoomIndex = get_room_index( vnum ) )
	    ||  pRoomIndex->area != pArea )
	    continue;

	for ( pReset = pRoomIndex->reset_first; pReset; pReset = pReset->next )
	{
	    switch ( pReset->command )
	    {
	    default:	bug( "Save_resets: bad command %c.", pReset->command );
			break;

	    case 'M':	pLastMob = get_mob_index( pReset->arg1 );
			fprintf( fp, "M 0 %5d %2d %5d \t* %s -> %s\n",
				pReset->arg1,
				pReset->arg2,
				pReset->arg3,
				pLastMob->short_descr,
				pRoomIndex->name );
			break;

	    case 'O':	pLastObj = get_obj_index( pReset->arg1 );
			fprintf( fp, "O 0 %5d  0 %5d \t* %s -> %s\n",
				pReset->arg1,
				pReset->arg3,
				capitalize( pLastObj->short_descr ),
				pRoomIndex->name );
			break;

	    case 'P':	pLastObj = get_obj_index( pReset->arg3 );
			fprintf( fp, "P 0 %5d  0 %5d \t* %s inside %s\n",
				pReset->arg1,
				pReset->arg3,
				capitalize( get_obj_index( pReset->arg1 )->short_descr ),
				pLastObj ? pLastObj->short_descr : "!NO_OBJ!" );

			if ( !pLastObj ) /*
					  * Thanks Rac! 
					  */
			{
			    sprintf( buf, "Save_resets: !NO_OBJ! in [%s]",
				    pArea->filename );
			    bug( buf, 0 );
			}
			break;

	    case 'G':	fprintf( fp, "G 0 %5d  0      \t*   %s\n",
				pReset->arg1,
				capitalize( pLastObj->short_descr ) );
			if ( !pLastMob )
			{
			    sprintf( buf, "Save_resets: !NO_MOB! in [%s]",
				    pArea->filename );
			    bug( buf, 0 );
			}
			break;

	    case 'E':	fprintf( fp, "E 0 %5d  0 %5d \t*   %s %s\n",
				pReset->arg1,
				pReset->arg3,
				capitalize( get_obj_index( pReset->arg1 )->short_descr ),
				flag_string( wear_loc_strings, pReset->arg3 ) );
			if ( !pLastMob )
			{
			    sprintf( buf, "Save_resets: !NO_MOB! in [%s]",
				    pArea->filename );
			    bug( buf, 0 );
			}
			break;

	    case 'D':	break;

	    case 'R':	fprintf( fp, "R 0 %5d %2d      \t* Randomize %s\n",
				pReset->arg1,
				pReset->arg2,
				pRoomIndex->name );
			break;
	    }
	}
    }
    fprintf( fp, "S\n\n\n" );

    return;
}


void save_shops( FILE *fp, AREA_DATA *pArea )
{
    MOB_INDEX_DATA *pMobIndex;
    SHOP_DATA      *pShopIndex;
    int             iTrade;
    int             vnum;

    fprintf( fp, "#SHOPS\n" );
    for ( vnum = pArea->low_m_vnum; vnum <= pArea->hi_m_vnum; vnum++ )
    {
	if ( !( pMobIndex = get_mob_index( vnum ) )
	    ||  pMobIndex->area != pArea
	    || !pMobIndex->pShop )
	    continue;

	pShopIndex = pMobIndex->pShop;

	fprintf( fp, "%d ", pShopIndex->keeper );
	for ( iTrade = 0; iTrade < MAX_BUY; 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" );

    return;
}


/* New format thanks to Rac */
void vsave_shops( FILE *fp, AREA_DATA *pArea )
{
    MOB_INDEX_DATA *pMobIndex;
    SHOP_DATA      *pShopIndex;
    int             iTrade;
    int             vnum;

    fprintf( fp, "#SHOPS\n" );
    for ( vnum = pArea->low_m_vnum; vnum <= pArea->hi_m_vnum; vnum++ )
    {
	if ( !( pMobIndex = get_mob_index( vnum ) )
	    ||  pMobIndex->area != pArea
	    || !pMobIndex->pShop )
	    continue;

	pShopIndex = pMobIndex->pShop;

	fprintf( fp, "%d ", pShopIndex->keeper );
	for ( iTrade = 0; iTrade < MAX_BUY; iTrade++ )
	{
	    if ( pShopIndex->buy_type[iTrade] != 0 )
		fprintf( fp, "%2d ", pShopIndex->buy_type[iTrade]	 );
	    else
		fprintf( fp, " 0 "					 );
	}
	fprintf( fp, "%3d %3d ",
			pShopIndex->profit_buy,
			pShopIndex->profit_sell				 );
	fprintf( fp, "%2d %2d ",
			pShopIndex->open_hour,
			pShopIndex->close_hour				 );
	fprintf( fp, "\t* %s\n",
			get_mob_index( pShopIndex->keeper )->short_descr );
    }
    fprintf( fp, "0\n\n\n" );

    return;
}


/*
 * Save_helps contributed by Walker <nkrendel@evans.Denver.Colorado.EDU>.
 */
void save_helps( FILE *fp, AREA_DATA *pArea )
{
    HELP_DATA *pHelp;
    bool       found	= FALSE;

    for ( pHelp = help_first; pHelp; pHelp = pHelp->next )
    {
	if (   !pHelp->area
	    ||  pHelp->area != pArea )
	    continue;

	if ( !found )
	{
	    fprintf( fp, "#HELPS\n\n" );
	    found = TRUE;
	}
	fprintf( fp, "%d %s~\n%s~\n\n",
		pHelp->level,
		all_capitalize( pHelp->keyword ),
		fix_string( pHelp->text ) );
    }

    if ( found )
	fprintf( fp, "0 $~\n\n" );

    return;
}


void save_area( AREA_DATA *pArea )
{
    FILE *fp;
    char  strsave [ MAX_INPUT_LENGTH ];

    fclose( fpReserve );

    sprintf( strsave, "%s%s", AREA_DIR, pArea->filename );

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

    fprintf( fp, "#AREADATA\n"					      );
    fprintf( fp, "Name        %s~\n",	pArea->name		      );
    fprintf( fp, "Author      %s~\n",	pArea->author		      );
    fprintf( fp, "Levels      %d %d\n",	pArea->llv, pArea->ulv	      );
    fprintf( fp, "Security    %d\n",	pArea->security		      );
    fprintf( fp, "VNUMs       %d %d\n",	pArea->lvnum, pArea->uvnum    );
    fprintf( fp, "Builders    %s~\n",	fix_string( pArea->builders ) );
    fprintf( fp, "Recall      %d\n",	pArea->recall		      );
    fprintf( fp, "Reset       %s~\n",	pArea->resetmsg		      );
    fprintf( fp, "End\n\n\n"					      );

    save_helps( fp, pArea );
    save_mobiles( fp, pArea );
    new_save_objects( fp, pArea );
    save_rooms( fp, pArea );

    if ( IS_SET( pArea->area_flags, AREA_VERBOSE ) )
    {
	vsave_specials( fp, pArea );
	vsave_games   ( fp, pArea );
	vsave_resets  ( fp, pArea );
	vsave_shops   ( fp, pArea );
    }
    else
    {
	save_specials( fp, pArea );
	save_games   ( fp, pArea );
	save_resets  ( fp, pArea );
	save_shops   ( fp, pArea );
    }

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

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


void do_asave( CHAR_DATA *ch, char *argument )
{
    AREA_DATA *pArea;
    char       arg1 [MAX_INPUT_LENGTH];
    int        value;

    if ( !ch )
    {
	send_to_all_char( "A gentle breeze comes from the east.\n\r" );
	save_area_list( );
	for ( pArea = area_first; pArea; pArea = pArea->next )
	{
	    save_area( pArea );
	    REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
	    REMOVE_BIT( pArea->area_flags, AREA_ADDED   );
	}
	send_to_all_char( "After the breeze all seems calm.\n\r" );
	return;
    }

    argument = one_argument( argument, arg1 );

    if ( arg1[0] == '\0' )
    {
	send_to_char( "Syntax: asave <vnum>\n\r",    ch );
	send_to_char( "or:     asave list\n\r",      ch );
	send_to_char( "or:     asave area\n\r",      ch );
	send_to_char( "or:     asave changed\n\r",   ch );
	send_to_char( "or:     asave world\n\r",     ch );
	send_to_char( "or:     asave ^ verbose\n\r", ch );
	return;
    }

    value = atoi( arg1 );

    if ( !( pArea = get_area_data( value ) ) && is_number( arg1 ) )
    {
	send_to_char( "That area does not exist.\n\r", ch );
	return;
    }

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

	if ( !str_cmp( "verbose", argument ) )
	    SET_BIT( pArea->area_flags, AREA_VERBOSE );

	save_area( pArea );
	REMOVE_BIT( pArea->area_flags, AREA_VERBOSE );
	return;
    }

    if ( !str_cmp( "world", arg1 ) )
    {
	save_area_list( );
	for ( pArea = area_first; pArea; pArea = pArea->next )
	{
	    if ( !is_builder( ch, pArea ) )
		continue;

	    if ( !str_cmp( "verbose", argument ) )
		SET_BIT( pArea->area_flags, AREA_VERBOSE );

	    save_area( pArea );
	    REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
	    REMOVE_BIT( pArea->area_flags, AREA_ADDED   );
	    REMOVE_BIT( pArea->area_flags, AREA_VERBOSE );
	}

	send_to_char( "You saved the world.\n\r", ch );
	send_to_all_char( "Database saved.\n\r" );
	return;
    }

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

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

	for ( pArea = area_first; pArea; pArea = pArea->next )
	{
	    if ( !is_builder( ch, pArea ) )
		continue;

	    if (   IS_SET( pArea->area_flags, AREA_CHANGED )
		|| IS_SET( pArea->area_flags, AREA_ADDED   ) )
	    {
		if ( !str_cmp( "verbose", argument ) )
		    SET_BIT( pArea->area_flags, AREA_VERBOSE );

		save_area( pArea );
		REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
		REMOVE_BIT( pArea->area_flags, AREA_ADDED   );
		REMOVE_BIT( pArea->area_flags, AREA_VERBOSE );

		sprintf( buf, "%24s - '%s'\n\r", pArea->name, pArea->filename );
		send_to_char( buf, ch );
	    }
	}

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

    if ( !str_cmp( arg1, "list" ) )
    {
	save_area_list( );
	return;
    }

    if ( !str_cmp( arg1, "area" ) )
    {
	pArea = ch->in_room->area;

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

	if ( !str_cmp( "verbose", argument ) )
	    SET_BIT( pArea->area_flags, AREA_VERBOSE );

	save_area( pArea );
	REMOVE_BIT( pArea->area_flags, AREA_CHANGED );
	REMOVE_BIT( pArea->area_flags, AREA_ADDED   );
	REMOVE_BIT( pArea->area_flags, AREA_VERBOSE );

	send_to_char( "Area saved.\n\r", ch );
	return;
    }

    do_asave( ch, "" );
    return;
}