FlCodebase3.1/
FlCodebase3.1/bounty/
FlCodebase3.1/challenge/
FlCodebase3.1/clans/
FlCodebase3.1/gods/
FlCodebase3.1/mobprogs/
FlCodebase3.1/player/
FlCodebase3.1/savemud/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  * 
 *                                                                         *
 *      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                     *
 *                                                                         *
 * Code Adapted and Improved by Abandoned Realms Mud                       *
 * and Aabahran: The Forsaken Lands Mud by Virigoth                        *
 *                                                                         *
 * Continued Production of this code is available at www.flcodebase.com    *
 ***************************************************************************/

/***************************************************************************
*	ROM 2.4 is copyright 1993-1995 Russ Taylor			   *
*	ROM has been brought to you by the ROM consortium		   *
*	    Russ Taylor (rtaylor@pacinfo.com)				   *
*	    Gabrielle Taylor (gtaylor@pacinfo.com)			   *
*	    Brian Moore (rom@rom.efn.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.        *
 *                                                                         *
 ***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <ctype.h>
#include "merc.h"
#include "cabal.h"
#include "clan.h"

extern bool disguise_check( CHAR_DATA* ch, int iClass );
extern int flag_lookup( const char *word, const struct flag_type *flag_table );
extern void expand_arg_mob( char *buf, 	const char *format, 
			    CHAR_DATA *mob, CHAR_DATA *ch, 	
			    const void *arg1, 
			    const void *arg2, CHAR_DATA *rch );
extern 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 );
/*
 * These defines correspond to the entries in fn_keyword[] table.
 * If you add a new if_check, you must also add a #define here.
 */
#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_EXISTS      (24)
#define CHK_AFFECTED    (25)
#define CHK_ACT         (26)
#define CHK_OFF         (27)
#define CHK_IMM         (28)
#define CHK_CARRIES     (29)
#define CHK_WEARS       (30)
#define CHK_HAS         (31)
#define CHK_USES        (32)
#define CHK_NAME        (33)
#define CHK_POS         (34)
#define CHK_CABAL        (35)
#define CHK_RACE        (36)
#define CHK_CLASS       (37)
#define CHK_OBJTYPE     (38)
#define CHK_VNUM        (39)
#define CHK_HPCNT       (40)
#define CHK_ROOM        (41)
#define CHK_SEX         (42)
#define CHK_LEVEL       (43)
#define CHK_ALIGN       (44)
#define CHK_MONEY       (45)
#define CHK_OBJVAL0     (46)
#define CHK_OBJVAL1     (47)
#define CHK_OBJVAL2     (48)
#define CHK_OBJVAL3     (49)
#define CHK_OBJVAL4     (50)
#define CHK_GRPSIZE     (51)
#define CHK_AFF_SPELL   (52)
#define CHK_GETDELAY    (53)
#define CHK_ISCARRIED   (54)
#define CHK_ISWORN	(55)
#define CHK_FOLLOWERS	(56)
#define CHK_OBJCOST	(57)
#define CHK_ISBLOODY	(58)
#define CHK_HASQUEST	(59)
#define CHK_ISHERE	(60)
#define CHK_ISCOMBAT	(61)
#define CHK_ISROYAL     (62)
#define CHK_HOMETOWN    (63)
#define CHK_CLAN	(64)
#define CHK_CRANK	(65)
#define CHK_ISELAWFUL	(66)
#define CHK_ISENEUTRAL	(67)
#define CHK_ISECHAOTIC	(68)
#define CHK_DISGUISE	(69)
#define CHK_CABALLY	(70)
#define CHK_CABENEMY	(71)
#define CHK_CABNEUT	(72)
#define CHK_AFFECTED2   (73)
#define CHK_CP		(74)
#define CHK_SKILL	(75)
#define CHK_EQUIP	(76)
#define CHK_NCARRIES	(77)
#define CHK_RELIGION	(78)
#define CHK_MOBCOUNT	(79)
#define CHK_EXIT	(80)
#define CHK_CONTAINS	(81)
#define CHK_NCONTAINS	(82)
#define CHK_HASPATH	(83)
#define CHK_PATH	(84)
#define CHK_NOBLE	(85)
#define CHK_ISPOISONED	(86)


/*
 * These defines correspond to the entries in fn_evals[] table.
 */
#define EVAL_EQ            0
#define EVAL_GE            1
#define EVAL_LE            2
#define EVAL_GT            3
#define EVAL_LT            4
#define EVAL_NE            5

/*
 * if-check keywords:
 */
const char * fn_keyword[] =
{
    "rand",		/* if rand 30		- if random number < 30 */

    "mobhere",		/* if mobhere fido	- is there a 'fido' here */
    "objhere",		/* if objhere bottle	- is there a 'bottle' here */
			/* if mobhere 1233	- is there mob vnum 1233 here */
			/* if objhere 1233	- is there obj vnum 1233 here */
    "mobexists",	/* if mobexists fido	- is there a fido somewhere */
    "objexists",	/* if objexists sword	- is there a sword somewhere */

    "people",		/* if people > 4	- does room contain > 4 people */
    "players",		/* if players > 1	- does room contain > 1 pcs */
    "mobs",		/* if mobs > 2		- does room contain > 2 mobiles */
    "clones",		/* if clones > 3	- are there > 3 mobs of same vnum here */
    "order",		/* if order == 0	- is mob the first in room */
    "hour",		/* if hour > 11		- is the time > 11 o'clock */


    "ispc",		/* if ispc $n 		- is $n a pc */
    "isnpc",		/* if isnpc $n 		- is $n a mobile */
    "isgood",		/* if isgood $n 	- is $n good */
    "isevil",		/* if isevil $n 	- is $n evil */
    "isneutral",	/* if isneutral $n 	- is $n neutral */
    "isimmort",		/* if isimmort $n	- is $n immortal */
    "ischarm",		/* if ischarm $n	- is $n charmed */
    "isfollow",		/* if isfollow $n	- is $n following someone */
    "isactive",		/* if isactive $n	- is $n's position > SLEEPING */
    "isdelay",		/* if isdelay $i	- does $i have mobprog pending */
    "isvisible",	/* if isvisible $n	- can mob see $n */
    "hastarget",	/* if hastarget $i	- does $i have a valid target */
    "istarget",		/* if istarget $n	- is $n mob's target */
    "exists",		/* if exists $n		- does $n exist somewhere */

    "affected",		/* if affected $n blind - is $n affected by blind */
    "act",		/* if act $i sentinel	- is $i flagged sentinel */
    "off",              /* if off $i berserk	- is $i flagged berserk */
    "imm",              /* if imm $i fire	- is $i immune to fire */
    "carries",		/* if carries $n sword	- does $n have a 'sword' */
			/* if carries $n 1233	- does $n have obj vnum 1233 */
    "wears",		/* if wears $n lantern	- is $n wearing a 'lantern' */
			/* if wears $n 1233	- is $n wearing obj vnum 1233 */
    "has",    		/* if has $n weapon	- does $n have obj of type weapon */
    "uses",		/* if uses $n armor	- is $n wearing obj of type armor */
    "name",		/* if name $n puff	- is $n's name 'puff' */
    "pos",		/* if pos $n standing	- is $n standing */
    "cabal",		/* if cabal $n 'whatever'- does $n belong to cabal 'whatever' */
    "race",		/* if race $n dragon	- is $n of 'dragon' race */
    "class",		/* if class $n mage	- is $n's class 'mage' */
    "objtype",		/* if objtype $p scroll	- is $p a scroll */

    "vnum",		/* if vnum $i == 1233  	- virtual number check */
    "hpcnt",		/* if hpcnt $i > 30	- hit point percent check */
    "room",		/* if room $i == 1233	- room virtual number */
    "sex",		/* if sex $i == 0	- sex check */
    "level",		/* if level $n < 5	- level check */
    "align",		/* if align $n < -1000	- alignment check */
    "money",		/* if money $n */
    "objval0",		/* if objval0 $i > 1000  - object value[] checks 0..4 */
    "objval1",
    "objval2",
    "objval3",
    "objval4",
    "grpsize",		/* if grpsize $n > 6	- group size check */
    "affspell",		/* if affspell $n 'mark of prey'  - check if affected by - */
    "getdelay",		/* if getdelay > 1      - trigger owner has present delay*/
    "iscarried",	/* if iscarried  $i	- if $i is carried */
    "isworn",		/* if isworn $i		- if $i is worn */
    "followers",	/* if followers $n > 6	- charmies check */
    "objcost",		/* if objcost $i > 1000 - object cost */
    "isbloody",		/* if isbloody $n       - is char bloody */
    "hasquest",		/* if hasquest $n 'Slayed A Dragon' - checks for a quest */
    "ishere",		/* if ishere $q		- is mob/pc/obj here (uses ONLY  $ codes unlike mobhere) */
    "iscombat",		/* if iscombat $n	- is $n in combat */
    "isroyal",          /* if isroyal $n        - is $n a Royal */
    "hometown",         /* if hometown $n whatever - is $n from this hometown*/
    "clan",             /* if clan $n whatever   - does $n belong to whatever*/
    "crank",            /* if crank $n < 5      - is n's clan rank < 5 */
    "iselawful",        /* if iselawful $n      - is n's ethos lawful   */
    "iseneutral",       /* if iseneutral $n      - is n's ethos neutral   */
    "isechaotic",       /* if isechaotic $n      - is n's ethos chaotic   */
    "disguise",         /* if disguise $n warrior- perform disguise check */
    "cabally",          /* if cabally $n justice - is $n an ally of justice (alliance) */
    "cabenemy",         /* if cabenemy $n justice - is $n an enemy of justice (vendetta) */
    "cabneut",         /*  if cabneut $n justice - is $n neutral with justice (napact/none) */
    "affected2",	/* if affected2 $n blind - is $n affected by AFF2 bit given */
    "cp",		/* if cp $n < 15 checks for cabal points */	
    "skill",		/* if skill $n <skill> checks for character having a given skill ( >= 1 ) */	
    "equipped",		/* if equip $n <wearloc> checks char is wearing anything in given wearloc */	
    "ncarries",	       /* if ncarries $n 12 sword - does $n have 12 or more 'sword's */
		       /* if ncarries $n 12 300 - does $n have 12 or more vnum 300's */
    "religion",		/* if religion $n 'nature'- does $n follow nature */
    "mobcount",		/* if mobcount 121 > 4	- are there more then 4 mobs with vnum 121 in world */
    "exit",		/* if exit north <flag> - is the flag set on exit */
    "contains",		/* if contains $i sword - does $i contai a sword */
    "ncontains",	/* if ncontains $i 1 sword - does actor contain 1 or more swords */
    "haspath",		/* if haspath $n	- does actor have a path set */
    "path",		/* if path $n == 1024	- does actor have a path set to room 1024 */
    "isnoble",          /* if isnoble $n        - is $n a Royal */
    "ispoisoned",       /* if ispoisoned $n     - is $n poinsed with non-self poison */
    "\n"		/* Table terminator */
};

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

