diff -c oldsrc/Makefile src/Makefile *** oldsrc/Makefile Wed Jun 8 18:13:46 1994 --- src/Makefile Mon Jun 13 12:33:39 1994 *************** *** 30,36 **** handler.o db.o interpreter.o utility.o spec_assign.o shop.o limits.o\ mobact.o fight.o modify.o weather.o spell_parser.o spells1.o\ spells2.o constants.o spec_procs.o signals.o objsave.o boards.o\ ! magic.o mail.o castle.o ban.o graph.o config.o ../bin/circle : $(OBJFILES) --- 30,37 ---- handler.o db.o interpreter.o utility.o spec_assign.o shop.o limits.o\ mobact.o fight.o modify.o weather.o spell_parser.o spells1.o\ spells2.o constants.o spec_procs.o signals.o objsave.o boards.o\ ! magic.o mail.o castle.o ban.o graph.o config.o mobprog.o mobcmd.o \ ! xrand.o ../bin/circle : $(OBJFILES) *************** *** 203,208 **** --- 204,219 ---- $(CC) -c $(CFLAGS) graph.c config.o : config.c structs.h $(CC) -c $(CFLAGS) config.c + + xrand.o: xrand.c + $(CC) -c $(CFLAGS) xrand.c + + mobcmd.o: mobcmd.c structs.h utils.h comm.h interpreter.h handler.h db.h + $(CC) -c $(CFLAGS) mobcmd.c + + mobprog.o: mobprog.c structs.h utils.h comm.h interpreter.h handler.h db.h + $(CC) -c $(CFLAGS) mobprog.c + ../bin/circle : $(CC) -o ../bin/circle $(PROFILE) $(OBJFILES) $(LIBS) diff -c oldsrc/act.comm.c src/act.comm.c *** oldsrc/act.comm.c Wed Jun 8 18:13:46 1994 --- src/act.comm.c Tue Jun 14 15:49:18 1994 *************** *** 35,40 **** --- 35,41 ---- send_to_char("Yes, but WHAT do you want to say?\n\r", ch); else { sprintf(buf, "$n says '%s'", argument + i); + MOBTrigger = FALSE; act(buf, FALSE, ch, 0, 0, TO_ROOM); if (!PRF_FLAGGED(ch, PRF_NOREPEAT)) { sprintf(buf, "You say '%s'\n\r", argument + i); *************** *** 41,46 **** --- 42,48 ---- send_to_char(buf, ch); } else send_to_char("Ok.\n\r", ch); + mprog_speech_trigger(argument, ch); } } diff -c oldsrc/act.movement.c src/act.movement.c *** oldsrc/act.movement.c Wed Jun 8 18:13:47 1994 --- src/act.movement.c Mon Jun 13 15:19:36 1994 *************** *** 108,113 **** --- 108,115 ---- return(-1); } + mprog_entry_trigger(ch); + mprog_greet_trigger(ch); return(1); } diff -c oldsrc/act.obj1.c src/act.obj1.c *** oldsrc/act.obj1.c Wed Jun 8 18:13:48 1994 --- src/act.obj1.c Tue Jun 14 15:46:42 1994 *************** *** 556,564 **** --- 556,568 ---- obj_from_char(obj); obj_to_char(obj, vict); + MOBTrigger = FALSE; act("You give $p to $N.", FALSE, ch, obj, vict, TO_CHAR); + MOBTrigger = FALSE; act("$n gives you $p.", FALSE, ch, obj, vict, TO_VICT); + MOBTrigger = FALSE; act("$n gives $p to $N.", TRUE, ch, obj, vict, TO_NOTVICT); + mprog_give_trigger(vict, ch, obj); } /* utility function for give */ *************** *** 600,607 **** --- 604,613 ---- } send_to_char("Ok.\n\r", ch); + mprog_bribe_trigger(vict, ch, amount); sprintf(buf, "%s gives you %d gold coins.\n\r", PERS(ch, vict), amount); send_to_char(buf, vict); + MOBTrigger = FALSE; act("$n gives some gold to $N.", TRUE, ch, 0, vict, TO_NOTVICT); if (IS_NPC(ch) || (GET_LEVEL(ch) < LEVEL_GOD)) GET_GOLD(ch) -= amount; diff -c oldsrc/act.offensive.c src/act.offensive.c *** oldsrc/act.offensive.c Wed Jun 8 18:13:48 1994 --- src/act.offensive.c Tue Jun 14 14:29:40 1994 *************** *** 26,32 **** extern struct room_data *world; /* extern functions */ ! void raw_kill(struct char_data *ch); int do_simple_move(struct char_data *ch, int cmd, int following); --- 26,32 ---- extern struct room_data *world; /* extern functions */ ! void raw_kill(struct char_data *ch, struct char_data *killer); int do_simple_move(struct char_data *ch, int cmd, int following); *************** *** 126,132 **** act("You chop $M to pieces! Ah! The blood!", FALSE, ch, 0, victim, TO_CHAR); act("$N chops you to pieces!", FALSE, victim, 0, ch, TO_CHAR); act("$n brutally slays $N!", FALSE, ch, 0, victim, TO_NOTVICT); ! raw_kill(victim); } } } --- 126,132 ---- act("You chop $M to pieces! Ah! The blood!", FALSE, ch, 0, victim, TO_CHAR); act("$N chops you to pieces!", FALSE, victim, 0, ch, TO_CHAR); act("$n brutally slays $N!", FALSE, ch, 0, victim, TO_NOTVICT); ! raw_kill(victim, ch); } } } diff -c oldsrc/act.other.c src/act.other.c *** oldsrc/act.other.c Wed Jun 8 18:13:49 1994 --- src/act.other.c Tue Jun 14 14:28:21 1994 *************** *** 40,46 **** ACMD(do_quit) { ! void die(struct char_data *ch); if (IS_NPC(ch) || !ch->desc) return; --- 40,46 ---- ACMD(do_quit) { ! void die(struct char_data *ch, struct char_data *killer); if (IS_NPC(ch) || !ch->desc) return; *************** *** 57,63 **** if (GET_POS(ch) < POSITION_STUNNED) { send_to_char("You die before your time...\n\r", ch); ! die(ch); return; } --- 57,63 ---- if (GET_POS(ch) < POSITION_STUNNED) { send_to_char("You die before your time...\n\r", ch); ! die(ch, NULL); return; } diff -c oldsrc/act.wizard.c src/act.wizard.c *** oldsrc/act.wizard.c Wed Jun 8 18:13:50 1994 --- src/act.wizard.c Tue Jun 14 15:51:17 1994 *************** *** 88,98 **** send_to_char("Yes.. But what?\n\r", ch); else { sprintf(buf, "$n %s", argument + i); act(buf, FALSE, ch, 0, 0, TO_ROOM); if (PRF_FLAGGED(ch, PRF_NOREPEAT)) send_to_char("Ok.\n\r", ch); ! else act(buf, FALSE, ch, 0, 0, TO_CHAR); } } --- 88,101 ---- send_to_char("Yes.. But what?\n\r", ch); else { sprintf(buf, "$n %s", argument + i); + MOBTrigger=FALSE; act(buf, FALSE, ch, 0, 0, TO_ROOM); if (PRF_FLAGGED(ch, PRF_NOREPEAT)) send_to_char("Ok.\n\r", ch); ! else { ! MOBTrigger=FALSE; act(buf, FALSE, ch, 0, 0, TO_CHAR); + } } } diff -c oldsrc/comm.c src/comm.c *** oldsrc/comm.c Wed Jun 8 18:13:52 1994 --- src/comm.c Tue Jun 14 10:35:17 1994 *************** *** 65,70 **** --- 65,71 ---- int maxdesc; /* highest desc num used */ int avail_descs; /* max descriptors available */ int tics = 0; /* for extern checkpointing */ + bool MOBTrigger = TRUE; /* For MOBProg */ extern int nameserver_is_slow; /* see config.c */ extern int auto_save; /* see config.c */ extern int autosave_time; /* see config.c */ *************** *** 1201,1210 **** struct char_data *to; static char buf[MAX_STRING_LENGTH]; ! if (!str) return; ! if (!*str) ! return; if (type == TO_VICT) to = (struct char_data *) vict_obj; --- 1202,1211 ---- struct char_data *to; static char buf[MAX_STRING_LENGTH]; ! if (!str || !*str) { ! MOBTrigger = TRUE; return; ! } if (type == TO_VICT) to = (struct char_data *) vict_obj; *************** *** 1214,1222 **** to = world[ch->in_room].people; for (; to; to = to->next_in_room) { ! if (to->desc && ((to != ch) || (type == TO_CHAR)) && (CAN_SEE(to, ch) || !hide_invisible || ! (type == TO_VICT)) && AWAKE(to) && !PLR_FLAGGED(to, PLR_WRITING) && !((type == TO_NOTVICT) && (to == (struct char_data *) vict_obj))) { for (strp = str, point = buf; ; ) --- 1215,1224 ---- to = world[ch->in_room].people; for (; to; to = to->next_in_room) { ! if (((to != ch) || (type == TO_CHAR)) && (CAN_SEE(to, ch) || !hide_invisible || ! (type == TO_VICT)) && ! AWAKE(to) && !PLR_FLAGGED(to, PLR_WRITING) && !((type == TO_NOTVICT) && (to == (struct char_data *) vict_obj))) { for (strp = str, point = buf; ; ) *************** *** 1290,1301 **** *(--point) = '\n'; *(++point) = '\r'; *(++point) = '\0'; - SEND_TO_Q(CAP(buf), to->desc); } ! if ((type == TO_VICT) || (type == TO_CHAR)) return; } } - - --- 1292,1307 ---- *(--point) = '\n'; *(++point) = '\r'; *(++point) = '\0'; + if(to->desc) + SEND_TO_Q(CAP(buf), to->desc); + if(MOBTrigger) + mprog_act_trigger(buf, to, ch, obj, vict_obj); } ! if ((type == TO_VICT) || (type == TO_CHAR)) { ! MOBTrigger = TRUE; return; + } } + MOBTrigger=TRUE; } diff -c oldsrc/db.c src/db.c *** oldsrc/db.c Wed Jun 8 18:13:53 1994 --- src/db.c Mon Jun 13 19:40:28 1994 *************** *** 26,31 **** --- 26,38 ---- #include "mail.h" #include "interpreter.h" + void mprog_read_programs(FILE * fp, struct index_data * pMobIndex); + void init_mm (void); + + char err_buf[MAX_STRING_LENGTH]; + + #define bug(x, y) {sprintf(err_buf, (x), (y)); log(err_buf); } + /************************************************************************** * declarations of most of the 'global' variables * ************************************************************************ */ *************** *** 204,209 **** --- 211,221 ---- log("Resetting the game time:"); reset_time(); + /* init random number generator */ + + init_mm(); + + log("Reading news, credits, help, bground, info & motds."); file_to_string_alloc(NEWS_FILE, &news); file_to_string_alloc(CREDITS_FILE, &credits); *************** *** 308,313 **** --- 320,327 ---- boot_time = time(0); + MOBTrigger = TRUE; + log("Boot db -- DONE."); } *************** *** 898,903 **** --- 912,926 ---- } + char fread_letter(FILE *fp) + { + char c; + do { + c = getc(fp); + } while (isspace(c)); + return c; + } + void load_mobiles(FILE *mob_f) { static int i = 0; *************** *** 1059,1064 **** --- 1082,1093 ---- mob_proto[i].nr = i; mob_proto[i].desc = 0; + letter=fread_letter(mob_f); + if(letter == '>') { + ungetc(letter, mob_f); + (void) mprog_read_programs(mob_f, &mob_index[i]); + } else ungetc(letter, mob_f); + if (!fscanf(mob_f, "%s\n", chk)) { sprintf(buf2, "SYSERR: Format error in mob file near mob #%d", nr); log(buf2); *************** *** 1726,1765 **** /* read and allocate space for a '~'-terminated string from a given file */ ! char *fread_string(FILE *fl, char *error) { ! char buf[MAX_STRING_LENGTH], tmp[500]; ! char *rslt; ! register char *point; ! int flag; bzero(buf, MAX_STRING_LENGTH); do { if (!fgets(tmp, MAX_STRING_LENGTH, fl)) { ! fprintf(stderr, "fread_string: format error at or near %s\n", error); ! exit(0); } if (strlen(tmp) + strlen(buf) > MAX_STRING_LENGTH) { ! log("SYSERR: fread_string: string too large (db.c)"); ! exit(0); } else ! strcat(buf, tmp); ! for (point = buf + strlen(buf) - 2; point >= buf && isspace(*point); point--) ! ; if ((flag = (*point == '~'))) ! if (*(buf + strlen(buf) - 3) == '\n') { ! *(buf + strlen(buf) - 2) = '\r'; ! *(buf + strlen(buf) - 1) = '\0'; ! } ! else ! *(buf + strlen(buf) - 2) = '\0'; else { ! *(buf + strlen(buf) + 1) = '\0'; ! *(buf + strlen(buf)) = '\r'; } } while (!flag); --- 1755,1794 ---- /* read and allocate space for a '~'-terminated string from a given file */ ! char *fread_string(FILE *fl, char *error) { ! char buf[MAX_STRING_LENGTH], tmp[500]; ! char *rslt; ! register char *point; ! int flag; bzero(buf, MAX_STRING_LENGTH); do { if (!fgets(tmp, MAX_STRING_LENGTH, fl)) { ! fprintf(stderr, "fread_string: format error at or near %s\n", error); ! exit(0); } if (strlen(tmp) + strlen(buf) > MAX_STRING_LENGTH) { ! log("SYSERR: fread_string: string too large (db.c)"); ! exit(0); } else ! strcat(buf, tmp); ! for (point = buf + strlen(buf) - 2; point >= buf && isspace(*point); point--) ! ; if ((flag = (*point == '~'))) ! if (*(buf + strlen(buf) - 3) == '\n') { ! *(buf + strlen(buf) - 2) = '\r'; ! *(buf + strlen(buf) - 1) = '\0'; ! } ! else ! *(buf + strlen(buf) - 2) = '\0'; else { ! *(buf + strlen(buf) + 1) = '\0'; ! *(buf + strlen(buf)) = '\r'; } } while (!flag); *************** *** 1773,1782 **** return(rslt); } - - - - /* release memory allocated for a char struct */ void free_char(struct char_data *ch) { --- 1802,1807 ---- *************** *** 2150,2154 **** --- 2175,2483 ---- else bot = mid + 1; } + } + + /* the functions */ + + /* This routine transfers between alpha and numeric forms of the + * mob_prog bitvector types. This allows the use of the words in the + * mob/script files. + */ + + int mprog_name_to_type ( char *name ) + { + if ( !str_cmp( name, "in_file_prog" ) ) return IN_FILE_PROG; + if ( !str_cmp( name, "act_prog" ) ) return ACT_PROG; + if ( !str_cmp( name, "speech_prog" ) ) return SPEECH_PROG; + if ( !str_cmp( name, "rand_prog" ) ) return RAND_PROG; + if ( !str_cmp( name, "fight_prog" ) ) return FIGHT_PROG; + if ( !str_cmp( name, "hitprcnt_prog" ) ) return HITPRCNT_PROG; + if ( !str_cmp( name, "death_prog" ) ) return DEATH_PROG; + if ( !str_cmp( name, "entry_prog" ) ) return ENTRY_PROG; + if ( !str_cmp( name, "greet_prog" ) ) return GREET_PROG; + if ( !str_cmp( name, "all_greet_prog" ) ) return ALL_GREET_PROG; + if ( !str_cmp( name, "give_prog" ) ) return GIVE_PROG; + if ( !str_cmp( name, "bribe_prog" ) ) return BRIBE_PROG; + + return( ERROR_PROG ); + } + + /* + * Read a number from a file. + */ + int fread_number( FILE *fp ) + { + int number; + bool sign; + char c; + + do { + c = getc( fp ); + } while ( isspace(c) ); + + number = 0; + + sign = FALSE; + if ( c == '+' ) { + c = getc( fp ); + } else if ( c == '-' ) { + sign = TRUE; + c = getc( fp ); + } + + if ( !isdigit(c) ) { + bug( "Fread_number: bad format.", 0 ); + exit( 1 ); + } + + while ( isdigit(c) ) { + number = number * 10 + c - '0'; + c = getc( fp ); + } + + if ( sign ) + number = 0 - number; + + if ( c == '|' ) + number += fread_number( fp ); + else if ( c != ' ' ) + ungetc( c, fp ); + + return number; + } + + /* + * Read to end of line (for comments). + */ + void fread_to_eol( FILE *fp ) + { + char c; + + do { + c = getc( fp ); + } while ( c != '\n' && c != '\r' ); + + do { + c = getc( fp ); + } while ( c == '\n' || c == '\r' ); + + ungetc( c, fp ); + return; + } + + /* + * Read one word (into static buffer). + */ + char *fread_word(FILE *fp) + { + static char word[MAX_INPUT_LENGTH]; + char *pword; + char cEnd; + + do + { + cEnd = getc( fp ); + } + while ( isspace( cEnd ) ); + + if ( cEnd == '\'' || cEnd == '"' ) + { + pword = word; + } + else + { + word[0] = cEnd; + pword = word+1; + cEnd = ' '; + } + + for ( ; pword < word + MAX_INPUT_LENGTH; pword++ ) + { + *pword = getc( fp ); + if ( cEnd == ' ' ? isspace(*pword) || *pword == '~' : *pword == cEnd ) + { + if ( cEnd == ' ' || cEnd == '~' ) + ungetc( *pword, fp ); + *pword = '\0'; + return word; + } + } + + log("SYSERR: Fread_word: word too long."); + exit( 1 ); + return NULL; + } + + + /* This routine reads in scripts of MOBprograms from a file */ + + MPROG_DATA* mprog_file_read( char *f, MPROG_DATA *mprg, + struct index_data *pMobIndex ) + { + + char MOBProgfile[ MAX_INPUT_LENGTH ]; + MPROG_DATA *mprg2; + FILE *progfile; + char letter; + bool done = FALSE; + + sprintf( MOBProgfile, "%s/%s", MOB_DIR, f ); + + progfile = fopen( MOBProgfile, "r" ); + if ( !progfile ) + { + bug( "Mob: %d couldnt open mobprog file", pMobIndex->virtual); + exit( 1 ); + } + + mprg2 = mprg; + switch ( letter = fread_letter( progfile ) ) + { + case '>': + break; + case '|': + bug( "empty mobprog file.", 0 ); + exit( 1 ); + break; + default: + bug( "in mobprog file syntax error.", 0 ); + exit( 1 ); + break; + } + + while ( !done ) + { + mprg2->type = mprog_name_to_type( fread_word( progfile ) ); + switch ( mprg2->type ) + { + case ERROR_PROG: + bug( "mobprog file type error", 0 ); + exit( 1 ); + break; + case IN_FILE_PROG: + bug( "mprog file contains a call to file.", 0 ); + exit( 1 ); + break; + default: + sprintf(buf2, "Error in file %s", f); + pMobIndex->progtypes = pMobIndex->progtypes | mprg2->type; + mprg2->arglist = fread_string( progfile,buf2 ); + mprg2->comlist = fread_string( progfile,buf2 ); + switch ( letter = fread_letter( progfile ) ) + { + case '>': + mprg2->next = (MPROG_DATA *)malloc( sizeof( MPROG_DATA ) ); + mprg2 = mprg2->next; + mprg2->next = NULL; + break; + case '|': + done = TRUE; + break; + default: + bug( "in mobprog file %s syntax error.", f ); + exit( 1 ); + break; + } + break; + } + } + fclose( progfile ); + return mprg2; + } + + struct index_data *get_obj_index (int vnum) + { + int nr; + for(nr = 0; nr <= top_of_objt; nr++) { + if(obj_index[nr].virtual == vnum) return &obj_index[nr]; + } + return NULL; + } + + struct index_data *get_mob_index (int vnum) + { + int nr; + for(nr = 0; nr <= top_of_mobt; nr++) { + if(mob_index[nr].virtual == vnum) return &mob_index[nr]; + } + return NULL; + } + + /* This procedure is responsible for reading any in_file MOBprograms. + */ + + void mprog_read_programs( FILE *fp, struct index_data *pMobIndex) + { + MPROG_DATA *mprg; + char letter; + bool done = FALSE; + + if ( ( letter = fread_letter( fp ) ) != '>' ) + { + bug( "Load_mobiles: vnum %d MOBPROG char", pMobIndex->virtual); + exit( 1 ); + } + pMobIndex->mobprogs = (MPROG_DATA *)malloc( sizeof( MPROG_DATA ) ); + mprg = pMobIndex->mobprogs; + + while ( !done ) + { + mprg->type = mprog_name_to_type( fread_word( fp ) ); + switch ( mprg->type ) + { + case ERROR_PROG: + bug( "Load_mobiles: vnum %d MOBPROG type.", pMobIndex->virtual); + exit( 1 ); + break; + case IN_FILE_PROG: + sprintf(buf2, "Mobprog for mob #%d", pMobIndex->virtual); + mprg = mprog_file_read( fread_word(fp), mprg,pMobIndex ); + fread_to_eol( fp ); /* need to strip off that silly ~*/ + switch ( letter = fread_letter( fp ) ) + { + case '>': + mprg->next = (MPROG_DATA *)malloc( sizeof( MPROG_DATA ) ); + mprg = mprg->next; + mprg->next = NULL; + break; + case '|': + mprg->next = NULL; + fread_to_eol( fp ); + done = TRUE; + break; + default: + bug( "Load_mobiles: vnum %d bad MOBPROG.", pMobIndex->virtual); + exit( 1 ); + break; + } + break; + default: + sprintf(buf2, "Mobprog for mob #%d", pMobIndex->virtual); + pMobIndex->progtypes = pMobIndex->progtypes | mprg->type; + mprg->arglist = fread_string( fp, buf2 ); + mprg->comlist = fread_string( fp, buf2 ); + switch ( letter = fread_letter( fp ) ) + { + case '>': + mprg->next = (MPROG_DATA *)malloc( sizeof( MPROG_DATA ) ); + mprg = mprg->next; + mprg->next = NULL; + break; + case '|': + mprg->next = NULL; + fread_to_eol( fp ); + done = TRUE; + break; + default: + bug( "Load_mobiles: vnum %d bad MOBPROG.", pMobIndex->virtual); + exit( 1 ); + break; + } + break; + } + } + + return; + } diff -c oldsrc/db.h src/db.h *** oldsrc/db.h Wed Jun 8 18:13:53 1994 --- src/db.h Fri Jun 10 13:54:31 1994 *************** *** 24,29 **** --- 24,31 ---- #define OBJ_PREFIX "world/obj" /* object prototypes */ #define ZON_PREFIX "world/zon" /* zon defs & command tables */ #define SHP_PREFIX "world/shp" /* shop definitions */ + /* MOBprog foo */ + #define MOB_DIR "world/prg" /* Mob program */ #define CREDITS_FILE "text/credits" /* for the 'credits' command */ #define NEWS_FILE "text/news" /* for the 'news' command */ *************** *** 127,132 **** --- 129,136 ---- struct index_data { int virtual; /* virtual number of this mob/obj */ int number; /* number of existing units of this mob/obj */ + int progtypes; /* program types for MOBProg */ + MPROG_DATA *mobprogs; /* programs for MOBProg */ int (*func)(); /* special procedure for this mob/obj */ }; diff -c oldsrc/fight.c src/fight.c *** oldsrc/fight.c Wed Jun 8 18:13:55 1994 --- src/fight.c Tue Jun 14 14:35:54 1994 *************** *** 329,335 **** ! void raw_kill(struct char_data *ch) { if (ch->specials.fighting) stop_fighting(ch); --- 329,335 ---- ! void raw_kill(struct char_data *ch, struct char_data *killer) { if (ch->specials.fighting) stop_fighting(ch); *************** *** 337,360 **** while (ch->affected) affect_remove(ch, ch->affected); ! death_cry(ch); make_corpse(ch); extract_char(ch); } ! ! ! void die(struct char_data *ch) { gain_exp(ch, -(GET_EXP(ch) / 2)); if (!IS_NPC(ch)) REMOVE_BIT(PLR_FLAGS(ch), PLR_KILLER | PLR_THIEF); ! raw_kill(ch); } - - void group_gain(struct char_data *ch, struct char_data *victim) { --- 337,359 ---- while (ch->affected) affect_remove(ch, ch->affected); ! /* death_cry(ch); */ ! /* replaced for MOBprog death action */ ! if(killer) ! mprog_death_trigger(ch, killer); make_corpse(ch); extract_char(ch); } ! void die(struct char_data *ch, struct char_data *killer) { gain_exp(ch, -(GET_EXP(ch) / 2)); if (!IS_NPC(ch)) REMOVE_BIT(PLR_FLAGS(ch), PLR_KILLER | PLR_THIEF); ! raw_kill(ch, killer); } void group_gain(struct char_data *ch, struct char_data *victim) { *************** *** 739,745 **** } if (IS_NPC(ch) && !IS_NPC(victim) && IS_SET(ch->specials2.act, MOB_MEMORY)) forget(ch, victim); ! die(victim); } } --- 738,744 ---- } if (IS_NPC(ch) && !IS_NPC(victim) && IS_SET(ch->specials2.act, MOB_MEMORY)) forget(ch, victim); ! die(victim, ch); } } *************** *** 886,892 **** } else { /* Not in same room */ stop_fighting(ch); } } } - --- 885,892 ---- } else { /* Not in same room */ stop_fighting(ch); } + mprog_hitprcnt_trigger(ch, ch->specials.fighting); + mprog_fight_trigger(ch, ch->specials.fighting); } } diff -c oldsrc/handler.c src/handler.c *** oldsrc/handler.c Wed Jun 8 18:13:56 1994 --- src/handler.c Tue Jun 14 14:30:22 1994 *************** *** 383,390 **** /* place a character in a room */ void char_to_room(struct char_data *ch, int room) { - void raw_kill(struct char_data *ch); - ch->next_in_room = world[room].people; world[room].people = ch; ch->in_room = room; --- 383,388 ---- diff -c oldsrc/interpreter.c src/interpreter.c *** oldsrc/interpreter.c Wed Jun 8 18:13:57 1994 --- src/interpreter.c Mon Jun 13 16:59:19 1994 *************** *** 191,197 **** --- 191,212 ---- ACMD(do_reboot); ACMD(do_last); ACMD(do_track); + ACMD(do_mpstat); + ACMD(do_mpasound); + ACMD(do_mpjunk); + ACMD(do_mpecho); + ACMD(do_mpechoat); + ACMD(do_mpechoaround); + ACMD(do_mpkill); + ACMD(do_mpmload); + ACMD(do_mpoload); + ACMD(do_mppurge); + ACMD(do_mpgoto); + ACMD(do_mpat); + ACMD(do_mptransfer); + ACMD(do_mpforce); + char *command[] = { "north", /* 1 */ *************** *** 494,499 **** --- 509,528 ---- "track", "whoami", "vstat", + "mpstat", /* 301 */ + "mpasound", + "mpjunk", + "mpecho", + "mpechoat", + "mpechoaround", + "mpkill", + "mpmload", + "mpoload", + "mppurge", + "mpgoto", /* 311 */ + "mpat", + "mptransfer", + "mpforce", "\n" }; *************** *** 1115,1120 **** --- 1144,1163 ---- COMMANDO(298, POSITION_STANDING, do_track , 0, 0) COMMANDO(299, POSITION_DEAD , do_gen_ps , 0, SCMD_WHOAMI) COMMANDO(300, POSITION_DEAD , do_vstat , LEVEL_GOD, 0) + COMMANDO(301, POSITION_DEAD , do_mpstat , 0, 0) + COMMANDO(302, POSITION_DEAD , do_mpasound , 0, 0) + COMMANDO(303, POSITION_DEAD , do_mpjunk , 0, 0) + COMMANDO(304, POSITION_DEAD , do_mpecho , 0, 0) + COMMANDO(305, POSITION_DEAD , do_mpechoat , 0, 0) + COMMANDO(306, POSITION_DEAD , do_mpechoaround , 0, 0) + COMMANDO(307, POSITION_DEAD , do_mpkill , 0, 0) + COMMANDO(308, POSITION_DEAD , do_mpmload , 0, 0) + COMMANDO(309, POSITION_DEAD , do_mpoload , 0, 0) + COMMANDO(310, POSITION_DEAD , do_mppurge , 0, 0) + COMMANDO(311, POSITION_DEAD , do_mpgoto , 0, 0) + COMMANDO(312, POSITION_DEAD , do_mpat , 0, 0) + COMMANDO(313, POSITION_DEAD , do_mptransfer , 0, 0) + COMMANDO(314, POSITION_DEAD , do_mpforce , 0, 0) } diff -c oldsrc/mobact.c src/mobact.c *** oldsrc/mobact.c Wed Jun 8 18:13:59 1994 --- src/mobact.c Mon Jun 13 15:13:10 1994 *************** *** 53,58 **** --- 53,60 ---- } } + if(!is_empty(world[ch->in_room].zone)) mprog_random_trigger(ch); + if (AWAKE(ch) && !(ch->specials.fighting)) { if (IS_SET(ch->specials2.act, MOB_SCAVENGER)) { /* if scavenger */ if (world[ch->in_room].contents && !number(0, 10)) { *************** *** 94,99 **** --- 96,116 ---- } } /* if can go */ + /* MOB Prog foo */ + if(IS_NPC(ch) && ch->mpactnum > 0 && !is_empty(world[ch->in_room].zone)) { + MPROG_ACT_LIST *tmp_act, *tmp2_act; + for(tmp_act = ch->mpact; tmp_act != NULL; tmp_act=tmp_act->next) { + mprog_wordlist_check(tmp_act->buf, ch, tmp_act->ch, + tmp_act->obj, tmp_act->vo, ACT_PROG); + free(tmp_act->buf); + } + for(tmp_act = ch->mpact; tmp_act != NULL; tmp_act=tmp2_act) { + tmp2_act = tmp_act->next; + free(tmp_act); + } + ch->mpactnum = 0; + ch->mpact = NULL; + } if (IS_SET(ch->specials2.act, MOB_AGGRESSIVE)) { found = FALSE; diff -c oldsrc/mobcmd.c src/mobcmd.c *** oldsrc/mobcmd.c Wed Jun 8 18:14:40 1994 --- src/mobcmd.c Tue Jun 14 16:24:17 1994 *************** *** 0 **** --- 1,769 ---- + /*************************************************************************** + * 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 * + ***************************************************************************/ + + #include <sys/types.h> + #include <stdio.h> + #include <string.h> + #include <stdlib.h> + #include "structs.h" + #include "db.h" + #include "utils.h" + #include "handler.h" + #include "interpreter.h" + #include "comm.h" + + extern struct index_data *mob_index; + extern struct room_data *world; + extern struct index_data *obj_index; + extern struct descriptor_data *descriptor_list; + + extern struct index_data *get_mob_index(int vnum); + extern struct index_data *get_obj_index(int vnum); + + #define bug(x, y) { sprintf(buf2, (x), (y)); log(buf2); } + + /* + * Local functions. + */ + + char * mprog_type_to_name ( int type ); + + /* This routine transfers between alpha and numeric forms of the + * mob_prog bitvector types. It allows the words to show up in mpstat to + * make it just a hair bit easier to see what a mob should be doing. + */ + + char *mprog_type_to_name( int type ) + { + switch ( type ) + { + case IN_FILE_PROG: return "in_file_prog"; + case ACT_PROG: return "act_prog"; + case SPEECH_PROG: return "speech_prog"; + case RAND_PROG: return "rand_prog"; + case FIGHT_PROG: return "fight_prog"; + case HITPRCNT_PROG: return "hitprcnt_prog"; + case DEATH_PROG: return "death_prog"; + case ENTRY_PROG: return "entry_prog"; + case GREET_PROG: return "greet_prog"; + case ALL_GREET_PROG: return "all_greet_prog"; + case GIVE_PROG: return "give_prog"; + case BRIBE_PROG: return "bribe_prog"; + default: return "ERROR_PROG"; + } + } + + /* string prefix routine */ + + bool str_prefix(const char *astr, const char *bstr) + { + if (!astr) { + log("Strn_cmp: null astr."); + return TRUE; + } + if (!bstr) { + log("Strn_cmp: null astr."); + return TRUE; + } + for(; *astr; astr++, bstr++) { + if(LOWER(*astr) != LOWER(*bstr)) return TRUE; + } + return FALSE; + } + + /* A trivial rehack of do_mstat. This doesnt show all the data, but just + * enough to identify the mob and give its basic condition. It does however, + * show the MOBprograms which are set. + */ + + void do_mpstat( struct char_data *ch, char *argument ) + { + char buf[ MAX_STRING_LENGTH ]; + char arg[ MAX_INPUT_LENGTH ]; + MPROG_DATA *mprg; + struct char_data *victim; + + one_argument( argument, arg ); + + if ( arg[0] == '\0' ) + { + send_to_char( "MobProg stat whom?\n\r", ch ); + return; + } + + if ( ( victim = get_char_vis( ch, arg ) ) == NULL ) + { + send_to_char( "They aren't here.\n\r", ch ); + return; + } + + if ( !IS_NPC( victim ) ) + { + send_to_char( "Only Mobiles can have Programs!\n\r", ch); + return; + } + + if ( !( mob_index[victim->nr].progtypes ) ) + { + send_to_char( "That Mobile has no Programs set.\n\r", ch); + return; + } + + sprintf( buf, "Name: %s. Vnum: %d.\n\r", + victim->player.name, mob_index[victim->nr].virtual ); + send_to_char( buf, ch ); + + sprintf( buf, "Short description: %s.\n\rLong description: %s", + victim->player.short_descr, + victim->player.long_descr[0] != '\0' ? + victim->player.long_descr : "(none).\n\r" ); + send_to_char( buf, ch ); + + sprintf( buf, "Hp: %d/%d. Mana: %d/%d. Move: %d/%d. \n\r", + victim->points.hit, victim->points.max_hit, + victim->points.mana, victim->points.max_mana, + victim->points.move, victim->points.max_move ); + send_to_char( buf, ch ); + + sprintf( buf, + "Lv: %d. Class: %d. Align: %d. AC: %d. Gold: %d. Exp: %d.\n\r", + victim->player.level, victim->player.class, victim->specials2.alignment, + GET_AC( victim ), victim->points.gold, victim->points.exp ); + send_to_char( buf, ch ); + + for ( mprg = mob_index[victim->nr].mobprogs; mprg != NULL; + mprg = mprg->next ) + { + sprintf( buf, ">%s %s\n\r%s\n\r", + mprog_type_to_name( mprg->type ), + mprg->arglist, + mprg->comlist ); + send_to_char( buf, ch ); + } + + return; + + } + + /* prints the argument to all the rooms aroud the mobile */ + + void do_mpasound( struct char_data *ch, char *argument ) + { + + sh_int was_in_room; + int door; + char arg[MAX_INPUT_LENGTH]; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + if (argument[0] == '\0' ) + { + bug( "Mpasound - No argument: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + one_argument( argument, arg ); + + was_in_room = ch->in_room; + for ( door = 0; door <= 5; door++ ) + { + struct room_direction_data *pexit; + + if ( ( pexit = world[was_in_room].dir_option[door] ) != NULL + && pexit->to_room != NULL + && pexit->to_room != was_in_room ) + { + ch->in_room = pexit->to_room; + MOBTrigger = FALSE; + act( arg, FALSE, ch, NULL, NULL, TO_ROOM ); + } + } + + ch->in_room = was_in_room; + return; + + } + + /* lets the mobile kill any player or mobile without murder*/ + + void do_mpkill( struct char_data *ch, char *argument ) + { + char arg[ MAX_INPUT_LENGTH ]; + struct char_data *victim; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + one_argument( argument, arg ); + + if ( arg[0] == '\0' ) + { + bug( "MpKill - no argument: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + if ( ( victim = get_char_room_vis( ch, arg ) ) == NULL ) + { + bug( "MpKill - Victim not in room: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + if ( victim == ch ) + { + bug( "MpKill - Bad victim to attack: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + if ( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim ) + { + bug( "MpKill - Charmed mob attacking master: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + if ( ch->specials.position == POSITION_FIGHTING ) + { + bug( "MpKill - Already fighting: vnum %d", + mob_index[ch->nr].virtual ); + return; + } + + hit( ch, victim, -1); + return; + } + + + /* lets the mobile destroy an object in its inventory + it can also destroy a worn object and it can destroy + items using all.xxxxx or just plain all of them */ + + void do_mpjunk( struct char_data *ch, char *argument ) + { + char arg[ MAX_INPUT_LENGTH ]; + int pos; + struct obj_data *obj; + struct obj_data *obj_next; + + if ( !IS_NPC( ch ) ) { + send_to_char( "Huh?\n\r", ch ); + return; + } + + one_argument( argument, arg ); + + if ( arg[0] == '\0') { + bug( "Mpjunk - No argument: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + if ( str_cmp( arg, "all" ) && str_prefix( "all.", arg ) ) { + if ((obj=get_object_in_equip_vis(ch,arg,ch->equipment,&pos))!= NULL) { + unequip_char( ch, pos); + extract_obj( obj ); + return; + } + if ((obj = get_obj_in_list_vis(ch, arg, ch->carrying)) != NULL ) + extract_obj( obj ); + return; + } else { + for ( obj = ch->carrying; obj != NULL; obj = obj_next ) { + obj_next = obj->next_content; + if ( arg[3] == '\0' || isname(arg+4, obj->name ) ) { + extract_obj(obj); + } + } + while((obj=get_object_in_equip_vis(ch,arg,ch->equipment,&pos))!=NULL){ + unequip_char(ch, pos); + extract_obj(obj); + } + } + return; + } + + /* prints the message to everyone in the room other than the mob and victim */ + + void do_mpechoaround( struct char_data *ch, char *argument ) + { + char arg[ MAX_INPUT_LENGTH ]; + struct char_data *victim; + char *p; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + p=one_argument( argument, arg ); + while(isspace(*p)) p++; /* skip over leading space */ + + if ( arg[0] == '\0' ) + { + bug( "Mpechoaround - No argument: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + if ( !( victim=get_char_room_vis( ch, arg ) ) ) + { + bug( "Mpechoaround - victim does not exist: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + act(p, FALSE, ch, NULL, victim, TO_NOTVICT ); + return; + } + + /* prints the message to only the victim */ + + void do_mpechoat( struct char_data *ch, char *argument ) + { + char arg[ MAX_INPUT_LENGTH ]; + struct char_data *victim; + char *p; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + p = one_argument( argument, arg ); + while(isspace(*p)) p++; /* skip over leading space */ + + if ( arg[0] == '\0') + { + bug( "Mpechoat - No argument: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + if ( !( victim = get_char_room_vis( ch, arg ) ) ) + { + bug( "Mpechoat - victim does not exist: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + act( p,FALSE, ch, NULL, victim, TO_VICT ); + return; + } + + /* prints the message to the room at large */ + + void do_mpecho( struct char_data *ch, char *argument ) + { + char *p; + + if ( !IS_NPC(ch) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + if ( argument[0] == '\0' ) + { + bug( "Mpecho - called w/o argument: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + p = argument; + while(isspace(*p)) p++; + + act(p,FALSE, ch, NULL, NULL, TO_ROOM ); + return; + + } + + /* lets the mobile load an item or mobile. All items + are loaded into inventory. you can specify a level with + the load object portion as well. */ + + void do_mpmload( struct char_data *ch, char *argument ) + { + char arg[ MAX_INPUT_LENGTH ]; + struct index_data *pMobIndex; + struct char_data *victim; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + one_argument( argument, arg ); + + if ( arg[0] == '\0' || !is_number(arg) ) + { + bug( "Mpmload - Bad vnum as arg: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + if ( ( pMobIndex = get_mob_index( atoi( arg ) ) ) == NULL ) + { + bug( "Mpmload - Bad mob vnum: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + victim = read_mobile( atoi(arg), VIRTUAL); + char_to_room( victim, ch->in_room ); + return; + } + + void do_mpoload( struct char_data *ch, char *argument ) + { + char arg1[ MAX_INPUT_LENGTH ]; + struct index_data *pObjIndex; + struct obj_data *obj; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + argument = one_argument( argument, arg1 ); + + if ( arg1[0] == '\0' || !is_number( arg1 ) ) + { + bug( "Mpoload - Bad syntax: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + if ( ( pObjIndex = get_obj_index( atoi( arg1 ) ) ) == NULL ) + { + bug( "Mpoload - Bad vnum arg: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + obj = read_object( atoi(arg1), VIRTUAL); + if ( CAN_WEAR(obj, ITEM_TAKE) ) { + obj_to_char( obj, ch ); + } else { + obj_to_room( obj, ch->in_room ); + } + + return; + } + + /* lets the mobile purge all objects and other npcs in the room, + or purge a specified object or mob in the room. It can purge + itself, but this had best be the last command in the MOBprogram + otherwise ugly stuff will happen */ + + void do_mppurge( struct char_data *ch, char *argument ) + { + char arg[ MAX_INPUT_LENGTH ]; + struct char_data *victim; + struct obj_data *obj; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + one_argument( argument, arg ); + + if ( arg[0] == '\0' ) + { + /* 'purge' */ + struct char_data *vnext; + struct obj_data *obj_next; + + for ( victim = world[ch->in_room].people; victim != NULL; victim = vnext ) + { + vnext = victim->next_in_room; + if ( IS_NPC( victim ) && victim != ch ) + extract_char( victim); + } + + for ( obj = world[ch->in_room].contents; obj != NULL; obj = obj_next ) + { + obj_next = obj->next_content; + extract_obj( obj ); + } + + return; + } + + if ( !( victim = get_char_room_vis( ch, arg ) ) == NULL ) + { + if ( ( obj = get_obj_vis( ch, arg ) ) ) { + extract_obj( obj ); + } else { + bug("Mppurge - Bad argument: vnum %d.",mob_index[ch->nr].virtual); + } + return; + } + + if ( !IS_NPC( victim ) ) + { + bug( "Mppurge - Purging a PC: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + extract_char( victim); + return; + } + + + /* lets the mobile goto any location it wishes that is not private */ + + void do_mpgoto( struct char_data *ch, char *argument ) + { + char arg[ MAX_INPUT_LENGTH ]; + sh_int location; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + one_argument( argument, arg ); + if ( arg[0] == '\0' ) + { + bug( "Mpgoto - No argument: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + if ( ( location = find_target_room( ch, arg ) ) < 0 ) + { + bug( "Mpgoto - No such location: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + if ( ch->specials.fighting != NULL ) + stop_fighting( ch); + + char_from_room( ch ); + char_to_room( ch, location ); + + return; + } + + /* lets the mobile do a command at another location. Very useful */ + + void do_mpat( struct char_data *ch, char *argument ) + { + char arg[ MAX_INPUT_LENGTH ]; + sh_int location; + sh_int original; + struct char_data *wch; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + argument = one_argument( argument, arg ); + + if ( arg[0] == '\0' || argument[0] == '\0' ) + { + bug( "Mpat - Bad argument: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + if ( ( location = find_target_room( ch, arg ) ) < 0) + { + bug( "Mpat - No such location: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + original = ch->in_room; + char_from_room( ch ); + char_to_room( ch, location ); + command_interpreter( ch, argument ); + + /* + * See if 'ch' still exists before continuing! + * Handles 'at XXXX quit' case. + */ + if(ch->in_room == location) { + char_from_room(ch); + char_to_room( ch, original ); + } + + return; + } + + /* lets the mobile transfer people. the all argument transfers + everyone in the current room to the specified location */ + + void do_mptransfer( struct char_data *ch, char *argument ) + { + char arg1[ MAX_INPUT_LENGTH ]; + char arg2[ MAX_INPUT_LENGTH ]; + sh_int location; + struct descriptor_data *d; + struct char_data *victim; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + argument = one_argument( argument, arg1 ); + argument = one_argument( argument, arg2 ); + + if ( arg1[0] == '\0' ) + { + bug( "Mptransfer - Bad syntax: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + if ( !str_cmp( arg1, "all" ) ) + { + for ( d = descriptor_list; d != NULL; d = d->next ) + { + if ( d->connected == CON_PLYNG + && d->character != ch + && d->character->in_room != NULL + && CAN_SEE( ch, d->character ) ) + { + char buf[MAX_STRING_LENGTH]; + sprintf( buf, "%s %s", d->character->player.name, arg2 ); + do_trans( ch, buf ); + } + } + return; + } + + /* + * Thanks to Grodyn for the optional location parameter. + */ + if ( arg2[0] == '\0' ) + { + location = ch->in_room; + } + else + { + if ( ( location = find_target_room( ch, arg2 ) ) < 0) + { + bug( "Mptransfer - No such location: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + if ( IS_SET(world[location].room_flags, PRIVATE) ) + { + bug( "Mptransfer - Private room: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + } + + if ( ( victim = get_char_vis( ch, arg1 ) ) == NULL ) + { + bug( "Mptransfer - No such person: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + if ( victim->in_room == NULL ) + { + bug( "Mptransfer - Victim in Limbo: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + if ( victim->specials.fighting != NULL ) + stop_fighting( victim); + + char_from_room( victim ); + char_to_room( victim, location ); + + return; + } + + /* lets the mobile force someone to do something. must be mortal level + and the all argument only affects those in the room with the mobile */ + + void do_mpforce( struct char_data *ch, char *argument ) + { + char arg[ MAX_INPUT_LENGTH ]; + + if ( !IS_NPC( ch ) ) + { + send_to_char( "Huh?\n\r", ch ); + return; + } + + argument = one_argument( argument, arg ); + + if ( arg[0] == '\0' || argument[0] == '\0' ) + { + bug( "Mpforce - Bad syntax: vnum %d.", mob_index[ch->nr].virtual ); + return; + } + + if ( !str_cmp( arg, "all" ) ) { + struct descriptor_data *i; + struct char_data *vch; + + for ( i = descriptor_list; i ; i = i->next) { + if(i->character != ch && !i->connected && + i->character->in_room == ch->in_room) { + vch = i->character; + if(GET_LEVEL(vch) < GET_LEVEL(ch) && CAN_SEE(ch, vch)) { + command_interpreter( vch, argument ); + } + } + } + } else { + struct char_data *victim; + + if ( ( victim = get_char_room_vis( ch, arg ) ) == NULL ) { + bug( "Mpforce - No such victim: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + if ( victim == ch ) { + bug( "Mpforce - Forcing oneself: vnum %d.", + mob_index[ch->nr].virtual ); + return; + } + + command_interpreter( victim, argument ); + } + + return; + } diff -c oldsrc/mobprog.c src/mobprog.c *** oldsrc/mobprog.c Wed Jun 8 18:14:40 1994 --- src/mobprog.c Tue Jun 14 14:48:51 1994 *************** *** 0 **** --- 1,1754 ---- + /*************************************************************************** + * 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 * + ***************************************************************************/ + + #include <sys/types.h> + #include <stdio.h> + #include <string.h> + #include <stdlib.h> + #include <ctype.h> + #include "structs.h" + #include "utils.h" + #include "interpreter.h" + #include "handler.h" + #include "db.h" + + char buf2[MAX_STRING_LENGTH]; + + extern struct index_data *mob_index; + extern struct index_data *obj_index; + extern struct room_data *world; + + extern void death_cry (struct char_data *ch); + + #define bug(x, y) { sprintf(buf2, (x), (y)); log(buf2); } + + + /* + * Local function prototypes + */ + + char * mprog_next_command ( char* clist ); + int mprog_seval ( char* lhs, char* opr, char* rhs ); + int mprog_veval ( int lhs, char* opr, int rhs ); + int mprog_do_ifchck ( char* ifchck, struct char_data* mob, + struct char_data* actor, struct obj_data* obj, + void* vo, struct char_data* rndm ); + char * mprog_process_if ( char* ifchck, char* com_list, + struct char_data* mob, struct char_data* actor, + struct obj_data* obj, void* vo, + struct char_data* rndm ); + void mprog_translate ( char ch, char* t, struct char_data* mob, + struct char_data* actor, struct obj_data* obj, + void* vo, struct char_data* rndm ); + void mprog_process_cmnd ( char* cmnd, struct char_data* mob, + struct char_data* actor, struct obj_data* obj, + void* vo, struct char_data* rndm ); + void mprog_driver ( char* com_list, struct char_data* mob, + struct char_data* actor, struct obj_data* obj, + void* vo ); + + /*************************************************************************** + * 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; + + while ( *pointer != '\n' && *pointer != '\0' ) + pointer++; + if ( *pointer == '\n' ) + *pointer++ = '\0'; + if ( *pointer == '\r' ) + *pointer++ = '\0'; + + return ( pointer ); + + } + + /* we need str_infix here because strstr is not case insensitive */ + + bool str_infix( const char *astr, const char *bstr ) + { + int sstr1; + int sstr2; + int ichar; + char c0; + + if ((c0 = LOWER(astr[0])) == '\0') + return FALSE; + + sstr1 = strlen(astr); + sstr2 = strlen(bstr); + + for ( ichar = 0; ichar <= sstr2 - sstr1; ichar++ ) { + if (c0 == LOWER(bstr[ichar]) && !str_prefix(astr, bstr + ichar)) + return FALSE; + } + + return TRUE; + } + + /* 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. + */ + int mprog_seval( char *lhs, char *opr, char *rhs ) + { + + if ( !str_cmp( opr, "==" ) ) + return ( !str_cmp( lhs, rhs ) ); + if ( !str_cmp( opr, "!=" ) ) + return ( str_cmp( lhs, rhs ) ); + if ( !str_cmp( opr, "/" ) ) + return ( !str_infix( rhs, lhs ) ); + if ( !str_cmp( opr, "!/" ) ) + return ( str_infix( rhs, lhs ) ); + + bug ( "Improper MOBprog operator\n\r", 0 ); + return 0; + + } + + int 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 MOBprog 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 + */ + int mprog_do_ifchck( char *ifchck, struct char_data *mob, struct char_data *actor, + struct obj_data *obj, void *vo, struct char_data *rndm) + { + + char buf[ MAX_INPUT_LENGTH ]; + char arg[ MAX_INPUT_LENGTH ]; + char opr[ MAX_INPUT_LENGTH ]; + char val[ MAX_INPUT_LENGTH ]; + struct char_data *vict = (struct char_data *) vo; + struct obj_data *v_obj = (struct 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", (int)mob_index[mob->nr].virtual); + 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_index[mob->nr].virtual); + 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_index[mob->nr].virtual); + 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_index[mob->nr].virtual ); + 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, "rand" ) ) + { + return ( number_percent() <= atoi(arg) ); + } + + 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; + default: + bug ( "Mob: %d bad argument to 'ispc'", + mob_index[mob->nr].virtual ); + 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; + default: + bug ("Mob: %d bad argument to 'isnpc'", + mob_index[mob->nr].virtual ); + 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; + default: + bug ( "Mob: %d bad argument to 'isgood'", + mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "isfight" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': return ( mob->specials.fighting ) ? 1 : 0; + case 'n': if ( actor ) + return ( actor->specials.fighting ) ? 1 : 0; + else return -1; + case 't': if ( vict ) + return ( vict->specials.fighting ) ? 1 : 0; + else return -1; + case 'r': if ( rndm ) + return ( rndm->specials.fighting ) ? 1 : 0; + else return -1; + default: + bug ( "Mob: %d bad argument to 'isfight'", + mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "isimmort" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': return ( GET_LEVEL( mob ) > LEVEL_IMMORT ); + case 'n': if ( actor ) + return ( GET_LEVEL( actor ) > LEVEL_IMMORT ); + else return -1; + case 't': if ( vict ) + return ( GET_LEVEL( vict ) > LEVEL_IMMORT ); + else return -1; + case 'r': if ( rndm ) + return ( GET_LEVEL( rndm ) > LEVEL_IMMORT ); + else return -1; + default: + bug ( "Mob: %d bad argument to 'isimmort'", + mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "ischarmed" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': return IS_AFFECTED( mob, 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; + default: + bug ( "Mob: %d bad argument to 'ischarmed'", + mob_index[mob->nr].virtual ); + 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; + default: + bug ( "Mob: %d bad argument to 'isfollow'", + mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "isaffected" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': return ( mob->specials.affected_by & atoi( arg ) ); + case 'n': if ( actor ) + return ( actor->specials.affected_by & atoi( arg ) ); + else return -1; + case 't': if ( vict ) + return ( vict->specials.affected_by & atoi( arg ) ); + else return -1; + case 'r': if ( rndm ) + return ( rndm->specials.affected_by & atoi( arg ) ); + else return -1; + default: + bug ( "Mob: %d bad argument to 'isaffected'", + mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "hitprcnt" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': lhsvl = mob->points.hit / mob->points.max_hit; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + case 'n': if ( actor ) + { + lhsvl = actor->points.hit / actor->points.max_hit; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 't': if ( vict ) + { + lhsvl = vict->points.hit / vict->points.max_hit; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'r': if ( rndm ) + { + lhsvl = rndm->points.hit / rndm->points.max_hit; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'hitprcnt'", + mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "inroom" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': lhsvl = mob->in_room; + rhsvl = atoi(val); + return mprog_veval( lhsvl, opr, rhsvl ); + case 'n': if ( actor ) + { + lhsvl = actor->in_room; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 't': if ( vict ) + { + lhsvl = vict->in_room; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'r': if ( rndm ) + { + lhsvl = rndm->in_room; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'inroom'", + mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "sex" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': lhsvl = mob->player.sex; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + case 'n': if ( actor ) + { + lhsvl = actor->player.sex; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 't': if ( vict ) + { + lhsvl = vict->player.sex; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'r': if ( rndm ) + { + lhsvl = rndm->player.sex; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'sex'", + mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "position" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': lhsvl = mob->specials.position; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + case 'n': if ( actor ) + { + lhsvl = actor->specials.position; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 't': if ( vict ) + { + lhsvl = vict->specials.position; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'r': if ( rndm ) + { + lhsvl = rndm->specials.position; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'position'", + mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "level" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': lhsvl = GET_LEVEL( mob ); + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + case 'n': if ( actor ) + { + lhsvl = GET_LEVEL( actor ); + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 't': if ( vict ) + { + lhsvl = GET_LEVEL( vict ); + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'r': if ( rndm ) + { + lhsvl = GET_LEVEL( rndm ); + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'level'", + mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "class" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': lhsvl = mob->player.class; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + case 'n': if ( actor ) + { + lhsvl = actor->player.class; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 't': if ( vict ) + { + lhsvl = vict->player.class; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'r': if ( rndm ) + { + lhsvl = rndm->player.class; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'class'", mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "goldamt" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': lhsvl = mob->points.gold; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + case 'n': if ( actor ) + { + lhsvl = actor->points.gold; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 't': if ( vict ) + { + lhsvl = vict->points.gold; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'r': if ( rndm ) + { + lhsvl = rndm->points.gold; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'goldamt'", mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "objtype" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'o': if ( obj ) + { + lhsvl = obj->obj_flags.type_flag; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'p': if ( v_obj ) + { + lhsvl = v_obj->obj_flags.type_flag; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'objtype'", mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "objval0" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'o': if ( obj ) + { + lhsvl = obj->obj_flags.value[0]; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'p': if ( v_obj ) + { + lhsvl = v_obj->obj_flags.value[0]; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'objval0'", mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "objval1" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'o': if ( obj ) + { + lhsvl = obj->obj_flags.value[1]; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'p': if ( v_obj ) + { + lhsvl = v_obj->obj_flags.value[1]; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'objval1'", mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "objval2" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'o': if ( obj ) + { + lhsvl = obj->obj_flags.value[2]; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'p': if ( v_obj ) + { + lhsvl = v_obj->obj_flags.value[2]; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'objval2'", mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "objval3" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'o': if ( obj ) + { + lhsvl = obj->obj_flags.value[3]; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'p': if ( v_obj ) + { + lhsvl = v_obj->obj_flags.value[3]; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'objval3'", mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "number" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': lhsvl = mob->points.gold; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + case 'n': if ( actor ) + { + if IS_NPC( actor ) + { + lhsvl = mob_index[actor->nr].virtual; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + } + else + return -1; + case 't': if ( vict ) + { + if IS_NPC( actor ) + { + lhsvl = mob_index[vict->nr].virtual; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + } + else + return -1; + case 'r': if ( rndm ) + { + if IS_NPC( actor ) + { + lhsvl = mob_index[rndm->nr].virtual; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + } + else return -1; + case 'o': if ( obj ) + { + lhsvl = obj_index[obj->item_number].virtual; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + case 'p': if ( v_obj ) + { + lhsvl = obj_index[v_obj->item_number].virtual; + rhsvl = atoi( val ); + return mprog_veval( lhsvl, opr, rhsvl ); + } + else + return -1; + default: + bug ( "Mob: %d bad argument to 'number'", mob_index[mob->nr].virtual ); + return -1; + } + } + + if ( !str_cmp( buf, "name" ) ) + { + switch ( arg[1] ) /* arg should be "$*" so just get the letter */ + { + case 'i': return mprog_seval( mob->player.name, opr, val ); + case 'n': if ( actor ) + return mprog_seval( actor->player.name, opr, val ); + else + return -1; + case 't': if ( vict ) + return mprog_seval( vict->player.name, opr, val ); + else + return -1; + case 'r': if ( rndm ) + return mprog_seval( rndm->player.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_index[mob->nr].virtual ); + 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 MOBprogram (return error) + */ + bug ( "Mob: %d unknown ifchck", mob_index[mob->nr].virtual ); + return -1; + + } + /* Quite a long and arduous function, this guy handles the control + * flow part of MOBprograms. 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 + * MOBprograms, so if the mud crashes here, check the mob carefully! + */ + char *mprog_process_if( char *ifchck, char *com_list, struct char_data *mob, + struct char_data *actor, struct obj_data *obj, void *vo, + struct char_data *rndm ) + { + + char null[ 1 ]; + char buf[ MAX_INPUT_LENGTH ]; + char *morebuf = '\0'; + char *cmnd = '\0'; + int loopdone = FALSE; + int flag = FALSE; + int legal; + + *null = '\0'; + + /* check for trueness of the ifcheck */ + if ( ( legal = mprog_do_ifchck( ifchck, mob, actor, obj, vo, rndm ) ) ) + if ( legal == 1 ) + flag = TRUE; + else + return null; + + 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", mob_index[mob->nr].virtual ); + return null; + } + morebuf = one_argument( cmnd, buf ); + if ( !str_cmp( buf, "or" ) ) + { + if ( ( legal = mprog_do_ifchck( morebuf,mob,actor,obj,vo,rndm ) ) ) + if ( legal == 1 ) + flag = TRUE; + else + return null; + } + 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); + while ( *cmnd==' ' ) + cmnd++; + if ( *com_list == '\0' ) + return null; + cmnd = com_list; + com_list = mprog_next_command( com_list ); + morebuf = one_argument( cmnd,buf ); + continue; + } + if ( !str_cmp( buf, "break" ) ) + return null; + 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_index[mob->nr].virtual ); + return null; + } + morebuf = one_argument( cmnd,buf ); + } + return com_list; + } + mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm ); + cmnd = com_list; + com_list = mprog_next_command( com_list ); + while ( *cmnd == ' ' ) + cmnd++; + if ( *cmnd == '\0' ) + { + bug ( "Mob: %d missing else or endif", mob_index[mob->nr].virtual ); + return null; + } + 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_index[mob->nr].virtual ); + return null; + } + 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_index[mob->nr].virtual ); + return null; + } + 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 ); + while ( *cmnd == ' ' ) + cmnd++; + if ( *com_list == '\0' ) + return null; + 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_index[mob->nr].virtual ); + return null; + } + if ( !str_cmp( buf, "break" ) ) + return null; + if ( !str_cmp( buf, "endif" ) ) + return com_list; + mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm ); + 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_index[mob->nr].virtual ); + return null; + } + 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, struct char_data *mob, struct char_data *actor, + struct obj_data *obj, void *vo, struct char_data *rndm ) + { + static char *he_she [] = { "it", "he", "she" }; + static char *him_her [] = { "it", "him", "her" }; + static char *his_her [] = { "its", "his", "her" }; + struct char_data *vict = (struct char_data *) vo; + struct obj_data *v_obj = (struct obj_data *) vo; + + *t = '\0'; + switch ( ch ) { + case 'i': + one_argument( mob->player.name, t ); + break; + + case 'I': + strcpy( t, mob->player.short_descr ); + break; + + case 'n': + if ( actor ) { + if ( CAN_SEE( mob,actor ) ) { + if ( !IS_NPC( actor ) ) { + strcpy(t, actor->player.name); + } else + one_argument( actor->player.name, t ); + } else + strcpy(t, "Someone"); + } + break; + + case 'N': + if ( actor ) + if ( CAN_SEE( mob, actor ) ) + if ( IS_NPC( actor ) ) + strcpy( t, actor->player.short_descr ); + else + { + strcpy( t, actor->player.name ); + strcat( t, " " ); + strcat( t, actor->player.title ); + } + else + strcpy( t, "someone" ); + break; + + case 't': + if ( vict ) { + if ( CAN_SEE( mob, vict ) ) { + if ( !IS_NPC( vict ) ) + strcpy(t, vict->player.name); + else + one_argument( vict->player.name, t ); + } else + strcpy(t, "Someone"); + } + break; + + case 'T': + if ( vict ) + if ( CAN_SEE( mob, vict ) ) + if ( IS_NPC( vict ) ) + strcpy( t, vict->player.short_descr ); + else + { + strcpy( t, vict->player.name ); + strcat( t, " " ); + strcat( t, vict->player.title ); + } + else + strcpy( t, "someone" ); + break; + + case 'r': + if ( rndm ) { + if ( CAN_SEE( mob, rndm ) ) { + if ( !IS_NPC( rndm ) ) + strcpy(t, rndm->player.name); + else + one_argument( rndm->player.name, t ); + } else + strcpy(t, "Someone"); + } + break; + + case 'R': + if ( rndm ) + if ( CAN_SEE( mob, rndm ) ) + if ( IS_NPC( rndm ) ) + strcpy(t,rndm->player.short_descr); + else + { + strcpy( t, rndm->player.name ); + strcat( t, " " ); + strcat( t, rndm->player.title ); + } + else + strcpy( t, "someone" ); + break; + + case 'e': + if ( actor ) + CAN_SEE( mob, actor ) ? strcpy( t, he_she[ actor->player.sex ] ) + : strcpy( t, "someone" ); + break; + + case 'm': + if ( actor ) + CAN_SEE( mob, actor ) ? strcpy( t, him_her[ actor->player.sex ] ) + : strcpy( t, "someone" ); + break; + + case 's': + if ( actor ) + CAN_SEE( mob, actor ) ? strcpy( t, his_her[ actor->player.sex ] ) + : strcpy( t, "someone's" ); + break; + + case 'E': + if ( vict ) + CAN_SEE( mob, vict ) ? strcpy( t, he_she[ vict->player.sex ] ) + : strcpy( t, "someone" ); + break; + + case 'M': + if ( vict ) + CAN_SEE( mob, vict ) ? strcpy( t, him_her[ vict->player.sex ] ) + : strcpy( t, "someone" ); + break; + + case 'S': + if ( vict ) + CAN_SEE( mob, vict ) ? strcpy( t, his_her[ vict->player.sex ] ) + : strcpy( t, "someone's" ); + break; + + case 'j': + strcpy( t, he_she[ mob->player.sex ] ); + break; + + case 'k': + strcpy( t, him_her[ mob->player.sex ] ); + break; + + case 'l': + strcpy( t, his_her[ mob->player.sex ] ); + break; + + case 'J': + if ( rndm ) + CAN_SEE( mob, rndm ) ? strcpy( t, he_she[ rndm->player.sex ] ) + : strcpy( t, "someone" ); + break; + + case 'K': + if ( rndm ) + CAN_SEE( mob, rndm ) ? strcpy( t, him_her[ rndm->player.sex ] ) + : strcpy( t, "someone" ); + break; + + case 'L': + if ( rndm ) + CAN_SEE( mob, rndm ) ? strcpy( t, his_her[ rndm->player.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_description ) + : 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_description ) + : 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_index[mob->nr].virtual ); + 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, struct char_data *mob, struct char_data *actor, + struct obj_data *obj, void *vo, struct char_data *rndm ) + { + 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 != '$' ) + { + *point++ = *str++; + continue; + } + str++; + mprog_translate( *str, tmp, mob, actor, obj, vo, rndm ); + i = tmp; + ++str; + while ( ( *point = *i ) != '\0' ) + ++point, ++i; + } + *point = '\0'; + command_interpreter( mob, buf ); + + return; + + } + + /* The main focus of the MOBprograms. 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, struct char_data *mob, struct char_data *actor, + struct obj_data *obj, void *vo) + { + + char tmpcmndlst[ MAX_STRING_LENGTH ]; + char buf [ MAX_INPUT_LENGTH ]; + char *morebuf; + char *command_list; + char *cmnd; + struct char_data *rndm = NULL; + struct char_data *vch = NULL; + int count = 0; + + if IS_AFFECTED( mob, AFF_CHARM ) + return; + + /* get a random visable mortal player who is in the room with the mob */ + for ( vch = world[mob->in_room].people; vch; vch = vch->next_in_room ) + if ( !IS_NPC( vch ) + && vch->player.level < LEVEL_IMPL-3 + && CAN_SEE( mob, vch ) ) + { + if ( number_range( 0, count ) == 0 ) + rndm = vch; + count++; + } + + strcpy( tmpcmndlst, com_list ); + command_list = tmpcmndlst; + cmnd = command_list; + command_list = mprog_next_command( command_list ); + while ( *cmnd != '\0' ) + { + morebuf = one_argument( cmnd, buf ); + if ( !str_cmp( buf, "if" ) ) + command_list = mprog_process_if( morebuf, command_list, mob, + actor, obj, vo, rndm ); + else + mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm ); + 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, struct char_data *mob, struct char_data *actor, + struct obj_data *obj, void *vo, int type ) + { + + char temp1[ MAX_STRING_LENGTH ]; + char temp2[ MAX_INPUT_LENGTH ]; + char word[ MAX_INPUT_LENGTH ]; + MPROG_DATA *mprg; + char *list; + char *start; + char *dupl; + char *end; + int i; + + for ( mprg = mob_index[mob->nr].mobprogs; mprg != NULL; mprg = mprg->next ) + if ( mprg->type & type ) + { + strcpy( temp1, mprg->arglist ); + list = temp1; + while(isspace(*list)) list++; + for ( i = 0; i < strlen( list ); i++ ) + list[i] = LOWER( list[i] ); + strcpy( temp2, arg ); + dupl = 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 == NULL ) ) + { + mprog_driver( mprg->comlist, mob, actor, obj, vo ); + 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 == NULL ) ) + { + mprog_driver( mprg->comlist, mob, actor, obj, vo ); + break; + } + else + dupl = start+1; + } + } + + return; + + } + + void mprog_percent_check( struct char_data *mob, struct char_data *actor, struct obj_data *obj, + void *vo, int type) + { + MPROG_DATA * mprg; + + for ( mprg = mob_index[mob->nr].mobprogs; mprg != NULL; mprg = mprg->next ) + if ( ( mprg->type & type ) + && ( number_percent( ) < atoi( mprg->arglist ) ) ) + { + mprog_driver( mprg->comlist, mob, actor, obj, vo ); + if ( type != GREET_PROG && type != ALL_GREET_PROG ) + break; + } + + 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, struct char_data *mob, struct char_data *ch, + struct obj_data *obj, void *vo) + { + + MPROG_ACT_LIST * tmp_act; + + if ( IS_NPC( mob ) + && ( mob_index[mob->nr].progtypes & ACT_PROG ) ) + { + tmp_act = malloc( sizeof( MPROG_ACT_LIST ) ); + if ( mob->mpactnum > 0 ) + tmp_act->next = mob->mpact->next; + 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( struct char_data *mob, struct char_data *ch, int amount ) + { + + char buf[ MAX_STRING_LENGTH ]; + MPROG_DATA *mprg; + struct obj_data *obj; + + if ( IS_NPC( mob ) + && ( mob_index[mob->nr].progtypes & BRIBE_PROG ) ) + { + obj = create_money(amount); + obj_to_char( obj, mob ); + mob->points.gold -= amount; + + for ( mprg = mob_index[mob->nr].mobprogs; mprg != NULL; mprg = mprg->next ) + if ( ( mprg->type & BRIBE_PROG ) + && ( amount >= atoi( mprg->arglist ) ) ) + { + mprog_driver( mprg->comlist, mob, ch, obj, NULL ); + break; + } + } + + return; + + } + + void mprog_death_trigger( struct char_data *mob, struct char_data *killer ) + { + + if ( IS_NPC( mob ) + && ( mob_index[mob->nr].progtypes & DEATH_PROG ) ) + { + mprog_percent_check( mob, killer, NULL, NULL, DEATH_PROG ); + } + + death_cry( mob ); + return; + + } + + void mprog_entry_trigger( struct char_data *mob ) + { + + if ( IS_NPC( mob ) + && ( mob_index[mob->nr].progtypes & ENTRY_PROG ) ) + mprog_percent_check( mob, NULL, NULL, NULL, ENTRY_PROG ); + + return; + + } + + void mprog_fight_trigger( struct char_data *mob, struct char_data *ch ) + { + + if ( IS_NPC( mob ) + && ( mob_index[mob->nr].progtypes & FIGHT_PROG ) ) + mprog_percent_check( mob, ch, NULL, NULL, FIGHT_PROG ); + + return; + + } + + void mprog_give_trigger( struct char_data *mob, struct char_data *ch, struct obj_data *obj ) + { + + char buf[MAX_INPUT_LENGTH]; + MPROG_DATA *mprg; + + if ( IS_NPC( mob ) + && ( mob_index[mob->nr].progtypes & GIVE_PROG ) ) + for ( mprg = mob_index[mob->nr].mobprogs; mprg != NULL; mprg = mprg->next ) + { + one_argument( mprg->arglist, buf ); + if ( ( mprg->type & GIVE_PROG ) + && ( ( !str_infix( obj->name, mprg->arglist ) ) + || ( !str_cmp( "all", buf ) ) ) ) + { + mprog_driver( mprg->comlist, mob, ch, obj, NULL ); + break; + } + } + + return; + + } + + void mprog_greet_trigger( struct char_data *ch ) + { + + struct char_data *vmob; + + for ( vmob = world[ch->in_room].people; vmob != NULL; vmob = vmob->next_in_room ) + if ( IS_NPC( vmob ) + && ch != vmob + && CAN_SEE( vmob, ch ) + && ( vmob->specials.fighting == NULL ) + && AWAKE( vmob ) + && ( mob_index[vmob->nr].progtypes & GREET_PROG) ) + mprog_percent_check( vmob, ch, NULL, NULL, GREET_PROG ); + else + if ( IS_NPC( vmob ) + && ( vmob->specials.fighting == NULL ) + && AWAKE( vmob ) + && ( mob_index[vmob->nr].progtypes & ALL_GREET_PROG ) ) + mprog_percent_check(vmob,ch,NULL,NULL,ALL_GREET_PROG); + + return; + + } + + void mprog_hitprcnt_trigger( struct char_data *mob, struct char_data *ch) + { + + MPROG_DATA *mprg; + + if ( IS_NPC( mob ) + && ( mob_index[mob->nr].progtypes & HITPRCNT_PROG ) ) + for ( mprg = mob_index[mob->nr].mobprogs; mprg != NULL; mprg = mprg->next ) + if ( ( mprg->type & HITPRCNT_PROG ) + && ( ( 100*mob->points.hit / mob->points.max_hit ) < atoi( mprg->arglist ) ) ) + { + mprog_driver( mprg->comlist, mob, ch, NULL, NULL ); + break; + } + + return; + + } + + void mprog_random_trigger( struct char_data *mob ) + { + + if ( mob_index[mob->nr].progtypes & RAND_PROG) + mprog_percent_check(mob,NULL,NULL,NULL,RAND_PROG); + + return; + + } + + void mprog_speech_trigger( char *txt, struct char_data *mob ) + { + + struct char_data *vmob; + + for ( vmob = world[mob->in_room].people; vmob != NULL; vmob = vmob->next_in_room ) + if ( IS_NPC( vmob ) && ( mob_index[vmob->nr].progtypes & SPEECH_PROG ) ) + mprog_wordlist_check( txt, vmob, mob, NULL, NULL, SPEECH_PROG ); + + return; + + } + diff -c oldsrc/structs.h src/structs.h *** oldsrc/structs.h Wed Jun 8 18:14:02 1994 --- src/structs.h Mon Jun 13 14:23:37 1994 *************** *** 472,477 **** --- 472,514 ---- typedef struct memory_rec_struct memory_rec; + /* MOBProgram foo */ + struct mob_prog_act_list { + struct mob_prog_act_list *next; + char *buf; + struct char_data *ch; + struct obj_data *obj; + void *vo; + }; + typedef struct mob_prog_act_list MPROG_ACT_LIST; + + struct mob_prog_data { + struct mob_prog_data *next; + int type; + char *arglist; + char *comlist; + }; + + typedef struct mob_prog_data MPROG_DATA; + + extern bool MOBTrigger; + + #define ERROR_PROG -1 + #define IN_FILE_PROG 0 + #define ACT_PROG 1 + #define SPEECH_PROG 2 + #define RAND_PROG 4 + #define FIGHT_PROG 8 + #define DEATH_PROG 16 + #define HITPRCNT_PROG 32 + #define ENTRY_PROG 64 + #define GREET_PROG 128 + #define ALL_GREET_PROG 256 + #define GIVE_PROG 512 + #define BRIBE_PROG 1024 + + /* end of MOBProg foo */ + /* This structure is purely intended to be an easy way to transfer */ /* and return information about time (real or mudwise). */ struct time_info_data { *************** *** 649,654 **** --- 686,694 ---- struct follow_type *followers; /* List of chars followers */ struct char_data *master; /* Who is char following? */ + /* MOBprog foo */ + MPROG_ACT_LIST *mpact; + int mpactnum; }; diff -c oldsrc/utility.c src/utility.c *** oldsrc/utility.c Wed Jun 8 18:14:02 1994 --- src/utility.c Mon Jun 13 12:29:47 1994 *************** *** 40,61 **** /* creates a random number in interval [from;to] */ int number(int from, int to) { ! return((random() % (to - from + 1)) + from); } - /* simulates dice roll */ int dice(int number, int size) { ! int r; ! int sum = 0; ! assert(size >= 1); ! for (r = 1; r <= number; r++) ! sum += ((random() % size) + 1); ! return(sum); } --- 40,66 ---- /* creates a random number in interval [from;to] */ int number(int from, int to) { ! /* changed to use the Mitchell-Moore algorithm */ ! return(number_range(from, to)); } /* simulates dice roll */ int dice(int number, int size) { ! /* changed to use the mitchell-moore algorith. */ ! int idice; ! int sum; ! switch ( size ) { ! case 0: return 0; ! case 1: return number; ! } ! for ( idice = 0, sum = 0; idice < number; idice++ ) ! sum += number_range( 1, size ); ! ! return sum; } *************** *** 310,314 **** (void) write(sock, off_string, sizeof(off_string)); } - --- 315,318 ---- diff -c oldsrc/xrand.c src/xrand.c *** oldsrc/xrand.c Fri Jun 10 20:55:54 1994 --- src/xrand.c Mon Jun 13 12:34:15 1994 *************** *** 0 **** --- 1,89 ---- + #include <sys/time.h> + #include <time.h> + + /* + * Generate a random number. + */ + int number_range( int from, int to ) + { + int power; + int number; + + if ( ( to = to - from + 1 ) <= 1 ) + return from; + + for ( power = 2; power < to; power <<= 1 ) + ; + + while ( ( number = number_mm( ) & (power - 1) ) >= to ) + ; + + return from + number; + } + + /* + * Generate a percentile roll. + */ + int number_percent( void ) + { + int percent; + + while ( ( percent = number_mm( ) & (128-1) ) > 99 ) + ; + + return 1 + percent; + } + + /* + * I've gotten too many bad reports on OS-supplied random number generators. + * This is the Mitchell-Moore algorithm from Knuth Volume II. + * Best to leave the constants alone unless you've read Knuth. + * -- Furey + */ + static int rgiState[2+55]; + + void init_mm( ) + { + int *piState; + int iState; + struct timeval last_time; + int current_time; + + gettimeofday(&last_time, 0); + current_time = last_time.tv_sec; + piState = &rgiState[2]; + + piState[-2] = 55 - 55; + piState[-1] = 55 - 24; + + piState[0] = ((int) current_time) & ((1 << 30) - 1); + piState[1] = 1; + for ( iState = 2; iState < 55; iState++ ) + { + piState[iState] = (piState[iState-1] + piState[iState-2]) + & ((1 << 30) - 1); + } + return; + } + + int number_mm( void ) + { + int *piState; + int iState1; + int iState2; + int iRand; + + piState = &rgiState[2]; + iState1 = piState[-2]; + iState2 = piState[-1]; + iRand = (piState[iState1] + piState[iState2]) + & ((1 << 30) - 1); + piState[iState1] = iRand; + if ( ++iState1 == 55 ) + iState1 = 0; + if ( ++iState2 == 55 ) + iState2 = 0; + piState[-2] = iState1; + piState[-1] = iState2; + return iRand >> 6; + }