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/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 *                  Game Reset Handler and Editing Module                   *
 *                         SmaugFUSS 1.8 Version                            *
 ****************************************************************************/

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

/* Externals */
extern int              top_reset;
int                     get_trapflag(char *flag);
extern bool             mud_down;

/*
 * Find some object with a given index data.
 * Used by area-reset 'P', 'T' and 'H' commands.
 */
OBJ_DATA               *get_obj_type(OBJ_INDEX_DATA *pObjIndex)
{
  OBJ_DATA               *obj;

  for(obj = first_object; obj; obj = obj->next)
  {
    if(obj->pIndexData == pObjIndex)
      return obj;
  }
  return NULL;
}

/* Find an object in a room so we can check it's dependents. Used by 'O' resets. */
OBJ_DATA               *get_obj_room(OBJ_INDEX_DATA *pObjIndex, ROOM_INDEX_DATA *pRoomIndex)
{
  OBJ_DATA               *obj;

  for(obj = pRoomIndex->first_content; obj; obj = obj->next_content)
  {
    if(obj->pIndexData == pObjIndex)
      return obj;
  }
  return NULL;
}

char                   *sprint_reset(RESET_DATA *pReset, short *num)
{
  RESET_DATA             *tReset, *gReset;
  static char             buf[MAX_STRING_LENGTH];
  char                    mobname[MAX_STRING_LENGTH], roomname[MAX_STRING_LENGTH], objname[MAX_STRING_LENGTH];
  static ROOM_INDEX_DATA *room;
  static OBJ_INDEX_DATA  *obj, *obj2;
  static MOB_INDEX_DATA  *mob;

  switch (pReset->command)
  {
    default:
      snprintf(buf, MAX_STRING_LENGTH, "%2d) *** BAD RESET: %c %d %d %d %d ***\r\n", *num, pReset->command, pReset->extra, pReset->arg1, pReset->arg2, pReset->arg3);
      break;

    case 'M':
      mob = get_mob_index(pReset->arg1);
      room = get_room_index(pReset->arg3);
      if(mob)
        strncpy(mobname, mob->player_name, MAX_STRING_LENGTH);
      else
        strncpy(mobname, "Mobile: *BAD VNUM*", MAX_STRING_LENGTH);
      if(room)
        strncpy(roomname, room->name, MAX_STRING_LENGTH);
      else
        strncpy(roomname, "Room: *BAD VNUM*", MAX_STRING_LENGTH);
      snprintf(buf, MAX_STRING_LENGTH, "%2d) %s (%d) -> %s Room: %d [%d]%s\r\n", *num, mobname, pReset->arg1, roomname, pReset->arg3, pReset->arg2, pReset->ch ? " [Reseted]" : "");

      for(tReset = pReset->first_reset; tReset; tReset = tReset->next_reset)
      {
        (*num)++;
        switch (tReset->command)
        {
          case 'E':
            if(!mob)
              strncpy(mobname, "* ERROR: NO MOBILE! *", MAX_STRING_LENGTH);
            if(!(obj = get_obj_index(tReset->arg1)))
              strncpy(objname, "Object: *BAD VNUM*", MAX_STRING_LENGTH);
            else
              strncpy(objname, obj->name, MAX_STRING_LENGTH);
            snprintf(buf + strlen(buf), MAX_STRING_LENGTH - strlen(buf),
                     "%2d) (equip) %s (%d) -> %s (%s) [%d]%s\r\n", *num, objname, tReset->arg1, mobname, wear_locs[tReset->arg3], tReset->arg2, tReset->obj ? " [Reseted]" : "");
            break;

          case 'G':
            if(!mob)
              strncpy(mobname, "* ERROR: NO MOBILE! *", MAX_STRING_LENGTH);
            if(!(obj = get_obj_index(tReset->arg1)))
              strncpy(objname, "Object: *BAD VNUM*", MAX_STRING_LENGTH);
            else
              strncpy(objname, obj->name, MAX_STRING_LENGTH);
            snprintf(buf + strlen(buf), MAX_STRING_LENGTH - strlen(buf), "%2d) (carry) %s (%d) -> %s [%d]%s\r\n", *num, objname, tReset->arg1, mobname, tReset->arg2, tReset->obj ? " [Reseted]" : "");
            break;
        }
        if(tReset->first_reset)
        {
          for(gReset = tReset->first_reset; gReset; gReset = gReset->next_reset)
          {
            (*num)++;
            switch (gReset->command)
            {
              case 'P':
                if(!(obj2 = get_obj_index(gReset->arg1)))
                  strncpy(objname, "Object1: *BAD VNUM*", MAX_STRING_LENGTH);
                else
                  strncpy(objname, obj2->name, MAX_STRING_LENGTH);
                if(gReset->arg3 > 0 && (obj = get_obj_index(gReset->arg3)) == NULL)
                  strncpy(roomname, "Object2: *BAD VNUM*", MAX_STRING_LENGTH);
                else if(!obj)
                  strncpy(roomname, "Object2: *NULL obj*", MAX_STRING_LENGTH);
                else
                  strncpy(roomname, obj->name, MAX_STRING_LENGTH);
                snprintf(buf + strlen(buf),
                         MAX_STRING_LENGTH - strlen(buf),
                         "%2d) (put) %s (%d) -> %s (%d) [%d]%s\r\n", *num, objname, gReset->arg1, roomname, obj ? obj->vnum : gReset->arg3, gReset->arg2, gReset->obj ? " [Reseted]" : "");
                break;
            }
          }
        }
      }
      break;

    case 'O':
      if(!(obj = get_obj_index(pReset->arg1)))
        strncpy(objname, "Object: *BAD VNUM*", MAX_STRING_LENGTH);
      else
        strncpy(objname, obj->name, MAX_STRING_LENGTH);
      room = get_room_index(pReset->arg3);
      if(!room)
        strncpy(roomname, "Room: *BAD VNUM*", MAX_STRING_LENGTH);
      else
        strncpy(roomname, room->name, MAX_STRING_LENGTH);
      snprintf(buf, MAX_STRING_LENGTH, "%2d) (object) %s (%d) -> %s Room: %d [%d]%s\r\n", *num, objname, pReset->arg1, roomname, pReset->arg3, pReset->arg2, pReset->obj ? " [Reseted]" : "");

      for(tReset = pReset->first_reset; tReset; tReset = tReset->next_reset)
      {
        (*num)++;
        switch (tReset->command)
        {
          case 'P':
            if(!(obj2 = get_obj_index(tReset->arg1)))
              strncpy(objname, "Object1: *BAD VNUM*", MAX_STRING_LENGTH);
            else
              strncpy(objname, obj2->name, MAX_STRING_LENGTH);
            if(tReset->arg3 > 0 && (obj = get_obj_index(tReset->arg3)) == NULL)
              strncpy(roomname, "Object2: *BAD VNUM*", MAX_STRING_LENGTH);
            else if(!obj)
              strncpy(roomname, "Object2: *NULL obj*", MAX_STRING_LENGTH);
            else
              strncpy(roomname, obj->name, MAX_STRING_LENGTH);
            snprintf(buf + strlen(buf), MAX_STRING_LENGTH - strlen(buf),
                     "%2d) (put) %s (%d) -> %s (%d) [%d]%s\r\n", *num, objname, tReset->arg1, roomname, obj ? obj->vnum : tReset->arg3, tReset->arg2, tReset->obj ? " [Reseted]" : "");
            break;

          case 'T':
            snprintf(buf + strlen(buf), MAX_STRING_LENGTH - strlen(buf),
                     "%2d) (trap) %d %d %d %d (%s) -> %s (%d)\r\n", *num,
                     tReset->extra, tReset->arg1, tReset->arg2, tReset->arg3, flag_string(tReset->extra, trap_flags), objname, obj ? obj->vnum : 0);
            break;

          case 'H':
            snprintf(buf + strlen(buf), MAX_STRING_LENGTH - strlen(buf), "%2d) (hide) -> %s\r\n", *num, objname);
            break;
        }
      }
      break;

    case 'D':
      if(pReset->arg2 < 0 || pReset->arg2 > MAX_DIR + 1)
        pReset->arg2 = 0;
      if(!(room = get_room_index(pReset->arg1)))
      {
        strncpy(roomname, "Room: *BAD VNUM*", MAX_STRING_LENGTH);
        snprintf(objname, MAX_STRING_LENGTH, "%s (no exit)", dir_name[pReset->arg2]);
      }
      else
      {
        strncpy(roomname, room->name, MAX_STRING_LENGTH);
        snprintf(objname, MAX_STRING_LENGTH, "%s%s", dir_name[pReset->arg2], get_exit(room, pReset->arg2) ? "" : " (NO EXIT!)");
      }
      switch (pReset->arg3)
      {
        default:
          strncpy(mobname, "(* ERROR *)", MAX_STRING_LENGTH);
          break;
        case 0:
          strncpy(mobname, "Open", MAX_STRING_LENGTH);
          break;
        case 1:
          strncpy(mobname, "Close", MAX_STRING_LENGTH);
          break;
        case 2:
          strncpy(mobname, "Close and lock", MAX_STRING_LENGTH);
          break;
        case 3:
          strncpy(mobname, "Dig (collapse)", MAX_STRING_LENGTH);
          break;
      }
      snprintf(buf, MAX_STRING_LENGTH, "%2d) %s [%d] the %s [%d] door %s (%d)\r\n", *num, mobname, pReset->arg3, objname, pReset->arg2, roomname, pReset->arg1);
      break;

    case 'R':
      if(!(room = get_room_index(pReset->arg1)))
        strncpy(roomname, "Room: *BAD VNUM*", MAX_STRING_LENGTH);
      else
        strncpy(roomname, room->name, MAX_STRING_LENGTH);
      snprintf(buf, MAX_STRING_LENGTH, "%2d) Randomize exits 0 to %d -> %s (%d)\r\n", *num, pReset->arg2, roomname, pReset->arg1);
      break;

    case 'T':
      if(!(room = get_room_index(pReset->arg3)))
        strncpy(roomname, "Room: *BAD VNUM*", MAX_STRING_LENGTH);
      else
        strncpy(roomname, room->name, MAX_STRING_LENGTH);
      snprintf(buf, MAX_STRING_LENGTH, "%2d) Trap: %d %d %d %d (%s) -> %s (%d)\r\n",
               *num, pReset->extra, pReset->arg1, pReset->arg2, pReset->arg3, flag_string(pReset->extra, trap_flags), roomname, room ? room->vnum : 0);
      break;
  }
  return buf;
}