/* checks for not self inflicted poison */
bool check_poison( CHAR_DATA* ch ){
  AFFECT_DATA* paf;

  if (IS_NPC(ch))
    return FALSE;

  for (paf = ch->affected; paf; paf = paf->next ){
    if (paf->type != gsn_poison )
      continue;
    //if mob poison, then poisoned
    else if (IS_NULLSTR(paf->string))
      return TRUE;
    //if pc poison not from self, then piosoned
    else if (str_cmp(ch->name, paf->string))
      return TRUE;
    //otherwise self poisoned, then not poisoned
    else
      return FALSE;
  }
  return FALSE;
}

/*
 * Return a valid keyword from a keyword table
 */
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;
}

/*
 * Perform numeric evaluation.
 * Called by cmd_eval()
 */
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( "num_eval: invalid oper", 0 );
             return 0;
    }
}

/*
 * ---------------------------------------------------------------------
 * UTILITY FUNCTIONS USED BY CMD_EVAL()
 * ----------------------------------------------------------------------
 */

/*
 * check for given number of mobs in the world 
 */
int world_mobcount( char* argument ){
  CHAR_DATA* vch;
  int vnum = atoi( argument );
  int total = 0;

  for ( vch = char_list; vch != NULL ; vch = vch->next ){
    if ( vch->in_room == NULL )
      continue;
    if (vnum > 0 && IS_NPC(vch) && vch->pIndexData->vnum == vnum)
      total++;
    else if ( vnum < 1 && is_name(argument, vch->name))
      total++;
    else
      continue;
  }
  return total;
}
    
/*
 * Get a random PC in the room (for $r parameter)
 */
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( "get_random_char received multiple prog types",0);
	return NULL;
    }

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

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

/*
 * Get a random NPC in the room (for $R parameter)
 */
CHAR_DATA *get_random_mob( 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( "get_random_char received multiple prog types",0);
	return NULL;
    }

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

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

/* 
 * How many other players / mobs are there in the room
 * iFlag: 0: all, 1: players, 2: mobiles 3: mobs w/ same vnum 4: same group
 */
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( "count_people_room received multiple prog types",0);
	return 0;
    }

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

    for ( count = 0; vch; vch = vch->next_in_room )
    {
      if (vch->invis_level > 1 || vch->incog_level > 1)
	continue;
	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 );
}

/*
 * Get the order of a mob in the room. Useful when several mobs in
 * a room have the same trigger and you want only the first of them
 * to act 
 */
