1stMud/CVS/
1stMud/area/CVS/
1stMud/backup/CVS/
1stMud/bin/
1stMud/bin/CVS/
1stMud/bin/extras/
1stMud/bin/extras/CVS/
1stMud/data/CVS/
1stMud/data/i3/CVS/
1stMud/doc/1stMud/
1stMud/doc/1stMud/CVS/
1stMud/doc/CVS/
1stMud/doc/Diku/
1stMud/doc/Diku/CVS/
1stMud/doc/MPDocs/CVS/
1stMud/doc/Merc/CVS/
1stMud/doc/Rom/
1stMud/doc/Rom/CVS/
1stMud/log/CVS/
1stMud/notes/
1stMud/notes/CVS/
1stMud/player/CVS/
1stMud/player/backup/CVS/
1stMud/player/deleted/CVS/
1stMud/src/CVS/
1stMud/src/config/CVS/
1stMud/src/h/CVS/
1stMud/src/o/CVS/
1stMud/win/CVS/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*  Much time and thought has gone into this software and you are          *
*  benefitting.  We hope that you share your changes too.  What goes      *
*  around, comes around.                                                  *
*  This code was freely distributed with the The Isles 1.1 source code,   *
*  and has been used here for OLC - OLC would not be what it is without   *
*  all the previous coders who released their source code.                *
***************************************************************************
*          1stMud ROM Derivative (c) 2001-2004 by Markanth                *
*            http://www.firstmud.com/  <markanth@firstmud.com>            *
*         By using this code you have agreed to follow the term of        *
*             the 1stMud license in ../doc/1stMud/LICENSE                 *
***************************************************************************/



#include "merc.h"
#include "tables.h"
#include "olc.h"
#include "interp.h"
#include "recycle.h"
#include "data_table.h"

#define ED_TABLE(a, b, c, d, e, f, g) {a, b, c, &e##_zero, do_##d, e##_data_table, \
                                        d##_create, d##_delete, d##_list, rw_##e##_data, \
                                        &e##_zero.f, g}
#define ED_LIST(a, b, c, d, e, f, g) {a, b, c, &e##_zero, do_##d, e##_data_table, \
                                        d##_create, d##_delete, d##_list, NULL, &e##_zero.f, g}
#define ED_BASIC(a, b, c, d, e, f, g) {a, b, c, &e##_zero, do_##d, e##_data_table, NULL, NULL, NULL, rw_##e##_data, &e##_zero.f, g}

OlcTable olc_ed_table[ED_MAX] = {
  ED_LIST ("AEdit", "area", ED_AREA, aedit, area, vnum, FIELD_VNUM),
  ED_LIST ("REdit", "room", ED_ROOM, redit, room_index, vnum, FIELD_VNUM),
  ED_LIST ("OEdit", "object", ED_OBJECT, oedit, obj_index, vnum,
	   FIELD_VNUM),
  ED_LIST ("MEdit", "mobile", ED_MOBILE, medit, char_index, vnum,
	   FIELD_VNUM),
  ED_LIST ("HEdit", "help", ED_HELP, hedit, help, keyword, FIELD_STRING),
  ED_LIST ("MPEdit", "mob-program", ED_MPCODE, mpedit, mprog, vnum,
	   FIELD_VNUM),
  ED_LIST ("OPEdit", "obj-program", ED_OPCODE, opedit, oprog, vnum,
	   FIELD_VNUM),
  ED_LIST ("RPEdit", "room-program", ED_RPCODE, rpedit, rprog, vnum,
	   FIELD_VNUM),
  ED_TABLE ("CEdit", "clan", ED_CLAN, cedit, clan, name, FIELD_STRING),
  ED_TABLE ("RAEdit", "race", ED_RACE, raedit, race, name, FIELD_STRING),
  ED_TABLE ("SEdit", "social", ED_SOCIAL, sedit, social, name,
	    FIELD_STRING),
  ED_TABLE ("SKEdit", "skill", ED_SKILL, skedit, skill, name,
	    FIELD_STRING),
  ED_TABLE ("GREdit", "group", ED_GROUP, gredit, group, name,
	    FIELD_STRING),
  ED_TABLE ("DEdit", "deity", ED_DEITY, dedit, deity, name, FIELD_STRING),
  ED_BASIC ("MudEdit", "mud", ED_Mud, mudedit, mud, name, FIELD_STRING),
  ED_TABLE ("CmdEdit", "command", ED_CMD, cmdedit, cmd, name,
	    FIELD_STRING),
  ED_TABLE ("ClEdit", "class", ED_CLASS, cledit, class, name,
	    FIELD_STRING),
  ED_TABLE ("ChanEdit", "channel", ED_CHAN, chanedit, channel, name,
	    FIELD_STRING),
  ED_TABLE ("SongEdit", "song", ED_SONG, songedit, song, name,
	    FIELD_STRING),
};

OlcTable *
olc_lookup (ed_t ed)
{
  int i;

  if (ed == ED_NONE)
    return NULL;

  for (i = 0; i < ED_MAX; i++)
    if (olc_ed_table[i].ed == ed)
      return &olc_ed_table[i];

  return NULL;
}

bool
olc_show (CharData * ch, OlcTable * ed)
{
  Buffer *output;

  if (!ch->desc || !ch->desc->pEdit || !ed->table || ch->desc->pString)
    return false;

  output = new_buf ();
  bprintln (output, stringf (ch, 0, Center, "=",
			     "[ %s : %s ]", ed->name,
			     olc_ed_vnum (ch->desc)));
  show_struct (ch, output, ed->type_zero, ed->table, ch->desc->pEdit, 0);
  bprintln (output, draw_line (ch, "=", 0));
  sendpage (ch, buf_string (output));
  free_buf (output);
  return true;
}

Olc_Fun (olced_show)
{
  OlcTable *ed;

  if (!ch->desc || ch->desc->editor == ED_NONE
      || (ed = olc_lookup (ch->desc->editor)) == NULL)
    return false;

  return olc_show (ch, ed);
}

Olc_Fun (olced_create)
{
  OlcTable *ed;

  if (!ch->desc || ch->desc->editor == ED_NONE
      || (ed = olc_lookup (ch->desc->editor)) == NULL || !ed->create_fun)
    return false;

  return (*ed->create_fun) (n_fun, ch, argument);
}

