dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// olc_save.cpp - saves area files etc
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with the dawn license *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 **************************************************************************/
/***************************************************************************
 *  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" // dawn standard includes

#include "areas.h"
#include "olc.h"
#include "immquest.h"
#include "offmoot.h"
#include "interp.h"
#include "help.h"
#include "lockers.h"

char *gamble_name( GAMBLE_FUN *function);
void save_attunes( FILE *fp, AREA_DATA *pArea );
void save_mix_db( void);
DECLARE_DO_FUN( do_saveherbs );

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

// areas.cpp
void save_rooms_NAFF( FILE *fp, AREA_DATA *pArea );
void save_object_NAFF( FILE *fp, OBJ_INDEX_DATA *pObjIndex );
void save_mobile_NAFF( FILE *fp, MOB_INDEX_DATA *pMobIndex );
/*
 *  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 int mri; // multi result index
	static char *multi_result[5]; // circular managed result buffer 
	// nothing to do with empty strings
	if( IS_NULLSTR(str)){
        return "";
	}
	// rotate buffers
	++mri%=5;

	manage_dynamic_buffer(&multi_result[mri], str_len(str)+2); // maintain result so always has enough space
	char *result=multi_result[mri]; // managed result buffer

	const char *in=str;
	char *out=result;

    while(*in!='\0') // loop thru, copying into result
    {
		while ((*in== '\r' || *in== '~')){
			in++;
		}
		if(*in!='\0'){
	        *out++= *in++;
		}
    }
    *out = '\0'; // terminate the string
    return result;
}


/*****************************************************************************
 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;

    if ( ( fp = fopen( AREA_LIST".write", "w" ) ) == NULL ){
        bugf("save_area_list(): fopen '%s' for write - error %d (%s)",
			AREA_LIST".write", errno, strerror( errno));
    }else{
		for( pArea = area_first; pArea; pArea = pArea->next ){
			fprintf( fp, "%s\n", pArea->file_name);
		}

		int bytes_written=fprintf( fp, "$\n" );
		fclose( fp );
		if( bytes_written != str_len("$\n") ){
			bugf("save_area_list(): fprintf to '%s' - error %d (%s)",
				AREA_LIST".write", errno, strerror( errno));
			bugf("Incomplete write of " AREA_LIST ".write, write aborted - check diskspace!");
		}else{		
			unlink(AREA_LIST);
			rename(AREA_LIST".write", AREA_LIST);
		}
    }
    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;

	static char local_buf[33];
	if(buf==NULL){
		buf=local_buf;
	}
	
	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;
}

/**************************************************************************/
void save_mobprogs( FILE *fp, AREA_DATA *pArea )
{
	MPROG_CODE *pMprog;
	int i;
	
	fprintf(fp, "#MOBPROGS\n");
	
	for( i = pArea->max_vnum; i>=pArea->min_vnum; i-- )
	{
		if ( (pMprog = get_mprog_index(i) ) != NULL)
		{
		      fprintf(fp, "#%d\n", i);
			  
			  // mobprog names from version 4 up
			  if (area_last->version>3) 
			  {
				  fprintf(fp, "%s~\n", pMprog->title?fix_string(pMprog->title):"");
				  fprintf(fp, "%s~\n", pMprog->author?fix_string(pMprog->author):"");
				  fprintf(fp, "%s~\n", pMprog->last_editor?fix_string(pMprog->last_editor):"");
				  fprintf(fp, "%ld\n", (long)pMprog->last_editdate);
			  }
			  fprintf(fp, "%s~\n", fix_string(pMprog->code));
		}
	}
	
	fprintf(fp,"#0\n\n");
	return;
}

