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>                   *
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *  MOBprograms for ROM 2.4 v0.98g (C) M.Nylander 1996                     *
 *  Based on MERC 2.2 MOBprograms concept by N'Atas-ha.                    *
 *  Written and adapted to ROM 2.4 by                                      *
 *          Markku Nylander (markku.nylander@uta.fi)                       *
 *  This code may be copied and distributed as per the ROM license.        *
 *                                                                         *
 ***************************************************************************/

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

int call_level = 0;

CH_CMD(do_mpreset)
{
	call_level = 0;
	chprintln(ch, "MAX_CALL_LEVEL reset. Fix the bugged Mprogram.");
	return;
}

#define    CHK_RAND    (0)
#define    CHK_MOBHERE     (1)
#define    CHK_OBJHERE     (2)
#define    CHK_MOBEXISTS   (3)
#define    CHK_OBJEXISTS   (4)
#define    CHK_PEOPLE      (5)
#define    CHK_PLAYERS     (6)
#define    CHK_MOBS        (7)
#define    CHK_CLONES      (8)
#define    CHK_ORDER       (9)
#define    CHK_HOUR        (10)
#define    CHK_ISPC        (11)
#define    CHK_ISNPC       (12)
#define    CHK_ISGOOD      (13)
#define    CHK_ISEVIL      (14)
#define    CHK_ISNEUTRAL   (15)
#define    CHK_ISIMMORT    (16)
#define    CHK_ISCHARM     (17)
#define    CHK_ISFOLLOW    (18)
#define    CHK_ISACTIVE    (19)
#define    CHK_ISDELAY     (20)
#define    CHK_ISVISIBLE   (21)
#define    CHK_HASTARGET   (22)
#define    CHK_ISTARGET    (23)
#define    CHK_AFFECTED    (24)
#define    CHK_ACT         (25)
#define    CHK_OFF         (26)
#define    CHK_IMM         (27)
#define    CHK_CARRIES     (28)
#define    CHK_WEARS       (20)
#define    CHK_HAS         (30)
#define    CHK_USES        (31)
#define    CHK_NAME        (32)
#define    CHK_POS         (33)
#define    CHK_CLAN        (34)
#define    CHK_RACE        (35)
#define    CHK_CLASS       (36)
#define    CHK_OBJTYPE     (37)
#define    CHK_VNUM        (38)
#define    CHK_HPCNT       (39)
#define    CHK_ROOM        (40)
#define    CHK_SEX         (41)
#define    CHK_LEVEL       (42)
#define    CHK_ALIGN       (43)
#define    CHK_MONEY       (44)
#define    CHK_OBJVAL0     (45)
#define    CHK_OBJVAL1     (46)
#define    CHK_OBJVAL2     (47)
#define    CHK_OBJVAL3     (48)
#define    CHK_OBJVAL4     (49)
#define    CHK_GRPSIZE     (50)
#define    CHK_ONQUEST     (52)
#define    CHK_HUNTER      (55)
#define    CHK_PLR         (57)
#define    CHK_SKILL       (58)
#define    CHK_WEIGHT      (60)

#define    EVAL_EQ            0
#define    EVAL_GE            1
#define    EVAL_LE            2
#define    EVAL_GT            3
#define    EVAL_LT            4
#define    EVAL_NE            5

const char *fn_keyword[] = {
	"rand",
	"mobhere",
	"objhere",
	"mobexists",
	"objexists",
	"people",
	"players",
	"mobs",
	"clones",
	"order",
	"hour",
	"ispc",
	"isnpc",
	"isgood",
	"isevil",
	"isneutral",
	"isimmort",
	"ischarm",
	"isfollow",
	"isactive",
	"isdelay",
	"isvisible",
	"hastarget",
	"istarget",
	"affected",
	"act",
	"off",
	"imm",
	"carries",
	"wears",
	"has",
	"uses",
	"name",
	"pos",
	"clan",
	"race",
	"class",
	"objtype",
	"vnum",
	"hpcnt",
	"room",
	"sex",
	"level",
	"align",
	"money",
	"objval0",
	"objval1",
	"objval2",
	"objval3",
	"objval4",
	"grpsize",
	"onquest",
	"hunter",
	"plr",
	"skill",
	"weight",
	"\n"
};

const char *fn_evals[] = {
	"==",
	">=",
	"<=",
	">",
	"<",
	"!=",
	"\n"
};

int keyword_lookup(const char **table, char *keyword)
{
	register int i;

	for (i = 0; table[i][0] != '\n'; i++)
		if (!str_cmp(table[i], keyword))
			return (i);
	return -1;
}

int num_eval(int lval, int oper, int rval)
{
	switch (oper)
	{
	case EVAL_EQ:
		return (lval == rval);
	case EVAL_GE:
		return (lval >= rval);
	case EVAL_LE:
		return (lval <= rval);
	case EVAL_NE:
		return (lval != rval);
	case EVAL_GT:
		return (lval > rval);
	case EVAL_LT:
		return (lval < rval);
	default:
		bug("invalid oper", 0);
		return 0;
	}
}

CHAR_DATA *get_random_char(CHAR_DATA * mob, OBJ_DATA * obj,
						   ROOM_INDEX_DATA * room)
{
	CHAR_DATA *vch, *victim = NULL;
	int now = 0, highest = 0;

	if ((mob && obj) || (mob && room) || (obj && room))
	{
		bug("received multiple prog types", 0);
		return NULL;
	}

	if (mob)
		vch = mob->in_room->first_person;
	else if (obj)
	{
		if (obj->in_room)
			vch = obj->in_room->first_person;
		else
			vch = obj->carried_by->in_room->first_person;
	}
	else
		vch = room->first_person;

	for (; vch; vch = vch->next_in_room)
	{
		if (mob && mob != vch && !IS_NPC(vch) && can_see(mob, vch)
			&& (now = number_percent()) > highest)
		{
			victim = vch;
			highest = now;
		}
		else if ((now = number_percent()) > highest)
		{
			victim = vch;
			highest = now;
		}
	}
	return victim;
}

int count_people_room(CHAR_DATA * mob, OBJ_DATA * obj,
					  ROOM_INDEX_DATA * room, int iFlag)
{
	CHAR_DATA *vch;
	int count;

	if ((mob && obj) || (mob && room) || (obj && room))
	{
		bug("received multiple prog types", 0);
		return 0;
	}

	if (mob)
		vch = mob->in_room->first_person;
	else if (obj)
	{
		if (obj->in_room)
			vch = obj->in_room->first_person;
		else
			vch = obj->carried_by->in_room->first_person;
	}
	else
		vch = room->first_person;

	for (count = 0; vch; vch = vch->next_in_room)
	{
		if (mob)
		{
			if (mob != vch
				&& (iFlag == 0 || (iFlag == 1 && !IS_NPC(vch))
					|| (iFlag == 2 && IS_NPC(vch)) || (iFlag == 3
													   && IS_NPC(mob)
													   && IS_NPC(vch)
													   && mob->pIndexData->
													   vnum ==
													   vch->pIndexData->vnum)
					|| (iFlag == 4 && is_same_group(mob, vch)))
				&& can_see(mob, vch))
				count++;
		}
		else if (obj || room)
		{
			if (iFlag == 0 || (iFlag == 1 && !IS_NPC(vch))
				|| (iFlag == 2 && IS_NPC(vch)))
				count++;
		}
	}

	return (count);
}

int get_order(CHAR_DATA * ch, OBJ_DATA * obj)
{
	CHAR_DATA *vch;
	OBJ_DATA *vobj;
	int i;

	if (ch && obj)
	{
		bug("received multiple prog types", 0);
		return 0;
	}

	if (ch && !IS_NPC(ch))
		return 0;

	if (ch)
	{
		vch = ch->in_room->first_person;
		vobj = NULL;
	}
	else
	{
		vch = NULL;
		if (obj->in_room)
			vobj = obj->in_room->first_content;
		else if (obj->carried_by->in_room->first_content)
			vobj = obj->carried_by->in_room->first_content;
		else
			vobj = NULL;
	}

	if (ch)
		for (i = 0; vch; vch = vch->next_in_room)
		{
			if (vch == ch)
				return i;

			if (IS_NPC(vch) && vch->pIndexData->vnum == ch->pIndexData->vnum)
				i++;
		}
	else
		for (i = 0; vobj; vobj = vobj->next_content)
		{
			if (vobj == obj)
				return i;

			if (vobj->pIndexData->vnum == obj->pIndexData->vnum)
				i++;
		}

	return 0;
}

bool has_item(CHAR_DATA * ch, vnum_t vnum, int pitem_type, bool fWear)
{
	OBJ_DATA *obj;

	for (obj = ch->first_carrying; obj; obj = obj->next_content)
		if ((vnum < 0 || obj->pIndexData->vnum == vnum)
			&& (pitem_type < 0 || obj->pIndexData->item_type == pitem_type)
			&& (!fWear || obj->wear_loc != WEAR_NONE))
			return TRUE;
	return FALSE;
}

bool get_mob_vnum_room(CHAR_DATA * ch, OBJ_DATA * obj,
					   ROOM_INDEX_DATA * room, vnum_t vnum)
{
	CHAR_DATA *mob;

	if ((ch && obj) || (ch && room) || (obj && room))
	{
		bug("received multiple prog types", 0);
		return FALSE;
	}

	if (ch)
		mob = ch->in_room->first_person;
	else if (obj)
	{
		if (obj->in_room)
			mob = obj->in_room->first_person;
		else
			mob = obj->carried_by->in_room->first_person;
	}
	else
		mob = room->first_person;

	for (; mob; mob = mob->next_in_room)
		if (IS_NPC(mob) && mob->pIndexData->vnum == vnum)
			return TRUE;
	return FALSE;
}