Olc_Fun (olced_delete)
{
  OlcTable *ed;

  if (!ch->desc || ch->desc->editor == ED_NONE
      || (ed = olc_lookup (ch->desc->editor)) == NULL || !ed->delete_fun)
    return false;

  return (*ed->delete_fun) (n_fun, ch, argument);
}

Olc_Fun (olced_list)
{
  OlcTable *ed;

  if (!ch->desc || ch->desc->editor == ED_NONE
      || (ed = olc_lookup (ch->desc->editor)) == NULL || !ed->list_fun)
    return false;

  return (*ed->list_fun) (n_fun, ch, argument);
}


AreaData *
get_olc_area (Descriptor * d)
{
  if (d->editor == ED_NONE || d->pEdit == NULL)
    return NULL;

  switch (d->editor)
    {
    case ED_AREA:
      return (AreaData *) d->pEdit;
    case ED_ROOM:
      return ((RoomIndex *) d->pEdit)->area;
    case ED_OBJECT:
      return ((ObjIndex *) d->pEdit)->area;
    case ED_MOBILE:
      return ((CharIndex *) d->pEdit)->area;
    case ED_MPCODE:
    case ED_OPCODE:
    case ED_RPCODE:
      return ((ProgCode *) d->pEdit)->area;
    default:
      return NULL;
    }
}

void
olcedit (CharData * ch, const char *argument, OlcTable * table)
{
  AreaData *pArea;

  pArea = get_olc_area (ch->desc);

  if (pArea && !IsBuilder (ch, pArea))
    {
      chprintlnf (ch, "%s:  Insufficient security to modify %s.",
		  table->name, table->longname);
      edit_done (ch);
      return;
    }

  if (!str_cmp (argument, "done"))
    {
      edit_done (ch);
      return;
    }

  if (emptystring (argument))
    {
      olc_show (ch, table);
      return;
    }

  if (!table->table
      || !edit_struct (ch, argument, table->type_zero, table->table,
		       ch->desc->pEdit))
    interpret (ch, argument);
  else if (table->save_fun)
    {
      (*table->save_fun) (act_write);
      if (pArea)
	SetBit (pArea->area_flags, AREA_CHANGED);
    }
  return;
}

bool
run_olc_editor (Descriptor * d, char *incomm)
{
  OlcTable *ed;

  if ((ed = olc_lookup (d->editor)) == NULL)
    return false;

  olcedit (CH (d), incomm, ed);
  return true;
}

const char *
olc_ed_name (Descriptor * d)
{
  OlcTable *ed;

  if (!d)
    return &str_empty[0];

  if ((ed = olc_lookup (d->editor)) == NULL)
    return &str_empty[0];

  return ed->name;
}

const char *
olc_ed_name_long (CharData * ch)
{
  OlcTable *ed;

  if (!ch->desc)
    return "Switched";

  if (IsNPC (ch))
    return &str_empty[0];

  if ((ed = olc_lookup (ch->desc->editor)) == NULL)
    return &str_empty[0];

  return ed->longname;
}

char *
olc_ed_vnum (Descriptor * d)
{
  OlcTable *ed;
  const char **str;
  vnum_t *vnum;
  long *l;
  int *i;

  if (!d || (ed = olc_lookup (d->editor)) == NULL)
    return &str_empty[0];

  switch (ed->field)
    {
    case FIELD_STRING:
      rwgetdata (str, const char *, ed->vnum, ed->type_zero, d->pEdit);

      return FORMATF ("%.10s", *str);
    case FIELD_INT:
    default:
      rwgetdata (i, int, ed->vnum, ed->type_zero, d->pEdit);

      return FORMATF ("%d", *i);
    case FIELD_LONG:
      rwgetdata (l, long, ed->vnum, ed->type_zero, d->pEdit);

      return FORMATF ("%ld", *l);
    case FIELD_VNUM:
      rwgetdata (vnum, vnum_t, ed->vnum, ed->type_zero, d->pEdit);
      return FORMATF ("%ld", *vnum);
    }
}

void
stop_editing (void *OLC)
{
  Descriptor *d;

  for (d = descriptor_first; d != NULL; d = d->next)
    {
      if (d->pEdit == NULL || d->character == NULL)
	continue;

      if (d->pEdit == OLC)
	edit_done (d->character);
    }
  return;
}

void
olc_msg (CharData * ch, const char *n_fun, const char *fmt, ...)
{
  char buf[MPL];
  va_list args;

  if (!ch || !ch->desc || NullStr (fmt))
    return;

  va_start (args, fmt);
  vsnprintf (buf, sizeof (buf), fmt, args);
  va_end (args);

  if (ch->desc->editor != ED_NONE)
    chprintlnf (ch, "%s: %s: %s", olc_ed_name (ch->desc), n_fun, buf);
  else
    chprintlnf (ch, "%s: %s", n_fun, buf);
}



Olc_Fun (show_olc_cmds)
{
  int cmd;
  OlcTable *ed;
  Column Cd;
  Buffer *buf;

  if ((ed = olc_lookup (ch->desc->editor)) == NULL || ed->table == NULL)
    {
      bugf ("table NULL, editor %d", ch->desc->editor);
      return false;
    }

  buf = new_buf ();
  set_cols (&Cd, ch, 4, COLS_BUF, buf);

  for (cmd = 0; ed->table[cmd].field != NULL; cmd++)
    {
      if (ed->table[cmd].function)
	print_cols (&Cd, ed->table[cmd].field);
    }

  for (cmd = 0; olc_comm_table[cmd].name != NULL; cmd++)
    {
      print_cols (&Cd, olc_comm_table[cmd].name);
    }

  cols_nl (&Cd);
  sendpage (ch, buf_string (buf));
  free_buf (buf);
  return false;
}

const struct olc_comm_type olc_comm_table[] = {
  {"create", olced_create},
  {"delete", olced_delete},
  {"list", olced_list},
  {"show", olced_show},
  {"commands", show_olc_cmds},
  {"?", show_olc_help},
  {"version", show_olc_version},
  {NULL, NULL}
};


AreaData *
get_area_data (int vnum)
{
  AreaData *pArea;

  for (pArea = area_first; pArea; pArea = pArea->next)
    {
      if (pArea->vnum == vnum)
	return pArea;
    }

  return 0;
}