int get_order( CHAR_DATA *ch, OBJ_DATA *obj )
{
    CHAR_DATA *vch;
    OBJ_DATA *vobj;
    int i;

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

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

    if ( ch )
    {
	vch = ch->in_room->people;
	vobj = NULL;
    }
    else
    {
	vch = NULL;
	if ( obj->in_room )
	    vobj = obj->in_room->contents;
	else if ( obj->carried_by->in_room->contents )
	    vobj = obj->carried_by->in_room->contents;
	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;
}

/*
 * Check if ch has a given item or item type
 * vnum: item vnum or -1
 * item_type: item type or -1
 * fWear: TRUE: item must be worn, FALSE: don't care
 */
bool has_item( CHAR_DATA *ch, sh_int vnum, sh_int item_type, bool fWear )
{
    OBJ_DATA *obj;
    for ( obj = ch->carrying; obj; obj = obj->next_content )
	if ( ( vnum < 0 || obj->pIndexData->vnum == vnum )
	&&   ( item_type < 0 || obj->pIndexData->item_type == item_type )
	&&   ( !fWear || obj->wear_loc != WEAR_NONE ) )
	    return TRUE;
    return FALSE;
}
/*
 * Check if ch has a given item or item type of given amount
 syntax: <min number> <itemname/itemvnum> 
 */
int count_item( OBJ_DATA* list, char* name, int vnum ){
  OBJ_DATA* obj;
  int count = 0;

  if (list == NULL)
    return 0;
  for (obj = list; obj; obj = obj->next_content ){
    if (obj->contains)
      count += count_item(obj->contains, name, vnum );
    if ( (vnum > 0 && obj->pIndexData->vnum == vnum )
	 || is_name( name, obj->name)
	 || !str_cmp(name, "*"))
      count++;
  }
  return count;
}

bool eval_exit_flag( ROOM_INDEX_DATA* room, char* direction, char* flag ){
  EXIT_DATA* pe;
  int dir, val;

  if (room == NULL || IS_NULLSTR(direction) || IS_NULLSTR(flag))
    return FALSE;
  else if ( (dir = dir_lookup(direction)) < 0)
    return FALSE;
  else if ( (pe = room->exit[dir]) == NULL)
    return FALSE;
  else if ( ( val = flag_value( exit_flags, flag ) ) == NO_FLAG )
    return FALSE;
  else if (!IS_SET(pe->exit_info, val))
    return FALSE;
  else
    return TRUE;
}

bool has_count_item( CHAR_DATA *ch, char* number, char* item){
  int count = 0;
  int i = 0;
  int vnum = 0;

  count = atoi( number );
  vnum = atoi( item );

  i = count_item( ch->carrying, item, vnum );
  return (i >= count );
}

bool has_count_item_obj( OBJ_DATA *obj, char* number, char* item){
  int count = 0;
  int i = 0;
  int vnum = 0;

  count = atoi( number );
  vnum = atoi( item );

  i = count_item( obj->contains, item, vnum );
  return (i >= count );
}

/*
 * Check if there's a mob with given vnum in the room
 */
bool get_mob_vnum_room( CHAR_DATA *ch, OBJ_DATA *obj, ROOM_INDEX_DATA *room, sh_int vnum )
{
    CHAR_DATA *mob;

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

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

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

/*
 * Check if there's an object with given vnum in the room
 */
bool get_obj_vnum_room( CHAR_DATA *ch, OBJ_DATA *obj, ROOM_INDEX_DATA *room, sh_int vnum )
{
    OBJ_DATA *vobj;

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

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

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

    
/* ---------------------------------------------------------------------
 * CMD_EVAL
 * This monster evaluates an if/or/and statement
 * There are five kinds of statement:
 * 1) keyword and value (no $-code)	    if random 30
 * 2) keyword, comparison and value	    if people > 2
 * 3) keyword and actor		    	    if isnpc $n
 * 4) keyword, actor and value		    if carries $n sword
 * 5) keyword, actor, comparison and value  if level $n >= 10
 *
 *----------------------------------------------------------------------
 */
int cmd_eval_mob( sh_int vnum, 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;

    char *original, buf[MAX_INPUT_LENGTH], code;
    char data[MSL];
    char quest[MSL];
    int lval = 0, oper = 0;
    int rval = -2;

    original = line;
    line = one_argument( line, buf );
    if ( buf[0] == '\0' || mob == NULL )
	return FALSE;

    /*
     * If this mobile has no target, let's assume our victim is the one
     */
    if ( mob->mprog_target == NULL )
	mob->mprog_target = ch;

    switch ( check )
      {
	/*
	 * Case 1: keyword and value
	 */
      case CHK_RAND:
	return( atoi( buf ) >= number_percent() );
      case CHK_EXIT:
	return (eval_exit_flag( mob->in_room, buf, line ));
      case CHK_MOBHERE:
	    if ( is_number( buf ) )
		return( get_mob_vnum_room( mob, NULL, NULL, atoi(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, atoi(buf) ) );
	    else
		return( (bool) (get_obj_here( mob, NULL, buf) != NULL) );
        case CHK_MOBEXISTS:
	    return( (bool) (get_char_world( NULL, buf) != NULL) );
	case CHK_OBJEXISTS:
	    return( (bool) (get_obj_world( mob, buf) != NULL) );
	/*
	 * Case 2 begins here: We sneakily use rval to indicate need
	 * 		       for numeric eval...
	 */
	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 = mud_data.time_info.hour; break;
	case CHK_GETDELAY:
	  rval =  mob->mprog_delay;break;
       case CHK_MOBCOUNT: 
	 rval = world_mobcount( buf ); 
	 line = one_argument( line, buf );
	 break;
    default:;
    }

    /*
     * Case 2 continued: evaluate expression
     */
    if ( rval >= 0 )
    {
	if ( (oper = keyword_lookup( fn_evals, buf )) < 0 )
	{
	    sprintf( buf, "Cmd_eval_mob: prog %d syntax error(2) '%s'",
		vnum, original );
	    bug( buf, 0 );
	    return FALSE;
	}
	one_argument( line, buf );
	lval = rval;
	rval = atoi( buf );
	return( num_eval( lval, oper, rval ) );
    }

    /*
     * Case 3,4,5: Grab actors from $* codes
     */
    if ( buf[0] != '$' || buf[1] == '\0' )
    {
	sprintf( buf, "Cmd_eval_mob: prog %d syntax error(3) '%s'",
		vnum, original );
	bug( buf, 0 );
        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:
	    sprintf( buf, "Cmd_eval_mob: prog %d syntax error(4) '%s'",
		vnum, original );
	    bug( buf, 0 );
	    return FALSE;
    }
    /*
     * From now on, we need an actor, so if none was found, bail out
     */
    if ( lval_char == NULL && lval_obj == NULL )
    	return FALSE;

    /*
     * Case 3: Keyword, comparison and value
     */
    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_ISELAWFUL:
      return( lval_char != NULL && !IS_NPC(lval_char) && !str_cmp("lawful", ethos_table[lval_char->pcdata->ethos].name));
    case CHK_ISENEUTRAL:
      return( lval_char != NULL && !IS_NPC(lval_char) && !str_cmp("neutral", ethos_table[lval_char->pcdata->ethos].name));
    case CHK_ISECHAOTIC:
      return( lval_char != NULL && !IS_NPC(lval_char) && !str_cmp("chaotic", ethos_table[lval_char->pcdata->ethos].name));
    case CHK_ISIMMORT:
      return( lval_char != NULL && IS_IMMORTAL( lval_char ) );
    case CHK_ISBLOODY:
      return (lval_char != NULL && is_fight_delay(lval_char,90));
    case CHK_ISPOISONED:
      return (lval_char != NULL && check_poison(lval_char));
    case CHK_ISCHARM: /* A relic from MERC 2.2 MOBprograms */
      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:
      if (lval_char!= NULL)
	return( lval_char->mprog_delay > 0 );
      else if (lval_obj!= NULL)
	return( lval_obj->oprog_delay > 0 );
    case CHK_HASPATH:
      if (lval_char!= NULL) return( lval_char->spec_path != NULL );
    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 );
    case CHK_ISHERE:
      if (lval_char)
	return (lval_char->in_room && lval_char->in_room == mob->in_room);
      else if (lval_obj)
	return (lval_obj->in_room && lval_obj->in_room == mob->in_room);
      break;
    case CHK_ISCOMBAT:
      return (lval_char && lval_char->fighting);
    default:;
     }

     /* 
      * Case 4: Keyword, actor and value
      */
    one_argument_2( line, quest );
    line = one_argument( line, buf );
     switch( check )
     {
       AFFECT_DATA* paf;
	case CHK_AFFECTED:
	    return( lval_char != NULL 
		    &&  IS_SET(lval_char->affected_by, flag_lookup(buf, affect_flags)));
	case CHK_AFFECTED2:
	    return( lval_char != NULL 
		    &&  IS_SET(lval_char->affected2_by, flag_lookup(buf, affect2_flags)));
     case CHK_AFF_SPELL:
	  if (lval_char != NULL)
	    return( is_affected(lval_char, skill_lookup(buf)) );
	  else if (lval_obj != NULL)
	    return( is_affected_obj(lval_obj, skill_lookup(buf)) );
	case CHK_HASQUEST:
	  if (lval_char != NULL){
	    int i = 0;
	    expand_arg_mob(data, quest, mob, lval_char, NULL, NULL, rch);
	    while (data[i] != '\0'){
	      data[i] = LOWER(data[i]);
	      i++;
	    }
	    return( NULL == has_quest(lval_char, data) ? FALSE : TRUE );
	  }
	case CHK_ACT:
	    return( lval_char != NULL 
		&&  IS_SET(lval_char->act, flag_lookup(buf, act_flags)) );
	case CHK_IMM:
	    return( lval_char != NULL 
		&&  IS_SET(lval_char->imm_flags, flag_lookup(buf, imm_flags)) );
     case CHK_ISROYAL:
       return( lval_char != NULL && IS_ROYAL(lval_char));
     case CHK_NOBLE:
       return( lval_char != NULL && IS_NOBLE(lval_char));
     case CHK_OFF:
       return( lval_char != NULL 
	       &&  IS_SET(lval_char->off_flags, flag_lookup(buf, off_flags)) );
     case CHK_CARRIES:
       if ( is_number( buf ) )
	 return( lval_char != NULL && has_item( lval_char, atoi(buf), -1, FALSE ) );
       else
	 return( lval_char != NULL && (get_obj_carry( lval_char, buf, NULL) != NULL) );
     case CHK_NCARRIES:
       return( lval_char != NULL && has_count_item(lval_char, buf, line));
     case CHK_NCONTAINS:
       return( lval_obj != NULL && has_count_item_obj(lval_obj, buf, line));
     case CHK_WEARS:
       if ( is_number( buf ) )
	 return( lval_char != NULL && has_item( lval_char, atoi(buf), -1, TRUE ) );
       else
	 return( lval_char != NULL && (get_obj_wear( lval_char, buf, NULL) != 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 && get_skill( lval_char, skill_lookup(buf)) >= 1 );
       case CHK_EQUIP:
           return( lval_char != NULL && get_eq_char( lval_char, flag_value( wear_loc_flags, buf )));
	case CHK_CONTAINS:
	  if ( lval_obj != NULL ) return (get_obj_list( NULL, line, lval_obj->contains) != NULL);
	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_HOMETOWN: 
            return( lval_char != NULL && lval_char->hometown == hometown_lookup( buf ) );
        case CHK_CLAN: 
	  return( lval_char != NULL && HAS_CLAN(lval_char) && GET_CLAN(lval_char) == GetClanHandle( buf ));
	case CHK_POS:
	    return( lval_char != NULL && lval_char->position == position_lookup( buf ) );
	case CHK_CABAL:
	  return( lval_char != NULL 
		  && ( (buf[0] == '*' && lval_char->pCabal) || (_is_cabal(lval_char->pCabal, get_cabal( buf )))) );
	case CHK_RELIGION:
	  return( lval_char != NULL && !IS_NPC(lval_char)
		  && !str_cmp(buf, deity_table[lval_char->pcdata->way].way));
	case CHK_CABALLY:
	  return( lval_char != NULL && is_friendly(lval_char->pCabal, get_cabal( buf )) == CABAL_FRIEND );
	case CHK_CABENEMY:
	  return( lval_char != NULL && is_friendly(lval_char->pCabal, get_cabal( buf )) == CABAL_ENEMY );
	case CHK_CABNEUT:
	  return( lval_char != NULL && is_friendly(lval_char->pCabal, get_cabal( buf )) == CABAL_NEUTRAL );
	case CHK_DISGUISE:
	  return( lval_char != NULL && disguise_check(lval_char, class_lookup( buf )) );
	case CHK_RACE:
	    return( lval_char != NULL && lval_char->race == race_lookup( buf ) );
	case CHK_CLASS:
	  if ( lval_char || (paf = affect_find(lval_char->affected, gen_guise)) == NULL)
	    return( lval_char != NULL && lval_char->class == class_lookup( buf ) );
	  else
	    return( lval_char != NULL && paf->modifier == class_lookup( buf ));
     case CHK_OBJTYPE:
       return( lval_obj != NULL && lval_obj->item_type == item_lookup( buf ) );
     default:;
     }
     
    /*
     * Case 5: Keyword, actor, comparison and value
     */
    if ( (oper = keyword_lookup( fn_evals, buf )) < 0 )
    {
	sprintf( buf, "Cmd_eval_mob: prog %d syntax error(5): '%s'",
		vnum, original );
	bug( buf, 0 );
	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_PATH:
	    if ( lval_char != NULL ) lval = get_path_vnum( lval_char) ; 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_ALIGN:
            if ( lval_char != NULL ) lval = lval_char->alignment; break;
        case CHK_MONEY:  
	  if ( lval_char != NULL ) /* Viri: No silver */
	    lval = lval_char->gold; //+ (lval_char->silver * 100); 
	  break;
        case CHK_CP:  
	  if ( lval_char != NULL ) lval = GET_CP(lval_char); 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_OBJCOST:
	    if ( lval_obj != NULL ) lval = lval_obj->cost; break;
	case CHK_GRPSIZE:
	    if( lval_char != NULL ) lval = count_people_room( lval_char, NULL, NULL, 4 ); break;
	case CHK_FOLLOWERS:
	  if( lval_char != NULL ) lval = get_charmed_by( lval_char); break;
	case CHK_CRANK:
	  if( lval_char != NULL && !IS_NPC(ch)) lval = lval_char->pcdata->clan_rank; break;
	default:
            return FALSE;
    }
    return( num_eval( lval, oper, rval ) );
}

int cmd_eval_obj( sh_int vnum, 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;

    char *original, buf[MAX_INPUT_LENGTH], code;
    int lval = 0, oper = 0, rval = -1;
    char data[MSL];
    char quest[MSL];

    original = line;
    line = one_argument( line, buf );
    if ( buf[0] == '\0' || obj == NULL )
	return FALSE;

    /*
     * If this object has no target, let's assume our victim is the one
     */
    if ( obj->oprog_target == NULL )
	obj->oprog_target = ch;

    switch ( check )
    {
	/*
	 * Case 1: keyword and value
	 */
    case CHK_RAND:
      return( atoi( buf ) >= number_percent() );
    case CHK_EXIT:
      return (eval_exit_flag( in_obj(obj)->in_room, buf, line ));
    case CHK_MOBHERE:
      if ( is_number( buf ) )
	return( get_mob_vnum_room( NULL, obj, NULL,  atoi(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,  atoi(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 2 begins here: We sneakily use rval to indicate need
	 * 		       for numeric eval...
	 */
	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 = mud_data.time_info.hour; break;
        case CHK_GETDELAY:
       	    rval =  obj->oprog_delay; break;
       case CHK_MOBCOUNT: 
	 rval = world_mobcount( buf ); 
	 line = one_argument( line, buf );
	 break;
    default:;
    }

    /*
     * Case 2 continued: evaluate expression
     */
    if ( rval >= 0 )
    {
	if ( (oper = keyword_lookup( fn_evals, buf )) < 0 )
	{
	    sprintf( buf, "Cmd_eval_obj: prog %d syntax error(2) '%s'",
		vnum, original );
	    bug( buf, 0 );
	    return FALSE;
	}
	one_argument( line, buf );
	lval = rval;
	rval = atoi( buf );
	return( num_eval( lval, oper, rval ) );
    }

    /*
     * Case 3,4,5: Grab actors from $* codes
     */
    if ( buf[0] != '$' || buf[1] == '\0' )
    {
	sprintf( buf, "Cmd_eval_obj: prog %d syntax error(3) '%s'",
		vnum, original );
	bug( buf, 0 );
        return FALSE;
    }
    else
        code = buf[1];
    switch( code )
    {
    	case 'i':
            lval_obj = obj; break;
    	case 'f':
	  if (ch && ch->fighting)
	    lval_char = ch->fighting;
	  else
	    lval_char = NULL;
	  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:
	    sprintf( buf, "Cmd_eval_obj: prog %d syntax error(4) '%s'",
		vnum, original );
	    bug( buf, 0 );
	    return FALSE;
    }
    /*
     * From now on, we need an actor, so if none was found, bail out
     */
    if ( lval_char == NULL && lval_obj == NULL )
    	return FALSE;

    /*
     * Case 3: Keyword, comparison and value
     */
    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_ISELAWFUL:
      return( lval_char != NULL && !IS_NPC(lval_char) && !str_cmp("lawful", ethos_table[lval_char->pcdata->ethos].name));
    case CHK_ISENEUTRAL:
      return( lval_char != NULL && !IS_NPC(lval_char) && !str_cmp("neutral", ethos_table[lval_char->pcdata->ethos].name));
    case CHK_ISECHAOTIC:
      return( lval_char != NULL && !IS_NPC(lval_char) && !str_cmp("chaotic", ethos_table[lval_char->pcdata->ethos].name));
    case CHK_ISIMMORT:
      return( lval_char != NULL && IS_IMMORTAL( lval_char ) );
    case CHK_ISBLOODY:
      return (lval_char != NULL && is_fight_delay(lval_char,90));
    case CHK_ISPOISONED:
      return (lval_char != NULL && check_poison(lval_char));
    case CHK_ISCHARM: /* A relic from MERC 2.2 MOBprograms */
      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:
      if (lval_char!= NULL)
	return( lval_char->mprog_delay > 0 );
      else if (lval_obj!= NULL)
	return( lval_obj->oprog_delay > 0 );
    case CHK_HASPATH:
      if (lval_char!= NULL) return( lval_char->spec_path != NULL );
    case CHK_HASTARGET:
      return( lval_obj != NULL && lval_obj->oprog_target != NULL);
//	      &&  lval_obj->in_room == lval_obj->oprog_target->in_room );
    case CHK_ISTARGET:
      return( lval_char != NULL && obj->oprog_target == lval_char );
    case CHK_ISHERE:
      if (lval_char)
	return (lval_char->in_room && lval_char->in_room == obj->in_room);
      else if (lval_obj)
	return (lval_obj->in_room && lval_obj->in_room == obj->in_room);
      break;
    case CHK_ISCOMBAT:
      return (lval_char && lval_char->fighting);
    case CHK_ISCARRIED:
      return( lval_obj != NULL && lval_obj->carried_by && lval_obj->wear_loc == WEAR_NONE);
    case CHK_ISWORN:
      return( lval_obj != NULL && lval_obj->carried_by && lval_obj->wear_loc != WEAR_NONE);
    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 && get_skill( lval_char, skill_lookup(buf)) >= 1 );
    case CHK_EQUIP:
      return( lval_char != NULL && get_eq_char( lval_char, flag_value( wear_loc_flags, line )));
    case CHK_CONTAINS:
      if ( lval_obj != NULL ) return (get_obj_list( NULL, line, lval_obj->contains) != NULL);

    default:;
    }

     /* 
      * Case 4: Keyword, actor and value
      */
     one_argument( line, quest );
     line = one_argument( line, buf );
     switch( check )
     {
       AFFECT_DATA* paf;
	case CHK_AFFECTED:
	    return( lval_char != NULL 
		&&  IS_SET(lval_char->affected_by, flag_lookup(buf, affect_flags)) );
	case CHK_AFFECTED2:
	    return( lval_char != NULL 
		    &&  IS_SET(lval_char->affected2_by, flag_lookup(buf, affect2_flags)));
	case CHK_AFF_SPELL:
	  if (lval_char != NULL)
	    return( is_affected(lval_char, skill_lookup(buf)) );
	  else if (lval_obj != NULL)
	    return( is_affected_obj(lval_obj, skill_lookup(buf)) );
	case CHK_HASQUEST:
	  if (lval_char != NULL){
	    int i = 0;
	    expand_arg_other(data, quest, obj, NULL, lval_char, NULL, NULL, rch);
	    while (data[i] != '\0'){
	      data[i] = LOWER(data[i]);
	      i++;
	    }
	    return( NULL == has_quest(lval_char, data) ? FALSE : TRUE );
	  }
	case CHK_ACT:
	    return( lval_char != NULL 
		&&  IS_SET(lval_char->act, flag_lookup(buf, act_flags)) );
	case CHK_IMM:
	    return( lval_char != NULL 
		&&  IS_SET(lval_char->imm_flags, flag_lookup(buf, imm_flags)) );
        case CHK_ISROYAL:
	  return( lval_char != NULL && IS_ROYAL(lval_char));
     case CHK_NOBLE:
       return( lval_char != NULL && IS_NOBLE(lval_char));
	case CHK_OFF:
	    return( lval_char != NULL 
		&&  IS_SET(lval_char->off_flags, flag_lookup(buf, off_flags)) );
	case CHK_CARRIES:
	    if ( is_number( buf ) )
		return( lval_char != NULL && has_item( lval_char, atoi(buf), -1, FALSE ) );
	    else
		return( lval_char != NULL && (get_obj_carry( lval_char, buf, NULL) != NULL) );
     case CHK_NCARRIES:
       return( lval_char != NULL && has_count_item(lval_char, buf, line));
       break;
     case CHK_NCONTAINS:
       return( lval_obj != NULL && has_count_item_obj(lval_obj, buf, line));
       break;
     case CHK_WEARS:
	    if ( is_number( buf ) )
		return( lval_char != NULL && has_item( lval_char, atoi(buf), -1, TRUE ) );
	    else
		return( lval_char != NULL && (get_obj_wear( lval_char, buf, NULL) != 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 && get_skill( lval_char, skill_lookup(buf)) >= 1 );
       case CHK_EQUIP:
           return( lval_char != NULL && get_eq_char( lval_char, flag_value( wear_loc_flags, line)));
     case CHK_CONTAINS:
       if ( lval_obj != NULL ) return (get_obj_list( NULL, line, lval_obj->contains) != NULL);
       
	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_HOMETOWN:
            return( lval_char != NULL && lval_char->hometown == hometown_lookup( buf ) );
        case CHK_CLAN: 
	  return( lval_char != NULL && HAS_CLAN(lval_char) && GET_CLAN(lval_char) == GetClanHandle( buf ));
	case CHK_POS:
	    return( lval_char != NULL && lval_char->position == position_lookup( buf ) );
	case CHK_CABAL:
	  return( lval_char != NULL 
		  && ( (buf[0] == '*' && lval_char->pCabal) || (_is_cabal(lval_char->pCabal, get_cabal( buf )))) );
	case CHK_RELIGION:
	  return( lval_char != NULL && !IS_NPC(lval_char)
		  && !str_cmp(buf, deity_table[lval_char->pcdata->way].way));
	case CHK_CABALLY:
	  return( lval_char != NULL && is_friendly(lval_char->pCabal, get_cabal( buf )) == CABAL_FRIEND );
	case CHK_CABENEMY:
	  return( lval_char != NULL && is_friendly(lval_char->pCabal, get_cabal( buf )) == CABAL_ENEMY );
	case CHK_CABNEUT:
	  return( lval_char != NULL && is_friendly(lval_char->pCabal, get_cabal( buf )) == CABAL_NEUTRAL );
	case CHK_DISGUISE:
	  return( lval_char != NULL && disguise_check(lval_char, class_lookup( buf )) );
	case CHK_RACE:
	    return( lval_char != NULL && lval_char->race == race_lookup( buf ) );
	case CHK_CLASS:
	  if ( lval_char || (paf = affect_find(lval_char->affected, gen_guise)) == NULL)
	    return( lval_char != NULL && lval_char->class == class_lookup( buf ) );
	  else
	    return( lval_char != NULL && paf->modifier == class_lookup( buf ));
	case CHK_OBJTYPE:
	    return( lval_obj != NULL && lval_obj->item_type == item_lookup( buf ) );
	default:;
    }

    /*
     * Case 5: Keyword, actor, comparison and value
     */
    if ( (oper = keyword_lookup( fn_evals, buf )) < 0 )
    {
	sprintf( buf, "Cmd_eval_obj: prog %d syntax error(5): '%s'",
		vnum, original );
	bug( buf, 0 );
	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_PATH:
	    if ( lval_char != NULL ) lval = get_path_vnum( lval_char) ; 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_ALIGN:
            if ( lval_char != NULL ) lval = lval_char->alignment; break;
	case CHK_MONEY:  /* Money is converted to silver... */
	    if ( lval_char != NULL ) 
	      lval = lval_char->gold;//Viri: no slilver + (lval_char->silver * 100);
	    break;
        case CHK_CP:  
	  if ( lval_char != NULL ) lval = GET_CP(lval_char); 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_OBJCOST:
	    if ( lval_obj != NULL ) lval = lval_obj->cost; break;
	case CHK_GRPSIZE:
	    if( lval_char != NULL ) lval = count_people_room( lval_char, NULL, NULL, 4 ); break;
	case CHK_FOLLOWERS:
	  if( lval_char != NULL ) lval = get_charmed_by( lval_char); break;
	case CHK_CRANK:
	  if( lval_char != NULL && !IS_NPC(ch)) lval = lval_char->pcdata->clan_rank; break;
	default:
            return FALSE;
    }
    return( num_eval( lval, oper, rval ) );
}

int cmd_eval_room( sh_int vnum, 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;

    char *original, buf[MAX_INPUT_LENGTH], code;
    char data[MSL];
    char quest[MSL];
    int lval = 0, oper = 0, rval = -1;

    original = line;
    line = one_argument( line, buf );
    if ( buf[0] == '\0' || room == NULL )
	return FALSE;

    /*
     * If this room has no target, let's assume our victim is the one
     */
    if ( room->rprog_target == NULL )
	room->rprog_target = ch;

    switch ( check )
    {
	/*
	 * Case 1: keyword and value
	 */
    case CHK_RAND:
      return( atoi( buf ) >= number_percent() );
    case CHK_EXIT:
      return (eval_exit_flag(room,  buf, line ));
    case CHK_MOBHERE:
      if ( is_number( buf ) )
		return( get_mob_vnum_room( NULL, NULL, room,  atoi(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,  atoi(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 2 begins here: We sneakily use rval to indicate need
	 * 		       for numeric eval...
	 */
	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( "Cmd_eval_room: received CHK_CLONES.",0); break;
	case CHK_ORDER:
	    bug( "Cmd_eval_room: received CHK_ORDER.",0); break;
	case CHK_HOUR:
	    rval = mud_data.time_info.hour; break;
	case CHK_GETDELAY:
	  rval =  room->rprog_delay;break;
       case CHK_MOBCOUNT: 
	 rval = world_mobcount( buf ); 
	 line = one_argument( line, buf );
	 break;
	default:;
    }

    /*
     * Case 2 continued: evaluate expression
     */
    if ( rval >= 0 )
    {
	if ( (oper = keyword_lookup( fn_evals, buf )) < 0 )
	{
	    sprintf( buf, "Cmd_eval_room: prog %d syntax error(2) '%s'",
		vnum, original );
	    bug( buf, 0 );
	    return FALSE;
	}
	one_argument( line, buf );
	lval = rval;
	rval = atoi( buf );
	return( num_eval( lval, oper, rval ) );
    }

    /*
     * Case 3,4,5: Grab actors from $* codes
     */
    if ( buf[0] != '$' || buf[1] == '\0' )
    {
	sprintf( buf, "Cmd_eval_room: prog %d syntax error(3) '%s'",
		vnum, original );
	bug( buf, 0 );
        return FALSE;
    }
    else
        code = buf[1];
    switch( code )
    {
    	case 'i':
            bug( "Cmd_eval_room: 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:
	    sprintf( buf, "Cmd_eval_room: prog %d syntax error(4) '%s'",
		vnum, original );
	    bug( buf, 0 );
	    return FALSE;
    }
    /*
     * From now on, we need an actor, so if none was found, bail out
     */
    if ( lval_char == NULL && lval_obj == NULL )
    	return FALSE;

    /*
     * Case 3: Keyword, comparison and value
     */
    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_ISELAWFUL:
      return( lval_char != NULL && !IS_NPC(lval_char) && !str_cmp("lawful", ethos_table[lval_char->pcdata->ethos].name));
    case CHK_ISENEUTRAL:
      return( lval_char != NULL && !IS_NPC(lval_char) && !str_cmp("neutral", ethos_table[lval_char->pcdata->ethos].name));
    case CHK_ISECHAOTIC:
      return( lval_char != NULL && !IS_NPC(lval_char) && !str_cmp("chaotic", ethos_table[lval_char->pcdata->ethos].name));
    case CHK_ISIMMORT:
      return( lval_char != NULL && IS_IMMORTAL( lval_char ) );
    case CHK_ISBLOODY:
      return (lval_char != NULL && is_fight_delay(lval_char,90));
    case CHK_ISPOISONED:
      return (lval_char != NULL && check_poison(lval_char));
    case CHK_ISCHARM: /* A relic from MERC 2.2 MOBprograms */
      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_HASPATH:
      if (lval_char!= NULL) return( lval_char->spec_path != NULL );
    case CHK_HASTARGET:
      return( room->rprog_target != NULL );
//		&&  lval_char->in_room == lval_char->mprog_target->in_room );
    case CHK_ISTARGET:
      return( lval_char != NULL && room->rprog_target == lval_char );
    case CHK_ISHERE:
      if (lval_char)
	return (lval_char->in_room && lval_char->in_room == room);
      else if (lval_obj)
	return (lval_obj->in_room && lval_obj->in_room == room);
      break;
    case CHK_ISCOMBAT:
      return (lval_char && lval_char->fighting);
    default:;
     }

     /* 
      * Case 4: Keyword, actor and value
      */
    one_argument( line, quest );
     line = one_argument( line, buf );
     switch( check )
     {
       AFFECT_DATA* paf;
	case CHK_AFFECTED:
	    return( lval_char != NULL 
		&&  IS_SET(lval_char->affected_by, flag_lookup(buf, affect_flags)) );
	case CHK_AFFECTED2:
	    return( lval_char != NULL 
		    &&  IS_SET(lval_char->affected2_by, flag_lookup(buf, affect2_flags)));
	case CHK_AFF_SPELL:
	  if (lval_char != NULL)
	    return( is_affected(lval_char, skill_lookup(buf)) );
	  else if (lval_obj != NULL)
	    return( is_affected_obj(lval_obj, skill_lookup(buf)) );
	case CHK_HASQUEST:
	  if (lval_char != NULL){
	    int i = 0;
	    expand_arg_other(data, quest, NULL, room, lval_char, NULL, NULL, rch);
	    while (data[i] != '\0'){
	      data[i] = LOWER(data[i]);
	      i++;
	    }
	    return( NULL == has_quest(lval_char, data) ? FALSE : TRUE );
	  }
	case CHK_ACT:
	    return( lval_char != NULL 
		&&  IS_SET(lval_char->act, flag_lookup(buf, act_flags)) );
	case CHK_IMM:
	    return( lval_char != NULL 
		&&  IS_SET(lval_char->imm_flags, flag_lookup(buf, imm_flags)) );
        case CHK_ISROYAL:
	  return( lval_char != NULL && IS_ROYAL(lval_char));
     case CHK_NOBLE:
       return( lval_char != NULL && IS_NOBLE(lval_char));
     case CHK_OFF:
       return( lval_char != NULL 
	       &&  IS_SET(lval_char->off_flags, flag_lookup(buf, off_flags)) );
     case CHK_CARRIES:
       if ( is_number( buf ) )
	 return( lval_char != NULL && has_item( lval_char, atoi(buf), -1, FALSE ) );
       else
	 return( lval_char != NULL && (get_obj_carry( lval_char, buf, NULL) != NULL) );
     case CHK_WEARS:
       if ( is_number( buf ) )
	 return( lval_char != NULL && has_item( lval_char, atoi(buf), -1, TRUE ) );
       else
	 return( lval_char != NULL && (get_obj_wear( lval_char, buf, NULL ) != NULL) );
       
     case CHK_NCARRIES:
       return( lval_char != NULL && has_count_item(lval_char, buf, line));
       break;
     case CHK_NCONTAINS:
       return( lval_obj != NULL && has_count_item_obj(lval_obj, buf, line));
       break;
     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_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_HOMETOWN:
            return( lval_char != NULL && lval_char->hometown == hometown_lookup( buf ) );
        case CHK_CLAN: 
	  return( lval_char != NULL && HAS_CLAN(lval_char) && GET_CLAN(lval_char) == GetClanHandle( buf ));
	case CHK_POS:
	    return( lval_char != NULL && lval_char->position == position_lookup( buf ) );
	case CHK_CABAL:
	  return( lval_char != NULL 
		  && ( (buf[0] == '*' && lval_char->pCabal) || (_is_cabal(lval_char->pCabal, get_cabal( buf )))) );
	case CHK_RELIGION:
	  return( lval_char != NULL && !IS_NPC(lval_char)
		  && !str_cmp(buf, deity_table[lval_char->pcdata->way].way));
	case CHK_CABALLY:
	  return( lval_char != NULL && is_friendly(lval_char->pCabal, get_cabal( buf )) == CABAL_FRIEND );
	case CHK_CABENEMY:
	  return( lval_char != NULL && is_friendly(lval_char->pCabal, get_cabal( buf )) == CABAL_ENEMY );
	case CHK_CABNEUT:
	  return( lval_char != NULL && is_friendly(lval_char->pCabal, get_cabal( buf )) == CABAL_NEUTRAL );
	case CHK_DISGUISE:
	  return( lval_char != NULL && disguise_check(lval_char, class_lookup( buf )) );
	case CHK_RACE:
	    return( lval_char != NULL && lval_char->race == race_lookup( buf ) );
	case CHK_CLASS:
	  if ( lval_char || (paf = affect_find(lval_char->affected, gen_guise)) == NULL)
	    return( lval_char != NULL && lval_char->class == class_lookup( buf ) );
	  else
	    return( lval_char != NULL && paf->modifier == class_lookup( buf ));
	case CHK_OBJTYPE:
	    return( lval_obj != NULL && lval_obj->item_type == item_lookup( buf ) );
	default:;
    }

    /*
     * Case 5: Keyword, actor, comparison and value
     */
    if ( (oper = keyword_lookup( fn_evals, buf )) < 0 )
    {
	sprintf( buf, "Cmd_eval_room: prog %d syntax error(5): '%s'",
		vnum, original );
	bug( buf, 0 );
	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_PATH:
	    if ( lval_char != NULL ) lval = get_path_vnum( lval_char) ; 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_ALIGN:
            if ( lval_char != NULL ) lval = lval_char->alignment; break;
	case CHK_MONEY:  /* Money is converted to silver... */
	    if ( lval_char != NULL ) 
	      lval = lval_char->gold;//Viri: No silver + (lval_char->silver * 100);
	    break;
        case CHK_CP:  
	  if ( lval_char != NULL ) lval = GET_CP(lval_char); 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_OBJCOST:
	    if ( lval_obj != NULL ) lval = lval_obj->cost; break;
	case CHK_GRPSIZE:
	    if( lval_char != NULL ) lval = count_people_room( lval_char, NULL, NULL, 4 ); break;
	case CHK_FOLLOWERS:
	  if( lval_char != NULL ) lval = get_charmed_by( lval_char); break;
	case CHK_CRANK:
	  if( lval_char != NULL && !IS_NPC(ch)) lval = lval_char->pcdata->clan_rank; break;
	default:
            return FALSE;
    }
    return( num_eval( lval, oper, rval ) );
}

/*
 * ------------------------------------------------------------------------
 * EXPAND_ARG
 * These are hacks of act() in comm.c. I've added some safety guards,
 * so that missing or invalid $-codes do not crash the server
 * ------------------------------------------------------------------------
 */
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 fname[MAX_INPUT_LENGTH];
    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;
 
    /*
     * Discard null and zero-length messages.
     */
    if ( format == NULL || format[0] == '\0' )
        return;

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

        switch ( *str )
        {
            default:  bug( "Expand_arg_mob: bad code %d.", *str );
                          i = " <@@@> ";                        break;
            case 'a': 
		if ( rch == NULL ) 
		    rch = get_random_mob( mob, NULL, NULL );
		i = someone;
		if( rch != NULL)// && can_see( mob, rch ) )
		{
                    one_argument( rch->name, fname );
		    i = capitalize(fname);
		} 						break;
            case 'A': 
		if ( rch == NULL ) 
		  rch = get_random_mob( mob, NULL, NULL );
		i  = ( rch != NULL && can_see( mob, rch ) )
		? ( IS_NPC( rch ) ? rch->short_descr : rch->name )
		:someone;					break;
            case 'i':
		one_argument( mob->name, fname );
		i = fname;                         		break;
            case 'I': i = mob->short_descr;                     break;
            case 'f': 
		i = someone;
		if ( ch != NULL && ch->fighting != NULL)
		{
            	    one_argument( ch->fighting->name, fname );
		    i = capitalize(fname);
		}						break;
            case 'F': 
	    	i = (ch != NULL && ch->fighting != NULL)
		  ? ( IS_NPC( ch->fighting ) ? ch->fighting->short_descr : ch->fighting->name )
		: someone;                         		break;

            case 'n': 
		i = someone;
		if ( ch != NULL)// && can_see( mob, ch ) )
		{
            	    one_argument( ch->name, fname );
		    i = capitalize(fname);
		}						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, fname );
		     i = capitalize(fname);
		}						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, fname );
		    i = capitalize(fname);
		} 						break;
            case 'R': 
		if ( rch == NULL ) 
		    rch = get_random_char( mob, NULL, NULL );
		i  = ( rch != NULL && can_see( mob, rch ) )
		? ( IS_NPC( rch ) ? rch->short_descr : rch->name )
		:someone;					break;
	    case 'q':
		i = someone;
		if ( mob->mprog_target != NULL)// && can_see( mob, mob->mprog_target ) )
	        {
		    one_argument( mob->mprog_target->name, fname );
		    i = capitalize( fname );
		} 						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 'v': 
		i = someone;
		if ( ch != NULL && IS_NPC(ch))
		{
		  sprintf(fname, "%d", ch->pIndexData->vnum);
		  i = fname;
		}						break;
            case 'V': 
		i = someone;
		if ( mob != NULL && IS_NPC(mob))
		{
		  sprintf(fname, "%d", mob->pIndexData->vnum);
		  i = fname;
		}						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, fname );
                    i = fname;
		} 						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, fname );
            	    i = fname;
		} 						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 fname[MAX_INPUT_LENGTH];
    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( "expand_arg_other received a obj and a room",0);
	return;
    }

    /*
     * Discard null and zero-length messages.
     */
    if ( format == NULL || format[0] == '\0' )
        return;

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

        switch ( *str )
        {
            default:  bug( "Expand_arg: bad code %d.", *str );
                          i = " <@@@> ";                        break;
            case 'i':
		if ( obj )
		{
		    one_argument( obj->name, fname );
		    i = fname;
		}
		else
		{
		    bug( "Expand_arg_other: room had an \"i\" case.",0);
		    i = " <@@@> ";
		}						break;
            case 'I':
		if ( obj )
		    i = obj->short_descr;
		else
		{
		    bug( "Expand_arg_other: room had an \"I\" case.",0);
		    i = " <@@@> ";
		}						break;
            case 'f': 
		i = someone;
		if ( ch != NULL && ch->fighting != NULL)
		{
            	    one_argument( ch->fighting->name, fname );
		    i = capitalize(fname);
		}						break;
            case 'F': 
	    	i = (ch != NULL && ch->fighting != NULL)
		  ? ( IS_NPC( ch->fighting ) ? ch->fighting->short_descr : ch->fighting->name )
		: someone;                         		break;
            case 'n': 
		i = someone;
		if ( ch != NULL )
		{
            	    one_argument( ch->name, fname );
		    i = capitalize(fname);
		}						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, fname );
		     i = capitalize(fname);
		}						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, fname );
		    i = capitalize(fname);
		} 						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, fname );
		    i = capitalize( fname );
		}
		else if ( room && room->rprog_target != NULL )
		{
		    one_argument( room->rprog_target->name, fname );
		    i = capitalize( fname );
		} 						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( "Expand_arg_other: 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( "Expand_arg_other: 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( "Expand_arg_other: 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, fname );
                    i = fname;
		} 						break;
            case 'O':
                i = (obj1 != NULL)
                ? obj1->short_descr
                : something;					break;
            case 'p':
		i = something;
		if ( obj2 != NULL )
		{
            	    one_argument( obj2->name, fname );
            	    i = fname;
		} 						break;
            case 'P':
            	i = (obj2 != NULL)
                ? obj2->short_descr
                : something;					break;
        }
 
        ++str;
        while ( ( *point = *i ) != '\0' )
            ++point, ++i;
 
    }
    *point = '\0';
 
    return;
}