bool get_obj_vnum_room(CHAR_DATA * ch, OBJ_DATA * obj,
					   ROOM_INDEX_DATA * room, vnum_t vnum)
{
	OBJ_DATA *vobj;

	if ((ch && obj) || (ch && room) || (obj && room))
	{
		bug("received multiple prog types", 0);
		return FALSE;
	}

	if (ch)
		vobj = ch->in_room->first_content;
	else if (obj)
	{
		if (obj->in_room)
			vobj = obj->in_room->first_content;
		else
			vobj = obj->carried_by->in_room->first_content;
	}
	else
		vobj = room->first_content;

	for (; vobj; vobj = vobj->next_content)
		if (vobj->pIndexData->vnum == vnum)
			return TRUE;
	return FALSE;
}

int cmd_eval_mob(vnum_t vnum, const char *line, int check, CHAR_DATA * mob,
				 CHAR_DATA * ch, const void *arg1, const void *arg2,
				 CHAR_DATA * rch)
{
	CHAR_DATA *lval_char = mob;
	CHAR_DATA *vch = (CHAR_DATA *) arg2;
	OBJ_DATA *obj1 = (OBJ_DATA *) arg1;
	OBJ_DATA *obj2 = (OBJ_DATA *) arg2;
	OBJ_DATA *lval_obj = NULL;
	const char *original;
	char buf[MIL], code;
	int lval = 0, oper = 0, rval = -1;

	original = line;
	line = one_argument(line, buf);
	if (IS_NULLSTR(buf) || mob == NULL)
		return FALSE;

	if (mob->mprog_target == NULL)
		mob->mprog_target = ch;

	switch (check)
	{

	case CHK_RAND:
		return (number_percent() < atoi(buf));
	case CHK_MOBHERE:
		if (is_number(buf))
			return (get_mob_vnum_room(mob, NULL, NULL, atol(buf)));
		else
			return ((bool) (get_char_room(mob, NULL, buf) != NULL));
	case CHK_OBJHERE:
		if (is_number(buf))
			return (get_obj_vnum_room(mob, NULL, NULL, atol(buf)));
		else
			return ((bool) (get_obj_here(mob, NULL, buf) != NULL));
	case CHK_MOBEXISTS:
		return ((bool) (get_char_world(mob, buf) != NULL));
	case CHK_OBJEXISTS:
		return ((bool) (get_obj_world(mob, buf) != NULL));

	case CHK_PEOPLE:
		rval = count_people_room(mob, NULL, NULL, 0);
		break;
	case CHK_PLAYERS:
		rval = count_people_room(mob, NULL, NULL, 1);
		break;
	case CHK_MOBS:
		rval = count_people_room(mob, NULL, NULL, 2);
		break;
	case CHK_CLONES:
		rval = count_people_room(mob, NULL, NULL, 3);
		break;
	case CHK_ORDER:
		rval = get_order(mob, NULL);
		break;
	case CHK_HOUR:
		rval = time_info.hour;
		break;
	default:;
	}

	if (rval >= 0)
	{
		if ((oper = keyword_lookup(fn_evals, buf)) < 0)
		{
			bugf("prog %ld syntax error(2) '%s'", vnum, original);
			return FALSE;
		}
		one_argument(line, buf);
		lval = rval;
		rval = atoi(buf);
		return (num_eval(lval, oper, rval));
	}

	if (buf[0] != '$' || buf[1] == '\0')
	{
		bugf("prog %ld syntax error(3) '%s'", vnum, original);
		return FALSE;
	}
	else
		code = buf[1];
	switch (code)
	{
	case 'i':
		lval_char = mob;
		break;
	case 'n':
		lval_char = ch;
		break;
	case 't':
		lval_char = vch;
		break;
	case 'r':
		lval_char = rch == NULL ? get_random_char(mob, NULL, NULL) : rch;
		break;
	case 'o':
		lval_obj = obj1;
		break;
	case 'p':
		lval_obj = obj2;
		break;
	case 'q':
		lval_char = mob->mprog_target;
		break;
	default:
		bugf("prog %ld syntax error(4) '%s'", vnum, original);
		return FALSE;
	}

	if (lval_char == NULL && lval_obj == NULL)
		return FALSE;

	switch (check)
	{
	case CHK_ISPC:
		return (lval_char != NULL && !IS_NPC(lval_char));
	case CHK_ISNPC:
		return (lval_char != NULL && IS_NPC(lval_char));
	case CHK_ISGOOD:
		return (lval_char != NULL && IS_GOOD(lval_char));
	case CHK_ISEVIL:
		return (lval_char != NULL && IS_EVIL(lval_char));
	case CHK_ISNEUTRAL:
		return (lval_char != NULL && IS_NEUTRAL(lval_char));
	case CHK_ISIMMORT:
		return (lval_char != NULL && IS_IMMORTAL(lval_char));
	case CHK_HUNTER:
		return (lval_char != NULL && lval_char->hunting == mob);
	case CHK_ISCHARM:

		return (lval_char != NULL && IS_AFFECTED(lval_char, AFF_CHARM));
	case CHK_ISFOLLOW:
		return (lval_char != NULL && lval_char->master != NULL
				&& lval_char->master->in_room == lval_char->in_room);
	case CHK_ONQUEST:
		return (lval_char != NULL && IS_QUESTOR(lval_char));
	case CHK_ISACTIVE:
		return (lval_char != NULL && lval_char->position > POS_SLEEPING);
	case CHK_ISDELAY:
		return (lval_char != NULL && lval_char->mprog_delay > 0);
	case CHK_ISVISIBLE:
		switch (code)
		{
		default:
		case 'i':
		case 'n':
		case 't':
		case 'r':
		case 'q':
			return (lval_char != NULL && can_see(mob, lval_char));
		case 'o':
		case 'p':
			return (lval_obj != NULL && can_see_obj(mob, lval_obj));
		}
	case CHK_HASTARGET:
		return (lval_char != NULL && lval_char->mprog_target != NULL
				&& lval_char->in_room == lval_char->mprog_target->in_room);
	case CHK_ISTARGET:
		return (lval_char != NULL && mob->mprog_target == lval_char);
	default:;
	}

	line = one_argument(line, buf);
	switch (check)
	{
	case CHK_AFFECTED:
		return (lval_char != NULL
				&& IS_AFFECTED(lval_char, flag_value(affect_flags, buf)));
	case CHK_ACT:
		return (lval_char != NULL
				&& IS_NPC(lval_char)
				&& IS_SET(lval_char->act, flag_value(act_flags, buf)));
	case CHK_PLR:
		return (lval_char != NULL
				&& !IS_NPC(lval_char)
				&& IS_SET(lval_char->act, flag_value(plr_flags, buf)));
	case CHK_IMM:
		return (lval_char != NULL
				&& IS_SET(lval_char->imm_flags, flag_value(imm_flags, buf)));
	case CHK_OFF:
		return (lval_char != NULL
				&& IS_SET(lval_char->off_flags, flag_value(off_flags, buf)));
	case CHK_CARRIES:
		if (is_number(buf))
			return (lval_char != NULL
					&& has_item(lval_char, atol(buf), -1, FALSE));
		else
			return (lval_char != NULL
					&& (get_obj_carry(lval_char, buf, lval_char) != NULL));
	case CHK_WEARS:
		if (is_number(buf))
			return (lval_char != NULL
					&& has_item(lval_char, atol(buf), -1, TRUE));
		else
			return (lval_char != NULL
					&& (get_obj_wear(lval_char, buf, TRUE) != NULL));
	case CHK_HAS:
		return (lval_char != NULL
				&& has_item(lval_char, -1, item_lookup(buf), FALSE));
	case CHK_USES:
		return (lval_char != NULL
				&& has_item(lval_char, -1, item_lookup(buf), TRUE));
	case CHK_SKILL:
		return (lval_char != NULL && !IS_NPC(lval_char)
				&& skill_lookup(buf) != -1
				&& get_skill(lval_char, skill_lookup(buf)) >= atoi(line));
	case CHK_NAME:
		switch (code)
		{
		default:
		case 'i':
		case 'n':
		case 't':
		case 'r':
		case 'q':
			return (lval_char != NULL && is_name(buf, lval_char->name));
		case 'o':
		case 'p':
			return (lval_obj != NULL && is_name(buf, lval_obj->name));
		}
	case CHK_POS:
		return (lval_char != NULL
				&& lval_char->position == position_lookup(buf));
	case CHK_CLAN:
		return (lval_char != NULL && lval_char->clan == clan_lookup(buf));
	case CHK_CLASS:
		return (lval_char != NULL && lval_char->Class[0] == class_lookup(buf));
	case CHK_RACE:
		return (lval_char != NULL && lval_char->race == race_lookup(buf));
	case CHK_OBJTYPE:
		return (lval_obj != NULL && lval_obj->item_type == item_lookup(buf));
	default:;
	}

	if ((oper = keyword_lookup(fn_evals, buf)) < 0)
	{
		bugf("prog %ld syntax error(5): '%s'", vnum, original);
		return FALSE;
	}
	one_argument(line, buf);
	rval = atoi(buf);

	switch (check)
	{
	case CHK_VNUM:
		switch (code)
		{
		default:
		case 'i':
		case 'n':
		case 't':
		case 'r':
		case 'q':
			if (lval_char != NULL && IS_NPC(lval_char))
				lval = lval_char->pIndexData->vnum;
			break;
		case 'o':
		case 'p':
			if (lval_obj != NULL)
				lval = lval_obj->pIndexData->vnum;
		}
		break;
	case CHK_HPCNT:
		if (lval_char != NULL)
			lval = (lval_char->hit * 100) / (UMAX(1, lval_char->max_hit));
		break;
	case CHK_ROOM:
		if (lval_char != NULL && lval_char->in_room != NULL)
			lval = lval_char->in_room->vnum;
		break;
	case CHK_SEX:
		if (lval_char != NULL)
			lval = lval_char->sex;
		break;
	case CHK_LEVEL:
		if (lval_char != NULL)
			lval = lval_char->level;
		break;
	case CHK_WEIGHT:
		if (lval_char != NULL)
			lval = get_carry_weight(lval_char);
		break;
	case CHK_ALIGN:
		if (lval_char != NULL)
			lval = lval_char->alignment;
		break;
	case CHK_MONEY:
		if (lval_char != NULL)
			lval = lval_char->gold;
		break;
	case CHK_OBJVAL0:
		if (lval_obj != NULL)
			lval = lval_obj->value[0];
		break;
	case CHK_OBJVAL1:
		if (lval_obj != NULL)
			lval = lval_obj->value[1];
		break;
	case CHK_OBJVAL2:
		if (lval_obj != NULL)
			lval = lval_obj->value[2];
		break;
	case CHK_OBJVAL3:
		if (lval_obj != NULL)
			lval = lval_obj->value[3];
		break;
	case CHK_OBJVAL4:
		if (lval_obj != NULL)
			lval = lval_obj->value[4];
		break;
	case CHK_GRPSIZE:
		if (lval_char != NULL)
			lval = count_people_room(lval_char, NULL, NULL, 4);
		break;
	default:
		return FALSE;
	}
	return (num_eval(lval, oper, rval));
}