/*
 * Create a new reset (for online building) - Thoric
 */
RESET_DATA             *make_reset(char letter, int extra, int arg1, int arg2, int arg3)
{
  RESET_DATA             *pReset;

  CREATE(pReset, RESET_DATA, 1);

  pReset->command = letter;
  pReset->extra = extra;
  pReset->arg1 = arg1;
  pReset->arg2 = arg2;
  pReset->arg3 = arg3;
  pReset->obj = NULL;
  pReset->ch = NULL;
  top_reset++;
  return pReset;
}

void add_obj_reset(ROOM_INDEX_DATA *room, char cm, OBJ_DATA *obj, int v2, int v3)
{
  RESET_DATA             *reset;
  OBJ_DATA               *inobj;
  static int              iNest;

  if((cm == 'O' || cm == 'P') && obj->pIndexData->vnum == OBJ_VNUM_TRAP)
  {
    if(cm == 'O')
    {
      reset = add_reset(room, 'T', obj->value[3], obj->value[1], obj->value[0], v3);
      if(reset)
      {
        obj->reset = reset;
        reset->obj = obj;
      }
    }
    return;
  }
  reset = add_reset(room, cm, (cm == 'P' ? iNest : 0), obj->pIndexData->vnum, v2, v3);
  if(reset)
  {
    obj->reset = reset;
    reset->obj = obj;
  }
  if(cm == 'O' && IS_OBJ_STAT(obj, ITEM_HIDDEN) && !CAN_WEAR(obj, ITEM_TAKE))
  {
    reset = add_reset(room, 'H', 1, 0, 0, 0);
    if(reset)
    {
      obj->reset = reset;
      reset->obj = obj;
    }
  }
  for(inobj = obj->first_content; inobj; inobj = inobj->next_content)
  {
    if(inobj->pIndexData->vnum == OBJ_VNUM_TRAP)
      add_obj_reset(room, 'O', inobj, 0, 0);
  }
  if(cm == 'P')
    iNest++;
  for(inobj = obj->first_content; inobj; inobj = inobj->next_content)
    add_obj_reset(room, 'P', inobj, inobj->count, obj->pIndexData->vnum);
  if(cm == 'P')
    iNest--;
  return;
}

