dbna/clans/
dbna/councils/
dbna/deity/
dbna/gods/
dbna/houses/
dbna/space/
/*
 *  Renumber Imm command
 *  Author: Cronel (cronel_kal@hotmail.com)
 *  of FrozenMUD (empire.digiunix.net 4000)
 *
 *  Permission to use and distribute this code is granted provided
 *  this header is retained and unaltered, and the distribution
 *  package contains all the original files unmodified.
 *  If you modify this code and use/distribute modified versions
 *  you must give credit to the original author(s).
 */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "mud.h"

#define NOT_FOUND (-1)
enum
{ REN_ROOM, REN_OBJ, REN_MOB };
struct renumber_data
{
  int old_vnum;
  int new_vnum;

  struct renumber_data *next;
};
typedef struct renumber_data RENUMBER_DATA;
struct renumber_area
{
  int low_obj, hi_obj;
  RENUMBER_DATA *r_obj;
  int low_mob, hi_mob;
  RENUMBER_DATA *r_mob;
  int low_room, hi_room;
  RENUMBER_DATA *r_room;
};
typedef struct renumber_area RENUMBER_AREA;

void renumber_area( CHAR_DATA * ch, AREA_DATA * area, RENUMBER_AREA * r_area, bool area_is_proto, bool verbose );

RENUMBER_AREA *gather_renumber_data( AREA_DATA * area, int new_base, bool fill_gaps );
RENUMBER_DATA *gather_one_list( short type, int low, int high, int new_base, bool fill_gaps, int *max_vnum );
void free_renumber_data( RENUMBER_DATA * r_data );

AREA_DATA *find_area( char *filename, bool * p_is_proto );
bool check_vnums( CHAR_DATA * ch, AREA_DATA * tarea, RENUMBER_AREA * r_area );

int find_translation( int vnum, RENUMBER_DATA * r_data );
void translate_reset( RESET_DATA * reset, RENUMBER_AREA * r_data );
void translate_objvals( CHAR_DATA * ch, AREA_DATA * area, RENUMBER_AREA * r_data, bool verbose );
void translate_exits( CHAR_DATA * ch, AREA_DATA * area, RENUMBER_AREA * r_area, bool verbose );
void warn_progs( CHAR_DATA * ch, int low, int high, AREA_DATA * area, RENUMBER_AREA * r_area );
void warn_in_prog( CHAR_DATA * ch, int low, int high, char *where, int vnum, MPROG_DATA * mprog, RENUMBER_AREA * r_area );

/* from db.c */
extern ROOM_INDEX_DATA *room_index_hash[MAX_KEY_HASH];
extern MOB_INDEX_DATA *mob_index_hash[MAX_KEY_HASH];
extern OBJ_INDEX_DATA *obj_index_hash[MAX_KEY_HASH];

