1stMud4.5.3/
1stMud4.5.3/backup/
1stMud4.5.3/bin/
1stMud4.5.3/bin/extras/
1stMud4.5.3/data/i3/
1stMud4.5.3/doc/1stMud/
1stMud4.5.3/doc/Diku/
1stMud4.5.3/doc/MPDocs/
1stMud4.5.3/doc/Rom/
1stMud4.5.3/notes/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*  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.                *
***************************************************************************
*          1stMud ROM Derivative (c) 2001-2004 by Markanth                *
*            http://www.firstmud.com/  <markanth@firstmud.com>            *
*         By using this code you have agreed to follow the term of        *
*             the 1stMud license in ../doc/1stMud/LICENSE                 *
***************************************************************************/

#include "merc.h"
#include "tables.h"
#include "olc.h"
#include "interp.h"
#include "special.h"
#include "data_table.h"
#include "recycle.h"

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

char *fix_string(const char *str)
{
	static char strfix[MAX_STRING_LENGTH * 2];
	int i;
	int o;

	if (str == NULL || !str_cmp(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;
}

void save_area_list(void)
{
#ifdef DISABLE_MYSQL
	FileData *fp;
	AreaData *pArea;

	if ((fp = f_open(AREA_LIST, "w")) == NULL)
	{
		bug("Save_area_list: file open");
		log_error("area.lst");
	}
	else
	{
		for (pArea = area_first; pArea; pArea = pArea->next)
		{
			f_printf(fp, "%s" LF, pArea->file_name);
		}

		f_printf(fp, "$" LF);
		f_close(fp);
	}
#endif
	return;
}

#define    NBUF 5
#define    NBITS 52

char *write_flags(flag_t flags)
{
	static int cnt;
	static char buf[NBUF][NBITS + 1];
	flag_t count = 0, temp = 1;

	cnt = (cnt + 1) % NBUF;

	buf[cnt][0] = '+';

	do
	{
		if (IsSet(flags, (temp << count)))
			buf[cnt][count + 1] = 'Y';
		else
			buf[cnt][count + 1] = 'n';
		count++;
	}
	while ((temp << count) <= flags && count < 64);

	buf[cnt][count + 1] = '\0';
	return buf[cnt];
}

void save_mobprogs(FileData * fp, AreaData * pArea)
{
	ProgCode *pMprog;
	vnum_t i;

	f_printf(fp, "#MOBPROGS" LF);

	for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
	{
		if ((pMprog = get_prog_index(i, PRG_MPROG)) != NULL)
		{
			f_printf(fp, "#%ld" LF, i);
			f_printf(fp, "%s~" LF, fix_string(pMprog->code));
		}
	}

	f_printf(fp, "#0" LF);
	f_printf(fp, "" LF);
	return;
}

void save_objprogs(FileData * fp, AreaData * pArea)
{
	ProgCode *pOprog;
	vnum_t i;

	f_printf(fp, "#OBJPROGS" LF);

	for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
	{
		if ((pOprog = get_prog_index(i, PRG_OPROG)) != NULL)
		{
			f_printf(fp, "#%ld" LF, i);
			f_printf(fp, "%s~" LF, fix_string(pOprog->code));
		}
	}

	f_printf(fp, "#0" LF);
	f_printf(fp, "" LF);
	return;
}

void save_roomprogs(FileData * fp, AreaData * pArea)
{
	ProgCode *pRprog;
	vnum_t i;

	f_printf(fp, "#ROOMPROGS" LF);

	for (i = pArea->min_vnum; i <= pArea->max_vnum; i++)
	{
		if ((pRprog = get_prog_index(i, PRG_RPROG)) != NULL)
		{
			f_printf(fp, "#%ld" LF, i);
			f_printf(fp, "%s~" LF, fix_string(pRprog->code));
		}
	}

	f_printf(fp, "#0" LF);
	f_printf(fp, "" LF);
	return;
}

void save_mobile(FileData * fp, CharIndex * pMobIndex)
{
	RaceData *race = pMobIndex->race;
	ProgList *pMprog;
	flag_t temp;

	f_printf(fp, "#%ld" LF, pMobIndex->vnum);
	f_printf(fp, "%s~" LF, pMobIndex->player_name);
	f_printf(fp, "%s~" LF, pMobIndex->short_descr);
	f_printf(fp, "%s~" LF, Upper(fix_string(pMobIndex->long_descr)));
	f_printf(fp, "%s~" LF, Upper(fix_string(pMobIndex->description)));
	f_printf(fp, "%s~" LF, race->name);
	f_printf(fp, "%s ", write_flags(pMobIndex->act));
	f_printf(fp, "%s ", write_flags(pMobIndex->affected_by));
	f_printf(fp, "%d %ld" LF, pMobIndex->alignment, pMobIndex->group);
	f_printf(fp, "%d ", pMobIndex->level);
	f_printf(fp, "%d %d ", pMobIndex->random, pMobIndex->autoset);
	f_printf(fp, "%d" LF, pMobIndex->hitroll);
	f_printf(fp, "%dd%d+%d ", pMobIndex->hit[DICE_NUMBER],
			 pMobIndex->hit[DICE_TYPE], pMobIndex->hit[DICE_BONUS]);
	f_printf(fp, "%dd%d+%d ", pMobIndex->mana[DICE_NUMBER],
			 pMobIndex->mana[DICE_TYPE], pMobIndex->mana[DICE_BONUS]);
	f_printf(fp, "%dd%d+%d ", pMobIndex->damage[DICE_NUMBER],
			 pMobIndex->damage[DICE_TYPE], pMobIndex->damage[DICE_BONUS]);
	f_printf(fp, "'%s'" LF, attack_table[pMobIndex->dam_type].name);
	f_printf(fp, "%d %d %d %d" LF, pMobIndex->ac[AC_PIERCE] / 10,
			 pMobIndex->ac[AC_BASH] / 10, pMobIndex->ac[AC_SLASH] / 10,
			 pMobIndex->ac[AC_EXOTIC] / 10);
	f_printf(fp, "%s ", write_flags(pMobIndex->off_flags));
	f_printf(fp, "%s ", write_flags(pMobIndex->imm_flags));
	f_printf(fp, "%s ", write_flags(pMobIndex->res_flags));
	f_printf(fp, "%s" LF, write_flags(pMobIndex->vuln_flags));
	f_printf(fp, "%s %s %s %ld" LF,
			 flag_string(position_flags, pMobIndex->start_pos),
			 flag_string(position_flags, pMobIndex->default_pos),
			 flag_string(sex_flags, pMobIndex->sex), pMobIndex->wealth);
	f_printf(fp, "%s ", write_flags(pMobIndex->form));
	f_printf(fp, "%s ", write_flags(pMobIndex->parts));

	f_printf(fp, "%s ", flag_string(size_flags, pMobIndex->size));
	f_printf(fp, "'%s'" LF, GetStr(pMobIndex->material, "unknown"));

	if ((temp = DIF(race->act, pMobIndex->act)))
		f_printf(fp, "F act %s" LF, write_flags(temp));

	if ((temp = DIF(race->aff, pMobIndex->affected_by)))
		f_printf(fp, "F aff %s" LF, write_flags(temp));

	if ((temp = DIF(race->off, pMobIndex->off_flags)))
		f_printf(fp, "F off %s" LF, write_flags(temp));

	if ((temp = DIF(race->imm, pMobIndex->imm_flags)))
		f_printf(fp, "F imm %s" LF, write_flags(temp));

	if ((temp = DIF(race->res, pMobIndex->res_flags)))
		f_printf(fp, "F res %s" LF, write_flags(temp));

	if ((temp = DIF(race->vuln, pMobIndex->vuln_flags)))
		f_printf(fp, "F vul %s" LF, write_flags(temp));

	if ((temp = DIF(race->form, pMobIndex->form)))
		f_printf(fp, "F for %s" LF, write_flags(temp));

	if ((temp = DIF(race->parts, pMobIndex->parts)))
		f_printf(fp, "F par %s" LF, write_flags(temp));

	for (pMprog = pMobIndex->mprog_first; pMprog; pMprog = pMprog->next)
	{
		f_printf(fp, "M %s %ld %s~" LF, prog_type_to_name(pMprog->trig_type),
				 pMprog->prog->vnum, pMprog->trig_phrase);
	}

	if (pMobIndex->kills > 2 || pMobIndex->deaths > 2)
		f_printf(fp, "S %ld %ld" LF, pMobIndex->kills, pMobIndex->deaths);

	return;
}

void save_mobiles(FileData * fp, AreaData * pArea)
{
	vnum_t i;
	CharIndex *pMob;

	f_printf(fp, "#MOBILES" LF);

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

	f_printf(fp, "#0" LF);
	f_printf(fp, "" LF);
	return;
}

void save_object(FileData * fp, ObjIndex * pObjIndex)
{
	char letter;
	AffectData *pAf;
	ExDescrData *pEd;
	ProgList *pOprog;

	f_printf(fp, "#%ld" LF, pObjIndex->vnum);
	f_printf(fp, "%s~" LF, pObjIndex->name);
	f_printf(fp, "%s~" LF, pObjIndex->short_descr);
	f_printf(fp, "%s~" LF, fix_string(pObjIndex->description));
	f_printf(fp, "%s~" LF, pObjIndex->material);
	f_printf(fp, "%s ", flag_string(type_flags, pObjIndex->item_type));
	f_printf(fp, "%s ", write_flags(pObjIndex->extra_flags));
	f_printf(fp, "%s" LF, write_flags(pObjIndex->wear_flags));

	switch (pObjIndex->item_type)
	{
		default:
			f_printf(fp, "%s ", write_flags(pObjIndex->value[0]));
			f_printf(fp, "%s ", write_flags(pObjIndex->value[1]));
			f_printf(fp, "%s ", write_flags(pObjIndex->value[2]));
			f_printf(fp, "%s ", write_flags(pObjIndex->value[3]));
			f_printf(fp, "%s" LF, write_flags(pObjIndex->value[4]));
			break;

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

		case ITEM_CONTAINER:
			f_printf(fp, "%ld %s %ld %ld %ld" LF, pObjIndex->value[0],
					 write_flags(pObjIndex->value[1]), pObjIndex->value[2],
					 pObjIndex->value[3], pObjIndex->value[4]);
			break;

		case ITEM_WEAPON:
			f_printf(fp, "%s %ld %ld %s %s" LF,
					 weapon_name(pObjIndex->value[0]), pObjIndex->value[1],
					 pObjIndex->value[2],
					 attack_table[pObjIndex->value[3]].name,
					 write_flags(pObjIndex->value[4]));
			break;

		case ITEM_PILL:
		case ITEM_POTION:
		case ITEM_SCROLL:
			f_printf(fp, "%ld '%s' '%s' '%s' '%s'" LF,
					 pObjIndex->value[0] > 0 ? 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:
			f_printf(fp, "%ld %ld %ld '%s' %ld" LF, pObjIndex->value[0],
					 pObjIndex->value[1], pObjIndex->value[2],
					 pObjIndex->value[3] !=
					 -1 ? skill_table[pObjIndex->value[3]].name : "",
					 pObjIndex->value[4]);
			break;
	}

	f_printf(fp, "%d %d %ld ", pObjIndex->level, pObjIndex->weight,
			 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';

	f_printf(fp, "%c" LF, letter);

	for (pAf = pObjIndex->affect_first; pAf; pAf = pAf->next)
	{
		if (pAf->where == TO_OBJECT || pAf->bitvector == 0)
			f_printf(fp, "A" LF "%d %d" LF, pAf->location, pAf->modifier);
		else
		{
			f_printf(fp, "F" LF);

			switch (pAf->where)
			{
				case TO_AFFECTS:
					letter = 'A';
					break;
				case TO_IMMUNE:
					letter = 'I';
					break;
				case TO_RESIST:
					letter = 'R';
					break;
				case TO_VULN:
					letter = 'V';
					break;
				default:
					bug("olc_save: Invalid Affect->where");
					letter = ' ';
					break;
			}

			f_printf(fp, "%c %d %d %s" LF, letter, pAf->location,
					 pAf->modifier, write_flags(pAf->bitvector));
		}
	}

	for (pEd = pObjIndex->ed_first; pEd; pEd = pEd->next)
	{
		f_printf(fp, "E" LF "%s~" LF "%s~" LF, pEd->keyword,
				 fix_string(pEd->description));
	}
	for (pOprog = pObjIndex->oprog_first; pOprog; pOprog = pOprog->next)
	{
		f_printf(fp, "O %s %ld %s~" LF, prog_type_to_name(pOprog->trig_type),
				 pOprog->prog->vnum, pOprog->trig_phrase);
	}

	return;
}

void save_objects(FileData * fp, AreaData * pArea)
{
	vnum_t i;
	ObjIndex *pObj;

	f_printf(fp, "#OBJECTS" LF);

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

	f_printf(fp, "#0" LF);
	f_printf(fp, "" LF);
	return;
}

void save_rooms(FileData * fp, AreaData * pArea)
{
	RoomIndex *pRoomIndex;
	ExDescrData *pEd;
	ExitData *pExit;
	int iHash;
	int door;
	ProgList *pRprog;

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

				for (pEd = pRoomIndex->ed_first; pEd; pEd = pEd->next)
				{
					f_printf(fp, "E" LF "%s~" LF "%s~" LF, pEd->keyword,
							 fix_string(pEd->description));
				}
				for (door = 0; door < MAX_DIR; door++)
				{
					if ((pExit = pRoomIndex->exit[door]) && pExit->u1.to_room
						&& !IsSet(pExit->rs_flags, EX_TEMP))
					{

						if (IsSet(pExit->rs_flags, EX_CLOSED)
							|| IsSet(pExit->rs_flags, EX_LOCKED)
							|| IsSet(pExit->rs_flags, EX_PICKPROOF)
							|| IsSet(pExit->rs_flags, EX_NOPASS)
							|| IsSet(pExit->rs_flags, EX_EASY)
							|| IsSet(pExit->rs_flags, EX_HARD)
							|| IsSet(pExit->rs_flags, EX_INFURIATING)
							|| IsSet(pExit->rs_flags, EX_NOCLOSE)
							|| IsSet(pExit->rs_flags, EX_NOLOCK))
							SetBit(pExit->rs_flags, EX_ISDOOR);
						else
							RemBit(pExit->rs_flags, EX_ISDOOR);

						f_printf(fp, "D%d" LF, pExit->orig_door);
						f_printf(fp, "%s~" LF,
								 fix_string(pExit->description));
						f_printf(fp, "%s~" LF, pExit->keyword);
						f_printf(fp, "%s %ld %ld" LF,
								 write_flags(pExit->rs_flags), pExit->key,
								 pExit->u1.to_room->vnum);
					}
				}
				if (pRoomIndex->mana_rate != 100
					|| pRoomIndex->heal_rate != 100)
					f_printf(fp, "M %d H %d" LF, pRoomIndex->mana_rate,
							 pRoomIndex->heal_rate);

				if (!NullStr(pRoomIndex->owner))
					f_printf(fp, "O %s~" LF, pRoomIndex->owner);
				if (pRoomIndex->guild > -1 && pRoomIndex->guild < top_class)
					f_printf(fp, "G %d" LF, pRoomIndex->guild);
				for (pRprog = pRoomIndex->rprog_first; pRprog;
					 pRprog = pRprog->next)
				{
					f_printf(fp, "R %s %ld %s~" LF,
							 prog_type_to_name(pRprog->trig_type),
							 pRprog->prog->vnum, pRprog->trig_phrase);
				}
				f_printf(fp, "S" LF);
			}
		}
	}
	f_printf(fp, "#0" LF);
	f_printf(fp, "" LF);
	return;
}

void save_specials(FileData * fp, AreaData * pArea)
{
	int iHash;
	CharIndex *pMobIndex;

	f_printf(fp, "#SPECIALS" LF);

	for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
	{
		for (pMobIndex = char_index_hash[iHash]; pMobIndex;
			 pMobIndex = pMobIndex->next)
		{
			if (pMobIndex && pMobIndex->area == pArea && pMobIndex->spec_fun)
			{
				if (IsSet(mud_info.mud_flags, VERBOSE_RESETS))
					f_printf(fp, "M %ld %s  * Load to: %s" LF,
							 pMobIndex->vnum, spec_name(pMobIndex->spec_fun),
							 pMobIndex->short_descr);
				else
					f_printf(fp, "M %ld %s" LF, pMobIndex->vnum,
							 spec_name(pMobIndex->spec_fun));
			}
		}
	}

	f_printf(fp, "S" LF);
	f_printf(fp, "" LF);
	return;
}

void save_door_resets(FileData * fp, AreaData * pArea)
{
	int iHash;
	RoomIndex *pRoomIndex;
	ExitData *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
						&& !IsSet(pExit->rs_flags, EX_TEMP)
						&& (IsSet(pExit->rs_flags, EX_CLOSED)
							|| IsSet(pExit->rs_flags, EX_LOCKED)))
					{
						if (IsSet(mud_info.mud_flags, VERBOSE_RESETS))
							f_printf(fp,
									 "F 0 %ld %d 0 %s  * The %s door of %s (%s)."
									 LF, pRoomIndex->vnum, pExit->orig_door,
									 write_flags(pExit->rs_flags),
									 dir_name[pExit->orig_door],
									 pRoomIndex->name, flag_string(exit_flags,
																   pExit->rs_flags));
						else
							f_printf(fp, "F 0 %ld %d 0 %s" LF,
									 pRoomIndex->vnum, pExit->orig_door,
									 write_flags(pExit->rs_flags));
					}
				}
			}
		}
	}
	return;
}

