1stMUD/corefiles/
1stMUD/gods/
1stMUD/notes/
1stMUD/player/
1stMUD/win32/
1stMUD/win32/ROM/
/**************************************************************************
*  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                    *
***************************************************************************
*       1stMUD ROM Derivative (c) 2001-2002 by Ryan Jennings              *
*            http://1stmud.dlmud.com/  <r-jenn@shaw.ca>                   *
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *  Based on MERC 2.2 MOBprograms by N'Atas-ha.                            *
 *  Written and adapted to ROM 2.4 by                                      *
 *          Markku Nylander (markku.nylander@uta.fi)                       *
 *                                                                         *
 ***************************************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "merc.h"
#include "mob_cmds.h"
#include "interp.h"
#include "olc.h"
#include "tables.h"

extern ROOM_INDEX_DATA *find_location(CHAR_DATA *, const char *);
#define OBJ_CMD(name) void name(OBJ_DATA * obj, const char *argument)
#define ROOM_CMD(name) void name(ROOM_INDEX_DATA * room, const char *argument)

/*
 * MOBcommand table.
 */
const struct mob_cmd_type mob_cmd_table[] = {
	{"asound", do_mpasound},
	{"gecho", do_mpgecho},
	{"zecho", do_mpzecho},
	{"kill", do_mpkill},
	{"assist", do_mpassist},
	{"junk", do_mpjunk},
	{"echo", do_mpecho},
	{"echoaround", do_mpechoaround},
	{"echoat", do_mpechoat},
	{"mload", do_mpmload},
	{"oload", do_mpoload},
	{"purge", do_mppurge},
	{"goto", do_mpgoto},
	{"at", do_mpat},
	{"transfer", do_mptransfer},
	{"gtransfer", do_mpgtransfer},
	{"otransfer", do_mpotransfer},
	{"force", do_mpforce},
	{"gforce", do_mpgforce},
	{"vforce", do_mpvforce},
	{"cast", do_mpcast},
	{"damage", do_mpdamage},
	{"remember", do_mpremember},
	{"forget", do_mpforget},
	{"delay", do_mpdelay},
	{"cancel", do_mpcancel},
	{"call", do_mpcall},
	{"flee", do_mpflee},
	{"remove", do_mpremove},
	{"peace", do_mppeace},
	{NULL, NULL}
};

/*
 * OBJcommand table.
 */
const struct obj_cmd_type obj_cmd_table[] = {
	{"gecho", do_opgecho},
	{"zecho", do_opzecho},
	{"echo", do_opecho},
	{"echoaround", do_opechoaround},
	{"echoat", do_opechoat},
	{"mload", do_opmload},
	{"oload", do_opoload},
	{"purge", do_oppurge},
	{"goto", do_opgoto},
	{"transfer", do_optransfer},
	{"gtransfer", do_opgtransfer},
	{"otransfer", do_opotransfer},
	{"force", do_opforce},
	{"gforce", do_opgforce},
	{"vforce", do_opvforce},
	{"damage", do_opdamage},
	{"remember", do_opremember},
	{"forget", do_opforget},
	{"delay", do_opdelay},
	{"cancel", do_opcancel},
	{"call", do_opcall},
	{"remove", do_opremove},
	{"attrib", do_opattrib},
	{"peace", do_oppeace},
	{NULL, NULL}
};

/*
 * ROOMcommand table.
 */
const struct room_cmd_type room_cmd_table[] = {
	{"asound", do_rpasound},
	{"gecho", do_rpgecho},
	{"zecho", do_rpzecho},
	{"echo", do_rpecho},
	{"echoaround", do_rpechoaround},
	{"echoat", do_rpechoat},
	{"mload", do_rpmload},
	{"oload", do_rpoload},
	{"purge", do_rppurge},
	{"transfer", do_rptransfer},
	{"gtransfer", do_rpgtransfer},
	{"otransfer", do_rpotransfer},
	{"force", do_rpforce},
	{"gforce", do_rpgforce},
	{"vforce", do_rpvforce},
	{"damage", do_rpdamage},
	{"remember", do_rpremember},
	{"forget", do_rpforget},
	{"delay", do_rpdelay},
	{"cancel", do_rpcancel},
	{"call", do_rpcall},
	{"remove", do_rpremove},
	{"peace", do_rppeace},
	{NULL, NULL}
};

char *prog_type_to_name(flag_t type)
{
	switch (type)
	{
	case TRIG_ACT:
		return "ACT";
	case TRIG_SPEECH:
		return "SPEECH";
	case TRIG_RANDOM:
		return "RANDOM";
	case TRIG_FIGHT:
		return "FIGHT";
	case TRIG_HPCNT:
		return "HPCNT";
	case TRIG_DEATH:
		return "DEATH";
	case TRIG_ENTRY:
		return "ENTRY";
	case TRIG_GREET:
		return "GREET";
	case TRIG_GRALL:
		return "GRALL";
	case TRIG_GIVE:
		return "GIVE";
	case TRIG_BRIBE:
		return "BRIBE";
	case TRIG_KILL:
		return "KILL";
	case TRIG_DELAY:
		return "DELAY";
	case TRIG_SURR:
		return "SURRENDER";
	case TRIG_EXIT:
		return "EXIT";
	case TRIG_EXALL:
		return "EXALL";
	case TRIG_GET:
		return "GET";
	case TRIG_DROP:
		return "DROP";
	case TRIG_SIT:
		return "SIT";
	default:
		return "ERROR";
	}
}

/*
 * MOBprog section
 */
CH_CMD(do_mob)
{
	/*
	 * Security check!
	 */
	if (ch->desc != NULL && get_trust(ch) < MAX_LEVEL)
		return;
	mob_interpret(ch, argument);
}

/*
 * Mob command interpreter. Implemented separately for security and speed
 * reasons. A trivial hack of interpret()
 */
void mob_interpret(CHAR_DATA * ch, const char *argument)
{
	char command[MIL];
	int cmd;

	argument = one_argument(argument, command);

	/*
	 * Look for command in command table.
	 */
	for (cmd = 0; !IS_NULLSTR(mob_cmd_table[cmd].name); cmd++)
	{
		if (command[0] == mob_cmd_table[cmd].name[0]
			&& !str_prefix(command, mob_cmd_table[cmd].name))
		{
			(*mob_cmd_table[cmd].do_fun) (ch, argument);
			tail_chain();
			return;
		}
	}
	bugf("invalid cmd from mob %ld: '%s'",
		 IS_NPC(ch) ? ch->pIndexData->vnum : 0, command);
}

/* 
 * Displays MOBprogram triggers of a mobile
 *
 * Syntax: mpstat [name]
 */
CH_CMD(do_mpstat)
{
	char arg[MSL];
	PROG_LIST *mprg;
	CHAR_DATA *victim;
	int i;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
	{
		chprintln(ch, "Mpstat whom?");
		return;
	}

	if ((victim = get_char_world(ch, arg)) == NULL)
	{
		chprintln(ch, "No such creature.");
		return;
	}

	if (!IS_NPC(victim))
	{
		chprintln(ch, "That is not a mobile.");
		return;
	}

	chprintlnf(ch, "Mobile #%-6ld [%s]\n\r", victim->pIndexData->vnum,
			   victim->short_descr);

	chprintlnf(ch, "Delay   %-6d [%s]\n\r", victim->mprog_delay,
			   victim->mprog_target ==
			   NULL ? "No target" : victim->mprog_target->name);

	if (!victim->pIndexData->mprog_flags)
	{
		chprintln(ch, "[No programs set]");
		return;
	}

	for (i = 0, mprg = victim->pIndexData->first_mprog; mprg != NULL;
		 mprg = mprg->next)

	{
		chprintlnf(ch, "[%2d] Trigger [%-8s] Program [%4ld] Phrase [%s]", ++i,
				   prog_type_to_name(mprg->trig_type), mprg->vnum,
				   mprg->trig_phrase);
	}

	return;

}

/*
 * Displays the source code of a given MOBprogram
 *
 * Syntax: mpdump [vnum]
 */
CH_CMD(do_mpdump)
{
	char buf[MIL];
	PROG_CODE *mprg;

	one_argument(argument, buf);
	if ((mprg = get_prog_index(atol(buf), PRG_MPROG)) == NULL)
	{
		chprintln(ch, "No such MOBprogram.");
		return;
	}
	page_to_char(mprg->code, ch);
}

/*
 * Prints the argument to all active players in the game
 *
 * Syntax: mob gecho [string]
 */