/*****************************************************************************
 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, int version)
{
    sh_int race = pMobIndex->race;
    MPROG_LIST *pMprog;
    char buf[MSL];
    long temp;

    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, "%s~\n",       race_table[race]->name );
    fprintf( fp, "%s ",         fwrite_flag( pMobIndex->act, buf ) );
    fprintf( fp, "%s\n",        fwrite_flag( pMobIndex->act2, buf ) );
	fprintf( fp, "%s ",         fwrite_flag( pMobIndex->affected_by, buf ) );
	fprintf( fp, "%s\n",        fwrite_flag( pMobIndex->affected_by2, buf ) );
    fprintf( fp, "%d %d\n",     pMobIndex->tendency, pMobIndex->alliance );
    fprintf( fp, "%d\n",        pMobIndex->xp_mod );
    fprintf( fp, "%d ",         pMobIndex->level );
    fprintf( fp, "%d ",         pMobIndex->hitroll );
    fprintf( fp, "%dd%d+%d ",	pMobIndex->hit[DICE_NUMBER], 
                                pMobIndex->hit[DICE_TYPE], 
                                pMobIndex->hit[DICE_BONUS] );
    fprintf( fp, "%dd%d+%d ",	pMobIndex->mana[DICE_NUMBER], 
                                pMobIndex->mana[DICE_TYPE], 
                                pMobIndex->mana[DICE_BONUS] );
    fprintf( fp, "%dd%d+%d ",	pMobIndex->damage[DICE_NUMBER], 
								pMobIndex->damage[DICE_TYPE], 
								pMobIndex->damage[DICE_BONUS] );
    fprintf( fp, "%s\n",		attack_table[pMobIndex->dam_type].name );

	if(version<6){ //  Area files versions 5 and lower divided ac by 10 in storage
		fprintf( fp, "%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 );
	}else{
		fprintf( fp, "%d %d %d %d\n", pMobIndex->ac[AC_PIERCE], 
									pMobIndex->ac[AC_BASH], 
									pMobIndex->ac[AC_SLASH], 
									pMobIndex->ac[AC_EXOTIC]);
	}
    fprintf( fp, "%s ",			fwrite_flag( pMobIndex->off_flags,  buf ) );
    fprintf( fp, "%s ",			fwrite_flag( pMobIndex->imm_flags,  buf ) );
    fprintf( fp, "%s ",			fwrite_flag( pMobIndex->res_flags,  buf ) );
    fprintf( fp, "%s\n",		fwrite_flag( pMobIndex->vuln_flags, buf ) );
    fprintf( fp, "%s %s %s %ld\n",
								position_table[pMobIndex->start_pos].short_name,
								position_table[pMobIndex->default_pos].short_name,
								sex_table[pMobIndex->sex].name,
								pMobIndex->wealth );
	fprintf( fp, "%s ",			fwrite_flag( pMobIndex->form,  buf ) );
	fprintf( fp, "%s ",			fwrite_flag( pMobIndex->parts, buf ) );

    fprintf( fp, "%s ",			size_table[pMobIndex->size].name );


	sprintf(buf, "%s", IS_NULLSTR(pMobIndex->material)? "unknown":pMobIndex->material);

	if (has_space(buf)){
		fprintf( fp, "'%s'\n" , buf); //quotes around materials with 2 words
	}else{
		fprintf( fp, "%s\n" , buf);
	}

    if (pMobIndex->group){
     	fprintf( fp, "G %d\n", pMobIndex->group);
	}
    if (pMobIndex->helpgroup){
     	fprintf( fp, "H %d\n", pMobIndex->helpgroup);
	}

    if ((temp = DIF(race_table[race]->act,pMobIndex->act)))
     	fprintf( fp, "F act %s\n", fwrite_flag(temp, buf) );

    if ((temp = DIF(race_table[race]->aff,pMobIndex->affected_by)))
     	fprintf( fp, "F aff %s\n", fwrite_flag(temp, buf) );

    if ((temp = DIF(race_table[race]->off,pMobIndex->off_flags)))
     	fprintf( fp, "F off %s\n", fwrite_flag(temp, buf) );

    if ((temp = DIF(race_table[race]->imm,pMobIndex->imm_flags)))
     	fprintf( fp, "F imm %s\n", fwrite_flag(temp, buf) );

    if ((temp = DIF(race_table[race]->res,pMobIndex->res_flags)))
     	fprintf( fp, "F res %s\n", fwrite_flag(temp, buf) );

    if ((temp = DIF(race_table[race]->vuln,pMobIndex->vuln_flags)))
     	fprintf( fp, "F vul %s\n", fwrite_flag(temp, buf) );

    if ((temp = DIF(race_table[race]->form,pMobIndex->form)))
     	fprintf( fp, "F for %s\n", fwrite_flag(temp, buf) );

    if ((temp = DIF(race_table[race]->parts,pMobIndex->parts)))
    	fprintf( fp, "F par %s\n", fwrite_flag(temp, buf) );

    for (pMprog = pMobIndex->mprogs; pMprog; pMprog = pMprog->next)
    {
		fprintf(fp, "M ");
		if(pMprog->pos_flags){ // encode a little = so say position flags flow
			fprintf(fp, "= %s ", flags_print(pMprog->pos_flags));
		}
        fprintf(fp, "%s %d %s~\n",
        mprog_type_to_name(pMprog->trig_type), pMprog->prog->vnum,
                pMprog->trig_phrase);
    }
    fprintf(fp, "\n");

    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 )) )
		if ( pArea->version<11){
		    save_mobile( fp, pMob, pArea->version);
		}else{
			save_mobile_NAFF( fp, pMob );
		}
    }

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

/**************************************************************************/
// write the object values to fp
void save_object_values( FILE *fp, OBJ_INDEX_DATA *pObjIndex )
{
	assertp(fp);
    char buf[MSL], buf2[MSL];

    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 %d 0 0\n",
				pObjIndex->value[2] < 1 ? -1 : pObjIndex->value[2] ); // infinite 
	    break;

		case ITEM_INSTRUMENT:
			fprintf( fp, "%d %d 0 0 0\n",
				pObjIndex->value[0],
				pObjIndex->value[1] );
		    break;

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

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

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

		case ITEM_COMPONENT:
            fprintf( fp, "%d %s 0 0 0\n",
                     pObjIndex->value[0],	// charges
					 pObjIndex->value[1]==-1?"none":  	// spell name
						pack_word(skill_table[pObjIndex->value[1]].name));
            break;
            
        case ITEM_FOOD:
            fprintf( fp, "%d %d 0 %s 0\n",
                     pObjIndex->value[0],
                     pObjIndex->value[1],
                     fwrite_flag( pObjIndex->value[3], buf ) );
            break;
            
        case ITEM_PORTAL:
            fprintf( fp, "%d %s %s %d 0\n",
                     pObjIndex->value[0],
                     fwrite_flag( pObjIndex->value[1], buf ),
                     fwrite_flag( pObjIndex->value[2], buf2 ),
                     pObjIndex->value[3]);
            break;
            
        case ITEM_FURNITURE:
            fprintf( fp, "%d %d %s %d %d\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 %d %d %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, "%d %d %d %d %d\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, "%d %s %s %s %s\n",
		     pObjIndex->value[0] > 0 ? // no negative numbers 
		     pObjIndex->value[0]
		     : 0,
		     pObjIndex->value[1] != -1 ?
		     pack_word(skill_table[pObjIndex->value[1]].name)
		     : "''",
		     pObjIndex->value[2] != -1 ?
		     pack_word(skill_table[pObjIndex->value[2]].name)
		     : "''",
		     pObjIndex->value[3] != -1 ?
		     pack_word(skill_table[pObjIndex->value[3]].name)
		     : "''",
		     pObjIndex->value[4] != -1 ?
		     pack_word(skill_table[pObjIndex->value[4]].name)
		     : "''");
	    break;

		case ITEM_PARCHMENT:
			fprintf( fp, "%d ", pObjIndex->value[0] );
			fprintf( fp, "%d ", pObjIndex->value[1] );
			fprintf( fp, "%d ", pObjIndex->value[2] );
			fprintf( fp, "%s ", language_safe_lookup_by_id(pObjIndex->value[3])->name);
			fprintf( fp, "%d ", pObjIndex->value[4] );
			break;

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