/*
 * ------------------------------------------------------------------------
 *  PROGRAM_FLOW
 *  This is the program driver. It parses the mob program code lines
 *  and passes "executable" commands to interpret()
 *  Lines beginning with 'mob' are passed to mob_interpret() to handle
 *  special mob commands (in mob_cmds.c)
 *-------------------------------------------------------------------------
 */

#define MAX_NESTED_LEVEL 12 /* Maximum nested if-else-endif's (stack size) */
#define BEGIN_BLOCK       0 /* Flag: Begin of if-else-endif block */
#define IN_BLOCK         -1 /* Flag: Executable statements */
#define END_BLOCK        -2 /* Flag: End of if-else-endif block */
#define MAX_CALL_LEVEL    5 /* Maximum nested calls */

void program_flow( 
        sh_int pvnum,  /* For diagnostic purposes */
	char *source,  /* the actual MOBprog code */
	CHAR_DATA *mob,
	OBJ_DATA *obj,
	ROOM_INDEX_DATA *room,
	CHAR_DATA *ch, const void *arg1, const void *arg2 )

{
    CHAR_DATA *rch = NULL;
    char *code, *line;
    char buf[MAX_STRING_LENGTH];
    char control[MAX_INPUT_LENGTH], data[MAX_STRING_LENGTH];
    char bugbuf[MAX_STRING_LENGTH];

    static int call_level; /* Keep track of nested "mpcall"s */

    int level, eval, check;
    int state[MAX_NESTED_LEVEL], /* Block state (BEGIN,IN,END) */
	cond[MAX_NESTED_LEVEL];  /* Boolean value based on the last if-check */

    sh_int mvnum = 0,ovnum = 0,rvnum = 0;

    /* safety check for charmed mobs */
    if (mob && IS_AFFECTED(mob, AFF_CHARM) && !IS_SET(mob->act, ACT_PET))
      return;

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

    if ( mob ){
      mvnum = mob->pIndexData->vnum;
      if (!IS_SET(mob->act, ACT_UPDATE_ALWAYS) 
	  && ( mob->in_room == NULL || 
	       (mob->homevnum && mob->in_room->vnum != mob->homevnum )) )
	return;
    }
    else if ( obj )
	ovnum = obj->pIndexData->vnum;
    else if ( room )
	rvnum = room->vnum;
    else
    {
	bug( "PROGs: program_flow did not receive a prog type.", 0 );
	return;
    }



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

    /*
     * Reset "stack"
     */
    for ( level = 0; level < MAX_NESTED_LEVEL; level++ )
    {
    	state[level] = IN_BLOCK;
        cond[level]  = TRUE;
    }
    level = 0;

    code = source;
    /*
     * Parse the Prog code
     */
    while ( *code )
    {
	bool first_arg = TRUE;
	char *b = buf, *c = control, *d = data;
	/*
	 * Get a command line. We sneakily get both the control word
	 * (if/and/or) and the rest of the line in one pass.
	 */
	while( isspace( *code ) && *code ) code++;
	while ( *code )
	{
	    if ( *code == '\n' || *code == '\r' )
		break;
	    else if ( isspace(*code) )
	    {
		if ( first_arg )
		    first_arg = FALSE;
		else
		    *d++ = *code;
	    }
	    else
	    {
		if ( first_arg )
		   *c++ = *code;
		else
		   *d++ = *code;
	    }
	    *b++ = *code++;
	}
	*b = *c = *d = '\0';

	if ( buf[0] == '\0' )
	    break;
	if ( buf[0] == '*' ) /* Comment */
	    continue;

        line = data;
	/* 
	 * Match control words
	 */
	if ( !str_cmp( control, "if" ) )
	{
	    if ( state[level] == BEGIN_BLOCK )
	    {
		if ( mob )
		    sprintf( buf, "Mobprog: misplaced if statement, mob %d prog %d",
			mvnum, pvnum );
		else if ( obj )
		    sprintf( buf, "Objprog: misplaced if statement, obj %d prog %d",
			ovnum, pvnum );
		else
		    sprintf( buf, "Roomprog: misplaced if statement, room %d prog %d",
			rvnum, pvnum );
		bug( buf, 0 );
		return;
	    }
	    state[level] = BEGIN_BLOCK;
            if ( ++level >= MAX_NESTED_LEVEL )
            {
		if ( mob )
		    sprintf( buf, "Mobprog: Max nested level exceeded, mob %d prog %d",
			mvnum, pvnum );
		else if ( obj )
		    sprintf( buf, "Objprog: Max nested level exceeded, obj %d prog %d",
			ovnum, pvnum );
		else
		    sprintf( buf, "Roomprog: Max nested level exceeded, room %d prog %d",
			rvnum, pvnum );
		bug( buf, 0 );
		return;
	    }
	    if ( level && cond[level-1] == FALSE ) 
	    {
		cond[level] = FALSE;
		continue;
	    }
	    line = one_argument( line, control );
	    if ( mob && ( check = keyword_lookup( fn_keyword, control ) ) >= 0 )
	    {
		cond[level] = cmd_eval_mob( pvnum, line, check, mob, ch, arg1, arg2, rch );
	    }
	    else if ( obj && ( check = keyword_lookup( fn_keyword, control ) ) >= 0 )
	    {
		cond[level] = cmd_eval_obj( pvnum, line, check, obj, ch, arg1, arg2, rch );
	    }
	    else if ( room && ( check = keyword_lookup( fn_keyword, control ) ) >= 0 )
	    {
		cond[level] = cmd_eval_room( pvnum, line, check, room, ch, arg1, arg2, rch );
	    }
	    else
	    {
		if ( mob )
		    sprintf( buf, "Mobprog: invalid if_check (if), mob %d prog %d",
			mvnum, pvnum );
		else if ( obj )
		    sprintf( buf, "Objprog: invalid if_check (if), obj %d prog %d",
			ovnum, pvnum );
		else
		    sprintf( buf, "Roomprog: invalid if_check (if), room %d prog %d",
			rvnum, pvnum );
		bug( buf, 0 );
		return;
	    }
	    state[level] = END_BLOCK;
    	}
	else if ( !str_cmp( control, "or" ) )
	{
	    if ( !level || state[level-1] != BEGIN_BLOCK )
	    {
		if ( mob )
		    sprintf( buf, "Mobprog: or without if, mob %d prog %d",
			mvnum, pvnum );
		else if ( obj )
		    sprintf( buf, "Objprog: or without if, obj %d prog %d",
			ovnum, pvnum );
		else
		    sprintf( buf, "Roomprog: or without if, room %d prog %d",
			rvnum, pvnum );
		bug( buf, 0 );
		return;
	    }
	    if ( level && cond[level-1] == FALSE ) continue;
	    line = one_argument( line, control );
	    if ( mob && ( check = keyword_lookup( fn_keyword, control ) ) >= 0 )
	    {
		eval = cmd_eval_mob( pvnum, line, check, mob, ch, arg1, arg2, rch );
	    }
	    else if ( obj && ( check = keyword_lookup( fn_keyword, control ) ) >= 0 )
	    {
		eval = cmd_eval_obj( pvnum, line, check, obj, ch, arg1, arg2, rch );
	    }
	    else if ( room && ( check = keyword_lookup( fn_keyword, control ) ) >= 0 )
	    {
		eval = cmd_eval_room( pvnum, line, check, room, ch, arg1, arg2, rch );
	    }
	    else
            {
		if ( mob )
		    sprintf( buf, "Mobprog: invalid if_check (or), mob %d prog %d",
			mvnum, pvnum );
		else if ( obj )
		    sprintf( buf, "Objprog: invalid if_check (or), obj %d prog %d",
			ovnum, pvnum );
		else
		    sprintf( buf, "Roomprog: invalid if_check (or), room %d prog %d",
			rvnum, pvnum );
		bug( buf, 0 );
		return;
            }
            cond[level] = (eval == TRUE) ? TRUE : cond[level];
    	}
	else if ( !str_cmp( control, "and" ) )
	{
	    if ( !level || state[level-1] != BEGIN_BLOCK )
	    {
		if ( mob )
		    sprintf( buf, "Mobprog: and without if, mob %d prog %d",
			mvnum, pvnum );
		else if ( obj )
		    sprintf( buf, "Objprog: and without if, obj %d prog %d",
			ovnum, pvnum );
		else
		    sprintf( buf, "Roomprog: and without if, room %d prog %d",
			rvnum, pvnum );
		bug( buf, 0 );
		return;
	    }
	    if ( level && cond[level-1] == FALSE ) continue;
	    line = one_argument( line, control );
	    if ( mob && ( check = keyword_lookup( fn_keyword, control ) ) >= 0 )
	    {
		eval = cmd_eval_mob( pvnum, line, check, mob, ch, arg1, arg2, rch );
	    }
	    else if ( obj && ( check = keyword_lookup( fn_keyword, control ) ) >= 0 )
	    {
		eval = cmd_eval_obj( pvnum, line, check, obj, ch, arg1, arg2, rch );
	    }
	    else if ( room && ( check = keyword_lookup( fn_keyword, control ) ) >= 0 )
	    {
		eval = cmd_eval_room( pvnum, line, check, room, ch, arg1, arg2, rch );
	    }
	    else
	    {
		if ( mob )
		    sprintf( buf, "Mobprog: invalid if_check (and), mob %d prog %d",
			mvnum, pvnum );
		else if ( obj )
		    sprintf( buf, "Objprog: invalid if_check (and), obj %d prog %d",
			ovnum, pvnum );
		else
		    sprintf( buf, "Roomprog: invalid if_check (and), room %d prog %d",
			rvnum, pvnum );
		bug( buf, 0 );
		return;
	    }
	    cond[level] = (cond[level] == TRUE) && (eval == TRUE) ? TRUE : FALSE;
    	}
	else if ( !str_cmp( control, "endif" ) )
	{
	    if ( !level || state[level-1] != BEGIN_BLOCK )
	    {
		if ( mob )
		    sprintf( buf, "Mobprog: endif without if, mob %d prog %d",
			mvnum, pvnum );
		else if ( obj )
		    sprintf( buf, "Objprog: endif without if, obj %d prog %d",
			ovnum, pvnum );
		else
		    sprintf( buf, "Roomprog: endif without if, room %d prog %d",
			rvnum, pvnum );
		bug( buf, 0 );
		call_level--;
		return;
	    }
	    cond[level] = TRUE;
	    state[level] = IN_BLOCK;
            state[--level] = END_BLOCK;
        }
	else if ( !str_cmp( control, "else" ) )
	{
	    if ( !level || state[level-1] != BEGIN_BLOCK )
	    {
		if ( mob )
		    sprintf( buf, "Mobprog: else without if, mob %d prog %d",
			mvnum, pvnum );
		else if ( obj )
		    sprintf( buf, "Objprog: else without if, obj %d prog %d",
			ovnum, pvnum );
		else
		    sprintf( buf, "Roomprog: else without if, room %d prog %d",
			rvnum, pvnum );
		bug( buf, 0 );
		return;
	    }
	    if ( level && cond[level-1] == FALSE ) continue;
            state[level] = IN_BLOCK;
            cond[level] = (cond[level] == TRUE) ? FALSE : TRUE;
        }
    	else if ( cond[level] == TRUE
		  && ( !str_cmp( control, "break" ) || !str_cmp( control, "end" ) ) )
	  {
	    call_level--;
            return;
	  }
    	else if ( cond[level] == TRUE
		  && ( !str_cmp( control, "return" ) ) )
	  {
	    call_level = 0;
            return;
	  }
	else if ( (!level || cond[level] == TRUE) && buf[0] != '\0' )
	{
	    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( control, "mob" ) )
	    {
		/* 
		 * Found a mob restricted command, pass it to mob interpreter
		 */
		line = one_argument( data, control );
		if ( !mob )
		    bug( "mob command in non MOBprog %d", pvnum);
		else{
		  mob->trust = 6969;
		  mob_interpret( mob, line );
		  mob->trust = UMIN(60, mob->level);
		}
	    }
	    else if ( !str_cmp( control, "obj" ) )
	    {
		/*
		 * Found an obj restricted command, pass it to obj interpreter
		 */
		line = one_argument( data, control );
		if ( !obj )
		    bug( "obj command in non OBJprog %d", pvnum);
		else
		    obj_interpret( obj, line );
	    }
	    else if ( !str_cmp( control, "room" ) )
	    {
		/*
		 * Found a room restricted command, pass it to room interpreter
		 */
		line = one_argument( data, control );
		if ( !room )
		    bug( "room command in non ROOMprog %d", pvnum );
		else
		    room_interpret( room, line );
	    }
	    else
	    {
		/* 
		 * Found a normal mud command, pass it to interpreter
		 */
		if ( !mob )
		    bug( "Normal MUD command in non-MOBprog, prog vnum %d", pvnum );
		else{
		  /* allow yells and skills */
		  REMOVE_BIT(mob->comm,COMM_NOCHANNELS);
		  REMOVE_BIT(mob->comm,COMM_NOYELL);
		  REMOVE_BIT(mob->comm,COMM_NOTELL);
		  mob->trust = 6969;
		  interpret( mob, data );
		  SET_BIT(mob->comm,COMM_NOCHANNELS);
		  SET_BIT(mob->comm,COMM_NOYELL);
		  SET_BIT(mob->comm,COMM_NOTELL);
		  mob->trust = mob->level;
		}
	    }
	}
    }
    call_level--;
}

