1stMud4.5.3/
1stMud4.5.3/backup/
1stMud4.5.3/bin/
1stMud4.5.3/bin/extras/
1stMud4.5.3/data/i3/
1stMud4.5.3/doc/1stMud/
1stMud4.5.3/doc/Diku/
1stMud4.5.3/doc/MPDocs/
1stMud4.5.3/doc/Rom/
1stMud4.5.3/notes/
/**************************************************************************
*  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),
	ED_TABLE("ColEdit", "color", ED_COLOR, coledit, color, 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();
	bprintlnf(output, CTAG(_OLCBORDER) "%s{x",
			  stringf(ch, 0, Center, "=",
					  "[ " CTAG(_OLCVAR) "%s{x : " CTAG(_OLCVAL) "%s"
					  CTAG(_OLCBORDER) " ]", ed->name,
					  olc_ed_vnum(ch->desc)));
	show_struct(ch, output, ed->type_zero, ed->table, ch->desc->pEdit, -1);
	bprintlnf(output, CTAG(_OLCBORDER) "%s{x", 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)
			TouchArea(pArea);
	}
	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];
}

ColorData *get_color_data(int color)
{
	if (VALID_COLOR(color))
		return &color_table[color];

	return &color_table[color];
}

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.");
			TouchArea(ch->in_room->area);
		}
		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));
			TouchArea(ch->in_room->area);
			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));
			TouchArea(ch->in_room->area);
			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)
			TouchArea(pArea);
		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;
			}
		}
	}
	TouchArea(parea);
	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"