void do_renumber( CHAR_DATA * ch, char *argument )
{
  RENUMBER_AREA *r_area;
  AREA_DATA *area;
  bool is_proto;
  char arg1[MAX_INPUT_LENGTH];
  int new_base;
  bool fill_gaps, verbose;

  /*
   * parse the first two parameters 
   */
  /*
   * first, area 
   */
  argument = one_argument( argument, arg1 );
  if( arg1[0] == '\0' )
  {
    ch_printf( ch, "What area do you want to renumber?\n\r" );
    return;
  }
  area = find_area( arg1, &is_proto );
  if( area == NULL )
  {
    ch_printf( ch, "No such area '%s'.\n\r", arg1 );
    return;
  }

  /*
   * and new vnum base 
   */
  argument = one_argument( argument, arg1 );
  if( arg1[0] == '\0' )
  {
    ch_printf( ch, "What will be the new vnum base for this area?\n\r" );
    return;
  }
  if( !is_number( arg1 ) )
  {
    ch_printf( ch, "Sorry, '%s' is not a valid vnum base number!\n\r", arg1 );
    return;
  }
  new_base = atoi( arg1 );

  /*
   * parse the flags 
   */
  fill_gaps = FALSE;
  verbose = FALSE;
  for( ;; )
  {
    argument = one_argument( argument, arg1 );
    if( arg1[0] == '\0' )
      break;
    else if( !str_prefix( arg1, "fillgaps" ) )
      fill_gaps = TRUE;
    else if( !str_prefix( arg1, "verbose" ) )
      verbose = TRUE;
    else
    {
      ch_printf( ch, "Invalid flag '%s'.\n\r", arg1 );
      return;
    }
  }

  /*
   * sanity check 
   */
  if( new_base == area->low_r_vnum && new_base == area->low_o_vnum && new_base == area->low_m_vnum && !fill_gaps )
  {
    ch_printf( ch,
               "You don't want to change the base vnum and you don't want to fill gaps...\n\rSo what DO you wanna do?\n\r" );
    return;
  }

  /*
   * some restrictions 
   */
  if( IS_NPC( ch ) )
  {
    ch_printf( ch, "Yeah, right.\n\r" );
    return;
  }
  if( ch->level < LEVEL_SAVIOR )
  {
    ch_printf( ch, "You don't have enough privileges.\n\r" );
    return;
  }
  if( ch->level == LEVEL_SAVIOR )
  {
    if( area->low_r_vnum < ch->pcdata->r_range_lo || area->hi_r_vnum > ch->pcdata->r_range_hi ||
        area->low_m_vnum < ch->pcdata->m_range_lo || area->hi_m_vnum > ch->pcdata->m_range_hi ||
        area->low_o_vnum < ch->pcdata->o_range_lo || area->hi_o_vnum > ch->pcdata->o_range_hi )
    {
      ch_printf( ch, "You can't renumber that area ('%s').\n\r", area->filename );
      return;
    }
  }

  /*
   * get the renumber data 
   */
  r_area = gather_renumber_data( area, new_base, fill_gaps );

  /*
   * one more restriction 
   */
  if( ch->level == LEVEL_SAVIOR )
  {
    if( r_area->low_room < ch->pcdata->r_range_lo || r_area->hi_room > ch->pcdata->r_range_hi ||
        r_area->low_obj < ch->pcdata->o_range_lo || r_area->hi_obj > ch->pcdata->o_range_hi ||
        r_area->low_mob < ch->pcdata->m_range_lo || r_area->hi_mob > ch->pcdata->m_range_hi )
    {
      ch_printf( ch, "The renumbered area would be outside your assigned vnum range.\n\r" );
      return;
    }
  }
  else if( is_proto )
  {
    if( r_area->low_room < area->low_r_vnum || r_area->hi_room > area->hi_r_vnum ||
        r_area->low_obj < area->low_o_vnum || r_area->hi_obj > area->hi_o_vnum ||
        r_area->low_mob < area->low_m_vnum || r_area->hi_mob > area->hi_m_vnum )
    {
      ch_printf( ch,
                 "Moving a proto area out of its range would create problems.\n\rWait till the area is finished to move it.\n\r" );
      return;
    }
  }

  /*
   * no overwriting of dest vnums 
   */
  if( check_vnums( ch, area, r_area ) )
    return;

  /*
   * another sanity check :) 
   */
  if( r_area == NULL || ( r_area->r_obj == NULL && r_area->r_mob == NULL && r_area->r_room == NULL ) )
  {
    ch_printf( ch, "No changes to make.\n\r" );
    if( r_area != NULL )
      DISPOSE( r_area );
    return;
  }

  /*
   * ok, do it! 
   */
  pager_printf( ch, "Renumbering area '%s' to new base %d, filling gaps: %s\n\r",
                area->filename, new_base, fill_gaps ? "yes" : "no" );
  renumber_area( ch, area, r_area, is_proto, verbose );
  pager_printf( ch, "Done.\n\r" );

  /*
   * clean up and goodbye 
   */
  if( r_area->r_room != NULL )
    free_renumber_data( r_area->r_room );
  if( r_area->r_obj != NULL )
    free_renumber_data( r_area->r_obj );
  if( r_area->r_mob != NULL )
    free_renumber_data( r_area->r_mob );
  DISPOSE( r_area );
}

bool check_vnums( CHAR_DATA * ch, AREA_DATA * tarea, RENUMBER_AREA * r_area )
{
  int high, low;
  AREA_DATA *area;
  bool proto;

  /*
   * this function assumes all the lows are allways gonna be
   * lower or equal to all the highs .. 
   */
  high = UMAX( r_area->hi_room, UMAX( r_area->hi_obj, r_area->hi_mob ) );
  low = UMIN( r_area->low_room, UMIN( r_area->low_obj, r_area->low_mob ) );

  /*
   * in do_check_vnums they use first_bsort, first_asort but.. i dunno.. 
   */
  area = first_area;
  proto = FALSE;
  while( area )
  {
    if( tarea == area )
      ;
    else if( !( high < area->low_r_vnum || low > area->hi_r_vnum ) ||
             !( high < area->low_o_vnum || low > area->hi_o_vnum ) || !( high < area->low_m_vnum || low > area->hi_m_vnum ) )
    {
      ch_printf( ch, "This operation would overwrite area %s! Use checkvnums first.\n\r", area->filename );
      return TRUE;
    }

    area = area->next;
    if( area == NULL && !proto )
    {
      area = first_build;
      proto = TRUE;
    }
  }
  return FALSE;
}