int cmd_eval_obj(vnum_t vnum, const char *line, int check, OBJ_DATA * obj,
				 CHAR_DATA * ch, const void *arg1, const void *arg2,
				 CHAR_DATA * rch)
{
	CHAR_DATA *lval_char = NULL;
	CHAR_DATA *vch = (CHAR_DATA *) arg2;
	OBJ_DATA *obj1 = (OBJ_DATA *) arg1;
	OBJ_DATA *obj2 = (OBJ_DATA *) arg2;
	OBJ_DATA *lval_obj = obj;
	const char *original;
	char buf[MIL], code;
	int lval = 0, oper = 0, rval = -1;

	original = line;
	line = one_argument(line, buf);
	if (IS_NULLSTR(buf) || obj == NULL)
		return FALSE;

	if (obj->oprog_target == NULL)
		obj->oprog_target = ch;

	switch (check)
	{

	case CHK_RAND:
		return (number_percent() < atoi(buf));
	case CHK_MOBHERE:
		if (is_number(buf))
			return (get_mob_vnum_room(NULL, obj, NULL, atol(buf)));
		else
			return ((bool)
					(get_char_room
					 (NULL,
					  (obj->in_room ? obj->in_room : obj->carried_by->in_room),
					  buf) != NULL));
	case CHK_OBJHERE:
		if (is_number(buf))
			return (get_obj_vnum_room(NULL, obj, NULL, atol(buf)));
		else
			return ((bool)
					(get_obj_here
					 (NULL,
					  (obj->in_room ? obj->in_room : obj->carried_by->in_room),
					  buf) != NULL));
	case CHK_MOBEXISTS:
		return ((bool) (get_char_world(NULL, buf) != NULL));
	case CHK_OBJEXISTS:
		return ((bool) (get_obj_world(NULL, buf) != NULL));

	case CHK_PEOPLE:
		rval = count_people_room(NULL, obj, NULL, 0);
		break;
	case CHK_PLAYERS:
		rval = count_people_room(NULL, obj, NULL, 1);
		break;
	case CHK_MOBS:
		rval = count_people_room(NULL, obj, NULL, 2);
		break;
	case CHK_CLONES:
		bug("cmd_eval_obj: received CHK_CLONES.", 0);
		break;
	case CHK_ORDER:
		rval = get_order(NULL, obj);
		break;
	case CHK_HOUR:
		rval = time_info.hour;
		break;
	default:;
	}

	if (rval >= 0)
	{
		if ((oper = keyword_lookup(fn_evals, buf)) < 0)
		{
			bugf("Cmd_eval_obj: prog %ld syntax error(2) '%s'", vnum, original);
			return FALSE;
		}
		one_argument(line, buf);
		lval = rval;
		rval = atoi(buf);
		return (num_eval(lval, oper, rval));
	}

	if (buf[0] != '$' || buf[1] == '\0')
	{
		bugf("Cmd_eval_obj: prog %ld syntax error(3) '%s'", vnum, original);
		return FALSE;
	}
	else
		code = buf[1];
	switch (code)
	{
	case 'i':
		lval_obj = obj;
		break;
	case 'n':
		lval_char = ch;
		break;
	case 't':
		lval_char = vch;
		break;
	case 'r':
		lval_char = rch == NULL ? get_random_char(NULL, obj, NULL) : rch;
		break;
	case 'o':
		lval_obj = obj1;
		break;
	case 'p':
		lval_obj = obj2;
		break;
	case 'q':
		lval_char = obj->oprog_target;
		break;
	default:
		bugf("Cmd_eval_obj: prog %ld syntax error(4) '%s'", vnum, original);
		return FALSE;
	}

	if (lval_char == NULL && lval_obj == NULL)
		return FALSE;

	switch (check)
	{
	case CHK_ISPC:
		return (lval_char != NULL && !IS_NPC(lval_char));
	case CHK_ISNPC:
		return (lval_char != NULL && IS_NPC(lval_char));
	case CHK_ISGOOD:
		return (lval_char != NULL && IS_GOOD(lval_char));
	case CHK_ISEVIL:
		return (lval_char != NULL && IS_EVIL(lval_char));
	case CHK_ISNEUTRAL:
		return (lval_char != NULL && IS_NEUTRAL(lval_char));
	case CHK_ISIMMORT:
		return (lval_char != NULL && IS_IMMORTAL(lval_char));
	case CHK_ISCHARM:

		return (lval_char != NULL && IS_AFFECTED(lval_char, AFF_CHARM));
	case CHK_ISFOLLOW:
		return (lval_char != NULL && lval_char->master != NULL
				&& lval_char->master->in_room == lval_char->in_room);
	case CHK_ISACTIVE:
		return (lval_char != NULL && lval_char->position > POS_SLEEPING);
	case CHK_ISDELAY:
		return (lval_char != NULL && lval_char->mprog_delay > 0);
	case CHK_HASTARGET:
		return (lval_char != NULL && lval_char->mprog_target != NULL
				&& lval_char->in_room == lval_char->mprog_target->in_room);
	case CHK_ISTARGET:
		return (lval_char != NULL && obj->oprog_target == lval_char);
	default:;
	}

	line = one_argument(line, buf);
	switch (check)
	{
	case CHK_AFFECTED:
		return (lval_char != NULL
				&& IS_AFFECTED(lval_char, flag_value(affect_flags, buf)));
	case CHK_ACT:
		return (lval_char != NULL
				&& IS_NPC(lval_char)
				&& IS_SET(lval_char->act, flag_value(act_flags, buf)));
	case CHK_PLR:
		return (lval_char != NULL
				&& !IS_NPC(lval_char)
				&& IS_SET(lval_char->act, flag_value(plr_flags, buf)));
	case CHK_IMM:
		return (lval_char != NULL
				&& IS_SET(lval_char->imm_flags, flag_value(imm_flags, buf)));
	case CHK_OFF:
		return (lval_char != NULL
				&& IS_SET(lval_char->off_flags, flag_value(off_flags, buf)));
	case CHK_CARRIES:
		if (is_number(buf))
			return (lval_char != NULL
					&& has_item(lval_char, atol(buf), -1, FALSE));
		else
			return (lval_char != NULL
					&& (get_obj_carry(lval_char, buf, lval_char) != NULL));
	case CHK_WEARS:
		if (is_number(buf))
			return (lval_char != NULL
					&& has_item(lval_char, atol(buf), -1, TRUE));
		else
			return (lval_char != NULL
					&& (get_obj_wear(lval_char, buf, FALSE) != NULL));
	case CHK_HAS:
		return (lval_char != NULL
				&& has_item(lval_char, -1, item_lookup(buf), FALSE));
	case CHK_USES:
		return (lval_char != NULL
				&& has_item(lval_char, -1, item_lookup(buf), TRUE));
	case CHK_SKILL:
		return (lval_char != NULL && !IS_NPC(lval_char)
				&& skill_lookup(buf) != -1
				&& get_skill(lval_char, skill_lookup(buf)) >= atoi(line));
	case CHK_NAME:
		switch (code)
		{
		default:
		case 'n':
		case 't':
		case 'r':
		case 'q':
			return (lval_char != NULL && is_name(buf, lval_char->name));
		case 'i':
		case 'o':
		case 'p':
			return (lval_obj != NULL && is_name(buf, lval_obj->name));
		}
	case CHK_POS:
		return (lval_char != NULL
				&& lval_char->position == position_lookup(buf));
	case CHK_CLAN:
		return (lval_char != NULL && lval_char->clan == clan_lookup(buf));
	case CHK_CLASS:
		return (lval_char != NULL && lval_char->Class[0] == class_lookup(buf));
	case CHK_RACE:
		return (lval_char != NULL && lval_char->race == race_lookup(buf));
	case CHK_OBJTYPE:
		return (lval_obj != NULL && lval_obj->item_type == item_lookup(buf));
	default:;
	}

	if ((oper = keyword_lookup(fn_evals, buf)) < 0)
	{
		bugf("Cmd_eval_obj: prog %ld syntax error(5): '%s'", vnum, original);
		return FALSE;
	}
	one_argument(line, buf);
	rval = atoi(buf);

	switch (check)
	{
	case CHK_VNUM:
		switch (code)
		{
		default:
		case 'n':
		case 't':
		case 'r':
		case 'q':
			if (lval_char != NULL && IS_NPC(lval_char))
				lval = lval_char->pIndexData->vnum;
			break;
		case 'i':
		case 'o':
		case 'p':
			if (lval_obj != NULL)
				lval = lval_obj->pIndexData->vnum;
		}
		break;
	case CHK_HPCNT:
		if (lval_char != NULL)
			lval = (lval_char->hit * 100) / (UMAX(1, lval_char->max_hit));
		break;
	case CHK_ROOM:
		if (lval_char != NULL && lval_char->in_room != NULL)
			lval = lval_char->in_room->vnum;
		else if (lval_obj != NULL
				 && (lval_obj->in_room != NULL || lval_obj->carried_by != NULL))
			lval =
				lval_obj->in_room ? lval_obj->in_room->
				vnum : lval_obj->carried_by->in_room->vnum;
		break;
	case CHK_SEX:
		if (lval_char != NULL)
			lval = lval_char->sex;
		break;
	case CHK_LEVEL:
		if (lval_char != NULL)
			lval = lval_char->level;
		break;
	case CHK_WEIGHT:
		if (lval_char != NULL)
			lval = get_carry_weight(lval_char);
		break;
	case CHK_ALIGN:
		if (lval_char != NULL)
			lval = lval_char->alignment;
		break;
	case CHK_MONEY:
		if (lval_char != NULL)
			lval = lval_char->gold;
		break;
	case CHK_OBJVAL0:
		if (lval_obj != NULL)
			lval = lval_obj->value[0];
		break;
	case CHK_OBJVAL1:
		if (lval_obj != NULL)
			lval = lval_obj->value[1];
		break;
	case CHK_OBJVAL2:
		if (lval_obj != NULL)
			lval = lval_obj->value[2];
		break;
	case CHK_OBJVAL3:
		if (lval_obj != NULL)
			lval = lval_obj->value[3];
		break;
	case CHK_OBJVAL4:
		if (lval_obj != NULL)
			lval = lval_obj->value[4];
		break;
	case CHK_GRPSIZE:
		if (lval_char != NULL)
			lval = count_people_room(lval_char, NULL, NULL, 4);
		break;
	default:
		return FALSE;
	}
	return (num_eval(lval, oper, rval));
}

