LOP/
LOP/area/
LOP/boards/
LOP/channels/
LOP/clans/
LOP/classes/
LOP/color/
LOP/councils/
LOP/deity/
LOP/races/
LOP/src/specials/
/*****************************************************************************
 * DikuMUD (C) 1990, 1991 by:                                                *
 *   Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen,   *
 *   and Katja Nyboe.                                                        *
 *---------------------------------------------------------------------------*
 * MERC 2.1 (C) 1992, 1993 by:                                               *
 *   Michael Chastain, Michael Quan, and Mitchell Tse.                       *
 *---------------------------------------------------------------------------*
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider.                    *
 *   Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, *
 *         gorog, Grishnakh, Nivek, Tricops, and Fireblade.                  *
 *---------------------------------------------------------------------------*
 * SMAUG 1.7 FUSS by: Samson and others of the SMAUG community.              *
 *                    Their contributions are greatly appreciated.           *
 *---------------------------------------------------------------------------*
 * LoP (C) 2006, 2007, 2008 by: the LoP team.                                *
 *****************************************************************************/

#include <stdio.h>
#include <string.h>
#include "h/mud.h"

extern bool fBootDb;
bool check_area_conflict( AREA_DATA *carea, int low_range, int hi_range );

CMDF( do_aassign )
{
   char buf[MSL];
   AREA_DATA *tarea, *tmp;

   if( !ch || is_npc( ch ) )
      return;

   set_char_color( AT_IMMORT, ch );

   if( !argument || argument[0] == '\0' )
   {
      send_to_char( "Usage: aassign <filename>\r\n", ch );
      return;
   }

   if( !str_cmp( "none", argument ) || !str_cmp( "clear", argument ) )
   {
      ch->pcdata->area = NULL;
      assign_area( ch );
      if( !ch->pcdata->area )
         send_to_char( "Area pointer cleared.\r\n", ch );
      else
         send_to_char( "Originally assigned area restored.\r\n", ch );
      return;
   }

   mudstrlcpy( buf, argument, sizeof( buf ) );
   tarea = NULL;

   if( get_trust( ch ) >= PERM_HEAD
   || ( is_name( buf, ch->pcdata->bestowments ) && get_trust( ch ) >= sysdata.perm_modify_proto ) )
   {
      for( tmp = first_area; tmp; tmp = tmp->next )
      {
         if( !str_cmp( buf, tmp->filename ) )
         {
            tarea = tmp;
            break;
         }
      }
   }
   if( !tarea )
   {
      for( tmp = first_build; tmp; tmp = tmp->next )
      {
         if( !str_cmp( buf, tmp->filename ) )
         {
            if( get_trust( ch ) >= PERM_HEAD
            || is_name( tmp->filename, ch->pcdata->bestowments )
            || ( ch->pcdata->council && is_name( "aassign", ch->pcdata->council->powers ) ) )
            {
               tarea = tmp;
               break;
            }
            else
            {
               send_to_char( "You do not have permission to use that area.\r\n", ch );
               return;
            }
         }
      }
   }
   if( !tarea )
   {
      send_to_char( "No such area. Check 'zones' and 'vnums'.\r\n", ch );
      return;
   }
   ch->pcdata->area = tarea;
   ch_printf( ch, "Assigning you: %s\r\n", tarea->name );
}

int save_programs( MPROG_DATA *mprog, FILE *fp )
{
   int count = 0;

   if( ( mprog->arglist && mprog->arglist[0] != '\0' ) )
   {
      if( mprog->type == IN_FILE_PROG )
      {
         fprintf( fp, "> %s %s~\n", mprog_type_to_name( mprog->type ), mprog->arglist );
         count++;
      }
      /* Don't let it save progs which came from files. That would be silly. */
      else if( mprog->comlist && mprog->comlist[0] != '\0' && !mprog->fileprog )
      {
         fprintf( fp, "> %s %s~\n%s~\n", mprog_type_to_name( mprog->type ),
            mprog->arglist, strip_cr( mprog->comlist ) );
         count++;
      }
   }
   return count;
}

