EmberMUD-0.9.41/
EmberMUD-0.9.41/clan/
EmberMUD-0.9.41/src/MSVC/
EmberMUD-0.9.41/src/Sleep/
EmberMUD-0.9.41/src/StartMUD/
EmberMUD-0.9.41/src/Win32Common/
/***************************************************************************
 *  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 Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

/***************************************************************************
 * MudProgs has been completely rewritten by Zane.  The only thing that    *
 * remains the same is how triggers are handled.  -Zane                    *
 *                                                                         *
 * Original MobProgs by N'Atas-ha.                                         *
 ***************************************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include "merc.h"
#include "interp.h"
#include "mud_progs.h"

/*
 * This is a string that contains a list of valid seperators in the script like
 * ()/-=*+, etc...
 */
#define SEPERATOR_STRING "(),=<>!&|*+-/%^"

#define Success_ 0
#define Error_ -1
#define R_ERROR -2

/*
 * Locals
 */

void release_supermob( void );
void set_supermob( void *source, int prog_type );
void init_supermob( void );
void mprog_wordlist_check( char *arg, int trigger_type, int prog_type );
bool mprog_percent_check( int trigger_type );
char *parse_script( char *script );
bool is_seperator( char c );
char *parse_if( char *instring );
char *parse_command( char *instring );
void parse_command_var( char var, char *outbuf);
int	parse_expression( char *instring );
int parse_proc( char *proc );
int exec_proc( char *procname, int intarg, char *chararg);
int evaluate(char *line, double *val);
void strip_whitespace( char *instring );
void *mprog_get_actor(char *arg, char type);
void mprog_driver(char *prog);

CHAR_DATA *ProgSource;
CHAR_DATA *ProgTriggeredBy;
CHAR_DATA *ProgVictim;
OBJ_DATA *ProgObjectSource;
OBJ_DATA *ProgObjectVictim;
ROOM_INDEX_DATA *ProgRoomSource;
CHAR_DATA *supermob;
int ExecMudProgID = 0;

/* Random/Semi-Random ch's */
CHAR_DATA *RandomNPC;
bool RandomNPC_picked;
void mprog_get_RandomNPC(void);
CHAR_DATA *RandomPC;
bool RandomPC_picked;
void mprog_get_RandomPC(void);
CHAR_DATA *RandomANY;
bool RandomANY_picked;
void mprog_get_RandomANY(void);
CHAR_DATA *MostEvilFighter;
bool MostEvilFighter_picked;
void mprog_get_MostEvilFighter(void);

/*
 * Main driver function, called by all triggers.
 */
void mprog_driver(char *prog)
{
    /* Clear out our temp picks */
    RandomNPC = NULL;
    RandomNPC_picked = FALSE;
    RandomPC = NULL;
    RandomPC_picked = FALSE;
    RandomANY = NULL;
    RandomANY_picked = FALSE;
    MostEvilFighter = NULL;
    MostEvilFighter_picked = FALSE;

    /* Increment our temp prog ID */
    ExecMudProgID++;

    parse_script( prog );

    /* Clear out locals */
	ProgSource = NULL;
	ProgTriggeredBy = NULL;
	ProgVictim = NULL;
	ProgObjectSource = NULL;
	ProgObjectVictim = NULL;
    ProgRoomSource = NULL;
}

/*
 * Main script parsing function.  Passes strings off to parse_if and parse_command
 * for processing.  Also correctly handles breaks.
 */
char *parse_script( char *script )
{
	char buf[MAX_STRING_LENGTH];
	char *curr;
	char *ptr = script;
	int pos;

	pos = 0;

	while( 1 )
	{
		/* Skip leading spaces */
		while( isspace(*ptr) )
			if ( *++ptr == '\0')
			{
				bug("Parse_Script: Script ended without 'break'.\r\n");
				return NULL;
			}
	
		curr = ptr;
		pos = 0;

		while( 1 )
		{
			buf[pos++] = *ptr;

			if ( isspace( *ptr ) || *ptr == '(' )
			{
				buf[--pos] = '\0';

				if ( !strcmp(buf, "if") )
				{
					while ( isspace( *ptr ) )
						ptr++;

					if ( *ptr != '(' )
					{
						bug("Parse_Script: Syntax error - If statment missing opening '('.\r\n");
						return NULL;
					}

					if ( ( ptr = parse_if ( ptr ) ) == NULL )
						return NULL;
					break;
				}
				else if ( !strcmp(buf, "break") )
				{
					if ( *ptr == '(' )
					{
						bug("Parse_Script: Syntax error - '(' encountered after 'break'.\r\n");
						return NULL;
					}
					return NULL;
				}
				else if ( !strcmp(buf, "else") )
				{
					if ( *ptr == '(' )
					{
						bug("Parse_Script: Syntax error - '(' encountered after 'else'.\r\n");
						return NULL;
					}
					return curr;
				}
				else if ( !strcmp(buf, "elseif") )
					return curr;
				else if ( !strcmp(buf, "endif") )
				{
					if ( *ptr == '(' )
					{
						bug("Parse_Script: Syntax error - '(' encountered after 'endif'.\r\n");
						return NULL;
					}
					return curr;
				}
				else
				{
					if ( *ptr == '(' )
					{
						bug("Parse_Script: Syntax error - '(' encountered after a command.\r\n");
						return NULL;
					}
					if ( ( ptr = parse_command( curr ) ) == NULL )
						return NULL;
					break;
				}
			}

			if ( ++ptr == '\0' )
			{
				bug("Parse_Script: EOF encountered in read.\r\n");
				return NULL;
			}
		}
	}

	return ptr;
}

/*
 * The main loop found and if and passed the remaining string to us. Now we process the if statement and then execute
 * commands.
 */
char *parse_if( char *instring )
{
	char buf[MAX_STRING_LENGTH];
	char *ptr = instring;
	char *tmpptr;
	int parans = 0;
	int pos = 0;
	int ifvalue = 0;
    bool elsedone = FALSE;

	/* Skip leading spaces */
	while( isspace(*ptr) )
		if ( ++ptr == '\0' )
		{
			bug("Parse_If: EOF encountered in read.\r\n");
			return NULL;
		}

	/* Evaluate the conditional portion of the if statement */
	while( 1 )
	{
		if ( isspace(*ptr) )
		{
			ptr++;
			continue;
		}
		else if ( *ptr == '(' )
		{
			if ( parans++ == 0 )
			{
				ptr++;
				continue;
			}

		}
		else if ( *ptr == ')' )
		{
			parans--;
			
			if ( parans < 0 )
			{
				bug("Parse_If: ')' without prior '('.\r\n");
				return NULL;
			}
			else if ( parans == 0 )
			{
				/* Check to make sure we don't have an extra ')' */
				tmpptr = ++ptr;
				while (*tmpptr && *tmpptr != '(' )
					if ( *tmpptr++ == ')' )
					{
						bug("Parse_If: Too many ')'s.\r\n");
						return NULL;
					}
				
				buf[pos] = '\0';
				ifvalue = parse_expression( buf );

				break;
			}
		}

		buf[pos++] = *ptr++;

		if ( *ptr == '\0' )
		{
			bug("Parse_If: Missing ')' in script.\r\n");
			return NULL;
		}
	}

	/* Call parse_script again.  This will process commands and allow for nested if's */
	if ( ifvalue )
		if ( ( ptr = parse_script( ptr ) ) == NULL )
			return NULL;


	/* Check for elseif and endif */

	while( 1 )
	{
		/* Skip leading spaces */
		while( isspace(*ptr) )
			if ( ++ptr == '\0' )
			{
				bug("Parse_If: EOF encountered in read.\r\n");
				return NULL;
			}

		pos = 0;

		while( 1 )
		{
			buf[pos++] = *ptr;

			if ( isspace( *ptr ) || *ptr == '(' )
			{
				buf[--pos] = '\0';

                if ( !strcmp(buf, "else" ) )
                {
                    if ( elsedone )
                    {
                        bug("Parse_If: Multiple else's in if statement.\r\n");
                        return NULL;
                    }

                    elsedone = TRUE;

		            if ( ( ptr = parse_script( ptr ) ) == NULL )
			            return NULL;
                    
                    while( isspace(*ptr) )
                        if (++ptr == '\0' )
                        {
				            bug("Parse_If: EOF encountered in read.\r\n");
				            return NULL;
                        }

                    break;
                }
				else if ( !strcmp(buf, "elseif") )
				{
					while ( isspace( *ptr ) )
						ptr++;

					if ( *ptr != '(' )
					{
						bug("Parse_If: Syntax error - Elseif statment missing opening '('.\r\n");
						return NULL;
					}

					if ( !ifvalue )
						return ( ptr = parse_if ( ptr ) );

					/* read to the end of the line */
					while( *ptr != '\r' && *ptr != '\n' && *ptr != '\0' )
						*ptr++;
					
					break;
				}
				else if ( !strcmp(buf, "endif") )
				{
					if ( *ptr == '(' )
					{
						bug("Parse_If: Syntax error - '(' encountered after 'endif'.\r\n");
						return NULL;
					}

					return ptr;
				}
				else
				{
					/*
					 * If we reached this point then we had an elseif with a prior sucessfull if
					 * so ignore all these lines untill we get to endif
					 */

					/* read to the end of the line */
					while( *ptr != '\r' && *ptr != '\n' && *ptr != '\0' )
						*ptr++;
					
					break;
				}
			}

			if ( ++ptr == '\0' )
			{
				bug("Parse_If: EOF encountered in read.\r\n");
				return NULL;
			}
		}
	}

	return ptr;
}

