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




#include "merc.h"
#include "tables.h"
#include "prog_cmds.h"
#include "recycle.h"

#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");
      return 0;
    }
}

CharData *
get_random_char (CharData * mob, ObjData * obj, RoomIndex * room)
{
  CharData *vch, *victim = NULL;
  int now = 0, highest = 0;

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

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

  for (; vch; vch = vch->next_in_room)
    {
      if (mob && mob != vch && !IsNPC (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 (CharData * mob, ObjData * obj, RoomIndex * room, int iFlag)
{
  CharData *vch;
  int count;

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

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

  for (count = 0; vch; vch = vch->next_in_room)
    {
      if (mob)
	{
	  if (mob != vch && (iFlag == 0 || (iFlag == 1 && !IsNPC (vch))
			     || (iFlag == 2 && IsNPC (vch)) || (iFlag == 3
								&&
								IsNPC (mob)
								&&
								IsNPC (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 && !IsNPC (vch))
	      || (iFlag == 2 && IsNPC (vch)))
	    count++;
	}
    }

  return (count);
}

int
get_order (CharData * ch, ObjData * obj)
{
  CharData *vch;
  ObjData *vobj;
  int i;

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

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

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

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

	if (IsNPC (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 (CharData * ch, vnum_t vnum, item_t pitem_type, bool fWear)
{
  ObjData *obj;

  for (obj = ch->carrying_first; 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 (CharData * ch, ObjData * obj, RoomIndex * room,
		   vnum_t vnum)
{
  CharData *mob;

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

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

  for (; mob; mob = mob->next_in_room)
    if (IsNPC (mob) && mob->pIndexData->vnum == vnum)
      return true;
  return false;
}

bool
get_obj_vnum_room (CharData * ch, ObjData * obj, RoomIndex * room,
		   vnum_t vnum)
{
  ObjData *vobj;

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

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

  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, CharData * mob,
	      CharData * ch, const void *arg1, const void *arg2,
	      CharData * rch)
{
  CharData *lval_char = mob;
  CharData *vch = (CharData *) arg2;
  ObjData *obj1 = (ObjData *) arg1;
  ObjData *obj2 = (ObjData *) arg2;
  ObjData *lval_obj = NULL;
  const char *original;
  char buf[MIL], code;
  int lval = 0, oper = 0, rval = -1;
  flag_t temp;

  original = line;
  line = one_argument (line, buf);
  if (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, atov (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, atov (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 && !IsNPC (lval_char));
    case CHK_ISNPC:
      return (lval_char != NULL && IsNPC (lval_char));
    case CHK_ISGOOD:
      return (lval_char != NULL && IsGood (lval_char));
    case CHK_ISEVIL:
      return (lval_char != NULL && IsEvil (lval_char));
    case CHK_ISNEUTRAL:
      return (lval_char != NULL && IsNeutral (lval_char));
    case CHK_ISIMMORT:
      return (lval_char != NULL && IsImmortal (lval_char));
    case CHK_HUNTER:
      return (lval_char != NULL && lval_char->hunting == mob);
    case CHK_ISCHARM:

      return (lval_char != NULL && IsAffected (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 && IsQuester (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:
      if ((temp = flag_value (affect_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL && IsAffected (lval_char, temp));
    case CHK_ACT:
      if ((temp = flag_value (act_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL
	      && IsNPC (lval_char) && IsSet (lval_char->act, temp));
    case CHK_PLR:
      if ((temp = flag_value (plr_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL
	      && !IsNPC (lval_char) && IsSet (lval_char->act, temp));
    case CHK_IMM:
      if ((temp = flag_value (imm_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL && IsSet (lval_char->imm_flags, temp));
    case CHK_OFF:
      if ((temp = flag_value (off_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL && IsSet (lval_char->off_flags, temp));
    case CHK_CARRIES:
      if (is_number (buf))
	return (lval_char != NULL
		&& has_item (lval_char, atov (buf), (item_t) - 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, atov (buf), (item_t) - 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_t) flag_value (type_flags, buf), false));
    case CHK_USES:
      return (lval_char != NULL
	      && has_item (lval_char, -1,
			   (item_t) flag_value (type_flags, buf), true));
    case CHK_SKILL:
      return (lval_char != NULL && !IsNPC (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 == flag_value (position_flags, buf));
    case CHK_CLAN:
      return (lval_char != NULL && CharClan (lval_char) == clan_lookup (buf));
    case CHK_CLASS:
      return (lval_char != NULL
	      && prime_class (lval_char) == 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 == flag_value (type_flags, 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 && IsNPC (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) / (Max (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, ObjData * obj,
	      CharData * ch, const void *arg1, const void *arg2,
	      CharData * rch)
{
  CharData *lval_char = NULL;
  CharData *vch = (CharData *) arg2;
  ObjData *obj1 = (ObjData *) arg1;
  ObjData *obj2 = (ObjData *) arg2;
  ObjData *lval_obj = obj;
  const char *original;
  char buf[MIL], code;
  int lval = 0, oper = 0, rval = -1;
  flag_t temp;

  original = line;
  line = one_argument (line, buf);
  if (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, atov (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, atov (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.");
      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 && !IsNPC (lval_char));
    case CHK_ISNPC:
      return (lval_char != NULL && IsNPC (lval_char));
    case CHK_ISGOOD:
      return (lval_char != NULL && IsGood (lval_char));
    case CHK_ISEVIL:
      return (lval_char != NULL && IsEvil (lval_char));
    case CHK_ISNEUTRAL:
      return (lval_char != NULL && IsNeutral (lval_char));
    case CHK_ISIMMORT:
      return (lval_char != NULL && IsImmortal (lval_char));
    case CHK_ISCHARM:

      return (lval_char != NULL && IsAffected (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:
      if ((temp = flag_value (affect_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL && IsAffected (lval_char, temp));
    case CHK_ACT:
      if ((temp = flag_value (act_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL
	      && IsNPC (lval_char) && IsSet (lval_char->act, temp));
    case CHK_PLR:
      if ((temp = flag_value (plr_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL
	      && !IsNPC (lval_char) && IsSet (lval_char->act, temp));
    case CHK_IMM:
      if ((temp = flag_value (imm_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL && IsSet (lval_char->imm_flags, temp));
    case CHK_OFF:
      if ((temp = flag_value (off_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL && IsSet (lval_char->off_flags, temp));
    case CHK_CARRIES:
      if (is_number (buf))
	return (lval_char != NULL
		&& has_item (lval_char, atov (buf), (item_t) - 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, atov (buf), (item_t) - 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_t) flag_value (type_flags, buf), false));
    case CHK_USES:
      return (lval_char != NULL
	      && has_item (lval_char, -1,
			   (item_t) flag_value (type_flags, buf), true));
    case CHK_SKILL:
      return (lval_char != NULL && !IsNPC (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 == flag_value (position_flags, buf));
    case CHK_CLAN:
      return (lval_char != NULL && CharClan (lval_char) == clan_lookup (buf));
    case CHK_CLASS:
      return (lval_char != NULL
	      && prime_class (lval_char) == 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 == flag_value (type_flags, 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 && IsNPC (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) / (Max (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,
	       RoomIndex * room, CharData * ch, const void *arg1,
	       const void *arg2, CharData * rch)
{
  CharData *lval_char = NULL;
  CharData *vch = (CharData *) arg2;
  ObjData *obj1 = (ObjData *) arg1;
  ObjData *obj2 = (ObjData *) arg2;
  ObjData *lval_obj = NULL;
  const char *original;
  char buf[MIL], code;
  int lval = 0, oper = 0, rval = -1;
  flag_t temp;

  original = line;
  line = one_argument (line, buf);
  if (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, atov (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, atov (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.");
      break;
    case CHK_ORDER:
      bug ("received CHK_ORDER.");
      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'.");
      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 && !IsNPC (lval_char));
    case CHK_ISNPC:
      return (lval_char != NULL && IsNPC (lval_char));
    case CHK_ISGOOD:
      return (lval_char != NULL && IsGood (lval_char));
    case CHK_ISEVIL:
      return (lval_char != NULL && IsEvil (lval_char));
    case CHK_ISNEUTRAL:
      return (lval_char != NULL && IsNeutral (lval_char));
    case CHK_ISIMMORT:
      return (lval_char != NULL && IsImmortal (lval_char));
    case CHK_ISCHARM:

      return (lval_char != NULL && IsAffected (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:
      if ((temp = flag_value (affect_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL && IsAffected (lval_char, temp));
    case CHK_ACT:
      if ((temp = flag_value (act_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL
	      && IsNPC (lval_char) && IsSet (lval_char->act, temp));
    case CHK_PLR:
      if ((temp = flag_value (plr_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL
	      && !IsNPC (lval_char) && IsSet (lval_char->act, temp));
    case CHK_IMM:
      if ((temp = flag_value (imm_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL && IsSet (lval_char->imm_flags, temp));
    case CHK_OFF:
      if ((temp = flag_value (off_flags, buf)) == NO_FLAG)
	return false;
      return (lval_char != NULL && IsSet (lval_char->off_flags, temp));
    case CHK_CARRIES:
      if (is_number (buf))
	return (lval_char != NULL
		&& has_item (lval_char, atov (buf), (item_t) - 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, atov (buf), (item_t) - 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_t) flag_value (type_flags, buf), false));
    case CHK_USES:
      return (lval_char != NULL
	      && has_item (lval_char, -1,
			   (item_t) flag_value (type_flags, buf), true));
    case CHK_SKILL:
      return (lval_char != NULL && !IsNPC (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 == flag_value (position_flags, buf));
    case CHK_CLAN:
      return (lval_char != NULL && CharClan (lval_char) == clan_lookup (buf));
    case CHK_CLASS:
      return (lval_char != NULL
	      && prime_class (lval_char) == 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_t) flag_value (type_flags,
							     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 && IsNPC (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) / (Max (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, CharData * mob,
		CharData * ch, const void *arg1, const void *arg2,
		CharData * rch)
{
  const char *someone = "someone";
  const char *something = "something";
  const char *someones = "someone's";

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

  if (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)) ? (IsNPC (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)) ? (IsNPC (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)) ? (IsNPC (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)) ? (IsNPC (mob->mprog_target) ?
						  mob->
						  mprog_target->short_descr :
						  mob->mprog_target->
						  name) : someone;
	  break;
	case 'j':
	  i = he_she[Range (0, mob->sex, 2)];
	  break;
	case 'e':
	  i = (ch != NULL
	       && can_see (mob, ch)) ? he_she[Range (0, ch->sex,
						     2)] : someone;
	  break;
	case 'E':
	  i = (vch != NULL
	       && can_see (mob, vch)) ? he_she[Range (0, vch->sex,
						      2)] : someone;
	  break;
	case 'J':
	  i = (rch != NULL
	       && can_see (mob, rch)) ? he_she[Range (0, rch->sex,
						      2)] : someone;
	  break;
	case 'X':
	  i = (mob->mprog_target != NULL
	       && can_see (mob, mob->mprog_target)) ? he_she[Range (0,
								    mob->
								    mprog_target->
								    sex,
								    2)] :
	    someone;
	  break;
	case 'k':
	  i = him_her[Range (0, mob->sex, 2)];
	  break;
	case 'm':
	  i = (ch != NULL
	       && can_see (mob, ch)) ? him_her[Range (0, ch->sex,
						      2)] : someone;
	  break;
	case 'M':
	  i = (vch != NULL
	       && can_see (mob, vch)) ? him_her[Range (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[Range (0, rch->sex,
						       2)] : someone;
	  break;
	case 'Y':
	  i = (mob->mprog_target != NULL
	       && can_see (mob, mob->mprog_target)) ? him_her[Range (0,
								     mob->
								     mprog_target->
								     sex,
								     2)] :
	    someone;
	  break;
	case 'l':
	  i = his_her[Range (0, mob->sex, 2)];
	  break;
	case 's':
	  i = (ch != NULL
	       && can_see (mob, ch)) ? his_her[Range (0, ch->sex,
						      2)] : someones;
	  break;
	case 'S':
	  i = (vch != NULL
	       && can_see (mob, vch)) ? his_her[Range (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[Range (0, rch->sex,
						       2)] : someones;
	  break;
	case 'Z':
	  i = (mob->mprog_target != NULL
	       && can_see (mob, mob->mprog_target)) ? his_her[Range (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, ObjData * obj,
		  RoomIndex * room, CharData * ch,
		  const void *arg1, const void *arg2, CharData * rch)
{
  const char *someone = "someone";
  const char *something = "something";
  const char *someones = "someone's";

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

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

  if (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.");
	      i = " <@@@> ";
	    }
	  break;
	case 'I':
	  if (obj)
	    i = obj->short_descr;
	  else
	    {
	      bug ("room had an \"I\" case.");
	      i = " <@@@> ";
	    }
	  break;
	case 'n':
	  i = someone;
	  if (ch != NULL)
	    {
	      one_argument (ch->name, name);
	      i = capitalize (name);
	    }
	  break;
	case 'N':
	  i = (ch !=
	       NULL) ? (IsNPC (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) ? (IsNPC (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) ? (IsNPC (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) ? (IsNPC (obj->oprog_target) ? obj->
			oprog_target->short_descr : obj->oprog_target->
			name) : (room
				 && room->rprog_target !=
				 NULL) ? (IsNPC (room->rprog_target) ? room->
					  rprog_target->short_descr : room->
					  rprog_target->name) : someone;
	  break;
	case 'j':
	  bug ("Obj/room received case 'j'");
	  i = " <@@@> ";
	  break;
	case 'e':
	  i = (ch != NULL) ? he_she[Range (0, ch->sex, 2)] : someone;
	  break;
	case 'E':
	  i = (vch != NULL) ? he_she[Range (0, vch->sex, 2)] : someone;
	  break;
	case 'J':
	  i = (rch != NULL) ? he_she[Range (0, rch->sex, 2)] : someone;
	  break;
	case 'X':
	  i = (obj
	       && obj->oprog_target != NULL) ? he_she[Range (0,
							     obj->
							     oprog_target->
							     sex, 2)] : (room
									 &&
									 room->
									 rprog_target
									 !=
									 NULL)
	    ? he_she[Range (0, room->rprog_target->sex, 2)] : someone;
	  break;
	case 'k':
	  bug ("received case 'k'.");
	  i = " <@@@> ";
	  break;
	case 'm':
	  i = (ch != NULL) ? him_her[Range (0, ch->sex, 2)] : someone;
	  break;
	case 'M':
	  i = (vch != NULL) ? him_her[Range (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[Range (0, rch->sex, 2)] : someone;
	  break;
	case 'Y':
	  i = (obj
	       && obj->oprog_target != NULL) ? him_her[Range (0,
							      obj->
							      oprog_target->
							      sex,
							      2)] : (room
								     &&
								     room->
								     rprog_target
								     !=
								     NULL) ?
	    him_her[Range (0, room->rprog_target->sex, 2)] : someone;
	  break;
	case 'l':
	  bug ("received case 'l'.");
	  i = " <@@@> ";
	  break;
	case 's':
	  i = (ch != NULL) ? his_her[Range (0, ch->sex, 2)] : someones;
	  break;
	case 'S':
	  i = (vch != NULL) ? his_her[Range (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[Range (0, rch->sex, 2)] : someones;
	  break;
	case 'Z':
	  i = (obj
	       && obj->oprog_target != NULL) ? his_her[Range (0,
							      obj->
							      oprog_target->
							      sex,
							      2)] : (room
								     &&
								     room->
								     rprog_target
								     !=
								     NULL) ?
	    his_her[Range (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;
}


const char *
prog_type (prog_t type)
{
  switch (type)
    {
    case PRG_MPROG:
      return "mobile";
    case PRG_OPROG:
      return "object";
    case PRG_RPROG:
      return "room";
    default:
      return "unknown";
    }
}

#define    MAX_NESTED_LEVEL 12

#define    BEGIN_BLOCK       0

#define    IN_BLOCK         -1

#define    END_BLOCK        -2

#define    MAX_CALL_LEVEL    5


#define MAX_PTRACE    	500
int ptrace_current;
int ptrace_calledby[MAX_PTRACE];
vnum_t callstack_pvnum[MAX_CALL_LEVEL];
vnum_t callstack_mvnum[MAX_CALL_LEVEL];
vnum_t callstack_rvnum[MAX_CALL_LEVEL];
int callstack_line[MAX_CALL_LEVEL];
bool callstack_aborted[MAX_CALL_LEVEL];
prog_t callstack_type[MAX_CALL_LEVEL];
vnum_t ptrace_pvnum[MAX_PTRACE];
vnum_t ptrace_mvnum[MAX_PTRACE];
vnum_t ptrace_rvnum[MAX_PTRACE];
prog_t ptrace_type[MAX_PTRACE];
unsigned char ptrace_calllevel[MAX_PTRACE];
time_t ptrace_time[MAX_PTRACE];
bool ptrace_aborted[MAX_PTRACE];

int call_level = 0;

Do_Fun (do_preset)
{
  int i;

  chprintln (ch, "Progs reseted.  (prog callstack depth to 0)");
  for (i = 0; i < MAX_CALL_LEVEL; i++)
    {
      callstack_pvnum[i] = 0;
      callstack_mvnum[i] = 0;
      callstack_rvnum[i] = 0;
      callstack_type[i] = PRG_NONE;
      callstack_aborted[i] = false;
    }
  call_level = 0;

  logf ("%s reset the prog callstack", ch->name);
  return;
}


Do_Fun (do_pinfo)
{
  int i;

  Buffer *output;

  output = new_buf ();

  bprintlnf (output,
	     "    Displaying program call abort history - calllevel currently is %d\r\n",
	     call_level);


  for (i = 0; i < MAX_CALL_LEVEL; i++)
    {
      if (callstack_aborted[i])
	{
	  bprintlnf
	    (output,
	     "      [%2d] Program %ld on %s %ld (in room %ld) {RABORTED!!! (BUGGY?){X\r\n",
	     i, callstack_pvnum[i], prog_type (callstack_type[i]),
	     callstack_mvnum[i], callstack_rvnum[i]);
	}
      else
	{
	  bprintlnf
	    (output,
	     "      [%2d] Program %ld on %s %ld (in room %ld)\r\n", i,
	     callstack_pvnum[i], prog_type (callstack_type[i]),
	     callstack_mvnum[i], callstack_rvnum[i]);
	}
    }

  {
    ProgCode *prg;

    for (prg = mprog_first; prg; prg = prg->next)
      {
	if (prg->disabled)
	  {
	    bprintlnf
	      (output,
	       "Mobprog %ld is disabled with the following text:{x",
	       prg->vnum);
	    bprintln (output, prg->disabled_text);
	  }
      }
    for (prg = oprog_first; prg; prg = prg->next)
      {
	if (prg->disabled)
	  {
	    bprintlnf
	      (output,
	       "Objprog %ld is disabled with the following text:{x",
	       prg->vnum);
	    bprintln (output, prg->disabled_text);
	  }
      }
    for (prg = rprog_first; prg; prg = prg->next)
      {
	if (prg->disabled)
	  {
	    bprintlnf
	      (output,
	       "Roomprog %ld is disabled with the following text:{x",
	       prg->vnum);
	    bprintln (output, prg->disabled_text);
	  }
      }
  }

  sendpage (ch, buf_string (output));
  free_buf (output);

  return;
}


Do_Fun (do_ptrace)
{
  char arg1[MIL];
  Buffer *output;
  int lines_to_show;
  int line;
  int count;
  int i;
  int lc;

  argument = one_argument (argument, arg1);
  if (NullStr (arg1))
    {
      lines_to_show = get_scr_cols (ch);
      lines_to_show %= MAX_PTRACE;
    }
  else if (is_number (arg1))
    {
      lines_to_show = atoi (arg1);
      if (lines_to_show < 1)
	{
	  chprintln (ch, "Lines to show, increased to 1");
	  lines_to_show = 1;
	}
      else if (lines_to_show > MAX_PTRACE)
	{
	  chprintlnf
	    (ch,
	     "Lines to show, decreased to the number logged in the trace - %d",
	     MAX_PTRACE);
	  lines_to_show = MAX_PTRACE;
	}
    }
  else
    {
      chprintlnf (ch,
		  "{RThe only parameter for ptrace must be a numeric value"
		  NEWLINE
		  "for the number of lines of the trace you wish to see.{x");
      return;
    }
  chprintlnf (ch, "Number of trace lines to show=%d", lines_to_show);

  output = new_buf ();

  bprintln (output, "{xPTrace {G#prog{x, {Mtype{x, {Yvnum{x, {Binroom{x");


  line = ptrace_current + MAX_PTRACE - lines_to_show;
  lc = 0;

  for (count = 0; count < lines_to_show; count++)
    {
      line++;
      line %= MAX_PTRACE;

      if (ptrace_time[line] == 0)
	continue;


      bprintf (output, "[%3d]%s  ", ++lc,
	       str_time (ptrace_time[line], GetTzone (ch), "%H:%M:%S"));


      for (i = 0; i < ptrace_calllevel[line]; i++)
	{
	  bprint (output, "        ");
	}

      bprintlnf (output, "{G%5ld{x,{M%6s,{Y%5ld{x,{B%5ld{x, %s",
		 ptrace_pvnum[line],
		 prog_type (ptrace_type[line]),
		 ptrace_mvnum[line],
		 ptrace_rvnum[line],
		 prog_type_to_name (ptrace_calledby[line]));
    }
  sendpage (ch, buf_string (output));
  free_buf (output);
}

Do_Fun (do_phelp)
{
  cmd_syntax (ch, NULL, n_fun, "trace", "reset", "info", "stat", "dump",
	      NULL);
}

Do_Fun (do_pstat)
{
  char cmd[MIL], arg[MIL];
  ProgList *prg;
  int i;

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

  if (NullStr (cmd))
    {
      cmd_syntax (ch, NULL, n_fun, "mob <vnum>", "obj <vnum>",
		  "rpstat <vnum>", NULL);
      return;
    }
  else if (!str_prefix (cmd, "room"))
    {
      RoomIndex *room;

      if (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 (atov (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, prg = room->rprog_first; prg != NULL; prg = prg->next)
	{
	  chprintlnf (ch,
		      "[%2d] Trigger [%-8s] Program [%4ld] Phrase [%s]",
		      ++i, prog_type_to_name (prg->trig_type),
		      prg->prog->vnum, prg->trig_phrase);
	}

      return;
    }
  else if (!str_prefix (cmd, "object"))
    {
      ObjData *obj;

      if (NullStr (arg) || (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, prg = obj->pIndexData->oprog_first; prg != NULL;
	   prg = prg->next)
	{
	  chprintlnf (ch,
		      "[%2d] Trigger [%-8s] Program [%4ld] Phrase [%s]",
		      ++i, prog_type_to_name (prg->trig_type),
		      prg->prog->vnum, prg->trig_phrase);
	}

      return;
    }
  else if (!str_prefix (cmd, "mobile"))
    {
      CharData *victim;

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

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

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

      chprintlnf (ch, "Delay   %-6d [%s]", 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, prg = victim->pIndexData->mprog_first; prg != NULL;
	   prg = prg->next)
	{
	  chprintlnf (ch,
		      "[%2d] Trigger [%-8s] Program [%4ld] Phrase [%s]",
		      ++i, prog_type_to_name (prg->trig_type),
		      prg->prog->vnum, prg->trig_phrase);
	}

      return;
    }
  else
    do_pstat (n_fun, ch, "");
}

Do_Fun (do_pdump)
{
  char cmd[MIL], buf[MIL];
  ProgCode *prg;

  argument = one_argument (argument, cmd);
  one_argument (argument, buf);

  if (NullStr (cmd))
    {
      cmd_syntax (ch, NULL, n_fun, "mob <vnum>", "obj <vnum>",
		  "room <vnum>", NULL);
      return;
    }
  else if (!str_prefix (cmd, "mobile"))
    {
      if ((prg = get_prog_index (atov (buf), PRG_MPROG)) == NULL)
	{
	  chprintln (ch, "No such MOBprogram.");
	  return;
	}
      sendpage (ch, prg->code);
    }
  else if (!str_prefix (cmd, "object"))
    {
      if ((prg = get_prog_index (atov (buf), PRG_OPROG)) == NULL)
	{
	  chprintln (ch, "No such OBJprogram.");
	  return;
	}
      sendpage (ch, prg->code);
    }
  else if (!str_prefix (cmd, "room"))
    {
      if ((prg = get_prog_index (atov (buf), PRG_RPROG)) == NULL)
	{
	  chprintln (ch, "No such ROOMprogram.");
	  return;
	}
      sendpage (ch, prg->code);
    }
  else
    do_pdump (n_fun, ch, "");
}

Do_Fun (do_programs)
{
  vinterpret (ch, n_fun, argument, "trace", do_ptrace, "reset", do_preset,
	      "info", do_pinfo, "stat", do_pstat, "dump", do_pdump, NULL,
	      do_phelp);
}

void
buggy_prog (ProgList * trigger, const char *fmt, ...)
{
  char buf[MSL];
  char *pBuf;
  int i;

  assert (trigger->prog->disabled == false);

  trigger->prog->disabled = true;

  sprintf (buf, "#############" NEWLINE
	   "             Disabling prog %ld,%ld,%ld,%d,%d:" NEWLINE
	   "             ",
	   callstack_pvnum[call_level - 1],
	   callstack_mvnum[call_level - 1],
	   callstack_rvnum[call_level - 1],
	   callstack_line[call_level - 1], call_level - 1);

  if (!NullStr (fmt))
    {
      va_list args;

      pBuf = &buf[strlen (buf)];
      va_start (args, fmt);
      vsnprintf (pBuf, sizeof (buf), fmt, args);
      va_end (args);
      bug (pBuf);
    }

  pBuf = &buf[strlen (buf)];
  sprintf (pBuf,
	   NEWLINE "             Trigger type '%s' phrase '%s'" NEWLINE,
	   prog_type_to_name (trigger->trig_type), trigger->trig_phrase);

  strcat (pBuf, "             Call stack info:" NEWLINE);


  for (i = 0; i < call_level; i++)
    {
      if (!callstack_aborted[i] || (i == call_level - 1))
	{
	  sprintf (pBuf + strlen (pBuf),
		   "             Program %ld on %s %ld (in room %ld), line %d"
		   NEWLINE, callstack_pvnum[i],
		   prog_type (callstack_type[i]), callstack_mvnum[i],
		   callstack_rvnum[i], callstack_line[i]);
	}
    }
  strcat (pBuf, "#############" NEWLINE NEWLINE);

  replace_str (&trigger->prog->disabled_text, buf);

}

void
program_flow (ProgList * program, CharData * mob,
	      ObjData * obj, RoomIndex * room, CharData * ch,
	      const void *arg1, const void *arg2)
{
  CharData *rch = NULL;
  const char *source;
  const char *code;
  const char *line;
  char ctrl[MAX_INPUT_LENGTH], data[MAX_STRING_LENGTH];
  static bool init_ptrace = true;
  char buf[MSL];
  prog_t type = PRG_NONE;
  int level, eval, check;
  int state[MAX_NESTED_LEVEL], cond[MAX_NESTED_LEVEL];
  vnum_t mvnum = 0, ovnum = 0, rvnum = 0, pvnum;

  if (init_ptrace)
    {
      memset (&ptrace_time[0], 0, sizeof (time_t));
      init_ptrace = false;
    }

  if (!program)
    {
      bug ("program_flow(): program==NULL!!!");
      return;
    }

  if ((mob && obj) || (mob && room) || (obj && room))
    {
      bug ("received multiple prog types.");
      return;
    }
  if (mob)
    {
      type = PRG_MPROG;
      mvnum = mob->pIndexData->vnum;
      rvnum = mob->in_room ? mob->in_room->vnum : 0;
    }
  else if (obj)
    {
      type = PRG_OPROG;
      ovnum = obj->pIndexData->vnum;
      mvnum = 0;
      rvnum = obj->in_room ? obj->in_room->vnum : 0;
    }
  else if (room)
    {
      type = PRG_RPROG;
      mvnum = 0;
      rvnum = room->vnum;
    }
  else
    {
      bug ("did not receive a prog type.");
      return;
    }

  pvnum = program->prog->vnum;

  callstack_pvnum[call_level] = pvnum;
  callstack_mvnum[call_level] = mvnum;
  callstack_rvnum[call_level] = rvnum;
  callstack_aborted[call_level] = true;

  callstack_line[call_level] = 0;
  callstack_type[call_level] = type;

  ptrace_current++;
  ptrace_current %= MAX_PTRACE;
  ptrace_calledby[ptrace_current] = program->trig_type;
  ptrace_pvnum[ptrace_current] = pvnum;
  ptrace_mvnum[ptrace_current] = mvnum;
  ptrace_rvnum[ptrace_current] = rvnum;
  ptrace_time[ptrace_current] = current_time;
  ptrace_calllevel[ptrace_current] = call_level;
  ptrace_type[ptrace_current] = type;

  if (++call_level > MAX_CALL_LEVEL)
    {
      int i;

      if (mob)
	bugf
	  ("Progs: MAX_CALL_LEVEL exceeded, vnum %ld, mprog vnum %ld",
	   mvnum, pvnum);
      else if (obj)
	bugf
	  ("Progs: MAX_CALL_LEVEL exceeded, vnum %ld oprog vnum %ld.",
	   ovnum, pvnum);
      else
	bugf
	  ("Progs: MAX_CALL_LEVEL exceeded, vnum %ld rprog vnum %ld.",
	   rvnum, pvnum);

      log_string ("Program callstack:\n");
      for (i = 0; i < MAX_CALL_LEVEL; i++)
	{
	  logf ("[%2d] Program %ld on %s %ld (in room %ld)", i,
		callstack_pvnum[i], prog_type (callstack_type[i]),
		callstack_mvnum[i], callstack_rvnum[i]);
	}
      return;
    }

  if (program->prog->disabled)
    {
      if (ch)
	{
	  bugf
	    ("Prog %ld triggered (%s) on me by '%s', not run cause prog is disabled.",
	     program->prog->vnum,
	     prog_type_to_name (program->trig_type), ch->name);
	}
      else
	{
	  bugf
	    ("Prog %ld triggered (%s), not run cause prog is disabled.",
	     program->prog->vnum, prog_type_to_name (program->trig_type));
	}
      call_level--;
      callstack_aborted[call_level] = false;
      return;
    }

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

  source = program->prog->code;
  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 (NullStr (buf))
	break;
      if (buf[0] == '*')

	continue;

      line = data;

      if (!str_cmp (ctrl, "if"))
	{
	  if (state[level] == BEGIN_BLOCK)
	    {
	      if (mob)
		buggy_prog (program,
			    "misplaced if statement, mob %ld prog %ld",
			    mvnum, pvnum);
	      else if (obj)
		buggy_prog (program,
			    "misplaced if statement, obj %ld prog %ld",
			    ovnum, pvnum);
	      else
		buggy_prog (program,
			    "misplaced if statement, room %ld prog %ld",
			    rvnum, pvnum);
	      call_level--;
	      return;
	    }
	  state[level] = BEGIN_BLOCK;
	  if (++level >= MAX_NESTED_LEVEL)
	    {
	      if (mob)
		buggy_prog (program,
			    "Max nested level exceeded, mob %ld prog %ld",
			    mvnum, pvnum);
	      else if (obj)
		buggy_prog (program,
			    "Max nested level exceeded, obj %ld prog %ld",
			    ovnum, pvnum);
	      else
		buggy_prog (program,
			    "Max nested level exceeded, room %ld prog %ld",
			    rvnum, pvnum);
	      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)
		buggy_prog (program,
			    "invalid if_check (if), mob %ld prog %ld",
			    mvnum, pvnum);
	      else if (obj)
		buggy_prog (program,
			    "invalid if_check (if), obj %ld prog %ld",
			    ovnum, pvnum);
	      else
		buggy_prog (program,
			    "invalid if_check (if), room %ld prog %ld",
			    rvnum, pvnum);
	      call_level--;
	      return;
	    }
	  state[level] = END_BLOCK;
	}
      else if (!str_cmp (ctrl, "or"))
	{
	  if (!level || state[level - 1] != BEGIN_BLOCK)
	    {
	      if (mob)
		buggy_prog (program, "or without if, mob %ld prog %ld",
			    mvnum, pvnum);
	      else if (obj)
		buggy_prog (program, "or without if, obj %ld prog %ld",
			    ovnum, pvnum);
	      else
		buggy_prog (program, "or without if, room %ld prog %ld",
			    rvnum, pvnum);
	      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)
		buggy_prog (program,
			    "invalid if_check (or), mob %ld prog %ld",
			    mvnum, pvnum);
	      else if (obj)
		buggy_prog (program,
			    "invalid if_check (or), obj %ld prog %ld",
			    ovnum, pvnum);
	      else
		buggy_prog (program,
			    "invalid if_check (or), room %ld prog %ld",
			    rvnum, pvnum);
	      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)
		buggy_prog (program, "and without if, mob %ld prog %ld",
			    mvnum, pvnum);
	      else if (obj)
		buggy_prog (program, "and without if, obj %ld prog %ld",
			    ovnum, pvnum);
	      else
		buggy_prog (program,
			    "and without if, room %ld prog %ld", rvnum,
			    pvnum);
	      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)
		buggy_prog (program,
			    "invalid if_check (and), mob %ld prog %ld",
			    mvnum, pvnum);
	      else if (obj)
		buggy_prog (program,
			    "invalid if_check (and), obj %ld prog %ld",
			    ovnum, pvnum);
	      else
		buggy_prog (program,
			    "invalid if_check (and), room %ld prog %ld",
			    rvnum, pvnum);
	      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)
		buggy_prog (program,
			    "endif without if, mob %ld prog %ld", mvnum,
			    pvnum);
	      else if (obj)
		buggy_prog (program,
			    "endif without if, obj %ld prog %ld", ovnum,
			    pvnum);
	      else
		buggy_prog (program,
			    "endif without if, room %ld prog %ld",
			    rvnum, pvnum);
	      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)
		buggy_prog (program,
			    "else without if, mob %ld prog %ld", mvnum,
			    pvnum);
	      else if (obj)
		buggy_prog (program,
			    "else without if, obj %ld prog %ld", ovnum,
			    pvnum);
	      else
		buggy_prog (program,
			    "else without if, room %ld prog %ld", rvnum,
			    pvnum);
	      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--;
	  callstack_aborted[call_level] = false;
	  return;
	}
      else if ((!level || cond[level] == (int) true) && !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");
	      else
		mob_interpret (mob, line);
	    }
	  else if (!str_cmp (ctrl, "obj"))
	    {

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

	      line = one_argument (data, ctrl);
	      if (!room)
		bug ("room command in non ROOMprog");
	      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--;
  callstack_aborted[call_level] = false;
}

void
p_act_trigger (const char *argument, CharData * mob, ObjData * obj,
	       RoomIndex * room, CharData * ch, const void *arg1,
	       const void *arg2, flag_t type)
{
  ProgList *prg;

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

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

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

  return;
}

bool
p_percent_trigger (CharData * mob, ObjData * obj,
		   RoomIndex * room, CharData * ch,
		   const void *arg1, const void *arg2, flag_t type)
{
  ProgList *prg;

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

  if (mob)
    {
      for (prg = mob->pIndexData->mprog_first; prg != NULL; prg = prg->next)
	{
	  if (prg->trig_type == type
	      && number_percent () < atoi (prg->trig_phrase))
	    {
	      program_flow (prg, mob, NULL, NULL, ch, arg1, arg2);
	      return (true);
	    }
	}
    }
  else if (obj)
    {
      for (prg = obj->pIndexData->oprog_first; prg != NULL; prg = prg->next)
	{
	  if (prg->trig_type == type
	      && number_percent () < atoi (prg->trig_phrase))
	    {
	      program_flow (prg, NULL, obj, NULL, ch, arg1, arg2);
	      return (true);
	    }
	}
    }
  else if (room)
    {
      for (prg = room->rprog_first; prg != NULL; prg = prg->next)
	{
	  if (prg->trig_type == type
	      && number_percent () < atoi (prg->trig_phrase))
	    {
	      program_flow (prg, NULL, NULL, room, ch, arg1, arg2);
	      return (true);
	    }
	}
    }
  else
    bug ("PERCENT trigger missing program type.");

  return (false);
}

void
p_bribe_trigger (CharData * mob, CharData * ch, money_t amount)
{
  ProgList *prg;

  for (prg = mob->pIndexData->mprog_first; prg; prg = prg->next)
    {
      if (prg->trig_type == TRIG_BRIBE
	  && amount >= strtoul (prg->trig_phrase, (char **) NULL, 10))
	{
	  program_flow (prg, mob, NULL, NULL, ch, NULL, NULL);
	  break;
	}
    }
  return;
}

bool
p_exit_trigger (CharData * ch, int dir, prog_t type)
{
  CharData *mob;
  ObjData *obj;
  RoomIndex *room;
  ProgList *prg;

  if (type == PRG_MPROG)
    {
      for (mob = ch->in_room->person_first; mob != NULL;
	   mob = mob->next_in_room)
	{
	  if (IsNPC (mob)
	      && (HasTriggerMob (mob, TRIG_EXIT)
		  || HasTriggerMob (mob, TRIG_EXALL)))
	    {
	      for (prg = mob->pIndexData->mprog_first; 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, mob, NULL, NULL, ch, NULL, NULL);
		      return true;
		    }
		  else if (prg->trig_type == TRIG_EXALL
			   && dir == atoi (prg->trig_phrase))
		    {
		      program_flow (prg, mob, NULL, NULL, ch, NULL, NULL);
		      return true;
		    }
		}
	    }
	}
    }
  else if (type == PRG_OPROG)
    {
      for (obj = ch->in_room->content_first; obj != NULL;
	   obj = obj->next_content)
	{
	  if (HasTriggerObj (obj, TRIG_EXALL))
	    {
	      for (prg = obj->pIndexData->oprog_first; prg; prg = prg->next)
		{
		  if (prg->trig_type == TRIG_EXALL
		      && dir == atoi (prg->trig_phrase))
		    {
		      program_flow (prg, NULL, obj, NULL, ch, NULL, NULL);
		      return true;
		    }
		}
	    }
	}

      for (mob = ch->in_room->person_first; mob; mob = mob->next_in_room)
	{
	  for (obj = mob->carrying_first; obj; obj = obj->next_content)
	    {
	      if (HasTriggerObj (obj, TRIG_EXALL))
		{
		  for (prg = obj->pIndexData->oprog_first; prg;
		       prg = prg->next)
		    {
		      if (prg->trig_type == TRIG_EXALL
			  && dir == atoi (prg->trig_phrase))
			{
			  program_flow (prg, NULL, obj, NULL, ch, NULL, NULL);
			  return true;
			}
		    }
		}
	    }
	}
    }
  else if (type == PRG_RPROG)
    {
      room = ch->in_room;

      if (HasTriggerRoom (room, TRIG_EXALL))
	{
	  for (prg = room->rprog_first; prg; prg = prg->next)
	    {
	      if (prg->trig_type == TRIG_EXALL
		  && dir == atoi (prg->trig_phrase))
		{
		  program_flow (prg, NULL, NULL, room, ch, NULL, NULL);
		  return true;
		}
	    }
	}
    }

  return false;
}

void
p_give_trigger (CharData * mob, ObjData * obj, RoomIndex * room,
		CharData * ch, ObjData * dropped, flag_t type)
{

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

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

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

	    if (is_number (p))
	      {
		if (dropped->pIndexData->vnum == atov (p))
		  {
		    program_flow (prg, 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, mob, NULL, NULL, ch,
				      (void *) dropped, NULL);
			return;
		      }
		  }
	      }
	  }
    }
  else if (obj)
    {
      for (prg = obj->pIndexData->oprog_first; prg; prg = prg->next)
	if (prg->trig_type == type)
	  {
	    program_flow (prg, NULL, obj, NULL, ch, (void *) obj, NULL);
	    return;
	  }
    }
  else if (room)
    {
      for (prg = room->rprog_first; prg; prg = prg->next)
	if (prg->trig_type == type)
	  {
	    p = prg->trig_phrase;

	    if (is_number (p))
	      {
		if (dropped->pIndexData->vnum == atov (p))
		  {
		    program_flow (prg, 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, NULL, NULL, room, ch,
				      (void *) dropped, NULL);
			return;
		      }
		  }
	      }
	  }
    }
}

void
p_greet_trigger (CharData * ch, prog_t type)
{
  CharData *mob;
  ObjData *obj;
  RoomIndex *room;

  if (type == PRG_MPROG)
    {
      for (mob = ch->in_room->person_first; mob != NULL;
	   mob = mob->next_in_room)
	{
	  if (IsNPC (mob)
	      && (HasTriggerMob (mob, TRIG_GREET)
		  || HasTriggerMob (mob, TRIG_GRALL)))
	    {

	      if (HasTriggerMob (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 (HasTriggerMob (mob, TRIG_GRALL))
		p_percent_trigger (mob, NULL, NULL, ch, NULL, NULL,
				   TRIG_GRALL);
	    }
	}
    }
  else if (type == PRG_OPROG)
    {
      for (obj = ch->in_room->content_first; obj != NULL;
	   obj = obj->next_content)
	{
	  if (HasTriggerObj (obj, TRIG_GRALL))
	    {
	      p_percent_trigger (NULL, obj, NULL, ch, NULL, NULL, TRIG_GRALL);
	      return;
	    }
	}

      for (mob = ch->in_room->person_first; mob; mob = mob->next_in_room)
	{
	  for (obj = mob->carrying_first; obj; obj = obj->next_content)
	    {
	      if (HasTriggerObj (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 (HasTriggerRoom (room, TRIG_GRALL))
	p_percent_trigger (NULL, NULL, room, ch, NULL, NULL, TRIG_GRALL);
    }

  return;
}

void
p_hprct_trigger (CharData * mob, CharData * ch)
{
  ProgList *prg;

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