1stMud/CVS/
1stMud/area/CVS/
1stMud/backup/CVS/
1stMud/bin/
1stMud/bin/CVS/
1stMud/bin/extras/
1stMud/bin/extras/CVS/
1stMud/data/CVS/
1stMud/data/i3/CVS/
1stMud/doc/1stMud/
1stMud/doc/1stMud/CVS/
1stMud/doc/CVS/
1stMud/doc/Diku/
1stMud/doc/Diku/CVS/
1stMud/doc/MPDocs/CVS/
1stMud/doc/Merc/CVS/
1stMud/doc/Rom/
1stMud/doc/Rom/CVS/
1stMud/log/CVS/
1stMud/notes/
1stMud/notes/CVS/
1stMud/player/CVS/
1stMud/player/backup/CVS/
1stMud/player/deleted/CVS/
1stMud/src/CVS/
1stMud/src/config/CVS/
1stMud/src/h/CVS/
1stMud/src/o/CVS/
1stMud/win/CVS/
/**************************************************************************
*  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)
{
  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);
    }

  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)
{
  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, AREA_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);
    }
  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, "{x", n_fun,
		      "<vnum>     - saves a particular area", NULL);
	  cmd_syntax (ch, "{x", n_fun,
		      "list       - saves the area.lst file", NULL);
	  cmd_syntax (ch, "{x", n_fun,
		      "area       - save the area being edited", NULL);
	  cmd_syntax (ch, "{x", n_fun, "helps      - save help files", NULL);
	  cmd_syntax (ch, "{x", n_fun, "data       - save all data files",
		      NULL);
	  cmd_syntax (ch, "{x", n_fun,
		      "changed    - saves all changed areas", NULL);
	  cmd_syntax (ch, "{x", n_fun,
		      "world      - save the world! (db dump)", NULL);
	  cmd_syntax (ch, "{x", n_fun,
		      "backup     - execute a backup script", NULL);
	  for (value = 0; datasave_table[value].name != NULL; value++)
	    {
	      cmd_syntax (ch, "{x", 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, AREA_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, AREA_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, AREA_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, AREA_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;
}