RENUMBER_AREA *gather_renumber_data( AREA_DATA * area, int new_base, bool fill_gaps )
/* this function actualy gathers all the renumber data for an area */
{
  RENUMBER_AREA *r_area;
  int max;

  CREATE( r_area, RENUMBER_AREA, 1 );

  r_area->r_mob = gather_one_list( REN_MOB, area->low_m_vnum, area->hi_m_vnum, new_base, fill_gaps, &max );
  r_area->low_mob = new_base;
  r_area->hi_mob = max;

  r_area->r_obj = gather_one_list( REN_OBJ, area->low_o_vnum, area->hi_o_vnum, new_base, fill_gaps, &max );
  r_area->low_obj = new_base;
  r_area->hi_obj = max;

  r_area->r_room = gather_one_list( REN_ROOM, area->low_r_vnum, area->hi_r_vnum, new_base, fill_gaps, &max );
  r_area->low_room = new_base;
  r_area->hi_room = max;

  return r_area;
}

RENUMBER_DATA *gather_one_list( short type, int low, int high, int new_base, bool fill_gaps, int *max_vnum )
/* this function builds a list of renumber data for a type (obj, room, or mob) */
{
  int cur_vnum;
  RENUMBER_DATA *r_data, root;
  bool found;
  ROOM_INDEX_DATA *room;
  OBJ_INDEX_DATA *obj;
  MOB_INDEX_DATA *mob;
  int i;
  int highest;

  memset( &root, 0, sizeof( RENUMBER_DATA ) );
  r_data = &root;

  cur_vnum = new_base;
  highest = -1;
  for( i = low; i <= high; i++ )
  {
    found = FALSE;
    switch ( type )
    {
      case REN_ROOM:
        room = get_room_index( i );
        if( room != NULL )
          found = TRUE;
        break;
      case REN_OBJ:
        obj = get_obj_index( i );
        if( obj != NULL )
          found = TRUE;
        break;
      case REN_MOB:
        mob = get_mob_index( i );
        if( mob != NULL )
          found = TRUE;
        break;
    }

    if( found )
    {
      if( cur_vnum > highest )
        highest = cur_vnum;
      if( cur_vnum != i )
      {
        CREATE( r_data->next, RENUMBER_DATA, 1 );
        r_data = r_data->next;
        r_data->old_vnum = i;
        r_data->new_vnum = cur_vnum;
      }
      cur_vnum++;
    }
    else if( !fill_gaps )
      cur_vnum++;
  }
  *max_vnum = highest;
  return root.next;
}

void free_renumber_data( RENUMBER_DATA * r_data )
/* disposes of a list of renumber data items */
{
  RENUMBER_DATA *r_next;

  while( r_data != NULL )
  {
    r_next = r_data->next;
    DISPOSE( r_data );
    r_data = r_next;
  }
}