/* 
 * ---------------------------------------------------------------------
 * Trigger handlers. These are called from various parts of the code
 * when an event is triggered.
 * ---------------------------------------------------------------------
 */

/*
 * A general purpose string trigger. Matches argument to a string trigger
 * phrase.
 */
void p_act_trigger( 
	char *argument, CHAR_DATA *mob, OBJ_DATA *obj,
	ROOM_INDEX_DATA *room, CHAR_DATA *ch, 
	const void *arg1, const void *arg2, int type )
{
    PROG_LIST *prg;
    char buf[MIL], buf2[MIL];
    if ( (mob && obj) || (mob && room) || (obj && room) )
    {
	bug( "Multiple program types in ACT trigger.", 0 );
	return;
    }
    /* invis imms should not trigger stuff */
    if (ch && !IS_NPC(ch) && IS_IMMORTAL(ch) 
	&& (ch->incog_level > 1 || ch->invis_level > 1))
      return;

    if ( mob )
    {
	for ( prg = mob->pIndexData->mprogs; prg != NULL; prg = prg->next )
	{
	  sprintf(buf, "%s", capitalize(prg->trig_phrase));
	  buf[0] = LOWER(buf[0]);
	  sprintf(buf2, "%s", capitalize(argument));
	  buf2[0] = LOWER(buf2[0]);

	  if ( prg->trig_type == type 
	       &&  (strstr( buf2, buf ) != NULL 
		    || prg->trig_phrase[0] == '*') )
	    {
	      program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, arg1, arg2 );
	      //    break;
	    }
	}
    }
    else if ( obj )
    {
      for ( prg = obj->pIndexData->oprogs; prg != NULL; prg = prg->next )
	{
	  sprintf(buf, "%s", capitalize(prg->trig_phrase));
	  if ( prg->trig_type == type
	       &&  (strstr( capitalize(argument), 
			    buf ) != NULL 
		    || prg->trig_phrase[0] == '*') )
	    {
	      program_flow( prg->vnum, prg->code, NULL, obj, NULL, ch, arg1, arg2 );
//	      break;
	    }
	}
    }
    else if ( room )
    {
	for ( prg = room->rprogs; prg != NULL; prg = prg->next )
	{
	  sprintf(buf, "%s", capitalize(prg->trig_phrase));
	  if ( prg->trig_type == type
	       &&  (strstr( capitalize(argument), 
			    buf ) != NULL 
		    || prg->trig_phrase[0] == '*') ){
	    
	    program_flow( prg->vnum, prg->code, NULL, NULL, room, ch, arg1, arg2 );
	    //    break;
	  }
	}
    }
    else
      bug( "ACT trigger with no program type.", 0 );
    
    return;
}