void save_resets(FileData * fp, AreaData * pArea)
{
	ResetData *pReset;
	CharIndex *pLastMob = NULL;
	ObjIndex *pLastObj;
	RoomIndex *pRoom;
	int iHash;

	f_printf(fp, "#RESETS" LF);

	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)
				{
					if (IsSet(mud_info.mud_flags, VERBOSE_RESETS))
						switch (pReset->command)
						{
							default:
								bugf("Save_resets: bad command %c.",
									 pReset->command);
								break;

							case 'M':
								pLastMob = get_char_index(pReset->arg1);
								f_printf(fp,
										 "M 0 %ld %d %ld %d  * Load %s" LF,
										 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);
								f_printf(fp,
										 "O 0 %ld 0 %ld  * %s loaded to %s"
										 LF, pReset->arg1, pReset->arg3,
										 capitalize(pLastObj->short_descr),
										 pRoom->name);
								break;

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

							case 'G':
								f_printf(fp,
										 "G 0 %ld 0  * %s is given to %s" LF,
										 pReset->arg1,
										 capitalize(get_obj_index
													(pReset->
													 arg1)->short_descr),
										 pLastMob ? pLastMob->short_descr :
										 "!NO_MOB!");
								if (!pLastMob)
								{
									bugf("Save_resets: !NO_MOB! in [%s]",
										 pArea->file_name);
								}
								break;

							case 'E':
								f_printf(fp,
										 "E 0 %ld 0 %ld  * %s is loaded %s of %s"
										 LF, 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)
								{
									bugf("Save_resets: !NO_MOB! in [%s]",
										 pArea->file_name);
								}
								break;

							case 'D':
								break;

							case 'R':
								pRoom = get_room_index(pReset->arg1);
								f_printf(fp,
										 "R 0 %ld %d %ld  * Randomize %s" LF,
										 pReset->arg1, pReset->arg2,
										 pReset->arg3, pRoom->name);
								break;
						}
					else
						switch (pReset->command)
						{
							default:
								bugf("Save_resets: bad command %c.",
									 pReset->command);
								break;

							case 'M':
								pLastMob = get_char_index(pReset->arg1);
								f_printf(fp, "M 0 %ld %d %ld %d" LF,
										 pReset->arg1, pReset->arg2,
										 pReset->arg3, pReset->arg4);
								break;

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

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

							case 'G':
								f_printf(fp, "G 0 %ld 0" LF, pReset->arg1);
								if (!pLastMob)
								{
									bugf("Save_resets: !NO_MOB! in [%s]",
										 pArea->file_name);
								}
								break;

							case 'E':
								f_printf(fp, "E 0 %ld 0 %ld" LF, pReset->arg1,
										 pReset->arg3);
								if (!pLastMob)
								{
									bugf("Save_resets: !NO_MOB! in [%s]",
										 pArea->file_name);
								}
								break;

							case 'D':
								break;

							case 'R':
								pRoom = get_room_index(pReset->arg1);
								f_printf(fp, "R 0 %ld %d %ld" LF,
										 pReset->arg1, pReset->arg2,
										 pReset->arg3);
								break;
						}
				}
			}
		}
	}
	f_printf(fp, "S" LF LF);
	return;
}