int	parse_expression( char *instring )
{
	char buf[MAX_STRING_LENGTH];
	char calcbuf[MAX_STRING_LENGTH];
	char *ptr = instring;
	char *tmpptr = NULL;
	int bufpos = 0;
	int calcpos = 0;
	int parans = 0;
	double retval = 0;

	*buf = '\0';
	*calcbuf = '\0';

	strip_whitespace( instring );

	while( *ptr != '\0' )
	{
		if ( isalpha(*ptr) )
		{
            if ( !tmpptr )
            {
			    bufpos = 0;
			    tmpptr = ptr;
            }

		    buf[bufpos++] = *ptr++;
		}
		else if ( *ptr == '(' && tmpptr )
		{
			buf[bufpos++] = *ptr++;
			parans++;
		}
		else if ( *ptr == ')' && tmpptr )
		{
			if ( parans <= 0 )
			{
				bug("Parse_Expression: ')' without prior '('.\r\n");
				return 0;
			}

			buf[bufpos++] = *ptr++;

			if ( --parans <= 0 )
			{
				buf[bufpos] = '\0';
                calcbuf[calcpos] = '\0';
                sprintf(&calcbuf[calcpos], "%d", parse_proc(buf));
				calcpos = strlen(calcbuf);
				tmpptr = NULL;
			}
		}
		else
		{
            if ( parans > 0 )
                buf[bufpos++] = *ptr++;
            else
            {
			    tmpptr = NULL;
    			calcbuf[calcpos++] = *ptr++;
            }
		}
	}

	if ( tmpptr )
	{
		bug("Parse_Expression: NULL encountered before ')'.\r\n");
		return 0;
	}

	calcbuf[calcpos] = '\0';

	if ( calcpos > 0 )
	{
        if ( evaluate(calcbuf, &retval) == Success_ )
            return (int) retval;
        else
        {
            bug("Parse_Expression: Error evaluating expression '%s'.\r\n", calcbuf);
            return 0;
        }
	}
	else
		return 0;
}

int parse_proc( char *proc )
{
	char procname[MAX_STRING_LENGTH];
	char arg[MAX_STRING_LENGTH];
	char *ptr = proc;
	char *tmpptr;

	tmpptr = procname;

	while( *ptr != '(' )
	{
		if ( *ptr == '\0' )
		{
			bug("Parse_Proc: NULL encountered before '('.\r\n");
			return 0;
		}
		*tmpptr++ = *ptr++;
	}

	*tmpptr = '\0';

	if ( *++ptr == '\0' )
	{
		bug("Parse_Proc: NULL encountered before ')'.\r\n");
		return 0;
	}

	tmpptr = arg;

	while( *ptr != ')' )
	{
		if ( *ptr == '\0' )
		{
			bug("Parse_Proc: NULL encountered before '('.\r\n");
			return 0;
		}
		*tmpptr++ = *ptr++;
	}

	*tmpptr = '\0';

	switch(*arg)
	{
	case '$':
		return exec_proc(procname, 0, arg);
		break;
	case '\0':
		return exec_proc(procname, 0, NULL);
		break;
	default:
		return exec_proc(procname, parse_expression(arg), NULL);
		break;
	}
}

int exec_proc( char *procname, int intarg, char *chararg)
{
	int cmd;
	bool found = FALSE;

	for ( cmd = 0; mprog_cmd_table[cmd].name[0] != '\0'; cmd++ )
		if ( procname[0] == mprog_cmd_table[cmd].name[0]
		&& !str_cmp(procname, mprog_cmd_table[cmd].name) )
		{
			found = TRUE;
			break;
		}

	if ( !found )
	{
		bug("Exec_Proc:  Invalid proc name - %s.\r\n", procname);
		return 0;
	}

	switch(UPPER(mprog_cmd_table[cmd].argtype))
	{
	case 'C':
		return (*mprog_cmd_table[cmd].mprog_fun) (mprog_get_actor(chararg, 'C'));
	case 'O':
		return (*mprog_cmd_table[cmd].mprog_fun) (mprog_get_actor(chararg, 'O'));
	case 'S':
		return (*mprog_cmd_table[cmd].mprog_fun) ((void *) chararg);
	case 'I':
		return (*mprog_cmd_table[cmd].mprog_fun) ((void *) &intarg);
    case 'N':
        return (*mprog_cmd_table[cmd].mprog_fun) ( NULL );
	default:
		bug("Exec_Proc: Unknown argtype %c.\r\n", mprog_cmd_table[cmd].argtype);
		return 0;
	}
}

/*
 * Returns a pointer to a CHAR_DATA structure when passed a $* variable.
 */
void *mprog_get_actor(char *arg, char type)
{
    ROOM_INDEX_DATA *pRoom;

    if ( !ProgSource || (pRoom = ProgSource->in_room) == NULL )
        return NULL;

	if ( strlen(arg) !=2 || *arg != '$' )
	{
		bug("Mprog_Get_Actor:  Invalid variable '%s'.\r\n", arg);
		return NULL;
	}

    switch( type )
    {
    case 'C':
	    switch( UPPER(arg[1]) )
	    {
	    case 'I':
            return ProgSource;
	    case 'N':
            return ProgTriggeredBy;
	    case 'T':
            return ProgVictim;
	    case 'R':
            if ( !RandomPC_picked )
                mprog_get_RandomPC();
        
            return RandomPC;
	    case 'X':
            if ( !MostEvilFighter_picked )
                mprog_get_MostEvilFighter();

            return MostEvilFighter;
	    case 'B':
            if ( !RandomNPC_picked )
                mprog_get_RandomNPC();

            return RandomNPC;
	    case 'C':
            if ( !RandomANY_picked )
                mprog_get_RandomANY();
       
            return RandomANY;
	    default:
		    bug("Mprog_Get_Actor:  Invalid variable '%s' for argtype 'C'.\r\n", arg);
		    return NULL;
	    }
        break;
    case 'O':
	    switch( UPPER(arg[1]) )
	    {
	    case 'O':
            return ProgObjectSource;
	    case 'P':
            return ProgObjectVictim;
	    default:
		    bug("Mprog_Get_Actor:  Invalid variable '%s' for argtype 'O'.\r\n", arg);
		    return NULL;
	    }
        break;
    default:
		bug("Mprog_Get_Actor:  Invalid argtype '%c'.\r\n", type);
		return NULL;
    }
}

char *parse_command( char *instring )
{
	char cmd[MAX_STRING_LENGTH];
    char buf[MAX_STRING_LENGTH];
	char *ptr = instring;
	int pos = 0;
    int bufpos = 0;
    bool escape = FALSE;

    *buf = '\0';

	/* Get rid of spaces in the beginning */
	while( *ptr == ' ' || *ptr == '\t' )
		ptr++;

	while( *ptr != '\r' && *ptr != '\n' )
    {
        switch(*ptr)
        {
        case '#':
            if(!escape)
            {
                if (*++ptr == '#')
                    cmd[pos++] = *ptr++;
                else
                    escape = TRUE;
            }
            else if ( escape )
            {
                if (*++ptr == '#')
                   buf[bufpos++] = *ptr++;
                else
                {
				    buf[bufpos] = '\0';
                    sprintf(&cmd[pos], "%d", parse_expression(buf));
				    pos = strlen(cmd);
                    escape = FALSE;
                }
            }
            break;
        case '$':
            if( !escape )
            {
                if ( *++ptr == '$' )
                    cmd[pos++] = *ptr++;
                else
                {
                    parse_command_var(*ptr, &cmd[pos]);
                    pos = strlen(cmd);
                    ptr++;
                }
            }
            else
                buf[bufpos++] = *ptr++;

            break;
        default:
            if(escape)
                buf[bufpos++] = *ptr++;
            else
    		    cmd[pos++] = *ptr++;
            break;
        }

        if ( *ptr == '\0' )
        {
            bug("Parse_Command: EOL encountered.\r\n");
            return NULL;
        }
    }


	cmd[pos] = '\0';

	/* Pass cmd and arg to the command interpreter */
    interpret(ProgSource, cmd);

	return ptr;
}