void renumber_area( CHAR_DATA * ch, AREA_DATA * area, RENUMBER_AREA * r_area, bool area_is_proto, bool verbose )
/* this is the function that actualy does the renumbering of "area" according
   to the renumber data in "r_area". "ch" is to show messages. */
{
  RENUMBER_DATA *r_data;
  ROOM_INDEX_DATA *room, *room_prev, *room_list, *room_next;
  MOB_INDEX_DATA *mob, *mob_prev, *mob_list, *mob_next;
  OBJ_INDEX_DATA *obj, *obj_prev, *obj_list, *obj_next;
  RESET_DATA *reset;
  int iHash;
  int low, high;

  high = UMAX( area->hi_r_vnum, UMIN( area->hi_o_vnum, area->hi_m_vnum ) );
  low = UMIN( area->low_r_vnum, UMIN( area->low_o_vnum, area->low_m_vnum ) );

  pager_printf( ch, "(Room) Renumbering...\n\r" );

  /*
   * what we do here is, for each list (room/obj/mob) first we
   * * take each element out of the hash array, change the vnum,
   * * and move it to our own list. after everything's moved out
   * * we put it in again. this is to avoid problems in situations
   * * where where room A is being moved to position B, but theres
   * * already a room B wich is also being moved to position C.
   * * a straightforward approach would result in us moving A to
   * * position B first, and then again to position C, and room
   * * B being lost inside the hash array, still there, but not
   * * foundable (its "covered" by A because they'd have the same 
   * * vnum). 
   */

  room_list = NULL;
  for( r_data = r_area->r_room; r_data; r_data = r_data->next )
  {
    if( verbose )
      pager_printf( ch, "(Room) %d -> %d\n\r", r_data->old_vnum, r_data->new_vnum );

    room = get_room_index( r_data->old_vnum );
    if( !room )
    {
      bug( "renumber_area: NULL room %d", r_data->old_vnum );
      continue;
    }

    /*
     * remove it from the hash list 
     */
    iHash = r_data->old_vnum % MAX_KEY_HASH;
    if( room_index_hash[iHash] == room )
      room_index_hash[iHash] = room->next;
    else
    {
      for( room_prev = room_index_hash[iHash]; room_prev && room_prev->next != room; room_prev = room_prev->next )
        ;
      if( room_prev == NULL )
      {
        bug( "renumber_area: Couldn't find a room in the hash table! Skipping it.\n\r" );
        continue;
      }
      room_prev->next = room->next;
      room->next = NULL;
    }

    /*
     * change the vnum 
     */
    room->vnum = r_data->new_vnum;

    /*
     * move it to the temporary list 
     */
    room->next = room_list;
    room_list = room;
  }
  /*
   * now move everything back into the hash array 
   */
  for( room = room_list; room; room = room_next )
  {
    room_next = room->next;
    /*
     * add it to the hash list again (new position) 
     */
    iHash = room->vnum % MAX_KEY_HASH;
    room->next = room_index_hash[iHash];
    room_index_hash[iHash] = room;
  }
  /*
   * if nothing was moved, or if the area is proto, dont change this 
   */
  if( r_area->r_room != NULL && !area_is_proto )
  {
    area->low_r_vnum = r_area->low_room;
    area->hi_r_vnum = r_area->hi_room;
  }

  pager_printf( ch, "(Mobs) Renumbering...\n\r" );
  mob_list = NULL;
  for( r_data = r_area->r_mob; r_data; r_data = r_data->next )
  {
    if( verbose )
      pager_printf( ch, "(Mobs) %d -> %d\n\r", r_data->old_vnum, r_data->new_vnum );

    mob = get_mob_index( r_data->old_vnum );
    if( !mob )
    {
      bug( "renumber_area: NULL mob %d", r_data->old_vnum );
      continue;
    }

    /*
     * fix references to this mob from shops while renumbering this mob 
     */
    if( mob->pShop )
    {
      if( verbose )
        pager_printf( ch, "(Mobs) Fixing shop for mob %d -> %d\n\r", r_data->old_vnum, r_data->new_vnum );
      mob->pShop->keeper = r_data->new_vnum;
    }
    if( mob->rShop )
    {
      if( verbose )
        pager_printf( ch, "(Mobs) Fixing repair shop for mob %d -> %d\n\r", r_data->old_vnum, r_data->new_vnum );
      mob->rShop->keeper = r_data->new_vnum;
    }

    /*
     * remove it from the hash list 
     */
    iHash = r_data->old_vnum % MAX_KEY_HASH;
    if( mob_index_hash[iHash] == mob )
      mob_index_hash[iHash] = mob->next;
    else
    {
      for( mob_prev = mob_index_hash[iHash]; mob_prev && mob_prev->next != mob; mob_prev = mob_prev->next )
        ;
      if( mob_prev == NULL )
      {
        bug( "renumber_area: Couldn't find a mob in the hash table! Skipping it.\n\r" );
        continue;
      }
      mob_prev->next = mob->next;
      mob->next = NULL;
    }

    /*
     * change the vnum 
     */
    mob->vnum = r_data->new_vnum;

    /*
     * move to private list 
     */
    mob->next = mob_list;
    mob_list = mob;
  }
  for( mob = mob_list; mob; mob = mob_next )
  {
    mob_next = mob->next;
    /*
     * add it to the hash list again 
     */
    iHash = mob->vnum % MAX_KEY_HASH;
    mob->next = mob_index_hash[iHash];
    mob_index_hash[iHash] = mob;
  }
  if( r_area->r_mob && !area_is_proto )
  {
    area->low_m_vnum = r_area->low_mob;
    area->hi_m_vnum = r_area->hi_mob;
  }

  pager_printf( ch, "(Objs) Renumbering...\n\r" );
  obj_list = NULL;
  for( r_data = r_area->r_obj; r_data; r_data = r_data->next )
  {
    if( verbose )
      pager_printf( ch, "(Objs) %d -> %d\n\r", r_data->old_vnum, r_data->new_vnum );
    obj = get_obj_index( r_data->old_vnum );
    if( !obj )
    {
      bug( "renumber_area: NULL obj %d", r_data->old_vnum );
      continue;
    }

    /*
     * remove it from the hash list 
     */
    iHash = r_data->old_vnum % MAX_KEY_HASH;
    if( obj_index_hash[iHash] == obj )
      obj_index_hash[iHash] = obj->next;
    else
    {
      for( obj_prev = obj_index_hash[iHash]; obj_prev && obj_prev->next != obj; obj_prev = obj_prev->next )
        ;
      if( obj_prev == NULL )
      {
        bug( "renumber_area: Couldn't find an obj in the hash table! Skipping it.\n\r" );
        continue;
      }
      obj_prev->next = obj->next;
      obj->next = NULL;
    }

    /*
     * change the vnum 
     */
    obj->vnum = r_data->new_vnum;

    /*
     * to our list 
     */
    obj->next = obj_list;
    obj_list = obj;
  }
  for( obj = obj_list; obj; obj = obj_next )
  {
    obj_next = obj->next;
    /*
     * add it to the hash list again 
     */
    iHash = obj->vnum % MAX_KEY_HASH;
    obj->next = obj_index_hash[iHash];
    obj_index_hash[iHash] = obj;
  }
  if( r_area->r_obj && !area_is_proto )
  {
    area->low_o_vnum = r_area->low_obj;
    area->hi_o_vnum = r_area->hi_obj;
  }

  pager_printf( ch, "Fixing references...\n\r" );

  pager_printf( ch, "... fixing objvals...\n\r" );
  translate_objvals( ch, area, r_area, verbose );

  pager_printf( ch, "... fixing exits...\n\r" );
  translate_exits( ch, area, r_area, verbose );

  pager_printf( ch, "... fixing resets...\n\r" );
  for( reset = area->first_reset; reset; reset = reset->next )
    translate_reset( reset, r_area );

  if( verbose )
  {
    pager_printf( ch, "Searching progs for references to renumbered vnums...\n\r" );
    warn_progs( ch, low, high, area, r_area );
  }
}