void save_shops(FileData * fp, AreaData * pArea)
{
	ShopData *pShopIndex;
	CharIndex *pMobIndex;
	int iTrade;
	int iHash;

	f_printf(fp, "#SHOPS" LF);

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

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

	f_printf(fp, "0" LF LF);
	return;
}

void save_area(AreaData * pArea)
{
#ifdef DISABLE_MYSQL
	FileData *fp;
	char filename[512];

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

	if (!(fp = f_open(filename, "w")))
	{
		bug("Open_area: file open");
		log_error(pArea->file_name);
	}
	else
	{
		RemBit(pArea->area_flags, OLC_CHANGED);
		f_printf(fp, "#AREADATA" LF);
		write_string(fp, "Name", pArea->name, NULL);
		write_string(fp, "Builders", pArea->builders, NULL);
		f_writef(fp, "VNUMs", "%ld %ld" LF, pArea->min_vnum, pArea->max_vnum);
		write_string(fp, "Credits", pArea->credits, NULL);
		write_string(fp, "LvlComment", pArea->lvl_comment, NULL);
		write_string(fp, "ResetMsg", pArea->resetmsg, NULL);
		write_int(fp, "MinLevel", "%d", pArea->min_level, 0);
		write_int(fp, "MaxLevel", "%d", pArea->max_level, MAX_LEVEL);
		write_int(fp, "Version", "%d", AREA_VERSION, 0);
		write_int(fp, "Security", "%d", pArea->security, 0);
		if (pArea->clan != NULL)
			write_string(fp, "Clan", pArea->clan->name, NULL);
		f_writef(fp, "Climate", "%d %d %d" LF, pArea->weather.climate_temp,
				 pArea->weather.climate_precip, pArea->weather.climate_wind);
		write_int(fp, "Recall", "%ld", pArea->recall, 0);
		write_bit(fp, "Flags", pArea->area_flags, 0);
		write_sound(fp, "Sound", pArea->sound);
		f_writef(fp, "Stats", "%ld %ld", pArea->kills, pArea->deaths);
		f_printf(fp, END_MARK LF);
		f_printf(fp, "" LF);
		f_printf(fp, "" LF);

		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);
		save_objprogs(fp, pArea);
		save_roomprogs(fp, pArea);

		f_printf(fp, "#$" LF);

		f_close(fp);
	}
