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


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

char *                  mprog_type_to_name      args( ( int type ) );
ROOM_INDEX_DATA *       find_location   args( ( CHAR_DATA *ch, char *arg ) );

char last_mprog[MSL];

#ifdef DUNNO_STRSTR
char * strstr(s1,s2) const char *s1; const char *s2;
{
    char *cp;
    int i, j=strlen(s1)-strlen(s2), k=strlen(s2);
    if(j < 0)
        return NULL;
    for(i = 0; i <= j && strncmp(s1++,s2,k) != 0; i++);
        return (i>j) ? NULL : (s1-1);
}
#endif

char *  mprog_next_command args( ( char* clist ) );
bool    mprog_seval        args( ( char* lhs, char* opr, char* rhs ) );
bool    mprog_veval        args( ( int lhs, char* opr, int rhs ) );
bool    mprog_do_ifchck    args( ( char* ifchck, CHAR_DATA* mob, CHAR_DATA* actor, OBJ_DATA* obj, void* vo, CHAR_DATA* rndm ) );
char *  mprog_process_if   args( ( char* ifchck, char* com_list, CHAR_DATA* mob, CHAR_DATA* actor, OBJ_DATA* obj, void* vo, CHAR_DATA* rndm ) );
void    mprog_translate    args( ( char ch, char* t, CHAR_DATA* mob, CHAR_DATA* actor, OBJ_DATA* obj, void* vo, CHAR_DATA* rndm ) );
void    mprog_process_cmnd args( ( char* cmnd, CHAR_DATA* mob, CHAR_DATA* actor, OBJ_DATA* obj, void* vo, CHAR_DATA* rndm ) );
void    mprog_driver       args( ( char* com_list, CHAR_DATA* mob, CHAR_DATA* actor, OBJ_DATA* obj, void* vo ) );
void    death_cry          args( ( CHAR_DATA *ch , CHAR_DATA* killer) );

char *mprog_type_to_name( int type )
{
    switch ( type )
    {
    case IN_FILE_PROG:          return "in_file_prog";
    case ACT_PROG:              return "act_prog";
    case SPEECH_PROG:           return "speech_prog";
    case RAND_PROG:             return "rand_prog";
    case FIGHT_PROG:            return "fight_prog";
    case HITPRCNT_PROG:         return "hitprcnt_prog";
    case DEATH_PROG:            return "death_prog";
    case ENTRY_PROG:            return "entry_prog";
    case GREET_PROG:            return "greet_prog";
    case ALL_GREET_PROG:        return "all_greet_prog";
    case GIVE_PROG:             return "give_prog";
    case BRIBE_PROG:            return "bribe_prog";
    case GET_PROG:		return "get_prog";
    case TIME_PROG:		return "time_prog";
    case DROP_PROG:		return "drop_prog";
    case GUILD_PROG:		return "guild_prog";
    case BLOODY_PROG:		return "bloody_prog";
    case JUSTICE_PROG:		return "justice_prog";
    case TELL_PROG:             return "tell_prog";
    default:                    return "ERROR_PROG";
    }
}

char *mprog_next_command( char *clist )
{
    char *pointer = clist;
    while ( *pointer != '\n' && *pointer != '\0' )
        pointer++;
    if ( *pointer == '\n' )
        *pointer++ = '\0';
    if ( *pointer == '\r' )
        *pointer++ = '\0';
    return ( pointer );
}

/* These two functions do the basic evaluation of ifcheck operators.   *
 *  It is important to note that the string operations are not what    *
 *  you probably expect.  Equality is exact and division is substring. *
 *  remember that lhs has been stripped of leading space, but can      *
 *  still have trailing spaces so be careful when editing since:       *
 *  "guard" and "guard " are not equal.                                */
bool mprog_seval( char *lhs, char *opr, char *rhs )                    
{
    if ( !str_cmp( opr, "==" ) || !str_cmp(opr,"="))
        return ( bool )( !str_cmp( lhs, rhs ) );
    if ( !str_cmp( opr, "!=" ) )
        return ( bool )( str_cmp( lhs, rhs ) );
    if ( !str_cmp( opr, "/" ) )
        return ( bool )( !str_infix( rhs, lhs ) );
    if ( !str_cmp( opr, "!/" ) )
        return ( bool )( str_infix( rhs, lhs ) );
    bugf ( "Improper MOBprog operator opr: %s\n\r", opr);
    return 0;
}

bool mprog_veval( int lhs, char *opr, int rhs )
{
    if ( !str_cmp( opr, "==" ) || !str_cmp(opr,"="))
        return ( lhs == rhs );
    if ( !str_cmp( opr, "!=" ) )
        return ( lhs != rhs );
    if ( !str_cmp( opr, ">" ) )
        return ( lhs > rhs );
    if ( !str_cmp( opr, "<" ) )
        return ( lhs < rhs );
    if ( !str_cmp( opr, "<=" ) )
        return ( lhs <= rhs );
    if ( !str_cmp( opr, ">=" ) )
        return ( lhs >= rhs );
    if ( !str_cmp( opr, "&" ) )
        return ( lhs & rhs );
    if ( !str_cmp( opr, "|" ) )
        return ( lhs | rhs );
    bugf ( "Improper MOBprog operator opr: %s\n\r", opr);
    return 0;
}

/* This function performs the evaluation of the if checks.  It is     *
 * here that you can add any ifchecks which you so desire. Hopefully  *
 * it is clear from what follows how one would go about adding your   *
 * own. The syntax for an if check is: ifchck ( arg ) [opr val]       *
 * where the parenthesis are required and the opr and val fields are  *
 * optional but if one is there then both must be. The spaces are all *
 * optional. The evaluation of the opr expressions is farmed out      *
 * to reduce the redundancy of the mammoth if statement list.         *
 * If there are errors, then return -1 otherwise return boolean 1,0   */