/*****************************************************************************
 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 )
{
    char letter;
    AFFECT_DATA *pAf=NULL;
    EXTRA_DESCR_DATA *pEd;
    char buf[MSL];

    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, "%s~\n",	pObjIndex->material );
    fprintf( fp, "%s ",		item_name(pObjIndex->item_type));
    fprintf( fp, "%s ",		fwrite_flag( pObjIndex->extra_flags,  buf ));
	fprintf( fp, "%s ",		fwrite_flag( pObjIndex->extra2_flags, buf ));
	if ( IS_TRAPPED( pObjIndex ))
	{
		fprintf( fp, "%ld %d %d %d ",
							(long)pObjIndex->trap_trig,
							pObjIndex->trap_dtype,
							pObjIndex->trap_charge,
							pObjIndex->trap_modifier );
	}
    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.
 */

	save_object_values( fp, pObjIndex );

    fprintf( fp, "%d ", pObjIndex->level );
    fprintf( fp, "%d ", pObjIndex->weight );
    fprintf( fp, "%d ", pObjIndex->cost );

         if ( pObjIndex->condition >  90 ) letter = 'P';
    else if ( pObjIndex->condition >  75 ) letter = 'G';
    else if ( pObjIndex->condition >  50 ) letter = 'A';
    else if ( pObjIndex->condition >  25 ) letter = 'W';
    else if ( pObjIndex->condition >  10 ) letter = 'D';
    else if ( pObjIndex->condition >   1 ) letter = 'B';
    else                                   letter = 'R';

    fprintf( fp, "%c\n", letter );

    fprintf( fp, "%d %d\n",
        pObjIndex->absolute_size,
        pObjIndex->relative_size);
 
//    fprintf( fp, "%s\n", fwrite_flag(pObjIndex->clss_restriction, buf) );

    for( pAf = pObjIndex->affected; pAf; pAf = pAf->next )
    {
//		if (pAf->where == WHERE_OBJEXTRA || pAf->bitvector == 0)
		if (pAf->where == WHERE_OBJEXTRA)
			fprintf( fp, "A %d %d\n",  reverse_translate_old_apply_number(pAf->location), pAf->modifier );
		else if (pAf->where == WHERE_OBJEXTRA2)
			fprintf( fp, "B %d %d\n",  reverse_translate_old_apply_number(pAf->location), pAf->modifier );
		else
		{
			fprintf( fp, "F " );
			
			switch(pAf->where)
			{
			case WHERE_AFFECTS:
				fprintf( fp, "A " );
				break;
			case WHERE_AFFECTS2:
				fprintf( fp, "B " );
				break;
			case WHERE_IMMUNE:
				fprintf( fp, "I " );
				break;
			case WHERE_RESIST:
				fprintf( fp, "R " );
				break;
			case WHERE_VULN:
				fprintf( fp, "V " );
				break;
			case WHERE_SKILLS:
				fprintf( fp, "K " );
				break;
			case WHERE_OBJECTSPELL:
				fprintf( fp, "Z " );
				break;
			default:
				bug("olc_save: Invalid Affect->where");
				break;
			}
			if ( pAf->where == WHERE_SKILLS ) {
				fprintf( fp, "'%s' %d\n", skill_table[pAf->type].name, pAf->modifier );
			} else if (pAf->where == WHERE_OBJECTSPELL){
				fprintf( fp, "'%s' %d %d %s\n", skill_table[pAf->type].name,
					pAf->level, pAf->duration, fwrite_flag( pAf->bitvector, buf ));
			}else{
				fprintf( fp, "%d %d %s\n", reverse_translate_old_apply_number(pAf->location), pAf->modifier,
					fwrite_flag( pAf->bitvector, buf ) );
			}
		}
    }

    // optional object stuff below here
	if(pObjIndex->class_allowances){
		//fwrite_wordflag(classnames_types, pObjIndex->class_allowances,"C ",fp);
		fwrite_wordflag(classnames_flags, pObjIndex->class_allowances,"_CA ",fp);
	}
	// save classgroup object restrictions
	{
		OBJRESTRICT_LIST_DATA *pr;
		for( pr = pObjIndex->restrict; pr; pr = pr->next )
		{
			fprintf( fp, "R %s %s %d 0\n",
				pr->classgroup->name,
				pr->affectprofile->name,
				pr->priority);
		}
	}

    for( pEd = pObjIndex->extra_descr; pEd; pEd = pEd->next )
    {
        if (is_space(pEd->description[0]))
        {
            fprintf( fp, "E\n%s~\n.%s~\n", pEd->keyword,
             fix_string( pEd->description ) );
        }
        else
        {   
            fprintf( fp, "E\n%s~\n%s~\n", pEd->keyword,
             fix_string( pEd->description ) );
        }
    }
    fprintf(fp, "\n");

    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 )) ){
			if ( pArea->version<11){
				save_object( fp, pObj );
			}else{
				save_object_NAFF( fp, pObj );
			}
		}
    }

    fprintf( fp, "#0\n\n\n\n" );
    return;
}
 