void delete_reset(RESET_DATA *pReset)
{
  RESET_DATA             *tReset, *tReset_next;

  for(tReset = pReset->first_reset; tReset; tReset = tReset_next)
  {
    tReset_next = tReset->next_reset;

    UNLINK(tReset, pReset->first_reset, pReset->last_reset, next_reset, prev_reset);
    delete_reset(tReset);
  }
  if(pReset->ch)
    pReset->ch->reset = NULL;
  pReset->ch = NULL;
  if(pReset->obj)
    pReset->obj->reset = NULL;
  pReset->obj = NULL;
  pReset->first_reset = pReset->last_reset = NULL;
  DISPOSE(pReset);
  return;
}

void instaroom(ROOM_INDEX_DATA *pRoom, bool dodoors)
{
  CHAR_DATA              *rch;
  OBJ_DATA               *obj;
  RESET_DATA             *preset;

  for(rch = pRoom->first_person; rch; rch = rch->next_in_room)
  {
    if(!IS_NPC(rch))
      continue;

    preset = add_reset(pRoom, 'M', 1, rch->pIndexData->vnum, rch->pIndexData->count, pRoom->vnum);
    preset->obj = NULL;
    if(rch->reset)  /* Set the old ch reset ch to NULL so it can reset later */
      rch->reset->ch = NULL;
    preset->ch = rch;
    rch->reset = preset;

    for(obj = rch->first_carrying; obj; obj = obj->next_content)
    {
      if(obj->wear_loc == WEAR_NONE)
        add_obj_reset(pRoom, 'G', obj, 1, 0);
      else
        add_obj_reset(pRoom, 'E', obj, 1, obj->wear_loc);
    }
  }
  for(obj = pRoom->first_content; obj; obj = obj->next_content)
    add_obj_reset(pRoom, 'O', obj, obj->count, pRoom->vnum);
  if(dodoors)
  {
    EXIT_DATA              *pexit;

    for(pexit = pRoom->first_exit; pexit; pexit = pexit->next)
    {
      int                     state = 0;

/* Volk - updated this so we can reset dig/hidden exits */
      if(!IS_SET(pexit->exit_info, EX_ISDOOR) && !IS_SET(pexit->exit_info, EX_DIG))
        continue;

      if(IS_SET(pexit->exit_info, EX_CLOSED))
      {
        if(IS_SET(pexit->exit_info, EX_LOCKED))
          state = 2;
        else
          state = 1;
      }

      if(IS_SET(pexit->exit_info, EX_DIG))
        state = 3;

      add_reset(pRoom, 'D', 0, pRoom->vnum, pexit->vdir, state);
    }
  }
  return;
}

void wipe_resets(ROOM_INDEX_DATA *room)
{
  RESET_DATA             *pReset, *pReset_next;

  for(pReset = room->first_reset; pReset; pReset = pReset_next)
  {
    pReset_next = pReset->next;

    UNLINK(pReset, room->first_reset, room->last_reset, next, prev);
    delete_reset(pReset);
  }
  room->first_reset = room->last_reset = NULL;
  return;
}

void wipe_area_resets(AREA_DATA *area)
{
  ROOM_INDEX_DATA        *room;

  if(!mud_down)
  {
    for(room = area->first_room; room; room = room->next_aroom)
      wipe_resets(room);
  }
  return;
}

/* Function modified from original form - Samson */
void do_instaroom(CHAR_DATA *ch, char *argument)
{
  bool                    dodoors;

  if(IS_NPC(ch) || get_trust(ch) < LEVEL_IMMORTAL || !ch->pcdata->area)
  {
    send_to_char("You don't have an assigned area to create resets for.\r\n", ch);
    return;
  }

  if(!str_cmp(argument, "nodoors"))
    dodoors = FALSE;
  else
    dodoors = TRUE;

  if(!can_rmodify(ch, ch->in_room))
    return;
  if(ch->in_room->area != ch->pcdata->area && get_trust(ch) < LEVEL_AJ_SGT)
  {
    send_to_char("You cannot reset this room.\r\n", ch);
    return;
  }
  if(ch->in_room->first_reset)
    wipe_resets(ch->in_room);
  instaroom(ch->in_room, dodoors);
  send_to_char("Room resets installed.\r\n", ch);
}

/* Function modified from original form - Samson */
void do_instazone(CHAR_DATA *ch, char *argument)
{
  AREA_DATA              *pArea;
  ROOM_INDEX_DATA        *pRoom;
  bool                    dodoors;

  if(IS_NPC(ch) || get_trust(ch) < LEVEL_IMMORTAL || !ch->pcdata->area)
  {
    send_to_char("You don't have an assigned area to create resets for.\r\n", ch);
    return;
  }
  if(!str_cmp(argument, "nodoors"))
    dodoors = FALSE;
  else
    dodoors = TRUE;
  pArea = ch->pcdata->area;
  wipe_area_resets(pArea);
  for(pRoom = pArea->first_room; pRoom; pRoom = pRoom->next_aroom)
    instaroom(pRoom, dodoors);
  send_to_char("Area resets installed.\r\n", ch);
  return;
}