bool
edit_done (CharData * ch)
{
  if (ch->desc->editor != ED_NONE)
    {
      act ("$n stop using the $t editor.", ch, olc_ed_name_long (ch), NULL,
	   TO_ROOM);
      act ("You stop using the $t editor.", ch, olc_ed_name_long (ch),
	   NULL, TO_CHAR);
    }

  ch->desc->pEdit = NULL;
  ch->desc->editor = ED_NONE;
  return false;
}

ChannelData *
get_chan_data (int chan)
{
  if (chan >= 0 && chan < top_channel)
    return &channel_table[chan];
  else
    return NULL;
}

SongData *
get_song_data (int song)
{
  if (song >= 0 && song < top_song)
    return &song_table[song];
  else
    return NULL;
}

SkillData *
get_skill_data (int skill)
{
  if (skill > -1 && skill < top_skill)
    return &skill_table[skill];

  return &skill_table[0];
}

GroupData *
get_group_data (int group)
{
  if (group > -1 && group < top_group)
    return &group_table[group];

  return &group_table[0];
}

ClassData *
get_class_data (int Class)
{
  if (Class > -1 && Class < top_class)
    return &class_table[Class];

  return &class_table[0];
}

bool
vnum_OK (vnum_t lnum, vnum_t hnum)
{
  int i;

  for (i = 0; vnum_table[i].vnum != -1; i++)
    {
      if (vnum_table[i].vnum >= lnum && vnum_table[i].vnum <= hnum)
	return false;
    }
  return true;
}

bool
check_vnum (vnum_t vnum, int type)
{
  int i;

  for (i = 0; vnum_table[i].vnum != -1; i++)
    {
      if (vnum_table[i].type != type)
	continue;

      if (vnum_table[i].vnum == vnum)
	return false;
    }
  return true;
}

void
display_resets (CharData * ch)
{
  RoomIndex *pRoom;
  ResetData *pReset;
  CharIndex *pMob = NULL;
  int iReset = 0;

  EditRoom (ch, pRoom);

  chprintln (ch,
	     " No.  Loads    Description       Location         Vnum   Mx Mn Description"
	     NEWLINE
	     "==== ======== ============= =================== ======== ===== ===========");

  for (pReset = pRoom->reset_first; pReset; pReset = pReset->next)
    {
      ObjIndex *pObj;
      CharIndex *pMobIndex;
      ObjIndex *pObjIndex;
      ObjIndex *pObjToIndex;
      RoomIndex *pRoomIndex;

      chprintf (ch, "[%2d] ", ++iReset);

      switch (pReset->command)
	{
	default:
	  chprintlnf (ch, "Bad reset command: %c.", pReset->command);
	  break;

	case 'M':
	  if (!(pMobIndex = get_char_index (pReset->arg1)))
	    {
	      chprintlnf (ch, "Load Mobile - Bad Mob %ld", pReset->arg1);
	      continue;
	    }

	  if (!(pRoomIndex = get_room_index (pReset->arg3)))
	    {
	      chprintlnf (ch, "Load Mobile - Bad Room %ld", pReset->arg3);
	      continue;
	    }

	  pMob = pMobIndex;


	  {
	    RoomIndex *pRoomIndexPrev;

	    pRoomIndexPrev = get_room_index (pRoomIndex->vnum - 1);
	    if (pRoomIndexPrev
		&& IsSet (pRoomIndexPrev->room_flags, ROOM_PET_SHOP))
	      chprintlnf (ch,
			  "P[%5ld] %-13.13s in room             R[%5ld] %2d-%2d %-15.15s",
			  pReset->arg1, pMob->short_descr,
			  pReset->arg3, pReset->arg2,
			  pReset->arg4, pRoomIndex->name);
	    else
	      chprintlnf (ch,
			  "M[%5ld] %-13.13s in room             R[%5ld] %2d-%2d %-15.15s",
			  pReset->arg1, pMob->short_descr,
			  pReset->arg3, pReset->arg2, pReset->arg4,
			  pRoomIndex->name);
	  }

	  break;

	case 'O':
	  if (!(pObjIndex = get_obj_index (pReset->arg1)))
	    {
	      chprintlnf (ch, "Load Object - Bad Object %ld", pReset->arg1);
	      continue;
	    }

	  pObj = pObjIndex;

	  if (!(pRoomIndex = get_room_index (pReset->arg3)))
	    {
	      chprintlnf (ch, "Load Object - Bad Room %ld", pReset->arg3);
	      continue;
	    }

	  chprintlnf (ch,
		      "O[%5ld] %-13.13s in room             "
		      "R[%5ld]       %-15.15s", pReset->arg1,
		      pObj->short_descr, pReset->arg3, pRoomIndex->name);

	  break;

	case 'P':
	  if (!(pObjIndex = get_obj_index (pReset->arg1)))
	    {
	      chprintlnf (ch, "Put Object - Bad Object %ld", pReset->arg1);
	      continue;
	    }

	  pObj = pObjIndex;

	  if (!(pObjToIndex = get_obj_index (pReset->arg3)))
	    {
	      chprintlnf (ch, "Put Object - Bad To Object %ld", pReset->arg3);
	      continue;
	    }

	  chprintlnf (ch,
		      "O[%5ld] %-13.13s inside              O[%5ld] %2d-%2d %-15.15s",
		      pReset->arg1, pObj->short_descr, pReset->arg3,
		      pReset->arg2, pReset->arg4, pObjToIndex->short_descr);

	  break;

	case 'G':
	case 'E':
	  if (!(pObjIndex = get_obj_index (pReset->arg1)))
	    {
	      chprintlnf (ch,
			  "Give/Equip Object - Bad Object %ld", pReset->arg1);
	      continue;
	    }

	  pObj = pObjIndex;

	  if (!pMob)
	    {
	      chprintln (ch, "Give/Equip Object - No Previous Mobile");
	      break;
	    }

	  if (pMob->pShop)
	    {
	      chprintlnf (ch,
			  "O[%5ld] %-13.13s in the inventory of S[%5ld]       %-15.15s",
			  pReset->arg1, pObj->short_descr,
			  pMob->vnum, pMob->short_descr);
	    }
	  else
	    chprintlnf (ch,
			"O[%5ld] %-13.13s %-19.19s M[%5ld]       %-15.15s",
			pReset->arg1, pObj->short_descr,
			(pReset->command ==
			 'G') ? "in the inventory" :
			flag_string (wear_loc_strings, pReset->arg3),
			pMob->vnum, pMob->short_descr);

	  break;


	case 'F':
	  pRoomIndex = get_room_index (pReset->arg1);
	  chprintlnf (ch,
		      "R[%5ld] %s door of %-19.19s reset to %s",
		      pReset->arg1,
		      capitalize (dir_name[pReset->arg2]),
		      pRoomIndex->name, flag_string (exit_flags,
						     pRoomIndex->exit
						     [pReset->
						      arg2]->rs_flags));
	  break;

	case 'R':
	  if (!(pRoomIndex = get_room_index (pReset->arg1)))
	    {
	      chprintlnf (ch, "Randomize Exits - Bad Room %ld", pReset->arg1);
	      continue;
	    }

	  chprintlnf (ch, "R[%5ld] Set to randomize %s %s.",
		      pReset->arg1,
		      pReset->arg3 == 0 ? "exits" : pReset->arg2 ==
		      0 ? "any available exit" : dir_name[pReset->arg2 -
							  1],
		      pReset->arg3 == 0 ? "in room" : pReset->arg3 ==
		      1 ? "to this area" : "to the world");

	  break;
	}
    }

  return;
}