/*****************************************************************************
 Name:		save_attunes
 Purpose:	Save #ATTUNE section of an area file.
 Called by:	save_area(olc_save.c).
 ****************************************************************************/
void save_attunes( FILE *fp, AREA_DATA *pArea )
{
	OBJ_INDEX_DATA *pObj;
	int i;
	char buf[MSL];

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

	for ( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
	{
		if (( pObj = get_obj_index(i)))
		{
			if ( IS_SET( pObj->attune_flags, ATTUNE_NEED_TO_USE ))
			{
				fprintf( fp, "O %d %s\n",
					pObj->vnum,
					fwrite_flag( pObj->attune_flags,  buf ));
			}
		}
	}
	fprintf( fp, "S\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;

    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, "#%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->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++ )	// I hate this
                {
                    if ( ( pExit = pRoomIndex->exit[door] )
                          && pExit->u1.to_room )
                    {

                        fprintf( fp, "D%d\n",      door );
                        fprintf( fp, "%s~\n",      fix_string( pExit->description ) );
                        fprintf( fp, "%s~\n",      pExit->keyword );
                        fprintf( fp, "%s %d %d\n", // locks
                                flags_print(pExit->rs_flags),
                                                   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->clan){
			fprintf ( fp, "C %s~\n" , pRoomIndex->clan->savename());
		}
		 			     
		if (pRoomIndex->owner && str_cmp(pRoomIndex->owner,""))
		 fprintf ( fp, "O %s~\n" , pRoomIndex->owner );

		if (pRoomIndex->msp_sound)
		 fprintf ( fp, "X %s~\n" , pRoomIndex->msp_sound );

        fprintf( fp, "S\n\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;
	OBJ_INDEX_DATA *pObjIndex;
    
    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 %d %s Load to: %s\n", pMobIndex->vnum,
                                                      spec_name( pMobIndex->spec_fun ),
                                                      pMobIndex->short_descr );
#else
                fprintf( fp, "M %d %s\n", pMobIndex->vnum,
                              spec_name( pMobIndex->spec_fun ) );
#endif
            }
        }

		// Go through the objects and save their obj_spec_funs too :)
		for( pObjIndex = obj_index_hash[iHash]; pObjIndex; pObjIndex = pObjIndex->next )
        {
			if ( pObjIndex && pObjIndex->area == pArea && pObjIndex->ospec_fun )
			{
				fprintf( fp, "O %d %s Load to: %s\n", pObjIndex->vnum,
													  ospec_name( pObjIndex->ospec_fun ),
													  pObjIndex->short_descr );
			}
		}
    }

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

/*****************************************************************************
 Name:		save_gamble
 Purpose:	Save #GAMBLE section of area file.
 Called by:	save_area(olc_save.c).
 ****************************************************************************/
void save_gamble( FILE *fp, AREA_DATA *pArea )
{
	int iHash;
	MOB_INDEX_DATA *pMobIndex;
	
	fprintf( fp, "#GAMBLE\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->gamble_fun )
			{
				fprintf( fp, "M %d %s\n", pMobIndex->vnum,
					gamble_name( pMobIndex->gamble_fun ));
			}
		}
	}
	fprintf( fp, "S\n\n\n\n" );
	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;
    int iHash;

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

    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:
						bugf( "Save_resets: bad command %c.", pReset->command );
						break;
						
					case 'M':
						pLastMob = get_mob_index( pReset->arg1 );
						fprintf( fp, "M 0 %d %d %d %d\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 %d %d %d\n", 
							pReset->arg1, pReset->arg2,
							pReset->arg3 );
						break;
						
					case 'P':
						pLastObj = get_obj_index( pReset->arg1 );
						fprintf( fp, "P 0 %d %d %d %d\n", 
							pReset->arg1,
							pReset->arg2,
							pReset->arg3,
							pReset->arg4 );
						break;
						
					case 'G':
						fprintf( fp, "G 0 %d %d\n", pReset->arg1, pReset->arg2);
						if ( !pLastMob )
						{
							bugf("Save_resets: !NO_MOB! in [%s]", pArea->file_name );
						}
						break;
						
					case 'E':
						// reset_version 1 format
						//fprintf( fp, "E 0 %d %d %d\n",
						//	pReset->arg1, pReset->arg2, pReset->arg3 );
						fprintf( fp, "E 0 %d %d",pReset->arg1, pReset->arg2);
						fwrite_wordflag( wear_location_types, pReset->arg3, "", fp);
						if ( !pLastMob )
						{
							bugf( "Save_resets: !NO_MOB! in [%s]", pArea->file_name );
						}
						break;
						
					case 'D':
						break;
						
					case 'R':
						pRoom = get_room_index( pReset->arg1 );
						fprintf( fp, "R 0 %d %d\n", 
							pReset->arg1,
							pReset->arg2 );
						break;
					}
				}
			}	/* 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;
}

/**************************************************************************/
extern bool gio_abort_fwrite_wordflag_with_undefined_flags; // gio code