/*
 * Takes the var name passed and converts it to a text string based on the var.
 */
void parse_command_var( char var, char *outbuf)
{
    char buf[MAX_STRING_LENGTH];
    static char *he_she        [] = { "it",  "he",  "she" };
    static char *him_her       [] = { "it",  "him", "her" };
    static char *his_her       [] = { "its", "his", "her" };

    *outbuf = '\0';
    *buf = '\0';

    switch(var)
    {
    case 'a':
        if ( ProgObjectSource ) 
            switch ( *( ProgObjectSource->name ) )
	        {
	        case 'a': case 'e': case 'i':
            case 'o': case 'u':
                strcat( outbuf, "an" );
	            break;
            default: 
                strcat( outbuf, "a" );
                break;
            }
        return;
    case 'A':
        if ( ProgObjectVictim ) 
            switch ( *( ProgObjectVictim->name ) )
	        {
	        case 'a': case 'e': case 'i':
            case 'o': case 'u':
                strcat( outbuf, "an" );
	            break;
            default: 
                strcat( outbuf, "a" );
                break;
            }
        return;
    case 'b':
        if ( !RandomNPC_picked )
            mprog_get_RandomNPC();

        if ( RandomNPC )
        {
            one_argument( RandomNPC->name, buf);
            strcat(outbuf, buf);
        }

        return;
    case 'B':
        if ( !RandomNPC_picked )
            mprog_get_RandomNPC();

        if ( RandomNPC )
            strcat(outbuf, RandomNPC->short_descr);

        return;
    case 'c':
        if ( !RandomANY_picked )
            mprog_get_RandomANY();
   
        if ( RandomANY )
        {
            one_argument( RandomANY->name, buf);
            strcat(outbuf, buf);
        }

        return;
    case 'C':
        if ( !RandomANY_picked )
            mprog_get_RandomANY();
   
        if ( RandomANY )
            strcat(outbuf, RandomANY->short_descr);

        return;
    case 'e':
        if ( ProgTriggeredBy )
        {
	        if ( can_see( ProgSource, ProgTriggeredBy ) )
                strcat( outbuf, he_she[ ProgTriggeredBy->sex ] );
            else
	            strcat( outbuf, "someone" );
        }

        return;
    case 'E':
        if ( ProgVictim )
        {
	        if ( can_see( ProgSource, ProgVictim ) )
                strcat( outbuf, he_she[ ProgVictim->sex ] );
            else
	            strcat( outbuf, "someone" );
        }

        return;
    case 'i':
        if ( ProgSource )
        {
            one_argument( ProgSource->name, buf);
            strcat(outbuf, buf);
        }

        return;
    case 'I':
        if ( ProgSource )
            strcat(outbuf, ProgSource->short_descr);

        return;
    case 'j':
        if ( ProgSource )
            strcat( outbuf, he_she[ ProgSource->sex ] );

        return;
    case 'J':
        if ( !RandomPC_picked )
            mprog_get_RandomPC();
    
        if ( RandomPC )
            strcat( outbuf, he_she[ RandomPC->sex ] );

        return;
    case 'k':
        if ( ProgSource )
            strcat( outbuf, him_her[ ProgSource->sex ] );

        return;
    case 'K':
        if ( !RandomPC_picked )
            mprog_get_RandomPC();
    
        if ( RandomPC )
            strcat( outbuf, him_her[ RandomPC->sex ] );

        return;
    case 'l':
        if ( ProgSource )
            strcat( outbuf, his_her[ ProgSource->sex ] );

        return;
    case 'L':
        if ( !RandomPC_picked )
            mprog_get_RandomPC();
    
        if ( RandomPC )
            strcat( outbuf, his_her[ RandomPC->sex ] );

        return;
    case 'm':
        if ( ProgTriggeredBy )
        {
	        if ( can_see( ProgSource, ProgTriggeredBy ) )
                strcat( outbuf, him_her[ ProgTriggeredBy->sex ] );
            else
	            strcat( outbuf, "someone" );
        }

        return;
    case 'M':
        if ( ProgVictim )
        {
	        if ( can_see( ProgSource, ProgVictim ) )
                strcat( outbuf, him_her[ ProgVictim->sex ] );
            else
	            strcat( outbuf, "someone" );
        }

        return;
    case 'n':
        if ( ProgTriggeredBy )
        {
            one_argument( ProgTriggeredBy->name, buf);
            strcat(outbuf, buf);
        }

        return;
    case 'N':
        if ( ProgTriggeredBy )
            strcat(outbuf, ProgTriggeredBy->short_descr);

        return;
    case 'o':
        if ( ProgObjectSource )
        {
            one_argument( ProgObjectSource->name, buf);
            strcat(outbuf, buf);
        }

        return;
    case 'O':
        if ( ProgObjectSource )
            strcat(outbuf, ProgObjectSource->short_descr);

        return;
    case 'p':
        if ( ProgObjectVictim )
        {
            one_argument( ProgObjectVictim->name, buf);
            strcat(outbuf, buf);
        }

        return;
    case 'P':
        if ( ProgObjectVictim )
            strcat(outbuf, ProgObjectVictim->short_descr);

        return;
    case 'r':
        if ( !RandomPC_picked )
            mprog_get_RandomPC();
    
        if ( RandomPC )
        {
            one_argument( RandomPC->name, buf);
            strcat(outbuf, buf);
        }

        return;
    case 'R':
        if ( !RandomPC_picked )
            mprog_get_RandomPC();
    
        if ( RandomPC )
            strcat(outbuf, RandomPC->short_descr);

        return;
    case 's':
        if ( ProgTriggeredBy )
        {
	        if ( can_see( ProgSource, ProgTriggeredBy ) )
                strcat( outbuf, his_her[ ProgTriggeredBy->sex ] );
            else
	            strcat( outbuf, "someone" );
        }

        return;
    case 'S':
        if ( ProgVictim )
        {
	        if ( can_see( ProgSource, ProgVictim ) )
                strcat( outbuf, his_her[ ProgVictim->sex ] );
            else
	            strcat( outbuf, "someone" );
        }

        return;
    case 't':
        if ( ProgVictim )
        {
            one_argument( ProgVictim->name, buf);
            strcat(outbuf, buf);
        }

        return;
    case 'T':
        if ( ProgVictim )
            strcat(outbuf, ProgVictim->short_descr);

        return;
    case 'x':
        if ( !MostEvilFighter_picked )
            mprog_get_MostEvilFighter();

        if ( MostEvilFighter )
        {
            one_argument( MostEvilFighter->name, buf);
            strcat(outbuf, buf);
        }

        return;
    case 'X':
        if ( !MostEvilFighter_picked )
            mprog_get_MostEvilFighter();

        if ( MostEvilFighter )
            strcat(outbuf, MostEvilFighter->short_descr);

        return;
    default:
        bug("Parse_Command_Var: Unkown command variable '$%c'.\r\n", var);
        return;
    }
}

void init_supermob( void )
{
   supermob = create_mobile( get_mob_index(MOB_VNUM_SUPERMOB) );
   char_to_room( supermob, get_room_index(ROOM_VNUM_SUPERMOB) );

   return;
}

void set_supermob( void *source, int prog_type )
{
  OBJ_DATA  *pObj = NULL;
  ROOM_INDEX_DATA *pRoom = NULL;
  OBJ_DATA *in_obj = NULL;
  char buf[200];

  if ( !supermob )
  {
    supermob = create_mobile(get_mob_index( MOB_VNUM_SUPERMOB ));
	char_to_room( supermob, get_room_index(ROOM_VNUM_SUPERMOB) );
  }

  if(!source)
     return;

  switch(prog_type)
  {
  case OBJ_PROG:
	  pObj = (OBJ_DATA *) source;

	  for ( in_obj = pObj; in_obj->in_obj; in_obj = in_obj->in_obj )
		;

	  if ( in_obj->carried_by )
		  pRoom = in_obj->carried_by->in_room;
	  else
		  pRoom = pObj->in_room;

	  if( !pRoom )
		 return;

	  if (supermob->short_descr)
		 free_string(supermob->short_descr);

	  supermob->short_descr = str_dup(pObj->short_descr);
	  supermob->level = pObj->level;

	  /* Added by Jenny to allow bug messages to show the vnum
		 of the object, and not just supermob's vnum */
	  sprintf( buf, "Object #%d", pObj->pIndexData->vnum );
	  free_string( supermob->description );
	  supermob->description = str_dup( buf );

      /*
       * Point the Supermob's prog list to the object's list for easier use.
       * Leave Supermob's progtypes at 0 so no progs are ever triggered.  -Zane
       */
      supermob->pIndexData->mudprogs = pObj->pIndexData->mudprogs;
	  break;
  case ROOM_PROG:
	  pRoom = (ROOM_INDEX_DATA *) source;

      if ( supermob->short_descr )
    	  free_string(supermob->short_descr);
      supermob->short_descr = str_dup(pRoom->name);

      if ( supermob->name )
    	  free_string(supermob->name);
      supermob->name        = str_dup(pRoom->name);

      /* Added by Jenny to allow bug messages to show the vnum
         of the room, and not just supermob's vnum */
      sprintf( buf, "Room #%d", pRoom->vnum );
	  if ( supermob->description )
		free_string( supermob->description );
      supermob->description = str_dup( buf );

      /*
       * Point the Supermob's prog list to the object's list for easier use.
       * Leave Supermob's progtypes at 0 so no progs are ever triggered.  -Zane
       */
      supermob->pIndexData->mudprogs = pRoom->mudprogs;
	  break;
  }

  char_from_room (supermob );
  char_to_room( supermob, pRoom); 
  
  return;
}