int generate_itemlevel(AREA_DATA *pArea, OBJ_INDEX_DATA *pObjIndex)
{
  int                     olevel;
  int                     min = UMAX(pArea->low_soft_range, 1);
  int                     max = UMIN(pArea->hi_soft_range, min + 15);

  if(pObjIndex->level > 0)
    olevel = UMIN(pObjIndex->level, MAX_LEVEL);
  else
    switch (pObjIndex->item_type)
    {
      default:
        olevel = 0;
        break;
      case ITEM_PILL:
        olevel = number_range(min, max);
        break;
      case ITEM_POTION:
        olevel = number_range(min, max);
        break;
      case ITEM_SCROLL:
        olevel = pObjIndex->value[0];
        break;
      case ITEM_WAND:
        olevel = number_range(min + 4, max + 1);
        break;
      case ITEM_STAFF:
        olevel = number_range(min + 9, max + 5);
        break;
      case ITEM_ARMOR:
        olevel = number_range(min + 4, max + 1);
        break;
      case ITEM_WEAPON:
        olevel = number_range(min + 4, max + 1);
        break;
    }
  return olevel;
}

/*
 * Count occurrences of an obj in a list.
 */
int count_obj_list(OBJ_INDEX_DATA *pObjIndex, OBJ_DATA *list)
{
  OBJ_DATA               *obj;
  int                     nMatch = 0;

  for(obj = list; obj; obj = obj->next_content)
  {
    if(obj->pIndexData == pObjIndex)
    {
      if(obj->count > 1)
        nMatch += obj->count;
      else
        nMatch++;
    }
  }
  return nMatch;
}

/*
 * Reset one room.
 */