int cmd_eval_room(vnum_t vnum, const char *line, int check,
				  ROOM_INDEX_DATA * room, CHAR_DATA * ch, const void *arg1,
				  const void *arg2, CHAR_DATA * rch)
{
	CHAR_DATA *lval_char = NULL;
	CHAR_DATA *vch = (CHAR_DATA *) arg2;
	OBJ_DATA *obj1 = (OBJ_DATA *) arg1;
	OBJ_DATA *obj2 = (OBJ_DATA *) arg2;
	OBJ_DATA *lval_obj = NULL;
	const char *original;
	char buf[MIL], code;
	int lval = 0, oper = 0, rval = -1;

	original = line;
	line = one_argument(line, buf);
	if (IS_NULLSTR(buf) || room == NULL)
		return FALSE;

	if (room->rprog_target == NULL)
		room->rprog_target = ch;

	switch (check)
	{

	case CHK_RAND:
		return (number_percent() < atoi(buf));
	case CHK_MOBHERE:
		if (is_number(buf))
			return (get_mob_vnum_room(NULL, NULL, room, atol(buf)));
		else
			return ((bool) (get_char_room(NULL, room, buf) != NULL));
	case CHK_OBJHERE:
		if (is_number(buf))
			return (get_obj_vnum_room(NULL, NULL, room, atol(buf)));
		else
			return ((bool) (get_obj_here(NULL, room, buf) != NULL));
	case CHK_MOBEXISTS:
		return ((bool) (get_char_world(NULL, buf) != NULL));
	case CHK_OBJEXISTS:
		return ((bool) (get_obj_world(NULL, buf) != NULL));

	case CHK_PEOPLE:
		rval = count_people_room(NULL, NULL, room, 0);
		break;
	case CHK_PLAYERS:
		rval = count_people_room(NULL, NULL, room, 1);
		break;
	case CHK_MOBS:
		rval = count_people_room(NULL, NULL, room, 2);
		break;
	case CHK_CLONES:
		bug("received CHK_CLONES.", 0);
		break;
	case CHK_ORDER:
		bug("received CHK_ORDER.", 0);
		break;
	case CHK_HOUR:
		rval = time_info.hour;
		break;
	default:;
	}

	if (rval >= 0)
	{
		if ((oper = keyword_lookup(fn_evals, buf)) < 0)
		{
			bugf("prog %ld syntax error(2) '%s'", vnum, original);
			return FALSE;
		}
		one_argument(line, buf);
		lval = rval;
		rval = atoi(buf);
		return (num_eval(lval, oper, rval));
	}

	if (buf[0] != '$' || buf[1] == '\0')
	{
		bugf("prog %ld syntax error(3) '%s'", vnum, original);
		return FALSE;
	}
	else
		code = buf[1];
	switch (code)
	{
	case 'i':
		bug("received code case 'i'.", 0);
		break;
	case 'n':
		lval_char = ch;
		break;
	case 't':
		lval_char = vch;
		break;
	case 'r':
		lval_char = rch == NULL ? get_random_char(NULL, NULL, room) : rch;
		break;
	case 'o':
		lval_obj = obj1;
		break;
	case 'p':
		lval_obj = obj2;
		break;
	case 'q':
		lval_char = room->rprog_target;
		break;
	default:
		bugf("prog %ld syntax error(4) '%s'", vnum, original);
		return FALSE;
	}

	if (lval_char == NULL && lval_obj == NULL)
		return FALSE;

	switch (check)
	{
	case CHK_ISPC:
		return (lval_char != NULL && !IS_NPC(lval_char));
	case CHK_ISNPC:
		return (lval_char != NULL && IS_NPC(lval_char));
	case CHK_ISGOOD:
		return (lval_char != NULL && IS_GOOD(lval_char));
	case CHK_ISEVIL:
		return (lval_char != NULL && IS_EVIL(lval_char));
	case CHK_ISNEUTRAL:
		return (lval_char != NULL && IS_NEUTRAL(lval_char));
	case CHK_ISIMMORT:
		return (lval_char != NULL && IS_IMMORTAL(lval_char));
	case CHK_ISCHARM:

		return (lval_char != NULL && IS_AFFECTED(lval_char, AFF_CHARM));
	case CHK_ISFOLLOW:
		return (lval_char != NULL && lval_char->master != NULL
				&& lval_char->master->in_room == lval_char->in_room);
	case CHK_ISACTIVE:
		return (lval_char != NULL && lval_char->position > POS_SLEEPING);
	case CHK_ISDELAY:
		return (lval_char != NULL && lval_char->mprog_delay > 0);
	case CHK_HASTARGET:
		return (lval_char != NULL && lval_char->mprog_target != NULL
				&& lval_char->in_room == lval_char->mprog_target->in_room);
	case CHK_ISTARGET:
		return (lval_char != NULL && room->rprog_target == lval_char);
	default:;
	}

	line = one_argument(line, buf);
	switch (check)
	{
	case CHK_AFFECTED:
		return (lval_char != NULL
				&& IS_AFFECTED(lval_char, flag_value(affect_flags, buf)));
	case CHK_ACT:
		return (lval_char != NULL
				&& IS_NPC(lval_char)
				&& IS_SET(lval_char->act, flag_value(act_flags, buf)));
	case CHK_PLR:
		return (lval_char != NULL
				&& !IS_NPC(lval_char)
				&& IS_SET(lval_char->act, flag_value(plr_flags, buf)));
	case CHK_IMM:
		return (lval_char != NULL
				&& IS_SET(lval_char->imm_flags, flag_value(imm_flags, buf)));
	case CHK_OFF:
		return (lval_char != NULL
				&& IS_SET(lval_char->off_flags, flag_value(off_flags, buf)));
	case CHK_CARRIES:
		if (is_number(buf))
			return (lval_char != NULL
					&& has_item(lval_char, atol(buf), -1, FALSE));
		else
			return (lval_char != NULL
					&& (get_obj_carry(lval_char, buf, lval_char) != NULL));
	case CHK_WEARS:
		if (is_number(buf))
			return (lval_char != NULL
					&& has_item(lval_char, atol(buf), -1, TRUE));
		else
			return (lval_char != NULL
					&& (get_obj_wear(lval_char, buf, FALSE) != NULL));
	case CHK_HAS:
		return (lval_char != NULL
				&& has_item(lval_char, -1, item_lookup(buf), FALSE));
	case CHK_USES:
		return (lval_char != NULL
				&& has_item(lval_char, -1, item_lookup(buf), TRUE));
	case CHK_SKILL:
		return (lval_char != NULL && !IS_NPC(lval_char)
				&& skill_lookup(buf) != -1
				&& get_skill(lval_char, skill_lookup(buf)) >= atoi(line));
	case CHK_NAME:
		switch (code)
		{
		default:
		case 'n':
		case 't':
		case 'r':
		case 'q':
			return (lval_char != NULL && is_name(buf, lval_char->name));
		case 'i':
			return FALSE;
		case 'o':
		case 'p':
			return (lval_obj != NULL && is_name(buf, lval_obj->name));
		}
	case CHK_POS:
		return (lval_char != NULL
				&& lval_char->position == position_lookup(buf));
	case CHK_CLAN:
		return (lval_char != NULL && lval_char->clan == clan_lookup(buf));
	case CHK_CLASS:
		return (lval_char != NULL && lval_char->Class[0] == class_lookup(buf));
	case CHK_RACE:
		return (lval_char != NULL && lval_char->race == race_lookup(buf));
	case CHK_OBJTYPE:
		return (lval_obj != NULL && lval_obj->item_type == item_lookup(buf));
	default:;
	}

	if ((oper = keyword_lookup(fn_evals, buf)) < 0)
	{
		bugf("prog %ld syntax error(5): '%s'", vnum, original);
		return FALSE;
	}
	one_argument(line, buf);
	rval = atoi(buf);

	switch (check)
	{
	case CHK_VNUM:
		switch (code)
		{
		default:
		case 'n':
		case 't':
		case 'r':
		case 'q':
			if (lval_char != NULL && IS_NPC(lval_char))
				lval = lval_char->pIndexData->vnum;
			break;
		case 'i':
			return FALSE;
		case 'o':
		case 'p':
			if (lval_obj != NULL)
				lval = lval_obj->pIndexData->vnum;
		}
		break;
	case CHK_HPCNT:
		if (lval_char != NULL)
			lval = (lval_char->hit * 100) / (UMAX(1, lval_char->max_hit));
		break;
	case CHK_ROOM:
		if (lval_char != NULL && lval_char->in_room != NULL)
			lval = lval_char->in_room->vnum;
		else if (lval_obj != NULL
				 && (lval_obj->in_room != NULL || lval_obj->carried_by != NULL))
			lval =
				lval_obj->in_room ? lval_obj->in_room->
				vnum : lval_obj->carried_by->in_room->vnum;
		break;
	case CHK_SEX:
		if (lval_char != NULL)
			lval = lval_char->sex;
		break;
	case CHK_LEVEL:
		if (lval_char != NULL)
			lval = lval_char->level;
		break;
	case CHK_WEIGHT:
		if (lval_char != NULL)
			lval = get_carry_weight(lval_char);
		break;
	case CHK_ALIGN:
		if (lval_char != NULL)
			lval = lval_char->alignment;
		break;
	case CHK_MONEY:
		if (lval_char != NULL)
			lval = lval_char->gold;
		break;
	case CHK_OBJVAL0:
		if (lval_obj != NULL)
			lval = lval_obj->value[0];
		break;
	case CHK_OBJVAL1:
		if (lval_obj != NULL)
			lval = lval_obj->value[1];
		break;
	case CHK_OBJVAL2:
		if (lval_obj != NULL)
			lval = lval_obj->value[2];
		break;
	case CHK_OBJVAL3:
		if (lval_obj != NULL)
			lval = lval_obj->value[3];
		break;
	case CHK_OBJVAL4:
		if (lval_obj != NULL)
			lval = lval_obj->value[4];
		break;
	case CHK_GRPSIZE:
		if (lval_char != NULL)
			lval = count_people_room(lval_char, NULL, NULL, 4);
		break;
	default:
		return FALSE;
	}
	return (num_eval(lval, oper, rval));
}