/*
 * A general purpose percentage trigger. Checks if a random percentage
 * number is less than trigger phrase
 */
bool p_percent_trigger( CHAR_DATA *mob, OBJ_DATA *obj, ROOM_INDEX_DATA *room,
	CHAR_DATA *ch, const void *arg1, const void *arg2, int type )
{
    PROG_LIST *prg;
    bool Ret = FALSE;

    if ( (mob && obj) || (mob && room) || (obj && room) )
    {
	bug( "Multiple program types in PERCENT trigger.", 0 );
	return ( FALSE );
    }
    /* invis imms should not trigger stuff */
    if (ch && !IS_NPC(ch) && IS_IMMORTAL(ch) 
	&& (ch->incog_level > 1 || ch->invis_level > 1))
      return FALSE;
    if ( mob )
    {
	for ( prg = mob->pIndexData->mprogs; 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 );
		Ret = TRUE;
	    }
	}
    }
    else if ( obj )
    {
	for ( prg = obj->pIndexData->oprogs; 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 );
		Ret = TRUE;
	    }
	}
    }
    else if ( room )
    {
	for ( prg = room->rprogs; 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 );
		Ret = TRUE;
	    }
	}
    }
    else
	bug( "PERCENT trigger missing program type.", 0 );

    return ( Ret);
}