void translate_exits( CHAR_DATA * ch, AREA_DATA * area, RENUMBER_AREA * r_area, bool verbose )
{
  int i, new_vnum;
  EXIT_DATA *exit, *rev_exit;
  ROOM_INDEX_DATA *room;
  int old_vnum;

  for( i = area->low_r_vnum; i <= area->hi_r_vnum; i++ )
  {
    room = get_room_index( i );
    if( !room )
      continue;
    for( exit = room->first_exit; exit; exit = exit->next )
    {
      /*
       * translate the exit destination, if it was moved 
       */
      new_vnum = find_translation( exit->vnum, r_area->r_room );
      if( new_vnum != NOT_FOUND )
        exit->vnum = new_vnum;
      /*
       * if this room was moved 
       */
      if( exit->rvnum != i )
      {
        old_vnum = exit->rvnum;
        exit->rvnum = i;
        /*
         * all reverse exits in other areas will be wrong 
         */
        rev_exit = get_exit_to( exit->to_room, rev_dir[exit->vdir], old_vnum );
        if( rev_exit && exit->to_room->area != area )
        {
          if( rev_exit->vnum != i )
          {
            pager_printf( ch, "...    fixing reverse exit in area %s.\n\r", exit->to_room->area->filename );
            rev_exit->vnum = i;
          }
        }
      }

      /*
       * translate the key 
       */
      if( exit->key != -1 )
      {
        new_vnum = find_translation( exit->key, r_area->r_obj );
        if( new_vnum == NOT_FOUND )
          continue;
        exit->key = new_vnum;
      }
    }
  }
}