#else
	vnum_t vnum;
	CharIndex *mob;
	ObjIndex *obj;
	RoomIndex *room;
	int i;

	db_del_area(pArea);

	db_insert_area(false, pArea);

	for (vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++)
	{
		if ((mob = get_char_index(vnum)))
		{
			db_insert_mob(false, mob);
			if (mob->mprog_first)
				db_insert_progs(false, pArea, mob->mprog_first, vnum, "MOB");
			if (mob->spec_fun)
				db_insert_specials(false, pArea, mob->spec_fun, vnum);
			if (mob->pShop)
				db_insert_shop(false, mob->pShop);
		}
		if ((obj = get_obj_index(vnum)))
		{
			db_insert_obj(false, obj);
			if (obj->ed_first)
				db_insert_descs(false, pArea, obj->ed_first, vnum, "OBJ");
			if (obj->affect_first)
				db_insert_objaffects(false, pArea, obj);
			if (obj->oprog_first)
				db_insert_progs(false, pArea, obj->oprog_first, vnum, "OBJ");
		}
		if ((room = get_room_index(vnum)))
		{
			db_insert_room(false, room);
			for (i = 0; i < MAX_DIR; i++)
			{
				if (room->exit[i] && room->exit[i]->u1.to_room
					&& !IsSet(room->exit[i]->rs_flags, EX_TEMP))
					db_insert_exits(false, pArea, room->exit[i], vnum);
			}
			if (room->ed_first)
				db_insert_descs(false, pArea, room->ed_first, vnum, "ROOM");
			if (room->rprog_first)
				db_insert_progs(false, pArea, room->rprog_first, vnum,
								"ROOM");
			if (room->reset_first)
				db_insert_resets(false, room);
		}
	}
