/*************************************************************************** * 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] ); }