void translate_objvals( CHAR_DATA * ch, AREA_DATA * area, RENUMBER_AREA * r_area, bool verbose )
{
  int i, new_vnum;
  OBJ_INDEX_DATA *obj;

  for( i = area->low_o_vnum; i <= area->hi_o_vnum; i++ )
  {
    obj = get_obj_index( i );
    if( !obj )
      continue;

    if( obj->item_type == ITEM_CONTAINER )
    {
      new_vnum = find_translation( obj->value[2], r_area->r_obj );
      if( new_vnum != NOT_FOUND )
      {
        if( verbose )
          pager_printf( ch, "...    container %d; fixing objval2 (key vnum) %d -> %d\n\r", i, obj->value[2], new_vnum );
        obj->value[2] = new_vnum;
      }
      else if( verbose )
        pager_printf( ch, "...    container %d; no need to fix.\n\r", i );
    }
    else if( obj->item_type == ITEM_SWITCH || obj->item_type == ITEM_LEVER ||
             obj->item_type == ITEM_PULLCHAIN || obj->item_type == ITEM_BUTTON )
    {
      /*
       * levers might have room vnum references in their objvals 
       */
      if( IS_SET( obj->value[0], TRIG_TELEPORT )
          || IS_SET( obj->value[0], TRIG_TELEPORTALL )
          || IS_SET( obj->value[0], TRIG_TELEPORTPLUS )
          || IS_SET( obj->value[0], TRIG_RAND4 )
          || IS_SET( obj->value[0], TRIG_RAND6 ) || IS_SET( obj->value[0], TRIG_DOOR ) )
      {
        new_vnum = find_translation( obj->value[1], r_area->r_room );
        if( new_vnum != NOT_FOUND )
        {
          if( verbose )
            pager_printf( ch, "...    lever %d: fixing source room (%d -> %d)\n\r", i, obj->value[1], new_vnum );
          obj->value[1] = new_vnum;
        }
        if( IS_SET( obj->value[0], TRIG_DOOR ) && IS_SET( obj->value[0], TRIG_PASSAGE ) )
        {
          new_vnum = find_translation( obj->value[2], r_area->r_room );
          if( new_vnum != NOT_FOUND )
          {
            if( verbose )
              pager_printf( ch, "...    lever %d: fixing dest room (passage) (%d -> %d)\n\r", i, obj->value[2], new_vnum );
            obj->value[2] = new_vnum;
          }
        }
      }
    }
  }
}

void warn_progs( CHAR_DATA * ch, int low, int high, AREA_DATA * area, RENUMBER_AREA * r_area )
{
  ROOM_INDEX_DATA *room;
  OBJ_INDEX_DATA *obj;
  MOB_INDEX_DATA *mob;
  MPROG_DATA *mprog;
  int i;

  for( i = area->low_r_vnum; i <= area->hi_r_vnum; i++ )
  {
    room = get_room_index( i );
    if( !room )
      continue;
    mprog = room->mudprogs;
    while( mprog )
    {
      warn_in_prog( ch, low, high, "room", i, mprog, r_area );
      mprog = mprog->next;
    }
  }

  for( i = area->low_o_vnum; i <= area->hi_o_vnum; i++ )
  {
    obj = get_obj_index( i );
    if( !obj )
      continue;
    mprog = obj->mudprogs;
    while( mprog )
    {
      warn_in_prog( ch, low, high, "obj", i, mprog, r_area );
      mprog = mprog->next;
    }
  }

  for( i = area->low_m_vnum; i <= area->hi_m_vnum; i++ )
  {
    mob = get_mob_index( i );
    if( !mob )
      continue;
    mprog = mob->mudprogs;
    while( mprog )
    {
      warn_in_prog( ch, low, high, "mob", i, mprog, r_area );
      mprog = mprog->next;
    }
  }
}



void warn_in_prog( CHAR_DATA * ch, int low, int high, char *where, int vnum, MPROG_DATA * mprog, RENUMBER_AREA * r_area )
{
  char *p, *start_number, cTmp;
  int num;

  p = mprog->comlist;
  while( *p )
  {
    if( isdigit( *p ) )
    {
      start_number = p;
      while( isdigit( *p ) && *p )
        p++;
      cTmp = *p;
      *p = 0;
      num = atoi( start_number );
      *p = cTmp;
      if( num >= low && num <= high )
      {
        pager_printf( ch,
                      "Warning! %s prog in %s vnum %d might contain a reference to %d.\n\r(Translation: Room %d, Obj %d, Mob %d)\n\r",
                      mprog_type_to_name( mprog->type ), where, vnum, num, find_translation( num, r_area->r_room ),
                      find_translation( num, r_area->r_obj ), find_translation( num, r_area->r_mob ) );
      }
      if( *p == '\0' )
        break;
    }
    p++;
  }
}