void
add_reset (RoomIndex * room, ResetData * pReset, int pIndex)
{
  ResetData *reset;
  int iReset = 0;

  if (!room)
    return;

  if (!room->reset_first)
    {
      Link (pReset, room->reset, next, prev);
      return;
    }

  for (reset = room->reset_first; reset; reset = reset->next)
    {
      if (++iReset == pIndex)
	break;
    }

  if (reset)
    Insert (pReset, reset, room->reset, next, prev);
  else
    Link (pReset, room->reset, next, prev);
  return;
}

Do_Fun (do_resets)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];
  char arg4[MAX_INPUT_LENGTH];
  char arg5[MAX_INPUT_LENGTH];
  char arg6[MAX_INPUT_LENGTH];
  char arg7[MAX_INPUT_LENGTH];
  ResetData *pReset = NULL;

  argument = one_argument (argument, arg1);
  argument = one_argument (argument, arg2);
  argument = one_argument (argument, arg3);
  argument = one_argument (argument, arg4);
  argument = one_argument (argument, arg5);
  argument = one_argument (argument, arg6);
  argument = one_argument (argument, arg7);

  if (!IsBuilder (ch, ch->in_room->area))
    {
      chprintln (ch, "Resets: Invalid security for editing this area.");
      return;
    }


  if (NullStr (arg1))
    {
      if (ch->in_room->reset_first)
	{
	  chprintln (ch, "Resets: M = mobile, R = room, O = object, "
		     "P = pet, S = shopkeeper");
	  display_resets (ch);
	}
      else
	chprintln (ch, "No resets in this room.");
    }


  if (is_number (arg1))
    {
      RoomIndex *pRoom = ch->in_room;


      if (!str_cmp (arg2, "delete"))
	{
	  int insert_loc = atoi (arg1);
	  int iReset = -1;

	  if (!ch->in_room->reset_first)
	    {
	      chprintln (ch, "No resets in this area.");
	      return;
	    }
	  for (pReset = pRoom->reset_first; pReset; pReset = pReset->next)
	    {
	      if (++iReset == insert_loc - 1)
		break;
	    }

	  if (!pReset)
	    {
	      chprintln (ch, "Reset not found.");
	      return;
	    }
	  UnLink (pReset, pRoom->reset, next, prev);
	  free_reset (pReset);
	  chprintln (ch, "Reset deleted.");
	  SetBit (ch->in_room->area->area_flags, AREA_CHANGED);
	}
      else
	if ((!str_cmp (arg2, "mob") && is_number (arg3)) ||
	    (!str_cmp (arg2, "obj") && is_number (arg3)))
	{

	  if (!str_cmp (arg2, "mob"))
	    {
	      if (get_char_index (is_number (arg3) ? atov (arg3) : 1) == NULL)
		{
		  chprintln (ch, "Mob no existe.");
		  return;
		}
	      pReset = new_reset ();
	      pReset->command = 'M';
	      pReset->arg1 = atol (arg3);
	      pReset->arg2 = is_number (arg4) ? atoi (arg4) : 1;
	      pReset->arg3 = ch->in_room->vnum;
	      pReset->arg4 = is_number (arg5) ? atoi (arg5) : 1;
	    }
	  else if (!str_cmp (arg2, "obj"))
	    {
	      pReset = new_reset ();
	      pReset->arg1 = atol (arg3);

	      if (!str_prefix (arg4, "inside"))
		{
		  ObjIndex *temp;

		  temp = get_obj_index (is_number (arg5) ? atov (arg5) : 1);
		  if ((temp->item_type != ITEM_CONTAINER)
		      && (temp->item_type != ITEM_CORPSE_NPC))
		    {
		      chprintln (ch, "Objeto 2 no es container.");
		      return;
		    }
		  pReset->command = 'P';
		  pReset->arg2 = is_number (arg6) ? atoi (arg6) : 1;
		  pReset->arg3 = is_number (arg5) ? atol (arg5) : 1;
		  pReset->arg4 = is_number (arg7) ? atoi (arg7) : 1;
		}
	      else if (!str_cmp (arg4, "room"))
		{
		  if (get_obj_index (atov (arg3)) == NULL)
		    {
		      chprintln (ch, "Vnum no existe.");
		      return;
		    }
		  pReset->command = 'O';
		  pReset->arg2 = 0;
		  pReset->arg3 = ch->in_room->vnum;
		  pReset->arg4 = 0;
		}
	      else

		{
		  int wear;

		  if ((wear = flag_value (wear_loc_flags, arg4)) == NO_FLAG)
		    {
		      chprintln (ch, "Resets: '? wear-loc'");
		      return;
		    }
		  if (get_obj_index (atov (arg3)) == NULL)
		    {
		      chprintln (ch, "Vnum no existe.");
		      return;
		    }
		  pReset->arg1 = atol (arg3);
		  pReset->arg3 = wear;
		  if (pReset->arg3 == WEAR_NONE)
		    pReset->command = 'G';
		  else
		    pReset->command = 'E';
		}
	    }
	  add_reset (ch->in_room, pReset, atol (arg1));
	  SetBit (ch->in_room->area->area_flags, AREA_CHANGED);
	  chprintln (ch, "Reset added.");
	}
      else if (!str_cmp (arg2, "random"))
	{
	  int door;

	  if (is_number (arg3))
	    {
	      door = atoi (arg3);
	    }
	  else
	    {
	      if ((door = get_direction (arg3)) != -1)
		door++;
	    }

	  if (door < 0 || door > MAX_DIR)
	    {
	      chprintln (ch, "Invalid argument.");
	      return;
	    }

	  if (door == 0
	      && (NullStr (arg4) || !is_exact_name (arg4, "area world")))
	    {
	      chprintln (ch, "Invalid or missing argument.");
	      return;
	    }
	  if (is_exact_name (arg4, "area world") && door > 0
	      && ch->in_room->exit[door - 1] != NULL)
	    {
	      chprintln (ch, "There is already an exit in that direction.");
	      return;
	    }
	  pReset = new_reset ();
	  pReset->command = 'R';
	  pReset->arg1 = ch->in_room->vnum;
	  pReset->arg2 = door;
	  pReset->arg3 =
	    !str_cmp (arg4, "area") ? 1 : !str_cmp (arg4, "world") ? 2 : 0;
	  add_reset (ch->in_room, pReset, atoi (arg1));
	  SetBit (ch->in_room->area->area_flags, AREA_CHANGED);
	  chprintln (ch, "Random exit reset added.");
	}
      else
	{
	  cmd_syntax (ch, NULL, n_fun, "<number> OBJ <vnum> <wear_loc>",
		      "<number> OBJ <vnum> inside <vnum> [limit] [count]",
		      "<number> OBJ <vnum> room",
		      "<number> MOB <vnum> [max #x area] [max #x room]",
		      "<number> DELETE",
		      "<number> RANDOM [#x exits]",
		      "<number> RANDOM <exit|0> area|world", NULL);
	}
    }

  return;
}