#endif
	return;
}

Do_Fun(do_asave)
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	AreaData *pArea;
	FILE *fp;
	int value, sec;

	fp = NULL;

	sec = !ch ? 9 : IsNPC(ch) ? 0 : ch->pcdata->security;

	argument = one_argument(argument, arg1);
	one_argument(argument, arg2);

	if (NullStr(arg1))
	{
		if (ch)
		{
			chprintln(ch, "Usage:");
			cmd_syntax(ch, "     ", n_fun,
					   "<vnum>     - saves a particular area", NULL);
			cmd_syntax(ch, "     ", n_fun,
					   "list       - saves the area.lst file", NULL);
			cmd_syntax(ch, "     ", n_fun,
					   "area       - save the area being edited", NULL);
			cmd_syntax(ch, "     ", n_fun, "helps      - save help files",
					   NULL);
			cmd_syntax(ch, "     ", n_fun, "data       - save all data files",
					   NULL);
			cmd_syntax(ch, "     ", n_fun,
					   "changed    - saves all changed areas", NULL);
			cmd_syntax(ch, "     ", n_fun,
					   "world      - save the world! (db dump)", NULL);
			cmd_syntax(ch, "     ", n_fun,
					   "backup     - execute a backup script", NULL);
			for (value = 0; datasave_table[value].name != NULL; value++)
			{
				cmd_syntax(ch, "     ", n_fun,
						   FORMATF("%-10s - saves %s data",
								   datasave_table[value].name,
								   datasave_table[value].name), NULL);
			}
		}

		return;
	}

	else if (is_number(arg1))
	{

		value = atoi(arg1);
		if (!(pArea = get_area_data(value)))
		{
			if (ch)
				chprintln(ch, "That area does not exist.");
			return;
		}
		if (ch && !IsBuilder(ch, pArea))
		{
			chprintln(ch, "You are not a builder for this area.");
			return;
		}

		save_area_list();
		save_area(pArea);

		return;
	}

	else if (!str_cmp("world", arg1))
	{
#ifdef HAVE_WORKING_FORK
		pid_t pid = fork();

		if (pid == 0)
		{
#endif
			save_area_list();
			for (pArea = area_first; pArea; pArea = pArea->next)
			{

				if (ch && !IsBuilder(ch, pArea))
					continue;

				save_area(pArea);
				RemBit(pArea->area_flags, OLC_CHANGED);
			}
			for (value = 0; datasave_table[value].name != NULL; value++)
				(*datasave_table[value].fun) (act_write);
#ifdef HAVE_WORKING_FORK

			_exit(1);
		}
		else if (pid > 0)
		{
#endif
			if (ch)
				chprintln(ch, "You saved the world.");
			log_string("World saved (db dump).");
#ifdef HAVE_WORKING_FORK

		}
		else
		{
			chprintln(ch, "Error saving world.");
			log_error("save world: fork()");
		}
#endif
		return;
	}
	else if (!str_cmp("backup", arg1))
	{
		FILE *fp;
		char buf[MIL];
		char p[MPL];

		if ((ch && get_trust(ch) < MAX_LEVEL - 2) || sec < 9)
		{
			chprintln(ch, "Sorry, not enough security to do that.");
			return;
		}
#if defined WIN32 || defined __CYGWIN__
		sprintf(buf, WIN_DIR "backup.bat %s", arg2);
#else
		sprintf(buf, BIN_DIR "backup %s", arg2);
#endif
		if ((fp = popen(buf, "r")) == NULL)
		{
			chprintlnf(ch, "Error processing %s %s", arg1, arg2);
			return;
		}

		fread(p, MPL - 1000, 1, fp);
		sendpage(ch, p);
		chprintln(ch, NULL);
		pclose(fp);
		return;
	}

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

		save_area_list();

		if (ch)
			chprintln(ch, "Saved zones:");
		else
			log_string("Saved zones:");

		sprintf(buf, "None.");

		for (pArea = area_first; pArea; pArea = pArea->next)
		{

			if (ch && !IsBuilder(ch, pArea))
				continue;

			if (IsSet(pArea->area_flags, OLC_CHANGED))
			{
				save_area(pArea);
				sprintf(buf, "%24s - '%s'", pArea->name, pArea->file_name);
				if (ch)
					chprintln(ch, buf);
				else
					log_string(buf);
				RemBit(pArea->area_flags, OLC_CHANGED);
			}
		}

		if (!str_cmp(buf, "None."))
		{
			if (ch)
				chprintln(ch, buf);
			else
				log_string("None.");
		}
		return;
	}

	else if (!str_cmp(arg1, "list"))
	{
		save_area_list();
		chprintln(ch, "Area list saved.");
		return;
	}

	else if (!str_cmp(arg1, "area"))
	{
		if (!ch || !ch->desc)
			return;

		if (ch->desc->editor == ED_NONE)
		{
			chprintln(ch,
					  "You are not editing an area, "
					  "therefore an area vnum is required.");
			return;
		}

		if ((pArea = get_olc_area(ch->desc)))
			pArea = ch->in_room->area;

		if (!IsBuilder(ch, pArea))
		{
			chprintln(ch, "You are not a builder for this area.");
			return;
		}

		save_area_list();
		save_area(pArea);
		RemBit(pArea->area_flags, OLC_CHANGED);
		chprintln(ch, "Area saved.");
		return;
	}
	else if (!str_cmp(arg1, "data"))
	{
		for (value = 0; datasave_table[value].name != NULL; value++)
			(*datasave_table[value].fun) (act_write);

		chprintln(ch, "All data files saved.");
		return;
	}
	else
	{
		for (value = 0; datasave_table[value].name != NULL; value++)
		{
			if (!str_cmp(arg1, datasave_table[value].name))
			{
				(*datasave_table[value].fun) (act_write);
				chprintlnf(ch, "%s data saved.",
						   capitalize(datasave_table[value].name));
				return;
			}
		}

		if (ch)
			do_function(ch, &do_asave, "");
	}
	return;
}