void p_bribe_trigger( CHAR_DATA *mob, CHAR_DATA *ch, int amount )
{
  const int MAX_BRIBE = 16;
  PROG_LIST *prg;
  int last = 0;
  int key[MAX_BRIBE];
  int end_key[MAX_BRIBE];
  PROG_LIST* bribes[MAX_BRIBE];
  int i, j;

    /* invis imms should not trigger stuff */
  if (ch && !IS_NPC(ch) && IS_IMMORTAL(ch) 
      && (ch->incog_level > 1 || ch->invis_level > 1))
    return;

/* we get a list of all the progs so we can sort them */
  for ( prg = mob->pIndexData->mprogs; prg; prg = prg->next ){
    if ( prg->trig_type == TRIG_BRIBE){
      bribes[last] = prg;
      key[last++] = atoi( prg->trig_phrase );
      if (last >= MAX_BRIBE){
	last --;
	break;
      }
    }
  }
  
/* reset end key */
  for (i = 0; i < last; i++)
    end_key[i] = i;
/* sort the list with good ole bubble sort */
  for (i = 0; i < last; i ++){
    for (j = 0; j < last - 1; j++){
      if (key[j] < key[j + 1]){
	int buf = key[j];
	key[j] = key[j + 1];
	key [j + 1] = buf;
      buf = end_key[j];
      end_key[j] = end_key[j + 1];
      end_key[j + 1] = buf;
      }
    }
  }
/* check the list for the greatest matching bribe */
    for(i = 0; i < last; i ++){
      prg = bribes[end_key[i]];
      if (atoi(prg->trig_phrase) <= amount){
	if (amount)
	  obj_to_ch(create_money(amount), mob); 
	mob->gold -= amount;
	program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, NULL, NULL );
	break;
      }
    }
}


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

    /* invis imms should not trigger stuff */
    if (ch && !IS_NPC(ch) && IS_IMMORTAL(ch) 
	&& (ch->incog_level > 1 || ch->invis_level > 1))
      return FALSE;

    if ( type == PRG_MPROG )
    {
	for ( mob = ch->in_room->people; 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->mprogs; prg; prg = prg->next )
		{
		/*
		 * Exit trigger works only if the mobile is not busy
		 * (fighting etc.). If you want to be sure all players
		 * are caught, use ExAll trigger
		 */
		  if ( (prg->trig_type == TRIG_EXIT || prg->trig_type == TRIG_EXALL)
		      &&  dir == dir_lookup( prg->trig_phrase )
		      &&  mob->position == mob->pIndexData->default_pos
		      &&  can_see( mob, ch ) )
		    {
		      /* The AFF_FLAG can be set by a prog using "stop" 
			 command, that way we can selectivly block movement
			 using prog command */
		      REMOVE_BIT(ch->affected_by, AFF_FLAG);
		      program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, NULL, NULL );
		      if (IS_SET(ch->affected_by, AFF_FLAG)){
			REMOVE_BIT(ch->affected_by, AFF_FLAG);
			fRet = TRUE;
		      }
		    }
		  else
		    if ( prg->trig_type == TRIG_EXALL
			 &&   dir == dir_lookup( prg->trig_phrase ) )
		      {
			/* The AFF_FLAG can be set by a prog using "stop" 
			   command, that way we can selectivly block movement
			   using prog command 
			*/
			REMOVE_BIT(ch->affected_by, AFF_FLAG);
			program_flow( prg->vnum, prg->code, mob, NULL, NULL, ch, NULL, NULL );
			if (IS_SET(ch->affected_by, AFF_FLAG)){
			  REMOVE_BIT(ch->affected_by, AFF_FLAG);
			  fRet = TRUE;
			}
		      }
		}
	    }
	}
    }
    else if ( type == PRG_OPROG )
    {
      for ( obj = ch->in_room->contents; obj != NULL; obj = obj->next_content )
	{
	  if ( HAS_TRIGGER_OBJ( obj, TRIG_EXALL ) )
	    {
	      for ( prg = obj->pIndexData->oprogs; prg; prg = prg->next )
		{
		  if ( prg->trig_type == TRIG_EXALL
		       && dir == dir_lookup( prg->trig_phrase ) )
		    {
		      /* The AFF_FLAG can be set by a prog using "stop" 
			 command, that way we can selectivly block movement
			 using prog command 
		      */
		      REMOVE_BIT(ch->affected_by, AFF_FLAG);
		      program_flow( prg->vnum, prg->code, NULL, obj, NULL, ch, NULL, NULL );
		      if (IS_SET(ch->affected_by, AFF_FLAG)){
			REMOVE_BIT(ch->affected_by, AFF_FLAG);
			fRet = TRUE;
		      }
		    }
		}
	    }
	}
      for ( mob = ch->in_room->people; mob; mob = mob->next_in_room )
	{
	  for ( obj = mob->carrying; obj; obj = obj->next_content )
	    {
	      if ( HAS_TRIGGER_OBJ( obj, TRIG_EXALL ) )
		{
		  for ( prg = obj->pIndexData->oprogs; prg; prg = prg->next )
		    {
		      if ( prg->trig_type == TRIG_EXALL
			   && dir == dir_lookup( prg->trig_phrase ) )
			{
		      /* The AFF_FLAG can be set by a prog using "stop" 
			 command, that way we can selectivly block movement
			 using prog command 
		      */
			  REMOVE_BIT(ch->affected_by, AFF_FLAG);
			  program_flow( prg->vnum, prg->code, NULL, obj, NULL, ch, NULL, NULL );
			  if (IS_SET(ch->affected_by, AFF_FLAG)){
			    REMOVE_BIT(ch->affected_by, AFF_FLAG);
			    fRet = TRUE;
			  }
			}
		    }
		}
	    }
	}
    }
    else if ( type == PRG_RPROG )
    {
      room = ch->in_room;

	if ( HAS_TRIGGER_ROOM( room, TRIG_EXALL ) )
	{
	    for ( prg = room->rprogs; prg; prg = prg->next )
	    {
		if ( prg->trig_type == TRIG_EXALL
		    && dir == dir_lookup( prg->trig_phrase ) )
		{
		  /* The AFF_FLAG can be set by a prog using "stop" 
		     command, that way we can selectivly block movement
		     using prog command 
		  */
		  REMOVE_BIT(ch->affected_by, AFF_FLAG);		  
		  program_flow( prg->vnum, prg->code, NULL, NULL, room, ch, NULL, NULL );
		  if (IS_SET(ch->affected_by, AFF_FLAG)){
		    REMOVE_BIT(ch->affected_by, AFF_FLAG);
		    fRet = TRUE;
		  }
		}
	    }
	}
    }
    
    return fRet;
}

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

    char        buf[MAX_INPUT_LENGTH], *p;
    PROG_LIST  *prg;

    if ( (mob && obj) || (mob && room) || (obj && room) )
    {
	bug( "Multiple program types in GIVE trigger.", 0 );
	return;
    }
    /* invis imms should not trigger stuff */
    if (ch && !IS_NPC(ch) && IS_IMMORTAL(ch) 
	&& (ch->incog_level > 1 || ch->invis_level > 1))
      return;
    if ( mob ){
      for ( prg = mob->pIndexData->mprogs; prg; prg = prg->next )
	if ( prg->trig_type == TRIG_GIVE ){
	  p = prg->trig_phrase;
	  /*
	   * Vnum argument
	   */
	  if ( is_number( p ) ){
	    if ( dropped->pIndexData->vnum == atoi(p) ){
	      program_flow(prg->vnum, prg->code, mob, NULL, NULL, ch, (void *) dropped, NULL);
	      return;
	    }
	  }
	  /*
	   * Dropped object name argument, e.g. 'sword'
	   */
	  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->oprogs; prg; prg = prg->next )
	if ( prg->trig_type == type ){
	  p = prg->trig_phrase;
	  /*
	   * Vnum argument
	   */
	  if ( is_number( p ) ){
	    if ( dropped->pIndexData->vnum == atoi(p) ){
	      program_flow( prg->vnum, prg->code, NULL, obj, NULL, ch, (void *) dropped, NULL );
	      return;
	    }
	  }
	  /*
	   * Dropped object name argument, e.g. 'sword'
	   */
	  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, obj, NULL, ch, (void *) dropped, NULL );
		return;
	      }
	    }
	  }
	}
    }
    else if ( room ){
      for ( prg = room->rprogs; prg; prg = prg->next )
	if ( prg->trig_type == type ){
	  p = prg->trig_phrase;
	  /*
	   * Vnum argument
	   */
	  if ( is_number( p ) ){
	    if ( dropped->pIndexData->vnum == atoi(p) ){
	      program_flow( prg->vnum, prg->code, NULL, NULL, room, ch, (void *) dropped, NULL );
	      return;
	    }
	  }
	  /*
	   * Dropped object name argument, e.g. 'sword'
	   */
	  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, *mob_next;
    OBJ_DATA *obj;
    ROOM_INDEX_DATA *room;

    /* invis imms should not trigger stuff */
    if (ch && !IS_NPC(ch) && IS_IMMORTAL(ch) 
	&& (ch->incog_level > 1 || ch->invis_level > 1))
      return;
    if ( type == PRG_MPROG )
    {
      for ( mob = ch->in_room->people; mob != NULL; mob = mob_next)
	{    
	  mob_next = mob->next_in_room;
	    if ( IS_NPC( mob )
	    && ( HAS_TRIGGER_MOB(mob, TRIG_GREET) || HAS_TRIGGER_MOB(mob,TRIG_GRALL) ) )
	    {
		/*
	 	* Greet trigger works only if the mobile is not busy
	 	* (fighting etc.). If you want to catch all players, use
	 	* GrAll trigger
	 	*/
		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 );
		if (mob == NULL || mob->in_room == NULL)
		  continue;
		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->contents; 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->people; mob; mob = mob->next_in_room )
	{
	    for ( obj = mob->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;

    /* invis imms should not trigger stuff */
    if (ch && !IS_NPC(ch) && IS_IMMORTAL(ch) 
	&& (ch->incog_level > 1 || ch->invis_level > 1))
      return;

    for ( prg = mob->pIndexData->mprogs; 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;
	}
}