int
compare_area (const void *v1, const void *v2)
{
  return (*(AreaData * *)v2)->min_vnum - (*(AreaData * *)v1)->min_vnum;
}


Do_Fun (do_alist)
{
  Buffer *output;
  AreaData **areas;
  AreaData *pArea;
  int i = 0;

  output = new_buf ();

  alloc_mem (areas, AreaData *, top_area);

  bprintlnf (output, "[%3s] %-25s [%-5s-%5s] [%-11s] %3s [%-10s] [%-10s]",
	     "Num", "Area Name", "lvnum", "uvnum", "Filename", "Sec",
	     "Builders", "Flags");

  for (pArea = area_first; pArea != NULL; pArea = pArea->next)
    areas[i++] = pArea;

  qsort (areas, i, sizeof (pArea), compare_area);

  while (--i >= 0)
    {
      bprintlnf
	(output,
	 "[%3d] %-25s [%-5ld-%5ld] %-13.13s [%1d] [%-10s] [%-10s]",
	 areas[i]->vnum, areas[i]->name, areas[i]->min_vnum,
	 areas[i]->max_vnum, areas[i]->file_name, areas[i]->security,
	 areas[i]->builders, flag_string (area_flags, areas[i]->area_flags));
    }
  bprintlnf (output, NEWLINE "Total areas: %d", top_area);
  sendpage (ch, buf_string (output));
  free_buf (output);
  free_mem (areas);
  return;
}

int
calc_avedam (int num_dice, int dam_dice)
{
  return ((1 + dam_dice) * num_dice / 2);
}

Do_Fun (do_avedam)
{
  int i, j;
  int k = 0;
  int lookingfor;

  if (NullStr (argument))
    {
      chprintln (ch, "What average dam are you looking for?");
      return;
    }

  lookingfor = atoi (argument);
  chprintlnf (ch, "Possible dice combinations for ave dam: %d", lookingfor);
  chprintln (ch, "T_Dice D_Dice   T_Dice D_Dice");
  chprintln (ch, "------ ------   ------ ------");
  for (i = 1; i <= lookingfor; i++)
    {
      for (j = 1; j <= lookingfor; j++)
	{
	  if (lookingfor == calc_avedam (i, j))
	    {
	      k++;
	      chprintf (ch, "%6d %6d   ", i, j);
	      if (k % 2 == 0)
		chprintln (ch, NULL);
	    }
	}
    }
  chprintln (ch, NULL);
}

void
edit_start (CharData * ch, void *OLC, ed_t Ed)
{
  ed_t old_ed;
  OlcTable *t;

  if (!ch || !ch->desc || !(t = olc_lookup (Ed)))
    return;

  old_ed = ch->desc->editor;

  ch->desc->pEdit = OLC;
  ch->desc->editor = Ed;
  if (old_ed != Ed)
    {
      act ("$n has entered the $t editor.", ch, t->longname, NULL, TO_ROOM);
      act ("You are now entering the $t editor, type 'done' to finish.",
	   ch, t->longname, NULL, TO_CHAR);
    }
  if (Ed == ED_ROOM && OLC != NULL)
    {
      char_from_room (ch);
      char_to_room (ch, (RoomIndex *) OLC);
    }
  olc_show (ch, t);
}

void
autoset (CharIndex * pMob)
{
  double roll, size, bonus, avg;
  double ac_n, ac_x;
  int level;

  if (!pMob || pMob->level < 1)
    return;

  level = pMob->level;

  bonus = Max (1, (number_fuzzier (level) - 5));
  ac_n =
    80 - (level * (7.77 + (level / 90))) - ((level / 9) ^ 2) - (bonus * 2);
  ac_x =
    80 - (level * (6.67 + (level / 90))) - ((level / 9) ^ 2) - (bonus * 2);
  pMob->ac[AC_PIERCE] = (int) ac_n;
  pMob->ac[AC_BASH] = (int) ac_n;
  pMob->ac[AC_SLASH] = (int) ac_n;
  pMob->ac[AC_EXOTIC] = (int) ac_x;

  pMob->mana[DICE_NUMBER] = number_fuzzier (level);
  pMob->mana[DICE_TYPE] = number_fuzzier (10);
  pMob->mana[DICE_BONUS] = number_fuzzier (85);

  avg = (number_fuzzier (level) * .84);
  roll = (number_fuzzier (level) / 9 + 1);
  size = (number_fuzzier ((int) roll) / 3);

  for (size = roll / 3; roll * (size + 2) / 2 < avg; size++)
    ;

  pMob->damage[DICE_NUMBER] = (int) Max (1, roll);
  pMob->damage[DICE_TYPE] = (int) Max (2, size);
  pMob->damage[DICE_BONUS] = (int) Max (1, number_fuzzier (level) * .89);

  bonus =
    Max (1,
	 (level / 53 + 1) * ((level * 10) + (level / 10)) - Min (20,
								 (2 *
								  level))
	 + 1);

  size = number_fuzzier (level) * 1.2 - number_fuzzier (1);

  roll = number_fuzzier (level) * 1.4 - number_fuzzier (2);

  pMob->hit[DICE_NUMBER] = (int) Max (1, roll);
  pMob->hit[DICE_TYPE] = (int) Max (2, size);
  pMob->hit[DICE_BONUS] = (int) Max (10, bonus);

  pMob->hitroll = number_range (level * 6 / 10, level);
}