/**************************************************************************/
void fwrite_areaecho(area_echo_data *pAe, FILE *fp)
{
	fprintf(fp, "AreaEcho %2d %2d %3d %s~\n", pAe->firsthour, pAe->lasthour,
			pAe->percentage,pack_string(pAe->echotext));
}
/**************************************************************************/
void fwrite_areaecho_recursive(area_echo_data *pAe, FILE *fp)
{
	if(!pAe)
	{ 
		return;
	}
	fwrite_areaecho_recursive(pAe->next, fp);
	fwrite_areaecho(pAe, fp);
}

/*****************************************************************************
 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 )
{
	pArea->version = 11; // force all areas to use NAFF
//	pArea->version = 6;  // force all areas to save in old format

    FILE *fp;
    fclose( fpReserve );
	char newfilename[MIL];
	sprintf(newfilename, "%s%s.save", BACKUP_AREA_DIR, pArea->file_name);
	logf("save_area(): saving %s...", pArea->file_name);
    if ( !( fp = fopen( newfilename, "w" ) ) )
    {
        bugf("save_area(): fopen '%s' for write - error %d (%s)",
			newfilename, errno, strerror( errno));
		exit_error( 1 , "save_area", "fopen for write error");
    }

	if(IS_SET(pArea->olc_flags, OLCAREA_IGNORE_UNDEFINED_FLAGS)){
		gio_abort_fwrite_wordflag_with_undefined_flags=false;
	}else{
		gio_abort_fwrite_wordflag_with_undefined_flags=true;
	}

	if(pArea->version>=11){
		fprintf( fp, "#DAWNAREADATA\n" );
	}else{
		fprintf( fp, "#AREADATA\n" );
	}
    fprintf( fp, "Version     %d\n",	pArea->version);
	fprintf( fp, "FromMUD     %s~\n",	MUD_NAME); // could aid in importing from other dawn based muds in future
	if(pArea->version>=11){
		fprintf( fp, "*parent_codebase %s\n", DAWN_RELEASE_VERSION);
	}
    fprintf( fp, "Name        %s~\n",        pArea->name );
	
	if(pArea->version>10){		
		fprintf( fp, "ShortName   %s~\n",	pack_string(pArea->short_name));
	}
	
    fprintf( fp, "Builders    %s~\n",    fix_string(ltrim_string(rtrim_string(pArea->builders ))) );	
	if(!IS_NULLSTR(pArea->credits)){
		fprintf( fp, "Credits     %s~\n",    fix_string(ltrim_string(rtrim_string(pArea->credits))) );
	}

	// builder restrictions - write to the file
	for (int br=0;br<MAX_BUILD_RESTRICTS;br++)
	{
		if(!IS_NULLSTR(pArea->build_restricts[br])){
			fprintf( fp, "build_restricts '%s' %s~\n",
				flag_string(buildrestrict_types, br),
				fix_string( pArea->build_restricts[br]) );
		}
	}

	fprintf( fp, "VNUMs       %d %d\n",     pArea->min_vnum, pArea->max_vnum );
    if (!IS_NULLSTR(pArea->lcomment))
    {
        fprintf( fp, "LComment    %s\n", fix_string( pArea->lcomment) );
    }
	if(pArea->version<11){
		char buf[MIL];
	    fprintf( fp, "AreaFlags   %s\n", fwrite_flag(pArea->area_flags, buf) );
	}else{
		fwrite_wordflag( area_flags, pArea->area_flags, "AFlags  ", fp );
	}
    if (pArea->low_level>-1)
        fprintf( fp, "LRange      %d %d\n",    pArea->low_level, pArea->high_level );
    fprintf( fp, "Security    %d\n",	pArea->security );
    fprintf( fp, "Colour      %s~\n",	pArea->colour);
	fprintf( fp, "colourcode  %c\n",	pArea->colourcode);
    fprintf( fp, "MapScale    %d\n",	pArea->mapscale);	
    fprintf( fp, "MapLevel    %d\n",	pArea->maplevel);	
    fprintf( fp, "Vnum_offset %d\n",	pArea->vnum_offset);
	if(pArea->continent){
		fprintf( fp, "Continent   %s~\n",	pArea->continent->name );
	}

	fwrite_areaecho_recursive(pArea->echoes, fp);
	if(pArea->version>=11){
		fprintf( fp, "*LastSaved  %.24s~\n",	ctime(&current_time));
	}
    fprintf( fp, "End\n\n\n\n" );

    save_mobiles(	fp, pArea );
    save_objects(	fp, pArea );
	if ( pArea->version<11){
	    save_rooms(		fp, pArea );
	}else{
		save_rooms_NAFF( fp, pArea );
	}
    save_specials(	fp, pArea );
    save_resets(	fp, pArea );
	if ( pArea->version>=11){
		save_shops_NAFF(fp, pArea );
		save_mobprogs_NAFF(	fp, pArea );
	}else{
	    save_shops(		fp, pArea );
		save_mobprogs(	fp, pArea );
		save_gamble(	fp, pArea );	// NAFF saves gambling in with mob
		save_attunes(	fp, pArea );	// NAFF saves attunes in with object
	}
    
    fprintf( fp, "#$\n" );

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

	// rename area/*.are to bak_area/*.are.old, 
	// then bak_area/*.are.save to area/*.are
	{
		char old_areafilename[MIL];
		sprintf(old_areafilename, "%s%s.old", BACKUP_AREA_DIR, pArea->file_name);
		char areafilename[MIL];
		sprintf(areafilename, "%s%s", AREA_DIR, pArea->file_name);
#ifdef WIN32
		unlink(old_areafilename);
#endif
		if(file_exists(areafilename)){
			if(rename(areafilename,old_areafilename)!=0){
				bugf("Error %d occured renaming '%s' to '%s'!.. exiting to avoid area file corruption.", 
					errno, areafilename, old_areafilename);
				exit_error( 1 , "save_area", "error renaming old filename");
			}
		}
		if(rename(newfilename, areafilename)!=0){
			bugf("Error %d occured renaming '%s' to '%s'!.. exiting to avoid area file corruption.", 
				errno, newfilename, areafilename);
			exit_error( 1 , "save_area", "error renaming new filename");
		}		
	}
	logf("save_area(): save complete.");

	if(IS_SET(pArea->olc_flags, OLCAREA_IGNORE_UNDEFINED_FLAGS)){
		gio_abort_fwrite_wordflag_with_undefined_flags=true;
	}
    return;
}


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

	pArea               =   new_area();
	pArea->min_vnum     =   0;
	pArea->max_vnum     =   32700;
	SET_BIT( pArea->olc_flags, OLCAREA_ADDED );

	pArea->file_name= str_dup("onefile.are");
    pArea->name= str_dup("allinone");
	pArea->security =9;

	save_area(pArea);
	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[MIL];
    AREA_DATA *pArea;
    FILE *fp;
    int value;

    fp = NULL;
	
	if (IS_NPC(ch) || ch->pcdata->security<2)
	{
		ch->println("You must have an olc security 2 or higher to use this command.");
		return;
	}

    if ( !ch ) // Do an autosave 
    {
		log_string("Doing autosave of areas.");
		save_area_list();
		for( pArea = area_first; pArea; pArea = pArea->next )
		{
			save_area( pArea );
			REMOVE_BIT( pArea->olc_flags, OLCAREA_CHANGED );
		}
		log_string("Autosave completed.");
		return;
    } // end of autosave

    smash_tilde( argument );
    strcpy( arg1, argument );
    if ( arg1[0] == '\0' )
    {
		ch->println("Syntax:");
		ch->println("  asave <vnum>   - saves a particular area");
		ch->println("  asave list     - saves the area.lst file");
		ch->println("  asave area     - saves the area being edited");
		ch->println("  asave .        - saves all changed zones");
		ch->println("  asave changed  - saves all changed zones");
		ch->println("  asave world    - saves the world! (db dump)");
		ch->println("  asave onefile  - saves the whole world into one file! (db dump)");
        return;
    }

	// Snarf the value (which need not be numeric). 
	value = atoi( arg1 );
	if ( !( pArea = get_area_data( value ) ) && is_number( arg1 ) )
	{
		ch->println("That area does not exist.");
		return;
	}
    
	// Save area of given vnum. 
    // ------------------------ 
    if ( is_number( arg1 ) )
    {
		if ( !IS_BUILDER( ch, pArea, BUILDRESTRICT_OTHER ) )
		{
			ch->println("You are not a builder for this area.");
			return;
		}
		save_area_list();
		save_area( pArea );
		ch->printlnf("Saved area %d (%s)", pArea->vnum, pArea->name);
		return;
    }

    // Save the world, only authorized areas. //
    // -------------------------------------- // 
    if ( !str_cmp( "world", arg1 ) )
    {
		if(!IS_ADMIN(ch)){
			ch->println("Only admin can asave the world.");
			return;
		}
		if(!HAS_SECURITY(ch,9)){
			ch->println("You require security 9 to asave the world.");
			return;
		}
		save_area_list();
		for( pArea = area_first; pArea; pArea = pArea->next )
		{
			// Builder must be assigned this area. 
			if ( !IS_BUILDER( ch, pArea, BUILDRESTRICT_OTHER ) )
			continue;	  

			save_area( pArea );
			REMOVE_BIT( pArea->olc_flags, OLCAREA_CHANGED );
		}
		ch->println( "You saved all area files.");
		ch->wrapln( "`RNOTE:`x It is strongly recommended that you use `=Casave .`x to save the area you are working on! "
			"- asave world forces the mud to resave EVERY area and usually lags the game.\r\n");
		return;
    }

	// Save the world into one file. //
    // ----------------------------- // 

    if ( !str_cmp( "onefile", arg1 ) )
    {
		save_world_onefile();
		ch->println("You saved the world into onefile.are.");
		return;
    }


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

    if ( !str_cmp( "changed", arg1 ) || !str_cmp( ".", arg1 ) )
    {
		char buf[MIL];
		
		save_area_list();
		ch->println("Saved zones:");
		sprintf( buf, "None.\r\n" );
		
		for( pArea = area_first; pArea; pArea = pArea->next )
		{
			// Builder must be assigned this area. 
			if ( !IS_BUILDER( ch, pArea, BUILDRESTRICT_OTHER ) )
				continue;
			// Save changed areas
			if ( IS_SET(pArea->olc_flags, OLCAREA_CHANGED) )
			{
				save_area( pArea );
				ch->printlnf("%24s - '%s'", pArea->name, pArea->file_name );
				buf[0] = '\0';
				REMOVE_BIT( pArea->olc_flags, OLCAREA_CHANGED );
			}
		}
		
		if ( !str_cmp( buf, "None.\r\n" ) ){
			ch->print( buf);
		}
		if(!str_cmp( "changed", arg1 )){
			ch->println("Note: you can use 'asave .' as shorthand for 'asave changed'");
		}
		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 )
		{
			ch->println("You are not editing an area, therefore an area vnum is required.");
			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, BUILDRESTRICT_OTHER ) )
		{
			ch->println("You are not a builder for this area.");
			return;
		}


		save_area_list();
		save_area( pArea );
		REMOVE_BIT( pArea->olc_flags, OLCAREA_CHANGED );
		ch->println("Area saved.");
		return;
	}

    /* Show correct syntax. */
    /* -------------------- */
    do_asave( ch, "" );
    return;
}

