/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*************************************************************************** * MudProgs has been completely rewritten by Zane. The only thing that * * remains the same is how triggers are handled. -Zane * * * * Original MobProgs by N'Atas-ha. * ***************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <math.h> #include "merc.h" #include "interp.h" #include "mud_progs.h" /* * This is a string that contains a list of valid seperators in the script like * ()/-=*+, etc... */ #define SEPERATOR_STRING "(),=<>!&|*+-/%^" #define Success_ 0 #define Error_ -1 #define R_ERROR -2 /* * Locals */ void release_supermob( void ); void set_supermob( void *source, int prog_type ); void init_supermob( void ); void mprog_wordlist_check( char *arg, int trigger_type, int prog_type ); bool mprog_percent_check( int trigger_type ); char *parse_script( char *script ); bool is_seperator( char c ); char *parse_if( char *instring ); char *parse_command( char *instring ); void parse_command_var( char var, char *outbuf); int parse_expression( char *instring ); int parse_proc( char *proc ); int exec_proc( char *procname, int intarg, char *chararg); int evaluate(char *line, double *val); void strip_whitespace( char *instring ); void *mprog_get_actor(char *arg, char type); void mprog_driver(char *prog); CHAR_DATA *ProgSource; CHAR_DATA *ProgTriggeredBy; CHAR_DATA *ProgVictim; OBJ_DATA *ProgObjectSource; OBJ_DATA *ProgObjectVictim; ROOM_INDEX_DATA *ProgRoomSource; CHAR_DATA *supermob; int ExecMudProgID = 0; /* Random/Semi-Random ch's */ CHAR_DATA *RandomNPC; bool RandomNPC_picked; void mprog_get_RandomNPC(void); CHAR_DATA *RandomPC; bool RandomPC_picked; void mprog_get_RandomPC(void); CHAR_DATA *RandomANY; bool RandomANY_picked; void mprog_get_RandomANY(void); CHAR_DATA *MostEvilFighter; bool MostEvilFighter_picked; void mprog_get_MostEvilFighter(void); /* * Main driver function, called by all triggers. */ void mprog_driver(char *prog) { /* Clear out our temp picks */ RandomNPC = NULL; RandomNPC_picked = FALSE; RandomPC = NULL; RandomPC_picked = FALSE; RandomANY = NULL; RandomANY_picked = FALSE; MostEvilFighter = NULL; MostEvilFighter_picked = FALSE; /* Increment our temp prog ID */ ExecMudProgID++; parse_script( prog ); /* Clear out locals */ ProgSource = NULL; ProgTriggeredBy = NULL; ProgVictim = NULL; ProgObjectSource = NULL; ProgObjectVictim = NULL; ProgRoomSource = NULL; } /* * Main script parsing function. Passes strings off to parse_if and parse_command * for processing. Also correctly handles breaks. */ char *parse_script( char *script ) { char buf[MAX_STRING_LENGTH]; char *curr; char *ptr = script; int pos; pos = 0; while( 1 ) { /* Skip leading spaces */ while( isspace(*ptr) ) if ( *++ptr == '\0') { bug("Parse_Script: Script ended without 'break'.\r\n"); return NULL; } curr = ptr; pos = 0; while( 1 ) { buf[pos++] = *ptr; if ( isspace( *ptr ) || *ptr == '(' ) { buf[--pos] = '\0'; if ( !strcmp(buf, "if") ) { while ( isspace( *ptr ) ) ptr++; if ( *ptr != '(' ) { bug("Parse_Script: Syntax error - If statment missing opening '('.\r\n"); return NULL; } if ( ( ptr = parse_if ( ptr ) ) == NULL ) return NULL; break; } else if ( !strcmp(buf, "break") ) { if ( *ptr == '(' ) { bug("Parse_Script: Syntax error - '(' encountered after 'break'.\r\n"); return NULL; } return NULL; } else if ( !strcmp(buf, "else") ) { if ( *ptr == '(' ) { bug("Parse_Script: Syntax error - '(' encountered after 'else'.\r\n"); return NULL; } return curr; } else if ( !strcmp(buf, "elseif") ) return curr; else if ( !strcmp(buf, "endif") ) { if ( *ptr == '(' ) { bug("Parse_Script: Syntax error - '(' encountered after 'endif'.\r\n"); return NULL; } return curr; } else { if ( *ptr == '(' ) { bug("Parse_Script: Syntax error - '(' encountered after a command.\r\n"); return NULL; } if ( ( ptr = parse_command( curr ) ) == NULL ) return NULL; break; } } if ( ++ptr == '\0' ) { bug("Parse_Script: EOF encountered in read.\r\n"); return NULL; } } } return ptr; } /* * The main loop found and if and passed the remaining string to us. Now we process the if statement and then execute * commands. */ char *parse_if( char *instring ) { char buf[MAX_STRING_LENGTH]; char *ptr = instring; char *tmpptr; int parans = 0; int pos = 0; int ifvalue = 0; bool elsedone = FALSE; /* Skip leading spaces */ while( isspace(*ptr) ) if ( ++ptr == '\0' ) { bug("Parse_If: EOF encountered in read.\r\n"); return NULL; } /* Evaluate the conditional portion of the if statement */ while( 1 ) { if ( isspace(*ptr) ) { ptr++; continue; } else if ( *ptr == '(' ) { if ( parans++ == 0 ) { ptr++; continue; } } else if ( *ptr == ')' ) { parans--; if ( parans < 0 ) { bug("Parse_If: ')' without prior '('.\r\n"); return NULL; } else if ( parans == 0 ) { /* Check to make sure we don't have an extra ')' */ tmpptr = ++ptr; while (*tmpptr && *tmpptr != '(' ) if ( *tmpptr++ == ')' ) { bug("Parse_If: Too many ')'s.\r\n"); return NULL; } buf[pos] = '\0'; ifvalue = parse_expression( buf ); break; } } buf[pos++] = *ptr++; if ( *ptr == '\0' ) { bug("Parse_If: Missing ')' in script.\r\n"); return NULL; } } /* Call parse_script again. This will process commands and allow for nested if's */ if ( ifvalue ) if ( ( ptr = parse_script( ptr ) ) == NULL ) return NULL; /* Check for elseif and endif */ while( 1 ) { /* Skip leading spaces */ while( isspace(*ptr) ) if ( ++ptr == '\0' ) { bug("Parse_If: EOF encountered in read.\r\n"); return NULL; } pos = 0; while( 1 ) { buf[pos++] = *ptr; if ( isspace( *ptr ) || *ptr == '(' ) { buf[--pos] = '\0'; if ( !strcmp(buf, "else" ) ) { if ( elsedone ) { bug("Parse_If: Multiple else's in if statement.\r\n"); return NULL; } elsedone = TRUE; if ( ( ptr = parse_script( ptr ) ) == NULL ) return NULL; while( isspace(*ptr) ) if (++ptr == '\0' ) { bug("Parse_If: EOF encountered in read.\r\n"); return NULL; } break; } else if ( !strcmp(buf, "elseif") ) { while ( isspace( *ptr ) ) ptr++; if ( *ptr != '(' ) { bug("Parse_If: Syntax error - Elseif statment missing opening '('.\r\n"); return NULL; } if ( !ifvalue ) return ( ptr = parse_if ( ptr ) ); /* read to the end of the line */ while( *ptr != '\r' && *ptr != '\n' && *ptr != '\0' ) *ptr++; break; } else if ( !strcmp(buf, "endif") ) { if ( *ptr == '(' ) { bug("Parse_If: Syntax error - '(' encountered after 'endif'.\r\n"); return NULL; } return ptr; } else { /* * If we reached this point then we had an elseif with a prior sucessfull if * so ignore all these lines untill we get to endif */ /* read to the end of the line */ while( *ptr != '\r' && *ptr != '\n' && *ptr != '\0' ) *ptr++; break; } } if ( ++ptr == '\0' ) { bug("Parse_If: EOF encountered in read.\r\n"); return NULL; } } } return ptr; } int parse_expression( char *instring ) { char buf[MAX_STRING_LENGTH]; char calcbuf[MAX_STRING_LENGTH]; char *ptr = instring; char *tmpptr = NULL; int bufpos = 0; int calcpos = 0; int parans = 0; double retval = 0; *buf = '\0'; *calcbuf = '\0'; strip_whitespace( instring ); while( *ptr != '\0' ) { if ( isalpha(*ptr) ) { if ( !tmpptr ) { bufpos = 0; tmpptr = ptr; } buf[bufpos++] = *ptr++; } else if ( *ptr == '(' && tmpptr ) { buf[bufpos++] = *ptr++; parans++; } else if ( *ptr == ')' && tmpptr ) { if ( parans <= 0 ) { bug("Parse_Expression: ')' without prior '('.\r\n"); return 0; } buf[bufpos++] = *ptr++; if ( --parans <= 0 ) { buf[bufpos] = '\0'; calcbuf[calcpos] = '\0'; sprintf(&calcbuf[calcpos], "%d", parse_proc(buf)); calcpos = strlen(calcbuf); tmpptr = NULL; } } else { if ( parans > 0 ) buf[bufpos++] = *ptr++; else { tmpptr = NULL; calcbuf[calcpos++] = *ptr++; } } } if ( tmpptr ) { bug("Parse_Expression: NULL encountered before ')'.\r\n"); return 0; } calcbuf[calcpos] = '\0'; if ( calcpos > 0 ) { if ( evaluate(calcbuf, &retval) == Success_ ) return (int) retval; else { bug("Parse_Expression: Error evaluating expression '%s'.\r\n", calcbuf); return 0; } } else return 0; } int parse_proc( char *proc ) { char procname[MAX_STRING_LENGTH]; char arg[MAX_STRING_LENGTH]; char *ptr = proc; char *tmpptr; tmpptr = procname; while( *ptr != '(' ) { if ( *ptr == '\0' ) { bug("Parse_Proc: NULL encountered before '('.\r\n"); return 0; } *tmpptr++ = *ptr++; } *tmpptr = '\0'; if ( *++ptr == '\0' ) { bug("Parse_Proc: NULL encountered before ')'.\r\n"); return 0; } tmpptr = arg; while( *ptr != ')' ) { if ( *ptr == '\0' ) { bug("Parse_Proc: NULL encountered before '('.\r\n"); return 0; } *tmpptr++ = *ptr++; } *tmpptr = '\0'; switch(*arg) { case '$': return exec_proc(procname, 0, arg); break; case '\0': return exec_proc(procname, 0, NULL); break; default: return exec_proc(procname, parse_expression(arg), NULL); break; } } int exec_proc( char *procname, int intarg, char *chararg) { int cmd; bool found = FALSE; for ( cmd = 0; mprog_cmd_table[cmd].name[0] != '\0'; cmd++ ) if ( procname[0] == mprog_cmd_table[cmd].name[0] && !str_cmp(procname, mprog_cmd_table[cmd].name) ) { found = TRUE; break; } if ( !found ) { bug("Exec_Proc: Invalid proc name - %s.\r\n", procname); return 0; } switch(UPPER(mprog_cmd_table[cmd].argtype)) { case 'C': return (*mprog_cmd_table[cmd].mprog_fun) (mprog_get_actor(chararg, 'C')); case 'O': return (*mprog_cmd_table[cmd].mprog_fun) (mprog_get_actor(chararg, 'O')); case 'S': return (*mprog_cmd_table[cmd].mprog_fun) ((void *) chararg); case 'I': return (*mprog_cmd_table[cmd].mprog_fun) ((void *) &intarg); case 'N': return (*mprog_cmd_table[cmd].mprog_fun) ( NULL ); default: bug("Exec_Proc: Unknown argtype %c.\r\n", mprog_cmd_table[cmd].argtype); return 0; } } /* * Returns a pointer to a CHAR_DATA structure when passed a $* variable. */ void *mprog_get_actor(char *arg, char type) { ROOM_INDEX_DATA *pRoom; if ( !ProgSource || (pRoom = ProgSource->in_room) == NULL ) return NULL; if ( strlen(arg) !=2 || *arg != '$' ) { bug("Mprog_Get_Actor: Invalid variable '%s'.\r\n", arg); return NULL; } switch( type ) { case 'C': switch( UPPER(arg[1]) ) { case 'I': return ProgSource; case 'N': return ProgTriggeredBy; case 'T': return ProgVictim; case 'R': if ( !RandomPC_picked ) mprog_get_RandomPC(); return RandomPC; case 'X': if ( !MostEvilFighter_picked ) mprog_get_MostEvilFighter(); return MostEvilFighter; case 'B': if ( !RandomNPC_picked ) mprog_get_RandomNPC(); return RandomNPC; case 'C': if ( !RandomANY_picked ) mprog_get_RandomANY(); return RandomANY; default: bug("Mprog_Get_Actor: Invalid variable '%s' for argtype 'C'.\r\n", arg); return NULL; } break; case 'O': switch( UPPER(arg[1]) ) { case 'O': return ProgObjectSource; case 'P': return ProgObjectVictim; default: bug("Mprog_Get_Actor: Invalid variable '%s' for argtype 'O'.\r\n", arg); return NULL; } break; default: bug("Mprog_Get_Actor: Invalid argtype '%c'.\r\n", type); return NULL; } } char *parse_command( char *instring ) { char cmd[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; char *ptr = instring; int pos = 0; int bufpos = 0; bool escape = FALSE; *buf = '\0'; /* Get rid of spaces in the beginning */ while( *ptr == ' ' || *ptr == '\t' ) ptr++; while( *ptr != '\r' && *ptr != '\n' ) { switch(*ptr) { case '#': if(!escape) { if (*++ptr == '#') cmd[pos++] = *ptr++; else escape = TRUE; } else if ( escape ) { if (*++ptr == '#') buf[bufpos++] = *ptr++; else { buf[bufpos] = '\0'; sprintf(&cmd[pos], "%d", parse_expression(buf)); pos = strlen(cmd); escape = FALSE; } } break; case '$': if( !escape ) { if ( *++ptr == '$' ) cmd[pos++] = *ptr++; else { parse_command_var(*ptr, &cmd[pos]); pos = strlen(cmd); ptr++; } } else buf[bufpos++] = *ptr++; break; default: if(escape) buf[bufpos++] = *ptr++; else cmd[pos++] = *ptr++; break; } if ( *ptr == '\0' ) { bug("Parse_Command: EOL encountered.\r\n"); return NULL; } } cmd[pos] = '\0'; /* Pass cmd and arg to the command interpreter */ interpret(ProgSource, cmd); return ptr; } /* * Takes the var name passed and converts it to a text string based on the var. */ void parse_command_var( char var, char *outbuf) { char buf[MAX_STRING_LENGTH]; static char *he_she [] = { "it", "he", "she" }; static char *him_her [] = { "it", "him", "her" }; static char *his_her [] = { "its", "his", "her" }; *outbuf = '\0'; *buf = '\0'; switch(var) { case 'a': if ( ProgObjectSource ) switch ( *( ProgObjectSource->name ) ) { case 'a': case 'e': case 'i': case 'o': case 'u': strcat( outbuf, "an" ); break; default: strcat( outbuf, "a" ); break; } return; case 'A': if ( ProgObjectVictim ) switch ( *( ProgObjectVictim->name ) ) { case 'a': case 'e': case 'i': case 'o': case 'u': strcat( outbuf, "an" ); break; default: strcat( outbuf, "a" ); break; } return; case 'b': if ( !RandomNPC_picked ) mprog_get_RandomNPC(); if ( RandomNPC ) { one_argument( RandomNPC->name, buf); strcat(outbuf, buf); } return; case 'B': if ( !RandomNPC_picked ) mprog_get_RandomNPC(); if ( RandomNPC ) strcat(outbuf, RandomNPC->short_descr); return; case 'c': if ( !RandomANY_picked ) mprog_get_RandomANY(); if ( RandomANY ) { one_argument( RandomANY->name, buf); strcat(outbuf, buf); } return; case 'C': if ( !RandomANY_picked ) mprog_get_RandomANY(); if ( RandomANY ) strcat(outbuf, RandomANY->short_descr); return; case 'e': if ( ProgTriggeredBy ) { if ( can_see( ProgSource, ProgTriggeredBy ) ) strcat( outbuf, he_she[ ProgTriggeredBy->sex ] ); else strcat( outbuf, "someone" ); } return; case 'E': if ( ProgVictim ) { if ( can_see( ProgSource, ProgVictim ) ) strcat( outbuf, he_she[ ProgVictim->sex ] ); else strcat( outbuf, "someone" ); } return; case 'i': if ( ProgSource ) { one_argument( ProgSource->name, buf); strcat(outbuf, buf); } return; case 'I': if ( ProgSource ) strcat(outbuf, ProgSource->short_descr); return; case 'j': if ( ProgSource ) strcat( outbuf, he_she[ ProgSource->sex ] ); return; case 'J': if ( !RandomPC_picked ) mprog_get_RandomPC(); if ( RandomPC ) strcat( outbuf, he_she[ RandomPC->sex ] ); return; case 'k': if ( ProgSource ) strcat( outbuf, him_her[ ProgSource->sex ] ); return; case 'K': if ( !RandomPC_picked ) mprog_get_RandomPC(); if ( RandomPC ) strcat( outbuf, him_her[ RandomPC->sex ] ); return; case 'l': if ( ProgSource ) strcat( outbuf, his_her[ ProgSource->sex ] ); return; case 'L': if ( !RandomPC_picked ) mprog_get_RandomPC(); if ( RandomPC ) strcat( outbuf, his_her[ RandomPC->sex ] ); return; case 'm': if ( ProgTriggeredBy ) { if ( can_see( ProgSource, ProgTriggeredBy ) ) strcat( outbuf, him_her[ ProgTriggeredBy->sex ] ); else strcat( outbuf, "someone" ); } return; case 'M': if ( ProgVictim ) { if ( can_see( ProgSource, ProgVictim ) ) strcat( outbuf, him_her[ ProgVictim->sex ] ); else strcat( outbuf, "someone" ); } return; case 'n': if ( ProgTriggeredBy ) { one_argument( ProgTriggeredBy->name, buf); strcat(outbuf, buf); } return; case 'N': if ( ProgTriggeredBy ) strcat(outbuf, ProgTriggeredBy->short_descr); return; case 'o': if ( ProgObjectSource ) { one_argument( ProgObjectSource->name, buf); strcat(outbuf, buf); } return; case 'O': if ( ProgObjectSource ) strcat(outbuf, ProgObjectSource->short_descr); return; case 'p': if ( ProgObjectVictim ) { one_argument( ProgObjectVictim->name, buf); strcat(outbuf, buf); } return; case 'P': if ( ProgObjectVictim ) strcat(outbuf, ProgObjectVictim->short_descr); return; case 'r': if ( !RandomPC_picked ) mprog_get_RandomPC(); if ( RandomPC ) { one_argument( RandomPC->name, buf); strcat(outbuf, buf); } return; case 'R': if ( !RandomPC_picked ) mprog_get_RandomPC(); if ( RandomPC ) strcat(outbuf, RandomPC->short_descr); return; case 's': if ( ProgTriggeredBy ) { if ( can_see( ProgSource, ProgTriggeredBy ) ) strcat( outbuf, his_her[ ProgTriggeredBy->sex ] ); else strcat( outbuf, "someone" ); } return; case 'S': if ( ProgVictim ) { if ( can_see( ProgSource, ProgVictim ) ) strcat( outbuf, his_her[ ProgVictim->sex ] ); else strcat( outbuf, "someone" ); } return; case 't': if ( ProgVictim ) { one_argument( ProgVictim->name, buf); strcat(outbuf, buf); } return; case 'T': if ( ProgVictim ) strcat(outbuf, ProgVictim->short_descr); return; case 'x': if ( !MostEvilFighter_picked ) mprog_get_MostEvilFighter(); if ( MostEvilFighter ) { one_argument( MostEvilFighter->name, buf); strcat(outbuf, buf); } return; case 'X': if ( !MostEvilFighter_picked ) mprog_get_MostEvilFighter(); if ( MostEvilFighter ) strcat(outbuf, MostEvilFighter->short_descr); return; default: bug("Parse_Command_Var: Unkown command variable '$%c'.\r\n", var); return; } } void init_supermob( void ) { supermob = create_mobile( get_mob_index(MOB_VNUM_SUPERMOB) ); char_to_room( supermob, get_room_index(ROOM_VNUM_SUPERMOB) ); return; } void set_supermob( void *source, int prog_type ) { OBJ_DATA *pObj = NULL; ROOM_INDEX_DATA *pRoom = NULL; OBJ_DATA *in_obj = NULL; char buf[200]; if ( !supermob ) { supermob = create_mobile(get_mob_index( MOB_VNUM_SUPERMOB )); char_to_room( supermob, get_room_index(ROOM_VNUM_SUPERMOB) ); } if(!source) return; switch(prog_type) { case OBJ_PROG: pObj = (OBJ_DATA *) source; for ( in_obj = pObj; in_obj->in_obj; in_obj = in_obj->in_obj ) ; if ( in_obj->carried_by ) pRoom = in_obj->carried_by->in_room; else pRoom = pObj->in_room; if( !pRoom ) return; if (supermob->short_descr) free_string(supermob->short_descr); supermob->short_descr = str_dup(pObj->short_descr); supermob->level = pObj->level; /* Added by Jenny to allow bug messages to show the vnum of the object, and not just supermob's vnum */ sprintf( buf, "Object #%d", pObj->pIndexData->vnum ); free_string( supermob->description ); supermob->description = str_dup( buf ); /* * Point the Supermob's prog list to the object's list for easier use. * Leave Supermob's progtypes at 0 so no progs are ever triggered. -Zane */ supermob->pIndexData->mudprogs = pObj->pIndexData->mudprogs; break; case ROOM_PROG: pRoom = (ROOM_INDEX_DATA *) source; if ( supermob->short_descr ) free_string(supermob->short_descr); supermob->short_descr = str_dup(pRoom->name); if ( supermob->name ) free_string(supermob->name); supermob->name = str_dup(pRoom->name); /* Added by Jenny to allow bug messages to show the vnum of the room, and not just supermob's vnum */ sprintf( buf, "Room #%d", pRoom->vnum ); if ( supermob->description ) free_string( supermob->description ); supermob->description = str_dup( buf ); /* * Point the Supermob's prog list to the object's list for easier use. * Leave Supermob's progtypes at 0 so no progs are ever triggered. -Zane */ supermob->pIndexData->mudprogs = pRoom->mudprogs; break; } char_from_room (supermob ); char_to_room( supermob, pRoom); return; } void release_supermob( void ) { char_from_room( supermob ); if ( supermob->name ) free_string( supermob->name ); if ( supermob->short_descr ) free_string( supermob->short_descr ); if ( supermob->description ) free_string( supermob->description ); supermob->name = str_dup("SuperMob"); supermob->level = HERO; supermob->pIndexData->mudprogs = NULL; char_to_room( supermob, get_room_index( ROOM_VNUM_SUPERMOB ) ); } void mprog_get_RandomNPC(void) { CHAR_DATA *ch; int count = 0; int random = 0; /* Get the number of NPC's in the room */ for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room ) if ( IS_NPC( ch ) && can_see( ProgSource, ch ) ) count++; random = number_range( 1, count ); count = 0; /* get a random visible NPC who is in the room with the mob */ for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room ) if ( IS_NPC( ch ) && can_see( ProgSource, ch ) && ++count == random ) { RandomNPC = ch; RandomNPC_picked = TRUE; } } void mprog_get_RandomPC(void) { CHAR_DATA *ch; int count = 0; int random = 0; /* Get the number of PC's in the room */ for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room ) if ( !IS_NPC( ch ) && can_see( ProgSource, ch ) ) count++; random = number_range( 1, count ); count = 0; /* get a random visible mortal player who is in the room with the mob */ for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room ) if ( !IS_NPC( ch ) && can_see( ProgSource, ch ) && ++count == random ) { RandomPC = ch; RandomPC_picked = TRUE; } } void mprog_get_RandomANY(void) { CHAR_DATA *ch; int count = 0; int random = 0; /* Get the number of visible PC's and NPC's in the room */ for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room ) if ( can_see( ProgSource, ch ) ) count++; random = number_range( 1, count ); count = 0; /* get a random visible NPC or PC in the room with the mob */ for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room ) if ( can_see( ProgSource, ch ) && ++count == random ) { RandomANY = ch; RandomANY_picked = TRUE; } } void mprog_get_MostEvilFighter(void) { CHAR_DATA *ch; int max_evil = 0; /* get the most evil visible mortal player who is in the room with the mob and is fighting */ for ( ch = ProgSource->in_room->people; ch; ch = ch->next_in_room ) if ( !IS_NPC( ch ) && can_see( ProgSource, ch ) ) if ( ch->fighting && ch->alignment < max_evil ) { max_evil = ch->alignment; MostEvilFighter = ch; MostEvilFighter_picked = TRUE; } } /* * Use the constant seperator string to decide wether or not c is a * seperator */ bool is_seperator( char c ) { char *ptr = SEPERATOR_STRING; do { if ( c == *ptr ) return TRUE; } while (*++ptr != '\0'); return FALSE; } void strip_whitespace( char *instring ) { char *inptr = instring, *outptr = instring; while( *inptr ) { if ( isspace(*inptr) ) inptr++; else *outptr++ = *inptr++; } *outptr = '\0'; } bool mprog_percent_check( int trigger_type ) { MPROG_LIST *pProgList; bool executed = FALSE; if ( !ProgSource || !ProgSource->pIndexData ) return FALSE; for ( pProgList = ProgSource->pIndexData->mudprogs; pProgList; pProgList = pProgList->next ) if ( ( pProgList->mudprog->trigger_type & trigger_type ) && ( number_percent( ) < atoi( pProgList->mudprog->arglist ) ) ) { executed = TRUE; mprog_driver( pProgList->mudprog->comlist ); if ( trigger_type != GREET_PROG && trigger_type != ALL_GREET_PROG && trigger_type != ENTER_PROG ) break; } return executed; } /* The next two routines are the basic trigger types. Either trigger * on a certain percent, or trigger on a keyword or word phrase. * To see how this works, look at the various trigger routines.. */ void mprog_wordlist_check( char *arg, int trigger_type, int prog_type ) { char temp1[ MAX_STRING_LENGTH ]; char temp2[ MAX_INPUT_LENGTH ]; char word[ MAX_INPUT_LENGTH ]; MPROG_DATA *mprg; MPROG_LIST *pProgList = NULL; char *list; char *start; char *dupl; char *end; unsigned int i; switch( prog_type ) { case ROOM_PROG: pProgList = ProgRoomSource->mudprogs; break; case OBJ_PROG: pProgList = ProgObjectSource->pIndexData->mudprogs; break; } pProgList = ProgSource->pIndexData->mudprogs; for ( ; pProgList; pProgList = pProgList->next ) if ( pProgList->mudprog->trigger_type & trigger_type ) { mprg = pProgList->mudprog; strcpy( temp1, mprg->arglist ); list = temp1; for ( i = 0; i < strlen( list ); i++ ) list[i] = LOWER( list[i] ); strcpy( temp2, arg ); dupl = remove_color(temp2); for ( i = 0; i < strlen( dupl ); i++ ) dupl[i] = LOWER( dupl[i] ); if ( ( list[0] == 'p' ) && ( list[1] == ' ' ) ) { list += 2; while ( ( start = strstr( dupl, list ) ) ) if ( (start == dupl || *(start-1) == ' ' ) && ( *(end = start + strlen( list ) ) == ' ' || *end == '\n' || *end == '\r' || *end == '\0' ) ) { if ( prog_type == OBJ_PROG ) { set_supermob( ProgObjectSource, prog_type ); ProgSource = supermob; } else if ( prog_type == ROOM_PROG ) { set_supermob( ProgRoomSource, prog_type ); ProgSource = supermob; } mprog_driver( mprg->comlist ); if ( ProgSource == supermob ) release_supermob(); break; } else dupl = start+1; } else { list = one_argument( list, word ); for( ; word[0] != '\0'; list = one_argument( list, word ) ) while ( ( start = strstr( dupl, word ) ) ) if ( ( start == dupl || *(start-1) == ' ' ) && ( *(end = start + strlen( word ) ) == ' ' || *end == '\n' || *end == '\r' || *end == '\0' ) ) { if ( prog_type == OBJ_PROG ) { set_supermob( ProgObjectSource, prog_type ); ProgSource = supermob; } else if ( prog_type == ROOM_PROG ) { set_supermob( ProgRoomSource, prog_type ); ProgSource = supermob; } mprog_driver( mprg->comlist ); if ( ProgSource == supermob ) release_supermob(); break; } else dupl = start+1; } } return; } /* The triggers.. These are really basic, and since most appear only * once in the code (hmm. i think they all do) it would be more efficient * to substitute the code in and make the mprog_xxx_check routines global. * However, they are all here in one nice place at the moment to make it * easier to see what they look like. If you do substitute them back in, * make sure you remember to modify the variable names to the ones in the * trigger calls. */ /* void mprog_act_trigger( char *buf, CHAR_DATA *mob, CHAR_DATA *ch, OBJ_DATA *obj, void *vo) { MPROG_ACT_LIST * tmp_act; MPROG_LIST *pProgList; bool found = FALSE; if ( IS_NPC( mob ) && IS_SET( mob->pIndexData->progtypes, ACT_PROG ) ) { if ( IS_NPC( ch ) && ch->pIndexData == mob->pIndexData ) return; for ( pProgList = mob->pIndexData->mudprogs; pProgList; pProgList = pProgList->next ) if ( pProgList->mudprog->trigger_type & ACT_PROG ) { found = TRUE; break; } if ( !found ) return; tmp_act = alloc_mem( sizeof( MPROG_ACT_LIST ) ); if ( mob->mpactnum > 0 ) tmp_act->next = mob->mpact; else tmp_act->next = NULL; mob->mpact = tmp_act; mob->mpact->buf = str_dup( buf ); mob->mpact->ch = ch; mob->mpact->obj = obj; mob->mpact->vo = vo; mob->mpactnum++; } return; }*/ void mprog_bribe_trigger( CHAR_DATA *mob, CHAR_DATA *ch, int amount ) { char buf[ MAX_STRING_LENGTH ]; MPROG_LIST *pList; OBJ_DATA *obj; if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & BRIBE_PROG ) ) { if ( IS_NPC( ch ) && ch->pIndexData == mob->pIndexData ) return; obj = create_object( get_obj_index( OBJ_VNUM_MONEY_SOME ), 0 ); sprintf( buf, obj->short_descr, amount ); free_string( obj->short_descr ); obj->short_descr = str_dup( buf ); obj->value[0] = amount; obj_to_char( obj, mob ); mob->gold -= amount; for ( pList = mob->pIndexData->mudprogs; pList; pList = pList->next ) if ( ( pList->mudprog->trigger_type & BRIBE_PROG ) && ( amount >= atoi( pList->mudprog->arglist ) ) ) { ProgSource = mob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_driver( pList->mudprog->comlist ); break; } } return; } void mprog_death_trigger( CHAR_DATA *mob ) { if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & DEATH_PROG ) ) { mob->position = POS_RESTING; ProgSource = mob; mprog_percent_check( DEATH_PROG ); mob->position = POS_DEAD; } else { death_cry( mob ); } return; } void mprog_entry_trigger( CHAR_DATA *mob ) { if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & ENTRY_PROG ) ) { ProgSource = mob; mprog_percent_check( ENTRY_PROG ); } return; } void mprog_fight_trigger( CHAR_DATA *mob, CHAR_DATA *ch ) { if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & FIGHT_PROG ) ) { if ( IS_NPC( ch ) && ch->pIndexData == mob->pIndexData ) return; ProgSource = mob; ProgTriggeredBy = ch; mprog_percent_check( FIGHT_PROG ); } return; } void mprog_fightgroup_trigger( CHAR_DATA *mob ) { CHAR_DATA *victim; if ( !mob || !mob->in_room ) return; if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & FIGHTGROUP_PROG ) ) { ProgSource = mob; for ( victim = mob->in_room->people; victim; victim = victim->next_in_room ) { if ( victim != mob && victim->fighting == mob ) { ProgTriggeredBy = victim; if ( mprog_percent_check( FIGHTGROUP_PROG ) ) break; } } } return; } void mprog_give_trigger( CHAR_DATA *mob, CHAR_DATA *ch, OBJ_DATA *obj ) { char buf[MAX_INPUT_LENGTH]; MPROG_LIST *pList; if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & GIVE_PROG ) ) { if ( IS_NPC( ch ) && ch->pIndexData == mob->pIndexData ) return; for ( pList = mob->pIndexData->mudprogs; pList; pList = pList->next ) { one_argument( pList->mudprog->arglist, buf ); if ( ( pList->mudprog->trigger_type & GIVE_PROG ) && ( ( !str_cmp( obj->name, pList->mudprog->arglist ) ) || ( !str_cmp( "all", buf ) ) ) ) { ProgSource = mob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_driver( pList->mudprog->comlist ); break; } } } return; } void mprog_greet_trigger( CHAR_DATA *ch ) { CHAR_DATA *vmob; if ( IS_NPC( ch ) ) return; for ( vmob = ch->in_room->people; vmob; vmob = vmob->next_in_room ) if ( IS_NPC( vmob ) && ch != vmob && can_see( vmob, ch ) && ( !vmob->fighting ) && IS_AWAKE( vmob ) && ( vmob->pIndexData->progtypes & GREET_PROG) ) { ProgSource = vmob; ProgTriggeredBy = ch; mprog_percent_check( GREET_PROG ); } else if ( IS_NPC( vmob ) && ( !vmob->fighting ) && IS_AWAKE( vmob ) && ( vmob->pIndexData->progtypes & ALL_GREET_PROG ) ) { ProgSource = vmob; ProgTriggeredBy = ch; mprog_percent_check( ALL_GREET_PROG ); } return; } void mprog_hitprcnt_trigger( CHAR_DATA *mob, CHAR_DATA *ch) { MPROG_LIST *pList; if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & HITPRCNT_PROG ) ) { if ( IS_NPC( ch ) && ch->pIndexData == mob->pIndexData ) return; for ( pList = mob->pIndexData->mudprogs; pList; pList = pList->next ) if ( ( pList->mudprog->trigger_type & HITPRCNT_PROG ) && ( ( 100*mob->hit / mob->max_hit ) < atoi( pList->mudprog->arglist ) ) ) { ProgSource = mob; ProgTriggeredBy = ch; mprog_driver( pList->mudprog->comlist ); break; } } return; } void mprog_random_trigger( CHAR_DATA *mob ) { if ( mob->pIndexData->progtypes & RAND_PROG) { ProgSource = mob; mprog_percent_check( RAND_PROG ); } return; } void mprog_speech_trigger( char *txt, CHAR_DATA *actor ) { CHAR_DATA *vmob; for ( vmob = actor->in_room->people; vmob; vmob = vmob->next_in_room ) if ( IS_NPC( vmob ) && ( vmob->pIndexData->progtypes & SPEECH_PROG ) ) { if ( IS_NPC( actor ) && ( vmob->pIndexData == actor->pIndexData ) ) continue; ProgSource = vmob; ProgTriggeredBy = actor; mprog_wordlist_check( txt, SPEECH_PROG, MOB_PROG ); } return; } /* Written by Zak, Jan 13/1998 * Goes in interpret() before regular command parsing. * This function checks all mobs in room with the character for a command * trigger matching what the character typed. * The function returns TRUE if the character's command should be run * through the regular interpreter too. */ bool mprog_command_trigger (char *txt, CHAR_DATA *ch) { char *argument; char arg [MAX_INPUT_LENGTH];/* I'm assuming that the cmd_table won't * ever have a command longer than * MAX_INPUT_LENGTH */ char *pMem; /* Pointer to the memory allocated by argument. * This is needed so we can free that memory up * at the end of the function */ CHAR_DATA *vmob; OBJ_DATA *obj; ROOM_INDEX_DATA *room; MPROG_LIST *pList; int cmd; bool can_do = TRUE; pMem = strdup(txt); argument = pMem; /* First check for the command typed being a prefix of anything in * the regular command table, and expand it to the full command. */ argument = one_argument( argument, arg ); for (cmd=0; cmd_table[cmd].name[0] != '\0'; cmd++) { if (arg[0] == cmd_table[cmd].name[0] && !str_prefix( arg, cmd_table[cmd].name ) ) { strncpy(arg,cmd_table[cmd].name,sizeof(arg)); break; } } /* Find mobs that are in_room that have a COMMAND_PROG */ for ( vmob = ch->in_room->people; vmob; vmob = vmob->next_in_room ) if ( IS_NPC( vmob ) && ( vmob->pIndexData->progtypes & COMMAND_PROG ) ) { for ( pList = vmob->pIndexData->mudprogs; pList; pList = pList->next ) { if ( ( pList->mudprog->trigger_type & COMMAND_PROG ) && (!str_cmp(pList->mudprog->arglist,arg)) ) { ProgSource = vmob; ProgTriggeredBy = ch; mprog_driver( pList->mudprog->comlist ); can_do = FALSE; } } } /* Obj and Room command_prog support by Kyle Boyd */ /* objs in inventory and worn... */ for ( obj = ch->carrying; obj; obj = obj->next_content ) if ( obj->pIndexData->progtypes & COMMAND_PROG ) { for ( pList = obj->pIndexData->mudprogs; pList; pList = pList->next ) { if ( (pList->mudprog->trigger_type & COMMAND_PROG) && (!str_cmp(pList->mudprog->arglist,arg)) ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_driver( pList->mudprog->comlist ); release_supermob(); can_do = FALSE; } } } /* objs in room... */ for ( obj = ch->in_room->contents; obj; obj = obj->next_content ) if ( obj->pIndexData->progtypes & COMMAND_PROG ) { for ( pList = vmob->pIndexData->mudprogs; pList; pList = pList->next) { if ( (pList->mudprog->trigger_type & COMMAND_PROG) && (!str_cmp(pList->mudprog->arglist,arg)) ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_driver( pList->mudprog->comlist ); release_supermob(); can_do = FALSE; } } } /* And finally, room progs */ room = ch->in_room; if ( room->progtypes & COMMAND_PROG ) { for ( pList = room->mudprogs; pList; pList = pList->next) { if ( (pList->mudprog->trigger_type & COMMAND_PROG) && (!str_cmp(pList->mudprog->arglist,arg)) ) { set_supermob( room, ROOM_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; mprog_driver( pList->mudprog->comlist ); release_supermob(); can_do = FALSE; } } } free(pMem); return can_do; } /***************************************************************** * ROOM PROG SUPPORT STARTS HERE: * * most of this code was taken from the SMAUG code base * * with modifications made to fit our mud... * *****************************************************************/ /* * Triggers follow */ /* void rprog_act_trigger( char *buf, ROOM_INDEX_DATA *room, CHAR_DATA *ch, OBJ_DATA *obj, void *vo ) { if ( room->progtypes & ACT_PROG ) { MPROG_ACT_LIST *tmp_act; */ /* supermob can't trigger it's own mprog */ /* if ( IS_NPC(ch) && ch->pIndexData == supermob->pIndexData ) return; tmp_act = alloc_mem( sizeof( MPROG_ACT_LIST ) ); if ( room->mpactnum > 0 ) tmp_act->next = room->mpact; else tmp_act->next = NULL; room->mpact = tmp_act; room->mpact->buf = str_dup(buf); room->mpact->ch = ch; room->mpact->obj = obj; room->mpact->vo = vo; room->mpactnum++; room_act_add(room); } return; }*/ void rprog_leave_trigger( CHAR_DATA *ch ) { if( ch->in_room && ch->in_room->progtypes & LEAVE_PROG ) { set_supermob( ch->in_room, ROOM_PROG ); ProgSource = supermob; mprog_percent_check( LEAVE_PROG ); release_supermob(); } return; } void rprog_enter_trigger( CHAR_DATA *ch ) { if( ch->in_room && ch->in_room->progtypes & ENTER_PROG ) { set_supermob( ch->in_room, ROOM_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; mprog_percent_check( ENTRY_PROG ); release_supermob(); } return; } void rprog_sleep_trigger( CHAR_DATA *ch ) { if( ch->in_room && ch->in_room->progtypes & SLEEP_PROG ) { set_supermob( ch->in_room, ROOM_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; mprog_percent_check( SLEEP_PROG ); release_supermob(); } return; } void rprog_rest_trigger( CHAR_DATA *ch ) { if( ch->in_room && ch->in_room->progtypes & REST_PROG ) { set_supermob( ch->in_room, ROOM_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; mprog_percent_check( REST_PROG ); release_supermob(); } return; } void rprog_rfight_trigger( CHAR_DATA *ch ) { if( ch->in_room && ch->in_room->progtypes & RFIGHT_PROG ) { set_supermob( ch->in_room, ROOM_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; mprog_percent_check( RFIGHT_PROG ); release_supermob(); } return; } void rprog_death_trigger( CHAR_DATA *ch ) { if( ch->in_room && ch->in_room->progtypes & RDEATH_PROG ) { set_supermob( ch->in_room, ROOM_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; mprog_percent_check( RDEATH_PROG ); release_supermob(); } return; } void rprog_speech_trigger( char *txt, CHAR_DATA *ch ) { /* prevent circular triggers by not allowing mob to trigger itself */ if ( IS_NPC(ch) && ch->pIndexData == supermob->pIndexData ) return; if( ch->in_room && ch->in_room->progtypes & SPEECH_PROG ) { ProgRoomSource = ch->in_room; ProgTriggeredBy = ch; /* supermob is set and released in mprog_wordlist_check */ mprog_wordlist_check( txt, SPEECH_PROG, ROOM_PROG ); } return; } void rprog_random_trigger( CHAR_DATA *ch ) { if ( ch->in_room && ch->in_room->progtypes & RAND_PROG) { set_supermob( ch->in_room, ROOM_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; mprog_percent_check( RAND_PROG ); release_supermob(); } return; } /***************************************************************** * OBJECT PROG SUPPORT STARTS HERE: * * most of this code was taken from the SMAUG code base * * with modifications made to fit our mud... * *****************************************************************/ /* * Triggers follow */ void oprog_greet_trigger( CHAR_DATA *ch ) { OBJ_DATA *vobj; for ( vobj=ch->in_room->contents; vobj; vobj = vobj->next_content ) if ( vobj->pIndexData->progtypes & GREET_PROG ) { set_supermob( vobj, OBJ_PROG ); /* not very efficient to do here */ ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = vobj; mprog_percent_check( GREET_PROG ); release_supermob(); } return; } void oprog_speech_trigger( char *txt, CHAR_DATA *ch ) { OBJ_DATA *vobj; /* supermob is set and released in mprog_wordlist_check */ for ( vobj=ch->in_room->contents; vobj; vobj = vobj->next_content ) if ( vobj->pIndexData->progtypes & SPEECH_PROG ) { ProgTriggeredBy = ch; ProgObjectSource = vobj; mprog_wordlist_check( txt, SPEECH_PROG, OBJ_PROG ); } return; } /* * Called at top of obj_update * make sure to put an if(!obj) continue * after it */ void oprog_random_trigger( OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & RAND_PROG) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgObjectSource = obj; mprog_percent_check( RAND_PROG ); release_supermob(); } return; } /* * in wear_obj, between each successful equip_char * the subsequent return */ void oprog_wear_trigger( CHAR_DATA *ch, OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & WEAR_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_percent_check( WEAR_PROG ); release_supermob(); } return; } bool oprog_use_trigger( CHAR_DATA *ch, OBJ_DATA *obj, CHAR_DATA *vict, OBJ_DATA *targ ) { bool executed = FALSE; if ( obj->pIndexData->progtypes & USE_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; if ( obj->item_type == ITEM_STAFF && vict ) ProgVictim = vict; else ProgObjectVictim = targ; executed = mprog_percent_check( USE_PROG ); release_supermob(); } return executed; } /* * call in remove_obj, right after unequip_char * do a if(!ch) return right after, and return TRUE (?) * if !ch */ void oprog_remove_trigger( CHAR_DATA *ch, OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & REMOVE_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_percent_check( REMOVE_PROG ); release_supermob(); } return; } /* * call in do_sac, right before extract_obj */ void oprog_sac_trigger( CHAR_DATA *ch, OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & SAC_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_percent_check( SAC_PROG ); release_supermob(); } return; } /* * call in do_get, right before check_for_trap * do a if(!ch) return right after */ void oprog_get_trigger( CHAR_DATA *ch, OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & GET_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_percent_check( GET_PROG ); release_supermob(); } return; } /* * called in damage_obj in act_obj.c */ void oprog_damage_trigger( CHAR_DATA *ch, OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & DAMAGE_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_percent_check( DAMAGE_PROG ); release_supermob(); } return; } /* * called in do_repair in shops.c */ void oprog_repair_trigger( CHAR_DATA *ch, OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & REPAIR_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_percent_check( REPAIR_PROG ); release_supermob(); } return; } /* * call twice in do_drop, right after the act( AT_ACTION,...) * do a if(!ch) return right after */ void oprog_drop_trigger( CHAR_DATA *ch, OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & DROP_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_percent_check( DROP_PROG ); release_supermob(); } return; } /* * call towards end of do_examine, right before check_for_trap */ void oprog_examine_trigger( CHAR_DATA *ch, OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & EXA_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_percent_check( EXA_PROG ); release_supermob(); } return; } /* * call in fight.c, group_gain, after (?) the obj_to_room */ void oprog_zap_trigger( CHAR_DATA *ch, OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & ZAP_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; mprog_percent_check( ZAP_PROG ); release_supermob(); } return; } /* void oprog_act_trigger( char *buf, OBJ_DATA *mobj, CHAR_DATA *ch, OBJ_DATA *obj, void *vo ) { if ( IS_NPC(ch) && ch->pIndexData == supermob->pIndexData ) return; */ /* prevent supermob from triggering itself */ /* if ( mobj->pIndexData->progtypes & ACT_PROG ) { MPROG_ACT_LIST *tmp_act; tmp_act = alloc_mem( sizeof(MPROG_ACT_LIST) ); if ( mobj->mpactnum > 0 ) tmp_act->next = mobj->mpact; else tmp_act->next = NULL; mobj->mpact = tmp_act; mobj->mpact->buf = str_dup(buf); mobj->mpact->ch = ch; mobj->mpact->obj = obj; mobj->mpact->vo = vo; mobj->mpactnum++; obj_act_add(mobj); } return; }*/ /* * call in fight.c, one_hit and second_one_hit at the end. */ void oprog_hit_trigger( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj ) { if ( obj->pIndexData->progtypes & HIT_PROG ) { set_supermob( obj, OBJ_PROG ); ProgSource = supermob; ProgTriggeredBy = ch; ProgObjectSource = obj; ProgVictim = victim; mprog_percent_check( HIT_PROG ); release_supermob(); } return; } /************************************************************************ * * * EVAL.C - A simple mathematical expression evaluator in C * * * * operators supported: Operator Precedence * * * * ( Lowest * * ) Highest * * + (addition) Low * * - (subtraction) Low * * * (multiplication) Medium * * / (division) Medium * * % (modulus) High * * ^ (exponentiation) High * * == Lowest * * != Lowest * * >= Lowest * * <= Lowest * * < Lowest * * > Lowest * * && Lowest * * || Lowest * * ! Lowest * * * * Original Copyright 1991-93 by Robert B. Stout as part of * * the MicroFirm Function Library (MFL) * * * * The user is granted a free limited license to use this source file * * to create royalty-free programs, subject to the terms of the * * license restrictions specified below. * * * ************************************************************************/ /*********************************************************************************** * * * Portions of SNIPPETS code are Copyright 1987-1996 by Robert B. Stout dba * * MicroFirm. The user is granted a free license to use these source files in * * any way except for commercial publication other than as part of your own * * program. This means you are explicitly granted the right to: * * * * 1. Use these files to create applications for any use, private or commercial, * * without any license fee. * * * * 2. Copy or otherwise publish copies of the source files so long as the * * original copyright notice is not removed and that such publication is * * free of any charges other than the costs of duplication and distribution. * * * * 3. Distribute modified versions of the source files so long as the original * * copyright notice is not removed, and that the modified nature is clearly * * noted in the source file, and that such distribution is free of any * * charges other than the costs of duplication and distribution. * * * * 4. Distribute object files and/or libraries compiled from the supplied * * source files, provided that such publication is free of any charges other * * than the costs of duplication and distribution. * * * * Rights reserved to the copyright holder include: * * * * 1. The right to publish these works commercially including, but not limited * * to, books, magazines, and commercial software libraries. * * * * 2. The commercial rights, as cited above, to all derivative source and/or * * object modules. Note that this explicitly grants to the user all rights, * * commercial or otherwise, to any and all executable programs created using * * MicroFirm copyrighted source or object files contained in SNIPPETS. * * * * Users are specifically prohibited from: * * * * 1. Removing the copyright notice and claiming the source files or any * * derivative works as their own. * * * * 2. Publishing the source files, the compiled object files, or libraries of * * the compiled object files commercially. * * * * In other words, you are free to use these files to make programs, not to make * * money! The programs you make with them, you may sell or give away as you * * like, but you many not sell either the source files or object files, alone * * or in a library, even if you've modified the original source, without a * * license from the copyright holder. * * * * * * Bob Stout * * FidoNet: 1:106/2000.6 * * C_Echo moderator (1990-1991, 1996-1997) * * Internet: rbs@snippets.org * * rbs@brokersys.com * * SnailMail: MicroFirm * * P.O. Box 428 * * Alief, TX 77411 * * * ***********************************************************************************/ struct operator_type { char token; char *tag; size_t taglen; int precedence; }; static struct operator_type verbs[] = { {'+', "+", 1, 2 }, {'-', "-", 1, 3 }, {'*', "*", 1, 4 }, {'/', "/", 1, 5 }, {'%', "%", 1, 5 }, {'^', "^", 1, 6 }, {'(', "(", 1, 0 }, {')', ")", 1, 99}, {'=', "==", 2, 0 }, {'\\', "!=", 2, 0 }, {'G', "<=", 2, 0 }, {'L', ">=", 2, 0 }, {'<', "<", 1, 0 }, {'>', ">", 1, 0 }, {'&', "&&", 2, 0 }, {'|', "||", 2, 0 }, {'!', "!", 1, 0 }, {0, 0, 0, 0 } }; static char op_stack[256]; /* Operator stack */ static double arg_stack[256]; /* Argument stack */ static char token[256]; /* Token buffer */ static int op_sptr, /* op_stack pointer */ arg_sptr, /* arg_stack pointer */ parens, /* Nesting level */ state; /* 0 = Awaiting expression 1 = Awaiting operator */ static int do_op(void); static int do_paren(void); static void push_op(char); static void push_arg(double); static int pop_arg(double *); static int pop_op(int *); static char *get_exp(char *); static struct operator_type *get_op(char *); static int getprec(char); static int getTOSprec(void); /************************************************************************/ /* */ /* evaluate() */ /* */ /* Evaluates an ASCII mathematical expression. */ /* */ /* Arguments: 1 - String to evaluate */ /* 2 - Storage to receive double result */ /* */ /* Returns: Success_ if successful */ /* Error_ if syntax error */ /* R_ERROR if runtime error */ /* */ /* Side effects: Removes all whitespace from the string and converts */ /* it to U.C. */ /* */ /************************************************************************/ int evaluate(char *line, double *val) { double arg; char *ptr = line, *str, *endptr; int ercode; struct operator_type *op; str_upr(line); state = op_sptr = arg_sptr = parens = 0; while (*ptr) { switch (state) { case 0: if (NULL != (str = get_exp(ptr))) { if (NULL != (op = get_op(str)) && strlen(str) == op->taglen) { push_op(op->token); ptr += op->taglen; break; } if (Success_ == strcmp(str, "-")) { push_op(*str); ++ptr; break; } else { if (0.0 == (arg = strtod(str, &endptr)) && NULL == strchr(str, '0')) { return Error_; } push_arg(arg); } ptr += strlen(str); } else return Error_; state = 1; break; case 1: if (NULL != (op = get_op(ptr))) { if (')' == *ptr) { if (Success_ > (ercode = do_paren())) return ercode; } else { while (op_sptr && op->precedence <= getTOSprec()) { do_op(); } push_op(op->token); state = 0; } ptr += op->taglen; } else return Error_; break; } } while (1 < arg_sptr) { if (Success_ > (ercode = do_op())) return ercode; } if (!op_sptr) return pop_arg(val); else if ( op_sptr == 1 && op_stack[0] == '!' ) { if (Success_ > (ercode = do_op())) return ercode; else { pop_arg(val); return Success_; } } else return Error_; } /* ** Evaluate stacked arguments and operands */ static int do_op(void) { double arg1, arg2; int op; if (Error_ == pop_op(&op)) return Error_; pop_arg(&arg1); pop_arg(&arg2); switch (op) { case '+': push_arg(arg2 + arg1); break; case '-': push_arg(arg2 - arg1); break; case '*': push_arg(arg2 * arg1); break; case '/': if (0.0 == arg1) return R_ERROR; push_arg(arg2 / arg1); break; case '%': if (0.0 == arg1) return R_ERROR; push_arg(fmod(arg2, arg1)); break; case '^': push_arg(pow(arg2, arg1)); break; case 'G': push_arg(arg2 <= arg1); break; case 'L': push_arg(arg2 >= arg1); break; case '=': push_arg(arg2 == arg1); break; case '\\': push_arg(arg2 != arg1); break; case '<': push_arg(arg2 < arg1); break; case '>': push_arg(arg2 > arg1); break; case '&': push_arg(arg2 && arg1); break; case '|': push_arg(arg2 || arg1); break; case '!': arg_sptr++; push_arg(!arg1); break; case '(': arg_sptr += 2; break; default: return Error_; } if (1 > arg_sptr) return Error_; else return op; } /* ** Evaluate one level */ static int do_paren(void) { int op; if (1 > parens--) return Error_; do { if (Success_ > (op = do_op())) break; } while (getprec((char)op)); return op; } /* ** Stack operations */ static void push_op(char op) { if (!getprec(op)) ++parens; op_stack[op_sptr++] = op; } static void push_arg(double arg) { arg_stack[arg_sptr++] = arg; } static int pop_arg(double *arg) { *arg = arg_stack[--arg_sptr]; if (0 > arg_sptr) return Error_; else return Success_; } static int pop_op(int *op) { if (!op_sptr && op_stack[0] != '!') return Error_; *op = op_stack[--op_sptr]; return Success_; } /* ** Get an expression */ static char * get_exp(char *str) { char *ptr = str, *tptr = token; struct operator_type *op; while (*ptr) { if (NULL != (op = get_op(ptr))) { if ('-' == *ptr) { if (str == ptr && !isdigit(ptr[1]) && '.' != ptr[1]) { push_arg(0.0); strcpy(token, op->tag); return token; } } else if (str == ptr) { strcpy(token, op->tag); return token; } else break; } *tptr++ = *ptr++; } *tptr = 0; return token; } /* ** Get an operator */ static struct operator_type * get_op(char *str) { struct operator_type *op; for (op = verbs; op->token; ++op) { if (!strncmp(str, op->tag, op->taglen)) return op; } return NULL; } /* ** Get precedence of a token */ static int getprec(char token) { struct operator_type *op; for (op = verbs; op->token; ++op) { if (token == op->token) break; } if (op->token) return op->precedence; else return 0; } /* ** Get precedence of TOS token */ static int getTOSprec(void) { if (!op_sptr) return 0; return getprec(op_stack[op_sptr - 1]); }