bool fold_area( AREA_DATA *tarea, char *filename, bool install )
{
   RESET_DATA *pReset, *tReset, *gReset;
   ROOM_INDEX_DATA *room;
   MOB_INDEX_DATA *pMobIndex;
   OBJ_INDEX_DATA *pObjIndex;
   MPROG_DATA *mprog;
   EXIT_DATA *xit;
   EXTRA_DESCR_DATA *ed;
   AFFECT_DATA *paf;
   NEIGHBOR_DATA *neigh;
   FILE *fp;
   char buf[MSL], newfilename[MSL], tempfilename[MSL];
   int val0, val1, val2, val3, val4, val5, vnum, stat;
   bool first;

   if( xIS_SET( tarea->flags, AFLAG_PROTOTYPE ) )
   {
      snprintf( newfilename, sizeof( newfilename ), "%s%s", BUILD_DIR, filename );
      snprintf( tempfilename, sizeof( buf ), "%s%s.temp", BUILD_DIR, filename );
   }
   else
   {
      snprintf( newfilename, sizeof( newfilename ), "%s%s", AREA_DIR, filename );
      snprintf( tempfilename, sizeof( buf ), "%s%s.temp", AREA_DIR, filename );
   }

   log_printf_plus( LOG_NORMAL, PERM_LEADER, "Saving %s...", newfilename );

   if( install )
   {
      xREMOVE_BIT( tarea->flags, AFLAG_PROTOTYPE );
      snprintf( newfilename, sizeof( newfilename ), "%s%s", AREA_DIR, filename );
   }
   if( !( fp = fopen( tempfilename, "w" ) ) )
   {
      bug( "%s: cant open %s for writing.", __FUNCTION__, newfilename );
      perror( newfilename );
      return false;
   }

   /* Save area info */
   if( tarea->name )
      fprintf( fp, "#AREA       %s~\n", tarea->name );
   fprintf( fp, "#VERSION    %d\n", AREA_VERSION_WRITE );
   if( tarea->author )
      fprintf( fp, "#AUTHOR     %s~\n", tarea->author );
   fprintf( fp, "#RANGES     %d %d %d %d\n", tarea->low_soft_range,
      tarea->hi_soft_range, tarea->low_hard_range, tarea->hi_hard_range );
   if( tarea->resetmsg )
      fprintf( fp, "#RESETMSG   %s~\n", tarea->resetmsg );
   if( tarea->reset_frequency )
      fprintf( fp, "#RESETFREQ  %d\n", tarea->reset_frequency );
   if( !xIS_EMPTY( tarea->flags ) )
      fprintf( fp, "#FLAGS      %s~\n", ext_flag_string( &tarea->flags, area_flags ) );
   fprintf( fp, "#CLIMATE    %d %d %d\n", tarea->weather->climate_temp,
      tarea->weather->climate_precip, tarea->weather->climate_wind );
   for( neigh = tarea->weather->first_neighbor; neigh; neigh = neigh->next )
      fprintf( fp, "#NEIGHBOR   %s~\n", neigh->name );

   /* save mobiles */
   first = true;
   for( vnum = tarea->low_vnum; vnum <= tarea->hi_vnum; vnum++ )
   {
      if( !( pMobIndex = get_mob_index( vnum ) ) )
         continue;
      if( first )
         fprintf( fp, "\n#MOBILES\n" );
      first = false;
      if( install )
         xREMOVE_BIT( pMobIndex->act, ACT_PROTOTYPE );
      fprintf( fp, "Vnum        %d\n", vnum );
      if( pMobIndex->level )
         fprintf( fp, "Level       %d\n", pMobIndex->level );
      if( pMobIndex->name )
         fprintf( fp, "Name        %s~\n", strip_cr( pMobIndex->name ) );
      if( pMobIndex->short_descr )
         fprintf( fp, "Short       %s~\n", strip_cr( pMobIndex->short_descr ) );
      if( pMobIndex->long_descr )
         fprintf( fp, "Long        %s~\n", strip_cr( pMobIndex->long_descr ) );
      if( pMobIndex->description )
         fprintf( fp, "Description\n %s~\n", strip_cr( pMobIndex->description ) );
      if( !xIS_EMPTY( pMobIndex->act ) )
         fprintf( fp, "Flags       %s~\n", ext_flag_string( &pMobIndex->act, act_flags ) );
      if( !xIS_EMPTY( pMobIndex->affected_by ) )
         fprintf( fp, "Affected    %s~\n", ext_flag_string( &pMobIndex->affected_by, a_flags ) );
      if( !xIS_EMPTY( pMobIndex->xflags ) )
         fprintf( fp, "Parts       %s~\n", ext_flag_string( &pMobIndex->xflags, part_flags ) );
      if( !xIS_EMPTY( pMobIndex->resistant ) )
         fprintf( fp, "Resistant   %s~\n", ext_flag_string( &pMobIndex->resistant, ris_flags ) );
      if( !xIS_EMPTY( pMobIndex->immune ) )
         fprintf( fp, "Immune      %s~\n", ext_flag_string( &pMobIndex->immune, ris_flags ) );
      if( !xIS_EMPTY( pMobIndex->susceptible ) )
         fprintf( fp, "Susceptible %s~\n", ext_flag_string( &pMobIndex->susceptible, ris_flags ) );
      if( !xIS_EMPTY( pMobIndex->attacks ) )
         fprintf( fp, "Attacks     %s~\n", ext_flag_string( &pMobIndex->attacks, attack_flags ) );
      if( !xIS_EMPTY( pMobIndex->defenses ) )
         fprintf( fp, "Defenses    %s~\n", ext_flag_string( &pMobIndex->defenses, defense_flags ) );
      if( pMobIndex->defposition )
         fprintf( fp, "DefPosition %s~\n", pos_names[pMobIndex->defposition] );
      if( pMobIndex->sex )
         fprintf( fp, "Sex         %s~\n", sex_names[pMobIndex->sex] );
      if( pMobIndex->alignment )
         fprintf( fp, "Alignment   %d\n", pMobIndex->alignment );
      fprintf( fp, "Hit         %d %d\n", pMobIndex->minhit, pMobIndex->maxhit );
      fprintf( fp, "Saves       %d %d %d %d %d\n", 
         pMobIndex->saving_poison_death, pMobIndex->saving_wand,
         pMobIndex->saving_para_petri, pMobIndex->saving_breath, pMobIndex->saving_spell_staff );
      if( !xIS_EMPTY( pMobIndex->speaks ) )
         fprintf( fp, "Speaks      %s~\n", ext_flag_string( &pMobIndex->speaks, lang_names ) );
      if( !xIS_EMPTY( pMobIndex->speaking ) )
         fprintf( fp, "Speaking    %s~\n", ext_flag_string( &pMobIndex->speaking, lang_names ) );

      fprintf( fp, "%s", "Stats      " );
      for( stat = 0; stat < STAT_MAX; stat++ )
         fprintf( fp, " %d", pMobIndex->perm_stats[stat] );
      fprintf( fp, "%s", "\n" );

      if( pMobIndex->ac )
         fprintf( fp, "Armor       %d\n", pMobIndex->ac );
      if( pMobIndex->mgold )
         fprintf( fp, "MGold       %d\n", pMobIndex->mgold );
      if( pMobIndex->gold )
         fprintf( fp, "Gold        %d\n", pMobIndex->gold );
      if( pMobIndex->height )
         fprintf( fp, "Height      %d\n", pMobIndex->height );
      if( pMobIndex->weight )
         fprintf( fp, "Weight      %d\n", pMobIndex->weight );
      if( pMobIndex->numattacks )
         fprintf( fp, "NumAttacks  %d\n", pMobIndex->numattacks );
      if( pMobIndex->hitroll )
         fprintf( fp, "HitRoll     %d\n", pMobIndex->hitroll );
      if( pMobIndex->damroll )
         fprintf( fp, "DamRoll     %d\n", pMobIndex->damroll );

      if( pMobIndex->spec_fun && pMobIndex->spec_funname )
         fprintf( fp, "Special     %s\n", pMobIndex->spec_funname );
      if( pMobIndex->pShop )
      {
         int stype;

         fprintf( fp, "NShop       %d %d %d %d ",
            pMobIndex->pShop->profit_buy,
            pMobIndex->pShop->profit_sell, pMobIndex->pShop->open_hour, pMobIndex->pShop->close_hour );
         for( stype = 0; stype < ITEM_TYPE_MAX; stype++ )
            if( pMobIndex->pShop->buy_type[stype] )
               fprintf( fp, " %s", o_types[stype] );
         fprintf( fp, "%s", "~\n" );
      }
      if( pMobIndex->rShop )
      {
         int stype;

         fprintf( fp, "NRepair     %d %d %d ",
            pMobIndex->rShop->profit_fix, pMobIndex->rShop->open_hour,
            pMobIndex->rShop->close_hour );
         for( stype = 0; stype < ITEM_TYPE_MAX; stype++ )
            if( pMobIndex->rShop->fix_type[stype] )
               fprintf( fp, " %s", o_types[stype] );
         fprintf( fp, "%s", "~\n" );
      }

      if( pMobIndex->mudprogs )
      {
         int count = 0;
         for( mprog = pMobIndex->mudprogs; mprog; mprog = mprog->next )
            count = save_programs( mprog, fp );
         if( count > 0 )
            fprintf( fp, "%s", "|\n" );
      }
      fprintf( fp, "End\n\n" );
   }
   if( !first )
      fprintf( fp, "#0\n\n\n" );

   /* save objects */
   first = true;
   for( vnum = tarea->low_vnum; vnum <= tarea->hi_vnum; vnum++ )
   {
      if( !( pObjIndex = get_obj_index( vnum ) ) )
         continue;
      if( first )
         fprintf( fp, "#OBJECTS\n" );
      first = false;
      if( install )
         xREMOVE_BIT( pObjIndex->extra_flags, ITEM_PROTOTYPE );
      fprintf( fp, "Vnum     %d\n", vnum );
      if( pObjIndex->level )
         fprintf( fp, "Level    %d\n", pObjIndex->level );
      fprintf( fp, "%s", "Stats   " );
      for( stat = 0; stat < STAT_MAX; stat++ )
         fprintf( fp, " %d", pObjIndex->stat_reqs[stat] );
      fprintf( fp, "%s", "\n" );
      if( pObjIndex->name )
         fprintf( fp, "Name     %s~\n", strip_cr( pObjIndex->name ) );
      if( pObjIndex->short_descr )
         fprintf( fp, "Short    %s~\n", strip_cr( pObjIndex->short_descr ) );
      if( pObjIndex->description )
         fprintf( fp, "Description\n%s~\n", strip_cr( pObjIndex->description ) );
      if( pObjIndex->action_desc )
         fprintf( fp, "Action   %s~\n", strip_cr( pObjIndex->action_desc ) );
      fprintf( fp, "Type     %s~\n", o_types[pObjIndex->item_type] );
      if( !xIS_EMPTY( pObjIndex->extra_flags ) )
         fprintf( fp, "Flags    %s~\n", ext_flag_string( &pObjIndex->extra_flags, o_flags ) );
      if( !xIS_EMPTY( pObjIndex->wear_flags ) )
         fprintf( fp, "Wear     %s~\n", ext_flag_string( &pObjIndex->wear_flags, w_flags ) );
      if( pObjIndex->layers )
         fprintf( fp, "Layers   %d\n", pObjIndex->layers );
      if( !xIS_EMPTY( pObjIndex->class_restrict ) )
         fprintf( fp, "Classes  %s~\n", ext_class_string( &pObjIndex->class_restrict ) );
      if( !xIS_EMPTY( pObjIndex->race_restrict ) )
         fprintf( fp, "Races    %s~\n", ext_race_string( &pObjIndex->race_restrict ) );

      val0 = pObjIndex->value[0];
      val1 = pObjIndex->value[1];
      val2 = pObjIndex->value[2];
      val3 = pObjIndex->value[3];
      val4 = pObjIndex->value[4];
      val5 = pObjIndex->value[5];
      switch( pObjIndex->item_type )
      {
         case ITEM_PILL:
         case ITEM_POTION:
         case ITEM_SCROLL:
            if( !is_valid_sn( val1 ) )
               val1 = HAS_SPELL_INDEX;
            if( !is_valid_sn( val2 ) )
               val2 = HAS_SPELL_INDEX;
            if( !is_valid_sn( val3 ) )
               val3 = HAS_SPELL_INDEX;
            break;

         case ITEM_STAFF:
         case ITEM_WAND:
            if( !is_valid_sn( val3 ) )
               val3 = HAS_SPELL_INDEX;
            break;

         case ITEM_SALVE:
            if( !is_valid_sn( val3 ) )
               val3 = HAS_SPELL_INDEX;
            if( !is_valid_sn( val4 ) )
               val4 = HAS_SPELL_INDEX;
            if( !is_valid_sn( val5 ) )
               val5 = HAS_SPELL_INDEX;
            break;
      }
      if( val0 )
         fprintf( fp, "Val0     %d\n", val0 );

      if( val1 )
      {
         fprintf( fp, "Val1     %d ", val1 );
         if( pObjIndex->item_type == ITEM_PILL || pObjIndex->item_type == ITEM_POTION
         || pObjIndex->item_type == ITEM_SCROLL )
            fprintf( fp, "'%s'", is_valid_sn( val1 ) ? skill_table[val1]->name : "NONE" );
         fprintf( fp, "%s", "\n" );
      }

      if( val2 )
      {
         fprintf( fp, "Val2     %d ", val2 );
         if( pObjIndex->item_type == ITEM_PILL || pObjIndex->item_type == ITEM_POTION
         || pObjIndex->item_type == ITEM_SCROLL )
            fprintf( fp, "'%s'", is_valid_sn( val2 ) ? skill_table[val2]->name : "NONE" );
         fprintf( fp, "%s", "\n" );
      }

      if( val3 )
      {
         fprintf( fp, "Val3     %d ", val3 );
         switch( pObjIndex->item_type )
         {
            case ITEM_PILL:
            case ITEM_POTION:
            case ITEM_SCROLL:
            case ITEM_STAFF:
            case ITEM_WAND:
            case ITEM_SALVE:
               fprintf( fp, "'%s'", is_valid_sn( val3 ) ? skill_table[val3]->name : "NONE" );
               break;
         }
         fprintf( fp, "%s", "\n" );
      }

      if( val4 )
      {
         fprintf( fp, "Val4     %d ", val4 );
         if( pObjIndex->item_type == ITEM_SALVE )
            fprintf( fp, "'%s'", is_valid_sn( val4 ) ? skill_table[val4]->name : "NONE" );
         fprintf( fp, "%s", "\n" );
      }

      if( val5 )
      {
         fprintf( fp, "Val5     %d ", val5 );
         if( pObjIndex->item_type == ITEM_SALVE )
            fprintf( fp, "'%s'", is_valid_sn( val5 ) ? skill_table[val5]->name : "NONE" );
         fprintf( fp, "%s", "\n" );
      }

      if( pObjIndex->weight )
         fprintf( fp, "Weight   %d\n", pObjIndex->weight );
      if( pObjIndex->cost )
         fprintf( fp, "Cost     %d\n", pObjIndex->cost );

      for( ed = pObjIndex->first_extradesc; ed; ed = ed->next )
         fprintf( fp, "E\n%s~\n%s~\n", ed->keyword, strip_cr( ed->description ) );

      for( paf = pObjIndex->first_affect; paf; paf = paf->next )
      {
         fprintf( fp, "%s", "Affect   " );
         if( paf->location >= 0 && paf->location < APPLY_MAX )
            fprintf( fp, "'%s'", a_types[paf->location] );
         else
            fprintf( fp, "'%d'", paf->location );
         if( paf->location == APPLY_EXT_AFFECT && paf->modifier >= 0 && paf->modifier < AFF_MAX )
            fprintf( fp, " '%s'", a_flags[paf->modifier] );
         else if( paf->location >= APPLY_RESISTANT && paf->location <= APPLY_SUSCEPTIBLE
         && paf->modifier >= 0 && paf->modifier < RIS_MAX )
            fprintf( fp, " '%s'", ris_flags[paf->modifier] );
         else if( ( paf->location == APPLY_WEAPONSPELL || paf->location == APPLY_WEARSPELL
         || paf->location == APPLY_REMOVESPELL || paf->location == APPLY_STRIPSN )
         && is_valid_sn( paf->modifier ) )
            fprintf( fp, " '%d'", skill_table[paf->modifier]->slot );
         else
            fprintf( fp, " '%d'", paf->modifier );
         fprintf( fp, "%s", "\n" );
      }

      if( pObjIndex->mudprogs )
      {
         int count = 0;
         for( mprog = pObjIndex->mudprogs; mprog; mprog = mprog->next )
            count = save_programs( mprog, fp );
         if( count > 0 )
            fprintf( fp, "%s", "|\n" );
      }
      fprintf( fp, "%s", "End\n\n" );
   }
   if( !first )
      fprintf( fp, "%s", "#0\n\n\n" );

   /* save rooms */
   first = true;
   for( vnum = tarea->low_vnum; vnum <= tarea->hi_vnum; vnum++ )
   {
      if( !( room = get_room_index( vnum ) ) )
         continue;
      if( first )
         fprintf( fp, "#ROOMS\n" );
      first = false;
      if( install )
      {
         CHAR_DATA *victim, *vnext;
         OBJ_DATA *obj, *obj_next;

         /* purge room of (prototyped) mobiles */
         for( victim = room->first_person; victim; victim = vnext )
         {
            vnext = victim->next_in_room;
            if( is_npc( victim ) && xIS_SET( victim->act, ACT_PROTOTYPE ) )
               extract_char( victim, true );
         }
         /* purge room of (prototyped) objects */
         for( obj = room->first_content; obj; obj = obj_next )
         {
            obj_next = obj->next_content;
            if( xIS_SET( obj->extra_flags, ITEM_PROTOTYPE ) )
               extract_obj( obj );
         }
      }
      fprintf( fp, "Vnum         %d\n", vnum );
      if( room->name )
         fprintf( fp, "Name         %s~\n", strip_cr( room->name ) );
      if( room->description )
         fprintf( fp, "Description  %s~\n", strip_cr( room->description ) );
      if( !xIS_EMPTY( room->room_flags ) )
         fprintf( fp, "Flags        %s~\n", ext_flag_string( &room->room_flags, r_flags ) );
      if( room->sector_type )
         fprintf( fp, "Sector       %s~\n", sect_flags[room->sector_type] );
      if( room->tele_delay )
         fprintf( fp, "Teledelay    %d\n", room->tele_delay );
      if( room->tele_vnum )
         fprintf( fp, "Televnum     %d\n", room->tele_vnum );
      if( room->tunnel )
         fprintf( fp, "Tunnel       %d\n", room->tunnel );
      for( xit = room->first_exit; xit; xit = xit->next )
      {
         bool bashed = false;

         if( xIS_SET( xit->exit_info, EX_PORTAL ) ) /* don't save portals */
            continue;
         if( xIS_SET( xit->exit_info, EX_MCREATED ) ) /* don't save mob created exits */
            continue;
         fprintf( fp, "Exit         %s\n", dir_name[xit->vdir] );
         if( xit->description && xit->description[0] != '\0' )
            fprintf( fp, "Description  %s~\n", strip_cr( xit->description ) );
         if( xit->keyword && xit->keyword[0] != '\0' )
            fprintf( fp, "Keyword      %s~\n", strip_cr( xit->keyword ) );

         if( xIS_SET( xit->exit_info, EX_BASHED ) )
            bashed = true;
         xREMOVE_BIT( xit->exit_info, EX_BASHED );
         if( !xIS_EMPTY( xit->exit_info ) )
            fprintf( fp, "Flags        %s~\n", ext_flag_string( &xit->exit_info, ex_flags ) );
         if( bashed )
            xSET_BIT( xit->exit_info, EX_BASHED );

         if( xit->key >= 0 )
            fprintf( fp, "Key          %d\n", xit->key );
         if( xit->vnum )
            fprintf( fp, "To           %d\n", xit->vnum );
         if( xit->pulltype )
            fprintf( fp, "Pulltype     %s~\n", pull_type_name( xit->pulltype ) );
         if( xit->pull )
            fprintf( fp, "Pull         %d\n", xit->pull );
         fprintf( fp, "%s", "End\n" );
      }

      for( pReset = room->first_reset; pReset; pReset = pReset->next )
      {
         switch( pReset->command ) /* extra arg1 arg2 arg3 */
         {
            default:
            case '*':
               break;
            case 'm':
            case 'M':
            case 'o':
            case 'O':
               fprintf( fp, "R %c %d %d %d %d %d\n", UPPER( pReset->command ),
                  pReset->extra, pReset->arg1, pReset->arg2, pReset->arg3, pReset->rchance );
               for( tReset = pReset->first_reset; tReset; tReset = tReset->next_reset )
               {
                  switch( tReset->command )
                  {
                     case 'p':
                     case 'P':
                     case 'e':
                     case 'E':
                        fprintf( fp, "  NR %c %d %d %d %d %d\n", UPPER( tReset->command ),
                           tReset->extra, tReset->arg1, tReset->arg2, tReset->arg3, tReset->rchance );
                        if( tReset->first_reset )
                        {
                           for( gReset = tReset->first_reset; gReset; gReset = gReset->next_reset )
                           {
                              if( gReset->command != 'p' && gReset->command != 'P' )
                                 continue;
                              fprintf( fp, "    NR %c %d %d %d %d %d\n", UPPER( gReset->command ),
                                 gReset->extra, gReset->arg1, gReset->arg2, gReset->arg3, gReset->rchance );
                           }
                        }
                        break;

                     case 'g':
                     case 'G':
                        fprintf( fp, "  NR %c %d %d %d %d\n", UPPER( tReset->command ),
                           tReset->extra, tReset->arg1, tReset->arg2, tReset->rchance );
                        if( tReset->first_reset )
                        {
                           for( gReset = tReset->first_reset; gReset; gReset = gReset->next_reset )
                           {
                              if( gReset->command != 'p' && gReset->command != 'P' )
                                 continue;
                              fprintf( fp, "    NR %c %d %d %d %d %d\n", UPPER( gReset->command ),
                                 gReset->extra, gReset->arg1, gReset->arg2, gReset->arg3, gReset->rchance );
                           }
                        }
                        break;

                     case 't':
                     case 'T':
                     case 'h':
                     case 'H':
                        fprintf( fp, "  NR %c %d %d %d %d %d\n", UPPER( tReset->command ),
                           tReset->extra, tReset->arg1, tReset->arg2, tReset->arg3, tReset->rchance );
                        break;
                  }
               }
               break;

            case 'd':
            case 'D':
            case 't':
            case 'T':
            case 'h':
            case 'H':
               fprintf( fp, "NR %c %d %d %d %d %d\n", UPPER( pReset->command ),
                  pReset->extra, pReset->arg1, pReset->arg2, pReset->arg3, pReset->rchance );
               break;

            case 'r':
            case 'R':
               fprintf( fp, "NR %c %d %d %d %d\n", UPPER( pReset->command ), pReset->extra, pReset->arg1,
                  pReset->arg2, pReset->rchance );
               break;
         }
      }

      for( ed = room->first_extradesc; ed; ed = ed->next )
         fprintf( fp, "E\n%s~\n%s~\n", ed->keyword, strip_cr( ed->description ) );

      if( room->mudprogs )
      {
         int count = 0;
         for( mprog = room->mudprogs; mprog; mprog = mprog->next )
            count = save_programs( mprog, fp );
         if( count > 0 )
            fprintf( fp, "%s", "|\n" );
      }
      fprintf( fp, "End\n\n" );
   }
   if( !first )
      fprintf( fp, "#0\n\n\n" );

   /* END */
   fprintf( fp, "#$\n" );
   fclose( fp );
   fp = NULL;
   rename( tempfilename, newfilename );
   return true;
}