void release_supermob( void )
{
  char_from_room( supermob );
  if ( supermob->name )
     free_string( supermob->name );
  if ( supermob->short_descr )
     free_string( supermob->short_descr );
  if ( supermob->description )
     free_string( supermob->description );
  supermob->name = str_dup("SuperMob");
  supermob->level = HERO;
  supermob->pIndexData->mudprogs = NULL;
  char_to_room( supermob, get_room_index( ROOM_VNUM_SUPERMOB ) );
}

void mprog_get_RandomNPC(void)
{
    CHAR_DATA *ch;
    int count = 0;
    int random = 0;

    /* Get the number of NPC's in the room */
    for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room )
        if ( IS_NPC( ch ) && can_see( ProgSource, ch ) )
            count++;

    random = number_range( 1, count );
    count = 0;

    /* get a random visible NPC who is in the room with the mob */
    for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room )
        if ( IS_NPC( ch ) && can_see( ProgSource, ch ) 
        && ++count == random )
        {
            RandomNPC = ch;
            RandomNPC_picked = TRUE;
        }
}

void mprog_get_RandomPC(void)
{
    CHAR_DATA *ch;
    int count = 0;
    int random = 0;

    /* Get the number of PC's in the room */
    for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room )
        if ( !IS_NPC( ch ) && can_see( ProgSource, ch ) )
            count++;

    random = number_range( 1, count );
    count = 0;

    /* get a random visible mortal player who is in the room with the mob */
    for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room )
        if ( !IS_NPC( ch ) && can_see( ProgSource, ch ) 
        && ++count == random )
        {
            RandomPC = ch;
            RandomPC_picked = TRUE;
        }
}

void mprog_get_RandomANY(void)
{
    CHAR_DATA *ch;
    int count = 0;
    int random = 0;

    /* Get the number of visible PC's and NPC's in the room */
    for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room )
        if ( can_see( ProgSource, ch ) )
            count++;

    random = number_range( 1, count );
    count = 0;

    /* get a random visible NPC or PC in the room with the mob */
    for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room )
        if ( can_see( ProgSource, ch ) 
        && ++count == random )
        {
            RandomANY = ch;
            RandomANY_picked = TRUE;
        }
}

void mprog_get_MostEvilFighter(void)
{
    CHAR_DATA *ch;
    int max_evil = 0;

    /* get the most evil visible mortal player who is in the room with the mob and is fighting */
    for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room )
        if ( !IS_NPC( ch ) && can_see( ProgSource, ch ) )
	        if ( ch->fighting && ch->alignment < max_evil )
            {
		       max_evil = ch->alignment;
		       MostEvilFighter = ch;
               MostEvilFighter_picked = TRUE;
            }
}

/*
 * Use the constant seperator string to decide wether or not c is a 
 * seperator
 */
bool is_seperator( char c )
{
	char *ptr = SEPERATOR_STRING;

	do
	{
		if ( c == *ptr )
			return TRUE;
	} while (*++ptr != '\0');

	return FALSE;
}

void strip_whitespace( char *instring )
{
	char *inptr = instring, *outptr = instring;

	while( *inptr )
	{
		if ( isspace(*inptr) )
			inptr++;
		else
			*outptr++ = *inptr++;
	}

	*outptr = '\0';
}

bool mprog_percent_check( int trigger_type )
{
	MPROG_LIST *pProgList;
	bool executed = FALSE;

	if ( !ProgSource || !ProgSource->pIndexData )
		return FALSE;

	for ( pProgList = ProgSource->pIndexData->mudprogs; pProgList; 
	  pProgList = pProgList->next )
		if ( ( pProgList->mudprog->trigger_type & trigger_type ) 
		  && ( number_percent( ) < atoi( pProgList->mudprog->arglist ) ) )
		{
			executed = TRUE;
			mprog_driver( pProgList->mudprog->comlist );
			if ( trigger_type != GREET_PROG && trigger_type != ALL_GREET_PROG
			&& trigger_type != ENTER_PROG )
				break;
		}

	return executed;
}

/* 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, int trigger_type, int prog_type )
{
  char			  temp1[ MAX_STRING_LENGTH ];
  char			  temp2[ MAX_INPUT_LENGTH ];
  char			  word[ MAX_INPUT_LENGTH ];
  MPROG_DATA	  *mprg;
  MPROG_LIST	  *pProgList = NULL;
  char			  *list;
  char			  *start;
  char			  *dupl;
  char			  *end;
  unsigned int    i;

  switch( prog_type )
  {
  case ROOM_PROG:
      pProgList = ProgRoomSource->mudprogs;
      break;
  case OBJ_PROG:
      pProgList = ProgObjectSource->pIndexData->mudprogs;
      break;
  }

  pProgList = ProgSource->pIndexData->mudprogs;

  for ( ; pProgList; pProgList = pProgList->next )
    if ( pProgList->mudprog->trigger_type & trigger_type )
    {
		mprg = pProgList->mudprog;

		strcpy( temp1, mprg->arglist );
		list = temp1;

		for ( i = 0; i < strlen( list ); i++ )
			list[i] = LOWER( list[i] );

		strcpy( temp2, arg );
		dupl = remove_color(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' ) )
				{
                    if ( prog_type == OBJ_PROG )
                    {
                        set_supermob( ProgObjectSource, prog_type );
                        ProgSource = supermob;
                    }
                    else if ( prog_type == ROOM_PROG )
                    {
                        set_supermob( ProgRoomSource, prog_type );
                        ProgSource = supermob;
                    }

					mprog_driver( mprg->comlist );

					if ( ProgSource == supermob )
						release_supermob();

					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' ) )
					{
                        if ( prog_type == OBJ_PROG )
                        {
                            set_supermob( ProgObjectSource, prog_type );
                            ProgSource = supermob;
                        }
                        else if ( prog_type == ROOM_PROG )
                        {
                            set_supermob( ProgRoomSource, prog_type );
                            ProgSource = supermob;
                        }

						mprog_driver( mprg->comlist );

						if ( ProgSource == supermob )
							release_supermob();

						break;
					}
				else
					dupl = start+1;
		}
  }

  return;
}

/* 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_act_trigger( char *buf, CHAR_DATA *mob, CHAR_DATA *ch,
		       OBJ_DATA *obj, void *vo)
{
  MPROG_ACT_LIST * tmp_act;
  MPROG_LIST *pProgList;
  bool found = FALSE;
  
  if ( IS_NPC( mob )
       && IS_SET( mob->pIndexData->progtypes, ACT_PROG ) )
  {
        if ( IS_NPC( ch ) && ch->pIndexData == mob->pIndexData )
           return;
        
        for ( pProgList = mob->pIndexData->mudprogs; pProgList; pProgList = pProgList->next )
            if ( pProgList->mudprog->trigger_type & ACT_PROG )
            {
                found = TRUE;
                break;
            }

        if ( !found )
           return;
           
        tmp_act = alloc_mem( sizeof( MPROG_ACT_LIST ) );
        if ( mob->mpactnum > 0 )
	  tmp_act->next = mob->mpact;
        else
	  tmp_act->next = NULL;

        mob->mpact      = tmp_act;
        mob->mpact->buf = str_dup( buf );
        mob->mpact->ch  = ch; 
        mob->mpact->obj = obj; 
        mob->mpact->vo  = vo; 
        mob->mpactnum++;
  }
  return;
}*/