void
autohard (CharIndex * pMob)
{
  double roll, size, bonus, avg;
  double ac_n, ac_x;
  int level;

  if (!pMob || pMob->level < 1)
    return;

  level = pMob->level;

  bonus = Max (1, (number_fuzzier (level) - 5));
  ac_n =
    70 - (level * (8.15 + (level / 90))) - ((level / 8) ^ 2) - (bonus * 2);
  ac_x =
    70 - (level * (7.12 + (level / 90))) - ((level / 8) ^ 2) - (bonus * 2);
  pMob->ac[AC_PIERCE] = (int) ac_n;
  pMob->ac[AC_BASH] = (int) ac_n;
  pMob->ac[AC_SLASH] = (int) ac_n;
  pMob->ac[AC_EXOTIC] = (int) ac_x;

  pMob->mana[DICE_NUMBER] = number_fuzzier (level);
  pMob->mana[DICE_TYPE] = number_fuzzier (12);
  pMob->mana[DICE_BONUS] = number_fuzzier (95);

  avg = (number_fuzzier (level) * .9);
  roll = (number_fuzzier (level) / 9 + 1);
  size = (number_fuzzier ((int) roll) / 3);

  for (size = roll / 3; roll * (size + 2) / 2 < avg; size++)
    ;

  pMob->damage[DICE_NUMBER] = (int) Max (1, roll);
  pMob->damage[DICE_TYPE] = (int) Max (2, size);
  pMob->damage[DICE_BONUS] = (int) Max (1, number_fuzzier (level) * .99);

  bonus = (level / 53 + 1) * ((level * 10) + (level / 10)) + 1;

  size = number_fuzzier (level) * 1.2 - number_fuzzier (1);

  size++;

  roll = number_fuzzier (level) * 1.4 - number_fuzzier (2);

  pMob->hit[DICE_NUMBER] = (int) Max (1, roll);
  pMob->hit[DICE_TYPE] = (int) Max (2, size);
  pMob->hit[DICE_BONUS] = (int) Max (10, bonus);

  pMob->hitroll = number_range (level * 65 / 100, level);
}

void
autoeasy (CharIndex * pMob)
{
  double roll, size, bonus, avg;
  double ac_n, ac_x;
  int level;

  if (!pMob || pMob->level < 1)
    return;

  level = pMob->level;

  bonus = Max (1, (number_fuzzier (level) - 5));
  ac_n =
    90 - (level * (7.47 + (level / 90))) - ((level / 10) ^ 2) - (bonus * 2);
  ac_x =
    90 - (level * (6.37 + (level / 90))) - ((level / 10) ^ 2) - (bonus * 2);
  pMob->ac[AC_PIERCE] = (int) ac_n;
  pMob->ac[AC_BASH] = (int) ac_n;
  pMob->ac[AC_SLASH] = (int) ac_n;
  pMob->ac[AC_EXOTIC] = (int) ac_x;

  pMob->mana[DICE_NUMBER] = number_fuzzier (level);
  pMob->mana[DICE_TYPE] = number_fuzzier (10);
  pMob->mana[DICE_BONUS] = number_fuzzier (60);

  avg = (number_fuzzier (level) * .76);
  roll = (number_fuzzier (level) / 9 + 1);
  size = (number_fuzzier ((int) roll) / 3);

  for (size = roll / 3; roll * (size + 2) / 2 < avg; size++)
    ;

  pMob->damage[DICE_NUMBER] = (int) Max (1, roll);
  pMob->damage[DICE_TYPE] = (int) Max (2, size);
  pMob->damage[DICE_BONUS] = (int) Max (1, number_fuzzier (level) * .82);

  bonus =
    Max (1,
	 (level / 55 + 1) * ((level * 9) + (level / 10)) - Min (20,
								(1.5 *
								 level)) + 1);

  size = number_fuzzier (level) * 1.2 - number_fuzzier (1);

  roll = number_fuzzier (level) * 1.4 - number_fuzzier (2);

  pMob->hit[DICE_NUMBER] = (int) Max (1, roll);
  pMob->hit[DICE_TYPE] = (int) Max (2, size);
  pMob->hit[DICE_BONUS] = (int) Max (10, bonus);

  pMob->hitroll = number_range (level * 59 / 100, level);
}