CMDF( do_savearea )
{
   AREA_DATA *tarea;
   char filename[256];

   set_char_color( AT_IMMORT, ch );

   if( is_npc( ch ) || !ch->pcdata
   || ( ( !argument || argument[0] == '\0' ) && !ch->pcdata->area )
   || ( get_trust( ch ) < PERM_LEADER && !ch->pcdata->area ) )
   {
      send_to_char( "You don't have an assigned area to save.\r\n", ch );
      return;
   }

   if( !argument || argument[0] == '\0' || get_trust( ch ) < PERM_LEADER )
      tarea = ch->pcdata->area;
   else
   {
      bool found = false;

      if( get_trust( ch ) < PERM_LEADER )
      {
         send_to_char( "You can only save your own area.\r\n", ch );
         return;
      }
      for( tarea = first_build; tarea; tarea = tarea->next )
      {
         if( !str_cmp( tarea->filename, argument ) )
         {
            found = true;
            break;
         }
      }
      if( !found )
      {
         send_to_char( "Area not found.\r\n", ch );
         return;
      }
   }

   if( !tarea )
   {
      send_to_char( "No area to save.\r\n", ch );
      return;
   }

   /* Ensure not wiping out their area with save before load - Scryn 8/11 */
   if( !IS_SET( tarea->status, AREA_LOADED ) )
   {
      send_to_char( "Your area is not loaded!\r\n", ch );
      return;
   }

   if( !xIS_SET( tarea->flags, AFLAG_PROTOTYPE ) )
   {
      ch_printf( ch, "Can't savearea %s, use foldarea instead.\r\n", tarea->filename );
      return;
   }
   snprintf( filename, sizeof( filename ), "%s", tarea->filename );
   ch_printf( ch, "Saving area %s...\r\n", tarea->filename );
   fold_area( tarea, filename, false );
   set_char_color( AT_IMMORT, ch );
   send_to_char( "Finished saving the area.\r\n", ch );
}

