/*************************************************************************** * 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. * ***************************************************************************/ /*************************************************************************** * The MOBprograms have been contributed by N'Atas-ha. Any support for * * these routines should not be expected from Merc Industries. However, * * under no circumstances should the blame for bugs, etc be placed on * * Merc Industries. They are not guaranteed to work on all systems due * * to their frequent use of strxxx functions. They are also not the most * * efficient way to perform their tasks, but hopefully should be in the * * easiest possible way to install and begin using. Documentation for * * such installation can be found in INSTALL. Enjoy... N'Atas-Ha * ***************************************************************************/ /*************************************************************************** * Heavy modifications were made to Mobprogs (now MudProgs) by Thanatos, * * Zak and Zane * ***************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include "merc.h" #include "interp.h" /* * Local function prototypes */ char * mprog_next_command args( ( char* clist ) ); bool mprog_seval args( ( char* lhs, char* opr, char* rhs ) ); bool mprog_veval args( ( int lhs, char* opr, int rhs ) ); long mprog_do_ifchck args( ( char* ifchck, CHAR_DATA* mob, CHAR_DATA* actor, OBJ_DATA* obj, void* vo, CHAR_DATA* rndm, CHAR_DATA* evil ) ); char * mprog_process_if args( ( char* ifchck, char* com_list, CHAR_DATA* mob, CHAR_DATA* actor, OBJ_DATA* obj, void* vo, CHAR_DATA* rndm, CHAR_DATA *evil ) ); void mprog_translate args( ( char ch, char* t, CHAR_DATA* mob, CHAR_DATA* actor, OBJ_DATA* obj, void* vo, CHAR_DATA* rndm, CHAR_DATA *evil ) ); void mprog_process_cmnd args( ( char* cmnd, CHAR_DATA* mob, CHAR_DATA* actor, OBJ_DATA* obj, void* vo, CHAR_DATA* rndm, CHAR_DATA *evil ) ); void mprog_driver args( ( char* com_list, CHAR_DATA* mob, CHAR_DATA* actor, OBJ_DATA* obj, void* vo ) ); void set_supermob args( ( void *source, int prog_type ) ); void release_supermob args( ( void ) ); void room_act_add args( ( ROOM_INDEX_DATA *room ) ); /* * Structure needed to efficiently handle room and object act * triggers. */ struct act_prog_data { struct act_prog_data *next; void *vo; }; CHAR_DATA *supermob; struct act_prog_data *room_act_list; struct act_prog_data *obj_act_list; /*************************************************************************** * Local function code and brief comments. */ /* if you dont have these functions, you damn well should... */ #ifdef DUNNO_STRSTR char * strstr(s1,s2) const char *s1; const char *s2; { char *cp; int i,j=strlen(s1)-strlen(s2),k=strlen(s2); if(j<0) return NULL; for(i=0; i<=j && strncmp(s1++,s2, k)!=0; i++); return (i>j) ? NULL : (s1-1); } #endif /* Used to get sequential lines of a multi line string (separated by "\n\r") * Thus its like one_argument(), but a trifle different. It is destructive * to the multi line string argument, and thus clist must not be shared. */ char *mprog_next_command( char *clist ) { char *pointer = clist; if ( !pointer ) return NULL; while ( *pointer != '\n' && *pointer != '\r' && *pointer != '\0' ) pointer++; /* Strip \n\r and/or \r\n */ if ( *pointer == '\n' ) *pointer++ = '\0'; else if ( *pointer == '\r' ) *pointer++ = '\0'; if ( *pointer == '\n' ) *pointer++ = '\0'; else if ( *pointer == '\r' ) *pointer++ = '\0'; return ( pointer ); } /* These two functions do the basic evaluation of ifcheck operators. * It is important to note that the string operations are not what * you probably expect. Equality is exact and division is substring. * remember that lhs has been stripped of leading space, but can * still have trailing spaces so be careful when editing since: * "guard" and "guard " are not equal. */ bool mprog_seval( char *lhs, char *opr, char *rhs ) { if ( !str_cmp( opr, "==" ) ) return ( bool )( !str_cmp( lhs, rhs ) ); if ( !str_cmp( opr, "!=" ) ) return ( bool )( str_cmp( lhs, rhs ) ); if ( !str_cmp( opr, "/" ) ) return ( bool )( !str_infix( rhs, lhs ) ); if ( !str_cmp( opr, "!/" ) ) return ( bool )( str_infix( rhs, lhs ) ); bug ( "Improper MudProg operator\n\r", 0 ); return 0; } bool mprog_veval( int lhs, char *opr, int rhs ) { if ( !str_cmp( opr, "==" ) ) return ( lhs == rhs ); if ( !str_cmp( opr, "!=" ) ) return ( lhs != rhs ); if ( !str_cmp( opr, ">" ) ) return ( lhs > rhs ); if ( !str_cmp( opr, "<" ) ) return ( lhs < rhs ); if ( !str_cmp( opr, "<=" ) ) return ( lhs <= rhs ); if ( !str_cmp( opr, ">=" ) ) return ( lhs >= rhs ); if ( !str_cmp( opr, "&" ) ) return ( lhs & rhs ); if ( !str_cmp( opr, "|" ) ) return ( lhs | rhs ); bug ( "Improper MudProg operator\n\r", 0 ); return 0; } /* This function performs the evaluation of the if checks. It is * here that you can add any ifchecks which you so desire. Hopefully * it is clear from what follows how one would go about adding your * own. The syntax for an if check is: ifchck ( arg ) [opr val] * where the parenthesis are required and the opr and val fields are * optional but if one is there then both must be. The spaces are all * optional. The evaluation of the opr expressions is farmed out * to reduce the redundancy of the mammoth if statement list. * If there are errors, then return -1 otherwise return boolean 1,0 */ long mprog_do_ifchck( char *ifchck, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm, CHAR_DATA *evil) { char buf[ MAX_INPUT_LENGTH ]; char arg[ MAX_INPUT_LENGTH ]; char opr[ MAX_INPUT_LENGTH ]; char val[ MAX_INPUT_LENGTH ]; CHAR_DATA *pMob; CHAR_DATA *vict = (CHAR_DATA *) vo; OBJ_DATA *v_obj = (OBJ_DATA *) vo; char *bufpt = buf; char *argpt = arg; char *oprpt = opr; char *valpt = val; char *point = ifchck; int lhsvl; int rhsvl; if ( *point == '\0' ) { bug ( "Mob: %d null ifchck", mob->pIndexData->vnum ); return -1; } /* skip leading spaces */ while ( *point == ' ' ) point++; /* get whatever comes before the left paren.. ignore spaces */ while ( *point != '(' ) if ( *point == '\0' ) { bug ( "Mob: %d ifchck syntax error", mob->pIndexData->vnum ); return -1; } else if ( *point == ' ' ) point++; else *bufpt++ = *point++; *bufpt = '\0'; point++; /* get whatever is in between the parens.. ignore spaces */ while ( *point != ')' ) if ( *point == '\0' ) { bug ( "Mob: %d ifchck syntax error", mob->pIndexData->vnum ); return -1; } else if ( *point == ' ' ) point++; else *argpt++ = *point++; *argpt = '\0'; point++; /* check to see if there is an operator */ while ( *point == ' ' ) point++; if ( *point == '\0' ) { *opr = '\0'; *val = '\0'; } else /* there should be an operator and value, so get them */ { while ( ( *point != ' ' ) && ( !isalnum( *point ) ) ) if ( *point == '\0' ) { bug ( "Mob: %d ifchck operator without value", mob->pIndexData->vnum ); return -1; } else *oprpt++ = *point++; *oprpt = '\0'; /* finished with operator, skip spaces and then get the value */ while ( *point == ' ' ) point++; for( ; ; ) { if ( ( *point != ' ' ) && ( *point == '\0' ) ) break; else *valpt++ = *point++; } *valpt = '\0'; } bufpt = buf; argpt = arg; oprpt = opr; valpt = val; /* Ok... now buf contains the ifchck, arg contains the inside of the * parentheses, opr contains an operator if one is present, and val * has the value if an operator was present. * So.. basically use if statements and run over all known ifchecks * Once inside, use the argument and expand the lhs. Then if need be * send the lhs,opr,rhs off to be evaluated. */ if ( !str_cmp( buf, "memory" ) ) { /* if memory() returns TRUE if anything is in memory */ /* if memory() == $* returns TRUE if memory ==,!=,/,!/ $* */ if ( mob->memory == NULL ) return FALSE; else if (get_char_world(mob,mob->memory->name) == NULL) return FALSE; if (opr[0]=='\0') return TRUE; if (val[0]=='$') switch (val[1]) { case 'i': return FALSE; /* can't remember myself */ case 'n': if (actor) return mprog_seval(actor->name,opr,mob->memory->name); else return -1; case 't': if (vict) return mprog_seval(vict->name,opr,mob->memory->name); else return -1; case 'r': if (rndm) return mprog_seval(rndm->name,opr,mob->memory->name); else return -1; case 'x': if (evil) return mprog_seval(evil->name,opr,mob->memory->name); else return -1; default : bug("Mob: %d bad val for 'if memory'",mob->pIndexData->vnum); return -1; } return mprog_seval(val,opr,mob->memory->name); } if ( !str_cmp( buf, "rand" ) ) { return ( number_percent() <= atoi(arg) ); } if ( !str_cmp(buf, "getrand" ) ) { lhsvl = number_range(1, atoi(arg)); if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } if ( !str_cmp(buf, "fightinroom" ) ) { for (pMob = mob->in_room->people; pMob && !pMob->fighting; pMob = pMob->next_in_room) ; if ( pMob ) lhsvl = 1; else lhsvl = 0; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } if ( !str_cmp(buf, "hour" ) ) { lhsvl = time_info.hour; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } if ( !str_cmp( buf, "ispc" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': return 0; case 'n': if ( actor ) return ( !IS_NPC( actor ) ); else return -1; case 't': if ( vict ) return ( !IS_NPC( vict ) ); else return -1; case 'r': if ( rndm ) return ( !IS_NPC( rndm ) ); else return -1; case 'x': if ( evil ) return ( !IS_NPC( evil ) ); else return -1; default: bug ( "Mob: %d bad argument to 'ispc'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "isnpc" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': return 1; case 'n': if ( actor ) return IS_NPC( actor ); else return -1; case 't': if ( vict ) return IS_NPC( vict ); else return -1; case 'r': if ( rndm ) return IS_NPC( rndm ); else return -1; case 'x': if ( evil ) return IS_NPC( evil ); else return -1; default: bug ("Mob: %d bad argument to 'isnpc'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "isgood" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': return IS_GOOD( mob ); case 'n': if ( actor ) return IS_GOOD( actor ); else return -1; case 't': if ( vict ) return IS_GOOD( vict ); else return -1; case 'r': if ( rndm ) return IS_GOOD( rndm ); else return -1; case 'x': if ( evil ) return IS_GOOD( evil ); else return -1; default: bug ( "Mob: %d bad argument to 'isgood'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "isfight" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': return ( mob->fighting ) ? 1 : 0; case 'n': if ( actor ) return ( actor->fighting ) ? 1 : 0; else return -1; case 't': if ( vict ) return ( vict->fighting ) ? 1 : 0; else return -1; case 'r': if ( rndm ) return ( rndm->fighting ) ? 1 : 0; else return -1; case 'x': if ( evil ) return ( evil->fighting ) ? 1 : 0; else return -1; default: bug ( "Mob: %d bad argument to 'isfight'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "isimmort" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': return ( get_trust( mob ) > LEVEL_IMMORTAL ); case 'n': if ( actor ) return ( get_trust( actor ) > LEVEL_IMMORTAL ); else return -1; case 't': if ( vict ) return ( get_trust( vict ) > LEVEL_IMMORTAL ); else return -1; case 'r': if ( rndm ) return ( get_trust( rndm ) > LEVEL_IMMORTAL ); else return -1; case 'x': if ( evil ) return ( get_trust( evil ) > LEVEL_IMMORTAL ); else return -1; default: bug ( "Mob: %d bad argument to 'isimmort'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "ischarmed" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': return IS_SET( mob->affected_by , AFF_CHARM ); case 'n': if ( actor ) return IS_AFFECTED( actor, AFF_CHARM ); else return -1; case 't': if ( vict ) return IS_AFFECTED( vict, AFF_CHARM ); else return -1; case 'r': if ( rndm ) return IS_AFFECTED( rndm, AFF_CHARM ); else return -1; case 'x': if ( evil ) return IS_AFFECTED( evil, AFF_CHARM ); else return -1; default: bug ( "Mob: %d bad argument to 'ischarmed'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "isfollow" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': return ( mob->master != NULL && mob->master->in_room == mob->in_room ); case 'n': if ( actor ) return ( actor->master != NULL && actor->master->in_room == actor->in_room ); else return -1; case 't': if ( vict ) return ( vict->master != NULL && vict->master->in_room == vict->in_room ); else return -1; case 'r': if ( rndm ) return ( rndm->master != NULL && rndm->master->in_room == rndm->in_room ); else return -1; case 'x': if ( evil ) return ( evil->master != NULL && evil->master->in_room == evil->in_room ); else return -1; default: bug ( "Mob: %d bad argument to 'isfollow'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "isaffected" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': return ( mob->affected_by & atoi( arg ) ); case 'n': if ( actor ) return ( actor->affected_by & atoi( arg ) ); else return -1; case 't': if ( vict ) return ( vict->affected_by & atoi( arg ) ); else return -1; case 'r': if ( rndm ) return ( rndm->affected_by & atoi( arg ) ); else return -1; case 'x': if ( evil ) return ( evil->affected_by & atoi( arg ) ); else return -1; default: bug ( "Mob: %d bad argument to 'isaffected'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "hitprcnt" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = mob->hit / mob->max_hit; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { lhsvl = actor->hit / actor->max_hit; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 't': if ( vict ) { lhsvl = vict->hit / vict->max_hit; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'r': if ( rndm ) { lhsvl = rndm->hit / rndm->max_hit; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'x': if ( evil ) { lhsvl = evil->hit / evil->max_hit; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'hitprcnt'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "inroom" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = mob->in_room->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { lhsvl = actor->in_room->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 't': if ( vict ) { lhsvl = vict->in_room->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'r': if ( rndm ) { lhsvl = rndm->in_room->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'x': if ( evil ) { lhsvl = evil->in_room->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'inroom'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "crimethief" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = IS_SET(mob->act, PLR_THIEF); if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { lhsvl = IS_SET(actor->act, PLR_THIEF); if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 't': if ( vict ) { lhsvl = IS_SET(vict->act, PLR_THIEF); if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'r': if ( rndm ) { lhsvl = IS_SET(rndm->act, PLR_THIEF); if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'x': if ( evil ) { lhsvl = IS_SET(evil->act, PLR_THIEF); if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'inroom'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "alignment" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = mob->alignment; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { lhsvl = actor->alignment; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 't': if ( vict ) { lhsvl = vict->alignment; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'r': if ( rndm ) { lhsvl = rndm->alignment; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'x': if ( evil ) { lhsvl = evil->alignment; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'alignment'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "sex" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = mob->sex; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { lhsvl = actor->sex; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 't': if ( vict ) { lhsvl = vict->sex; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'r': if ( rndm ) { lhsvl = rndm->sex; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'x': if ( evil ) { lhsvl = evil->sex; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'sex'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "position" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = mob->position; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { lhsvl = actor->position; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 't': if ( vict ) { lhsvl = vict->position; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'r': if ( rndm ) { lhsvl = rndm->position; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'x': if ( evil ) { lhsvl = evil->position; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'position'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "level" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = get_trust( mob ); if ( *opr == '\0' ) { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { lhsvl = get_trust( actor ); if ( *opr == '\0' ) { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 't': if ( vict ) { lhsvl = get_trust( vict ); if ( *opr == '\0' ) { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'r': if ( rndm ) { lhsvl = get_trust( rndm ); if ( *opr == '\0' ) { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'x': if ( evil ) { lhsvl = get_trust( evil ); if ( *opr == '\0' ) { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'level'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "immune" ) ) { if ( !obj ) return FALSE; switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = check_immune( mob, attack_table[obj->value[3]].damage ); if ( *opr == '\0' ) { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { lhsvl = check_immune( actor, attack_table[obj->value[3]].damage ); if ( *opr == '\0' ) { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'r': if ( rndm ) { lhsvl = check_immune( rndm, attack_table[obj->value[3]].damage ); if ( *opr == '\0' ) { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'x': if ( evil ) { lhsvl = check_immune( evil, attack_table[obj->value[3]].damage ); if ( *opr == '\0' ) { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 't': if ( vict ) { lhsvl = check_immune( vict, attack_table[obj->value[3]].damage ); if ( *opr == '\0' ) { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'immune'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "class" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = mob->Class; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { lhsvl = actor->Class; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 't': if ( vict ) { lhsvl = vict->Class; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'r': if ( rndm ) { lhsvl = rndm->Class; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'x': if ( evil ) { lhsvl = evil->Class; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'class'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "goldamt" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = mob->gold; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { lhsvl = actor->gold; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 't': if ( vict ) { lhsvl = vict->gold; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'r': if ( rndm ) { lhsvl = rndm->gold; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'x': if ( evil ) { lhsvl = evil->gold; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'goldamt'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "objtype" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'o': if ( obj ) { lhsvl = obj->item_type; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'p': if ( v_obj ) { lhsvl = v_obj->item_type; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'objtype'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "objval0" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'o': if ( obj ) { lhsvl = obj->value[0]; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'p': if ( v_obj ) { lhsvl = v_obj->value[0]; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'objval0'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "objval1" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'o': if ( obj ) { lhsvl = obj->value[1]; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'p': if ( v_obj ) { lhsvl = v_obj->value[1]; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'objval1'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "objval2" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'o': if ( obj ) { lhsvl = obj->value[2]; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'p': if ( v_obj ) { lhsvl = v_obj->value[2]; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'objval2'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "objval3" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'o': if ( obj ) { lhsvl = obj->value[3]; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'p': if ( v_obj ) { lhsvl = v_obj->value[3]; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'objval3'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "number" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': lhsvl = mob->gold; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } case 'n': if ( actor ) { if IS_NPC( actor ) { lhsvl = actor->pIndexData->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } } else return -1; case 't': if ( vict ) { if IS_NPC( actor ) { lhsvl = vict->pIndexData->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } } else return -1; case 'r': if ( rndm ) { if IS_NPC( actor ) { lhsvl = rndm->pIndexData->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } } else return -1; case 'x': if ( evil ) { if IS_NPC( actor ) { lhsvl = evil->pIndexData->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } } else return -1; case 'o': if ( obj ) { lhsvl = obj->pIndexData->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; case 'p': if ( v_obj ) { lhsvl = v_obj->pIndexData->vnum; if (*opr == '\0') { return lhsvl; } else { if ( strstr(val, "(") ) { rhsvl = mprog_do_ifchck(val, mob, actor, obj, vo, rndm, evil); } else { rhsvl = atoi( val ); } return mprog_veval( lhsvl, opr, rhsvl ); } } else return -1; default: bug ( "Mob: %d bad argument to 'number'", mob->pIndexData->vnum ); return -1; } } if ( !str_cmp( buf, "name" ) ) { switch ( arg[1] ) /* arg should be "$*" so just get the letter */ { case 'i': return mprog_seval( mob->name, opr, val ); case 'n': if ( actor ) return mprog_seval( actor->name, opr, val ); else return -1; case 't': if ( vict ) return mprog_seval( vict->name, opr, val ); else return -1; case 'r': if ( rndm ) return mprog_seval( rndm->name, opr, val ); else return -1; case 'x': if ( evil ) return mprog_seval( evil->name, opr, val ); else return -1; case 'o': if ( obj ) return mprog_seval( obj->name, opr, val ); else return -1; case 'p': if ( v_obj ) return mprog_seval( v_obj->name, opr, val ); else return -1; default: bug ( "Mob: %d bad argument to 'name'", mob->pIndexData->vnum ); return -1; } } /* Ok... all the ifchcks are done, so if we didnt find ours then something * odd happened. So report the bug and abort the MudProg (return error) */ bug ( "Mob: %d unknown ifchck = %s", mob->pIndexData->vnum, buf ); return -1; } /* Quite a long and arduous function, this guy handles the control * flow part of MudProgs. Basicially once the driver sees an * 'if' attention shifts to here. While many syntax errors are * caught, some will still get through due to the handling of break * and errors in the same fashion. The desire to break out of the * recursion without catastrophe in the event of a mis-parse was * believed to be high. Thus, if an error is found, it is bugged and * the parser acts as though a break were issued and just bails out * at that point. I havent tested all the possibilites, so I'm speaking * in theory, but it is 'guaranteed' to work on syntactically correct * MudProgs, so if the mud crashes here, check the mob carefully! */ char *mprog_process_if( char *ifchck, char *com_list, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm, CHAR_DATA *evil ) { char null[ 1 ]; char buf[ MAX_INPUT_LENGTH ]; char *morebuf = '\0'; char *cmnd = '\0'; bool loopdone = FALSE; bool flag = FALSE; long legal; *null = '\0'; /* check for trueness of the ifcheck */ if ( ( legal = mprog_do_ifchck( ifchck, mob, actor, obj, vo, rndm, evil ) ) ) if ( legal == 1 ) flag = TRUE; else return '\0'; while( loopdone == FALSE ) /*scan over any existing or statements */ { cmnd = com_list; com_list = mprog_next_command( com_list ); while ( *cmnd == ' ' ) cmnd++; if ( *cmnd == '\0' ) { bug ( "Mob: %d no commands after IF/OR/AND", mob->pIndexData->vnum ); return '\0'; } morebuf = one_argument( cmnd, buf ); if ( !str_cmp( buf, "or" ) ) { if ( ( legal = mprog_do_ifchck( morebuf,mob,actor,obj,vo,rndm, evil ) ) ) if ( legal == 1 ) flag = TRUE; else return '\0'; } else if ( !str_cmp( buf, "and" ) ) { if ( ( legal = mprog_do_ifchck( morebuf,mob,actor,obj,vo,rndm, evil ) ) ) if ( legal == 1 ) flag = flag && TRUE; else return '\0'; } else loopdone = TRUE; } if ( flag ) for ( ; ; ) /*ifcheck was true, do commands but ignore else to endif*/ { if ( !str_cmp( buf, "if" ) ) { com_list = mprog_process_if(morebuf,com_list,mob,actor,obj,vo,rndm,evil); while ( *cmnd==' ' ) cmnd++; if ( *com_list == '\0' ) return '\0'; cmnd = com_list; com_list = mprog_next_command( com_list ); morebuf = one_argument( cmnd,buf ); continue; } if ( !str_cmp( buf, "break" ) ) return '\0'; if ( !str_cmp( buf, "endif" ) ) return com_list; if ( !str_cmp( buf, "else" ) ) { while ( str_cmp( buf, "endif" ) ) { cmnd = com_list; com_list = mprog_next_command( com_list ); while ( *cmnd == ' ' ) cmnd++; if ( *cmnd == '\0' ) { bug ( "Mob: %d missing endif after else", mob->pIndexData->vnum ); return '\0'; } morebuf = one_argument( cmnd,buf ); } return com_list; } mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm, evil ); cmnd = com_list; com_list = mprog_next_command( com_list ); while ( *cmnd == ' ' ) cmnd++; if ( *cmnd == '\0' ) { bug ( "Mob: %d missing else or endif", mob->pIndexData->vnum ); return '\0'; } morebuf = one_argument( cmnd, buf ); } else /*false ifcheck, find else and do existing commands or quit at endif*/ { while ( ( str_cmp( buf, "else" ) ) && ( str_cmp( buf, "endif" ) ) ) { cmnd = com_list; com_list = mprog_next_command( com_list ); while ( *cmnd == ' ' ) cmnd++; if ( *cmnd == '\0' ) { bug ( "Mob: %d missing an else or endif", mob->pIndexData->vnum ); return '\0'; } morebuf = one_argument( cmnd, buf ); } /* found either an else or an endif.. act accordingly */ if ( !str_cmp( buf, "endif" ) ) return com_list; cmnd = com_list; com_list = mprog_next_command( com_list ); while ( *cmnd == ' ' ) cmnd++; if ( *cmnd == '\0' ) { bug ( "Mob: %d missing endif", mob->pIndexData->vnum ); return '\0'; } morebuf = one_argument( cmnd, buf ); for ( ; ; ) /*process the post-else commands until an endif is found.*/ { if ( !str_cmp( buf, "if" ) ) { com_list = mprog_process_if( morebuf, com_list, mob, actor, obj, vo, rndm, evil ); while ( *cmnd == ' ' ) cmnd++; if ( *com_list == '\0' ) return '\0'; cmnd = com_list; com_list = mprog_next_command( com_list ); morebuf = one_argument( cmnd,buf ); continue; } if ( !str_cmp( buf, "else" ) ) { bug ( "Mob: %d found else in an else section", mob->pIndexData->vnum ); return '\0'; } if ( !str_cmp( buf, "break" ) ) return '\0'; if ( !str_cmp( buf, "endif" ) ) return com_list; mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm, evil ); cmnd = com_list; com_list = mprog_next_command( com_list ); while ( *cmnd == ' ' ) cmnd++; if ( *cmnd == '\0' ) { bug ( "Mob:%d missing endif in else section", mob->pIndexData->vnum ); return '\0'; } morebuf = one_argument( cmnd, buf ); } } } /* This routine handles the variables for command expansion. * If you want to add any go right ahead, it should be fairly * clear how it is done and they are quite easy to do, so you * can be as creative as you want. The only catch is to check * that your variables exist before you use them. At the moment, * using $t when the secondary target refers to an object * i.e. >prog_act drops~<nl>if ispc($t)<nl>sigh<nl>endif<nl>~<nl> * probably makes the mud crash (vice versa as well) The cure * would be to change act() so that vo becomes vict & v_obj. * but this would require a lot of small changes all over the code. */ void mprog_translate( char ch, char *t, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm, CHAR_DATA *evil ) { static char *he_she [] = { "it", "he", "she" }; static char *him_her [] = { "it", "him", "her" }; static char *his_her [] = { "its", "his", "her" }; CHAR_DATA *vict = (CHAR_DATA *) vo; OBJ_DATA *v_obj = (OBJ_DATA *) vo; *t = '\0'; switch ( ch ) { /* * Mob that has the mob prog */ case 'i': one_argument( mob->name, t ); break; case 'I': strcpy( t, mob->short_descr ); break; /* * char that triggered the mob prog */ case 'n': if ( actor ) { if ( can_see( mob,actor ) ) one_argument( actor->name, t ); if ( !IS_NPC( actor ) ) *t = UPPER( *t ); } else { bug( "Mprog_Translate: case 'n', NULL actor" ); strcpy( t, "someone" ); } break; case 'N': if ( actor ) if ( can_see( mob, actor ) ) if ( IS_NPC( actor ) ) strcpy( t, actor->short_descr ); else { strcpy( t, actor->name ); strcat( t, " " ); strcat( t, actor->pcdata->title ); } else strcpy( t, "someone" ); break; /* * used for victim */ case 't': if ( vict ) { if ( can_see( mob, vict ) ) one_argument( vict->name, t ); if ( !IS_NPC( vict ) ) *t = UPPER( *t ); } else { strcpy( t, "someone" ); } break; case 'T': if ( vict ) if ( can_see( mob, vict ) ) if ( IS_NPC( vict ) ) strcpy( t, vict->short_descr ); else { strcpy( t, vict->name ); strcat( t, " " ); strcat( t, vict->pcdata->title ); } else strcpy( t, "someone" ); break; case 'r': if ( rndm ) { if ( can_see( mob, rndm ) ) one_argument( rndm->name, t ); if ( !IS_NPC( rndm ) ) *t = UPPER( *t ); } else strcpy( t, "someone" ); break; case 'R': if ( rndm ) if ( can_see( mob, rndm ) ) if ( IS_NPC( rndm ) ) strcpy(t,rndm->short_descr); else { strcpy( t, rndm->name ); strcat( t, " " ); strcat( t, rndm->pcdata->title ); } else strcpy( t, "someone" ); break; case 'x': if ( evil ) { if ( can_see( mob, evil ) ) one_argument( evil->name, t ); if ( !IS_NPC( evil ) ) *t = UPPER( *t ); } else strcpy( t, "someone" ); break; case 'X': if ( evil ) if ( can_see( mob, evil ) ) if ( IS_NPC( evil ) ) strcpy(t,evil->short_descr); else { strcpy( t, evil->name ); strcat( t, " " ); strcat( t, evil->pcdata->title ); } else strcpy( t, "someone" ); break; case 'e': if ( actor ) can_see( mob, actor ) ? strcpy( t, he_she[ actor->sex ] ) : strcpy( t, "someone" ); break; case 'm': if ( actor ) can_see( mob, actor ) ? strcpy( t, him_her[ actor->sex ] ) : strcpy( t, "someone" ); break; case 's': if ( actor ) can_see( mob, actor ) ? strcpy( t, his_her[ actor->sex ] ) : strcpy( t, "someone's" ); break; case 'E': if ( vict ) can_see( mob, vict ) ? strcpy( t, he_she[ vict->sex ] ) : strcpy( t, "someone" ); break; case 'M': if ( vict ) can_see( mob, vict ) ? strcpy( t, him_her[ vict->sex ] ) : strcpy( t, "someone" ); break; case 'S': if ( vict ) can_see( mob, vict ) ? strcpy( t, his_her[ vict->sex ] ) : strcpy( t, "someone's" ); break; case 'j': strcpy( t, he_she[ mob->sex ] ); break; case 'k': strcpy( t, him_her[ mob->sex ] ); break; case 'l': strcpy( t, his_her[ mob->sex ] ); break; case 'J': if ( rndm ) can_see( mob, rndm ) ? strcpy( t, he_she[ rndm->sex ] ) : strcpy( t, "someone" ); break; case 'K': if ( rndm ) can_see( mob, rndm ) ? strcpy( t, him_her[ rndm->sex ] ) : strcpy( t, "someone" ); break; case 'L': if ( rndm ) can_see( mob, rndm ) ? strcpy( t, his_her[ rndm->sex ] ) : strcpy( t, "someone's" ); break; case 'o': if ( obj ) can_see_obj( mob, obj ) ? one_argument( obj->name, t ) : strcpy( t, "something" ); break; case 'O': if ( obj ) can_see_obj( mob, obj ) ? strcpy( t, obj->short_descr ) : strcpy( t, "something" ); break; case 'p': if ( v_obj ) can_see_obj( mob, v_obj ) ? one_argument( v_obj->name, t ) : strcpy( t, "something" ); break; case 'P': if ( v_obj ) can_see_obj( mob, v_obj ) ? strcpy( t, v_obj->short_descr ) : strcpy( t, "something" ); break; case 'a': if ( obj ) switch ( *( obj->name ) ) { case 'a': case 'e': case 'i': case 'o': case 'u': strcpy( t, "an" ); break; default: strcpy( t, "a" ); } break; case 'A': if ( v_obj ) switch ( *( v_obj->name ) ) { case 'a': case 'e': case 'i': case 'o': case 'u': strcpy( t, "an" ); break; default: strcpy( t, "a" ); } break; case '$': strcpy( t, "$" ); break; default: bug( "Mob: %d bad $var", mob->pIndexData->vnum ); break; } return; } /* This procedure simply copies the cmnd to a buffer while expanding * any variables by calling the translate procedure. The observant * code scrutinizer will notice that this is taken from act() */ void mprog_process_cmnd( char *cmnd, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm, CHAR_DATA *evil ) { char buf[ MAX_INPUT_LENGTH ]; char tmp[ MAX_INPUT_LENGTH ]; char *str; char *i; char *point; point = buf; str = cmnd; while ( *str != '\0' ) { if ( *str != '$' ) { if ( *str == '\r' ) str++; else *point++ = *str++; continue; } str++; mprog_translate( *str, tmp, mob, actor, obj, vo, rndm, evil ); i = tmp; ++str; while ( ( *point = *i ) != '\0' ) ++point, ++i; } *point = '\0'; interpret( mob, buf ); return; } /* The main focus of the MudProgs. This routine is called * whenever a trigger is successful. It is responsible for parsing * the command list and figuring out what to do. However, like all * complex procedures, everything is farmed out to the other guys. */ void mprog_driver ( char *com_list, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo) { char tmpcmndlst[ MAX_STRING_LENGTH ]; char buf [ MAX_INPUT_LENGTH ]; char *morebuf; char *command_list; char *cmnd; CHAR_DATA *rndm = NULL; CHAR_DATA *vch = NULL; CHAR_DATA *evil = NULL; int count = 0; int max_evil = 999999; if ( !mob ) { bug( "MPDriver: NULL mob!" ); return; } if IS_AFFECTED( mob, AFF_CHARM ) return; /* get a random visable mortal player who is in the room with the mob */ for ( vch = mob->in_room->people; vch; vch = vch->next_in_room ) if ( !IS_NPC( vch ) && can_see( mob, vch ) ) { if ( number_range( 0, count ) == 0 ) rndm = vch; count++; } /* get the most evil visable mortal player who is in the room with the mob and is fighting */ for ( vch = mob->in_room->people; vch; vch = vch->next_in_room ) if ( !IS_NPC( vch ) && can_see( mob, vch ) ) { if ( vch->fighting && vch->alignment < max_evil ) { max_evil = vch->alignment; evil = vch; } } strcpy( tmpcmndlst, com_list ); command_list = tmpcmndlst; cmnd = command_list; command_list = mprog_next_command( command_list ); while ( cmnd && *cmnd ) { morebuf = one_argument( cmnd, buf ); if ( !str_cmp( buf, "if" ) ) command_list = mprog_process_if( morebuf, command_list, mob, actor, obj, vo, rndm, evil ); else mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm, evil ); cmnd = command_list; command_list = mprog_next_command( command_list ); } return; } /*************************************************************************** * Global function code and brief comments. */ /* 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, void *source, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, int trigger_type, int prog_type ) { CHAR_DATA *pMob = NULL; OBJ_DATA *pObj = NULL; ROOM_INDEX_DATA *pRoom = NULL; 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 MOB_PROG: pMob = (CHAR_DATA *) source; pProgList = pMob->pIndexData->mudprogs; break; case OBJ_PROG: pObj = (OBJ_DATA *) source; pMob = supermob; pProgList = pObj->pIndexData->mudprogs; break; case ROOM_PROG: pRoom = (ROOM_INDEX_DATA *) source; pMob = supermob; pProgList = pRoom->mudprogs; break; default: 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 ( pMob == supermob ) set_supermob( source, prog_type ); mprog_driver( mprg->comlist, pMob, actor, obj, vo ); if ( pMob == 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 ( pMob == supermob ) set_supermob( source, prog_type ); mprog_driver( mprg->comlist, pMob, actor, obj, vo ); if ( pMob == supermob ) release_supermob(); break; } else dupl = start+1; } } return; } bool mprog_percent_check( CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, int trigger_type, int prog_type) { MPROG_LIST *pProgList; bool executed = FALSE; switch(prog_type) { case MOB_PROG: for ( pProgList = mob->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, mob, actor, obj, vo ); if ( trigger_type != GREET_PROG && trigger_type != ALL_GREET_PROG ) break; } break; case OBJ_PROG: for ( pProgList = obj->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, mob, actor, obj, vo ); if ( trigger_type != GREET_PROG ) break; } break; case ROOM_PROG: for ( pProgList = mob->in_room->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, mob, actor, obj, vo ); if(trigger_type != ENTER_PROG) break; } break; default: executed = FALSE; break; } return executed; } /* 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 ) ) ) { mprog_driver( pList->mudprog->comlist, mob, ch, obj, NULL ); break; } } return; } void mprog_death_trigger( CHAR_DATA *mob ) { if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & DEATH_PROG ) ) { mob->position = POS_RESTING; mprog_percent_check( mob, NULL, NULL, NULL, DEATH_PROG, MOB_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 ) ) mprog_percent_check( mob, NULL, NULL, NULL, ENTRY_PROG, MOB_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; mprog_percent_check( mob, ch, NULL, NULL, FIGHT_PROG, MOB_PROG ); } return; } void mprog_fightroom_trigger( CHAR_DATA *mob ) { CHAR_DATA *victim; if ( !mob || !mob->in_room ) return; if ( IS_NPC( mob ) && ( mob->pIndexData->progtypes & FIGHTROOM_PROG ) ) { for ( victim = mob->in_room->people; victim; victim = victim->next_in_room ) { if ( victim != mob && victim->fighting == mob && mprog_percent_check( mob, victim, NULL, NULL, FIGHTROOM_PROG, MOB_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 ) ) ) ) { mprog_driver( pList->mudprog->comlist, mob, ch, obj, NULL ); 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) ) mprog_percent_check( vmob, ch, NULL, NULL, GREET_PROG, MOB_PROG ); else if ( IS_NPC( vmob ) && ( !vmob->fighting ) && IS_AWAKE( vmob ) && ( vmob->pIndexData->progtypes & ALL_GREET_PROG ) ) mprog_percent_check(vmob,ch,NULL,NULL,ALL_GREET_PROG, MOB_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 ) ) ) { mprog_driver( pList->mudprog->comlist, mob, ch, NULL, NULL ); break; } } return; } void mprog_random_trigger( CHAR_DATA *mob ) { if ( mob->pIndexData->progtypes & RAND_PROG) mprog_percent_check(mob,NULL,NULL,NULL,RAND_PROG, MOB_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; mprog_wordlist_check( txt, vmob, actor, NULL, NULL, 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_DATA *vmob; OBJ_DATA *obj; ROOM_INDEX_DATA *room; MPROG_LIST *pList; int cmd; bool can_do = TRUE; argument = strdup(txt); /* 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)) ) { mprog_driver( pList->mudprog->comlist, vmob, ch, NULL, NULL ); 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 ); mprog_driver( pList->mudprog->comlist, supermob, ch, obj, NULL ); 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 ); mprog_driver( pList->mudprog->comlist, supermob, ch, obj, NULL ); 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 ); mprog_driver( pList->mudprog->comlist, supermob, ch, NULL, NULL ); release_supermob(); can_do = FALSE; } } } 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... * *****************************************************************/ void init_supermob( ) { 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); /* 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 ); 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 ); break; } char_from_room (supermob ); char_to_room( supermob, pRoom); return; } void release_supermob( ) { char_from_room( supermob ); if ( supermob->name ) free_string( supermob->name ); supermob->name = str_dup("SuperMob"); char_to_room( supermob, get_room_index( ROOM_VNUM_SUPERMOB ) ); } /* * 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 ); mprog_percent_check( supermob, ch, NULL, NULL, LEAVE_PROG, ROOM_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 ); mprog_percent_check( supermob, ch, NULL, NULL, ENTRY_PROG, ROOM_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 ); mprog_percent_check( supermob, ch, NULL, NULL, SLEEP_PROG, ROOM_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 ); mprog_percent_check( supermob, ch, NULL, NULL, REST_PROG, ROOM_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 ); mprog_percent_check( supermob, ch, NULL, NULL, RFIGHT_PROG, ROOM_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 ); mprog_percent_check( supermob, ch, NULL, NULL, RDEATH_PROG, ROOM_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 ) { /* supermob is set and released in mprog_wordlist_check */ mprog_wordlist_check( txt, ch->in_room, ch, NULL, NULL, 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 ); mprog_percent_check(supermob,ch,NULL,NULL,RAND_PROG, ROOM_PROG); release_supermob(); } return; } /* Written by Jenny, Nov 29/95 */ void progbug( char *str, CHAR_DATA *mob ) { /* Check if we're dealing with supermob, which means the bug occurred in a room or obj prog. */ if ( mob->pIndexData->vnum == MOB_VNUM_SUPERMOB ) { /* It's supermob. In set_supermob the description was set to indicate the object or room, so we just need to show the description in the bug message. */ bug( "%s, %s.", str, !mob->description ? "(unknown)" : mob->description ); } else { bug( "%s, Mob #%d.", str, mob->pIndexData->vnum ); } return; } /* Room act prog updates. Use a separate list cuz we dont really wanna go thru 5-10000 rooms every pulse.. can we say lag? -- Alty */ void room_act_add( ROOM_INDEX_DATA *room ) { struct act_prog_data *runner; for ( runner = room_act_list; runner; runner = runner->next ) if ( runner->vo == room ) return; runner = alloc_mem( sizeof(*runner) ); runner->vo = room; runner->next = room_act_list; room_act_list = runner; } void room_act_update( void ) { struct act_prog_data *runner; MPROG_ACT_LIST *mpact; while ( (runner = room_act_list) ) { ROOM_INDEX_DATA *room = runner->vo; while ( (mpact = room->mpact) ) { if ( mpact->ch->in_room == room ) mprog_wordlist_check(mpact->buf, room, mpact->ch, mpact->obj, mpact->vo, ACT_PROG, ROOM_PROG); room->mpact = mpact->next; free_string( mpact->buf ); free_mem( mpact, sizeof(*mpact) ); } room->mpact = NULL; room->mpactnum = 0; room_act_list = runner->next; free_mem( runner, sizeof(*runner) ); } 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 */ mprog_percent_check( supermob, ch, vobj, NULL, GREET_PROG, OBJ_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 ) { mprog_wordlist_check( txt, vobj, ch, vobj, NULL, 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 ); mprog_percent_check(supermob,NULL,obj,NULL,RAND_PROG, OBJ_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 ); mprog_percent_check( supermob, ch, obj, NULL, WEAR_PROG, OBJ_PROG ); release_supermob(); } return; } bool oprog_use_trigger( CHAR_DATA *ch, OBJ_DATA *obj, CHAR_DATA *vict, OBJ_DATA *targ, void *vo ) { bool executed = FALSE; if ( obj->pIndexData->progtypes & USE_PROG ) { set_supermob( obj, OBJ_PROG ); if ( obj->item_type == ITEM_STAFF ) { if ( vict ) executed = mprog_percent_check( supermob, ch, obj, vict, USE_PROG, OBJ_PROG ); else executed = mprog_percent_check( supermob, ch, obj, targ, USE_PROG, OBJ_PROG ); } else { executed = mprog_percent_check( supermob, ch, obj, NULL, USE_PROG, OBJ_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 ); mprog_percent_check( supermob, ch, obj, NULL, REMOVE_PROG, OBJ_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 ); mprog_percent_check( supermob, ch, obj, NULL, SAC_PROG, OBJ_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 ); mprog_percent_check( supermob, ch, obj, NULL, GET_PROG, OBJ_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 ); mprog_percent_check( supermob, ch, obj, NULL, DAMAGE_PROG, OBJ_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 ); mprog_percent_check( supermob, ch, obj, NULL, REPAIR_PROG, OBJ_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 ); mprog_percent_check( supermob, ch, obj, NULL, DROP_PROG, OBJ_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 ); mprog_percent_check( supermob, ch, obj, NULL, EXA_PROG, OBJ_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 ); mprog_percent_check( supermob, ch, obj, NULL, ZAP_PROG, OBJ_PROG ); release_supermob(); } return; } void obj_act_add( OBJ_DATA *obj ); 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; } void obj_act_add( OBJ_DATA *obj ) { struct act_prog_data *runner; for ( runner = obj_act_list; runner; runner = runner->next ) if ( runner->vo == obj ) return; runner = alloc_mem( sizeof(*runner) ); runner->vo = obj; runner->next = obj_act_list; obj_act_list = runner; } void obj_act_update( void ) { struct act_prog_data *runner; MPROG_ACT_LIST *mpact; while ( (runner = obj_act_list) != NULL ) { OBJ_DATA *obj = runner->vo; while ( (mpact = obj->mpact) != NULL ) { mprog_wordlist_check(mpact->buf, obj, mpact->ch, mpact->obj, mpact->vo, ACT_PROG, OBJ_PROG); obj->mpact = mpact->next; free_string(mpact->buf); free_mem(mpact, sizeof(*mpact) ); } obj->mpact = NULL; obj->mpactnum = 0; obj_act_list = runner->next; free_mem(runner, sizeof(*runner)); } 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 ); mprog_percent_check( supermob, ch, obj, victim, HIT_PROG, OBJ_PROG ); release_supermob(); } return; }