void expand_arg_mob(char *buf, const char *format, CHAR_DATA * mob,
					CHAR_DATA * ch, const void *arg1, const void *arg2,
					CHAR_DATA * rch)
{
	static char *const he_she[] = { "it", "he", "she" };
	static char *const him_her[] = { "it", "him", "her" };
	static char *const his_her[] = { "its", "his", "her" };
	const char *someone = "someone";
	const char *something = "something";
	const char *someones = "someone's";

	char name[MIL];
	CHAR_DATA *vch = (CHAR_DATA *) arg2;
	OBJ_DATA *obj1 = (OBJ_DATA *) arg1;
	OBJ_DATA *obj2 = (OBJ_DATA *) arg2;
	const char *str;
	const char *i;
	char *point;

	if (IS_NULLSTR(format))
		return;

	point = buf;
	str = format;
	while (*str != '\0')
	{
		if (*str != '$')
		{
			*point++ = *str++;
			continue;
		}
		++str;

		switch (*str)
		{
		default:
			bugf("bad code %c.", *str);
			i = " <@@@> ";
			break;
		case 'i':
			one_argument(mob->name, name);
			i = name;
			break;
		case 'I':
			i = mob->short_descr;
			break;
		case 'n':
			i = someone;
			if (ch != NULL && can_see(mob, ch))
			{
				one_argument(ch->name, name);
				i = capitalize(name);
			}
			break;
		case 'N':
			i = (ch != NULL
				 && can_see(mob,
							ch)) ? (IS_NPC(ch) ? ch->
									short_descr : ch->name) : someone;
			break;
		case 't':
			i = someone;
			if (vch != NULL && can_see(mob, vch))
			{
				one_argument(vch->name, name);
				i = capitalize(name);
			}
			break;
		case 'T':
			i = (vch != NULL
				 && can_see(mob,
							vch)) ? (IS_NPC(vch) ? vch->
									 short_descr : vch->name) : someone;
			break;
		case 'r':
			if (rch == NULL)
				rch = get_random_char(mob, NULL, NULL);
			i = someone;
			if (rch != NULL && can_see(mob, rch))
			{
				one_argument(rch->name, name);
				i = capitalize(name);
			}
			break;
		case 'R':
			if (rch == NULL)
				rch = get_random_char(mob, NULL, NULL);
			i = (rch != NULL
				 && can_see(mob,
							rch)) ? (IS_NPC(ch) ? ch->
									 short_descr : ch->name) : someone;
			break;
		case 'q':
			i = someone;
			if (mob->mprog_target != NULL && can_see(mob, mob->mprog_target))
			{
				one_argument(mob->mprog_target->name, name);
				i = capitalize(name);
			}
			break;
		case 'Q':
			i = (mob->mprog_target != NULL
				 && can_see(mob,
							mob->mprog_target)) ? (IS_NPC(mob->mprog_target) ?
												   mob->
												   mprog_target->short_descr :
												   mob->mprog_target->
												   name) : someone;
			break;
		case 'j':
			i = he_she[URANGE(0, mob->sex, 2)];
			break;
		case 'e':
			i = (ch != NULL
				 && can_see(mob, ch)) ? he_she[URANGE(0, ch->sex, 2)] : someone;
			break;
		case 'E':
			i = (vch != NULL
				 && can_see(mob, vch)) ? he_she[URANGE(0, vch->sex,
													   2)] : someone;
			break;
		case 'J':
			i = (rch != NULL
				 && can_see(mob, rch)) ? he_she[URANGE(0, rch->sex,
													   2)] : someone;
			break;
		case 'X':
			i = (mob->mprog_target != NULL
				 && can_see(mob, mob->mprog_target)) ? he_she[URANGE(0,
																	 mob->mprog_target->sex,
																	 2)] :
				someone;
			break;
		case 'k':
			i = him_her[URANGE(0, mob->sex, 2)];
			break;
		case 'm':
			i = (ch != NULL
				 && can_see(mob, ch)) ? him_her[URANGE(0, ch->sex,
													   2)] : someone;
			break;
		case 'M':
			i = (vch != NULL
				 && can_see(mob, vch)) ? him_her[URANGE(0, vch->sex,
														2)] : someone;
			break;
		case 'K':
			if (rch == NULL)
				rch = get_random_char(mob, NULL, NULL);
			i = (rch != NULL
				 && can_see(mob, rch)) ? him_her[URANGE(0, rch->sex,
														2)] : someone;
			break;
		case 'Y':
			i = (mob->mprog_target != NULL
				 && can_see(mob, mob->mprog_target)) ? him_her[URANGE(0,
																	  mob->mprog_target->sex,
																	  2)] :
				someone;
			break;
		case 'l':
			i = his_her[URANGE(0, mob->sex, 2)];
			break;
		case 's':
			i = (ch != NULL
				 && can_see(mob, ch)) ? his_her[URANGE(0, ch->sex,
													   2)] : someones;
			break;
		case 'S':
			i = (vch != NULL
				 && can_see(mob, vch)) ? his_her[URANGE(0, vch->sex,
														2)] : someones;
			break;
		case 'L':
			if (rch == NULL)
				rch = get_random_char(mob, NULL, NULL);
			i = (rch != NULL
				 && can_see(mob, rch)) ? his_her[URANGE(0, rch->sex,
														2)] : someones;
			break;
		case 'Z':
			i = (mob->mprog_target != NULL
				 && can_see(mob, mob->mprog_target)) ? his_her[URANGE(0,
																	  mob->mprog_target->sex,
																	  2)] :
				someones;
			break;
		case 'o':
			i = something;
			if (obj1 != NULL && can_see_obj(mob, obj1))
			{
				one_argument(obj1->name, name);
				i = name;
			}
			break;
		case 'O':
			i = (obj1 != NULL
				 && can_see_obj(mob, obj1)) ? obj1->short_descr : something;
			break;
		case 'p':
			i = something;
			if (obj2 != NULL && can_see_obj(mob, obj2))
			{
				one_argument(obj2->name, name);
				i = name;
			}
			break;
		case 'P':
			i = (obj2 != NULL
				 && can_see_obj(mob, obj2)) ? obj2->short_descr : something;
			break;
		}

		++str;
		while ((*point = *i) != '\0')
			++point, ++i;

	}
	*point = '\0';

	return;
}

