6D/
6D/area/
6D/boards/
6D/city/
6D/color/
6D/corpses/
6D/councils/
6D/htowns/
6D/news/
6D/specials/
6D/src/specials/
6D/src/trades/
/*
 *  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 "h/mud.h"
#include "h/shops.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, const 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')
  {
    send_to_char("\r\nSyntax: renumber <area filename> <new vnum base> [flags]\r\n", ch);
    send_to_char("\r\nFlags: fillgaps verbose\r\n", ch);
    return;
  }
  area = find_area(arg1, &is_proto);
  if(area == NULL)
  {
    ch_printf(ch, "No such area '%s'.\r\n", 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?\r\n");
    return;
  }
  if(!is_number(arg1))
  {
    ch_printf(ch, "Sorry, '%s' is not a valid vnum base number!\r\n", 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'.\r\n", 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...\r\nSo what DO you wanna do?\r\n");
    return;
  }

  /*
   * some restrictions 
   */
  if(IS_NPC(ch))
  {
    ch_printf(ch, "Yeah, right.\r\n");
    return;
  }
  if(ch->level < LEVEL_IMMORTAL)
  {
    ch_printf(ch, "You don't have enough privileges.\r\n");
    return;
  }
  if(ch->level == LEVEL_IMMORTAL)
  {
    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').\r\n", area->filename);
      return;
    }
  }

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

  /*
   * one more restriction 
   */
  if(ch->level == LEVEL_IMMORTAL)
  {
    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.\r\n");
      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.\r\nWait till the area is finished to move it.\r\n");
      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.\r\n");
    if(r_area != NULL)
      DISPOSE(r_area);
    return;
  }

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

  /*
   * 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.\r\n", 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             *preset, *treset;
  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...\r\n");

  /*
   * 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\r\n", 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.\r\n");
        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...\r\n");
  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\r\n", 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\r\n", 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\r\n", 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.\r\n");
        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...\r\n");
  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\r\n", 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.\r\n");
        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...\r\n");

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

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

  pager_printf(ch, "... fixing resets...\r\n");
  for(room = area->first_room; room; room = room->next_aroom)
  {
    for(preset = room->first_reset; preset; preset = preset->next)
    {
      translate_reset(preset, r_area);
      for(treset = preset->first_reset; treset; treset = preset->next_reset)
        translate_reset(treset, r_area);
    }
  }

  if(verbose)
  {
    pager_printf(ch, "Searching progs for references to renumbered vnums...\r\n");
    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              *pexit, *rv_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(pexit = room->first_exit; pexit; pexit = pexit->next)
    {
      /*
       * translate the exit destination, if it was moved 
       */
      new_vnum = find_translation(pexit->vnum, r_area->r_room);
      if(new_vnum != NOT_FOUND)
        pexit->vnum = new_vnum;
      /*
       * if this room was moved 
       */
      if(pexit->rvnum != i)
      {
        old_vnum = pexit->rvnum;
        pexit->rvnum = i;
        /*
         * all reverse exits in other areas will be wrong 
         */
        rv_exit = get_exit_to(pexit->to_room, rev_dir[pexit->vdir], old_vnum);
        if(rv_exit && pexit->to_room->area != area)
        {
          if(rv_exit->vnum != i)
          {
            pager_printf(ch, "...    fixing reverse exit in area %s.\r\n", pexit->to_room->area->filename);
            rv_exit->vnum = i;
          }
        }
      }

      /*
       * translate the key 
       */
      if(pexit->key != -1)
      {
        new_vnum = find_translation(pexit->key, r_area->r_obj);
        if(new_vnum == NOT_FOUND)
          continue;
        pexit->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\r\n", i, obj->value[2], new_vnum);
        obj->value[2] = new_vnum;
      }
      else if(verbose)
        pager_printf(ch, "...    container %d; no need to fix.\r\n", 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)\r\n", 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)\r\n", 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, const 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.\r\n(Translation: Room %d, Obj %d, Mob %d)\r\n",
                     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 
   */
  const 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.\r\n");
      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 = (char *)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.\r\n");
          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.\r\n");
          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.\r\n", 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;
}