CH_CMD(do_mpgecho)
{
	DESCRIPTOR_DATA *d;

	if (IS_NULLSTR(argument))
	{
		bugf("missing argument from vnum %ld",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	for (d = descriptor_first; d; d = d->next)
	{
		if (d->connected == CON_PLAYING)
		{
			if (IS_IMMORTAL(d->character))
				chprint(d->character, "Mob echo> ");
			chprintln(d->character, argument);
		}
	}
}

/*
 * Prints the argument to all players in the same area as the mob
 *
 * Syntax: mob zecho [string]
 */
CH_CMD(do_mpzecho)
{
	DESCRIPTOR_DATA *d;

	if (IS_NULLSTR(argument))
	{
		bugf("missing argument from vnum %ld",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if (ch->in_room == NULL)
		return;

	for (d = descriptor_first; d; d = d->next)
	{
		if (d->connected == CON_PLAYING && d->character->in_room != NULL
			&& d->character->in_room->area == ch->in_room->area)
		{
			if (IS_IMMORTAL(d->character))
				chprint(d->character, "Mob echo> ");
			chprintln(d->character, argument);
		}
	}
}

/*
 * Prints the argument to all the rooms aroud the mobile
 *
 * Syntax: mob asound [string]
 */
CH_CMD(do_mpasound)
{
	ROOM_INDEX_DATA *was_in_room;
	int door;

	if (IS_NULLSTR(argument))
		return;

	was_in_room = ch->in_room;
	for (door = 0; door < MAX_DIR; door++)
	{
		EXIT_DATA *pexit;

		if ((pexit = was_in_room->exit[door]) != NULL
			&& pexit->u1.to_room != NULL && pexit->u1.to_room != was_in_room)
		{
			ch->in_room = pexit->u1.to_room;
			MOBtrigger = FALSE;
			act(argument, ch, NULL, NULL, TO_ROOM);
			MOBtrigger = TRUE;
		}
	}
	ch->in_room = was_in_room;
	return;

}

/*
 * Lets the mobile kill any player or mobile without murder
 *
 * Syntax: mob kill [victim]
 */
CH_CMD(do_mpkill)
{
	char arg[MIL];
	CHAR_DATA *victim;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
		return;

	if ((victim = get_char_room(ch, NULL, arg)) == NULL)
		return;

	if (victim == ch || IS_NPC(victim) || ch->position == POS_FIGHTING)
		return;

	if (IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim)
	{
		bugf("Charmed mob attacking master from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	multi_hit(ch, victim, TYPE_UNDEFINED);
	return;
}

/*
 * Lets the mobile assist another mob or player
 *
 * Syntax: mob assist [character]
 */
CH_CMD(do_mpassist)
{
	char arg[MIL];
	CHAR_DATA *victim;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
		return;

	if ((victim = get_char_room(ch, NULL, arg)) == NULL)
		return;

	if (victim == ch || ch->fighting != NULL || victim->fighting == NULL)
		return;

	multi_hit(ch, victim->fighting, TYPE_UNDEFINED);
	return;
}

/*
 * Lets the mobile destroy an object in its inventory
 * it can also destroy a worn object and it can destroy 
 * items using all.xxxxx or just plain all of them 
 *
 * Syntax: mob junk [item]
 */

CH_CMD(do_mpjunk)
{
	char arg[MIL];
	OBJ_DATA *obj;
	OBJ_DATA *obj_next;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
		return;

	if (str_cmp(arg, "all") && str_prefix("all.", arg))
	{
		if ((obj = get_obj_wear(ch, arg, TRUE)) != NULL)
		{
			unequip_char(ch, obj);
			extract_obj(obj);
			return;
		}
		if ((obj = get_obj_carry(ch, arg, ch)) == NULL)
			return;
		extract_obj(obj);
	}
	else
		for (obj = ch->first_carrying; obj != NULL; obj = obj_next)
		{
			obj_next = obj->next_content;
			if (arg[3] == '\0' || is_name(&arg[4], obj->name))
			{
				if (obj->wear_loc != WEAR_NONE)
					unequip_char(ch, obj);
				extract_obj(obj);
			}
		}

	return;

}

/*
 * Prints the message to everyone in the room other than the mob and victim
 *
 * Syntax: mob echoaround [victim] [string]
 */

CH_CMD(do_mpechoaround)
{
	char arg[MIL];
	CHAR_DATA *victim;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg))
		return;

	if ((victim = get_char_room(ch, NULL, arg)) == NULL)
		return;

	act(argument, ch, NULL, victim, TO_NOTVICT);
}

/*
 * Prints the message to only the victim
 *
 * Syntax: mob echoat [victim] [string]
 */
CH_CMD(do_mpechoat)
{
	char arg[MIL];
	CHAR_DATA *victim;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
		return;

	if ((victim = get_char_room(ch, NULL, arg)) == NULL)
		return;

	act(argument, ch, NULL, victim, TO_VICT);
}

/*
 * Prints the message to the room at large
 *
 * Syntax: mpecho [string]
 */
CH_CMD(do_mpecho)
{
	if (IS_NULLSTR(argument))
		return;
	act(argument, ch, NULL, NULL, TO_ROOM);
}

/*
 * Lets the mobile load another mobile.
 *
 * Syntax: mob mload [vnum]
 */
CH_CMD(do_mpmload)
{
	char arg[MIL];
	MOB_INDEX_DATA *pMobIndex;
	CHAR_DATA *victim;
	vnum_t vnum;

	one_argument(argument, arg);

	if (ch->in_room == NULL || IS_NULLSTR(arg) || !is_number(arg))
		return;

	vnum = atol(arg);
	if ((pMobIndex = get_mob_index(vnum)) == NULL)
	{
		bugf("bad mob index (%ld) from mob %ld", vnum,
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	victim = create_mobile(pMobIndex);
	char_to_room(victim, ch->in_room);
	return;
}

/*
 * Lets the mobile load an object
 *
 * Syntax: mob oload [vnum] [level] {R}
 */
CH_CMD(do_mpoload)
{
	char arg1[MIL];
	char arg2[MIL];
	char arg3[MIL];
	OBJ_INDEX_DATA *pObjIndex;
	OBJ_DATA *obj;
	int level;
	bool fToroom = FALSE, fWear = FALSE;

	argument = one_argument(argument, arg1);
	argument = one_argument(argument, arg2);
	one_argument(argument, arg3);

	if (IS_NULLSTR(arg1) || !is_number(arg1))
	{
		bugf("Bad syntax from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if (IS_NULLSTR(arg2))
	{
		level = get_trust(ch);
	}
	else
	{
		/*
		 * New feature from Alander.
		 */
		if (!is_number(arg2))
		{
			bugf("Bad syntax from vnum %ld.",
				 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
			return;
		}
		level = atoi(arg2);
		if (level < 0 || level > get_trust(ch))
		{
			bugf("Bad level from vnum %ld.",
				 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
			return;
		}
	}

	/*
	 * Added 3rd argument
	 * omitted - load to mobile's inventory
	 * 'R'     - load to room
	 * 'W'     - load to mobile and force wear
	 */
	if (arg3[0] == 'R' || arg3[0] == 'r')
		fToroom = TRUE;
	else if (arg3[0] == 'W' || arg3[0] == 'w')
		fWear = TRUE;

	if ((pObjIndex = get_obj_index(atol(arg1))) == NULL)
	{
		bugf("Bad vnum arg from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	obj = create_object(pObjIndex, level);
	if ((fWear || !fToroom) && CAN_WEAR(obj, ITEM_TAKE))
	{
		obj_to_char(obj, ch);
		if (fWear)
			wear_obj(ch, obj, TRUE);
	}
	else
	{
		obj_to_room(obj, ch->in_room);
	}

	return;
}

/*
 * Lets the mobile purge all objects and other npcs in the room,
 * or purge a specified object or mob in the room. The mobile cannot
 * purge itself for safety reasons.
 *
 * syntax mob purge {target}
 */
CH_CMD(do_mppurge)
{
	char arg[MIL];
	CHAR_DATA *victim;
	OBJ_DATA *obj;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
	{
		/* 'purge' */
		CHAR_DATA *vnext;
		OBJ_DATA *obj_next;

		for (victim = ch->in_room->first_person; victim != NULL; victim = vnext)
		{
			vnext = victim->next_in_room;
			if (IS_NPC(victim) && victim != ch
				&& (IS_NPC(victim) && !IS_SET(victim->act, ACT_NOPURGE)))
				extract_char(victim, TRUE);
		}

		for (obj = ch->in_room->first_content; obj != NULL; obj = obj_next)
		{
			obj_next = obj->next_content;
			if (!IS_OBJ_STAT(obj, ITEM_NOPURGE))
				extract_obj(obj);
		}

		return;
	}

	if ((victim = get_char_room(ch, NULL, arg)) == NULL)
	{
		if ((obj = get_obj_here(ch, NULL, arg)))
		{
			extract_obj(obj);
		}
		else
		{
			bugf("Bad argument from vnum %ld.",
				 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		}
		return;
	}

	if (!IS_NPC(victim))
	{
		bugf("Purging a PC from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	extract_char(victim, TRUE);
	return;
}

/*
 * Lets the mobile goto any location it wishes that is not private.
 *
 * Syntax: mob goto [location]
 */
CH_CMD(do_mpgoto)
{
	char arg[MIL];
	ROOM_INDEX_DATA *location;

	one_argument(argument, arg);
	if (IS_NULLSTR(arg))
	{
		bugf("No argument from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if ((location = find_location(ch, arg)) == NULL)
	{
		bugf("No such location from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if (ch->fighting != NULL)
		stop_fighting(ch, TRUE);

	char_from_room(ch);
	char_to_room(ch, location);

	return;
}

/* 
 * Lets the mobile do a command at another location.
 *
 * Syntax: mob at [location] [commands]
 */
CH_CMD(do_mpat)
{
	char arg[MIL];
	ROOM_INDEX_DATA *location;
	ROOM_INDEX_DATA *original;
	CHAR_DATA *wch;
	OBJ_DATA *on, *obj;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
	{
		bugf("Bad argument from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if ((location = find_location(ch, arg)) == NULL)
	{
		bugf("No such location from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	original = ch->in_room;
	on = ch->on;
	char_from_room(ch);
	char_to_room(ch, location);
	interpret(ch, argument);

	/*
	 * See if 'ch' still exists before continuing!
	 * Handles 'at XXXX quit' case.
	 */
	for (wch = char_first; wch != NULL; wch = wch->next)
	{
		if (wch == ch)
		{
			char_from_room(ch);
			char_to_room(ch, original);
			for (obj = original->first_content; obj; obj = obj->next_content)
			{
				if (obj == on)
				{
					ch->on = on;
					break;
				}
			}
			break;
		}
	}
	return;
}

/*
 * Lets the mobile transfer people.  The 'all' argument transfers
 *  everyone in the current room to the specified location
 *
 * Syntax: mob transfer [target|'all'] [location]
 */
CH_CMD(do_mptransfer)
{
	char arg1[MIL];
	char arg2[MIL];
	char buf[MSL];
	ROOM_INDEX_DATA *location;
	CHAR_DATA *victim;

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

	if (IS_NULLSTR(arg1))
	{
		bugf("Bad syntax from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if (!str_cmp(arg1, "all"))
	{
		CHAR_DATA *victim_next;

		for (victim = ch->in_room->first_person; victim != NULL;
			 victim = victim_next)
		{
			victim_next = victim->next_in_room;
			if (!IS_NPC(victim))
			{
				sprintf(buf, "%s %s", victim->name, arg2);
				do_function(ch, &do_mptransfer, buf);
			}
		}
		return;
	}

	/*
	 * Thanks to Grodyn for the optional location parameter.
	 */
	if (IS_NULLSTR(arg2))
	{
		location = ch->in_room;
	}
	else
	{
		if ((location = find_location(ch, arg2)) == NULL)
		{
			bugf("No such location from vnum %ld.",
				 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
			return;
		}

		if (room_is_private(location))
			return;
	}

	if ((victim = get_char_world(ch, arg1)) == NULL)
		return;

	if (victim->in_room == NULL)
		return;

	if (victim->fighting != NULL)
		stop_fighting(victim, TRUE);
	char_from_room(victim);
	char_to_room(victim, location);
	do_function(victim, &do_look, "auto");
	if (!IS_NPC(victim))
	{
		p_greet_trigger(victim, PRG_MPROG);
		p_greet_trigger(victim, PRG_OPROG);
		p_greet_trigger(victim, PRG_RPROG);
	}
	return;
}

/*
 * Lets the mobile transfer all chars in same group as the victim.
 *
 * Syntax: mob gtransfer [victim] [location]
 */
CH_CMD(do_mpgtransfer)
{
	char arg1[MIL];
	char arg2[MIL];
	char buf[MSL];
	CHAR_DATA *who, *victim, *victim_next;

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

	if (IS_NULLSTR(arg1))
	{
		bugf("Bad syntax from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if ((who = get_char_room(ch, NULL, arg1)) == NULL)
		return;

	for (victim = ch->in_room->first_person; victim; victim = victim_next)
	{
		victim_next = victim->next_in_room;
		if (is_same_group(who, victim))
		{
			sprintf(buf, "%s %s", victim->name, arg2);
			do_function(ch, &do_mptransfer, buf);
		}
	}
	return;
}

/*
 * Lets the mobile force someone to do something. Must be mortal level
 * and the all argument only affects those in the room with the mobile.
 *
 * Syntax: mob force [victim] [commands]
 */
CH_CMD(do_mpforce)
{
	char arg[MIL];

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
	{
		bugf("Bad syntax from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if (!str_cmp(arg, "all"))
	{
		CHAR_DATA *vch;
		CHAR_DATA *vch_next;

		for (vch = char_first; vch != NULL; vch = vch_next)
		{
			vch_next = vch->next;

			if (vch->in_room == ch->in_room
				&& get_trust(vch) < get_trust(ch) && can_see(ch, vch))
			{
				interpret(vch, argument);
			}
		}
	}
	else
	{
		CHAR_DATA *victim;

		if ((victim = get_char_room(ch, NULL, arg)) == NULL)
			return;

		if (victim == ch)
			return;

		interpret(victim, argument);
	}

	return;
}

/*
 * Lets the mobile force a group something. Must be mortal level.
 *
 * Syntax: mob gforce [victim] [commands]
 */
CH_CMD(do_mpgforce)
{
	char arg[MIL];
	CHAR_DATA *victim, *vch, *vch_next;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
	{
		bugf("Bad syntax from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if ((victim = get_char_room(ch, NULL, arg)) == NULL)
		return;

	if (victim == ch)
		return;

	for (vch = victim->in_room->first_person; vch != NULL; vch = vch_next)
	{
		vch_next = vch->next_in_room;

		if (is_same_group(victim, vch))
		{
			interpret(vch, argument);
		}
	}
	return;
}

/*
 * Forces all mobiles of certain vnum to do something (except ch)
 *
 * Syntax: mob vforce [vnum] [commands]
 */
CH_CMD(do_mpvforce)
{
	CHAR_DATA *victim, *victim_next;
	char arg[MIL];
	vnum_t vnum;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
	{
		bugf("Bad syntax from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if (!is_number(arg))
	{
		bugf("Non-number argument vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	vnum = atol(arg);

	for (victim = char_first; victim; victim = victim_next)
	{
		victim_next = victim->next;
		if (IS_NPC(victim) && victim->pIndexData->vnum == vnum
			&& ch != victim && victim->fighting == NULL)
			interpret(victim, argument);
	}
	return;
}

/*
 * Lets the mobile cast spells --
 * Beware: this does only crude checking on the target validity
 * and does not account for mana etc., so you should do all the
 * necessary checking in your mob program before issuing this cmd!
 *
 * Syntax: mob cast [spell] {target}
 */

CH_CMD(do_mpcast)
{
	CHAR_DATA *vch;
	OBJ_DATA *obj;
	void *victim = NULL;
	char spell[MIL], target[MIL];
	int sn;

	argument = one_argument(argument, spell);
	one_argument(argument, target);

	if (IS_NULLSTR(spell))
	{
		bugf("Bad syntax from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}

	if ((sn = skill_lookup(spell)) == -1)
	{
		bugf("No such spell from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	vch = get_char_room(ch, NULL, target);
	obj = get_obj_here(ch, NULL, target);
	switch (skill_table[sn].target)
	{
	default:
		return;
	case TAR_IGNORE:
		break;
	case TAR_CHAR_OFFENSIVE:
		if (vch == NULL || vch == ch)
			return;
		victim = (void *) vch;
		break;
	case TAR_CHAR_DEFENSIVE:
		victim = vch == NULL ? (void *) ch : (void *) vch;
		break;
	case TAR_CHAR_SELF:
		victim = (void *) ch;
		break;
	case TAR_OBJ_CHAR_DEF:
	case TAR_OBJ_CHAR_OFF:
	case TAR_OBJ_INV:
		if (obj == NULL)
			return;
		victim = (void *) obj;
	}
	(*skill_table[sn].spell_fun) (sn, ch->level, ch, victim,
								  skill_table[sn].target);
	return;
}

/*
 * Lets mob cause unconditional damage to someone. Nasty, use with caution.
 * Also, this is silent, you must show your own damage message...
 *
 * Syntax: mob damage [victim] [min] [max] {kill}
 */
CH_CMD(do_mpdamage)
{
	CHAR_DATA *victim = NULL, *victim_next;
	char target[MIL], min[MIL], max[MIL];
	int low, high;
	bool fAll = FALSE, fKill = FALSE;

	argument = one_argument(argument, target);
	argument = one_argument(argument, min);
	argument = one_argument(argument, max);

	if (target[0] == '\0')
	{
		bugf("Bad syntax from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	if (!str_cmp(target, "all"))
		fAll = TRUE;
	else if ((victim = get_char_room(ch, NULL, target)) == NULL)
		return;

	if (is_number(min))
		low = atoi(min);
	else
	{
		bugf("Bad damage min vnum %ld.", IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	if (is_number(max))
		high = atoi(max);
	else
	{
		bugf("Bad damage max vnum %ld.", IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	one_argument(argument, target);

	/*
	 * If kill parameter is omitted, this command is "safe" and will not
	 * kill the victim.
	 */

	if (target[0] != '\0')
		fKill = TRUE;
	if (fAll)
	{
		for (victim = ch->in_room->first_person; victim; victim = victim_next)
		{
			victim_next = victim->next_in_room;
			if (victim != ch)
				damage(victim, victim,
					   fKill ? number_range(low, high) : UMIN(victim->hit,
															  number_range
															  (low, high)),
					   TYPE_UNDEFINED, DAM_NONE, FALSE);
		}
	}
	else
		damage(victim, victim,
			   fKill ? number_range(low, high) : UMIN(victim->hit,
													  number_range(low,
																   high)),
			   TYPE_UNDEFINED, DAM_NONE, FALSE);
	return;
}

/*
 * Lets the mobile to remember a target. The target can be referred to
 * with $q and $Q codes in MOBprograms. See also "mob forget".
 *
 * Syntax: mob remember [victim]
 */
CH_CMD(do_mpremember)
{
	char arg[MIL];

	one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		ch->mprog_target = get_char_world(ch, arg);
	else
		bugf("missing argument from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
}

/*
 * Reverse of "mob remember".
 *
 * Syntax: mob forget
 */
CH_CMD(do_mpforget)
{
	ch->mprog_target = NULL;
}

/*
 * Sets a delay for MOBprogram execution. When the delay time expires,
 * the mobile is checked for a MObprogram with DELAY trigger, and if
 * one is found, it is executed. Delay is counted in PULSE_MOBILE
 *
 * Syntax: mob delay [pulses]
 */
CH_CMD(do_mpdelay)
{
	char arg[MIL];

	one_argument(argument, arg);
	if (!is_number(arg))
	{
		bugf("invalid arg from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	ch->mprog_delay = atoi(arg);
}

/*
 * Reverse of "mob delay", deactivates the timer.
 *
 * Syntax: mob cancel
 */
CH_CMD(do_mpcancel)
{
	ch->mprog_delay = -1;
}

/*
 * Lets the mobile to call another MOBprogram withing a MOBprogram.
 * This is a crude way to implement subroutines/functions. Beware of
 * nested loops and unwanted triggerings... Stack usage might be a problem.
 * Characters and objects referred to must be in the same room with the
 * mobile.
 *
 * Syntax: mob call [vnum] [victim|'null'] [object1|'null'] [object2|'null']
 *
 */
CH_CMD(do_mpcall)
{
	char arg[MIL];
	CHAR_DATA *vch;
	OBJ_DATA *obj1, *obj2;
	PROG_CODE *prg;

	argument = one_argument(argument, arg);
	if (IS_NULLSTR(arg))
	{
		bugf("missing arguments from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	if ((prg = get_prog_index(atol(arg), PRG_MPROG)) == NULL)
	{
		bugf("invalid prog from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	vch = NULL;
	obj1 = obj2 = NULL;
	argument = one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		vch = get_char_room(ch, NULL, arg);
	argument = one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		obj1 = get_obj_here(ch, NULL, arg);
	argument = one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		obj2 = get_obj_here(ch, NULL, arg);
	program_flow(prg->vnum, prg->code, ch, NULL, NULL, vch, (void *) obj1,
				 (void *) obj2);
}

/*
 * Forces the mobile to flee.
 *
 * Syntax: mob flee
 *
 */
CH_CMD(do_mpflee)
{
	ROOM_INDEX_DATA *was_in;
	EXIT_DATA *pexit;
	int door, attempt;

	if (ch->fighting != NULL)
		return;

	if ((was_in = ch->in_room) == NULL)
		return;

	for (attempt = 0; attempt < MAX_DIR; attempt++)
	{
		door = number_door();
		if ((pexit = was_in->exit[door]) == 0 || pexit->u1.to_room == NULL
			|| IS_SET(pexit->exit_info, EX_CLOSED) || (IS_NPC(ch)
													   &&
													   IS_SET
													   (pexit->u1.
														to_room->room_flags,
														ROOM_NO_MOB)))
			continue;

		move_char(ch, door, TRUE);
		if (ch->in_room != was_in)
			return;
	}
}

/*
 * Lets the mobile to transfer an object. The object must be in the same
 * room with the mobile.
 *
 * Syntax: mob otransfer [item name] [location]
 */
CH_CMD(do_mpotransfer)
{
	OBJ_DATA *obj;
	ROOM_INDEX_DATA *location;
	char arg[MIL];
	char buf[MIL];

	argument = one_argument(argument, arg);
	if (IS_NULLSTR(arg))
	{
		bugf("Missing argument from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	one_argument(argument, buf);
	if ((location = find_location(ch, buf)) == NULL)
	{
		bugf("No such location from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	if ((obj = get_obj_here(ch, NULL, arg)) == NULL)
		return;
	if (obj->carried_by == NULL)
		obj_from_room(obj);
	else
	{
		if (obj->wear_loc != WEAR_NONE)
			unequip_char(ch, obj);
		obj_from_char(obj);
	}
	obj_to_room(obj, location);
}

/*
 * Lets the mobile to strip an object or all objects from the victim.
 * Useful for removing e.g. quest objects from a character.
 *
 * Syntax: mob remove [victim] [object vnum|'all']
 */
CH_CMD(do_mpremove)
{
	CHAR_DATA *victim;
	OBJ_DATA *obj, *obj_next;
	vnum_t vnum = 0;
	bool fAll = FALSE;
	char arg[MIL];

	argument = one_argument(argument, arg);
	if ((victim = get_char_room(ch, NULL, arg)) == NULL)
		return;

	one_argument(argument, arg);
	if (!str_cmp(arg, "all"))
		fAll = TRUE;
	else if (!is_number(arg))
	{
		bugf("Invalid object from vnum %ld.",
			 IS_NPC(ch) ? ch->pIndexData->vnum : 0);
		return;
	}
	else
		vnum = atol(arg);

	for (obj = victim->first_carrying; obj; obj = obj_next)
	{
		obj_next = obj->next_content;
		if (fAll || obj->pIndexData->vnum == vnum)
		{
			unequip_char(victim, obj);
			obj_from_char(obj);
			extract_obj(obj);
		}
	}
}

CH_CMD(do_mppeace)
{
	CHAR_DATA *rch;

	for (rch = ch->in_room->first_person; rch != NULL; rch = rch->next_in_room)
	{
		if (rch->fighting != NULL)
			stop_fighting(rch, TRUE);
		if (IS_NPC(rch) && IS_SET(rch->act, ACT_AGGRESSIVE))
			REMOVE_BIT(rch->act, ACT_AGGRESSIVE);
	}
}

/*
 * OBJprog section
 */
OBJ_CMD(do_obj)
{
	/*
	 * Security check!
	 */
	if (obj->level < MAX_LEVEL)
		return;
	obj_interpret(obj, argument);
}

/*
 * Obj command interpreter. Implemented separately for security and speed
 * reasons. A trivial hack of interpret()
 */
OBJ_CMD(obj_interpret)
{
	char command[MIL];
	int cmd;

	argument = one_argument(argument, command);

	/*
	 * Look for command in command table.
	 */
	for (cmd = 0; !IS_NULLSTR(obj_cmd_table[cmd].name); cmd++)
	{
		if (command[0] == obj_cmd_table[cmd].name[0]
			&& !str_prefix(command, obj_cmd_table[cmd].name))
		{
			(*obj_cmd_table[cmd].obj_fun) (obj, argument);
			tail_chain();
			return;
		}
	}
	bugf("invalid cmd from obj %ld: '%s'", obj->pIndexData->vnum, command);
}

CH_CMD(do_opstat)
{
	char arg[MSL];
	PROG_LIST *oprg;
	OBJ_DATA *obj;
	int i;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
	{
		chprintln(ch, "Opstat what?");
		return;
	}

	if ((obj = get_obj_world(ch, arg)) == NULL)
	{
		chprintln(ch, "No such object.");
		return;
	}

	chprintlnf(ch, "Object #%-6ld [%s]", obj->pIndexData->vnum,
			   obj->short_descr);

	chprintlnf(ch, "Delay   %-6d [%s]", obj->oprog_delay,
			   obj->oprog_target ==
			   NULL ? "No target" : obj->oprog_target->name);

	if (!obj->pIndexData->oprog_flags)
	{
		chprintln(ch, "[No programs set]");
		return;
	}

	for (i = 0, oprg = obj->pIndexData->first_oprog; oprg != NULL;
		 oprg = oprg->next)

	{
		chprintlnf(ch, "[%2d] Trigger [%-8s] Program [%4ld] Phrase [%s]", ++i,
				   prog_type_to_name(oprg->trig_type), oprg->vnum,
				   oprg->trig_phrase);
	}

	return;

}

CH_CMD(do_opdump)
{
	char buf[MIL];
	PROG_CODE *oprg;

	one_argument(argument, buf);
	if ((oprg = get_prog_index(atol(buf), PRG_OPROG)) == NULL)
	{
		chprintln(ch, "No such OBJprogram.");
		return;
	}
	page_to_char(oprg->code, ch);
}

OBJ_CMD(do_opgecho)
{
	DESCRIPTOR_DATA *d;

	if (IS_NULLSTR(argument))
	{
		bugf("missing argument from vnum %ld", obj->pIndexData->vnum);
		return;
	}

	for (d = descriptor_first; d; d = d->next)
	{
		if (d->connected == CON_PLAYING)
		{
			if (IS_IMMORTAL(d->character))
				chprint(d->character, "Obj echo> ");
			chprintln(d->character, argument);
		}
	}
}

OBJ_CMD(do_opzecho)
{
	DESCRIPTOR_DATA *d;

	if (IS_NULLSTR(argument))
	{
		bugf("missing argument from vnum %ld", obj->pIndexData->vnum);
		return;
	}

	if (obj->in_room == NULL
		&& (obj->carried_by == NULL || obj->carried_by->in_room == NULL))
		return;

	for (d = descriptor_first; d; d = d->next)
	{
		if (d->connected == CON_PLAYING && d->character->in_room != NULL
			&&
			((obj->in_room
			  && d->character->in_room->area == obj->in_room->area)
			 || (obj->carried_by
				 && d->character->in_room->area ==
				 obj->carried_by->in_room->area)))
		{
			if (IS_IMMORTAL(d->character))
				chprint(d->character, "Obj echo> ");
			chprintln(d->character, argument);
		}
	}
}

OBJ_CMD(do_opechoaround)
{
	char arg[MIL];
	CHAR_DATA *victim, *vch;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg))
		return;

	if ((victim =
		 get_char_room(NULL,
					   obj->in_room ? obj->in_room : obj->carried_by->in_room,
					   arg)) == NULL)
		return;

	if (obj->in_room && obj->in_room->first_person)
		vch = obj->in_room->first_person;
	else if (obj->carried_by && obj->carried_by->in_room)
		vch = obj->carried_by->in_room->first_person;
	else
		vch = NULL;

	for (; vch; vch = vch->next_in_room)
	{
		if (vch == victim)
			continue;
		chprint(vch, argument);
	}
}

OBJ_CMD(do_opechoat)
{
	char arg[MIL];
	CHAR_DATA *victim;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
		return;

	if ((victim =
		 get_char_room(NULL,
					   obj->in_room ? obj->in_room : obj->carried_by->in_room,
					   arg)) == NULL)
		return;

	act(argument,
		obj->carried_by ? obj->carried_by : obj->in_room->first_person, obj,
		victim, TO_VICT);
}

OBJ_CMD(do_opecho)
{
	if (IS_NULLSTR(argument))
		return;

	if (!obj->carried_by && !obj->in_room->first_person)
		return;

	act(argument,
		obj->carried_by ? obj->carried_by : obj->in_room->first_person, NULL,
		NULL, TO_ROOM);
	act(argument,
		obj->carried_by ? obj->carried_by : obj->in_room->first_person, NULL,
		NULL, TO_CHAR);
}

OBJ_CMD(do_opmload)
{
	char arg[MIL];
	MOB_INDEX_DATA *pMobIndex;
	CHAR_DATA *victim;
	vnum_t vnum;

	one_argument(argument, arg);

	if ((obj->in_room == NULL
		 && (obj->carried_by == NULL || obj->carried_by->in_room == NULL))
		|| IS_NULLSTR(arg) || !is_number(arg))
		return;

	vnum = atol(arg);
	if ((pMobIndex = get_mob_index(vnum)) == NULL)
	{
		bugf("bad mob index (%ld) from obj %ld", vnum, obj->pIndexData->vnum);
		return;
	}
	victim = create_mobile(pMobIndex);
	char_to_room(victim,
				 obj->in_room ? obj->in_room : obj->carried_by->in_room);
	return;
}

OBJ_CMD(do_opoload)
{
	char arg1[MIL];
	char arg2[MIL];
	OBJ_INDEX_DATA *pObjIndex;
	OBJ_DATA *nobj;
	int level;

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

	if (IS_NULLSTR(arg1) || !is_number(arg1))
	{
		bugf("Bad syntax from vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	if (IS_NULLSTR(arg2))
	{
		level = obj->level;
	}
	else
	{

		if (!is_number(arg2))
		{
			bugf("Bad syntax from vnum %ld.", obj->pIndexData->vnum);
			return;
		}
		level = atol(arg2);
		if (level < 0 || level > obj->level)
		{
			bugf("Bad level from vnum %ld.", obj->pIndexData->vnum);
			return;
		}
	}

	if ((pObjIndex = get_obj_index(atol(arg1))) == NULL)
	{
		bugf("Bad vnum arg from vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	nobj = create_object(pObjIndex, level);
	obj_to_room(nobj, obj->in_room ? obj->in_room : obj->carried_by->in_room);

	return;
}

OBJ_CMD(do_oppurge)
{
	char arg[MIL];
	CHAR_DATA *victim;
	OBJ_DATA *vobj;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
	{

		CHAR_DATA *vnext;
		OBJ_DATA *obj_next;

		if (obj->in_room && obj->in_room->first_person)
			victim = obj->in_room->first_person;
		else if (obj->carried_by && obj->carried_by->in_room)
			victim = obj->carried_by->in_room->first_person;
		else
			victim = NULL;

		for (; victim != NULL; victim = vnext)
		{
			vnext = victim->next_in_room;
			if (IS_NPC(victim) && !IS_SET(victim->act, ACT_NOPURGE))
				extract_char(victim, TRUE);
		}

		if (obj->in_room)
			vobj = obj->in_room->first_content;
		else
			vobj = obj->carried_by->in_room->first_content;

		for (; vobj != NULL; vobj = obj_next)
		{
			obj_next = vobj->next_content;
			if (!IS_OBJ_STAT(vobj, ITEM_NOPURGE) && vobj != obj)
				extract_obj(vobj);
		}

		return;
	}

	if ((victim =
		 get_char_room(NULL,
					   obj->in_room ? obj->in_room : obj->carried_by->in_room,
					   arg)) == NULL)
	{
		if ((vobj =
			 get_obj_here(NULL,
						  obj->in_room ? obj->in_room : obj->
						  carried_by->in_room, arg)))
		{
			extract_obj(vobj);
		}
		else if (obj->carried_by
				 && (vobj = get_obj_carry(obj->carried_by, arg, NULL)) != NULL)
		{
			extract_obj(vobj);
		}
		else if (obj->carried_by
				 && (vobj = get_obj_wear(obj->carried_by, arg, FALSE)) != NULL)
		{
			unequip_char(vobj->carried_by, vobj);
			extract_obj(vobj);
		}
		else
		{
			bugf("Bad argument from vnum %ld.", obj->pIndexData->vnum);
		}
		return;
	}

	if (!IS_NPC(victim))
	{
		bugf("Purging a PC from vnum %ld.", obj->pIndexData->vnum);
		return;
	}
	extract_char(victim, TRUE);
	return;
}

OBJ_CMD(do_opgoto)
{
	char arg[MIL];
	ROOM_INDEX_DATA *location;
	CHAR_DATA *victim;
	OBJ_DATA *dobj;

	one_argument(argument, arg);
	if (IS_NULLSTR(arg))
	{
		bugf("No argument from vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	if (is_number(arg))
		location = get_room_index(atol(arg));
	else if ((victim = get_char_world(NULL, arg)) != NULL)
		location = victim->in_room;
	else if ((dobj = get_obj_world(NULL, arg)) != NULL)
		location = dobj->in_room;
	else
	{
		bugf("No such location from vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	if (obj->in_room != NULL)
		obj_from_room(obj);
	else if (obj->carried_by != NULL)
		obj_from_char(obj);
	obj_to_room(obj, location);

	return;
}

OBJ_CMD(do_optransfer)
{
	char arg1[MIL];
	char arg2[MIL];
	char buf[MSL];
	ROOM_INDEX_DATA *location;
	CHAR_DATA *victim;
	OBJ_DATA *dobj;

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

	if (IS_NULLSTR(arg1))
	{
		bugf("Bad syntax from vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	if (!str_cmp(arg1, "all"))
	{
		CHAR_DATA *victim_next;

		if (obj->in_room && obj->in_room->first_person)
			victim = obj->in_room->first_person;
		else if (obj->carried_by)
			victim = obj->carried_by->in_room->first_person;
		else
			victim = NULL;
		for (; victim != NULL; victim = victim_next)
		{
			victim_next = victim->next_in_room;
			if (!IS_NPC(victim))
			{
				sprintf(buf, "%s %s", victim->name, arg2);
				do_optransfer(obj, buf);
			}
		}
		return;
	}

	if (IS_NULLSTR(arg2))
	{
		location = obj->in_room ? obj->in_room : obj->carried_by->in_room;
	}
	else
	{
		if (is_number(arg2))
			location = get_room_index(atol(arg2));
		else if ((victim = get_char_world(NULL, arg2)) != NULL)
			location = victim->in_room;
		else if ((dobj = get_obj_world(NULL, arg2)) != NULL)
			location = dobj->in_room;
		else
		{
			bugf("No such location from vnum %ld.", obj->pIndexData->vnum);
			return;
		}

		if (room_is_private(location))
			return;
	}

	if ((victim = get_char_world(NULL, arg1)) == NULL)
		return;

	if (victim->in_room == NULL)
		return;

	if (victim->fighting != NULL)
		stop_fighting(victim, TRUE);
	char_from_room(victim);
	char_to_room(victim, location);
	do_function(victim, &do_look, "auto");
	if (!IS_NPC(victim))
	{
		p_greet_trigger(victim, PRG_MPROG);
		p_greet_trigger(victim, PRG_OPROG);
		p_greet_trigger(victim, PRG_RPROG);
	}

	return;
}

OBJ_CMD(do_opgtransfer)
{
	char arg1[MIL];
	char arg2[MIL];
	char buf[MSL];
	CHAR_DATA *who, *victim, *victim_next;

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

	if (IS_NULLSTR(arg1))
	{
		bugf("Bad syntax from vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	if ((who =
		 get_char_room(NULL,
					   (obj->in_room) ? obj->in_room : obj->carried_by->in_room,
					   arg1)) == NULL)
		return;

	if (obj->in_room && obj->in_room->first_person)
		victim = obj->in_room->first_person;
	else if (obj->carried_by && obj->carried_by->in_room)
		victim = obj->carried_by->in_room->first_person;
	else
		victim = NULL;

	for (; victim; victim = victim_next)
	{
		victim_next = victim->next_in_room;
		if (is_same_group(who, victim))
		{
			sprintf(buf, "%s %s", victim->name, arg2);
			do_optransfer(obj, buf);
		}
	}
	return;
}

OBJ_CMD(do_opforce)
{
	char arg[MIL];

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
	{
		bugf("Bad syntax from vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	if (!obj->in_room && !obj->carried_by)
		return;
	if (obj->in_room && !obj->in_room->first_person)
		return;
	if (obj->carried_by && !obj->carried_by->in_room)
		return;

	if (!str_cmp(arg, "all"))
	{
		CHAR_DATA *vch;
		CHAR_DATA *vch_next;

		for (vch = char_first; vch != NULL; vch = vch_next)
		{
			vch_next = vch->next;

			if (((obj->in_room && vch->in_room == obj->in_room)
				 || (obj->carried_by
					 && vch->in_room == obj->carried_by->in_room))
				&& get_trust(vch) < obj->level)
			{
				interpret(vch, argument);
			}
		}
	}
	else
	{
		CHAR_DATA *victim;

		if ((victim =
			 get_char_room(NULL,
						   (obj->in_room) ? obj->in_room : obj->
						   carried_by->in_room, arg)) == NULL)
			return;

		interpret(victim, argument);
	}

	return;
}

OBJ_CMD(do_opgforce)
{
	char arg[MIL];
	CHAR_DATA *victim, *vch, *vch_next;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
	{
		bugf("Bad syntax from vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	if ((victim =
		 get_char_room(NULL,
					   obj->in_room ? obj->in_room : obj->carried_by->in_room,
					   arg)) == NULL)
		return;

	for (vch = victim->in_room->first_person; vch != NULL; vch = vch_next)
	{
		vch_next = vch->next_in_room;

		if (is_same_group(victim, vch))
		{
			interpret(vch, argument);
		}
	}
	return;
}

OBJ_CMD(do_opvforce)
{
	CHAR_DATA *victim, *victim_next;
	char arg[MIL];
	vnum_t vnum;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
	{
		bugf("Bad syntax from vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	if (!is_number(arg))
	{
		bugf("Non-number argument vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	vnum = atol(arg);

	for (victim = char_first; victim; victim = victim_next)
	{
		victim_next = victim->next;
		if (IS_NPC(victim) && victim->pIndexData->vnum == vnum
			&& victim->fighting == NULL)
			interpret(victim, argument);
	}
	return;
}

OBJ_CMD(do_opdamage)
{
	CHAR_DATA *victim = NULL, *victim_next;
	char target[MIL], min[MIL], max[MIL];
	int low, high;
	bool fAll = FALSE, fKill = FALSE;

	argument = one_argument(argument, target);
	argument = one_argument(argument, min);
	argument = one_argument(argument, max);

	if (IS_NULLSTR(target))
	{
		bugf("Bad syntax from vnum %ld.", obj->pIndexData->vnum);
		return;
	}
	if (!str_cmp(target, "all"))
		fAll = TRUE;
	else if ((victim =
			  get_char_room(NULL,
							obj->in_room ? obj->in_room : obj->
							carried_by->in_room, target)) == NULL)
		return;

	if (is_number(min))
		low = atoi(min);
	else
	{
		bugf("Bad damage min vnum %ld.", obj->pIndexData->vnum);
		return;
	}
	if (is_number(max))
		high = atoi(max);
	else
	{
		bugf("Bad damage max vnum %ld.", obj->pIndexData->vnum);
		return;
	}
	one_argument(argument, target);

	if (!IS_NULLSTR(target))
		fKill = TRUE;
	if (fAll)
	{
		if (obj->in_room && obj->in_room->first_person)
			victim = obj->in_room->first_person;
		else if (obj->carried_by)
			victim = obj->carried_by->in_room->first_person;
		else
			victim = NULL;

		for (; victim; victim = victim_next)
		{
			victim_next = victim->next_in_room;
			if (obj->carried_by && victim != obj->carried_by)
				damage(victim, victim,
					   fKill ? number_range(low, high) : UMIN(victim->hit,
															  number_range
															  (low, high)),
					   TYPE_UNDEFINED, DAM_NONE, FALSE);
		}
	}
	else
		damage(victim, victim,
			   fKill ? number_range(low, high) : UMIN(victim->hit,
													  number_range(low,
																   high)),
			   TYPE_UNDEFINED, DAM_NONE, FALSE);
	return;
}

OBJ_CMD(do_opremember)
{
	char arg[MIL];

	one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		obj->oprog_target = get_char_world(NULL, arg);
	else
		bugf("missing argument from vnum %ld.", obj->pIndexData->vnum);
}

OBJ_CMD(do_opforget)
{
	obj->oprog_target = NULL;
}

OBJ_CMD(do_opdelay)
{
	char arg[MIL];

	one_argument(argument, arg);
	if (!is_number(arg))
	{
		bugf("invalid arg from vnum %ld.", obj->pIndexData->vnum);
		return;
	}
	obj->oprog_delay = atoi(arg);
}

OBJ_CMD(do_opcancel)
{
	obj->oprog_delay = -1;
}

OBJ_CMD(do_opcall)
{
	char arg[MIL];
	CHAR_DATA *vch;
	OBJ_DATA *obj1, *obj2;
	PROG_CODE *prg;

	argument = one_argument(argument, arg);
	if (IS_NULLSTR(arg))
	{
		bugf("missing arguments from vnum %ld.", obj->pIndexData->vnum);
		return;
	}
	if ((prg = get_prog_index(atol(arg), PRG_OPROG)) == NULL)
	{
		bugf("invalid prog from vnum %ld.", obj->pIndexData->vnum);
		return;
	}
	vch = NULL;
	obj1 = obj2 = NULL;
	argument = one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		vch =
			get_char_room(NULL,
						  obj->in_room ? obj->in_room : obj->
						  carried_by->in_room, arg);
	argument = one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		obj1 =
			get_obj_here(NULL,
						 obj->in_room ? obj->in_room : obj->carried_by->in_room,
						 arg);
	argument = one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		obj2 =
			get_obj_here(NULL,
						 obj->in_room ? obj->in_room : obj->carried_by->in_room,
						 arg);
	program_flow(prg->vnum, prg->code, NULL, obj, NULL, vch, (void *) obj1,
				 (void *) obj2);
}

OBJ_CMD(do_opotransfer)
{
	OBJ_DATA *obj1, *dobj;
	ROOM_INDEX_DATA *location;
	char arg[MIL];
	char buf[MIL];
	CHAR_DATA *victim;

	argument = one_argument(argument, arg);
	if (IS_NULLSTR(arg))
	{
		bugf("Missing argument from vnum %ld.", obj->pIndexData->vnum);
		return;
	}
	one_argument(argument, buf);
	if (is_number(buf))
		location = get_room_index(atol(buf));
	else if ((victim = get_char_world(NULL, buf)) != NULL)
		location = victim->in_room;
	else if ((dobj = get_obj_world(NULL, arg)) != NULL)
		location = dobj->in_room;
	else
	{
		bugf("No such location from vnum %ld.", obj->pIndexData->vnum);
		return;
	}

	if ((obj1 =
		 get_obj_here(NULL,
					  obj->in_room ? obj->in_room : obj->carried_by->in_room,
					  arg)) == NULL)
		return;
	if (obj1->carried_by == NULL)
		obj_from_room(obj1);
	else
	{
		if (obj1->wear_loc != WEAR_NONE)
			unequip_char(obj1->carried_by, obj1);
		obj_from_char(obj1);
	}
	obj_to_room(obj1, location);
}

OBJ_CMD(do_opremove)
{
	CHAR_DATA *victim;
	OBJ_DATA *obj1, *obj_next;
	vnum_t vnum = 0;
	bool fAll = FALSE;
	char arg[MIL];

	argument = one_argument(argument, arg);
	if ((victim =
		 get_char_room(NULL,
					   obj->in_room ? obj->in_room : obj->carried_by->in_room,
					   arg)) == NULL)
		return;

	one_argument(argument, arg);
	if (!str_cmp(arg, "all"))
		fAll = TRUE;
	else if (!is_number(arg))
	{
		bugf("Invalid object from vnum %ld.", obj->pIndexData->vnum);
		return;
	}
	else
		vnum = atol(arg);

	for (obj1 = victim->first_carrying; obj1; obj1 = obj_next)
	{
		obj_next = obj->next_content;
		if (fAll || obj1->pIndexData->vnum == vnum)
		{
			unequip_char(victim, obj1);
			obj_from_char(obj1);
			extract_obj(obj1);
		}
	}
}

OBJ_CMD(do_opattrib)
{
	CHAR_DATA *ch;
	char target[MIL], arg1[MIL], arg2[MIL];
	char arg3[MIL], arg4[MIL], arg5[MIL];
	char arg6[MIL], arg7[MIL];
	char mod, *p;
	int i, level, condition;
	vnum_t value0, value1, value2, value3, value4;

	argument = one_argument(argument, target);
	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);
	one_argument(argument, arg7);

	if (!str_cmp(target, "worn"))
	{
		if (!obj->carried_by)
			return;
		else
			ch = obj->carried_by;
	}
	else if ((ch =
			  get_char_room(NULL,
							obj->in_room ? obj->in_room : obj->
							carried_by->in_room, target)) == NULL)
		return;

	if (!str_cmp(arg1, "none"))
		level = obj->level;
	else if (!isdigit(arg1[0]))
	{
		p = arg1;
		mod = arg1[0];

		for (i = 1; i; i++)
		{
			if (arg1[i] == '\0')
			{
				*p = '\0';
				break;
			}

			*p = arg1[i];
			p++;
		}

		if (!is_number(arg1))
		{
			bugf("received non-number argument from vnum %ld",
				 obj->pIndexData->vnum);
			return;
		}

		switch (mod)
		{
		case '+':
			level = ch->level + atoi(arg1);
			break;
		case '-':
			level = ch->level - atoi(arg1);
			break;
		case '*':
			level = ch->level * atoi(arg1);
			break;
		case '/':
			level = ch->level / atoi(arg1);
			break;
		default:
			bugf("invalid modifier from vnum %ld", obj->pIndexData->vnum);
			return;
		}
	}
	else if (is_number(arg1))
		level = atoi(arg1);
	else
	{
		bugf("received non-number argument from vnum %ld",
			 obj->pIndexData->vnum);
		return;
	}

	if (!str_cmp(arg2, "none"))
		condition = obj->condition;
	else if (!isdigit(arg2[0]))
	{
		p = arg2;
		mod = arg2[0];

		for (i = 1; i; i++)
		{
			if (arg2[i] == '\0')
			{
				*p = '\0';
				break;
			}

			*p = arg2[i];
			p++;
		}

		if (!is_number(arg2))
		{
			bugf("received non-number argument from vnum %ld",
				 obj->pIndexData->vnum);
			return;
		}

		switch (mod)
		{
		case '+':
			condition = ch->level + atoi(arg2);
			break;
		case '-':
			condition = ch->level - atoi(arg2);
			break;
		case '*':
			condition = ch->level * atoi(arg2);
			break;
		case '/':
			condition = ch->level / atoi(arg2);
			break;
		default:
			bugf("invalid modifier from vnum %ld", obj->pIndexData->vnum);
			return;
		}
	}
	else if (is_number(arg2))
		condition = atoi(arg2);
	else
	{
		bugf("received non-number argument from vnum %ld",
			 obj->pIndexData->vnum);
		return;
	}

	if (!str_cmp(arg3, "none"))
		value0 = obj->value[0];
	else if (!isdigit(arg3[0]))
	{
		p = arg3;
		mod = arg3[0];

		for (i = 1; i; i++)
		{
			if (arg3[i] == '\0')
			{
				*p = '\0';
				break;
			}

			*p = arg3[i];
			p++;
		}

		if (!is_number(arg3))
		{
			bugf("received non-number argument from vnum %ld",
				 obj->pIndexData->vnum);
			return;
		}

		switch (mod)
		{
		case '+':
			value0 = ch->level + atol(arg3);
			break;
		case '-':
			value0 = ch->level - atol(arg3);
			break;
		case '*':
			value0 = ch->level * atol(arg3);
			break;
		case '/':
			value0 = ch->level / atol(arg3);
			break;
		default:
			bugf("invalid modifier from vnum %ld", obj->pIndexData->vnum);
			return;
		}
	}
	else if (is_number(arg3))
		value0 = atol(arg3);
	else
	{
		bugf("received non-number argument from vnum %ld",
			 obj->pIndexData->vnum);
		return;
	}

	if (!str_cmp(arg4, "none"))
		value1 = obj->value[1];
	else if (!isdigit(arg4[0]))
	{
		p = arg4;
		mod = arg4[0];

		for (i = 1; i; i++)
		{
			if (arg4[i] == '\0')
			{
				*p = '\0';
				break;
			}

			*p = arg4[i];
			p++;
		}

		if (!is_number(arg4))
		{
			bugf("received non-number argument from vnum %ld",
				 obj->pIndexData->vnum);
			return;
		}

		switch (mod)
		{
		case '+':
			value1 = ch->level + atol(arg4);
			break;
		case '-':
			value1 = ch->level - atol(arg4);
			break;
		case '*':
			value1 = ch->level * atol(arg4);
			break;
		case '/':
			value1 = ch->level / atol(arg4);
			break;
		default:
			bugf("invalid modifier from vnum %ld", obj->pIndexData->vnum);
			return;
		}
	}
	else if (is_number(arg4))
		value1 = atol(arg4);
	else
	{
		bugf("received non-number argument from vnum %ld",
			 obj->pIndexData->vnum);
		return;
	}

	if (!str_cmp(arg5, "none"))
		value2 = obj->value[2];
	else if (!isdigit(arg5[0]))
	{
		p = arg5;
		mod = arg5[0];

		for (i = 1; i; i++)
		{
			if (arg5[i] == '\0')
			{
				*p = '\0';
				break;
			}

			*p = arg5[i];
			p++;
		}

		if (!is_number(arg5))
		{
			bugf("received non-number argument from vnum %ld",
				 obj->pIndexData->vnum);
			return;
		}

		switch (mod)
		{
		case '+':
			value2 = ch->level + atol(arg5);
			break;
		case '-':
			value2 = ch->level - atol(arg5);
			break;
		case '*':
			value2 = ch->level * atol(arg5);
			break;
		case '/':
			value2 = ch->level / atol(arg5);
			break;
		default:
			bugf("invalid modifier from vnum %ld", obj->pIndexData->vnum);
			return;
		}
	}
	else if (is_number(arg5))
		value2 = atol(arg5);
	else
	{
		bugf("received non-number argument from vnum %ld",
			 obj->pIndexData->vnum);
		return;
	}

	if (!str_cmp(arg6, "none"))
		value3 = obj->value[3];
	else if (!isdigit(arg6[0]))
	{
		p = arg6;
		mod = arg6[0];

		for (i = 1; i; i++)
		{
			if (arg6[i] == '\0')
			{
				*p = '\0';
				break;
			}

			*p = arg6[i];
			p++;
		}

		if (!is_number(arg6))
		{
			bugf("received non-number argument from vnum %ld",
				 obj->pIndexData->vnum);
			return;
		}

		switch (mod)
		{
		case '+':
			value3 = ch->level + atol(arg6);
			break;
		case '-':
			value3 = ch->level - atol(arg6);
			break;
		case '*':
			value3 = ch->level * atol(arg6);
			break;
		case '/':
			value3 = ch->level / atol(arg6);
			break;
		default:
			bugf("invalid modifier from vnum %ld", obj->pIndexData->vnum);
			return;
		}
	}
	else if (is_number(arg6))
		value3 = atol(arg6);
	else
	{
		bugf("received non-number argument from vnum %ld",
			 obj->pIndexData->vnum);
		return;
	}

	if (!str_cmp(arg7, "none"))
		value4 = obj->value[4];
	else if (!isdigit(arg7[0]))
	{
		p = arg7;
		mod = arg7[0];

		for (i = 1; i; i++)
		{
			if (arg7[i] == '\0')
			{
				*p = '\0';
				break;
			}

			*p = arg7[i];
			p++;
		}

		if (!is_number(arg7))
		{
			bugf("received non-number argument from vnum %ld",
				 obj->pIndexData->vnum);
			return;
		}

		switch (mod)
		{
		case '+':
			value4 = ch->level + atol(arg7);
			break;
		case '-':
			value4 = ch->level - atol(arg7);
			break;
		case '*':
			value4 = ch->level * atol(arg7);
			break;
		case '/':
			value4 = ch->level / atol(arg7);
			break;
		default:
			bugf("invalid modifier from vnum %ld", obj->pIndexData->vnum);
			return;
		}
	}
	else if (is_number(arg7))
		value4 = atol(arg7);
	else
	{
		bugf("received non-number argument from vnum %ld",
			 obj->pIndexData->vnum);
		return;
	}

	obj->level = level;
	obj->condition = condition;
	obj->value[0] = value0;
	obj->value[1] = value1;
	obj->value[2] = value2;
	obj->value[3] = value3;
	obj->value[4] = value4;
}

OBJ_CMD(do_oppeace)
{
	CHAR_DATA *rch;
	ROOM_INDEX_DATA *room =
		obj->in_room ? obj->in_room : obj->carried_by->in_room;

	for (rch = room->first_person; rch != NULL; rch = rch->next_in_room)
	{
		if (rch->fighting != NULL)
			stop_fighting(rch, TRUE);
		if (IS_NPC(rch) && IS_SET(rch->act, ACT_AGGRESSIVE))
			REMOVE_BIT(rch->act, ACT_AGGRESSIVE);
	}
}

ROOM_CMD(do_room)
{
	room_interpret(room, argument);
}

ROOM_CMD(room_interpret)
{
	char command[MIL];
	int cmd;

	argument = one_argument(argument, command);

	for (cmd = 0; !IS_NULLSTR(room_cmd_table[cmd].name); cmd++)
	{
		if (command[0] == room_cmd_table[cmd].name[0]
			&& !str_prefix(command, room_cmd_table[cmd].name))
		{
			(*room_cmd_table[cmd].room_fun) (room, argument);
			tail_chain();
			return;
		}
	}
	bugf("invalid cmd from room %ld: '%s'", room->vnum, command);
}

CH_CMD(do_rpstat)
{
	char arg[MSL];
	PROG_LIST *rprg;
	ROOM_INDEX_DATA *room;
	int i;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
		room = ch->in_room;
	else if (!is_number(arg))
	{
		chprintln(ch, "You must provide a number.");
		return;
	}
	else if ((room = get_room_index(atol(arg))) == NULL)
	{
		chprintln(ch, "No such room.");
		return;
	}

	chprintlnf(ch, "Room #%-6ld [%s]", room->vnum, room->name);

	chprintlnf(ch, "Delay   %-6d [%s]", room->rprog_delay,
			   room->rprog_target ==
			   NULL ? "No target" : room->rprog_target->name);

	if (!room->rprog_flags)
	{
		chprintln(ch, "[No programs set]");
		return;
	}

	for (i = 0, rprg = room->first_rprog; rprg != NULL; rprg = rprg->next)

	{
		chprintlnf(ch, "[%2d] Trigger [%-8s] Program [%4ld] Phrase [%s]", ++i,
				   prog_type_to_name(rprg->trig_type), rprg->vnum,
				   rprg->trig_phrase);
	}

	return;

}

CH_CMD(do_rpdump)
{
	char buf[MIL];
	PROG_CODE *rprg;

	one_argument(argument, buf);
	if ((rprg = get_prog_index(atol(buf), PRG_RPROG)) == NULL)
	{
		chprintln(ch, "No such ROOMprogram.");
		return;
	}
	page_to_char(rprg->code, ch);
}

ROOM_CMD(do_rpgecho)
{
	DESCRIPTOR_DATA *d;

	if (IS_NULLSTR(argument))
	{
		bugf("missing argument from vnum %ld", room->vnum);
		return;
	}

	for (d = descriptor_first; d; d = d->next)
	{
		if (d->connected == CON_PLAYING)
		{
			if (IS_IMMORTAL(d->character))
				chprint(d->character, "Room echo> ");
			chprintln(d->character, argument);
		}
	}
}

ROOM_CMD(do_rpzecho)
{
	DESCRIPTOR_DATA *d;

	if (IS_NULLSTR(argument))
	{
		bugf("missing argument from vnum %ld", room->vnum);
		return;
	}

	for (d = descriptor_first; d; d = d->next)
	{
		if (d->connected == CON_PLAYING && d->character->in_room != NULL
			&& d->character->in_room->area == room->area)
		{
			if (IS_IMMORTAL(d->character))
				chprint(d->character, "Room echo> ");
			chprintln(d->character, argument);
		}
	}
}

ROOM_CMD(do_rpasound)
{
	int door;

	if (IS_NULLSTR(argument))
		return;

	for (door = 0; door < MAX_DIR; door++)
	{
		EXIT_DATA *pexit;

		if ((pexit = room->exit[door]) != NULL && pexit->u1.to_room != NULL
			&& pexit->u1.to_room != room
			&& pexit->u1.to_room->first_person != NULL)
		{
			act(argument, pexit->u1.to_room->first_person, NULL, NULL, TO_ROOM);
			act(argument, pexit->u1.to_room->first_person, NULL, NULL, TO_CHAR);
		}
	}
	return;

}

ROOM_CMD(do_rpechoaround)
{
	char arg[MIL];
	CHAR_DATA *victim;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg))
		return;

	if ((victim = get_char_room(NULL, room, arg)) == NULL)
		return;

	act(argument, victim, NULL, victim, TO_NOTVICT);
}

ROOM_CMD(do_rpechoat)
{
	char arg[MIL];
	CHAR_DATA *victim;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
		return;

	if ((victim = get_char_room(NULL, room, arg)) == NULL)
		return;

	act(argument, victim, NULL, NULL, TO_CHAR);
}

ROOM_CMD(do_rpecho)
{
	if (IS_NULLSTR(argument))
		return;

	if (!room->first_person)
		return;

	act(argument, room->first_person, NULL, NULL, TO_ROOM);
	act(argument, room->first_person, NULL, NULL, TO_CHAR);
}

ROOM_CMD(do_rpmload)
{
	char arg[MIL];
	MOB_INDEX_DATA *pMobIndex;
	CHAR_DATA *victim;
	vnum_t vnum;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg) || !is_number(arg))
		return;

	vnum = atol(arg);
	if ((pMobIndex = get_mob_index(vnum)) == NULL)
	{
		bugf("bad mob index (%ld) from room %ld", vnum, room->vnum);
		return;
	}
	victim = create_mobile(pMobIndex);
	char_to_room(victim, room);
	return;
}

ROOM_CMD(do_rpoload)
{
	char arg1[MIL];
	char arg2[MIL];
	char arg3[MIL];
	OBJ_INDEX_DATA *pObjIndex;
	OBJ_DATA *obj;
	int level;

	argument = one_argument(argument, arg1);
	argument = one_argument(argument, arg2);
	one_argument(argument, arg3);

	if (IS_NULLSTR(arg1) || !is_number(arg1) || IS_NULLSTR(arg2)
		|| !is_number(arg2))
	{
		bugf("Bad syntax from vnum %ld.", room->vnum);
		return;
	}

	level = atoi(arg2);
	if (level < 0 || level > LEVEL_IMMORTAL)
	{
		bugf("Bad level from vnum %ld.", room->vnum);
		return;
	}

	if ((pObjIndex = get_obj_index(atol(arg1))) == NULL)
	{
		bugf("Bad vnum arg from vnum %ld.", room->vnum);
		return;
	}

	obj = create_object(pObjIndex, level);
	obj_to_room(obj, room);

	return;
}

ROOM_CMD(do_rppurge)
{
	char arg[MIL];
	CHAR_DATA *victim;
	OBJ_DATA *obj;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
	{

		CHAR_DATA *vnext;
		OBJ_DATA *obj_next;

		for (victim = room->first_person; victim != NULL; victim = vnext)
		{
			vnext = victim->next_in_room;
			if (IS_NPC(victim) && !IS_SET(victim->act, ACT_NOPURGE))
				extract_char(victim, TRUE);
		}

		for (obj = room->first_content; obj != NULL; obj = obj_next)
		{
			obj_next = obj->next_content;
			if (!IS_OBJ_STAT(obj, ITEM_NOPURGE))
				extract_obj(obj);
		}

		return;
	}

	if ((victim = get_char_room(NULL, room, arg)) == NULL)
	{
		if ((obj = get_obj_here(NULL, room, arg)))
		{
			extract_obj(obj);
		}
		else
		{
			bugf("Bad argument from vnum %ld.", room->vnum);
		}
		return;
	}

	if (!IS_NPC(victim))
	{
		bugf("Purging a PC from vnum %ld.", room->vnum);
		return;
	}
	extract_char(victim, TRUE);
	return;
}

ROOM_CMD(do_rptransfer)
{
	char arg1[MIL];
	char arg2[MIL];
	char buf[MSL];
	ROOM_INDEX_DATA *location;
	CHAR_DATA *victim;
	OBJ_DATA *tobj;

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

	if (IS_NULLSTR(arg1))
	{
		bugf("Bad syntax from vnum %ld.", room->vnum);
		return;
	}

	if (!str_cmp(arg1, "all"))
	{
		CHAR_DATA *victim_next;

		for (victim = room->first_person; victim != NULL; victim = victim_next)
		{
			victim_next = victim->next_in_room;
			if (!IS_NPC(victim))
			{
				sprintf(buf, "%s %s", victim->name, arg2);
				do_rptransfer(room, buf);
			}
		}
		return;
	}

	if (IS_NULLSTR(arg2))
	{
		location = room;
	}
	else
	{
		if (is_number(arg2))
			location = get_room_index(atol(arg2));
		else if ((victim = get_char_world(NULL, arg2)) != NULL)
			location = victim->in_room;
		else if ((tobj = get_obj_world(NULL, arg2)) != NULL)
			location = tobj->in_room;
		else
		{
			bugf("No such location from vnum %ld.", room->vnum);
			return;
		}

		if (room_is_private(location))
			return;
	}

	if ((victim = get_char_world(NULL, arg1)) == NULL)
		return;

	if (victim->in_room == NULL)
		return;

	if (victim->fighting != NULL)
		stop_fighting(victim, TRUE);
	char_from_room(victim);
	char_to_room(victim, location);
	do_function(victim, &do_look, "auto");
	if (!IS_NPC(victim))
	{
		p_greet_trigger(victim, PRG_MPROG);
		p_greet_trigger(victim, PRG_OPROG);
		p_greet_trigger(victim, PRG_RPROG);
	}

	return;
}

ROOM_CMD(do_rpgtransfer)
{
	char arg1[MIL];
	char arg2[MIL];
	char buf[MSL];
	CHAR_DATA *who, *victim, *victim_next;

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

	if (IS_NULLSTR(arg1))
	{
		bugf("Bad syntax from vnum %ld.", room->vnum);
		return;
	}

	if ((who = get_char_room(NULL, room, arg1)) == NULL)
		return;

	for (victim = room->first_person; victim; victim = victim_next)
	{
		victim_next = victim->next_in_room;
		if (is_same_group(who, victim))
		{
			sprintf(buf, "%s %s", victim->name, arg2);
			do_rptransfer(room, buf);
		}
	}
	return;
}

ROOM_CMD(do_rpforce)
{
	char arg[MIL];

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
	{
		bugf("Bad syntax from vnum %ld.", room->vnum);
		return;
	}

	if (!str_cmp(arg, "all"))
	{
		CHAR_DATA *vch;
		CHAR_DATA *vch_next;

		for (vch = char_first; vch != NULL; vch = vch_next)
		{
			vch_next = vch->next;

			if (vch->in_room == room && !IS_IMMORTAL(vch))
				interpret(vch, argument);
		}
	}
	else
	{
		CHAR_DATA *victim;

		if ((victim = get_char_room(NULL, room, arg)) == NULL)
			return;

		interpret(victim, argument);
	}

	return;
}

ROOM_CMD(do_rpgforce)
{
	char arg[MIL];
	CHAR_DATA *victim, *vch, *vch_next;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
	{
		bugf("Bad syntax from vnum %ld.", room->vnum);
		return;
	}

	if ((victim = get_char_room(NULL, room, arg)) == NULL)
		return;

	for (vch = victim->in_room->first_person; vch != NULL; vch = vch_next)
	{
		vch_next = vch->next_in_room;

		if (is_same_group(victim, vch))
			interpret(vch, argument);
	}
	return;
}

ROOM_CMD(do_rpvforce)
{
	CHAR_DATA *victim, *victim_next;
	char arg[MIL];
	vnum_t vnum;

	argument = one_argument(argument, arg);

	if (IS_NULLSTR(arg) || IS_NULLSTR(argument))
	{
		bugf("Bad syntax from vnum %ld.", room->vnum);
		return;
	}

	if (!is_number(arg))
	{
		bugf("Non-number argument vnum %ld.", room->vnum);
		return;
	}

	vnum = atol(arg);

	for (victim = char_first; victim; victim = victim_next)
	{
		victim_next = victim->next;
		if (IS_NPC(victim) && victim->pIndexData->vnum == vnum
			&& victim->fighting == NULL)
			interpret(victim, argument);
	}
	return;
}

ROOM_CMD(do_rpdamage)
{
	CHAR_DATA *victim = NULL, *victim_next;
	char target[MIL], min[MIL], max[MIL];
	int low, high;
	bool fAll = FALSE, fKill = FALSE;

	argument = one_argument(argument, target);
	argument = one_argument(argument, min);
	argument = one_argument(argument, max);

	if (IS_NULLSTR(target))
	{
		bugf("Bad syntax from vnum %ld.", room->vnum);
		return;
	}
	if (!str_cmp(target, "all"))
		fAll = TRUE;
	else if ((victim = get_char_room(NULL, room, target)) == NULL)
		return;

	if (is_number(min))
		low = atoi(min);
	else
	{
		bugf("Bad damage min vnum %ld.", room->vnum);
		return;
	}
	if (is_number(max))
		high = atoi(max);
	else
	{
		bugf("Bad damage max vnum %ld.", room->vnum);
		return;
	}
	one_argument(argument, target);

	if (!IS_NULLSTR(target))
		fKill = TRUE;
	if (fAll)
	{
		for (victim = room->first_person; victim; victim = victim_next)
		{
			victim_next = victim->next_in_room;
			damage(victim, victim,
				   fKill ? number_range(low, high) : UMIN(victim->hit,
														  number_range
														  (low, high)),
				   TYPE_UNDEFINED, DAM_NONE, FALSE);
		}
	}
	else
		damage(victim, victim,
			   fKill ? number_range(low, high) : UMIN(victim->hit,
													  number_range(low,
																   high)),
			   TYPE_UNDEFINED, DAM_NONE, FALSE);
	return;
}

ROOM_CMD(do_rpremember)
{
	char arg[MIL];

	one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		room->rprog_target = get_char_world(NULL, arg);
	else
		bugf("missing argument from vnum %ld.", room->vnum);
}

ROOM_CMD(do_rpforget)
{
	room->rprog_target = NULL;
}

ROOM_CMD(do_rpdelay)
{
	char arg[MIL];

	one_argument(argument, arg);
	if (!is_number(arg))
	{
		bugf("invalid arg from vnum %ld.", room->vnum);
		return;
	}
	room->rprog_delay = atoi(arg);
}

ROOM_CMD(do_rpcancel)
{
	room->rprog_delay = -1;
}

ROOM_CMD(do_rpcall)
{
	char arg[MIL];
	CHAR_DATA *vch;
	OBJ_DATA *obj1, *obj2;
	PROG_CODE *prg;

	argument = one_argument(argument, arg);
	if (IS_NULLSTR(arg))
	{
		bugf("missing arguments from vnum %ld.", room->vnum);
		return;
	}
	if ((prg = get_prog_index(atol(arg), PRG_RPROG)) == NULL)
	{
		bugf("invalid prog from vnum %ld.", room->vnum);
		return;
	}
	vch = NULL;
	obj1 = obj2 = NULL;
	argument = one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		vch = get_char_room(NULL, room, arg);
	argument = one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		obj1 = get_obj_here(NULL, room, arg);
	argument = one_argument(argument, arg);
	if (!IS_NULLSTR(arg))
		obj2 = get_obj_here(NULL, room, arg);
	program_flow(prg->vnum, prg->code, NULL, NULL, room, vch, (void *) obj1,
				 (void *) obj2);
}

ROOM_CMD(do_rpotransfer)
{
	OBJ_DATA *obj, *tobj;
	ROOM_INDEX_DATA *location;
	char arg[MIL];
	char buf[MIL];
	CHAR_DATA *victim;

	argument = one_argument(argument, arg);
	if (IS_NULLSTR(arg))
	{
		bugf("Missing argument from vnum %ld.", room->vnum);
		return;
	}
	one_argument(argument, buf);

	if (is_number(buf))
		location = get_room_index(atol(buf));
	else if ((victim = get_char_world(NULL, buf)) != NULL)
		location = victim->in_room;
	else if ((tobj = get_obj_world(NULL, arg)) != NULL)
		location = tobj->in_room;
	else
	{
		bugf("No such location from vnum %ld.", room->vnum);
		return;
	}

	if ((obj = get_obj_here(NULL, room, arg)) == NULL)
		return;

	if (obj->carried_by == NULL)
		obj_from_room(obj);
	else
	{
		if (obj->wear_loc != WEAR_NONE)
			unequip_char(obj->carried_by, obj);
		obj_from_char(obj);
	}
	obj_to_room(obj, location);
}

ROOM_CMD(do_rpremove)
{
	CHAR_DATA *victim;
	OBJ_DATA *obj, *obj_next;
	vnum_t vnum = 0;
	bool fAll = FALSE;
	char arg[MIL];

	argument = one_argument(argument, arg);
	if ((victim = get_char_room(NULL, room, arg)) == NULL)
		return;

	one_argument(argument, arg);
	if (!str_cmp(arg, "all"))
		fAll = TRUE;
	else if (!is_number(arg))
	{
		bugf("Invalid object from vnum %ld.", room->vnum);
		return;
	}
	else
		vnum = atol(arg);

	for (obj = victim->first_carrying; obj; obj = obj_next)
	{
		obj_next = obj->next_content;
		if (fAll || obj->pIndexData->vnum == vnum)
		{
			unequip_char(victim, obj);
			obj_from_char(obj);
			extract_obj(obj);
		}
	}
}

ROOM_CMD(do_rppeace)
{
	CHAR_DATA *rch;

	for (rch = room->first_person; rch != NULL; rch = rch->next_in_room)
	{
		if (rch->fighting != NULL)
			stop_fighting(rch, TRUE);
		if (IS_NPC(rch) && IS_SET(rch->act, ACT_AGGRESSIVE))
			REMOVE_BIT(rch->act, ACT_AGGRESSIVE);
	}
}