void reset_room(ROOM_INDEX_DATA *room)
{
  RESET_DATA             *pReset, *tReset, *gReset;
  OBJ_DATA               *nestmap[MAX_NEST];
  CHAR_DATA              *mob;
  OBJ_DATA               *obj, *lastobj, *to_obj;
  ROOM_INDEX_DATA        *pRoomIndex = NULL;
  MOB_INDEX_DATA         *pMobIndex = NULL;
  OBJ_INDEX_DATA         *pObjIndex = NULL, *pObjToIndex;
  EXIT_DATA              *pexit;
  const char             *filename = room->area->filename;
  int                     level = 0, n, num = 0, lastnest;

  mob = NULL;
  obj = NULL;
  lastobj = NULL;
  if(!room->first_reset)
    return;
  level = 0;
  for(pReset = room->first_reset; pReset; pReset = pReset->next)
  {
    switch (pReset->command)
    {
      default:
        bug("%s: %s: bad command %c.", __FUNCTION__, filename, pReset->command);
        break;

      case 'M':
        if(!(pMobIndex = get_mob_index(pReset->arg1)))
        {
          bug("%s: %s: 'M': bad mob vnum %d.", __FUNCTION__, filename, pReset->arg1);
          continue;
        }
        if(!(pRoomIndex = get_room_index(pReset->arg3)))
        {
          bug("%s: %s: 'M': bad room vnum %d.", __FUNCTION__, filename, pReset->arg3);
          continue;
        }

        if(pReset->ch)
          mob = pReset->ch;
        else
        {
          mob = create_mobile(pMobIndex);

          if(IS_SET(pRoomIndex->room_flags, ROOM_PET_STOREROOM))
          {
            ROOM_INDEX_DATA        *pRoomPrev = get_room_index(pReset->arg3 - 1);

            if(pRoomPrev && IS_SET(pRoomPrev->room_flags, ROOM_PET_SHOP))
              xSET_BIT(mob->act, ACT_PET);
          }
          if(room_is_dark(pRoomIndex))
            xSET_BIT(mob->affected_by, AFF_INFRARED);
          char_to_room(mob, pRoomIndex);
        }

        mob->reset = pReset;
        pReset->ch = mob;

        level = URANGE(0, mob->level - 2, LEVEL_AVATAR);

        if(pReset->first_reset)
        {
          for(tReset = pReset->first_reset; tReset; tReset = tReset->next_reset)
          {
            switch (tReset->command)
            {
              case 'G':
              case 'E':
                if(!(pObjIndex = get_obj_index(tReset->arg1)))
                {
                  bug("%s: %s: 'E' or 'G': bad obj vnum %d.", __FUNCTION__, filename, tReset->arg1);
                  continue;
                }
                if(!mob)
                {
                  lastobj = NULL;
                  continue;
                }

                if(tReset->obj)
                  obj = tReset->obj;
                else
                {
                  /*
                   * If we are giving it to them (can be sold) then do the inventory else 
                   * just handle it normal 
                   */
                  if(tReset->command == 'G')
                  {
                    if(mob->pIndexData->pShop)
                    {
                      int                     olevel = generate_itemlevel(room->area, pObjIndex);

                      obj = create_object(pObjIndex, olevel);
                      xSET_BIT(obj->extra_flags, ITEM_INVENTORY);
                    }
                    else
                      obj = create_object(pObjIndex, number_fuzzy(level));
                  }
                  else
                    obj = create_object(pObjIndex, number_fuzzy(level));
                }

                if(!obj)
                {
                  bug("%s: object is NULL.", __FUNCTION__);
                  continue;
                }

                tReset->obj = obj;
                obj->reset = tReset;
                obj->level = URANGE(0, obj->level, LEVEL_AVATAR);

                if(!obj->carried_by)
                {
                  xSET_BIT(obj->extra_flags, ITEM_NOGROUP);
                  obj = obj_to_char(obj, mob);
                  if(obj)
                  {
                    tReset->obj = obj;
                    obj->reset = tReset;
                  }
                  if(tReset->command == 'E')
                  {
                    if(obj->carried_by != mob)
                    {
                      bug("'E' reset: can't give object %d to mob %d.", obj->pIndexData->vnum, mob->pIndexData->vnum);
                      continue;
                    }
                    equip_char(mob, obj, tReset->arg3);
                  }
                  xREMOVE_BIT(obj->extra_flags, ITEM_NOGROUP);
                }

                for(n = 0; n < MAX_NEST; n++)
                  nestmap[n] = NULL;
                nestmap[0] = obj;
                lastobj = nestmap[0];
                lastnest = 0;

                if(tReset->first_reset)
                {
                  for(gReset = tReset->first_reset; gReset; gReset = gReset->next_reset)
                  {
                    int                     iNest;

                    to_obj = lastobj;

                    switch (gReset->command)
                    {
                      case 'H':
                        if(!lastobj)
                          break;
                        xSET_BIT(lastobj->extra_flags, ITEM_HIDDEN);
                        break;

                      case 'P':
                        if(!(pObjIndex = get_obj_index(gReset->arg1)))
                        {
                          bug("%s: %s: 'P': bad obj vnum %d.", __FUNCTION__, filename, gReset->arg1);
                          continue;
                        }
                        iNest = gReset->extra;

                        if(!(pObjToIndex = get_obj_index(gReset->arg3)))
                        {
                          bug("%s: %s: 'P': bad objto vnum %d.", __FUNCTION__, filename, gReset->arg3);
                          continue;
                        }
                        if(iNest >= MAX_NEST)
                        {
                          bug("%s: %s: 'P': Exceeded nesting limit of %d", __FUNCTION__, filename, MAX_NEST);
                          obj = NULL;
                          break;
                        }
                        if(count_obj_list(pObjIndex, to_obj->first_content) > 0)
                        {
                          obj = NULL;
                          continue;
                        }

                        if(gReset->obj)
                          obj = gReset->obj;
                        else
                        {
                          if(iNest < lastnest)
                            to_obj = nestmap[iNest];
                          else if(iNest == lastnest)
                            to_obj = nestmap[lastnest];
                          else
                            to_obj = lastobj;

                          obj = create_object(pObjIndex, number_fuzzy(UMAX(generate_itemlevel(room->area, pObjIndex), to_obj->level)));
                          if(num > 1)
                            pObjIndex->count += (num - 1);
                          obj->count = gReset->arg2;
                          obj->level = UMIN(obj->level, LEVEL_AVATAR);
                          obj->count = gReset->arg2;
                          xSET_BIT(obj->extra_flags, ITEM_NOGROUP);
                          obj_to_obj(obj, to_obj);
                          xREMOVE_BIT(obj->extra_flags, ITEM_NOGROUP);
                          if(iNest > lastnest)
                          {
                            nestmap[iNest] = to_obj;
                            lastnest = iNest;
                          }
                        }
                        if(!obj)
                        {
                          bug("%s: object is NULL.", __FUNCTION__);
                          continue;
                        }
                        obj->reset = gReset;
                        gReset->obj = obj;
                        lastobj = obj;

                        /*
                         * Hackish fix for nested puts 
                         */
                        if(gReset->arg3 == OBJ_VNUM_MONEY_ONE)
                          gReset->arg3 = to_obj->pIndexData->vnum;
                        break;
                    }
                  }
                }
                break;
            }
          }
        }
        break;

      case 'O':
        if(!(pObjIndex = get_obj_index(pReset->arg1)))
        {
          bug("%s: %s: 'O': bad obj vnum %d.", __FUNCTION__, filename, pReset->arg1);
          continue;
        }
        if(!(pRoomIndex = get_room_index(pReset->arg3)))
        {
          bug("%s: %s: 'O': bad room vnum %d.", __FUNCTION__, filename, pReset->arg3);
          continue;
        }
        if(pReset->obj)
          obj = pReset->obj;
        else
        {
          if(count_obj_list(pObjIndex, pRoomIndex->first_content) < 1)
          {
            obj = create_object(pObjIndex, number_fuzzy(generate_itemlevel(room->area, pObjIndex)));
            if(num > 1)
              pObjIndex->count += (num - 1);
            obj->count = pReset->arg2;
            obj->level = UMIN(obj->level, LEVEL_AVATAR);
            obj->cost = 0;
            xSET_BIT(obj->extra_flags, ITEM_NOGROUP);
            obj_to_room(obj, pRoomIndex);
            xREMOVE_BIT(obj->extra_flags, ITEM_NOGROUP);
            obj->reset = pReset;
            pReset->obj = obj;
          }
          else
          {
            int                     x;

            if(!(obj = get_obj_room(pObjIndex, pRoomIndex)))
            {
              obj = NULL;
              lastobj = NULL;
              break;
            }
            obj->extra_flags = pObjIndex->extra_flags;
            for(x = 0; x < 6; ++x)
              obj->value[x] = pObjIndex->value[x];
          }
        }
        if(!obj)
        {
          bug("%s: object is NULL.", __FUNCTION__);
          continue;
        }

        for(n = 0; n < MAX_NEST; n++)
          nestmap[n] = NULL;
        nestmap[0] = obj;
        lastobj = nestmap[0];
        lastnest = 0;
        if(pReset->first_reset)
        {
          for(tReset = pReset->first_reset; tReset; tReset = tReset->next_reset)
          {
            int                     iNest;

            to_obj = lastobj;

            switch (tReset->command)
            {
              case 'H':
                if(!lastobj)
                  break;
                xSET_BIT(lastobj->extra_flags, ITEM_HIDDEN);
                break;

              case 'T':
                if(!IS_SET(tReset->extra, TRAP_OBJ))
                {
                  bug("%s: Room reset found on object reset list", __FUNCTION__);
                  break;
                }
                else
                {
                  /*
                   * We need to preserve obj for future 'T' checks 
                   */
                  OBJ_DATA               *pobj;

                  if(tReset->arg3 > 0)
                  {
                    if(!(pObjToIndex = get_obj_index(tReset->arg3)))
                    {
                      bug("%s: %s: 'T': bad objto vnum %d.", __FUNCTION__, filename, tReset->arg3);
                      continue;
                    }
                    if(room->area->nplayer > 0 || !(to_obj = get_obj_type(pObjToIndex)) || (to_obj->carried_by && !IS_NPC(to_obj->carried_by)) || is_trapped(to_obj))
                      break;
                  }
                  else
                  {
                    if(!lastobj || !obj)
                      break;
                    to_obj = obj;
                  }
                  pobj = make_trap(tReset->arg2, tReset->arg1, number_fuzzy(to_obj->level), tReset->extra);
                  xSET_BIT(pobj->extra_flags, ITEM_NOGROUP);
                  obj_to_obj(pobj, to_obj);
                  xREMOVE_BIT(pobj->extra_flags, ITEM_NOGROUP);
                }
                break;

              case 'P':
                if(!(pObjIndex = get_obj_index(tReset->arg1)))
                {
                  bug("%s: %s: 'P': bad obj vnum %d.", __FUNCTION__, filename, tReset->arg1);
                  continue;
                }
                iNest = tReset->extra;

                if(!(pObjToIndex = get_obj_index(tReset->arg3)))
                {
                  bug("%s: %s: 'P': bad objto vnum %d.", __FUNCTION__, filename, tReset->arg3);
                  continue;
                }

                if(iNest >= MAX_NEST)
                {
                  bug("%s: %s: 'P': Exceeded nesting limit of %d. Room %d.", __FUNCTION__, filename, MAX_NEST, room->vnum);
                  obj = NULL;
                  break;
                }

                if(count_obj_list(pObjIndex, to_obj->first_content) > 0)
                {
                  obj = NULL;
                  continue;
                }

                if(tReset->obj)
                  obj = tReset->obj;
                else
                {
                  if(iNest < lastnest)
                    to_obj = nestmap[iNest];
                  else if(iNest == lastnest)
                    to_obj = nestmap[lastnest];
                  else
                    to_obj = lastobj;

                  obj = create_object(pObjIndex, number_fuzzy(UMAX(generate_itemlevel(room->area, pObjIndex), to_obj->level)));
                  if(num > 1)
                    pObjIndex->count += (num - 1);
                  xSET_BIT(obj->extra_flags, ITEM_NOGROUP);
                  obj_to_obj(obj, to_obj);
                  xREMOVE_BIT(obj->extra_flags, ITEM_NOGROUP);
                  if(iNest > lastnest)
                  {
                    nestmap[iNest] = to_obj;
                    lastnest = iNest;
                  }
                }

                if(!obj)
                {
                  bug("%s: object is NULL.", __FUNCTION__);
                  continue;
                }

                obj->count = tReset->arg2;
                obj->level = UMIN(obj->level, LEVEL_AVATAR);
                obj->count = tReset->arg2;
                obj->reset = tReset;
                tReset->obj = obj;
                lastobj = obj;

                /*
                 * Hackish fix for nested puts 
                 */
                if(tReset->arg3 == OBJ_VNUM_MONEY_ONE)
                  tReset->arg3 = to_obj->pIndexData->vnum;
                break;
            }
          }
        }
        break;

      case 'T':
        if(IS_SET(pReset->extra, TRAP_OBJ))
        {
          bug("%s: Object trap found in room %d reset list", __FUNCTION__, room->vnum);
          break;
        }
        else
        {
          if(!(pRoomIndex = get_room_index(pReset->arg3)))
          {
            bug("%s: %s: 'T': bad room %d.", __FUNCTION__, filename, pReset->arg3);
            continue;
          }
          if(room->area->nplayer > 0 || count_obj_list(get_obj_index(OBJ_VNUM_TRAP), pRoomIndex->first_content) > 0)
            break;
          to_obj = make_trap(pReset->arg1, pReset->arg1, 10, pReset->extra);
          xSET_BIT(to_obj->extra_flags, ITEM_NOGROUP);
          obj_to_room(to_obj, pRoomIndex);
          xREMOVE_BIT(to_obj->extra_flags, ITEM_NOGROUP);
        }
        break;

      case 'D':
        if(!(pRoomIndex = get_room_index(pReset->arg1)))
        {
          bug("%s: %s: 'D': bad room vnum %d.", __FUNCTION__, filename, pReset->arg1);
          continue;
        }
        if(!(pexit = get_exit(pRoomIndex, pReset->arg2)))
          break;
        switch (pReset->arg3)
        {
          case 0:
            REMOVE_BIT(pexit->exit_info, EX_CLOSED);
            REMOVE_BIT(pexit->exit_info, EX_LOCKED);
            break;
          case 1:
            SET_BIT(pexit->exit_info, EX_CLOSED);
            REMOVE_BIT(pexit->exit_info, EX_LOCKED);
            if(IS_SET(pexit->exit_info, EX_xSEARCHABLE))
              SET_BIT(pexit->exit_info, EX_SECRET);
            break;
          case 2:
            SET_BIT(pexit->exit_info, EX_CLOSED);
            SET_BIT(pexit->exit_info, EX_LOCKED);
            if(IS_SET(pexit->exit_info, EX_xSEARCHABLE))
              SET_BIT(pexit->exit_info, EX_SECRET);
            break;
          case 3:
            SET_BIT(pexit->exit_info, EX_DIG);
            break;
        }
        break;

      case 'R':
        if(!(pRoomIndex = get_room_index(pReset->arg1)))
        {
          bug("%s: %s: 'R': bad room vnum %d.", __FUNCTION__, filename, pReset->arg1);
          continue;
        }
        randomize_exits(pRoomIndex, pReset->arg2);
        break;
    }
  }
}