void
autoweapon (ObjIndex * pObj)
{
  AffectData *pAf, *pObjAf;
  bool bDamroll, bHitroll;
  double pDice, size, bonus;
  int level, mod;

  if (!pObj || pObj->item_type != ITEM_WEAPON)
    return;

  if (pObj->level < 1 || IsObjStat (pObj, ITEM_QUEST))
    return;

  level = pObj->level;

  bonus = Max (1, number_fuzzier (level) / 9 - 1);
  pDice = (number_fuzzier (level) * .22 + 2);
  size = (number_fuzzier ((int) pDice) / 2);

  for (size = pDice / 2; pDice * (size + 2) / 2 < level; size++)
    ;

  pDice = Max (2, pDice);
  size = Max (3, size);

  switch (pObj->value[0])
    {
    default:
    case WEAPON_EXOTIC:
    case WEAPON_SWORD:
      break;
    case WEAPON_DAGGER:
      pDice = Max (2, pDice - 1);
      size = Max (3, size - 1);
      break;
    case WEAPON_SPEAR:
    case WEAPON_POLEARM:
      size++;
      break;
    case WEAPON_MACE:
    case WEAPON_AXE:
      size = Max (3, size - 1);
      break;
    case WEAPON_FLAIL:
    case WEAPON_WHIP:
      pDice = Max (2, pDice - 1);
      break;
    }

  pDice += 1;
  size -= 1;

  pDice = Max (2, number_fuzzier ((int) pDice));
  size = Max (3, number_fuzzier ((int) size));

  pObj->value[1] = (long) pDice;
  pObj->value[2] = (long) size;

  mod = Max (1, number_range (number_fuzzier ((int) bonus) * 6 / 10,
			      number_fuzzier ((int) bonus)));

  if (mod > 0)
    {
      bDamroll = false;
      bHitroll = false;

      for (pObjAf = pObj->affect_first; pObjAf; pObjAf = pObjAf->next)
	{
	  if (pObjAf->location == APPLY_DAMROLL)
	    {
	      pObjAf->level = level;
	      pObjAf->modifier = mod;
	      bDamroll = true;
	    }
	  else if (pObjAf->location == APPLY_HITROLL)
	    {
	      pObjAf->level = level;
	      pObjAf->modifier = mod;
	      bHitroll = true;
	    }
	}

      if (!bDamroll)
	{
	  pAf = new_affect ();
	  pAf->location = APPLY_DAMROLL;
	  pAf->modifier = mod;
	  pAf->where = TO_OBJECT;
	  pAf->type = -1;
	  pAf->duration = -1;
	  pAf->bitvector = 0;
	  pAf->level = level;
	  Link (pAf, pObj->affect, next, prev);
	}

      if (!bHitroll)
	{
	  pAf = new_affect ();
	  pAf->location = APPLY_HITROLL;
	  pAf->modifier = mod;
	  pAf->where = TO_OBJECT;
	  pAf->type = -1;
	  pAf->duration = -1;
	  pAf->bitvector = 0;
	  pAf->level = level;
	  Link (pAf, pObj->affect, next, prev);
	}
    }
}

void
autoarmor (ObjIndex * pObj)
{
  int size;
  int level;

  if (!pObj || pObj->item_type != ITEM_ARMOR)
    return;

  if (pObj->level < 1 || IsObjStat (pObj, ITEM_QUEST))
    return;

  level = pObj->level;

  size = Max (1, number_fuzzier (level) / 2 + 1);

  pObj->value[0] = size;
  pObj->value[1] = size;
  pObj->value[2] = size;
  pObj->value[3] = (size - 1);
}

void
area_set_auto (AreaData * pArea)
{
  ObjIndex *pObjIndex;
  CharIndex *pMobIndex;
  vnum_t vnum;

  if (!pArea)
    return;

  for (vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++)
    {
      if ((pMobIndex = get_char_index (vnum)) != NULL
	  && pMobIndex->level >= 1)
	{
	  switch (pMobIndex->autoset)
	    {
	    case AUTOEASY:
	      autoeasy (pMobIndex);
	      break;
	    case AUTOSET:
	      autoset (pMobIndex);
	      break;
	    case AUTOHARD:
	      autohard (pMobIndex);
	      break;
	    case AUTORANDOM:
	      switch (number_range (1, 3))
		{
		case 1:
		  autoeasy (pMobIndex);
		  break;
		case 2:
		  autoset (pMobIndex);
		  break;
		case 3:
		  autohard (pMobIndex);
		  break;
		}
	      break;
	    case AUTODEFAULT:
	      if (pMobIndex->level < MAX_LEVEL / 10)
		autoeasy (pMobIndex);
	      else if (pMobIndex->level < MAX_LEVEL / 2)
		autoset (pMobIndex);
	      else
		autohard (pMobIndex);
	      break;
	    }
	}

      if ((pObjIndex = get_obj_index (vnum)) != NULL
	  && !IsObjStat (pObjIndex, ITEM_QUEST) && pObjIndex->level >= 1)
	{

	  if (pObjIndex->item_type == ITEM_WEAPON)
	    autoweapon (pObjIndex);
	  else if (pObjIndex->item_type == ITEM_ARMOR)
	    autoarmor (pObjIndex);
	}
    }
}

Do_Fun (do_areaset)
{
  AreaData *pArea;

  if (!str_cmp (argument, "world"))
    {
      for (pArea = area_first; pArea; pArea = pArea->next)
	area_set_auto (pArea);
      chprintln (ch, "World set to default values.");
    }
  else if (ch->in_room != NULL && (pArea = ch->in_room->area) != NULL)
    {
      area_set_auto (pArea);
      chprintlnf (ch, "%s set to default values.", pArea->name);
    }
  else
    cmd_syntax (ch, NULL, n_fun,
		"world       - set the whole world.",
		"            - set your current area.", NULL);

  return;
}


void
find_area_levels (CharData * ch, AreaData * pArea, bool set)
{
  int low = MAX_LEVEL, high = 0;

  if (IsSet (pArea->area_flags, AREA_PLAYER_HOMES))
    {
      low = 0;
      high = MAX_LEVEL;
    }
  else
    {
      vnum_t vnum;
      CharIndex *pMob;
      bool found = false;

      for (vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++)
	{
	  if ((pMob = get_char_index (vnum)) != NULL)
	    {
	      if (pMob->level > 0 && pMob->level <= MAX_LEVEL
		  && pMob->pShop == NULL
		  && !IsSet (pMob->act,
			     ACT_TRAIN | ACT_PRACTICE | ACT_IS_HEALER |
			     ACT_PET | ACT_PET | ACT_GAIN))
		{
		  if (pMob->level > high)
		    high = pMob->level;
		  if (pMob->level < low)
		    low = pMob->level;
		  found = true;
		}
	    }
	}
      if (!found)
	{
	  low = 0;
	  high = MAX_LEVEL;
	}
    }
  if (!set)
    chprintlnf (ch, "Recomended levels for %s: %03d - %03d",
		pArea->name, low, high);
  else
    {
      if (low != pArea->min_level || high != pArea->max_level)
	SetBit (pArea->area_flags, AREA_CHANGED);
      pArea->min_level = low;
      pArea->max_level = high;
      chprintlnf (ch, "%s: min level set to %d, max level set to %d.",
		  pArea->name, low, high);
    }
}