void expand_arg_other(char *buf, const char *format, OBJ_DATA * obj,
					  ROOM_INDEX_DATA * room, CHAR_DATA * ch,
					  const void *arg1, const void *arg2, CHAR_DATA * rch)
{
	static char *const he_she[] = { "it", "he", "she" };
	static char *const him_her[] = { "it", "him", "her" };
	static char *const his_her[] = { "its", "his", "her" };
	const char *someone = "someone";
	const char *something = "something";
	const char *someones = "someone's";

	char name[MIL];
	CHAR_DATA *vch = (CHAR_DATA *) arg2;
	OBJ_DATA *obj1 = (OBJ_DATA *) arg1;
	OBJ_DATA *obj2 = (OBJ_DATA *) arg2;
	const char *str;
	const char *i;
	char *point;

	if (obj && room)
	{
		bug("received a obj and a room", 0);
		return;
	}

	if (IS_NULLSTR(format))
		return;

	point = buf;
	str = format;
	while (*str != '\0')
	{
		if (*str != '$')
		{
			*point++ = *str++;
			continue;
		}
		++str;

		switch (*str)
		{
		default:
			bugf("bad code %c.", *str);
			i = " <@@@> ";
			break;
		case 'i':
			if (obj)
			{
				one_argument(obj->name, name);
				i = name;
			}
			else
			{
				bug("room had an \"i\" case.", 0);
				i = " <@@@> ";
			}
			break;
		case 'I':
			if (obj)
				i = obj->short_descr;
			else
			{
				bug("room had an \"I\" case.", 0);
				i = " <@@@> ";
			}
			break;
		case 'n':
			i = someone;
			if (ch != NULL)
			{
				one_argument(ch->name, name);
				i = capitalize(name);
			}
			break;
		case 'N':
			i = (ch !=
				 NULL) ? (IS_NPC(ch) ? ch->short_descr : ch->name) : someone;
			break;
		case 't':
			i = someone;
			if (vch != NULL)
			{
				one_argument(vch->name, name);
				i = capitalize(name);
			}
			break;
		case 'T':
			i = (vch !=
				 NULL) ? (IS_NPC(vch) ? vch->short_descr : vch->name) : someone;
			break;
		case 'r':
			if (rch == NULL && obj)
				rch = get_random_char(NULL, obj, NULL);
			else if (rch == NULL && room)
				rch = get_random_char(NULL, NULL, room);
			i = someone;
			if (rch != NULL)
			{
				one_argument(rch->name, name);
				i = capitalize(name);
			}
			break;
		case 'R':
			if (rch == NULL && obj)
				rch = get_random_char(NULL, obj, NULL);
			else if (rch == NULL && room)
				rch = get_random_char(NULL, NULL, room);
			i = (rch !=
				 NULL) ? (IS_NPC(ch) ? ch->short_descr : ch->name) : someone;
			break;
		case 'q':
			i = someone;
			if (obj && obj->oprog_target != NULL)
			{
				one_argument(obj->oprog_target->name, name);
				i = capitalize(name);
			}
			else if (room && room->rprog_target != NULL)
			{
				one_argument(room->rprog_target->name, name);
				i = capitalize(name);
			}
			break;
		case 'Q':
			i = (obj
				 && obj->oprog_target !=
				 NULL) ? (IS_NPC(obj->oprog_target) ? obj->
						  oprog_target->short_descr : obj->oprog_target->
						  name) : (room
								   && room->rprog_target !=
								   NULL) ? (IS_NPC(room->rprog_target) ? room->
											rprog_target->short_descr : room->
											rprog_target->name) : someone;
			break;
		case 'j':
			bug("Obj/room received case 'j'", 0);
			i = " <@@@> ";
			break;
		case 'e':
			i = (ch != NULL) ? he_she[URANGE(0, ch->sex, 2)] : someone;
			break;
		case 'E':
			i = (vch != NULL) ? he_she[URANGE(0, vch->sex, 2)] : someone;
			break;
		case 'J':
			i = (rch != NULL) ? he_she[URANGE(0, rch->sex, 2)] : someone;
			break;
		case 'X':
			i = (obj
				 && obj->oprog_target != NULL) ? he_she[URANGE(0,
															   obj->oprog_target->sex,
															   2)] : (room
																	  &&
																	  room->rprog_target
																	  !=
																	  NULL) ?
				he_she[URANGE(0, room->rprog_target->sex, 2)] : someone;
			break;
		case 'k':
			bug("received case 'k'.", 0);
			i = " <@@@> ";
			break;
		case 'm':
			i = (ch != NULL) ? him_her[URANGE(0, ch->sex, 2)] : someone;
			break;
		case 'M':
			i = (vch != NULL) ? him_her[URANGE(0, vch->sex, 2)] : someone;
			break;
		case 'K':
			if (obj && rch == NULL)
				rch = get_random_char(NULL, obj, NULL);
			else if (room && rch == NULL)
				rch = get_random_char(NULL, NULL, room);
			i = (rch != NULL) ? him_her[URANGE(0, rch->sex, 2)] : someone;
			break;
		case 'Y':
			i = (obj
				 && obj->oprog_target != NULL) ? him_her[URANGE(0,
																obj->oprog_target->sex,
																2)] : (room
																	   &&
																	   room->rprog_target
																	   !=
																	   NULL) ?
				him_her[URANGE(0, room->rprog_target->sex, 2)] : someone;
			break;
		case 'l':
			bug("received case 'l'.", 0);
			i = " <@@@> ";
			break;
		case 's':
			i = (ch != NULL) ? his_her[URANGE(0, ch->sex, 2)] : someones;
			break;
		case 'S':
			i = (vch != NULL) ? his_her[URANGE(0, vch->sex, 2)] : someones;
			break;
		case 'L':
			if (obj && rch == NULL)
				rch = get_random_char(NULL, obj, NULL);
			else if (room && rch == NULL)
				rch = get_random_char(NULL, NULL, room);
			i = (rch != NULL) ? his_her[URANGE(0, rch->sex, 2)] : someones;
			break;
		case 'Z':
			i = (obj
				 && obj->oprog_target != NULL) ? his_her[URANGE(0,
																obj->oprog_target->sex,
																2)] : (room
																	   &&
																	   room->rprog_target
																	   !=
																	   NULL) ?
				his_her[URANGE(0, room->rprog_target->sex, 2)] : someones;
			break;
		case 'o':
			i = something;
			if (obj1 != NULL)
			{
				one_argument(obj1->name, name);
				i = name;
			}
			break;
		case 'O':
			i = (obj1 != NULL) ? obj1->short_descr : something;
			break;
		case 'p':
			i = something;
			if (obj2 != NULL)
			{
				one_argument(obj2->name, name);
				i = name;
			}
			break;
		case 'P':
			i = (obj2 != NULL) ? obj2->short_descr : something;
			break;
		}

		++str;
		while ((*point = *i) != '\0')
			++point, ++i;

	}
	*point = '\0';

	return;
}

#define    MAX_NESTED_LEVEL 12

#define    BEGIN_BLOCK       0

#define    IN_BLOCK         -1

#define    END_BLOCK        -2

#define    MAX_CALL_LEVEL    5

