asgard/
asgard/.settings/
asgard/area/
asgard/data/clans/
asgard/data/clans/history/
asgard/data/rosters/
asgard/src/notice/
/**************************************************************************
 *  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.  
 */

#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 "tables.h"  
#include "olc.h"  
#include "newclan.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 = get_temp_file()) == NULL)
	{
		printf_debug("Save_area_list: fopen");
		perror("area.lst");
	}
	else
	{
		/*
		 * Add any help files that need to be loaded at
		 * startup to this section.
		 */
		//        fprintf( fp, "help.are\n"       );    /* ROM OLC */
		fprintf(fp, "social.are\n"); /* ROM OLC */
		//        fprintf( fp, "rot.are\n"        );
		//        fprintf( fp, "olc.hlp\n"        );

		/* Search through Help_area_list */
		for (ha = had_list; ha; ha = ha->next)
		{
			if (ha->area == NULL) /* If area is null..as should be */
				fprintf(fp, "%s\n", ha->filename); /* write down name */
		}
		for (pArea = area_first; pArea; pArea = pArea->next)
		{
			fprintf(fp, "%s\n", pArea->file_name);
		}

		fprintf(fp, "$\n");
		close_write_file("area.lst");
	}

	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;
}

void save_mobprogs(FILE *fp, AREA_DATA *pArea)
{
	MPROG_CODE *pMprog;
	int i;

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

	for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
	{
		if ((pMprog = get_mprog_index(i)) != NULL)
		{
			fprintf(fp, "#%d\n", i);
			fprintf(fp, "%s~\n", fix_string(pMprog->code));
		}
	}

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

void recursive_save_mprogs(MPROG_LIST *pMprog, FILE *fp) {
	if (pMprog == NULL)
		return;
	recursive_save_mprogs(pMprog->next, fp);
	fprintf(fp, "M %s %d %s~\n", mprog_type_to_name(pMprog->trig_type),
			pMprog->vnum, pMprog->trig_phrase);
}

/*****************************************************************************  
 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)
{
	sh_int race = pMobIndex->race;
	char buf[MAX_STRING_LENGTH];
	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 ", fwrite_flag(pMobIndex->affected_by, buf));
	fprintf(fp, "%s ", fwrite_flag(pMobIndex->shielded_by, buf));
	fprintf(fp, "%d %d\n", pMobIndex->alignment, pMobIndex->group);
	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);
	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);
	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);
	fprintf(fp, "%s\n", IS_NULLSTR(pMobIndex->material) ? pMobIndex->material
			: "unknown");

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

	if (pMobIndex->see_all_mortals)
		fprintf(fp, "S %d\n", pMobIndex->see_all_mortals);

	fprintf(fp, "V %d\n", pMobIndex->mob_tier);
	fprintf(fp, "A %d\n", pMobIndex->attacks);

	// Save mprogs to ensure they're loaded in the same order.
	recursive_save_mprogs(pMobIndex->mprogs, fp);

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

	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\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_DRINK_CON:
	case ITEM_FOUNTAIN:
		fprintf(fp, "%d %d '%s' %d %d\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, "%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_PIT:
		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_FOOD:
		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_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_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 ? 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, "%d %d %d '%s' %d\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, "%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 > 0)
		letter = 'B';
	else
		letter = 'R';

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

	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;
			case TO_SHIELDS:
				fprintf(fp, "S ");
				break;
			default:
				printf_debug("olc_save: Invalid Affect->where");
				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));
	}

	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;

	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)
					{
						int locks = 0;
						if (IS_SET( pExit->rs_flags, EX_ISDOOR )
								&& (!IS_SET( pExit->rs_flags, EX_PICKPROOF ))
								&& (!IS_SET( pExit->rs_flags, EX_NOPASS )))
							locks = 1;
						if (IS_SET( pExit->rs_flags, EX_ISDOOR )
								&& (IS_SET( pExit->rs_flags, EX_PICKPROOF ))
								&& (!IS_SET( pExit->rs_flags, EX_NOPASS )))
							locks = 2;
						if (IS_SET( pExit->rs_flags, EX_ISDOOR )
								&& (!IS_SET( pExit->rs_flags, EX_PICKPROOF ))
								&& (IS_SET( pExit->rs_flags, EX_NOPASS )))
							locks = 3;
						if (IS_SET( pExit->rs_flags, EX_ISDOOR )
								&& (IS_SET( pExit->rs_flags, EX_PICKPROOF ))
								&& (IS_SET( pExit->rs_flags, EX_NOPASS )))
							locks = 4;

						fprintf(fp, "D%d\n", pExit->orig_door);
						fprintf(fp, "%s~\n", fix_string(pExit->description));
						fprintf(fp, "%s~\n", pExit->keyword);
						fprintf(fp, "%d %d %d\n", locks, 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 (!IS_NULLSTR(pRoomIndex->owner))
					fprintf(fp, "O %s~\n", pRoomIndex->owner);

				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 %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  
			}
		}
	}

	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 )))
#if defined( VERBOSE )  
						fprintf(
								fp,
								"D 0 %d %d %d The %s door of %s is %s\n",
								pRoomIndex->vnum,
								pExit->orig_door,
								IS_SET( pExit->rs_flags, EX_LOCKED) ? 2 : 1,
								dir_name[pExit->orig_door],
								pRoomIndex->name,
								IS_SET( pExit->rs_flags, EX_LOCKED) ? "closed and locked"
										: "closed");
#endif  
#if !defined( VERBOSE )  
					fprintf( fp, "D 0 %d %d %d\n",
							pRoomIndex->vnum,
							pExit->orig_door,
							IS_SET( pExit->rs_flags, EX_LOCKED) ? 2 : 1 );
#endif  
				}
			}
		}
	}
	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, "#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:
						printf_debug("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 %d 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)
						{
							printf_debug("Save_resets: !NO_MOB! in [%s]",
									pArea->file_name);
						}
						break;

					case 'E':
						fprintf(
								fp,
								"E 0 %d 0 %d *%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)
						{
							printf_debug("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 *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 %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 0 %d\n",
							pReset->arg1,
							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 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 %d 0 %d\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 %d %d\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;
}

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

	if (!(fp = get_temp_file()))
	{
		printf_debug("Open_area: fopen");
		perror(pArea->file_name);
		return;
	}

	fprintf(fp, "#AREADATA\n");
	fprintf(fp, "Name %s~\n", pArea->name);
	fprintf(fp, "Builders %s~\n", fix_string(pArea->builders));
	fprintf(fp, "VNUMs %d %d\n", pArea->min_vnum, pArea->max_vnum);
	fprintf(fp, "Continent %d\n", pArea->continent);
	fprintf(fp, "Mobtier %d\n", pArea->mob_tier);
	fprintf(fp, "Credits %s~\n", pArea->credits);
	fprintf(fp, "Security %d\n", pArea->security);
	fprintf(fp, "Flags %d\n", pArea->area_flags & AREA_RESTRICTED );
	fprintf(fp, "End\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_mobprogs(fp, pArea);

	/* If the area has a help...stick it on the end
	 if ( pArea->helps && pArea->helps->first )
	 save_helps( fp, pArea->helps );  covered by asave helps now */

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

	close_write_file(pArea->file_name);
	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("  asave helps    - saves the helps\n\r", ch);
		send_to_char("  asave clans    - saves the clans\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 (ch && !IS_BUILDER( ch, pArea ))
				continue;

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

		save_other_helps(NULL); /* Save non-area helps */

		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(NULL); /* Save non-area helps */

		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 == ED_NONE)
		{
			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;
		case ED_HELP:
			send_to_char("You cannot save an area from within HEDIT.", ch);
			return;
		case ED_CLAN:
			send_to_char("You cannot save an area from within CEDIT.", ch);
			return;
		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;
	}

	/* Save Help File */
	if (!str_cmp(arg1, "helps"))
	{
		save_other_helps(ch);
		send_to_char("Helps Saved.\n\r", ch);
		return;
	}

	// Shouldn't need this
	/*     if(!str_cmp(arg1, "clans"))
	 {
	 if(CLANS_CHANGED)
	 {
	 save_clans();
	 send_to_char( "Clans Saved.\n\r", ch);
	 load_new_clans_list();
	 send_to_char( "Clans Loaded.\n\r",ch);
	 CLANS_CHANGED = FALSE;
	 return;
	 }
	 send_to_char("There were no changes to be saved.\n\r",ch);
	 return;
	 }  */

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

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

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

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

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

	ha->changed = FALSE;

	return;
}

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

	/* Run through Help_area_List */
	for (ha = had_list; ha != NULL; ha = ha->next)
	{
		/* If the help is changed ... */
		if (ha->changed == TRUE)
		{
			if ((fp = get_temp_file()) == NULL)
			{
				perror(ha->filename);
				send_to_char("Error saving Helps.\n\r", ch);
				return;
			}

			/* Save helps for...open file and the help in it. */
			save_helps(fp, ha);

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

			fprintf(fp, "#$\n");
			close_write_file(ha->filename);
		}
	}
	return;
}