/*
 * Dangerous command.  Can be used to install an area that was either:
 *   (a) already installed but removed from area.lst
 *   (b) designed offline
 * The mud will likely crash if:
 *   (a) this area is already loaded
 *   (b) it contains vnums that exist
 *   (c) the area has errors
 *
 * NOTE: Use of this command is not recommended.		-Thoric
 */
CMDF( do_unfoldarea )
{
   set_char_color( AT_IMMORT, ch );

   if( !argument || argument[0] == '\0' )
   {
      send_to_char( "Unfold what?\r\n", ch );
      return;
   }

   fBootDb = true;
   load_area_file( last_area, argument );
   fBootDb = false;
}

CMDF( do_foldarea )
{
   AREA_DATA *tarea;

   set_char_color( AT_IMMORT, ch );

   if( is_npc( ch ) || !ch->pcdata
   || ( ( !argument || argument[0] == '\0' ) && !ch->pcdata->area )
   || ( get_trust( ch ) < PERM_LEADER && !ch->pcdata->area ) )
   {
      send_to_char( "You don't have an assigned area to fold.\r\n", ch );
      return;
   }

   if( argument[0] == '\0' || get_trust( ch ) < PERM_LEADER )
      tarea = ch->pcdata->area;
   else
   {
      bool found = false;

      if( get_trust( ch ) < PERM_LEADER )
      {
         send_to_char( "You can only save your own area.\r\n", ch );
         return;
      }
      for( tarea = first_area; tarea; tarea = tarea->next )
      {
         if( !str_cmp( tarea->filename, argument ) )
         {
            found = true;
            break;
         }
      }
      if( !found )
      {
         send_to_char( "Area not found.\r\n", ch );
         return;
      }
   }

   if( !tarea )
   {
      send_to_char( "No area to fold.\r\n", ch );
      return;
   }

   if( xIS_SET( tarea->flags, AFLAG_PROTOTYPE ) )
   {
      ch_printf( ch, "Can't foldarea %s, use savearea instead.\r\n", tarea->filename );
      return;
   }

   send_to_char( "Folding area...\r\n", ch );
   fold_area( tarea, tarea->filename, false );
   set_char_color( AT_IMMORT, ch );
   send_to_char( "Done.\r\n", ch );
}