Do_Fun (do_arecommend)
{
  AreaData *pArea;
  char arg[MIL];
  bool set = false;

  argument = one_argument (argument, arg);
  set = !str_cmp (argument, "set");

  if (NullStr (arg) || (set = !str_cmp (arg, "set")))
    {
      pArea = ch->in_room->area;

      find_area_levels (ch, pArea, set);
      chprintlnf (ch, "Use '%s all [set]' to see all areas.", n_fun);
      chprintlnf (ch, "Use '%s <area> [set]' to see a specific area.", n_fun);
    }
  else if (!str_cmp (arg, "all"))
    {
      for (pArea = area_first; pArea; pArea = pArea->next)
	find_area_levels (ch, pArea, set);
    }
  else if ((pArea = area_lookup (arg)) != NULL)
    {
      find_area_levels (ch, pArea, set);
    }
  else
    {
      cmd_syntax (ch, NULL, n_fun,
		  "[set]        - recommend levels for current area.",
		  "all [set]    - recommend levels for all areas.",
		  "<area> [set] - recommend levels for a specific area.",
		  NULL);
    }
}

Do_Fun (do_afun_help)
{
  cmd_syntax (ch, NULL, n_fun,
	      "set          - autoset mob/obj values for this area",
	      "links        - find exits in and out of area",
	      "relevel      - change levels on mobs/objs in area",
	      "recommend    - recommend min/max level for area", NULL);
}


Do_Fun (do_relevel)
{
  char arg[MIL], arg2[MIL];
  AreaData *parea;
  int amount;
  bool pAdd = false, pSub = false;
  vnum_t vnum;
  char *relvl_help;
  CharIndex *pmob;
  ObjIndex *pobj;

  argument = one_argument (argument, arg);
  argument = one_argument (argument, arg2);

  relvl_help = "+/- <amount> [area]";
  if (NullStr (arg) || (NullStr (arg2) || !is_number (arg2)))
    {
      cmd_syntax (ch, NULL, n_fun, relvl_help, NULL);
      return;
    }

  if (!str_cmp (arg, "+"))
    pAdd = true;
  else if (!str_cmp (arg, "-"))
    pSub = true;
  else
    {
      cmd_syntax (ch, NULL, n_fun, relvl_help, NULL);
      return;
    }

  if (!NullStr (argument))
    {
      if ((parea = area_lookup (argument)) == NULL)
	{
	  chprintln (ch, "Invalid area to relevel.");
	  return;
	}
    }
  else
    parea = ch->in_room->area;

  amount = atoi (arg2);

  if (amount <= 0 || amount > MAX_LEVEL)
    {
      chprintln (ch, "Invalid amount.");
      return;
    }

  for (vnum = parea->min_vnum; vnum < parea->max_vnum; vnum++)
    {
      if ((pmob = get_char_index (vnum)) != NULL && pmob->level > 0)
	{
	  if (pAdd)
	    pmob->level = Max (1, pmob->level + amount);
	  else if (pSub)
	    pmob->level = Max (1, pmob->level - amount);
	}
      if ((pobj = get_obj_index (vnum)) != NULL && pobj->level > 0)
	{
	  if (pAdd)
	    pobj->level = Range (1, pobj->level + amount, MAX_MORTAL_LEVEL);
	  else if (pSub)
	    pobj->level = Range (1, pobj->level - amount, MAX_MORTAL_LEVEL);
	  switch (pobj->item_type)
	    {
	    case ITEM_POTION:
	    case ITEM_SCROLL:
	    case ITEM_PILL:
	    case ITEM_WAND:
	    case ITEM_STAFF:
	      if (pAdd)
		pobj->value[0] =
		  Range (1, pobj->value[0] + amount, MAX_LEVEL);
	      else if (pSub)
		pobj->value[0] =
		  Range (1, pobj->value[0] - amount, MAX_LEVEL);
	      break;
	    default:
	      break;
	    }
	}
    }
  SetBit (parea->area_flags, AREA_CHANGED);
  area_set_auto (parea);

  chprintln (ch, "Area re-leveled and auto-set.");
  return;
}


Do_Fun (do_alinks)
{
  int i;
  vnum_t vnum;
  RoomIndex *room;
  AreaData *area, *target;

  if (IsNPC (ch) || (ch->in_room == NULL))
    return;
  if (!IsBuilder (ch, ch->in_room->area) && !IsImmortal (ch))
    {
      chprintln (ch, "Huh?");
      return;
    }
  target = ch->in_room->area;

  if (!str_cmp (argument, "in"))
    {
      chprintlnf (ch, NEWLINE "Exits leading IN to %s:",
		  capitalize (ch->in_room->area->name));
      {
	for (area = area_first; area; area = area->next)
	  {
	    if (area != ch->in_room->area)
	      {
		for (vnum = area->min_vnum; vnum <= area->max_vnum; vnum++)
		  {
		    if ((room = get_room_index (vnum)) != NULL)
		      for (i = 0; i < MAX_DIR; i++)
			{
			  if (room->exit[i] != NULL)
			    if (room->exit[i]->u1.to_room->area == target)
			      {
				chprintlnf (ch,
					    "%-5s from %7ld [%s]",
					    dir_name[i], room->vnum,
					    room->area->name);
			      }
			}
		  }
	      }
	  }
      }
      return;
    }

  if (!str_cmp (argument, "out"))
    {
      chprintlnf (ch, NEWLINE "Exits leading OUT of %s:",
		  capitalize (ch->in_room->area->name));
      for (vnum = target->min_vnum; vnum <= target->max_vnum; vnum++)
	{
	  if ((room = get_room_index (vnum)))
	    {
	      for (i = 0; i < MAX_DIR; i++)
		if (room->exit[i] != NULL)
		  if (room->exit[i]->u1.to_room->area != target)
		    {
		      chprintlnf (ch, "%-5s from %7ld [%s]",
				  dir_name[i], vnum,
				  room->exit[i]->u1.to_room->area->name);
		    }
	    }
	}
      return;
    }

  cmd_syntax (ch, NULL, n_fun, "links <in|out>", NULL);
  return;
}

Do_Fun (do_afun)
{
  vinterpret (ch, n_fun, argument, "links", do_alinks, "set", do_areaset,
	      "relevel", do_relevel, "recommend",
	      do_arecommend, NULL, do_afun_help);
}

#include "olc_dofun.h"