void reset_area(AREA_DATA *area)
{
  ROOM_INDEX_DATA        *room;

  if(!area->first_room)
    return;

  for(room = area->first_room; room; room = room->next_aroom)
    reset_room(room);
}

/* Setup put nesting levels, regardless of whether or not the resets will
   actually reset, or if they're bugged. */
void renumber_put_resets(ROOM_INDEX_DATA *room)
{
  RESET_DATA             *pReset, *tReset, *lastobj = NULL;

  for(pReset = room->first_reset; pReset; pReset = pReset->next)
  {
    switch (pReset->command)
    {
      default:
        break;

      case 'O':
        lastobj = pReset;
        for(tReset = pReset->first_reset; tReset; tReset = tReset->next_reset)
        {
          switch (tReset->command)
          {
            case 'P':
              if(tReset->arg3 == 0)
              {
                if(!lastobj)
                  tReset->extra = 1000000;
                else if(lastobj->command != 'P' || lastobj->arg3 > 0)
                  tReset->extra = 0;
                else
                  tReset->extra = lastobj->extra + 1;
                lastobj = tReset;
              }
              break;
          }
        }
        break;
    }
  }
}

/*
 * Add a reset to an area -Thoric
 */
RESET_DATA             *add_reset(ROOM_INDEX_DATA *room, char letter, int extra, int arg1, int arg2, int arg3)
{
  RESET_DATA             *pReset;

  if(!room)
  {
    bug("%s: NULL room!", __FUNCTION__);
    return NULL;
  }

  letter = UPPER(letter);
  pReset = make_reset(letter, extra, arg1, arg2, arg3);

  switch (letter)
  {
    case 'M':
      room->last_mob_reset = pReset;
      break;

    case 'E':
    case 'G':
      if(!room->last_mob_reset)
      {
        bug("%s: Can't add '%c' reset to room: last_mob_reset is NULL.", __FUNCTION__, letter);
        return NULL;
      }
      room->last_obj_reset = pReset;
      LINK(pReset, room->last_mob_reset->first_reset, room->last_mob_reset->last_reset, next_reset, prev_reset);
      return pReset;

    case 'P':
      if(!room->last_obj_reset)
      {
        bug("%s: Can't add '%c' reset to room: last_obj_reset is NULL.", __FUNCTION__, letter);
        return NULL;
      }
      LINK(pReset, room->last_obj_reset->first_reset, room->last_obj_reset->last_reset, next_reset, prev_reset);
      return pReset;

    case 'O':
      room->last_obj_reset = pReset;
      break;

    case 'T':
      if(IS_SET(extra, TRAP_OBJ))
      {
        pReset->prev_reset = NULL;
        pReset->next_reset = room->last_obj_reset->first_reset;
        if(room->last_obj_reset->first_reset)
          room->last_obj_reset->first_reset->prev_reset = pReset;
        room->last_obj_reset->first_reset = pReset;
        if(!room->last_obj_reset->last_reset)
          room->last_obj_reset->last_reset = pReset;
        return pReset;
      }
      break;

    case 'H':
      pReset->prev_reset = NULL;
      pReset->next_reset = room->last_obj_reset->first_reset;
      if(room->last_obj_reset->first_reset)
        room->last_obj_reset->first_reset->prev_reset = pReset;
      room->last_obj_reset->first_reset = pReset;
      if(!room->last_obj_reset->last_reset)
        room->last_obj_reset->last_reset = pReset;
      return pReset;
  }
  LINK(pReset, room->first_reset, room->last_reset, next, prev);
  return pReset;
}