extern int top_area;

void write_area_list( void )
{
   AREA_DATA *tarea;
   FILE *fp;

   if( !( fp = fopen( AREA_LIST, "w" ) ) )
   {
      bug( "FATAL: can't open %s for writing!", AREA_LIST );
      return;
   }
   for( tarea = first_area; tarea; tarea = tarea->next )
      fprintf( fp, "%s\n", tarea->filename );
   fprintf( fp, "$\n" );
   fclose( fp );
   fp = NULL;
}

/*
 * A complicated to use command as it currently exists.		-Thoric
 * Once area->author and area->name are cleaned up... it will be easier
 */
CMDF( do_installarea )
{
   AREA_DATA *tarea;
   char arg[MIL], buf[MSL];
   int num;
   DESCRIPTOR_DATA *d;

   set_char_color( AT_IMMORT, ch );

   argument = one_argument( argument, arg );
   if( !arg || arg[0] == '\0' )
   {
      send_to_char( "Usage: installarea <filename> [Area title]\r\n", ch );
      return;
   }

   for( tarea = first_build; tarea; tarea = tarea->next )
   {
      if( !str_cmp( tarea->filename, arg ) )
      {
         if( argument && argument[0] != '\0' )
         {
            STRSET( tarea->name, argument );
         }

         /* Fold area with install flag -- auto-removes prototype flags */
         send_to_char( "Saving and installing file...\r\n", ch );
         if( !( fold_area( tarea, tarea->filename, true ) ) )
         {
           send_to_char( "There was a problem in folding the area...\r\n", ch );
           return;
         }

         /* Remove from prototype area list */
         UNLINK( tarea, first_build, last_build, next, prev );

         /* Add to real area list */
         LINK( tarea, first_area, last_area, next, prev );

         /* Remove it from the prototype sort list. BUGFIX: Samson 4-15-03 */
         UNLINK( tarea, first_bsort, last_bsort, next_sort, prev_sort );

         /* Sort the area into it's proper sort list. BUGFIX: Samson 4-15-03 */
         sort_area( tarea, false );

         /* Don't forget to update the list */
         sort_area_by_name( tarea );

         /* Fix up author if online */
         for( d = first_descriptor; d; d = d->next )
         {
            if( d->character && d->character->pcdata && d->character->pcdata->area == tarea )
            {
               /* remove area from author */
               d->character->pcdata->area = NULL;
               /* clear out author vnums */
               d->character->pcdata->range_lo = 0;
               d->character->pcdata->range_hi = 0;
               save_char_obj( d->character );
            }
         }
         top_area++;
         send_to_char( "Writing area.lst...\r\n", ch );
         write_area_list( );
         send_to_char( "Resetting new area.\r\n", ch );
         num = tarea->nplayer;
         tarea->nplayer = 0;
         reset_area( tarea );
         tarea->nplayer = num;
         send_to_char( "Renaming author's building file.\r\n", ch );
         snprintf( buf, sizeof( buf ), "%s%s.installed", BUILD_DIR, tarea->filename );
         snprintf( arg, sizeof( arg ), "%s%s", BUILD_DIR, tarea->filename );
         rename( arg, buf );
         send_to_char( "Done.\r\n", ch );
         return;
      }
   }
   send_to_char( "No such area exists.\r\n", ch );
}