void translate_reset( RESET_DATA * reset, RENUMBER_AREA * r_data )
/* this function translates a reset according to the renumber data in r_data */
{
  /*
   * a list based approach to fixing the resets. instead
   * of having a bunch of several instances of very 
   * similar code, i just made this array that tells the
   * code what to do. it's pretty straightforward 
   */
  char *action_table[] = { "Mm1r3", "Oo1r3", "Ho1", "Po1o3",
    "Go1", "Eo1", "Dr1", "Rr1", NULL
  };
  char *p;
  RENUMBER_DATA *r_table;
  int *parg, new_vnum, i;

  /*
   * T is a special case 
   */
  if( reset->command == 'T' )
  {
    if( IS_SET( reset->extra, TRAP_ROOM ) )
      r_table = r_data->r_room;
    else if( IS_SET( reset->extra, TRAP_OBJ ) )
      r_table = r_data->r_obj;
    else
    {
      bug( "translate_reset: Invalid 'T' reset found.\n\r" );
      return;
    }
    new_vnum = find_translation( reset->arg3, r_table );
    if( new_vnum != NOT_FOUND )
      reset->arg3 = new_vnum;
    return;
  }

  /*
   * B is another special case 
   */
  if( reset->command == 'B' )
  {
    bug( "translate_reset: B command found." );
    if( ( reset->arg2 & BIT_RESET_TYPE_MASK ) == BIT_RESET_DOOR || ( reset->arg2 & BIT_RESET_TYPE_MASK ) == BIT_RESET_ROOM )
    {
      new_vnum = find_translation( reset->arg1, r_data->r_obj );
      if( new_vnum != NOT_FOUND )
        reset->arg1 = new_vnum;
    }
    return;
  }

  for( i = 0; action_table[i] != NULL; i++ )
  {
    if( reset->command == action_table[i][0] )
    {
      p = action_table[i] + 1;
      while( *p )
      {
        if( *p == 'm' )
          r_table = r_data->r_mob;
        else if( *p == 'o' )
          r_table = r_data->r_obj;
        else if( *p == 'r' )
          r_table = r_data->r_room;
        else
        {
          bug( "translate_reset: Invalid action found in action table.\n\r" );
          p += 2;
          continue;
        }
        p++;

        if( *p == '1' )
          parg = &( reset->arg1 );
        else if( *p == '2' )
          parg = &( reset->arg2 );
        else if( *p == '3' )
          parg = &( reset->arg3 );
        else
        {
          bug( "translate_reset: Invalid argument number found in action table.\n\r" );
          p++;
          continue;
        }
        p++;

        new_vnum = find_translation( *parg, r_table );
        if( new_vnum != NOT_FOUND )
          *parg = new_vnum;

      }
      return;
    }
  }

  if( action_table[i] == NULL )
    bug( "translate_reset: Invalid reset '%c' found.\n\r", reset->command );
}

int find_translation( int vnum, RENUMBER_DATA * r_data )
/* returns the new vnum for the old vnum "vnum" according to the info in
 * r_data 
 */
{
  RENUMBER_DATA *r_temp;

  for( r_temp = r_data; r_temp; r_temp = r_temp->next )
  {
    if( r_temp->old_vnum == vnum )
      return r_temp->new_vnum;
  }
  return NOT_FOUND;
}


AREA_DATA *find_area( char *filename, bool * p_is_proto )
/* simply returns a pointer to a "filename" or NULL if no such area. stores
   TRUE in *p_is_proto if the area is proto */
{
  bool found;
  AREA_DATA *area;

  found = FALSE;

  for( area = first_area; area; area = area->next )
  {
    if( !str_cmp( area->filename, filename ) )
    {
      found = TRUE;
      break;
    }
  }

  if( found )
  {
    *p_is_proto = FALSE;
    return area;
  }

  for( area = first_build; area; area = area->next )
  {
    if( !str_cmp( area->filename, filename ) )
    {
      found = TRUE;
      break;
    }
  }

  if( found )
  {
    *p_is_proto = TRUE;
    return area;
  }
  else
    return NULL;
}