/*****************************************************************************
 Name:		do_asave
 Purpose:	Entry point for saving area data.
 Called by:	interpreter(interp.c)
 ****************************************************************************/
// prototype
void save_clan_db( void );

void reboot_autosave( char_data *ch)
{
	char buf [MSL];
    AREA_DATA *pArea;

	log_string("Starting reboot_autosave():");
	
	// inform the person doing the reboot
	if (ch && ch->desc && ch->desc->connected_socket){
		ch->desc->write( "starting auto changed area save.\r\n",0);
	}

	// areas
	{
		bool none= true;
		for( pArea = area_first; pArea; pArea = pArea->next )
		{
			// Save changed areas.
			if ( IS_SET(pArea->olc_flags, OLCAREA_CHANGED) )
			{
				save_area( pArea );
				sprintf( buf, "**%s -> %s", pArea->name, pArea->file_name );
				log_string( buf);
				if (ch && ch->desc && ch->desc->connected_socket)	
				{		
					ch->desc->write(buf,0);
					ch->desc->write("\r\n",0);
				}
				REMOVE_BIT( pArea->olc_flags, OLCAREA_CHANGED );
				none= false;
			}		
		}
		if (none)
		{
			log_string("No areas needed saving.");		
			if (ch && ch->desc)	
				ch->desc->write("No areas needed saving.\r\n",0);
		}
		else
		{
			save_area_list();
		}
		log_string("reboot area autosave completed.");
	}

	// room invite lists
	{
		bool none= true;
		for( pArea = area_first; pArea; pArea = pArea->next )
		{
			// Save changed room invite lists.
			if ( IS_SET(pArea->olc_flags, OLCAREA_INVITELISTCHANGED) )
			{
				save_area_roominvitelist( pArea );
				sprintf( buf, "**%s room invite list.", pArea->name);
				log_string( buf);
				if (ch && ch->desc && ch->desc->connected_socket)	
				{		
					ch->desc->write(buf,0);
					ch->desc->write("\r\n",0);
				}
				REMOVE_BIT( pArea->olc_flags, OLCAREA_INVITELISTCHANGED);
				none= false;
			}		
		}
		if(none)
		{
			if(GAMESETTING4(GAMESET4_ROOM_INVITES_DISABLED)){
				log_string("No room invite lists needed saving - room invites are disabled.");
			}else{
				log_string("No room invite lists needed saving.");
			}
			if (ch && ch->desc)	
				ch->desc->write("No room invite lists needed saving.\r\n",0);
		}
		log_string("reboot area autosave completed.");
	}
	
	if (IS_SET(SKILL_TABLE_FLAGS,SEDIT_CHANGED)){
		log_string("Autosaving " SKILLS_FILE);
		do_write_skills(NULL,"");
		REMOVE_BIT(SKILL_TABLE_FLAGS,SEDIT_CHANGED);
		log_string("Skills autosave complete.");
	}

	if (IS_SET(CLASS_TABLE_FLAGS,CLASSEDIT_CHANGED)){
		log_string("Autosaving " CLASSES_LIST);
		do_write_classes(NULL,"");
		REMOVE_BIT(CLASS_TABLE_FLAGS,CLASSEDIT_CHANGED);
		log_string("Class table autosave complete.");
	}

	// Save Command Table if it was changed
	if (IS_SET(COM_TABLE_FLAGS,COMEDIT_CHANGED)){
		log_string("Autosaving " COMMANDS_FILE);
		do_write_commandtable(NULL,"");
		REMOVE_BIT(COM_TABLE_FLAGS,COMEDIT_CHANGED);
		log_string("Autosave complete.");
	}

	// Save Deity Table if it was changed
	if (IS_SET(DEITY_FLAGS,DEDIT_CHANGED)){
		log_string("Autosaving " DEITY_FILE);
		do_savedeities(NULL,"");
		REMOVE_BIT(DEITY_FLAGS,DEDIT_CHANGED);
		log_string("Autosave complete.");
	}

	// Save Herb Table if it was changed
	if ( IS_SET( HERB_FLAGS,DEDIT_CHANGED)){	// using dedit_changed cause I'm too lazy to make an herb_changed :)
		log_string("Autosaving " HERB_FILE );
		do_saveherbs(NULL,"");
		REMOVE_BIT( HERB_FLAGS, DEDIT_CHANGED);
		log_string("Autosave complete.");
	}

	if (IS_SET(QUEST_TABLE_FLAGS,QEDIT_CHANGED)){
		log_string("Autosaving " QUEST_FILE);
		save_quest_db();
		REMOVE_BIT(QUEST_TABLE_FLAGS,QEDIT_CHANGED);
		log_string("Autosave complete.");
	}

	if (IS_SET(MIX_FLAGS,DEDIT_CHANGED)){
		log_string("Autosaving " MIX_FILE);
		save_mix_db();
		REMOVE_BIT(MIX_FLAGS,DEDIT_CHANGED);
		log_string("Autosave complete.");
	}

	if (IS_SET(CLAN_FLAGS,DEDIT_CHANGED)){
		log_string("Autosaving " CLAN_FILE);
		save_clan_db();		
		REMOVE_BIT(CLAN_FLAGS,DEDIT_CHANGED);
		log_string("Autosave complete.");
	}

	if (IS_SET(SKILLGROUPEDIT_FLAGS, DEDIT_CHANGED)){
		log_string("Autosaving " SKILLGROUPS_FILE);
		do_write_skillgroups(NULL,"");
		REMOVE_BIT(SKILLGROUPEDIT_FLAGS,DEDIT_CHANGED);
		log_string("Autosave complete.");
	}

	if (LANGUAGE_NEEDS_SAVING){
		log_string("Autosaving languages");
		do_write_languages(NULL,"");
		LANGUAGE_NEEDS_SAVING=false;
		log_string("Autosave complete.");
	}

	do_hsave(NULL,"");

	lockers->lockers_save_db();
}
/**************************************************************************/
void do_hsave( char_data *ch, char *argument)
{
	helpfile_data *pHelpFD;
	bool nonesaved= true;

	// if it isn't the code doing it
    if (ch){
		if (!HAS_SECURITY(ch,1)){
			ch->println("The hsave command is an olc command, you dont have olc permissions.");
			return;
		}
		
		if (!HAS_SECURITY(ch,7)){
			ch->println("security 7 required for hsave, you dont have olc permissions.");
			return;
		}
	}

    for ( pHelpFD = helpfile_first; pHelpFD; pHelpFD = pHelpFD->next )
    {  
		if (IS_SET(pHelpFD->flags, HELPFILE_CHANGED) || !str_cmp("all", argument))
		{
			if (ch)
			{
				ch->printlnf("Saving helpfile: %s", pHelpFD->file_name);
			}
			nonesaved = false;
			logf("Saving help: %s", pHelpFD->file_name);
			//save_helpfile(pHelpFD);
			save_helpfile_NAFF(pHelpFD);
			REMOVE_BIT(pHelpFD->flags, HELPFILE_CHANGED);
		}
    }

	if (ch && nonesaved)
	{
		ch->println("No helpfiles needed saving.");
	}
	if(!nonesaved){
		logf("Helpfile saving completed.");
	}
    return;    
}