CMDF( do_astat )
{
   AREA_DATA *tarea;
   bool proto = false, found = false;

   set_char_color( AT_PLAIN, ch );

   tarea = ch->in_room->area;

   if( argument && argument[0] != '\0' )
   {
      for( tarea = first_area; tarea; tarea = tarea->next )
      {
         if( !str_cmp( tarea->filename, argument ) )
         {
            found = true;
            break;
         }
      }
      if( !found )
      {
         for( tarea = first_build; tarea; tarea = tarea->next )
         {
            if( !str_cmp( tarea->filename, argument ) )
            {
               found = true;
               proto = true;
               break;
            }
         }
      }
      if( !found )
      {
         send_to_char( "Area not found.  Check 'zones'.\r\n", ch );
         return;
      }
   }

   ch_printf( ch, "\r\n&wName:      &W%s\r\n", tarea->name );
   ch_printf( ch, "&wFilename:  &W%-20s\r\n", tarea->filename );
   ch_printf( ch, "&wPrototype: &W%s\r\n", proto ? "yes" : "no" );
   ch_printf( ch, "&wAuthor:    &W%s\r\n", tarea->author );
   ch_printf( ch, "&wAge:       &W%-3d\r\n", tarea->age );
   ch_printf( ch, "&wPlayers:    &W%10d   &wMax: &W%d\r\n", tarea->nplayer, tarea->max_players );

   ch_printf( ch, "&wVnum range: &W%10d &w- &W%d\r\n", tarea->low_vnum, tarea->hi_vnum );
   ch_printf( ch, "&wSoft range: &W%10d &w- &W%d\r\n", tarea->low_soft_range, tarea->hi_soft_range );
   ch_printf( ch, "&wHard range: &W%10d &w- &W%d\r\n", tarea->low_hard_range, tarea->hi_hard_range );

   ch_printf( ch, "&wArea flags: &W%s\r\n", ext_flag_string( &tarea->flags, area_flags ) );
   ch_printf( ch, "&wResetmsg: &W%s\r\n", tarea->resetmsg ? tarea->resetmsg : "(default)" ); /* Rennard */
   ch_printf( ch, "&wReset frequency: &W%d &wminutes.\r\n", tarea->reset_frequency ? tarea->reset_frequency : 15 );
}