void mprog_bribe_trigger( CHAR_DATA *mob, CHAR_DATA *ch, int amount )
{
  char        buf[ MAX_STRING_LENGTH ];
  MPROG_LIST *pList;
  OBJ_DATA   *obj;

  if ( IS_NPC( mob )
      && ( mob->pIndexData->progtypes & BRIBE_PROG ) )
  {
      if ( IS_NPC( ch ) && ch->pIndexData == mob->pIndexData )
         return;
      obj = create_object( get_obj_index( OBJ_VNUM_MONEY_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 ( pList = mob->pIndexData->mudprogs; pList; pList = pList->next )
		if ( ( pList->mudprog->trigger_type & BRIBE_PROG )
	      && ( amount >= atoi( pList->mudprog->arglist ) ) )
		{
			ProgSource = mob;
			ProgTriggeredBy = ch;
			ProgObjectSource = obj;

			mprog_driver( pList->mudprog->comlist );
			break;
		}
  }
  
  return;
}

void mprog_death_trigger( CHAR_DATA *mob )
{

   if ( IS_NPC( mob )
     && ( mob->pIndexData->progtypes & DEATH_PROG ) )
   {
        mob->position = POS_RESTING;

		ProgSource = mob;
        mprog_percent_check( DEATH_PROG );
        mob->position = POS_DEAD;
   }
   else
   {
	death_cry( mob );
   }
 return;
}

void mprog_entry_trigger( CHAR_DATA *mob )
{

    if ( IS_NPC( mob )
    && ( mob->pIndexData->progtypes & ENTRY_PROG ) )
    {
        ProgSource = mob;
        mprog_percent_check( ENTRY_PROG );
    }

    return;

}

void mprog_fight_trigger( CHAR_DATA *mob, CHAR_DATA *ch )
{

    if ( IS_NPC( mob )
    && ( mob->pIndexData->progtypes & FIGHT_PROG ) )
    {
        if ( IS_NPC( ch ) && ch->pIndexData == mob->pIndexData )
           return;

        ProgSource = mob;
        ProgTriggeredBy = ch;
        mprog_percent_check( FIGHT_PROG );
    }

    return;

}

void mprog_fightgroup_trigger( CHAR_DATA *mob )
{
	CHAR_DATA *victim;

	if ( !mob || !mob->in_room )
		return;

    if ( IS_NPC( mob )
      && ( mob->pIndexData->progtypes & FIGHTGROUP_PROG ) )
    {
        ProgSource = mob;

		for ( victim = mob->in_room->people; victim; victim = victim->next_in_room )
		{
			if ( victim != mob && victim->fighting == mob )
            {
                ProgTriggeredBy = victim;
    			if ( mprog_percent_check( FIGHTGROUP_PROG ) )
				    break;
            }
		}
    }

 return;

}

void mprog_give_trigger( CHAR_DATA *mob, CHAR_DATA *ch, OBJ_DATA *obj )
{
 char        buf[MAX_INPUT_LENGTH];
 MPROG_LIST *pList;

 if ( IS_NPC( mob )
     && ( mob->pIndexData->progtypes & GIVE_PROG ) )
 {
     if ( IS_NPC( ch ) && ch->pIndexData == mob->pIndexData )
            return;
            
   for ( pList = mob->pIndexData->mudprogs; pList; pList = pList->next )
   {
         one_argument( pList->mudprog->arglist, buf );

         if ( ( pList->mudprog->trigger_type & GIVE_PROG )
	     && ( ( !str_cmp( obj->name, pList->mudprog->arglist ) )
	       || ( !str_cmp( "all", buf ) ) ) )
		 {
             ProgSource = mob;
             ProgTriggeredBy = ch;
             ProgObjectSource = obj;

			 mprog_driver( pList->mudprog->comlist );
			 break;
		 }
   }
 }
 
 return;
}

void mprog_greet_trigger( CHAR_DATA *ch )
{
    CHAR_DATA *vmob;

    if ( IS_NPC( ch ) )
        return;
       
    for ( vmob = ch->in_room->people; vmob; vmob = vmob->next_in_room )
    if ( IS_NPC( vmob ) && ch != vmob && can_see( vmob, ch )
    && ( !vmob->fighting ) && IS_AWAKE( vmob )
    && ( vmob->pIndexData->progtypes & GREET_PROG) )
    {
        ProgSource = vmob;
        ProgTriggeredBy = ch;

        mprog_percent_check( GREET_PROG );
    }
    else if ( IS_NPC( vmob )
	&& ( !vmob->fighting )
	&& IS_AWAKE( vmob )
	&& ( vmob->pIndexData->progtypes & ALL_GREET_PROG ) )
    {
        ProgSource = vmob; 
        ProgTriggeredBy = ch;

        mprog_percent_check( ALL_GREET_PROG );
    }

    return;
}

void mprog_hitprcnt_trigger( CHAR_DATA *mob, CHAR_DATA *ch)
{
    MPROG_LIST *pList;

    if ( IS_NPC( mob )
    && ( mob->pIndexData->progtypes & HITPRCNT_PROG ) )
    {
        if ( IS_NPC( ch ) && ch->pIndexData == mob->pIndexData )
            return;
       
        for ( pList = mob->pIndexData->mudprogs; pList; pList = pList->next )
            if ( ( pList->mudprog->trigger_type & HITPRCNT_PROG )
	        && ( ( 100*mob->hit / mob->max_hit ) < atoi( pList->mudprog->arglist ) ) )
            {
                ProgSource = mob;
                ProgTriggeredBy = ch;

	            mprog_driver( pList->mudprog->comlist );
	            break;
            }
    }
 
    return;
}

void mprog_random_trigger( CHAR_DATA *mob )
{
    if ( mob->pIndexData->progtypes & RAND_PROG)
    {
        ProgSource = mob;

        mprog_percent_check( RAND_PROG );
    }

    return;
}

void mprog_speech_trigger( char *txt, CHAR_DATA *actor )
{
    CHAR_DATA *vmob;

    for ( vmob = actor->in_room->people; vmob; vmob = vmob->next_in_room )
        if ( IS_NPC( vmob ) && ( vmob->pIndexData->progtypes & SPEECH_PROG ) )
        {
            if ( IS_NPC( actor ) && ( vmob->pIndexData == actor->pIndexData ) )
                continue;

            ProgSource = vmob;
            ProgTriggeredBy = actor;

            mprog_wordlist_check( txt, SPEECH_PROG, MOB_PROG );
        }

    return;
}

/* Written by Zak, Jan 13/1998
 * Goes in interpret() before regular command parsing.
 * This function checks all mobs in room with the character for a command
 * trigger matching what the character typed.
 * The function returns TRUE if the character's command should be run
 * through the regular interpreter too. */
bool mprog_command_trigger (char *txt, CHAR_DATA *ch)
{
    char *argument;
    char arg [MAX_INPUT_LENGTH];/* I'm assuming that the cmd_table won't
	                			 * ever have a command longer than
				                 * MAX_INPUT_LENGTH                     */
    char *pMem;                 /* Pointer to the memory allocated by argument.
                                 * This is needed so we can free that memory up
                                 * at the end of the function */
    CHAR_DATA  *vmob;
    OBJ_DATA   *obj;
    ROOM_INDEX_DATA  *room;
    MPROG_LIST *pList;
    int cmd;
    bool can_do = TRUE;

    pMem = strdup(txt);
    argument = pMem;

    /* First check for the command typed being a prefix of anything in 
     * the regular command table, and expand it to the full command. */
  
    argument = one_argument( argument, arg );
    for (cmd=0; cmd_table[cmd].name[0] != '\0'; cmd++)
    {
	    if (arg[0] == cmd_table[cmd].name[0] 
        && !str_prefix( arg, cmd_table[cmd].name ) )
	    {
	        strncpy(arg,cmd_table[cmd].name,sizeof(arg));
	        break;
	    }
    }
   
    /* Find mobs that are in_room that have a COMMAND_PROG */
   
    for ( vmob = ch->in_room->people; vmob; vmob = vmob->next_in_room )
        if ( IS_NPC( vmob ) && ( vmob->pIndexData->progtypes & COMMAND_PROG ) )
        {
	        for ( pList = vmob->pIndexData->mudprogs; pList; pList = pList->next )
	        {
	            if ( ( pList->mudprog->trigger_type & COMMAND_PROG ) 
                && (!str_cmp(pList->mudprog->arglist,arg)) )
	            {
                    ProgSource = vmob;
                    ProgTriggeredBy = ch;

		            mprog_driver( pList->mudprog->comlist );
		            can_do = FALSE;
	            }
	        }
        }

    /* Obj and Room command_prog support by Kyle Boyd */

    /* objs in inventory and worn... */
    for ( obj = ch->carrying; obj; obj = obj->next_content )
        if ( obj->pIndexData->progtypes & COMMAND_PROG )
        {
	        for ( pList = obj->pIndexData->mudprogs; pList; pList = pList->next )
	        {
	            if ( (pList->mudprog->trigger_type & COMMAND_PROG) 
                && (!str_cmp(pList->mudprog->arglist,arg)) )
	            {
		        set_supermob( obj, OBJ_PROG );
                ProgSource = supermob;
                ProgTriggeredBy = ch;
                ProgObjectSource = obj;

		        mprog_driver( pList->mudprog->comlist );

		        release_supermob();
		        can_do = FALSE;
	            }
	        }
        }

    /* objs in room... */

    for ( obj = ch->in_room->contents; obj; obj = obj->next_content )
        if ( obj->pIndexData->progtypes & COMMAND_PROG )
        {
	        for ( pList = vmob->pIndexData->mudprogs; pList; pList = pList->next)
	        {
	            if ( (pList->mudprog->trigger_type & COMMAND_PROG) 
                && (!str_cmp(pList->mudprog->arglist,arg)) )
                {
		            set_supermob( obj, OBJ_PROG );
                    ProgSource = supermob;
                    ProgTriggeredBy = ch;
                    ProgObjectSource = obj;

		            mprog_driver( pList->mudprog->comlist );

		            release_supermob();
		            can_do = FALSE;
                }
	        }
        }

    /* And finally, room progs */

    room = ch->in_room;
    if ( room->progtypes & COMMAND_PROG )
    {
	    for ( pList = room->mudprogs; pList; pList = pList->next)
	    {
	        if ( (pList->mudprog->trigger_type & COMMAND_PROG) 
            && (!str_cmp(pList->mudprog->arglist,arg)) )
            {
		        set_supermob( room, ROOM_PROG );
                ProgSource = supermob;
                ProgTriggeredBy = ch;

		        mprog_driver( pList->mudprog->comlist );

		        release_supermob();
		        can_do = FALSE;
            }
	    }
    }

    free(pMem);

    return can_do;
}

/*****************************************************************
 *   ROOM PROG SUPPORT STARTS HERE:                              *
 *          most of this code was taken from the SMAUG code base *
 *          with modifications made to fit our mud...            *
 *****************************************************************/

/*
 * Triggers follow
 */
/*
void rprog_act_trigger( char *buf, ROOM_INDEX_DATA *room, CHAR_DATA *ch,
			OBJ_DATA *obj, void *vo )
{
   if ( room->progtypes & ACT_PROG ) 
   {
      MPROG_ACT_LIST *tmp_act;
*/      
      /* supermob can't trigger it's own mprog */
/*      if ( IS_NPC(ch) && ch->pIndexData == supermob->pIndexData )
         return;
         
      tmp_act = alloc_mem( sizeof( MPROG_ACT_LIST ) );
      if ( room->mpactnum > 0 )
        tmp_act->next = room->mpact;
      else
        tmp_act->next = NULL;
      
      room->mpact = tmp_act;
      room->mpact->buf = str_dup(buf);
      room->mpact->ch = ch;
      room->mpact->obj = obj;
      room->mpact->vo = vo;
      room->mpactnum++;
      room_act_add(room);
   }
   return;
}*/

void rprog_leave_trigger( CHAR_DATA *ch )
{
  if( ch->in_room && ch->in_room->progtypes & LEAVE_PROG ) 
  {
    set_supermob( ch->in_room, ROOM_PROG );
    ProgSource = supermob;

    mprog_percent_check( LEAVE_PROG );

    release_supermob();
  }
  return;
}

void rprog_enter_trigger( CHAR_DATA *ch )
{
  if( ch->in_room && ch->in_room->progtypes & ENTER_PROG ) 
  {
    set_supermob( ch->in_room, ROOM_PROG );
    ProgSource = supermob;
    ProgTriggeredBy = ch;

    mprog_percent_check( ENTRY_PROG );

    release_supermob();
  }
  return;
}

void rprog_sleep_trigger( CHAR_DATA *ch )
{
  if( ch->in_room && ch->in_room->progtypes & SLEEP_PROG ) 
  {
    set_supermob( ch->in_room, ROOM_PROG );
    ProgSource = supermob;
    ProgTriggeredBy = ch;

    mprog_percent_check( SLEEP_PROG );

    release_supermob();
  }
  return;
}

void rprog_rest_trigger( CHAR_DATA *ch )
{
  if( ch->in_room && ch->in_room->progtypes & REST_PROG ) 
  {
    set_supermob( ch->in_room, ROOM_PROG );
    ProgSource = supermob;
    ProgTriggeredBy = ch;

    mprog_percent_check( REST_PROG );

    release_supermob();
  }
  return;
}

void rprog_rfight_trigger( CHAR_DATA *ch )
{
  if( ch->in_room && ch->in_room->progtypes & RFIGHT_PROG ) 
  {
    set_supermob( ch->in_room, ROOM_PROG );
    ProgSource = supermob;
    ProgTriggeredBy = ch;

    mprog_percent_check( RFIGHT_PROG );

    release_supermob();
  }
  return;
}

void rprog_death_trigger( CHAR_DATA *ch )
{
  if( ch->in_room && ch->in_room->progtypes & RDEATH_PROG ) 
  {
    set_supermob( ch->in_room, ROOM_PROG );
    ProgSource = supermob;
    ProgTriggeredBy = ch;

    mprog_percent_check( RDEATH_PROG );

    release_supermob();
  }
  return;
}

void rprog_speech_trigger( char *txt, CHAR_DATA *ch )
{
  /* prevent circular triggers by not allowing mob to trigger itself */
  if ( IS_NPC(ch) && ch->pIndexData == supermob->pIndexData )
     return;
     
  if( ch->in_room && ch->in_room->progtypes & SPEECH_PROG ) 
  {
      ProgRoomSource = ch->in_room;
      ProgTriggeredBy = ch;

      /* supermob is set and released in mprog_wordlist_check */
      mprog_wordlist_check( txt, SPEECH_PROG, ROOM_PROG );
  }
 return;
}

void rprog_random_trigger( CHAR_DATA *ch )
{

  if ( ch->in_room && ch->in_room->progtypes & RAND_PROG)
  {
    set_supermob( ch->in_room, ROOM_PROG );
    ProgSource = supermob;
    ProgTriggeredBy = ch;

    mprog_percent_check( RAND_PROG );

    release_supermob();
  }
  return;
}

/*****************************************************************
 *   OBJECT PROG SUPPORT STARTS HERE:				             *
 *          most of this code was taken from the SMAUG code base *
 *          with modifications made to fit our mud...            *
 *****************************************************************/

/*
 * Triggers follow
 */
void oprog_greet_trigger( CHAR_DATA *ch )
{
  OBJ_DATA *vobj;

  for ( vobj=ch->in_room->contents; vobj; vobj = vobj->next_content )
    if  ( vobj->pIndexData->progtypes & GREET_PROG ) 
    {
     set_supermob( vobj, OBJ_PROG );  /* not very efficient to do here */
     ProgSource = supermob;
     ProgTriggeredBy = ch;
     ProgObjectSource = vobj;

     mprog_percent_check( GREET_PROG );

     release_supermob();
    }

  return;
}

void oprog_speech_trigger( char *txt, CHAR_DATA *ch )
{
   OBJ_DATA *vobj;

  /* supermob is set and released in mprog_wordlist_check */
  for ( vobj=ch->in_room->contents; vobj; vobj = vobj->next_content )
    if  ( vobj->pIndexData->progtypes & SPEECH_PROG ) 
    {
        ProgTriggeredBy = ch;
        ProgObjectSource = vobj;

        mprog_wordlist_check( txt, SPEECH_PROG, OBJ_PROG );
    }

 return;
}

/*
 * Called at top of obj_update
 * make sure to put an if(!obj) continue
 * after it
 */
void oprog_random_trigger( OBJ_DATA *obj )
{

  if ( obj->pIndexData->progtypes & RAND_PROG)
  {
     set_supermob( obj, OBJ_PROG );
     ProgSource = supermob;
     ProgObjectSource = obj;

     mprog_percent_check( RAND_PROG );

     release_supermob();
  }
  return;
}

/*
 * in wear_obj, between each successful equip_char 
 * the subsequent return
 */
void oprog_wear_trigger( CHAR_DATA *ch, OBJ_DATA *obj )
{
   if ( obj->pIndexData->progtypes & WEAR_PROG ) 
   {
      set_supermob( obj, OBJ_PROG );
      ProgSource = supermob;
      ProgTriggeredBy = ch;
      ProgObjectSource = obj;

      mprog_percent_check( WEAR_PROG );

      release_supermob();
   }
   return;
}

bool oprog_use_trigger( CHAR_DATA *ch, OBJ_DATA *obj, CHAR_DATA *vict,
                        OBJ_DATA *targ )
{
   bool executed = FALSE;

   if ( obj->pIndexData->progtypes & USE_PROG ) 
   {
      set_supermob( obj, OBJ_PROG );
      ProgSource = supermob;
      ProgTriggeredBy = ch;
      ProgObjectSource = obj;

      if ( obj->item_type == ITEM_STAFF && vict )
          ProgVictim = vict;
      else
          ProgObjectVictim = targ;

      executed = mprog_percent_check( USE_PROG );

      release_supermob();
   }
   return executed;
}

/*
 * call in remove_obj, right after unequip_char   
 * do a if(!ch) return right after, and return TRUE (?)
 * if !ch
 */
void oprog_remove_trigger( CHAR_DATA *ch, OBJ_DATA *obj )
{
   if ( obj->pIndexData->progtypes & REMOVE_PROG ) 
   {
     set_supermob( obj, OBJ_PROG );
     ProgSource = supermob;
     ProgTriggeredBy = ch;
     ProgObjectSource = obj;

     mprog_percent_check( REMOVE_PROG );

     release_supermob();
   }
   return;
}


/*
 * call in do_sac, right before extract_obj
 */
void oprog_sac_trigger( CHAR_DATA *ch, OBJ_DATA *obj )
{
   if ( obj->pIndexData->progtypes & SAC_PROG ) 
   {
      set_supermob( obj, OBJ_PROG );
      ProgSource = supermob;
      ProgTriggeredBy = ch;
      ProgObjectSource = obj;

      mprog_percent_check( SAC_PROG );

      release_supermob();
   }
   return;
}

/*
 * call in do_get, right before check_for_trap
 * do a if(!ch) return right after
 */
void oprog_get_trigger( CHAR_DATA *ch, OBJ_DATA *obj )
{
   if ( obj->pIndexData->progtypes & GET_PROG ) 
   {
      set_supermob( obj, OBJ_PROG );
      ProgSource = supermob;
      ProgTriggeredBy = ch;
      ProgObjectSource = obj;

      mprog_percent_check( GET_PROG );

      release_supermob();
   }
   return;
}

/*
 * called in damage_obj in act_obj.c
 */
void oprog_damage_trigger( CHAR_DATA *ch, OBJ_DATA *obj )
{
   if ( obj->pIndexData->progtypes & DAMAGE_PROG ) 
   {
      set_supermob( obj, OBJ_PROG );
      ProgSource = supermob;
      ProgTriggeredBy = ch;
      ProgObjectSource = obj;

      mprog_percent_check( DAMAGE_PROG );

      release_supermob();
   }
   return;
}

/*
 * called in do_repair in shops.c
 */
void oprog_repair_trigger( CHAR_DATA *ch, OBJ_DATA *obj )
{

   if ( obj->pIndexData->progtypes & REPAIR_PROG ) 
   {
      set_supermob( obj, OBJ_PROG );
      ProgSource = supermob;
      ProgTriggeredBy = ch;
      ProgObjectSource = obj;

      mprog_percent_check( REPAIR_PROG );

      release_supermob();
   }
   return;
}

/*
 * call twice in do_drop, right after the act( AT_ACTION,...)
 * do a if(!ch) return right after
 */
void oprog_drop_trigger( CHAR_DATA *ch, OBJ_DATA *obj )
{
   if ( obj->pIndexData->progtypes & DROP_PROG ) 
   {
      set_supermob( obj, OBJ_PROG );
      ProgSource = supermob;
      ProgTriggeredBy = ch;
      ProgObjectSource = obj;

      mprog_percent_check( DROP_PROG );

      release_supermob();
   }
   return;
}

/*
 * call towards end of do_examine, right before check_for_trap
 */
void oprog_examine_trigger( CHAR_DATA *ch, OBJ_DATA *obj )
{
   if ( obj->pIndexData->progtypes & EXA_PROG ) 
   {
      set_supermob( obj, OBJ_PROG );
      ProgSource = supermob;
      ProgTriggeredBy = ch;
      ProgObjectSource = obj;

      mprog_percent_check( EXA_PROG );

      release_supermob();
   }
   return;
}


/*
 * call in fight.c, group_gain, after (?) the obj_to_room
 */
void oprog_zap_trigger( CHAR_DATA *ch, OBJ_DATA *obj )
{
   if ( obj->pIndexData->progtypes & ZAP_PROG ) 
   {
      set_supermob( obj, OBJ_PROG );
      ProgSource = supermob;
      ProgTriggeredBy = ch;
      ProgObjectSource = obj;

      mprog_percent_check( ZAP_PROG );

      release_supermob();
   }
   return;
}

/*
void oprog_act_trigger( char *buf, OBJ_DATA *mobj, CHAR_DATA *ch,
			OBJ_DATA *obj, void *vo )
{
   if ( IS_NPC(ch) && ch->pIndexData == supermob->pIndexData )
      return;   
*/
   /* prevent supermob from triggering itself */
/*   if ( mobj->pIndexData->progtypes & ACT_PROG ) 
   {
      MPROG_ACT_LIST *tmp_act;
      
      tmp_act = alloc_mem( sizeof(MPROG_ACT_LIST) );
      if ( mobj->mpactnum > 0 )
        tmp_act->next = mobj->mpact;
      else
        tmp_act->next = NULL;
      
      mobj->mpact = tmp_act;
      mobj->mpact->buf = str_dup(buf);
      mobj->mpact->ch = ch;
      mobj->mpact->obj = obj;
      mobj->mpact->vo = vo;
      mobj->mpactnum++;
      obj_act_add(mobj);
   }
   return;
}*/

/*
 * call in fight.c, one_hit and second_one_hit at the end.
 */
void oprog_hit_trigger( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj )
{
   if ( obj->pIndexData->progtypes & HIT_PROG ) 
   {
      set_supermob( obj, OBJ_PROG );
      ProgSource = supermob;
      ProgTriggeredBy = ch;
      ProgObjectSource = obj;
      ProgVictim = victim;

      mprog_percent_check( HIT_PROG );

      release_supermob();
   }
   return;
}

/************************************************************************
 *                                                                      *
 *  EVAL.C - A simple mathematical expression evaluator in C            *
 *                                                                      *
 *  operators supported: Operator               Precedence              *
 *                                                                      *
 *                         (                     Lowest                 *
 *                         )                     Highest                *
 *                         +   (addition)        Low                    *
 *                         -   (subtraction)     Low                    *
 *                         *   (multiplication)  Medium                 *
 *                         /   (division)        Medium                 *
 *                         %   (modulus)         High                   *
 *                         ^   (exponentiation)  High                   *
 *                         ==					 Lowest                 *
 *                         !=					 Lowest                 *
 *                         >=					 Lowest                 *
 *                         <=                    Lowest                 *
 *                         <                     Lowest                 *
 *                         >                     Lowest                 *
 *                         &&                    Lowest                 *
 *                         ||                    Lowest                 *
 *                         !                     Lowest                 *
 *                                                                      *
 *  Original Copyright 1991-93 by Robert B. Stout as part of            *
 *  the MicroFirm Function Library (MFL)                                *
 *                                                                      *
 *  The user is granted a free limited license to use this source file  *
 *  to create royalty-free programs, subject to the terms of the        *
 *  license restrictions specified below.                               *
 *                                                                      *
 ************************************************************************/

/***********************************************************************************
 *                                                                                 *
 * Portions of SNIPPETS code are Copyright 1987-1996 by Robert B. Stout dba        *
 * MicroFirm. The user is granted a free license to use these source files in      *
 * any way except for commercial publication other than as part of your own        *
 * program. This means you are explicitly granted the right to:                    *
 *                                                                                 *
 * 1.  Use these files to create applications for any use, private or commercial,  *
 *     without any license fee.                                                    *
 *                                                                                 *
 * 2.  Copy or otherwise publish copies of the source files so long as the         *
 *     original copyright notice is not removed and that such publication is       *
 *     free of any charges other than the costs of duplication and distribution.   *
 *                                                                                 *
 * 3.  Distribute modified versions of the source files so long as the original    *
 *     copyright notice is not removed, and that the modified nature is clearly    *
 *     noted in the source file, and that such distribution is free of any         *
 *     charges other than the costs of duplication and distribution.               *
 *                                                                                 *
 * 4.  Distribute object files and/or libraries compiled from the supplied         *
 *     source files, provided that such publication is free of any charges other   *
 *     than the costs of duplication and distribution.                             *
 *                                                                                 *
 * Rights reserved to the copyright holder include:                                *
 *                                                                                 *
 * 1.  The right to publish these works commercially including, but not limited    *
 *     to, books, magazines, and commercial software libraries.                    *
 *                                                                                 *
 * 2.  The commercial rights, as cited above, to all derivative source and/or      *
 *     object modules. Note that this explicitly grants to the user all rights,    *
 *     commercial or otherwise, to any and all executable programs created using   *
 *     MicroFirm copyrighted source or object files contained in SNIPPETS.         *
 *                                                                                 *
 * Users are specifically prohibited from:                                         *
 *                                                                                 *
 * 1.  Removing the copyright notice and claiming the source files or any          *
 *     derivative works as their own.                                              *
 *                                                                                 *
 * 2.  Publishing the source files, the compiled object files, or libraries of     *
 *     the compiled object files commercially.                                     *
 *                                                                                 *
 * In other words, you are free to use these files to make programs, not to make   *
 * money! The programs you make with them, you may sell or give away as you        *
 * like, but you many not sell either the source files or object files, alone      *
 * or in a library, even if you've modified the original source, without a         *
 * license from the copyright holder.                                              *
 *                                                                                 *
 *                                                                                 *
 * Bob Stout                                                                       *
 * FidoNet:    1:106/2000.6                                                        *
 *             C_Echo moderator (1990-1991, 1996-1997)                             *
 * Internet:   rbs@snippets.org                                                    *
 *             rbs@brokersys.com                                                   *
 * SnailMail:  MicroFirm                                                           *
 *             P.O. Box 428                                                        *
 *             Alief, TX 77411                                                     *
 *                                                                                 *
 ***********************************************************************************/

struct operator_type {
      char        token;
      char       *tag;
      size_t      taglen;
      int         precedence;
};

static struct operator_type verbs[] = {
      {'+',  "+",       1, 2 },
      {'-',  "-",       1, 3 },
      {'*',  "*",       1, 4 },
      {'/',  "/",       1, 5 },
      {'%',  "%",       1, 5 },
      {'^',  "^",       1, 6 },
      {'(',  "(",       1, 0 },
      {')',  ")",       1, 99},
      {'=',  "==",      2, 0 },
      {'\\', "!=",      2, 0 },
      {'G',  "<=",      2, 0 },
      {'L',  ">=",      2, 0 },
      {'<',  "<",       1, 0 },
      {'>',  ">",       1, 0 },
      {'&',  "&&",      2, 0 },
      {'|',  "||",      2, 0 },
      {'!',  "!",       1, 0 },
      {0,  0,     0, 0 }
};

static char   op_stack[256];                    /* Operator stack       */
static double arg_stack[256];                   /* Argument stack       */
static char   token[256];                       /* Token buffer         */
static int    op_sptr,                          /* op_stack pointer     */
              arg_sptr,                         /* arg_stack pointer    */
              parens,                           /* Nesting level        */
              state;                            /* 0 = Awaiting expression
                                                   1 = Awaiting operator
                                                */
static int              do_op(void);
static int              do_paren(void);
static void             push_op(char);
static void             push_arg(double);
static int              pop_arg(double *);
static int              pop_op(int *);
static char            *get_exp(char *);
static struct operator_type *get_op(char *);
static int              getprec(char);
static int              getTOSprec(void);

/************************************************************************/
/*                                                                      */
/*  evaluate()                                                          */
/*                                                                      */
/*  Evaluates an ASCII mathematical expression.                         */
/*                                                                      */
/*  Arguments: 1 - String to evaluate                                   */
/*             2 - Storage to receive double result                     */
/*                                                                      */
/*  Returns: Success_ if successful                                     */
/*           Error_ if syntax error                                     */
/*           R_ERROR if runtime error                                   */
/*                                                                      */
/*  Side effects: Removes all whitespace from the string and converts   */
/*                it to U.C.                                            */
/*                                                                      */
/************************************************************************/

int evaluate(char *line, double *val)
{
      double arg;
      char *ptr = line, *str, *endptr;
      int ercode;
      struct operator_type *op;

      str_upr(line);
      state = op_sptr = arg_sptr = parens = 0;

      while (*ptr)
      {
            switch (state)
            {
            case 0:
                  if (NULL != (str = get_exp(ptr)))
                  {
                        if (NULL != (op = get_op(str)) &&
                              strlen(str) == op->taglen)
                        {
                              push_op(op->token);
                              ptr += op->taglen;
                              break;
                        }

                        if (Success_ == strcmp(str, "-"))
                        {
                              push_op(*str);
                              ++ptr;
                              break;
                        }

                        else
                        {
                              if (0.0 == (arg = strtod(str, &endptr)) &&
                                    NULL == strchr(str, '0'))
                              {
                                    return Error_;
                              }
                              push_arg(arg);
                        }
                        ptr += strlen(str);
                  }
                  else
                      return Error_;

                  state = 1;
                  break;

            case 1:
                  if (NULL != (op = get_op(ptr)))
                  {
                        if (')' == *ptr)
                        {
                              if (Success_ > (ercode = do_paren()))
                                    return ercode;
                        }
                        else
                        {
                              while (op_sptr &&
                                    op->precedence <= getTOSprec())
                              {
                                    do_op();
                              }
                              push_op(op->token);
                              state = 0;
                        }

                        ptr += op->taglen;
                  }
                  else  return Error_;

                  break;
            }
      }

      while (1 < arg_sptr)
      {
        if (Success_ > (ercode = do_op()))
           return ercode;
      }
      if (!op_sptr)
            return pop_arg(val);
      else if ( op_sptr == 1 && op_stack[0] == '!' )
      {
          if (Success_ > (ercode = do_op()))
              return ercode;
          else
          {
             pop_arg(val);
             return Success_;
          }
      }
      else  return Error_;
}

/*
**  Evaluate stacked arguments and operands
*/

static int do_op(void)
{
      double arg1, arg2;
      int op;

      if (Error_ == pop_op(&op))
            return Error_;

      pop_arg(&arg1);
      pop_arg(&arg2);

      switch (op)
      {
      case '+':
            push_arg(arg2 + arg1);
            break;

      case '-':
            push_arg(arg2 - arg1);
            break;

      case '*':
            push_arg(arg2 * arg1);
            break;

      case '/':
            if (0.0 == arg1)
                  return R_ERROR;
            push_arg(arg2 / arg1);
            break;

      case '%':
            if (0.0 == arg1)
                  return R_ERROR;
            push_arg(fmod(arg2, arg1));
            break;

      case '^':
            push_arg(pow(arg2, arg1));
            break;

      case 'G':
            push_arg(arg2 <= arg1);
            break;

      case 'L':
            push_arg(arg2 >= arg1);
            break;

      case '=':
            push_arg(arg2 == arg1);
            break;

      case '\\':
            push_arg(arg2 != arg1);
            break;

      case '<':
            push_arg(arg2 < arg1);
            break;

      case '>':
            push_arg(arg2 > arg1);
            break;

      case '&':
            push_arg(arg2 && arg1);
            break;

      case '|':
            push_arg(arg2 || arg1);
            break;

      case '!':
            arg_sptr++;
            push_arg(!arg1);
            break;

      case '(':
            arg_sptr += 2;
            break;

      default:
            return Error_;
      }
      if (1 > arg_sptr)
            return Error_;
      else  return op;
}

/*
**  Evaluate one level
*/

static int do_paren(void)
{
      int op;

      if (1 > parens--)
            return Error_;
      do
      {
            if (Success_ > (op = do_op()))
                  break;
      } while (getprec((char)op));
      return op;
}

/*
**  Stack operations
*/

static void push_op(char op)
{
      if (!getprec(op))
            ++parens;
      op_stack[op_sptr++] = op;
}

static void push_arg(double arg)
{
      arg_stack[arg_sptr++] = arg;
}

static int pop_arg(double *arg)
{
      *arg = arg_stack[--arg_sptr];
      if (0 > arg_sptr)
            return Error_;
      else  return Success_;
}

static int pop_op(int *op)
{
    if (!op_sptr && op_stack[0] != '!')
            return Error_;
      *op = op_stack[--op_sptr];
      return Success_;
}

/*
**  Get an expression
*/

static char * get_exp(char *str)
{
      char *ptr = str, *tptr = token;
      struct operator_type *op;

      while (*ptr)
      {
            if (NULL != (op = get_op(ptr)))
            {
                  if ('-' == *ptr)
                  {
                        if (str == ptr && !isdigit(ptr[1]) && '.' != ptr[1])
                        {
                              push_arg(0.0);
                              strcpy(token, op->tag);
                              return token;
                        }
                  }

                  else if (str == ptr)
                  {
                        strcpy(token, op->tag);
                        return token;
                  }

                  else break;
            }

            *tptr++ = *ptr++;
      }
      *tptr = 0;

      return token;
}

/*
**  Get an operator
*/

static struct operator_type * get_op(char *str)
{
      struct operator_type *op;

      for (op = verbs; op->token; ++op)
      {
            if (!strncmp(str, op->tag, op->taglen))
                  return op;
      }
      return NULL;
}

/*
**  Get precedence of a token
*/

static int getprec(char token)
{
      struct operator_type *op;

      for (op = verbs; op->token; ++op)
      {
            if (token == op->token)
                  break;
      }
      if (op->token)
            return op->precedence;
      else  return 0;
}

/*
**  Get precedence of TOS token
*/

static int getTOSprec(void)
{
      if (!op_sptr)
            return 0;
      return getprec(op_stack[op_sptr - 1]);
}