bool mprog_do_ifchck( char *ifchck, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm)
{
    char buf[MIL], arg[MIL], opr[MIL], val[MIL], newbuf[MIL];
    CHAR_DATA *vict = (CHAR_DATA *) vo;
    OBJ_DATA *v_obj = (OBJ_DATA  *) vo;
    char *bufpt = buf, *argpt = arg, *oprpt = opr, *valpt = val, *point = ifchck;
    int lhsvl, rhsvl;
    if ( *point == '\0' ) 
    {
        bug ( "Mob: %d null ifchck", mob->pIndexData->vnum ); 
        return -1;
    }   
    while ( *point == ' ' )
        point++;
    while ( *point != '(' ) 
    {
        if ( *point == '\0' )
        {
            bug ( "Mob: %d ifchck syntax error", mob->pIndexData->vnum ); 
            return -1;
        }   
        else if ( *point == ' ' && str_prefix( "quest", buf ) )
            point++;
        else 
            *bufpt++ = *point++; 
    }
    *bufpt = '\0';
    point++;
    while ( *point != ')' ) 
    {
        if ( *point == '\0' )
        {
            bug ( "Mob: %d ifchck syntax error", mob->pIndexData->vnum ); 
            return -1;
        }   
        else if ( *point == ' ' )
            point++;
        else
            *argpt++ = *point++;
    }
    *argpt = '\0';
    point++;
    while ( *point == ' ' )
        point++;
    if ( *point == '\0' ) 
    {
      *opr = '\0';
      *val = '\0';
    }   
    else
    {
        while ( ( *point != ' ' ) && ( !isalnum( *point ) ) ) 
        {
            if ( *point == '\0' )
            {
                bug ( "Mob: %d ifchck operator without value",mob->pIndexData->vnum ); 
                return -1;
            }   
            else
                *oprpt++ = *point++; 
        }
        *oprpt = '\0';
        while ( *point == ' ' )
            point++;
        for( ; ; )
	{
            if ( ( *point != ' ' ) && ( *point == '\0' ) )
                break;
            else
                *valpt++ = *point++; 
	}
        *valpt = '\0';
    }
    bufpt = buf;
    argpt = arg;
    oprpt = opr;
    valpt = val;
    /* Ok... now buf contains the ifchck, arg contains the inside of the  *
     *  parentheses, opr contains an operator if one is present, and val  *
     *  has the value if an operator was present.                         *
     *  So.. basically use if statements and run over all known ifchecks  *
     *  Once inside, use the argument and expand the lhs. Then if need be *
     *  send the lhs,opr,rhs off to be evaluated.                         */
    if ( !str_cmp( buf, "rand" ) )
        return ( number_percent() <= atoi(arg) );
    if ( !str_cmp( buf, "ishome" ) )
    {
	if (mob->homevnum == mob->in_room->vnum)
	    return 1;
	else
	    return 0;
    }
    if ( !str_cmp( buf, "isindoor" ) )
    {
	if ( !IS_OUTSIDE(mob) )
	    return 1;
	else
	    return 0;
    }
    if ( !str_cmp( buf, "findmob" ) )
    {
	CHAR_DATA *rch;
	bool found = FALSE;
	for ( rch = mob->in_room->people; rch != NULL; rch = rch->next_in_room )
	    if ( IS_NPC(rch) && can_see( mob, rch ) && rch->pIndexData->vnum == atoi(arg) )
		found = TRUE;
	if (found)
	    return 1;
	else
	    return 0;
    }
    if ( !str_cmp( buf, "isweather" ) )
    {
	if (atoi(arg) == mud_data.weather_info.sky)
	    return 1;
	else
	    return 0;
    }
    if ( !str_prefix( "quest", buf ) )
    {
	bufpt = one_argument(bufpt, newbuf);
	nlogf("%s %s", bufpt, buf);
        switch ( arg[1] )
	{
        case 'n': if ( actor && !IS_NPC(actor) ) return mprog_veval( atoi(val), opr, questnum(actor, bufpt ));
                  else return FALSE;
        case 't': if ( vict && !IS_NPC(vict) ) return mprog_veval( atoi(val), opr, questnum(vict, bufpt ));
                  else return FALSE;
        case 'r': if ( rndm && !IS_NPC(rndm) ) return mprog_veval( atoi(val), opr, questnum(rndm, bufpt ));
                  else return FALSE;
        default:  bug ( "Mob: %d bad argument to 'quest'", mob->pIndexData->vnum ); return 0;
        }
    }
    if ( !str_cmp( buf, "iscabal" ) )
        switch ( arg[1] )
	{
        case 'n': if ( actor && !IS_NPC(actor) && actor->pCabal) return mprog_veval( atoi(val), opr, actor->pCabal->vnum );
                  else return FALSE;
        case 't': if ( vict && !IS_NPC(vict) && vict->pCabal) return mprog_veval( atoi(val), opr, vict->pCabal->vnum );
                  else return FALSE;
        case 'r': if ( rndm && !IS_NPC(rndm) && rndm->pCabal) return mprog_veval( atoi(val), opr, rndm->pCabal->vnum );
                  else return FALSE;
        default:  bug ( "Mob: %d bad argument to 'iscabal'", mob->pIndexData->vnum ); return 0;
        }

// ROYAL IFs - Crypticant
    if ( !str_cmp( buf, "isroyal" ) )
        switch ( arg[1] )
        {
        case 'i': if (IS_SET( mob->act2, PLR_ROYAL )) return TRUE;
                  else return FALSE;
        case 'n': if ( actor )
                      if (IS_SET( actor->act2, PLR_ROYAL )) return TRUE;
                      else return FALSE;
                  else return 0;
        case 't': if ( vict )
                      if (IS_SET( actor->act2, PLR_ROYAL )) return TRUE;
                      else return FALSE;
                  else return 0;
        case 'r': if ( rndm )
                      if (IS_SET( actor->act2, PLR_ROYAL )) return TRUE;
                      else return FALSE;
                  else return 0;      
        default:  bug ( "Mob: %d bad argument to 'isroyal'",mob->pIndexData->vnum ); return 0;
        }        
// END

    if ( !str_cmp( buf, "isclass" ) )
        switch ( arg[1] )
        {
        case 'n': if ( actor && !IS_NPC(actor)) return ( atoi(val) == actor->class );
                  else return 0;
        case 't': if ( vict && !IS_NPC(vict)) return ( atoi(val) == vict->class );
                  else return 0;
        case 'r': if ( rndm && !IS_NPC(rndm)) return ( atoi(val) == rndm->class );
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'isclass'", mob->pIndexData->vnum ); return 0;
        }
    if ( !str_cmp( buf, "israce" ) )
        switch ( arg[1] )
        {
        case 'n': if ( actor && !IS_NPC(actor)) return ( atoi(val) == actor->race );
                  else return 0;
        case 't': if ( vict && !IS_NPC(vict)) return ( atoi(val) == vict->race );
                  else return 0;
        case 'r': if ( rndm && !IS_NPC(rndm)) return ( atoi(val) == rndm->race );
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'israce'", mob->pIndexData->vnum ); return 0;
        }
    if ( !str_cmp( buf, "roomobj" ) )
    {
	OBJ_DATA *obj;
	bool found = FALSE;
	for ( obj = mob->in_room->contents; obj != NULL; obj = obj->next_content )
	    if ( obj->pIndexData->vnum == atoi(arg) )
		found = TRUE;
	if (found)
	    return 1;
	else
	    return 0;
    }
    if ( !str_cmp( buf, "mobobj" ) )
    {
	OBJ_DATA *obj;
	bool found = FALSE;
	for ( obj = mob->carrying; obj != NULL; obj = obj->next_content )
	    if ( obj->pIndexData->vnum == atoi(arg) )
		found = TRUE;
	if (found)
	    return 1;
	else
	    return 0;
    }
    if ( !str_cmp( buf, "charwear" ) )
    {
	OBJ_DATA *obj;
	for ( obj = actor->carrying; obj != NULL; obj = obj->next_content )
	    if ( obj->pIndexData->vnum == atoi(arg) && obj->wear_loc != WEAR_NONE )
		return 1;
	return 0;
    }
    if ( !str_cmp( buf, "charobj" ) )
    {
	OBJ_DATA *obj;
	bool found = FALSE;
	for ( obj = actor->carrying; obj != NULL; obj = obj->next_content )
	    if ( obj->pIndexData->vnum == atoi(arg) )
		found = TRUE;
	if (found)
	    return 1;
	else
	    return 0;
    }
    if ( !str_cmp( buf, "ischar" ) )
    {
	if (rndm)
	    return 1;
	else
	    return 0;
    }
    if ( !str_cmp( buf, "isnghost") )
    {
        switch ( arg[1] )
	{
	case 'i': return 0;
        case 'n': if ( actor ) return ( !is_ghost( actor, 600 ) );
                  else return 1;
        case 't': if ( vict ) return ( !is_ghost( vict, 600 ) );
                  else return 1;
        case 'r': if ( rndm ) return ( !is_ghost( rndm,600 ) );
                  else return 1;
        default:  bug ( "Mob: %d bad argument to 'isnghost'", mob->pIndexData->vnum ); return 1;
	}
    }
    if ( !str_cmp( buf, "ispc" ) )
        switch ( arg[1] )
	{
	case 'i': return 0;
        case 'n': if ( actor ) return ( !IS_NPC( actor ) );
                  else return 0;
        case 't': if ( vict ) return ( !IS_NPC( vict ) );
                  else return 0;
        case 'r': if ( rndm ) return ( !IS_NPC( rndm ) );
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'ispc'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "isnpc" ) )
        switch ( arg[1] )
	{
	case 'i': return 1;
        case 'n': if ( actor ) return IS_NPC( actor );
	          else return 0;
        case 't': if ( vict ) return IS_NPC( vict );
	          else return 0;
        case 'r': if ( rndm ) return IS_NPC( rndm );
	          else return 0;
        default:  bug ("Mob: %d bad argument to 'isnpc'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "isawake" ) )
        switch ( arg[1] )
	{
	case 'i': return IS_AWAKE( mob );
        case 'n': if ( actor ) return IS_AWAKE( actor );
	          else return 0;
        case 't': if ( vict ) return IS_AWAKE( vict );
	          else return 0;
        case 'r': if ( rndm ) return IS_AWAKE( rndm );
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'isawake'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "isasleep" ) )
        switch ( arg[1] )
	{
	case 'i': return (!IS_AWAKE( mob ));
        case 'n': if ( actor ) return (!IS_AWAKE( actor ));
	          else return 0;
        case 't': if ( vict ) return (!IS_AWAKE( vict ));
	          else return 0;
        case 'r': if ( rndm ) return (!IS_AWAKE( rndm ));
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'isasleep'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "ischaotice" ) )
        switch ( arg[1] )
	{
        case 'n': if ( actor && !IS_NPC(actor)) return (actor->pcdata->ethos == ETHOS_CHAOTIC);
	          else return 0;
        case 't': if ( vict && !IS_NPC(vict)) return (vict->pcdata->ethos == ETHOS_CHAOTIC);
	          else return 0;
        case 'r': if ( rndm && !IS_NPC(rndm)) return (rndm->pcdata->ethos == ETHOS_CHAOTIC);
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'ischaotice'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "islawfule" ) )
        switch ( arg[1] )
	{
        case 'n': if ( actor && !IS_NPC(actor)) return (actor->pcdata->ethos == ETHOS_LAWFUL);
	          else return 0;
        case 't': if ( vict && !IS_NPC(vict)) return (vict->pcdata->ethos == ETHOS_LAWFUL);
	          else return 0;
        case 'r': if ( rndm && !IS_NPC(rndm)) return (rndm->pcdata->ethos == ETHOS_LAWFUL);
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'islawfule'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "isneutrale" ) )
        switch ( arg[1] )
	{
        case 'n': if ( actor && !IS_NPC(actor)) return (actor->pcdata->ethos == ETHOS_NEUTRAL);
	          else return 0;
        case 't': if ( vict && !IS_NPC(vict)) return (vict->pcdata->ethos == ETHOS_NEUTRAL);
	          else return 0;
        case 'r': if ( rndm && !IS_NPC(rndm)) return (rndm->pcdata->ethos == ETHOS_NEUTRAL);
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'isneutrale'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "istrueneutral" ) )
        switch ( arg[1] )
	{
        case 'n': if ( actor && !IS_NPC(actor)) return (actor->pcdata->ethos == ETHOS_NEUTRAL && IS_NEUTRAL(actor));
	          else return 0;
        case 't': if ( vict && !IS_NPC(vict)) return (vict->pcdata->ethos == ETHOS_NEUTRAL && IS_NEUTRAL(vict));
	          else return 0;
        case 'r': if ( rndm && !IS_NPC(rndm)) return (rndm->pcdata->ethos == ETHOS_NEUTRAL && IS_NEUTRAL(rndm));
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'istrueneutral'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "isgood" ) )
        switch ( arg[1] )
	{
	case 'i': return IS_GOOD( mob );
        case 'n': if ( actor ) return IS_GOOD( actor );
	          else return 0;
        case 't': if ( vict ) return IS_GOOD( vict );
	          else return 0;
        case 'r': if ( rndm ) return IS_GOOD( rndm );
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'isgood'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "isevil" ) )
        switch ( arg[1] )
	{
	case 'i': return IS_EVIL( mob );
        case 'n': if ( actor ) return IS_EVIL( actor );
	          else return 0;
        case 't': if ( vict ) return IS_EVIL( vict );
	          else return 0;
        case 'r': if ( rndm ) return IS_EVIL( rndm );
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'isevil", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "neutral" ) )
        switch ( arg[1] )
	{
	case 'i': return IS_NEUTRAL( mob );
        case 'n': if ( actor ) return IS_NEUTRAL( actor );
	          else return 0;
        case 't': if ( vict ) return IS_NEUTRAL( vict );
	          else return 0;
        case 'r': if ( rndm ) return IS_NEUTRAL( rndm );
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'isneutral", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "isfight" ) )
        switch ( arg[1] )
	{
	case 'i': return ( mob->fighting ) ? 1 : 0;
        case 'n': if ( actor ) return ( actor->fighting ) ? 1 : 0;
	          else return 0;
        case 't': if ( vict ) return ( vict->fighting ) ? 1 : 0;
	          else return 0;
        case 'r': if ( rndm ) return ( rndm->fighting ) ? 1 : 0;
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'isfight'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "isimmort" ) )
        switch ( arg[1] )
	{
	case 'i': return ( get_trust( mob ) > LEVEL_IMMORTAL && !mob->invis_level);
        case 'n': if ( actor ) return ( get_trust( actor ) > LEVEL_IMMORTAL && !actor->invis_level);
  	          else return 0;
        case 't': if ( vict ) return ( get_trust( vict ) > LEVEL_IMMORTAL && !vict->invis_level);
                  else return 0;
        case 'r': if ( rndm ) return ( get_trust( rndm ) > LEVEL_IMMORTAL && !rndm->invis_level);
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'isimmort'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "ischarmed" ) )
        switch ( arg[1] )
	{
        case 'i': if (IS_AFFECTED( mob, AFF_CHARM )) return TRUE;
                  else return FALSE;
        case 'n': if ( actor )
                      if (IS_AFFECTED( actor, AFF_CHARM )) return TRUE;
                      else return FALSE;
	          else return 0;
	case 't': if ( vict )
                      if (IS_AFFECTED( actor, AFF_CHARM )) return TRUE;
                      else return FALSE;
	          else return 0;
	case 'r': if ( rndm )
                      if (IS_AFFECTED( actor, AFF_CHARM )) return TRUE;
                      else return FALSE;
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'ischarmed'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "isfollow" ) )
        switch ( arg[1] )
	{
        case 'i': return ( mob->master != NULL && mob->master->in_room == mob->in_room );
        case 'n': if ( actor ) return ( actor->master != NULL && actor->master->in_room == actor->in_room );
	          else return 0;
        case 't': if ( vict ) return ( vict->master != NULL && vict->master->in_room == vict->in_room );
	          else return 0;
        case 'r': if ( rndm ) return ( rndm->master != NULL && rndm->master->in_room == rndm->in_room );
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'isfollow'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "isaffected" ) )
        switch ( arg[1] )
	{
	case 'i': return ( mob->affected != NULL );
        case 'n': if ( actor ) return ( actor->affected != NULL );
	          else return 0;
        case 't': if ( vict ) return ( vict->affected != NULL);
	          else return 0;
        case 'r': if ( rndm ) return ( rndm->affected != NULL );
	          else return 0;
        default:  bug ( "Mob: %d bad argument to 'isaffected'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "hitprcnt" ) )
        switch ( arg[1] )
	{
	case 'i': lhsvl = (mob->hit * 100)/ mob->max_hit;
	          rhsvl = atoi( val );
         	  return mprog_veval( lhsvl, opr, rhsvl );
	case 'n': if ( actor )
                  {
                      lhsvl = (actor->hit * 100)/ actor->max_hit;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
                  }
                  else return 0;
	case 't': if ( vict )
	          {
                      lhsvl = (vict->hit * 100)/ vict->max_hit;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'r': if ( rndm )
	          {
                      lhsvl = (rndm->hit * 100)/ rndm->max_hit;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'hitprcnt'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "inroom" ) )
        switch ( arg[1] )
	{
	case 'i': lhsvl = mob->in_room->vnum;
	          rhsvl = atoi(val);
	          return mprog_veval( lhsvl, opr, rhsvl );
	case 'n': if ( actor )
	          {
                      lhsvl = actor->in_room->vnum;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 't': if ( vict )
	          {
                      lhsvl = vict->in_room->vnum;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'r': if ( rndm )
	          {
                      lhsvl = rndm->in_room->vnum;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'inroom'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "sex" ) )
        switch ( arg[1] )
	{
	case 'i': lhsvl = mob->sex;
	          rhsvl = atoi( val );
	          return mprog_veval( lhsvl, opr, rhsvl );
	case 'n': if ( actor )
	          {
                      lhsvl = actor->sex;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 't': if ( vict )
	          {
                      lhsvl = vict->sex;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'r': if ( rndm )
	          {
                      lhsvl = rndm->sex;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'sex'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "position" ) )
        switch ( arg[1] )
	{
	case 'i': lhsvl = mob->position;
	          rhsvl = atoi( val );
	          return mprog_veval( lhsvl, opr, rhsvl );
	case 'n': if ( actor )
	          {
                      lhsvl = actor->position;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 't': if ( vict )
	          {
                      lhsvl = vict->position;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'r': if ( rndm )
	          {
                      lhsvl = rndm->position;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'position'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "istime" ) )
    {
	int temp;
	temp = mud_data.time_info.hour;
	lhsvl = atoi(arg);
	rhsvl = atoi(val);
	if ( lhsvl <= rhsvl )
	    return ( (lhsvl <= temp) && (temp <= rhsvl ) );
	else
	    return ( ( (lhsvl <= temp) && (rhsvl <= temp ) ) || ( ( lhsvl >= temp && rhsvl >= temp ) ) );
    }

    if ( !str_cmp( buf, "level" ) )
        switch ( arg[1] )
	{
	case 'i': lhsvl = mob->level;
	          rhsvl = atoi( val );
	          return mprog_veval( lhsvl, opr, rhsvl );
	case 'n': if ( actor )
	          {
                      lhsvl = actor->level;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 't': if ( vict )
	          {
                      lhsvl = vict->level;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'r': if ( rndm )
	          {
                      lhsvl = rndm->level;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'level'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "class" ) )
        switch ( arg[1] )
	{
	case 'i': lhsvl = mob->class;
	          rhsvl = atoi( val );
                  return mprog_veval( lhsvl, opr, rhsvl );
	case 'n': if ( actor )
	          {
                      lhsvl = actor->class;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 't': if ( vict )
	          {
                      lhsvl = vict->class;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'r': if ( rndm )
	          {
                      lhsvl = rndm->class;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'class'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "goldamt" ) )
        switch ( arg[1] )
	{
	case 'i': lhsvl = mob->gold;
                  rhsvl = atoi( val );
                  return mprog_veval( lhsvl, opr, rhsvl );
	case 'n': if ( actor )
	          {
                      lhsvl = actor->gold;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 't': if ( vict )
	          {
                      lhsvl = vict->gold;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'r': if ( rndm )
	          {
                      lhsvl = rndm->gold;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'goldamt'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "objtype" ) )
        switch ( arg[1] )
	{
	case 'o': if ( obj )
	          {
                      lhsvl = obj->item_type;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                 else return 0;
	case 'p': if ( v_obj )
	          {
                      lhsvl = v_obj->item_type;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
	          else
                      return 0;
        default:  bug ( "Mob: %d bad argument to 'objtype'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "objval0" ) )
        switch ( arg[1] )
	{
	case 'o': if ( obj )
	          {
                      lhsvl = obj->value[0];
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
                  }
                  else return 0;
	case 'p': if ( v_obj )
	          {
                      lhsvl = v_obj->value[0];
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default: bug ( "Mob: %d bad argument to 'objval0'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "objval1" ) )
        switch ( arg[1] )
	{
	case 'o': if ( obj )
	          {
                      lhsvl = obj->value[1];
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'p': if ( v_obj )
	          {
                      lhsvl = v_obj->value[1];
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default: bug ( "Mob: %d bad argument to 'objval1'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "objval2" ) )
        switch ( arg[1] )
	{
	case 'o': if ( obj )
	          {
                      lhsvl = obj->value[2];
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'p': if ( v_obj )
	          {
                      lhsvl = v_obj->value[2];
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default: bug ( "Mob: %d bad argument to 'objval2'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "objval3" ) )
        switch ( arg[1] )
	{
	case 'o': if ( obj )
	          {
                      lhsvl = obj->value[3];
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'p': if ( v_obj ) 
	          {
                      lhsvl = v_obj->value[3];
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'objval3'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "number" ) )
        switch ( arg[1] )
	{
	case 'i': lhsvl = mob->gold;
	          rhsvl = atoi( val );
	          return mprog_veval( lhsvl, opr, rhsvl );
	case 'n': if ( actor )
		  {
                      if IS_NPC( actor )
                      {
                          lhsvl = actor->pIndexData->vnum;
                          rhsvl = atoi( val );
                          return mprog_veval( lhsvl, opr, rhsvl );
                      }
		  }
                  else return 0;
	case 't': if ( vict )
		  {
                      if IS_NPC( vict )
                      {
                          lhsvl = vict->pIndexData->vnum;
                          rhsvl = atoi( val );
                          return mprog_veval( lhsvl, opr, rhsvl );
                      }
		  }
                  else return 0;
	case 'r': if ( rndm )
		  {
                      if IS_NPC( rndm )
                      {
                          lhsvl = rndm->pIndexData->vnum;
                          rhsvl = atoi( val );
                          return mprog_veval( lhsvl, opr, rhsvl );
                      }
		  }
                 else return 0;
	case 'o': if ( obj )
	          {
                      lhsvl = obj->pIndexData->vnum;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
	case 'p': if ( v_obj )
	          {
                      lhsvl = v_obj->pIndexData->vnum;
                      rhsvl = atoi( val );
                      return mprog_veval( lhsvl, opr, rhsvl );
		  }
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'number'", mob->pIndexData->vnum ); return 0;
	}
    if ( !str_cmp( buf, "name" ) )
        switch ( arg[1] )
	{
	case 'i': return mprog_seval( mob->name, opr, val );
        case 'n': if ( actor ) return mprog_seval( actor->name, opr, val );
                  else return 0;
        case 't': if ( vict ) return mprog_seval( vict->name, opr, val );
                  else return 0;
        case 'r': if ( rndm ) return mprog_seval( rndm->name, opr, val );
                  else return 0;
        case 'o': if ( obj ) return mprog_seval( obj->name, opr, val );
                  else return 0;
        case 'p': if ( v_obj ) return mprog_seval( v_obj->name, opr, val );
                  else return 0;
        default:  bug ( "Mob: %d bad argument to 'name'", mob->pIndexData->vnum ); return 0;
	}
    bug ( "Mob: %d unknown ifchck", mob->pIndexData->vnum ); 
    return 0;
}

/* Quite a long and arduous function, this guy handles the control      *
 * flow part of MOBprograms.  Basicially once the driver sees an        *
 * 'if' attention shifts to here.  While many syntax errors are         *
 * caught, some will still get through due to the handling of break     *
 * and errors in the same fashion.  The desire to break out of the      *
 * recursion without catastrophe in the event of a mis-parse was        *
 * believed to be high. Thus, if an error is found, it is bugged and    *
 * the parser acts as though a break were issued and just bails out     *
 * at that point. I havent tested all the possibilites, so I'm speaking *
 * in theory, but it is 'guaranteed' to work on syntactically correct   *
 * MOBprograms, so if the mud crashes here, check the mob carefully!    */
char *mprog_process_if( char *ifchck, char *com_list, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm )
{
    char null[1], buf[MIL];
    char *morebuf = '\0', *cmnd = '\0';
    bool loopdone = FALSE, flag = FALSE;
    int legal;
    null[0] = '\0';
    if ( ( legal = mprog_do_ifchck( ifchck, mob, actor, obj, vo, rndm ) ) )
    {
        if ( legal == 1 )
            flag = TRUE;
        else
            return NULL;
    }
    while( loopdone == FALSE )
    {
        cmnd     = com_list;
        com_list = mprog_next_command( com_list );
        while ( *cmnd == ' ' )
            cmnd++;
        if ( *cmnd == '\0' )
        {
            bug ( "Mob: %d no commands after IF/OR", mob->pIndexData->vnum ); 
            return NULL;
        }
        morebuf = one_argument( cmnd, buf );
        if ( !str_cmp( buf, "or" ) )
        {
            if ( ( legal = mprog_do_ifchck( morebuf,mob,actor,obj,vo,rndm ) ) )
            {
                if ( legal == 1 )
                    flag = TRUE;
                else
                    return NULL;
            }
        }
        else
            loopdone = TRUE;
    }
    if ( flag )
        for ( ; ; )
        {
            if ( !str_cmp( buf, "if" ) )
            { 
                com_list = mprog_process_if(morebuf,com_list,mob,actor,obj,vo,rndm);
		if (com_list == NULL)
		  com_list = null;
                while ( *cmnd==' ' )
                    cmnd++;
                if ( *com_list == '\0' )
                    return NULL;
                cmnd     = com_list;
                com_list = mprog_next_command( com_list );
                morebuf  = one_argument( cmnd,buf );
                continue;
            }
            if ( !str_cmp( buf, "break" ) )
                return NULL;
            if ( !str_cmp( buf, "endif" ) )
                return com_list; 
            if ( !str_cmp( buf, "else" ) ) 
            {
                while ( str_cmp( buf, "endif" ) ) 
                {
                    cmnd     = com_list;
                    com_list = mprog_next_command( com_list );
		    if (com_list == NULL)
		      com_list = null;
                    while ( *cmnd == ' ' )
                        cmnd++;
                    if ( *cmnd == '\0' )
                    {
                        bug ( "Mob: %d missing endif after else", mob->pIndexData->vnum );
                        return NULL;
                    }
                    morebuf = one_argument( cmnd,buf );
                }
                return com_list; 
            }
            mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm );
            cmnd     = com_list;
            com_list = mprog_next_command( com_list );
	    if (com_list == NULL)
	      com_list = null;
            while ( *cmnd == ' ' )
                cmnd++;
            if ( *cmnd == '\0' )
            {
                bug ( "Mob: %d missing else or endif", mob->pIndexData->vnum ); 
                return NULL;
            }
            morebuf = one_argument( cmnd, buf );
        }
        else
        {
            while ( ( str_cmp( buf, "else" ) ) && ( str_cmp( buf, "endif" ) ) )
            {
                cmnd     = com_list;
                com_list = mprog_next_command( com_list );
		if (com_list == NULL)
		  com_list = null;
                while ( *cmnd == ' ' )
                    cmnd++;
                if ( *cmnd == '\0' )
                {
                    bug ( "Mob: %d missing an else or endif", mob->pIndexData->vnum ); 
                    return NULL;
                }
                morebuf = one_argument( cmnd, buf );
            }
            if ( !str_cmp( buf, "endif" ) )
                return com_list;
            cmnd     = com_list;
            com_list = mprog_next_command( com_list );
	    if (com_list == NULL)
	      com_list = null;
            while ( *cmnd == ' ' )
                cmnd++;
            if ( *cmnd == '\0' )
            { 
                bug ( "Mob: %d missing endif", mob->pIndexData->vnum ); 
                return NULL;
            }
            morebuf = one_argument( cmnd, buf );
            for ( ; ; )
            {
                if ( !str_cmp( buf, "if" ) )
                { 
                    com_list = mprog_process_if( morebuf, com_list, mob, actor, obj, vo, rndm );
		    if (com_list == NULL)
		      com_list = null;
                    while ( *cmnd == ' ' )
                        cmnd++;
                    if ( *com_list == '\0' )
                        return NULL;
                    cmnd     = com_list;
                    com_list = mprog_next_command( com_list );
                    morebuf  = one_argument( cmnd,buf );
                    continue;
                }
            if ( !str_cmp( buf, "else" ) ) 
            {
                bug ( "Mob: %d found else in an else section", mob->pIndexData->vnum ); 
                return NULL;
            }
            if ( !str_cmp( buf, "break" ) )
                return NULL;
            if ( !str_cmp( buf, "endif" ) )
                return com_list; 
            mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm );
            cmnd     = com_list;
            com_list = mprog_next_command( com_list );
	    if (com_list == NULL)
	      com_list = null;
            while ( *cmnd == ' ' )
                cmnd++;
            if ( *cmnd == '\0' )
            {
                bug ( "Mob:%d missing endif in else section", mob->pIndexData->vnum ); 
                return NULL;
            }
            morebuf = one_argument( cmnd, buf );
        }
    }
}

/* This routine handles the variables for command expansion.        *
 * If you want to add any go right ahead, it should be fairly       *
 * clear how it is done and they are quite easy to do, so you       *
 * can be as creative as you want. The only catch is to check       *
 * that your variables exist before you use them. At the moment,    *
 * using $t when the secondary target refers to an object           *
 * i.e. >prog_act drops~<nl>if ispc($t)<nl>sigh<nl>endif<nl>~<nl>   *
 * probably makes the mud crash (vice versa as well) The cure       *
 * would be to change act() so that vo becomes vict & v_obj.        *
 * but this would require a lot of small changes all over the code. */
void mprog_translate( char ch, char *t, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm )
{
    static char *he_she        [] = { "it",  "he",  "she" };
    static char *him_her       [] = { "it",  "him", "her" };
    static char *his_her       [] = { "its", "his", "her" };
    CHAR_DATA   *vict             = (CHAR_DATA *) vo;
    OBJ_DATA    *v_obj            = (OBJ_DATA  *) vo;
    *t = '\0';
    switch ( ch )
    {
    case 'i': one_argument( mob->name, t ); break;
    case 'I': strcpy( t, mob->short_descr ); break;
    case 'n': if ( actor )
              {
                  one_argument( actor->name, t );
                  if ( !IS_NPC( actor ) )
                      *t = UPPER( *t );
              }
              break;
    case 'N': if ( actor ) 
              {
                  if ( IS_NPC( actor ) )
                      strcpy( t, PERS2(actor) );
                  else
                      strcpy( t, PERS2(actor) );
              }
              break;
    case 't': if ( vict )
              {
                  one_argument( vict->name, t );
                  if ( !IS_NPC( vict ) )
                      *t = UPPER( *t );
              }
              break;
    case 'T': if ( vict ) 
              {
                  if ( IS_NPC( vict ) )
                      strcpy( t, PERS2(vict) );
                  else
                      strcpy( t, PERS2(vict) );
              }
              break;
    case 'r': if ( rndm )
              {
                  one_argument( rndm->name, t );
                  if ( !IS_NPC( rndm ) )
                      *t = UPPER( *t );
              }
              break;
    case 'R': if ( rndm ) 
              {
                  if ( IS_NPC( rndm ) )
                      strcpy(t,PERS2(rndm) );
                  else
		    strcpy( t, PERS2(rndm) );
              }
              break;
    case 'e': if ( actor ) can_see( mob, actor ) ? strcpy( t, he_she[ actor->sex ] ) : strcpy( t, "someone" ); break;
    case 'm': if ( actor ) can_see( mob, actor ) ? strcpy( t, him_her[ actor->sex ] ) : strcpy( t, "someone" ); break;
    case 's': if ( actor ) can_see( mob, actor ) ? strcpy( t, his_her[ actor->sex ] ) : strcpy( t, "someone's" ); break;
    case 'E': if ( vict )  can_see( mob, vict ) ? strcpy( t, he_she[ vict->sex ] ) : strcpy( t, "someone" ); break;
    case 'M': if ( vict )  can_see( mob, vict ) ? strcpy( t, him_her[ vict->sex ] ) : strcpy( t, "someone" ); break;
    case 'S': if ( vict )  can_see( mob, vict ) ? strcpy( t, his_her[ vict->sex ] ) : strcpy( t, "someone's" ); break;
    case 'j': strcpy( t, he_she[ mob->sex ] ); break;
    case 'k': strcpy( t, him_her[ mob->sex ] ); break;
    case 'l': strcpy( t, his_her[ mob->sex ] ); break;
    case 'J': if ( rndm )  can_see( mob, rndm ) ? strcpy( t, he_she[ rndm->sex ] ) : strcpy( t, "someone" ); break;
    case 'K': if ( rndm )  can_see( mob, rndm ) ? strcpy( t, him_her[ rndm->sex ] ) : strcpy( t, "someone" ); break;
    case 'L': if ( rndm )  can_see( mob, rndm ) ? strcpy( t, his_her[ rndm->sex ] ) : strcpy( t, "someone's" ); break;
    case 'o': if ( obj )   can_see_obj( mob, obj ) ? one_argument( obj->name, t ) : strcpy( t, "something" ); break;
    case 'O': if ( obj )   can_see_obj( mob, obj ) ? strcpy( t, obj->short_descr ) : strcpy( t, "something" ); break;
    case 'p': if ( v_obj ) can_see_obj( mob, v_obj ) ? one_argument( v_obj->name, t ) : strcpy( t, "something" ); break;
    case 'P': if ( v_obj ) can_see_obj( mob, v_obj ) ? strcpy( t, v_obj->short_descr ) : strcpy( t, "something" ); break;
    case 'a': if ( obj )
                  switch ( *( obj->name ) )
                  {
                  case 'a': case 'e': case 'i': case 'o': case 'u': strcpy( t, "an" ); break;
                  default: strcpy( t, "a" );
                  }
              break;
    case 'A': if ( v_obj ) 
                  switch ( *( v_obj->name ) )
                  {
                  case 'a': case 'e': case 'i': case 'o': case 'u': strcpy( t, "an" ); break;
                  default: strcpy( t, "a" );
                  }
              break;
    case '$': strcpy( t, "$" ); break;
    default:  bug( "Mob: %d bad $var", mob->pIndexData->vnum ); break;
    }
    return;
}

/* This procedure simply copies the cmnd to a buffer while expanding *
 * any variables by calling the translate procedure.  The observant  *
 * code scrutinizer will notice that this is taken from act()        */
void mprog_process_cmnd( char *cmnd, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm )
{
    char buf[MIL], tmp[MIL];
    char *str, *i;
    char *point;
    int trust;

    point = buf;
    str = cmnd;
    while ( *str != '\0' )
    {
        if ( *str != '$' )
        {
            *point++ = *str++;
            continue;
        }
        str++;
        mprog_translate( *str, tmp, mob, actor, obj, vo, rndm );
        i = tmp;
        ++str;
        while ( ( *point = *i ) != '\0' )
            ++point, ++i;
    }
    *point = '\0';
    trust = mob->trust;
    mob->trust = 6969;
    interpret( mob, buf );
    mob->trust = trust;
}

/* The main focus of the MOBprograms.  This routine is called        *
 *  whenever a trigger is successful.  It is responsible for parsing *
 *  the command list and figuring out what to do. However, like all  *
 *  complex procedures, everything is farmed out to the other guys.  */
void mprog_driver ( char *com_list, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo)
{
    char tmpcmndlst[MSL], buf[MIL];
    char null = '\0';
    char *morebuf, *command_list, *cmnd;
    CHAR_DATA *rndm = NULL, *vch = NULL;
    int count = 0;
    char *strtime = ctime( &mud_data.current_time );
    strtime[strlen(strtime)-1] = '\0';
    sprintf (last_mprog, "Mobprog: [%5d] %s in [%5d] %s: (%s)",
      mob->pIndexData->vnum, mob->short_descr, mob->in_room ? mob->in_room->vnum : 0,
      mob->in_room ? mob->in_room->name : "(not in a room)", strtime);
    if (mob->pIndexData->mobprogs->dowhen == 0 && ( mob->in_room == NULL || mob->in_room->vnum != mob->homevnum ) )
	return;
    /* switched Viri: this should be allowed, especialy for testing etc.
    if (IS_NPC(mob) && mob->desc)
      return;
    */
    if IS_AFFECTED( mob, AFF_CHARM )
        return;
    if (actor && IS_IMMORTAL(actor) && (actor->invis_level || actor->incog_level))
	return;
    if ( (mob && mob->in_room == NULL) || (actor && actor->in_room == NULL))
	return;
    REMOVE_BIT(mob->comm,COMM_NOCHANNELS);
    REMOVE_BIT(mob->comm,COMM_NOYELL);
    REMOVE_BIT(mob->comm,COMM_NOTELL);
    mob->trust = 6969;
    for ( vch = mob->in_room->people; vch; vch = vch->next_in_room )
        if ( can_see( mob, vch ) && vch != mob && !vch->invis_level)
        {
            if ( number_range( 0, count ) == 0 )
                rndm = vch;
            count++;
        }
    if (rndm == NULL)
	rndm = mob;
    strcpy( tmpcmndlst, com_list );
    command_list = tmpcmndlst;
    cmnd         = command_list;
    if (command_list == NULL)
      command_list = &null;
    command_list = mprog_next_command( command_list );
    while ( *cmnd != '\0' )
    {
        morebuf = one_argument( cmnd, buf );
        if ( !str_cmp( buf, "if" ) )
            command_list = mprog_process_if( morebuf, command_list, mob, actor, obj, vo, rndm );
        else
            mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm );
	if (command_list == NULL)
	  command_list = &null;
        cmnd         = command_list;
        command_list = mprog_next_command( command_list );
    }
    SET_BIT(mob->comm,COMM_NOCHANNELS);
    SET_BIT(mob->comm,COMM_NOYELL);
    SET_BIT(mob->comm,COMM_NOTELL);
    mob->trust = mob->level;
    sprintf (last_mprog, "Mobprog: (Finished) [%5d] %s in [%5d] %s: (%s)",
      mob->pIndexData->vnum, mob->short_descr, mob->in_room ? mob->in_room->vnum : 0,
      mob->in_room ? mob->in_room->name : "(not in a room)", strtime);
}

/* The next two routines are the basic trigger types. Either trigger *
 *  on a certain percent, or trigger on a keyword or word phrase.    *
 *  To see how this works, look at the various trigger routines..    */
void mprog_wordlist_check( char *arg, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, int type )
{
    char temp1[MSL], temp2[MIL], word[MIL];
    MPROG_DATA *mprg;
    char *list, *start, *dupl, *end;
    int i;
    for ( mprg = mob->pIndexData->mobprogs; mprg != NULL; mprg = mprg->next )
        if ( mprg->type & type )
        {
            strcpy( temp1, mprg->arglist );
            list = temp1;
            for ( i = 0; i < strlen( list ); i++ )
                list[i] = LOWER( list[i] );
            strcpy( temp2, arg );
            dupl = temp2;
            for ( i = 0; i < strlen( dupl ); i++ )
                dupl[i] = LOWER( dupl[i] );
            if ( ( list[0] == 'p' ) && ( list[1] == ' ' ) )
            {
                list += 2;
                while ( ( start = strstr( dupl, list ) ) )
                {
                    if ( (start == dupl || *(start-1) == ' ' )
                    && ( *(end = start + strlen( list ) ) == ' ' || *end == '\n' || *end == '\r' || *end == '\0' ) )
                    {
                        mprog_driver( mprg->comlist, mob, actor, obj, vo );
                        break;
                    }
                    else
                        dupl = start+1;
                }
            }
            else
            {
                list = one_argument( list, word );
                for( ; word[0] != '\0'; list = one_argument( list, word ) )
                    while ( ( start = strstr( dupl, word ) ) )
                    {
                        if ( ( start == dupl || *(start-1) == ' ' )
                        && ( *(end = start + strlen( word ) ) == ' ' || *end == '\n' || *end == '\r' || *end == '\0' ) )
                        {
                            mprog_driver( mprg->comlist, mob, actor, obj, vo );
                            break;
                        }
                        else
                            dupl = start+1;
                    }
            }
        }
}

void mprog_percent_check( CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, int type)
{
    MPROG_DATA * mprg;
    for ( mprg = mob->pIndexData->mobprogs; mprg != NULL; mprg = mprg->next )
        if ( ( mprg->type & type ) && ( number_percent( ) < atoi( mprg->arglist ) ) )
        {
            mprog_driver( mprg->comlist, mob, actor, obj, vo );
            if ( type != GREET_PROG && type != ALL_GREET_PROG )
                break;
        }
}

/* The triggers.. These are really basic, and since most appear only       *
 * once in the code (hmm. i think they all do) it would be more efficient  *
 * to substitute the code in and make the mprog_xxx_check routines global. *
 * However, they are all here in one nice place at the moment to make it   *
 * easier to see what they look like. If you do substitute them back in,   *
 * make sure you remember to modify the variable names to the ones in the  *
 * trigger calls.                                                          */
void mprog_bribe_trigger( CHAR_DATA *mob, CHAR_DATA *ch, int amount )
{
    char buf[MSL];
    MPROG_DATA *mprg;
    OBJ_DATA *obj;
    if ( IS_AWAKE(mob) && IS_NPC( mob ) && ( mob->pIndexData->progtypes & BRIBE_PROG ) )
    {
        obj = create_object( get_obj_index( OBJ_VNUM_GOLD_SOME ), 0);
        sprintf( buf, obj->short_descr, amount );
        free_string( obj->short_descr );
        obj->short_descr = str_dup( buf );
        obj->value[0] = amount;
        obj_to_char( obj, mob );
        mob->gold -= amount;
        for ( mprg = mob->pIndexData->mobprogs; mprg != NULL; mprg = mprg->next )
            if ( ( mprg->type & BRIBE_PROG ) && ( amount >= atoi( mprg->arglist ) ) && mob->position != POS_FIGHTING )
            {
                mprog_driver( mprg->comlist, mob, ch, obj, NULL );
                break;
            }
    }
}

void mprog_time_trigger( CHAR_DATA *mob )
{
    if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & TIME_PROG ) && mob->position != POS_FIGHTING )
        mprog_percent_check( mob, NULL, NULL, NULL, TIME_PROG );
}

void mprog_death_trigger( CHAR_DATA *ch, CHAR_DATA *mob )
{
    if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & DEATH_PROG ) )
        mprog_percent_check( mob, ch, NULL, NULL, DEATH_PROG );
    if (!IS_SET(mob->form,FORM_INSTANT_DECAY))
	death_cry( mob , ch );
}

void mprog_entry_trigger( CHAR_DATA *mob )
{
    if ( IS_AWAKE(mob) && IS_NPC( mob ) && ( mob->pIndexData->progtypes & ENTRY_PROG ) && mob->position != POS_FIGHTING)
        mprog_percent_check( mob, NULL, NULL, NULL, ENTRY_PROG );
}

void mprog_fight_trigger( CHAR_DATA *mob, CHAR_DATA *ch )
{
    if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & FIGHT_PROG ) )
        mprog_percent_check( mob, ch, NULL, NULL, FIGHT_PROG );
}

void mprog_give_trigger( CHAR_DATA *mob, CHAR_DATA *ch, OBJ_DATA *obj )
{
    if ( IS_AWAKE(mob) && IS_NPC( mob ) && ( mob->pIndexData->progtypes & GIVE_PROG ) && mob->position != POS_FIGHTING )
        mprog_percent_check( mob, ch, obj, NULL, GIVE_PROG );
}

void mprog_get_trigger( CHAR_DATA *mob, CHAR_DATA *ch, OBJ_DATA *obj )
{
    if ( IS_AWAKE(mob) && IS_NPC( mob ) && ( mob->pIndexData->progtypes & GET_PROG ) && mob->position != POS_FIGHTING )
        mprog_percent_check( mob, ch, obj, NULL, GET_PROG );
}

void mprog_drop_trigger( CHAR_DATA *mob, CHAR_DATA *ch, OBJ_DATA *obj )
{
    if ( IS_AWAKE(mob) && IS_NPC( mob ) && ( mob->pIndexData->progtypes & DROP_PROG ) && mob->position != POS_FIGHTING)
        mprog_percent_check( mob, ch, obj, NULL, DROP_PROG );
}

void mprog_greet_trigger( CHAR_DATA *ch )
{
    CHAR_DATA *vmob, *vnext;
    for ( vmob = ch->in_room->people; vmob != NULL; vmob = vnext )
    {
        vnext = vmob->next_in_room;
        if ( IS_NPC( vmob ) && ch != vmob && can_see( vmob, ch ) && ( vmob->fighting == NULL )
	&& vmob->position != POS_FIGHTING && IS_AWAKE( vmob ) && ( vmob->pIndexData->progtypes & GREET_PROG) )
            mprog_percent_check( vmob, ch, NULL, NULL, GREET_PROG );
        else if ( IS_NPC( vmob ) && ( vmob->fighting == NULL ) && IS_AWAKE( vmob )
        && ( vmob->pIndexData->progtypes & ALL_GREET_PROG ) )
            mprog_percent_check(vmob,ch,NULL,NULL,ALL_GREET_PROG);
    }
}

void mprog_hitprcnt_trigger( CHAR_DATA *mob, CHAR_DATA *ch)
{
    MPROG_DATA *mprg;
    if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & HITPRCNT_PROG ) )
    for ( mprg = mob->pIndexData->mobprogs; mprg != NULL; mprg = mprg->next )
        if ( ( mprg->type & HITPRCNT_PROG ) && ( ( 100*mob->hit / mob->max_hit ) < atoi( mprg->arglist ) ) )
        {
            mprog_driver( mprg->comlist, mob, ch, NULL, NULL );
            break;
        }
}

void mprog_random_trigger( CHAR_DATA *mob )
{
    if ( mob->pIndexData->progtypes & RAND_PROG && mob->position != POS_FIGHTING )
        mprog_percent_check(mob,NULL,NULL,NULL,RAND_PROG);
}

void mprog_act_trigger( char *buf, CHAR_DATA *ch, CHAR_DATA *mob, OBJ_DATA *obj, void *vo)
{
    CHAR_DATA *vmob;
    if (mob->in_room == NULL)
	return;
    for ( vmob = mob->in_room->people; vmob != NULL; vmob = vmob->next_in_room )
        if ( IS_AWAKE(vmob) && IS_NPC( vmob ) && ( vmob->pIndexData->progtypes & ACT_PROG ) )
            mprog_wordlist_check( buf, vmob, mob, NULL, NULL, ACT_PROG );
}

void mprog_speech_trigger( char *txt, CHAR_DATA *ch, CHAR_DATA *mob )
{
    if ( IS_AWAKE(mob) && IS_NPC( mob ) && ( mob->pIndexData->progtypes & SPEECH_PROG ) )
        mprog_wordlist_check( txt, mob, ch, NULL, NULL, SPEECH_PROG );
}

void mprog_tell_trigger( char *txt, CHAR_DATA *mob )
{
    CHAR_DATA *vmob;
    for ( vmob = mob->in_room->people; vmob != NULL; vmob = vmob->next_in_room )
        if ( IS_AWAKE(vmob) && IS_NPC( vmob ) && ( vmob->pIndexData->progtypes & TELL_PROG ) )
            mprog_wordlist_check( txt, vmob, mob, NULL, NULL, TELL_PROG );
}

void mprog_guild_trigger( CHAR_DATA *mob, CHAR_DATA *ch )
{
    if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & GUILD_PROG )  )
        mprog_percent_check( mob, ch, NULL, NULL, GUILD_PROG );
}

void mprog_bloody_trigger( CHAR_DATA *mob, CHAR_DATA *ch )
{
    if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & BLOODY_PROG )  )
        mprog_percent_check( mob, ch, NULL, NULL, BLOODY_PROG );
}

void mprog_justice_trigger( CHAR_DATA *mob, CHAR_DATA *ch )
{
    if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & JUSTICE_PROG )  )
        mprog_percent_check( mob, ch, NULL, NULL, JUSTICE_PROG );
}

void do_old_mpstat( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    MPROG_DATA *mprg;
    CHAR_DATA  *victim;
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "MobProg stat whom?\n\r", ch );
	return;
    }
    if ( ( victim = get_char_world( ch, arg ) ) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }
    if ( !IS_NPC( victim ) )
    {
	send_to_char( "Only Mobiles can have Programs!\n\r", ch);
	return;
    }
    if ( !( victim->pIndexData->progtypes ) )
    {
	send_to_char( "That Mobile has no Programs set.\n\r", ch);
	return;
    }
    sendf( ch, "Name: %s.  Vnum: %d.\n\r", victim->name, victim->pIndexData->vnum );
    sendf( ch, "Short description: %s.\n\rLong  description: %s",
      victim->short_descr, victim->long_descr[0] != '\0' ? victim->long_descr : "(none).\n\r" );
    for ( mprg = victim->pIndexData->mobprogs; mprg != NULL; mprg = mprg->next )
    {
        sendf( ch, ">%s %s\n\r%s\n\r",
          mprog_type_to_name( mprg->type ), mprg->arglist, mprg->comlist );
    }
}

/* Removes a mob from the game */
void do_disappear( CHAR_DATA *ch, char *argument )
{
    if (!IS_NPC(ch))
	return;
    extract_char(ch,TRUE);
}

void do_if( CHAR_DATA *ch, char *argument )
{
}

void do_endif( CHAR_DATA *ch, char *argument )
{
}