/* check other areas for a conflict while ignoring the current area */
bool check_for_area_conflicts( AREA_DATA *carea, int lo, int hi )
{
   AREA_DATA *area;

   for( area = first_area; area; area = area->next )
      if( area != carea && check_area_conflict( area, lo, hi ) )
         return true;
   for( area = first_build; area; area = area->next )
      if( area != carea && check_area_conflict( area, lo, hi ) )
         return true;

   return false;
}

void do_aset( CHAR_DATA *ch, char *argument )
{
   AREA_DATA *tarea;
   char arg1[MIL], arg2[MIL], arg3[MIL];
   bool proto, found;
   int vnum, value;

   set_char_color( AT_IMMORT, ch );

   argument = one_argument( argument, arg1 );
   argument = one_argument( argument, arg2 );
   vnum = atoi( argument );
   if( arg1[0] == '\0' || arg2[0] == '\0' )
   {
      send_to_char( "Usage: aset <area filename> <field> <value>\r\n", ch );
      send_to_char( "\r\nField being one of:\r\n", ch );
      send_to_char( "  low_vnum     hi_vnum     low_soft  hi_soft   low_hard   hi_hard\r\n", ch );
      send_to_char( "  name         filename    author    resetmsg  resetfreq  flags\r\n", ch );
      return;
   }

   found = false;
   proto = false;
   for( tarea = first_area; tarea; tarea = tarea->next )
   {
      if( !str_cmp( tarea->filename, arg1 ) )
      {
         found = true;
         break;
      }
   }
   if( !found )
   {
      for( tarea = first_build; tarea; tarea = tarea->next )
      {
         if( !str_cmp( tarea->filename, arg1 ) )
         {
            found = true;
            proto = true;
            break;
         }
      }
   }
   if( !found )
   {
      send_to_char( "Area not found.\r\n", ch );
      return;
   }

   if( !str_cmp( arg2, "name" ) )
   {
      AREA_DATA *uarea;

      if( !argument || argument[0] == '\0' )
      {
         send_to_char( "You can't set an area's name to nothing.\r\n", ch );
         return;
      }
      for( uarea = first_area; uarea; uarea = uarea->next )
      {
         if( !str_cmp( uarea->name, argument ) )
         {
            send_to_char( "There is already an installed area with that name.\r\n", ch );
            return;
         }
      }
      for( uarea = first_build; uarea; uarea = uarea->next )
      {
         if( !str_cmp( uarea->name, argument ) )
         {
            send_to_char( "There is already a prototype area with that name.\r\n", ch );
            return;
         }
      }
      STRSET( tarea->name, argument );
      send_to_char( "Done.\r\n", ch );
      return;
   }

   if( !str_cmp( arg2, "filename" ) )
   {
      char filename[256], newfilename[256];

      if( proto )
      {
         send_to_char( "You should only change the filename of installed areas.\r\n", ch );
         return;
      }
      if( !argument || argument[0] == '\0' )
      {
         send_to_char( "You can't set an area's filename to nothing.\r\n", ch );
         return;
      }
      if( strstr( argument, "." ) )
      {
         send_to_char( "You can't use a . in area filenames. (.are) is added onto the end automatically.\r\n", ch );
         return;
      }      
      snprintf( newfilename, sizeof( newfilename ), "%s.are", argument );
      if( !can_use_path( ch, AREA_DIR, newfilename ) )
         return;
      snprintf( filename, sizeof( filename ), "%s%s", AREA_DIR, tarea->filename );
      STRSET( tarea->filename, newfilename );
      snprintf( newfilename, sizeof( newfilename ), "%s%s", AREA_DIR, tarea->filename );
      rename( filename, newfilename );
      write_area_list( );
      send_to_char( "Done.\r\n", ch );
      return;
   }

   if( !str_cmp( arg2, "low_vnum" ) )
   {
      if( check_for_area_conflicts( tarea, tarea->low_vnum, vnum ) )
      {
         send_to_char( "That would conflict with another area.\r\n", ch );
         return;
      }
      if( tarea->hi_vnum < vnum )
      {
         send_to_char( "Can't set low_vnum higher than the hi_vnum.\r\n", ch );
         return;
      }
      tarea->low_vnum = vnum;
      ch_printf( ch, "Low_vnum set to %d.\r\n", tarea->low_vnum );
      return;
   }

   if( !str_cmp( arg2, "hi_vnum" ) )
   {
      if( check_for_area_conflicts( tarea, tarea->hi_vnum, vnum ) )
      {
         send_to_char( "That would conflict with another area.\r\n", ch );
         return;
      }
      if( tarea->low_vnum > vnum )
      {
         send_to_char( "Can't set hi_vnum lower than the low_vnum.\r\n", ch );
         return;
      }
      tarea->hi_vnum = vnum;
      ch_printf( ch, "Hi_vnum set to %d.\r\n", tarea->hi_vnum );
      return;
   }

   if( !str_cmp( arg2, "low_soft" ) )
   {
      tarea->low_soft_range = URANGE( 0, vnum, MAX_LEVEL );
      ch_printf( ch, "Low_soft set to level %d.\r\n", tarea->low_soft_range );
      return;
   }

   if( !str_cmp( arg2, "hi_soft" ) )
   {
      tarea->hi_soft_range = URANGE( 0, vnum, MAX_LEVEL );
      ch_printf( ch, "Hi_soft set to level %d.\r\n", tarea->hi_soft_range );
      return;
   }

   if( !str_cmp( arg2, "low_hard" ) )
   {
      tarea->low_hard_range = URANGE( 0, vnum, MAX_LEVEL );
      ch_printf( ch, "Low_hard set to level %d.\r\n", tarea->low_hard_range );
      return;
   }

   if( !str_cmp( arg2, "hi_hard" ) )
   {
      tarea->hi_hard_range = URANGE( 0, vnum, MAX_LEVEL );
      ch_printf( ch, "Hi_hard set to level %d.\r\n", tarea->hi_hard_range );
      return;
   }

   if( !str_cmp( arg2, "author" ) )
   {
      STRSET( tarea->author, argument );
      ch_printf( ch, "Author set to %s.\r\n", tarea->author ? tarea->author : "(Nothing)" );
      return;
   }

   if( !str_cmp( arg2, "resetmsg" ) )
   {
      STRSET( tarea->resetmsg, argument );
      ch_printf( ch, "Resetmsg set to %s.\r\n", tarea->resetmsg ? tarea->resetmsg : "(Nothing)" );
      return;
   }

   if( !str_cmp( arg2, "resetfreq" ) )
   {
      tarea->reset_frequency = UMAX( 0, vnum );
      ch_printf( ch, "Resetfreq set to %d.\r\n", tarea->reset_frequency );
      return;
   }

   if( !str_cmp( arg2, "flags" ) )
   {
      if( !argument || argument[0] == '\0' )
      {
         send_to_char( "Usage: aset <filename> flags <flag> [flag]...\r\n", ch );
         return;
      }
      while( argument[0] != '\0' )
      {
         argument = one_argument( argument, arg3 );
         value = get_flag( arg3, area_flags, AFLAG_MAX );
         if( value < 0 || value >= AFLAG_MAX )
            ch_printf( ch, "Unknown flag: %s\r\n", arg3 );
         else
            xTOGGLE_BIT( tarea->flags, value );
      }
      ch_printf( ch, "Flags set to %s.\r\n", ext_flag_string( &tarea->flags, area_flags ) );
      return;
   }

   do_aset( ch, "" );
}