void program_flow(vnum_t pvnum, const char *source, CHAR_DATA * mob,
				  OBJ_DATA * obj, ROOM_INDEX_DATA * room, CHAR_DATA * ch,
				  const void *arg1, const void *arg2)
{
	CHAR_DATA *rch = NULL;
	const char *code;
	const char *line;
	char buf[MAX_STRING_LENGTH];
	char ctrl[MAX_INPUT_LENGTH], data[MAX_STRING_LENGTH];
	char bugbuf[MAX_STRING_LENGTH];

	int level, eval, check;
	int state[MAX_NESTED_LEVEL], cond[MAX_NESTED_LEVEL];

	vnum_t mvnum = 0, ovnum = 0, rvnum = 0;

	if ((mob && obj) || (mob && room) || (obj && room))
	{
		bug("received multiple prog types.", 0);
		return;
	}

	if (mob)
		mvnum = mob->pIndexData->vnum;
	else if (obj)
		ovnum = obj->pIndexData->vnum;
	else if (room)
		rvnum = room->vnum;
	else
	{
		bug("did not receive a prog type.", 0);
		return;
	}

	if (++call_level > MAX_CALL_LEVEL)
	{
		if (mob)
			sprintf(bugbuf,
					"Progs: MAX_CALL_LEVEL exceeded, vnum %ld, mprog vnum %ld",
					mvnum, pvnum);
		else if (obj)
			sprintf(bugbuf,
					"Progs: MAX_CALL_LEVEL exceeded, vnum %ld oprog vnum %ld.",
					ovnum, pvnum);
		else
			sprintf(bugbuf,
					"Progs: MAX_CALL_LEVEL exceeded, vnum %ld rprog vnum %ld.",
					rvnum, pvnum);
		bug(bugbuf, 0);
		call_level = 0;
		return;
	}

	for (level = 0; level < MAX_NESTED_LEVEL; level++)
	{
		state[level] = IN_BLOCK;
		cond[level] = TRUE;
	}
	level = 0;

	code = source;

	while (*code)
	{
		bool arg_first = TRUE;
		char *b = buf, *c = ctrl, *d = data;

		while (isspace(*code) && *code)
			code++;
		while (*code)
		{
			if (*code == '\n' || *code == '\r')
				break;
			else if (isspace(*code))
			{
				if (arg_first)
					arg_first = FALSE;
				else
					*d++ = *code;
			}
			else
			{
				if (arg_first)
					*c++ = *code;
				else
					*d++ = *code;
			}
			*b++ = *code++;
		}
		*b = *c = *d = '\0';

		if (IS_NULLSTR(buf))
			break;
		if (buf[0] == '*')

			continue;

		line = data;

		if (!str_cmp(ctrl, "if"))
		{
			if (state[level] == BEGIN_BLOCK)
			{
				if (mob)
					sprintf(buf, "misplaced if statement, mob %ld prog %ld",
							mvnum, pvnum);
				else if (obj)
					sprintf(buf, "misplaced if statement, obj %ld prog %ld",
							ovnum, pvnum);
				else
					sprintf(buf, "misplaced if statement, room %ld prog %ld",
							rvnum, pvnum);
				bug(buf, 0);
				call_level--;
				return;
			}
			state[level] = BEGIN_BLOCK;
			if (++level >= MAX_NESTED_LEVEL)
			{
				if (mob)
					sprintf(buf,
							"Max nested level exceeded, mob %ld prog %ld",
							mvnum, pvnum);
				else if (obj)
					sprintf(buf,
							"Max nested level exceeded, obj %ld prog %ld",
							ovnum, pvnum);
				else
					sprintf(buf,
							"Max nested level exceeded, room %ld prog %ld",
							rvnum, pvnum);
				bug(buf, 0);
				call_level--;
				return;
			}
			if (level && cond[level - 1] == FALSE)
			{
				cond[level] = FALSE;
				continue;
			}
			line = one_argument(line, ctrl);
			if (mob && (check = keyword_lookup(fn_keyword, ctrl)) >= 0)
			{
				cond[level] =
					cmd_eval_mob(pvnum, line, check, mob, ch, arg1, arg2, rch);
			}
			else if (obj && (check = keyword_lookup(fn_keyword, ctrl)) >= 0)
			{
				cond[level] =
					cmd_eval_obj(pvnum, line, check, obj, ch, arg1, arg2, rch);
			}
			else if (room && (check = keyword_lookup(fn_keyword, ctrl)) >= 0)
			{
				cond[level] =
					cmd_eval_room(pvnum, line, check, room, ch, arg1, arg2,
								  rch);
			}
			else
			{
				if (mob)
					sprintf(buf, "invalid if_check (if), mob %ld prog %ld",
							mvnum, pvnum);
				else if (obj)
					sprintf(buf, "invalid if_check (if), obj %ld prog %ld",
							ovnum, pvnum);
				else
					sprintf(buf, "invalid if_check (if), room %ld prog %ld",
							rvnum, pvnum);
				bug(buf, 0);
				call_level--;
				return;
			}
			state[level] = END_BLOCK;
		}
		else if (!str_cmp(ctrl, "or"))
		{
			if (!level || state[level - 1] != BEGIN_BLOCK)
			{
				if (mob)
					sprintf(buf, "or without if, mob %ld prog %ld", mvnum,
							pvnum);
				else if (obj)
					sprintf(buf, "or without if, obj %ld prog %ld", ovnum,
							pvnum);
				else
					sprintf(buf, "or without if, room %ld prog %ld", rvnum,
							pvnum);
				bug(buf, 0);
				return;
			}
			if (level && cond[level - 1] == FALSE)
				continue;
			line = one_argument(line, ctrl);
			if (mob && (check = keyword_lookup(fn_keyword, ctrl)) >= 0)
			{
				eval =
					cmd_eval_mob(pvnum, line, check, mob, ch, arg1, arg2, rch);
			}
			else if (obj && (check = keyword_lookup(fn_keyword, ctrl)) >= 0)
			{
				eval =
					cmd_eval_obj(pvnum, line, check, obj, ch, arg1, arg2, rch);
			}
			else if (room && (check = keyword_lookup(fn_keyword, ctrl)) >= 0)
			{
				eval =
					cmd_eval_room(pvnum, line, check, room, ch, arg1, arg2,
								  rch);
			}
			else
			{
				if (mob)
					sprintf(buf, "invalid if_check (or), mob %ld prog %ld",
							mvnum, pvnum);
				else if (obj)
					sprintf(buf, "invalid if_check (or), obj %ld prog %ld",
							ovnum, pvnum);
				else
					sprintf(buf, "invalid if_check (or), room %ld prog %ld",
							rvnum, pvnum);
				bug(buf, 0);
				call_level--;
				return;
			}
			cond[level] = (eval == (int) TRUE) ? TRUE : cond[level];
		}
		else if (!str_cmp(ctrl, "and"))
		{
			if (!level || state[level - 1] != BEGIN_BLOCK)
			{
				if (mob)
					sprintf(buf, "and without if, mob %ld prog %ld", mvnum,
							pvnum);
				else if (obj)
					sprintf(buf, "and without if, obj %ld prog %ld", ovnum,
							pvnum);
				else
					sprintf(buf, "and without if, room %ld prog %ld", rvnum,
							pvnum);
				bug(buf, 0);
				call_level--;
				return;
			}
			if (level && cond[level - 1] == FALSE)
				continue;
			line = one_argument(line, ctrl);
			if (mob && (check = keyword_lookup(fn_keyword, ctrl)) >= 0)
			{
				eval =
					cmd_eval_mob(pvnum, line, check, mob, ch, arg1, arg2, rch);
			}
			else if (obj && (check = keyword_lookup(fn_keyword, ctrl)) >= 0)
			{
				eval =
					cmd_eval_obj(pvnum, line, check, obj, ch, arg1, arg2, rch);
			}
			else if (room && (check = keyword_lookup(fn_keyword, ctrl)) >= 0)
			{
				eval =
					cmd_eval_room(pvnum, line, check, room, ch, arg1, arg2,
								  rch);
			}
			else
			{
				if (mob)
					sprintf(buf, "invalid if_check (and), mob %ld prog %ld",
							mvnum, pvnum);
				else if (obj)
					sprintf(buf, "invalid if_check (and), obj %ld prog %ld",
							ovnum, pvnum);
				else
					sprintf(buf, "invalid if_check (and), room %ld prog %ld",
							rvnum, pvnum);
				bug(buf, 0);
				call_level--;
				return;
			}
			cond[level] = (cond[level] == (int) TRUE)
				&& (eval == (int) TRUE) ? TRUE : FALSE;
		}
		else if (!str_cmp(ctrl, "endif"))
		{
			if (!level || state[level - 1] != BEGIN_BLOCK)
			{
				if (mob)
					sprintf(buf, "endif without if, mob %ld prog %ld", mvnum,
							pvnum);
				else if (obj)
					sprintf(buf, "endif without if, obj %ld prog %ld", ovnum,
							pvnum);
				else
					sprintf(buf, "endif without if, room %ld prog %ld",
							rvnum, pvnum);
				bug(buf, 0);
				call_level--;
				return;
			}
			cond[level] = TRUE;
			state[level] = IN_BLOCK;
			state[--level] = END_BLOCK;
		}
		else if (!str_cmp(ctrl, "else"))
		{
			if (!level || state[level - 1] != BEGIN_BLOCK)
			{
				if (mob)
					sprintf(buf, "else without if, mob %ld prog %ld", mvnum,
							pvnum);
				else if (obj)
					sprintf(buf, "else without if, obj %ld prog %ld", ovnum,
							pvnum);
				else
					sprintf(buf, "else without if, room %ld prog %ld", rvnum,
							pvnum);
				bug(buf, 0);
				call_level--;
				return;
			}
			if (level && cond[level - 1] == FALSE)
				continue;
			state[level] = IN_BLOCK;
			cond[level] = (cond[level] == (int) TRUE) ? FALSE : TRUE;
		}
		else if (cond[level] == (int) TRUE
				 && (!str_cmp(ctrl, "break") || !str_cmp(ctrl, "end")))
		{
			call_level--;
			return;
		}
		else if ((!level || cond[level] == (int) TRUE) && !IS_NULLSTR(buf))
		{
			state[level] = IN_BLOCK;

			if (mob)
				expand_arg_mob(data, buf, mob, ch, arg1, arg2, rch);
			else if (obj)
				expand_arg_other(data, buf, obj, NULL, ch, arg1, arg2, rch);
			else
				expand_arg_other(data, buf, NULL, room, ch, arg1, arg2, rch);

			if (!str_cmp(ctrl, "mob"))
			{

				line = one_argument(data, ctrl);
				if (!mob)
					bug("mob command in non MOBprog", 0);
				else
					mob_interpret(mob, line);
			}
			else if (!str_cmp(ctrl, "obj"))
			{

				line = one_argument(data, ctrl);
				if (!obj)
					bug("obj command in non OBJprog", 0);
				else
					obj_interpret(obj, line);
			}
			else if (!str_cmp(ctrl, "room"))
			{

				line = one_argument(data, ctrl);
				if (!room)
					bug("room command in non ROOMprog", 0);
				else
					room_interpret(room, line);
			}
			else
			{

				if (!mob)
					bugf("Normal MUD command in non-MOBprog, prog vnum %ld",
						 pvnum);
				else
					interpret(mob, data);
			}
		}
	}
	call_level--;
}

void p_act_trigger(const char *argument, CHAR_DATA * mob, OBJ_DATA * obj,
				   ROOM_INDEX_DATA * room, CHAR_DATA * ch, const void *arg1,
				   const void *arg2, flag_t type)
{
	PROG_LIST *prg;

	if ((mob && obj) || (mob && room) || (obj && room))
	{
		bug("Multiple program types in ACT trigger.", 0);
		return;
	}

	if (mob)
	{
		if (!IS_NPC(mob))
		{
			bug("Attempt to access p_act_trigger on a PLAYER.", 0);
			return;
		}

		for (prg = mob->pIndexData->first_mprog; prg != NULL; prg = prg->next)
		{
			if (prg->trig_type == type
				&& strstr(argument, prg->trig_phrase) != NULL)
			{
				program_flow(prg->vnum, prg->code, mob, NULL, NULL, ch, arg1,
							 arg2);
				break;
			}
		}
	}
	else if (obj)
	{
		for (prg = obj->pIndexData->first_oprog; prg != NULL; prg = prg->next)
		{
			if (prg->trig_type == type
				&& strstr(argument, prg->trig_phrase) != NULL)
			{
				program_flow(prg->vnum, prg->code, NULL, obj, NULL, ch, arg1,
							 arg2);
				break;
			}
		}
	}
	else if (room)
	{
		for (prg = room->first_rprog; prg != NULL; prg = prg->next)
		{
			if (prg->trig_type == type
				&& strstr(argument, prg->trig_phrase) != NULL)
			{
				program_flow(prg->vnum, prg->code, NULL, NULL, room, ch,
							 arg1, arg2);
				break;
			}
		}
	}
	else
		bug("ACT trigger with no program type.", 0);

	return;
}