/**************************************************************************/
// Name:		save_helpfile
// Purpose:	Save a helpfile, 
// Called by:	do_hsave(olc_save.c).
/**************************************************************************/
void save_helpfile( helpfile_data *pHelpfile )
{
    FILE *fp;
    char buf[MSL];

    fclose( fpReserve );
    sprintf (buf, "%s%s", HELP_DIR, pHelpfile->file_name);
    if ( !( fp = fopen( buf , "w" ) ) ){
        bugf("save_helpfile(): fopen '%s' for write - error %d (%s)",
			buf, errno, strerror( errno));
		exit_error( 1 , "save_helpfile", "fopen for write error");
    }

    fprintf( fp, "#HELPS\n\n" );
    save_helpentries( fp, pHelpfile );
    fprintf( fp, "#$\n" );

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

/**************************************************************************/
void save_helpentries( FILE *fp, helpfile_data *pHelpfile )
{
    help_data *pHelp;

    for ( pHelp = help_first; pHelp != NULL; pHelp = pHelp->next )
    {
		if (pHelp->helpfile==pHelpfile && !IS_SET(pHelp->flags, HELP_REMOVEHELP))
		{
			fprintf(fp, "-2 2~\n" );
			fprintf(fp, "%d %s~\n", pHelp->level, fix_string(pHelp->keyword));

			fwrite_wordflag( help_flags, pHelp->flags, " ", fp );

			if ( is_space(pHelp->text[0]) )
			{
				fprintf(fp, ".");
			}

			hide_tilde (pHelp->text);
			
			// add a little . to maintain formating in help entries if required
			if (is_space(pHelp->text[0]))
			{
				fprintf(fp, ".");
			}

			fprintf(fp, "%s~\n\n\n", fix_string(pHelp->text));
			show_tilde (pHelp->text);
		}
	}

	//  mark the end of the helps section
	fprintf( fp, "0 $~\n");
    return;
}

/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/