/* List stuff in the range for which ever */
/*
 * 0 = rooms
 * 1 = objects
 * 2 = mobiles
 * 3 and higher does all three
 */
void do_arealist( CHAR_DATA *ch, short type, char *argument )
{
   ROOM_INDEX_DATA *room;
   OBJ_INDEX_DATA *obj;
   MOB_INDEX_DATA *mob;
   char arg1[MIL], arg2[MIL];
   AREA_DATA *tarea;
   int vnum, lrange, trange;
   bool free = false;

   set_pager_color( AT_PLAIN, ch );
   if( is_npc( ch ) || !ch->pcdata || ( !ch->pcdata->area && get_trust( ch ) < PERM_LEADER ) )
   {
      send_to_char( "&YYou don't have an assigned area.\r\n", ch );
      return;
   }

   tarea = ch->pcdata->area;
   if( !tarea && ch->in_room && ch->in_room->area )
      tarea = ch->in_room->area;

   argument = one_argument( argument, arg1 );
   if( !is_number( arg1 ) && !str_cmp( arg1, "free" ) )
   {
      free = true;
      argument = one_argument( argument, arg1 );
   }
   argument = one_argument( argument, arg2 );

   lrange = ( arg1 && arg1[0] != '\0' && is_number( arg1 ) ? atoi( arg1 ) : tarea ? tarea->low_vnum : -1 );
   trange = ( arg2 && arg2[0] != '\0' && is_number( arg2 ) ? atoi( arg2 ) : tarea ? tarea->hi_vnum : -1 );

   if( tarea && ( lrange < tarea->low_vnum || trange > tarea->hi_vnum ) && get_trust( ch ) < PERM_LEADER )
   {
      send_to_char( "&YThat is out of your vnum range.\r\n", ch );
      return;
   }

   if( lrange <= 0 && trange <= 0 )
   {
      send_to_char( "&YYou have to specify a low and high vnum and they have to be above 0.\r\n", ch );
      return;
   }
   if( trange <= lrange )
   {
      send_to_char( "&YThe first vnum should be lower then the second. EXAMPLE ( 400 500 ).\r\n", ch );
      return;
   }
   if( !tarea && ( trange - lrange ) > 1000 )
   {
      send_to_char( "&YLimiting the amount of stuff shown to 1000 possible vnums...\r\n", ch );
      trange = ( lrange + 1000 );
   }
   pager_printf( ch, "Displaying %svnums %d to %d.\r\n", free ? "free " : "", lrange, trange );
   for( vnum = lrange; vnum <= trange; vnum++ )
   {
      if( !free )
      {
         if( ( type == 0 || type > 2 ) && ( room = get_room_index( vnum ) ) )
            pager_printf( ch, "%s%5d) %s\r\n", type > 2 ? "ROOM    #" : "", vnum, room->name );
         if( ( type == 1 || type > 2 ) && ( obj = get_obj_index( vnum ) ) )
            pager_printf( ch, "%s%5d) %-20s (%s)\r\n", type > 2 ? "OBJECT  #" : "", vnum, obj->name, obj->short_descr );
         if( ( type == 2 || type > 2 ) && ( mob = get_mob_index( vnum ) ) )
            pager_printf( ch, "%s%5d) %-20s (%s)\r\n", type > 2 ? "MOBILE  #" : "", vnum, mob->name, mob->short_descr );
      }
      else
      {
         if( ( type == 0 || type > 2 ) && !( room = get_room_index( vnum ) ) )
            pager_printf( ch, "%s%5d)\r\n", type > 2 ? "ROOM    #" : "", vnum );
         if( ( type == 1 || type > 2 ) && !( obj = get_obj_index( vnum ) ) )
            pager_printf( ch, "%s%5d)\r\n", type > 2 ? "OBJECT  #" : "", vnum );
         if( ( type == 2 || type > 2 ) && !( mob = get_mob_index( vnum ) ) )
            pager_printf( ch, "%s%5d)\r\n", type > 2 ? "MOBILE  #" : "", vnum );
      }
   }
}

CMDF( do_rlist )
{
   do_arealist( ch, 0, argument );
}

CMDF( do_olist )
{
   do_arealist( ch, 1, argument );
}

CMDF( do_mlist )
{
   do_arealist( ch, 2, argument );
}

CMDF( do_vlist )
{
   do_arealist( ch, 3, argument );
}