bool p_percent_trigger(CHAR_DATA * mob, OBJ_DATA * obj,
					   ROOM_INDEX_DATA * room, CHAR_DATA * ch,
					   const void *arg1, const void *arg2, flag_t type)
{
	PROG_LIST *prg;

	if ((mob && obj) || (mob && room) || (obj && room))
	{
		bug("Multiple program types in PERCENT trigger.", 0);
		return (FALSE);
	}

	if (mob)
	{
		for (prg = mob->pIndexData->first_mprog; prg != NULL; prg = prg->next)
		{
			if (prg->trig_type == type
				&& number_percent() < atoi(prg->trig_phrase))
			{
				program_flow(prg->vnum, prg->code, mob, NULL, NULL, ch, arg1,
							 arg2);
				return (TRUE);
			}
		}
	}
	else if (obj)
	{
		for (prg = obj->pIndexData->first_oprog; prg != NULL; prg = prg->next)
		{
			if (prg->trig_type == type
				&& number_percent() < atoi(prg->trig_phrase))
			{
				program_flow(prg->vnum, prg->code, NULL, obj, NULL, ch, arg1,
							 arg2);
				return (TRUE);
			}
		}
	}
	else if (room)
	{
		for (prg = room->first_rprog; prg != NULL; prg = prg->next)
		{
			if (prg->trig_type == type
				&& number_percent() < atoi(prg->trig_phrase))
			{
				program_flow(prg->vnum, prg->code, NULL, NULL, room, ch,
							 arg1, arg2);
				return (TRUE);
			}
		}
	}
	else
		bug("PERCENT trigger missing program type.", 0);

	return (FALSE);
}

void p_bribe_trigger(CHAR_DATA * mob, CHAR_DATA * ch, long amount)
{
	PROG_LIST *prg;

	for (prg = mob->pIndexData->first_mprog; prg; prg = prg->next)
	{
		if (prg->trig_type == TRIG_BRIBE && amount >= atol(prg->trig_phrase))
		{
			program_flow(prg->vnum, prg->code, mob, NULL, NULL, ch, NULL, NULL);
			break;
		}
	}
	return;
}

bool p_exit_trigger(CHAR_DATA * ch, int dir, int type)
{
	CHAR_DATA *mob;
	OBJ_DATA *obj;
	ROOM_INDEX_DATA *room;
	PROG_LIST *prg;

	if (type == PRG_MPROG)
	{
		for (mob = ch->in_room->first_person; mob != NULL;
			 mob = mob->next_in_room)
		{
			if (IS_NPC(mob)
				&& (HAS_TRIGGER_MOB(mob, TRIG_EXIT)
					|| HAS_TRIGGER_MOB(mob, TRIG_EXALL)))
			{
				for (prg = mob->pIndexData->first_mprog; prg; prg = prg->next)
				{

					if (prg->trig_type == TRIG_EXIT
						&& dir == atoi(prg->trig_phrase)
						&& mob->position == mob->pIndexData->default_pos
						&& can_see(mob, ch))
					{
						program_flow(prg->vnum, prg->code, mob, NULL, NULL,
									 ch, NULL, NULL);
						return TRUE;
					}
					else if (prg->trig_type == TRIG_EXALL
							 && dir == atoi(prg->trig_phrase))
					{
						program_flow(prg->vnum, prg->code, mob, NULL, NULL,
									 ch, NULL, NULL);
						return TRUE;
					}
				}
			}
		}
	}
	else if (type == PRG_OPROG)
	{
		for (obj = ch->in_room->first_content; obj != NULL;
			 obj = obj->next_content)
		{
			if (HAS_TRIGGER_OBJ(obj, TRIG_EXALL))
			{
				for (prg = obj->pIndexData->first_oprog; prg; prg = prg->next)
				{
					if (prg->trig_type == TRIG_EXALL
						&& dir == atoi(prg->trig_phrase))
					{
						program_flow(prg->vnum, prg->code, NULL, obj, NULL,
									 ch, NULL, NULL);
						return TRUE;
					}
				}
			}
		}

		for (mob = ch->in_room->first_person; mob; mob = mob->next_in_room)
		{
			for (obj = mob->first_carrying; obj; obj = obj->next_content)
			{
				if (HAS_TRIGGER_OBJ(obj, TRIG_EXALL))
				{
					for (prg = obj->pIndexData->first_oprog; prg;
						 prg = prg->next)
					{
						if (prg->trig_type == TRIG_EXALL
							&& dir == atoi(prg->trig_phrase))
						{
							program_flow(prg->vnum, prg->code, NULL, obj,
										 NULL, ch, NULL, NULL);
							return TRUE;
						}
					}
				}
			}
		}
	}
	else if (type == PRG_RPROG)
	{
		room = ch->in_room;

		if (HAS_TRIGGER_ROOM(room, TRIG_EXALL))
		{
			for (prg = room->first_rprog; prg; prg = prg->next)
			{
				if (prg->trig_type == TRIG_EXALL
					&& dir == atoi(prg->trig_phrase))
				{
					program_flow(prg->vnum, prg->code, NULL, NULL, room, ch,
								 NULL, NULL);
					return TRUE;
				}
			}
		}
	}

	return FALSE;
}

void p_give_trigger(CHAR_DATA * mob, OBJ_DATA * obj, ROOM_INDEX_DATA * room,
					CHAR_DATA * ch, OBJ_DATA * dropped, flag_t type)
{

	char buf[MIL];
	const char *p;
	PROG_LIST *prg;

	if ((mob && obj) || (mob && room) || (obj && room))
	{
		bug("Multiple program types in GIVE trigger.", 0);
		return;
	}

	if (mob)
	{
		for (prg = mob->pIndexData->first_mprog; prg; prg = prg->next)
			if (prg->trig_type == TRIG_GIVE)
			{
				p = prg->trig_phrase;

				if (is_number(p))
				{
					if (dropped->pIndexData->vnum == atol(p))
					{
						program_flow(prg->vnum, prg->code, mob, NULL, NULL,
									 ch, (void *) dropped, NULL);
						return;
					}
				}

				else
				{
					while (*p)
					{
						p = one_argument(p, buf);

						if (is_name(buf, dropped->name) || !str_cmp("all", buf))
						{
							program_flow(prg->vnum, prg->code, mob, NULL,
										 NULL, ch, (void *) dropped, NULL);
							return;
						}
					}
				}
			}
	}
	else if (obj)
	{
		for (prg = obj->pIndexData->first_oprog; prg; prg = prg->next)
			if (prg->trig_type == type)
			{
				program_flow(prg->vnum, prg->code, NULL, obj, NULL, ch,
							 (void *) obj, NULL);
				return;
			}
	}
	else if (room)
	{
		for (prg = room->first_rprog; prg; prg = prg->next)
			if (prg->trig_type == type)
			{
				p = prg->trig_phrase;

				if (is_number(p))
				{
					if (dropped->pIndexData->vnum == atol(p))
					{
						program_flow(prg->vnum, prg->code, NULL, NULL, room,
									 ch, (void *) dropped, NULL);
						return;
					}
				}

				else
				{
					while (*p)
					{
						p = one_argument(p, buf);

						if (is_name(buf, dropped->name) || !str_cmp("all", buf))
						{
							program_flow(prg->vnum, prg->code, NULL, NULL,
										 room, ch, (void *) dropped, NULL);
							return;
						}
					}
				}
			}
	}
}

void p_greet_trigger(CHAR_DATA * ch, int type)
{
	CHAR_DATA *mob;
	OBJ_DATA *obj;
	ROOM_INDEX_DATA *room;

	if (type == PRG_MPROG)
	{
		for (mob = ch->in_room->first_person; mob != NULL;
			 mob = mob->next_in_room)
		{
			if (IS_NPC(mob)
				&& (HAS_TRIGGER_MOB(mob, TRIG_GREET)
					|| HAS_TRIGGER_MOB(mob, TRIG_GRALL)))
			{

				if (HAS_TRIGGER_MOB(mob, TRIG_GREET)
					&& mob->position == mob->pIndexData->default_pos
					&& can_see(mob, ch))
					p_percent_trigger(mob, NULL, NULL, ch, NULL, NULL,
									  TRIG_GREET);
				else if (HAS_TRIGGER_MOB(mob, TRIG_GRALL))
					p_percent_trigger(mob, NULL, NULL, ch, NULL, NULL,
									  TRIG_GRALL);
			}
		}
	}
	else if (type == PRG_OPROG)
	{
		for (obj = ch->in_room->first_content; obj != NULL;
			 obj = obj->next_content)
		{
			if (HAS_TRIGGER_OBJ(obj, TRIG_GRALL))
			{
				p_percent_trigger(NULL, obj, NULL, ch, NULL, NULL, TRIG_GRALL);
				return;
			}
		}

		for (mob = ch->in_room->first_person; mob; mob = mob->next_in_room)
		{
			for (obj = mob->first_carrying; obj; obj = obj->next_content)
			{
				if (HAS_TRIGGER_OBJ(obj, TRIG_GRALL))
				{
					p_percent_trigger(NULL, obj, NULL, ch, NULL, NULL,
									  TRIG_GRALL);
					return;
				}
			}
		}
	}
	else if (type == PRG_RPROG)
	{
		room = ch->in_room;

		if (HAS_TRIGGER_ROOM(room, TRIG_GRALL))
			p_percent_trigger(NULL, NULL, room, ch, NULL, NULL, TRIG_GRALL);
	}

	return;
}

void p_hprct_trigger(CHAR_DATA * mob, CHAR_DATA * ch)
{
	PROG_LIST *prg;

	for (prg = mob->pIndexData->first_mprog; prg != NULL; prg = prg->next)
		if ((prg->trig_type == TRIG_HPCNT)
			&& ((100 * mob->hit / mob->max_hit) < atoi(prg->trig_phrase)))
		{
			program_flow(prg->vnum, prg->code, mob, NULL, NULL, ch, NULL, NULL);
			break;
		}
}