RESET_DATA             *find_oreset(ROOM_INDEX_DATA *room, char *oname)
{
  RESET_DATA             *pReset;
  OBJ_INDEX_DATA         *pobj;
  char                    arg[MAX_INPUT_LENGTH];
  int                     cnt = 0, num = number_argument(oname, arg);

  for(pReset = room->first_reset; pReset; pReset = pReset->next)
  {
    /*
     * Only going to allow traps/hides on room reset objects. Unless someone can come up with a better way to do this.
     */
    if(pReset->command != 'O')
      continue;

    if(!(pobj = get_obj_index(pReset->arg1)))
      continue;

    if(is_name(arg, pobj->name) && ++cnt == num)
      return pReset;
  }
  return NULL;
}

void do_reset(CHAR_DATA *ch, char *argument)
{
  char                    arg[MAX_INPUT_LENGTH];

  if(!argument || argument[0] == '\0')
  {
    send_to_char("Usage: reset area\r\n", ch);
    send_to_char("Usage: reset room\r\n", ch);
    send_to_char("Usage: reset rlist ( Room resets )\r\n", ch);
    send_to_char("Usage: reset list ( Area resets )\r\n", ch);
    send_to_char("Usage: reset random <direction>\r\n", ch);
    send_to_char("Usage: reset delete <number>\r\n", ch);
    send_to_char("Usage: reset hide <objname>\r\n", ch);
    send_to_char("Usage: reset trap room <type> <charges> [flags]\r\n", ch);
    send_to_char("Usage: reset trap obj <name> <type> <charges> [flags]\r\n", ch);
    return;
  }

  argument = one_argument(argument, arg);
  if(!str_cmp(arg, "area"))
  {
    reset_area(ch->in_room->area);
    send_to_char("Area has been reset.\r\n", ch);
    return;
  }

  if(!str_cmp(arg, "room"))
  {
    reset_room(ch->in_room);
    send_to_char("Room has been reset.\r\n", ch);
    return;
  }

  if(!str_cmp(arg, "rlist"))
  {
    RESET_DATA             *pReset;
    char                   *rbuf;
    short                   num;
    ROOM_INDEX_DATA        *room;
    bool                    found = FALSE;

    room = ch->in_room;
    num = 0;
    if(room->first_reset)
    {
      for(pReset = room->first_reset; pReset; pReset = pReset->next)
      {
        found = TRUE;
        if(++num == 1)
          ch_printf(ch, "Room:[%d]\r\n", room->vnum);
        if(!(rbuf = sprint_reset(pReset, &num)))
          continue;
        send_to_char(rbuf, ch);
      }
    }
    if(!found)
      send_to_char("The room you're in has no resets.\r\n", ch);
    return;
  }

  if(!str_cmp(arg, "list"))
  {
    RESET_DATA             *pReset;
    char                   *rbuf;
    short                   num;
    ROOM_INDEX_DATA        *room;
    bool                    found = FALSE;

    for(room = ch->in_room->area->first_room; room; room = room->next_aroom)
    {
      num = 0;
      if(!room->first_reset)
        continue;

      for(pReset = room->first_reset; pReset; pReset = pReset->next)
      {
        num++;
        found = TRUE;
        if(num == 1)
          ch_printf(ch, "Room:[%d]\r\n", room->vnum);
        if(!(rbuf = sprint_reset(pReset, &num)))
          continue;
        send_to_char(rbuf, ch);
      }
    }
    if(!found)
      send_to_char("The area you're in has no resets.\r\n", ch);
    return;
  }

  /*
   * Yeah, I know, this function is mucho ugly... but... 
   */
  if(!str_cmp(arg, "delete"))
  {
    RESET_DATA             *pReset, *tReset, *pReset_next, *tReset_next, *gReset, *gReset_next;
    int                     num, nfind = 0;

    if(!argument || argument[0] == '\0')
    {
      send_to_char("You must specify a reset # in this room to delete one.\r\n", ch);
      return;
    }

    if(!is_number(argument))
    {
      send_to_char("Specified reset must be designated by number. See &Wredit rlist&D.\r\n", ch);
      return;
    }
    num = atoi(argument);

    for(pReset = ch->in_room->first_reset; pReset; pReset = pReset_next)
    {
      pReset_next = pReset->next;

      nfind++;
      if(nfind == num)
      {
        UNLINK(pReset, ch->in_room->first_reset, ch->in_room->last_reset, next, prev);
        delete_reset(pReset);
        send_to_char("Reset deleted.\r\n", ch);
        return;
      }

      for(tReset = pReset->first_reset; tReset; tReset = tReset_next)
      {
        tReset_next = tReset->next_reset;

        nfind++;
        if(nfind == num)
        {
          UNLINK(tReset, pReset->first_reset, pReset->last_reset, next_reset, prev_reset);
          delete_reset(tReset);
          send_to_char("Reset deleted.\r\n", ch);
          return;
        }

        for(gReset = tReset->first_reset; gReset; gReset = gReset_next)
        {
          gReset_next = gReset->next_reset;

          nfind++;
          if(nfind == num)
          {
            UNLINK(gReset, tReset->first_reset, tReset->last_reset, next_reset, prev_reset);
            delete_reset(gReset);
            send_to_char("Reset deleted.\r\n", ch);
            return;
          }
        }
      }
    }
    send_to_char("No reset matching that number was found in this room.\r\n", ch);
    return;
  }

  if(!str_cmp(arg, "random"))
  {
    RESET_DATA             *pReset;
    int                     vnum;

    argument = one_argument(argument, arg);
    vnum = get_dir(arg);

    if(vnum < 0 || vnum > 9)
    {
      send_to_char("Reset which random doors?\r\n", ch);
      return;
    }

    if(vnum == 0)
    {
      send_to_char("There is no point in randomizing one door.\r\n", ch);
      return;
    }

    pReset = make_reset('R', 0, ch->in_room->vnum, vnum, 0);
    pReset->prev = NULL;
    pReset->next = ch->in_room->first_reset;
    if(ch->in_room->first_reset)
      ch->in_room->first_reset->prev = pReset;
    ch->in_room->first_reset = pReset;
    if(!ch->in_room->last_reset)
      ch->in_room->last_reset = pReset;
    send_to_char("Reset random doors created.\r\n", ch);
    return;
  }

  if(!str_cmp(arg, "trap"))
  {
    RESET_DATA             *pReset = NULL;
    RESET_DATA             *tReset = NULL;
    char                    oname[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
    int                     num, chrg, value, extra = 0, vnum;

    argument = one_argument(argument, arg2);

    if(!str_cmp(arg2, "room"))
    {
      vnum = ch->in_room->vnum;
      extra = TRAP_ROOM;

      argument = one_argument(argument, arg);
      num = is_number(arg) ? atoi(arg) : -1;
      argument = one_argument(argument, arg);
      chrg = is_number(arg) ? atoi(arg) : -1;
    }
    else if(!str_cmp(arg2, "obj"))
    {
      argument = one_argument(argument, oname);
      if(!(pReset = find_oreset(ch->in_room, oname)))
      {
        send_to_char("No matching reset found to set a trap on.\r\n", ch);
        return;
      }
      vnum = 0;
      extra = TRAP_OBJ;

      argument = one_argument(argument, arg);
      num = is_number(arg) ? atoi(arg) : -1;
      argument = one_argument(argument, arg);
      chrg = is_number(arg) ? atoi(arg) : -1;
    }
    else
    {
      send_to_char("Trap reset must be on 'room' or 'obj'\r\n", ch);
      return;
    }

    if(num < 1 || num > MAX_TRAPTYPE)
    {
      send_to_char("Invalid trap type.\r\n", ch);
      return;
    }

    if(chrg < 0 || chrg > 10000)
    {
      send_to_char("Invalid trap charges. Must be between 1 and 10000.\r\n", ch);
      return;
    }

    while(*argument)
    {
      argument = one_argument(argument, arg);
      value = get_trapflag(arg);
      if(value < 0 || value > 31)
      {
        ch_printf(ch, "Bad trap flag: %s\r\n", arg);
        continue;
      }
      SET_BIT(extra, 1 << value);
    }
    tReset = make_reset('T', extra, num, chrg, vnum);
    if(pReset)
    {
      tReset->prev_reset = NULL;
      tReset->next_reset = pReset->first_reset;
      if(pReset->first_reset)
        pReset->first_reset->prev_reset = tReset;
      pReset->first_reset = tReset;
      if(!pReset->last_reset)
        pReset->last_reset = tReset;
    }
    else
    {
      tReset->prev = NULL;
      tReset->next = ch->in_room->first_reset;
      if(ch->in_room->first_reset)
        ch->in_room->first_reset->prev = tReset;
      ch->in_room->first_reset = tReset;
      if(!ch->in_room->last_reset)
        ch->in_room->last_reset = tReset;
    }
    send_to_char("Trap created.\r\n", ch);
    return;
  }

  if(!str_cmp(arg, "hide"))
  {
    RESET_DATA             *pReset = NULL;
    RESET_DATA             *tReset = NULL;

    if(!(pReset = find_oreset(ch->in_room, argument)))
    {
      send_to_char("No such object to hide in this room.\r\n", ch);
      return;
    }
    tReset = make_reset('H', 1, 0, 0, 0);
    if(pReset)
    {
      tReset->prev_reset = NULL;
      tReset->next_reset = pReset->first_reset;
      if(pReset->first_reset)
        pReset->first_reset->prev_reset = tReset;
      pReset->first_reset = tReset;
      if(!pReset->last_reset)
        pReset->last_reset = tReset;
    }
    else
    {
      tReset->prev = NULL;
      tReset->next = ch->in_room->first_reset;
      if(ch->in_room->first_reset)
        ch->in_room->first_reset->prev = tReset;
      ch->in_room->first_reset = tReset;
      if(!ch->in_room->last_reset)
        ch->in_room->last_reset = tReset;
    }
    send_to_char("Hide reset created.\r\n", ch);
    return;
  }
  do_reset(ch, (char *)"");
  return;
}