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;
+ }