/***************************************************************************
* 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 = NULL;
CHAR_DATA *ProgTriggeredBy = NULL;
CHAR_DATA *ProgVictim = NULL;
OBJ_DATA *ProgObjectSource = NULL;
OBJ_DATA *ProgObjectVictim = NULL;
ROOM_INDEX_DATA *ProgRoomSource = NULL;
char *ProgExtraArgs = NULL;
CHAR_DATA *supermob = NULL;
int ExecMudProgID = 0;
/* Random/Semi-Random ch's */
CHAR_DATA *RandomNPC = NULL;
bool RandomNPC_picked;
void mprog_get_RandomNPC( void );
CHAR_DATA *RandomPC = NULL;
bool RandomPC_picked;
void mprog_get_RandomPC( void );
CHAR_DATA *RandomANY = NULL;
bool RandomANY_picked;
void mprog_get_RandomANY( void );
CHAR_DATA *MostEvilFighter = NULL;
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;
ProgExtraArgs = 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,
IS_NPC( RandomANY ) ? RandomANY->short_descr : RandomANY->
name );
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,
IS_NPC( ProgTriggeredBy ) ? ProgTriggeredBy->
short_descr : ProgTriggeredBy->name );
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->name );
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,
IS_NPC( ProgVictim ) ? ProgVictim->
short_descr : ProgVictim->name );
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,
IS_NPC( MostEvilFighter ) ? MostEvilFighter->
short_descr : MostEvilFighter->name );
return;
case 'd':
if ( !ProgExtraArgs )
return;
else
{
char word[MAX_STRING_LENGTH];
char *copy = strdup( ProgExtraArgs );
one_argument( copy, word );
strcat( outbuf, word );
free( copy );
}
return;
case 'D':
if ( !ProgExtraArgs )
return;
else
strcat( outbuf, ProgExtraArgs );
return;
default:
bug( "Parse_Command_Var: Unknown 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 )
init_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 );
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 = 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;
case MOB_PROG:
pProgList = ProgSource->pIndexData->mudprogs;
break;
}
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 *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 & ACT_PROG ) )
{
if ( IS_NPC( actor ) && ( vmob->pIndexData == actor->pIndexData ) )
continue;
ProgSource = vmob;
ProgTriggeredBy = actor;
mprog_wordlist_check( txt, ACT_PROG, MOB_PROG );
}
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 *extra )
{
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;
ProgExtraArgs = extra;
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;
ProgExtraArgs = extra;
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 = 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;
ProgExtraArgs = extra;
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;
ProgExtraArgs = extra;
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 *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 & ACT_PROG )
{
ProgRoomSource = ch->in_room;
ProgTriggeredBy = ch;
/* supermob is set and released in mprog_wordlist_check */
mprog_wordlist_check( txt, ACT_PROG, ROOM_PROG );
}
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 *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 & ACT_PROG )
{
ProgTriggeredBy = ch;
ProgObjectSource = vobj;
mprog_wordlist_check( txt, ACT_PROG, OBJ_PROG );
}
return;
}
/*
* call in fight.c, 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) Med-Low *
* - (subtraction) Med-Low *
* * (multiplication) Medium *
* / (division) Medium *
* % (modulus) High *
* ^ (exponentiation) High *
* == Low *
* != Low *
* >= Low *
* <= Low *
* < Low *
* > Low *
* && Lowest *
* || Lowest *
* ! Low *
* *
* 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, 1},
{'\\', "!=", 2, 1},
{'G', "<=", 2, 1},
{'L', ">=", 2, 1},
{'<', "<", 1, 1},
{'>', ">", 1, 1},
{'&', "&&", 2, 0},
{'|', "||", 2, 0},
{'!', "!", 1, 1},
{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] );
}