MOB_PROG.C
上传用户:kesirui
上传日期:2007-01-07
资源大小:263k
文件大小:46k
源码类别:

Internet/网络编程

开发平台:

WINDOWS

  1. /***************************************************************************
  2.  *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
  3.  *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
  4.  *                                                                         *
  5.  *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
  6.  *  Chastain, Michael Quan, and Mitchell Tse.                              *
  7.  *                                                                         *
  8.  *  In order to use any part of this Merc Diku Mud, you must comply with   *
  9.  *  both the original Diku license in 'license.doc' as well the Merc       *
  10.  *  license in 'license.txt'.  In particular, you may not remove either of *
  11.  *  these copyright notices.                                               *
  12.  *                                                                         *
  13.  *  Much time and thought has gone into this software and you are          *
  14.  *  benefitting.  We hope that you share your changes too.  What goes      *
  15.  *  around, comes around.                                                  *
  16.  ***************************************************************************/
  17. /***************************************************************************
  18.  *  The MOBprograms have been contributed by N'Atas-ha.  Any support for   *
  19.  *  these routines should not be expected from Merc Industries.  However,  *
  20.  *  under no circumstances should the blame for bugs, etc be placed on     *
  21.  *  Merc Industries.  They are not guaranteed to work on all systems due   *
  22.  *  to their frequent use of strxxx functions.  They are also not the most *
  23.  *  efficient way to perform their tasks, but hopefully should be in the   *
  24.  *  easiest possible way to install and begin using. Documentation for     *
  25.  *  such installation can be found in INSTALL.  Enjoy...         N'Atas-Ha *
  26.  ***************************************************************************/
  27. #include <sys/types.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <stdlib.h>
  31. #include <ctype.h>
  32. #include "merc.h"
  33. /*
  34.  * Local function prototypes
  35.  */
  36. char * mprog_next_command args( ( char* clist ) );
  37. bool mprog_seval args( ( char* lhs, char* opr, char* rhs ) );
  38. bool mprog_veval args( ( int lhs, char* opr, int rhs ) );
  39. bool mprog_do_ifchck args( ( char* ifchck, CHAR_DATA* mob,
  40.        CHAR_DATA* actor, OBJ_DATA* obj,
  41.        void* vo, CHAR_DATA* rndm ) );
  42. char * mprog_process_if args( ( char* ifchck, char* com_list, 
  43.        CHAR_DATA* mob, CHAR_DATA* actor,
  44.        OBJ_DATA* obj, void* vo,
  45.        CHAR_DATA* rndm ) );
  46. void mprog_translate args( ( char ch, char* t, CHAR_DATA* mob,
  47.        CHAR_DATA* actor, OBJ_DATA* obj,
  48.        void* vo, CHAR_DATA* rndm ) );
  49. void mprog_process_cmnd args( ( char* cmnd, CHAR_DATA* mob, 
  50.        CHAR_DATA* actor, OBJ_DATA* obj,
  51.        void* vo, CHAR_DATA* rndm ) );
  52. void mprog_driver args( ( char* com_list, CHAR_DATA* mob,
  53.        CHAR_DATA* actor, OBJ_DATA* obj,
  54.        void* vo ) );
  55. /***************************************************************************
  56.  * Local function code and brief comments.
  57.  */
  58. /* if you dont have these functions, you damn well should... */
  59. #ifdef DUNNO_STRSTR
  60. char * strstr(s1,s2) const char *s1; const char *s2;
  61. {
  62.   char *cp;
  63.   int i,j=strlen(s1)-strlen(s2),k=strlen(s2);
  64.   if(j<0)
  65.     return NULL;
  66.   for(i=0; i<=j && strncmp(s1++,s2, k)!=0; i++);
  67.   return (i>j) ? NULL : (s1-1);
  68. }
  69. #endif
  70. /* Used to get sequential lines of a multi line string (separated by "nr")
  71.  * Thus its like one_argument(), but a trifle different. It is destructive
  72.  * to the multi line string argument, and thus clist must not be shared.
  73.  */
  74. char *mprog_next_command( char *clist )
  75. {
  76.   char *pointer = clist;
  77.   while ( *pointer != 'n' && *pointer != '' )
  78.     pointer++;
  79.   if ( *pointer == 'n' )
  80.     *pointer++ = '';
  81.   if ( *pointer == 'r' )
  82.     *pointer++ = '';
  83.   return ( pointer );
  84. }
  85. /* These two functions do the basic evaluation of ifcheck operators.
  86.  *  It is important to note that the string operations are not what
  87.  *  you probably expect.  Equality is exact and division is substring.
  88.  *  remember that lhs has been stripped of leading space, but can
  89.  *  still have trailing spaces so be careful when editing since:
  90.  *  "guard" and "guard " are not equal.
  91.  */
  92. bool mprog_seval( char *lhs, char *opr, char *rhs )
  93. {
  94.   if ( !str_cmp( opr, "==" ) )
  95.     return ( bool )( !str_cmp( lhs, rhs ) );
  96.   if ( !str_cmp( opr, "!=" ) )
  97.     return ( bool )( str_cmp( lhs, rhs ) );
  98.   if ( !str_cmp( opr, "/" ) )
  99.     return ( bool )( !str_infix( rhs, lhs ) );
  100.   if ( !str_cmp( opr, "!/" ) )
  101.     return ( bool )( str_infix( rhs, lhs ) );
  102.   bug ( "Improper MOBprog operatornr", 0 );
  103.   return 0;
  104. }
  105. bool mprog_veval( int lhs, char *opr, int rhs )
  106. {
  107.   if ( !str_cmp( opr, "==" ) )
  108.     return ( lhs == rhs );
  109.   if ( !str_cmp( opr, "!=" ) )
  110.     return ( lhs != rhs );
  111.   if ( !str_cmp( opr, ">" ) )
  112.     return ( lhs > rhs );
  113.   if ( !str_cmp( opr, "<" ) )
  114.     return ( lhs < rhs );
  115.   if ( !str_cmp( opr, ">=" ) )
  116.     return ( lhs <= rhs );
  117.   if ( !str_cmp( opr, ">=" ) )
  118.     return ( lhs >= rhs );
  119.   if ( !str_cmp( opr, "&" ) )
  120.     return ( lhs & rhs );
  121.   if ( !str_cmp( opr, "|" ) )
  122.     return ( lhs | rhs );
  123.   bug ( "Improper MOBprog operatornr", 0 );
  124.   return 0;
  125. }
  126. /* This function performs the evaluation of the if checks.  It is
  127.  * here that you can add any ifchecks which you so desire. Hopefully
  128.  * it is clear from what follows how one would go about adding your
  129.  * own. The syntax for an if check is: ifchck ( arg ) [opr val]
  130.  * where the parenthesis are required and the opr and val fields are
  131.  * optional but if one is there then both must be. The spaces are all
  132.  * optional. The evaluation of the opr expressions is farmed out
  133.  * to reduce the redundancy of the mammoth if statement list.
  134.  * If there are errors, then return -1 otherwise return boolean 1,0
  135.  */
  136. bool mprog_do_ifchck( char *ifchck, CHAR_DATA *mob, CHAR_DATA *actor,
  137.      OBJ_DATA *obj, void *vo, CHAR_DATA *rndm)
  138. {
  139.   char buf[ MAX_INPUT_LENGTH ];
  140.   char arg[ MAX_INPUT_LENGTH ];
  141.   char opr[ MAX_INPUT_LENGTH ];
  142.   char val[ MAX_INPUT_LENGTH ];
  143.   CHAR_DATA *vict = (CHAR_DATA *) vo;
  144.   OBJ_DATA *v_obj = (OBJ_DATA  *) vo;
  145.   char     *bufpt = buf;
  146.   char     *argpt = arg;
  147.   char     *oprpt = opr;
  148.   char     *valpt = val;
  149.   char     *point = ifchck;
  150.   int       lhsvl;
  151.   int       rhsvl;
  152.   if ( *point == '' ) 
  153.     {
  154.       bug ( "Mob: %d null ifchck", mob->pIndexData->vnum ); 
  155.       return -1;
  156.     }   
  157.   /* skip leading spaces */
  158.   while ( *point == ' ' )
  159.     point++;
  160.   /* get whatever comes before the left paren.. ignore spaces */
  161.   while ( *point != '(' ) 
  162.     if ( *point == '' ) 
  163.       {
  164. bug ( "Mob: %d ifchck syntax error", mob->pIndexData->vnum ); 
  165. return -1;
  166.       }   
  167.     else
  168.       if ( *point == ' ' )
  169. point++;
  170.       else 
  171. *bufpt++ = *point++; 
  172.   *bufpt = '';
  173.   point++;
  174.   /* get whatever is in between the parens.. ignore spaces */
  175.   while ( *point != ')' ) 
  176.     if ( *point == '' ) 
  177.       {
  178. bug ( "Mob: %d ifchck syntax error", mob->pIndexData->vnum ); 
  179. return -1;
  180.       }   
  181.     else
  182.       if ( *point == ' ' )
  183. point++;
  184.       else 
  185. *argpt++ = *point++; 
  186.   *argpt = '';
  187.   point++;
  188.   /* check to see if there is an operator */
  189.   while ( *point == ' ' )
  190.     point++;
  191.   if ( *point == '' ) 
  192.     {
  193.       *opr = '';
  194.       *val = '';
  195.     }   
  196.   else /* there should be an operator and value, so get them */
  197.     {
  198.       while ( ( *point != ' ' ) && ( !isalnum( *point ) ) ) 
  199. if ( *point == '' ) 
  200.   {
  201.     bug ( "Mob: %d ifchck operator without value",
  202.  mob->pIndexData->vnum ); 
  203.     return -1;
  204.   }   
  205. else
  206.   *oprpt++ = *point++; 
  207.       *oprpt = '';
  208.  
  209.       /* finished with operator, skip spaces and then get the value */
  210.       while ( *point == ' ' )
  211. point++;
  212.       for( ; ; )
  213. {
  214.   if ( ( *point != ' ' ) && ( *point == '' ) )
  215.     break;
  216.   else
  217.     *valpt++ = *point++; 
  218. }
  219.       *valpt = '';
  220.     }
  221.   bufpt = buf;
  222.   argpt = arg;
  223.   oprpt = opr;
  224.   valpt = val;
  225.   /* Ok... now buf contains the ifchck, arg contains the inside of the
  226.    *  parentheses, opr contains an operator if one is present, and val
  227.    *  has the value if an operator was present.
  228.    *  So.. basically use if statements and run over all known ifchecks
  229.    *  Once inside, use the argument and expand the lhs. Then if need be
  230.    *  send the lhs,opr,rhs off to be evaluated.
  231.    */
  232.   if ( !str_cmp( buf, "rand" ) )
  233.     {
  234.       return ( number_percent() <= atoi(arg) );
  235.     }
  236.   if ( !str_cmp( buf, "ispc" ) )
  237.     {
  238.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  239. {
  240. case 'i': return 0;
  241. case 'n': if ( actor )
  242.                return ( !IS_NPC( actor ) );
  243.           else return -1;
  244. case 't': if ( vict )
  245.                      return ( !IS_NPC( vict ) );
  246.           else return -1;
  247. case 'r': if ( rndm )
  248.                      return ( !IS_NPC( rndm ) );
  249.           else return -1;
  250. default:
  251.   bug ( "Mob: %d bad argument to 'ispc'", mob->pIndexData->vnum ); 
  252.   return -1;
  253. }
  254.     }
  255.   if ( !str_cmp( buf, "isnpc" ) )
  256.     {
  257.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  258. {
  259. case 'i': return 1;
  260. case 'n': if ( actor )
  261.              return IS_NPC( actor );
  262.           else return -1;
  263. case 't': if ( vict )
  264.                      return IS_NPC( vict );
  265.           else return -1;
  266. case 'r': if ( rndm )
  267.              return IS_NPC( rndm );
  268.           else return -1;
  269. default:
  270.   bug ("Mob: %d bad argument to 'isnpc'", mob->pIndexData->vnum ); 
  271.   return -1;
  272. }
  273.     }
  274.   if ( !str_cmp( buf, "isgood" ) )
  275.     {
  276.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  277. {
  278. case 'i': return IS_GOOD( mob );
  279. case 'n': if ( actor )
  280.              return IS_GOOD( actor );
  281.           else return -1;
  282. case 't': if ( vict )
  283.              return IS_GOOD( vict );
  284.           else return -1;
  285. case 'r': if ( rndm )
  286.              return IS_GOOD( rndm );
  287.           else return -1;
  288. default:
  289.   bug ( "Mob: %d bad argument to 'isgood'", mob->pIndexData->vnum ); 
  290.   return -1;
  291. }
  292.     }
  293.   if ( !str_cmp( buf, "isfight" ) )
  294.     {
  295.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  296. {
  297. case 'i': return ( mob->fighting ) ? 1 : 0;
  298. case 'n': if ( actor )
  299.              return ( actor->fighting ) ? 1 : 0;
  300.           else return -1;
  301. case 't': if ( vict )
  302.              return ( vict->fighting ) ? 1 : 0;
  303.           else return -1;
  304. case 'r': if ( rndm )
  305.              return ( rndm->fighting ) ? 1 : 0;
  306.           else return -1;
  307. default:
  308.   bug ( "Mob: %d bad argument to 'isfight'", mob->pIndexData->vnum ); 
  309.   return -1;
  310. }
  311.     }
  312.   if ( !str_cmp( buf, "isimmort" ) )
  313.     {
  314.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  315. {
  316. case 'i': return ( get_trust( mob ) > LEVEL_IMMORTAL );
  317. case 'n': if ( actor )
  318.              return ( get_trust( actor ) > LEVEL_IMMORTAL );
  319.              else return -1;
  320. case 't': if ( vict )
  321.              return ( get_trust( vict ) > LEVEL_IMMORTAL );
  322.                   else return -1;
  323. case 'r': if ( rndm )
  324.              return ( get_trust( rndm ) > LEVEL_IMMORTAL );
  325.                   else return -1;
  326. default:
  327.   bug ( "Mob: %d bad argument to 'isimmort'", mob->pIndexData->vnum ); 
  328.   return -1;
  329. }
  330.     }
  331.   if ( !str_cmp( buf, "ischarmed" ) )
  332.     {
  333.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  334. {
  335. case 'i': return IS_AFFECTED( mob, AFF_CHARM );
  336. case 'n': if ( actor )
  337.              return IS_AFFECTED( actor, AFF_CHARM );
  338.           else return -1;
  339. case 't': if ( vict )
  340.              return IS_AFFECTED( vict, AFF_CHARM );
  341.           else return -1;
  342. case 'r': if ( rndm )
  343.              return IS_AFFECTED( rndm, AFF_CHARM );
  344.           else return -1;
  345. default:
  346.   bug ( "Mob: %d bad argument to 'ischarmed'",
  347.        mob->pIndexData->vnum ); 
  348.   return -1;
  349. }
  350.     }
  351.   if ( !str_cmp( buf, "isfollow" ) )
  352.     {
  353.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  354. {
  355. case 'i': return ( mob->master != NULL
  356.   && mob->master->in_room == mob->in_room );
  357. case 'n': if ( actor )
  358.              return ( actor->master != NULL
  359.      && actor->master->in_room == actor->in_room );
  360.           else return -1;
  361. case 't': if ( vict )
  362.              return ( vict->master != NULL
  363.      && vict->master->in_room == vict->in_room );
  364.           else return -1;
  365. case 'r': if ( rndm )
  366.              return ( rndm->master != NULL
  367.      && rndm->master->in_room == rndm->in_room );
  368.           else return -1;
  369. default:
  370.   bug ( "Mob: %d bad argument to 'isfollow'", mob->pIndexData->vnum ); 
  371.   return -1;
  372. }
  373.     }
  374.   if ( !str_cmp( buf, "isaffected" ) )
  375.     {
  376.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  377. {
  378. case 'i': return ( mob->affected_by & atoi( arg ) );
  379. case 'n': if ( actor )
  380.              return ( actor->affected_by & atoi( arg ) );
  381.           else return -1;
  382. case 't': if ( vict )
  383.              return ( vict->affected_by & atoi( arg ) );
  384.           else return -1;
  385. case 'r': if ( rndm )
  386.              return ( rndm->affected_by & atoi( arg ) );
  387.           else return -1;
  388. default:
  389.   bug ( "Mob: %d bad argument to 'isaffected'",
  390.        mob->pIndexData->vnum ); 
  391.   return -1;
  392. }
  393.     }
  394.   if ( !str_cmp( buf, "hitprcnt" ) )
  395.     {
  396.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  397. {
  398. case 'i': lhsvl = mob->hit / mob->max_hit;
  399.           rhsvl = atoi( val );
  400.             return mprog_veval( lhsvl, opr, rhsvl );
  401. case 'n': if ( actor )
  402.           {
  403.     lhsvl = actor->hit / actor->max_hit;
  404.     rhsvl = atoi( val );
  405.     return mprog_veval( lhsvl, opr, rhsvl );
  406.   }
  407.           else
  408.     return -1;
  409. case 't': if ( vict )
  410.           {
  411.     lhsvl = vict->hit / vict->max_hit;
  412.     rhsvl = atoi( val );
  413.     return mprog_veval( lhsvl, opr, rhsvl );
  414.   }
  415.           else
  416.     return -1;
  417. case 'r': if ( rndm )
  418.           {
  419.     lhsvl = rndm->hit / rndm->max_hit;
  420.     rhsvl = atoi( val );
  421.     return mprog_veval( lhsvl, opr, rhsvl );
  422.   }
  423.           else
  424.     return -1;
  425. default:
  426.   bug ( "Mob: %d bad argument to 'hitprcnt'", mob->pIndexData->vnum ); 
  427.   return -1;
  428. }
  429.     }
  430.   if ( !str_cmp( buf, "inroom" ) )
  431.     {
  432.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  433. {
  434. case 'i': lhsvl = mob->in_room->vnum;
  435.           rhsvl = atoi(val);
  436.           return mprog_veval( lhsvl, opr, rhsvl );
  437. case 'n': if ( actor )
  438.           {
  439.     lhsvl = actor->in_room->vnum;
  440.     rhsvl = atoi( val );
  441.     return mprog_veval( lhsvl, opr, rhsvl );
  442.   }
  443.           else
  444.     return -1;
  445. case 't': if ( vict )
  446.           {
  447.     lhsvl = vict->in_room->vnum;
  448.     rhsvl = atoi( val );
  449.     return mprog_veval( lhsvl, opr, rhsvl );
  450.   }
  451.           else
  452.     return -1;
  453. case 'r': if ( rndm )
  454.           {
  455.     lhsvl = rndm->in_room->vnum;
  456.     rhsvl = atoi( val );
  457.     return mprog_veval( lhsvl, opr, rhsvl );
  458.   }
  459.           else
  460.     return -1;
  461. default:
  462.   bug ( "Mob: %d bad argument to 'inroom'", mob->pIndexData->vnum ); 
  463.   return -1;
  464. }
  465.     }
  466.   if ( !str_cmp( buf, "sex" ) )
  467.     {
  468.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  469. {
  470. case 'i': lhsvl = mob->sex;
  471.           rhsvl = atoi( val );
  472.           return mprog_veval( lhsvl, opr, rhsvl );
  473. case 'n': if ( actor )
  474.           {
  475.     lhsvl = actor->sex;
  476.     rhsvl = atoi( val );
  477.     return mprog_veval( lhsvl, opr, rhsvl );
  478.   }
  479.           else
  480.     return -1;
  481. case 't': if ( vict )
  482.           {
  483.     lhsvl = vict->sex;
  484.     rhsvl = atoi( val );
  485.     return mprog_veval( lhsvl, opr, rhsvl );
  486.   }
  487.           else
  488.     return -1;
  489. case 'r': if ( rndm )
  490.           {
  491.     lhsvl = rndm->sex;
  492.     rhsvl = atoi( val );
  493.     return mprog_veval( lhsvl, opr, rhsvl );
  494.   }
  495.           else
  496.     return -1;
  497. default:
  498.   bug ( "Mob: %d bad argument to 'sex'", mob->pIndexData->vnum ); 
  499.   return -1;
  500. }
  501.     }
  502.   if ( !str_cmp( buf, "position" ) )
  503.     {
  504.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  505. {
  506. case 'i': lhsvl = mob->position;
  507.           rhsvl = atoi( val );
  508.           return mprog_veval( lhsvl, opr, rhsvl );
  509. case 'n': if ( actor )
  510.           {
  511.     lhsvl = actor->position;
  512.     rhsvl = atoi( val );
  513.     return mprog_veval( lhsvl, opr, rhsvl );
  514.   }
  515.           else
  516.     return -1;
  517. case 't': if ( vict )
  518.           {
  519.     lhsvl = vict->position;
  520.     rhsvl = atoi( val );
  521.     return mprog_veval( lhsvl, opr, rhsvl );
  522.   }
  523.           else
  524.     return -1;
  525. case 'r': if ( rndm )
  526.           {
  527.     lhsvl = rndm->position;
  528.     rhsvl = atoi( val );
  529.     return mprog_veval( lhsvl, opr, rhsvl );
  530.   }
  531.           else
  532.     return -1;
  533. default:
  534.   bug ( "Mob: %d bad argument to 'position'", mob->pIndexData->vnum ); 
  535.   return -1;
  536. }
  537.     }
  538.   if ( !str_cmp( buf, "level" ) )
  539.     {
  540.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  541. {
  542. case 'i': lhsvl = get_trust( mob );
  543.           rhsvl = atoi( val );
  544.           return mprog_veval( lhsvl, opr, rhsvl );
  545. case 'n': if ( actor )
  546.           {
  547.     lhsvl = get_trust( actor );
  548.     rhsvl = atoi( val );
  549.     return mprog_veval( lhsvl, opr, rhsvl );
  550.   }
  551.           else 
  552.     return -1;
  553. case 't': if ( vict )
  554.           {
  555.     lhsvl = get_trust( vict );
  556.     rhsvl = atoi( val );
  557.     return mprog_veval( lhsvl, opr, rhsvl );
  558.   }
  559.           else
  560.     return -1;
  561. case 'r': if ( rndm )
  562.           {
  563.     lhsvl = get_trust( rndm );
  564.     rhsvl = atoi( val );
  565.     return mprog_veval( lhsvl, opr, rhsvl );
  566.   }
  567.           else
  568.     return -1;
  569. default:
  570.   bug ( "Mob: %d bad argument to 'level'", mob->pIndexData->vnum ); 
  571.   return -1;
  572. }
  573.     }
  574.   if ( !str_cmp( buf, "class" ) )
  575.     {
  576.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  577. {
  578. case 'i': lhsvl = mob->class;
  579.           rhsvl = atoi( val );
  580.                   return mprog_veval( lhsvl, opr, rhsvl );
  581. case 'n': if ( actor )
  582.           {
  583.     lhsvl = actor->class;
  584.     rhsvl = atoi( val );
  585.     return mprog_veval( lhsvl, opr, rhsvl );
  586.   }
  587.           else 
  588.     return -1;
  589. case 't': if ( vict )
  590.           {
  591.     lhsvl = vict->class;
  592.     rhsvl = atoi( val );
  593.     return mprog_veval( lhsvl, opr, rhsvl );
  594.   }
  595.           else
  596.     return -1;
  597. case 'r': if ( rndm )
  598.           {
  599.     lhsvl = rndm->class;
  600.     rhsvl = atoi( val );
  601.     return mprog_veval( lhsvl, opr, rhsvl );
  602.   }
  603.           else
  604.     return -1;
  605. default:
  606.   bug ( "Mob: %d bad argument to 'class'", mob->pIndexData->vnum ); 
  607.   return -1;
  608. }
  609.     }
  610.   if ( !str_cmp( buf, "goldamt" ) )
  611.     {
  612.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  613. {
  614. case 'i': lhsvl = mob->gold;
  615.                   rhsvl = atoi( val );
  616.                   return mprog_veval( lhsvl, opr, rhsvl );
  617. case 'n': if ( actor )
  618.           {
  619.     lhsvl = actor->gold;
  620.     rhsvl = atoi( val );
  621.     return mprog_veval( lhsvl, opr, rhsvl );
  622.   }
  623.           else
  624.     return -1;
  625. case 't': if ( vict )
  626.           {
  627.     lhsvl = vict->gold;
  628.     rhsvl = atoi( val );
  629.     return mprog_veval( lhsvl, opr, rhsvl );
  630.   }
  631.           else
  632.     return -1;
  633. case 'r': if ( rndm )
  634.           {
  635.     lhsvl = rndm->gold;
  636.     rhsvl = atoi( val );
  637.     return mprog_veval( lhsvl, opr, rhsvl );
  638.   }
  639.           else
  640.     return -1;
  641. default:
  642.   bug ( "Mob: %d bad argument to 'goldamt'", mob->pIndexData->vnum ); 
  643.   return -1;
  644. }
  645.     }
  646.   if ( !str_cmp( buf, "objtype" ) )
  647.     {
  648.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  649. {
  650. case 'o': if ( obj )
  651.           {
  652.     lhsvl = obj->item_type;
  653.     rhsvl = atoi( val );
  654.     return mprog_veval( lhsvl, opr, rhsvl );
  655.   }
  656.          else
  657.    return -1;
  658. case 'p': if ( v_obj )
  659.           {
  660.     lhsvl = v_obj->item_type;
  661.     rhsvl = atoi( val );
  662.     return mprog_veval( lhsvl, opr, rhsvl );
  663.   }
  664.           else
  665.     return -1;
  666. default:
  667.   bug ( "Mob: %d bad argument to 'objtype'", mob->pIndexData->vnum ); 
  668.   return -1;
  669. }
  670.     }
  671.   if ( !str_cmp( buf, "objval0" ) )
  672.     {
  673.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  674. {
  675. case 'o': if ( obj )
  676.           {
  677.     lhsvl = obj->value[0];
  678.     rhsvl = atoi( val );
  679.     return mprog_veval( lhsvl, opr, rhsvl );
  680.   }
  681.           else
  682.     return -1;
  683. case 'p': if ( v_obj )
  684.           {
  685.     lhsvl = v_obj->value[0];
  686.     rhsvl = atoi( val );
  687.     return mprog_veval( lhsvl, opr, rhsvl );
  688.   }
  689.           else 
  690.     return -1;
  691. default:
  692.   bug ( "Mob: %d bad argument to 'objval0'", mob->pIndexData->vnum ); 
  693.   return -1;
  694. }
  695.     }
  696.   if ( !str_cmp( buf, "objval1" ) )
  697.     {
  698.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  699. {
  700. case 'o': if ( obj )
  701.           {
  702.     lhsvl = obj->value[1];
  703.     rhsvl = atoi( val );
  704.     return mprog_veval( lhsvl, opr, rhsvl );
  705.   }
  706.           else
  707.     return -1;
  708. case 'p': if ( v_obj )
  709.           {
  710.     lhsvl = v_obj->value[1];
  711.     rhsvl = atoi( val );
  712.     return mprog_veval( lhsvl, opr, rhsvl );
  713.   }
  714.           else
  715.     return -1;
  716. default:
  717.   bug ( "Mob: %d bad argument to 'objval1'", mob->pIndexData->vnum ); 
  718.   return -1;
  719. }
  720.     }
  721.   if ( !str_cmp( buf, "objval2" ) )
  722.     {
  723.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  724. {
  725. case 'o': if ( obj )
  726.           {
  727.     lhsvl = obj->value[2];
  728.     rhsvl = atoi( val );
  729.     return mprog_veval( lhsvl, opr, rhsvl );
  730.   }
  731.           else
  732.     return -1;
  733. case 'p': if ( v_obj )
  734.           {
  735.     lhsvl = v_obj->value[2];
  736.     rhsvl = atoi( val );
  737.     return mprog_veval( lhsvl, opr, rhsvl );
  738.   }
  739.           else
  740.     return -1;
  741. default:
  742.   bug ( "Mob: %d bad argument to 'objval2'", mob->pIndexData->vnum ); 
  743.   return -1;
  744. }
  745.     }
  746.   if ( !str_cmp( buf, "objval3" ) )
  747.     {
  748.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  749. {
  750. case 'o': if ( obj )
  751.           {
  752.     lhsvl = obj->value[3];
  753.     rhsvl = atoi( val );
  754.     return mprog_veval( lhsvl, opr, rhsvl );
  755.   }
  756.           else
  757.     return -1;
  758. case 'p': if ( v_obj ) 
  759.           {
  760.     lhsvl = v_obj->value[3];
  761.     rhsvl = atoi( val );
  762.     return mprog_veval( lhsvl, opr, rhsvl );
  763.   }
  764.           else
  765.     return -1;
  766. default:
  767.   bug ( "Mob: %d bad argument to 'objval3'", mob->pIndexData->vnum ); 
  768.   return -1;
  769. }
  770.     }
  771.   if ( !str_cmp( buf, "number" ) )
  772.     {
  773.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  774. {
  775. case 'i': lhsvl = mob->gold;
  776.           rhsvl = atoi( val );
  777.           return mprog_veval( lhsvl, opr, rhsvl );
  778. case 'n': if ( actor )
  779.           {
  780.     if IS_NPC( actor )
  781.     {
  782.       lhsvl = actor->pIndexData->vnum;
  783.       rhsvl = atoi( val );
  784.       return mprog_veval( lhsvl, opr, rhsvl );
  785.     }
  786.   }
  787.           else
  788.     return -1;
  789. case 't': if ( vict )
  790.           {
  791.     if IS_NPC( actor )
  792.     {
  793.       lhsvl = vict->pIndexData->vnum;
  794.       rhsvl = atoi( val );
  795.       return mprog_veval( lhsvl, opr, rhsvl );
  796.     }
  797.   }
  798.                   else
  799.     return -1;
  800. case 'r': if ( rndm )
  801.           {
  802.     if IS_NPC( actor )
  803.     {
  804.       lhsvl = rndm->pIndexData->vnum;
  805.       rhsvl = atoi( val );
  806.       return mprog_veval( lhsvl, opr, rhsvl );
  807.     }
  808.   }
  809.          else return -1;
  810. case 'o': if ( obj )
  811.           {
  812.     lhsvl = obj->pIndexData->vnum;
  813.     rhsvl = atoi( val );
  814.     return mprog_veval( lhsvl, opr, rhsvl );
  815.   }
  816.           else
  817.     return -1;
  818. case 'p': if ( v_obj )
  819.           {
  820.     lhsvl = v_obj->pIndexData->vnum;
  821.     rhsvl = atoi( val );
  822.     return mprog_veval( lhsvl, opr, rhsvl );
  823.   }
  824.           else
  825.     return -1;
  826. default:
  827.   bug ( "Mob: %d bad argument to 'number'", mob->pIndexData->vnum ); 
  828.   return -1;
  829. }
  830.     }
  831.   if ( !str_cmp( buf, "name" ) )
  832.     {
  833.       switch ( arg[1] )  /* arg should be "$*" so just get the letter */
  834. {
  835. case 'i': return mprog_seval( mob->name, opr, val );
  836. case 'n': if ( actor )
  837.             return mprog_seval( actor->name, opr, val );
  838.           else
  839.     return -1;
  840. case 't': if ( vict )
  841.             return mprog_seval( vict->name, opr, val );
  842.           else
  843.     return -1;
  844. case 'r': if ( rndm )
  845.             return mprog_seval( rndm->name, opr, val );
  846.           else
  847.     return -1;
  848. case 'o': if ( obj )
  849.             return mprog_seval( obj->name, opr, val );
  850.           else
  851.     return -1;
  852. case 'p': if ( v_obj )
  853.             return mprog_seval( v_obj->name, opr, val );
  854.           else
  855.     return -1;
  856. default:
  857.   bug ( "Mob: %d bad argument to 'name'", mob->pIndexData->vnum ); 
  858.   return -1;
  859. }
  860.     }
  861.   /* Ok... all the ifchcks are done, so if we didnt find ours then something
  862.    * odd happened.  So report the bug and abort the MOBprogram (return error)
  863.    */
  864.   bug ( "Mob: %d unknown ifchck", mob->pIndexData->vnum ); 
  865.   return -1;
  866. }
  867. /* Quite a long and arduous function, this guy handles the control
  868.  * flow part of MOBprograms.  Basicially once the driver sees an
  869.  * 'if' attention shifts to here.  While many syntax errors are
  870.  * caught, some will still get through due to the handling of break
  871.  * and errors in the same fashion.  The desire to break out of the
  872.  * recursion without catastrophe in the event of a mis-parse was
  873.  * believed to be high. Thus, if an error is found, it is bugged and
  874.  * the parser acts as though a break were issued and just bails out
  875.  * at that point. I havent tested all the possibilites, so I'm speaking
  876.  * in theory, but it is 'guaranteed' to work on syntactically correct
  877.  * MOBprograms, so if the mud crashes here, check the mob carefully!
  878.  */
  879. char *mprog_process_if( char *ifchck, char *com_list, CHAR_DATA *mob,
  880.        CHAR_DATA *actor, OBJ_DATA *obj, void *vo,
  881.        CHAR_DATA *rndm )
  882. {
  883.  char null[ 1 ];
  884.  char buf[ MAX_INPUT_LENGTH ];
  885.  char *morebuf = '';
  886.  char    *cmnd = '';
  887.  bool loopdone = FALSE;
  888.  bool     flag = FALSE;
  889.  int  legal;
  890.  *null = '';
  891.  /* check for trueness of the ifcheck */
  892.  if ( ( legal = mprog_do_ifchck( ifchck, mob, actor, obj, vo, rndm ) ) )
  893.    if ( legal == 1 )
  894.      flag = TRUE;
  895.    else
  896.      return null;
  897.  while( loopdone == FALSE ) /*scan over any existing or statements */
  898.  {
  899.      cmnd     = com_list;
  900.      com_list = mprog_next_command( com_list );
  901.      while ( *cmnd == ' ' )
  902.        cmnd++;
  903.      if ( *cmnd == '' )
  904.      {
  905.  bug ( "Mob: %d no commands after IF/OR", mob->pIndexData->vnum ); 
  906.  return null;
  907.      }
  908.      morebuf = one_argument( cmnd, buf );
  909.      if ( !str_cmp( buf, "or" ) )
  910.      {
  911.  if ( ( legal = mprog_do_ifchck( morebuf,mob,actor,obj,vo,rndm ) ) )
  912.    if ( legal == 1 )
  913.      flag = TRUE;
  914.    else
  915.      return null;
  916.      }
  917.      else
  918.        loopdone = TRUE;
  919.  }
  920.  
  921.  if ( flag )
  922.    for ( ; ; ) /*ifcheck was true, do commands but ignore else to endif*/ 
  923.    {
  924.        if ( !str_cmp( buf, "if" ) )
  925.        { 
  926.    com_list = mprog_process_if(morebuf,com_list,mob,actor,obj,vo,rndm);
  927.    while ( *cmnd==' ' )
  928.      cmnd++;
  929.    if ( *com_list == '' )
  930.      return null;
  931.    cmnd     = com_list;
  932.    com_list = mprog_next_command( com_list );
  933.    morebuf  = one_argument( cmnd,buf );
  934.    continue;
  935.        }
  936.        if ( !str_cmp( buf, "break" ) )
  937.  return null;
  938.        if ( !str_cmp( buf, "endif" ) )
  939.  return com_list; 
  940.        if ( !str_cmp( buf, "else" ) ) 
  941.        {
  942.    while ( str_cmp( buf, "endif" ) ) 
  943.    {
  944.        cmnd     = com_list;
  945.        com_list = mprog_next_command( com_list );
  946.        while ( *cmnd == ' ' )
  947.  cmnd++;
  948.        if ( *cmnd == '' )
  949.        {
  950.    bug ( "Mob: %d missing endif after else",
  951. mob->pIndexData->vnum );
  952.    return null;
  953.        }
  954.        morebuf = one_argument( cmnd,buf );
  955.    }
  956.    return com_list; 
  957.        }
  958.        mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm );
  959.        cmnd     = com_list;
  960.        com_list = mprog_next_command( com_list );
  961.        while ( *cmnd == ' ' )
  962.  cmnd++;
  963.        if ( *cmnd == '' )
  964.        {
  965.            bug ( "Mob: %d missing else or endif", mob->pIndexData->vnum ); 
  966.            return null;
  967.        }
  968.        morebuf = one_argument( cmnd, buf );
  969.    }
  970.  else /*false ifcheck, find else and do existing commands or quit at endif*/
  971.    {
  972.      while ( ( str_cmp( buf, "else" ) ) && ( str_cmp( buf, "endif" ) ) )
  973.        {
  974.  cmnd     = com_list;
  975.  com_list = mprog_next_command( com_list );
  976.  while ( *cmnd == ' ' )
  977.    cmnd++;
  978.  if ( *cmnd == '' )
  979.    {
  980.      bug ( "Mob: %d missing an else or endif",
  981.   mob->pIndexData->vnum ); 
  982.      return null;
  983.    }
  984.  morebuf = one_argument( cmnd, buf );
  985.        }
  986.      /* found either an else or an endif.. act accordingly */
  987.      if ( !str_cmp( buf, "endif" ) )
  988.        return com_list;
  989.      cmnd     = com_list;
  990.      com_list = mprog_next_command( com_list );
  991.      while ( *cmnd == ' ' )
  992.        cmnd++;
  993.      if ( *cmnd == '' )
  994.        { 
  995.  bug ( "Mob: %d missing endif", mob->pIndexData->vnum ); 
  996.  return null;
  997.        }
  998.      morebuf = one_argument( cmnd, buf );
  999.      
  1000.      for ( ; ; ) /*process the post-else commands until an endif is found.*/
  1001.        {
  1002.  if ( !str_cmp( buf, "if" ) )
  1003.    { 
  1004.      com_list = mprog_process_if( morebuf, com_list, mob, actor,
  1005.  obj, vo, rndm );
  1006.      while ( *cmnd == ' ' )
  1007.        cmnd++;
  1008.      if ( *com_list == '' )
  1009.        return null;
  1010.      cmnd     = com_list;
  1011.      com_list = mprog_next_command( com_list );
  1012.      morebuf  = one_argument( cmnd,buf );
  1013.      continue;
  1014.    }
  1015.  if ( !str_cmp( buf, "else" ) ) 
  1016.    {
  1017.      bug ( "Mob: %d found else in an else section",
  1018.   mob->pIndexData->vnum ); 
  1019.      return null;
  1020.    }
  1021.  if ( !str_cmp( buf, "break" ) )
  1022.    return null;
  1023.  if ( !str_cmp( buf, "endif" ) )
  1024.    return com_list; 
  1025.  mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm );
  1026.  cmnd     = com_list;
  1027.  com_list = mprog_next_command( com_list );
  1028.  while ( *cmnd == ' ' )
  1029.    cmnd++;
  1030.  if ( *cmnd == '' )
  1031.    {
  1032.      bug ( "Mob:%d missing endif in else section",
  1033.   mob->pIndexData->vnum ); 
  1034.      return null;
  1035.    }
  1036.  morebuf = one_argument( cmnd, buf );
  1037.        }
  1038.    }
  1039. }
  1040. /* This routine handles the variables for command expansion.
  1041.  * If you want to add any go right ahead, it should be fairly
  1042.  * clear how it is done and they are quite easy to do, so you
  1043.  * can be as creative as you want. The only catch is to check
  1044.  * that your variables exist before you use them. At the moment,
  1045.  * using $t when the secondary target refers to an object 
  1046.  * i.e. >prog_act drops~<nl>if ispc($t)<nl>sigh<nl>endif<nl>~<nl>
  1047.  * probably makes the mud crash (vice versa as well) The cure
  1048.  * would be to change act() so that vo becomes vict & v_obj.
  1049.  * but this would require a lot of small changes all over the code.
  1050.  */
  1051. void mprog_translate( char ch, char *t, CHAR_DATA *mob, CHAR_DATA *actor,
  1052.                     OBJ_DATA *obj, void *vo, CHAR_DATA *rndm )
  1053. {
  1054.  static char *he_she        [] = { "it",  "he",  "she" };
  1055.  static char *him_her       [] = { "it",  "him", "her" };
  1056.  static char *his_her       [] = { "its", "his", "her" };
  1057.  CHAR_DATA   *vict             = (CHAR_DATA *) vo;
  1058.  OBJ_DATA    *v_obj            = (OBJ_DATA  *) vo;
  1059.  *t = '';
  1060.  switch ( ch ) {
  1061.      case 'i':
  1062.          one_argument( mob->name, t );
  1063.       break;
  1064.      case 'I':
  1065.          strcpy( t, mob->short_descr );
  1066.       break;
  1067.      case 'n':
  1068.          if ( actor )
  1069.    if ( can_see( mob,actor ) )
  1070.      one_argument( actor->name, t );
  1071.          if ( !IS_NPC( actor ) )
  1072.    *t = UPPER( *t );
  1073.       break;
  1074.      case 'N':
  1075.          if ( actor ) 
  1076.             if ( can_see( mob, actor ) )
  1077.        if ( IS_NPC( actor ) )
  1078.  strcpy( t, actor->short_descr );
  1079.        else
  1080.        {
  1081.    strcpy( t, actor->name );
  1082.    strcat( t, " " );
  1083.    strcat( t, actor->pcdata->title );
  1084.        }
  1085.     else
  1086.       strcpy( t, "someone" );
  1087.  break;
  1088.      case 't':
  1089.          if ( vict )
  1090.    if ( can_see( mob, vict ) )
  1091.      one_argument( vict->name, t );
  1092.          if ( !IS_NPC( vict ) )
  1093.    *t = UPPER( *t );
  1094.  break;
  1095.      case 'T':
  1096.          if ( vict ) 
  1097.             if ( can_see( mob, vict ) )
  1098.        if ( IS_NPC( vict ) )
  1099.  strcpy( t, vict->short_descr );
  1100.        else
  1101.        {
  1102.  strcpy( t, vict->name );
  1103.  strcat( t, " " );
  1104.  strcat( t, vict->pcdata->title );
  1105.        }
  1106.     else
  1107.       strcpy( t, "someone" );
  1108.  break;
  1109.      
  1110.      case 'r':
  1111.          if ( rndm )
  1112.    if ( can_see( mob, rndm ) )
  1113.      one_argument( rndm->name, t );
  1114.          if ( !IS_NPC( rndm ) )
  1115.    *t = UPPER( *t );
  1116.       break;
  1117.      case 'R':
  1118.          if ( rndm ) 
  1119.             if ( can_see( mob, rndm ) )
  1120.        if ( IS_NPC( rndm ) )
  1121.  strcpy(t,rndm->short_descr);
  1122.        else
  1123.        {
  1124.  strcpy( t, rndm->name );
  1125.  strcat( t, " " );
  1126.  strcat( t, rndm->pcdata->title );
  1127.        }
  1128.     else
  1129.       strcpy( t, "someone" );
  1130.  break;
  1131.      case 'e':
  1132.          if ( actor )
  1133.    can_see( mob, actor ) ? strcpy( t, he_she[ actor->sex ] )
  1134.                          : strcpy( t, "someone" );
  1135.  break;
  1136.   
  1137.      case 'm':
  1138.          if ( actor )
  1139.    can_see( mob, actor ) ? strcpy( t, him_her[ actor->sex ] )
  1140.                                  : strcpy( t, "someone" );
  1141.  break;
  1142.   
  1143.      case 's':
  1144.          if ( actor )
  1145.    can_see( mob, actor ) ? strcpy( t, his_her[ actor->sex ] )
  1146.                          : strcpy( t, "someone's" );
  1147.  break;
  1148.      
  1149.      case 'E':
  1150.          if ( vict )
  1151.    can_see( mob, vict ) ? strcpy( t, he_she[ vict->sex ] )
  1152.                                 : strcpy( t, "someone" );
  1153.  break;
  1154.   
  1155.      case 'M':
  1156.          if ( vict )
  1157.    can_see( mob, vict ) ? strcpy( t, him_her[ vict->sex ] )
  1158.                                 : strcpy( t, "someone" );
  1159.  break;
  1160.   
  1161.      case 'S':
  1162.          if ( vict )
  1163.    can_see( mob, vict ) ? strcpy( t, his_her[ vict->sex ] )
  1164.                                 : strcpy( t, "someone's" ); 
  1165.  break;
  1166.      case 'j':
  1167.  strcpy( t, he_she[ mob->sex ] );
  1168.  break;
  1169.   
  1170.      case 'k':
  1171.  strcpy( t, him_her[ mob->sex ] );
  1172.  break;
  1173.   
  1174.      case 'l':
  1175.  strcpy( t, his_her[ mob->sex ] );
  1176.  break;
  1177.      case 'J':
  1178.          if ( rndm )
  1179.    can_see( mob, rndm ) ? strcpy( t, he_she[ rndm->sex ] )
  1180.                         : strcpy( t, "someone" );
  1181.  break;
  1182.   
  1183.      case 'K':
  1184.          if ( rndm )
  1185.    can_see( mob, rndm ) ? strcpy( t, him_her[ rndm->sex ] )
  1186.                                 : strcpy( t, "someone" );
  1187.  break;
  1188.   
  1189.      case 'L':
  1190.          if ( rndm )
  1191.    can_see( mob, rndm ) ? strcpy( t, his_her[ rndm->sex ] )
  1192.                         : strcpy( t, "someone's" );
  1193.  break;
  1194.      case 'o':
  1195.          if ( obj )
  1196.    can_see_obj( mob, obj ) ? one_argument( obj->name, t )
  1197.                                    : strcpy( t, "something" );
  1198.  break;
  1199.      case 'O':
  1200.          if ( obj )
  1201.    can_see_obj( mob, obj ) ? strcpy( t, obj->short_descr )
  1202.                                    : strcpy( t, "something" );
  1203.  break;
  1204.      case 'p':
  1205.          if ( v_obj )
  1206.    can_see_obj( mob, v_obj ) ? one_argument( v_obj->name, t )
  1207.                                      : strcpy( t, "something" );
  1208.  break;
  1209.      case 'P':
  1210.          if ( v_obj )
  1211.    can_see_obj( mob, v_obj ) ? strcpy( t, v_obj->short_descr )
  1212.                                      : strcpy( t, "something" );
  1213.       break;
  1214.      case 'a':
  1215.          if ( obj ) 
  1216.           switch ( *( obj->name ) )
  1217.   {
  1218.     case 'a': case 'e': case 'i':
  1219.             case 'o': case 'u': strcpy( t, "an" );
  1220.       break;
  1221.             default: strcpy( t, "a" );
  1222.           }
  1223.  break;
  1224.      case 'A':
  1225.          if ( v_obj ) 
  1226.           switch ( *( v_obj->name ) )
  1227.   {
  1228.             case 'a': case 'e': case 'i':
  1229.     case 'o': case 'u': strcpy( t, "an" );
  1230.       break;
  1231.             default: strcpy( t, "a" );
  1232.           }
  1233.  break;
  1234.      case '$':
  1235.          strcpy( t, "$" );
  1236.  break;
  1237.      default:
  1238.          bug( "Mob: %d bad $var", mob->pIndexData->vnum );
  1239.  break;
  1240.        }
  1241.  return;
  1242. }
  1243. /* This procedure simply copies the cmnd to a buffer while expanding
  1244.  * any variables by calling the translate procedure.  The observant
  1245.  * code scrutinizer will notice that this is taken from act()
  1246.  */
  1247. void mprog_process_cmnd( char *cmnd, CHAR_DATA *mob, CHAR_DATA *actor,
  1248. OBJ_DATA *obj, void *vo, CHAR_DATA *rndm )
  1249. {
  1250.   char buf[ MAX_INPUT_LENGTH ];
  1251.   char tmp[ MAX_INPUT_LENGTH ];
  1252.   char *str;
  1253.   char *i;
  1254.   char *point;
  1255.   point   = buf;
  1256.   str     = cmnd;
  1257.   while ( *str != '' )
  1258.   {
  1259.     if ( *str != '$' )
  1260.     {
  1261.       *point++ = *str++;
  1262.       continue;
  1263.     }
  1264.     str++;
  1265.     mprog_translate( *str, tmp, mob, actor, obj, vo, rndm );
  1266.     i = tmp;
  1267.     ++str;
  1268.     while ( ( *point = *i ) != '' )
  1269.       ++point, ++i;
  1270.   }
  1271.   *point = '';
  1272.   interpret( mob, buf );
  1273.   return;
  1274. }
  1275. /* The main focus of the MOBprograms.  This routine is called 
  1276.  *  whenever a trigger is successful.  It is responsible for parsing
  1277.  *  the command list and figuring out what to do. However, like all
  1278.  *  complex procedures, everything is farmed out to the other guys.
  1279.  */
  1280. void mprog_driver ( char *com_list, CHAR_DATA *mob, CHAR_DATA *actor,
  1281.    OBJ_DATA *obj, void *vo)
  1282. {
  1283.  char tmpcmndlst[ MAX_STRING_LENGTH ];
  1284.  char buf       [ MAX_INPUT_LENGTH ];
  1285.  char *morebuf;
  1286.  char *command_list;
  1287.  char *cmnd;
  1288.  CHAR_DATA *rndm  = NULL;
  1289.  CHAR_DATA *vch   = NULL;
  1290.  int        count = 0;
  1291.  if IS_AFFECTED( mob, AFF_CHARM )
  1292.    return;
  1293.  /* get a random visable mortal player who is in the room with the mob */
  1294.  for ( vch = mob->in_room->people; vch; vch = vch->next_in_room )
  1295.    if ( !IS_NPC( vch )
  1296.        &&  vch->level < LEVEL_IMMORTAL
  1297.        &&  can_see( mob, vch ) )
  1298.      {
  1299.        if ( number_range( 0, count ) == 0 )
  1300.  rndm = vch;
  1301.        count++;
  1302.      }
  1303.   
  1304.  strcpy( tmpcmndlst, com_list );
  1305.  command_list = tmpcmndlst;
  1306.  cmnd         = command_list;
  1307.  command_list = mprog_next_command( command_list );
  1308.  while ( *cmnd != '' )
  1309.    {
  1310.      morebuf = one_argument( cmnd, buf );
  1311.      if ( !str_cmp( buf, "if" ) )
  1312.        command_list = mprog_process_if( morebuf, command_list, mob,
  1313.        actor, obj, vo, rndm );
  1314.      else
  1315.        mprog_process_cmnd( cmnd, mob, actor, obj, vo, rndm );
  1316.      cmnd         = command_list;
  1317.      command_list = mprog_next_command( command_list );
  1318.    }
  1319.  return;
  1320. }
  1321. /***************************************************************************
  1322.  * Global function code and brief comments.
  1323.  */
  1324. /* The next two routines are the basic trigger types. Either trigger
  1325.  *  on a certain percent, or trigger on a keyword or word phrase.
  1326.  *  To see how this works, look at the various trigger routines..
  1327.  */
  1328. void mprog_wordlist_check( char *arg, CHAR_DATA *mob, CHAR_DATA *actor,
  1329.   OBJ_DATA *obj, void *vo, int type )
  1330. {
  1331.   char        temp1[ MAX_STRING_LENGTH ];
  1332.   char        temp2[ MAX_INPUT_LENGTH ];
  1333.   char        word[ MAX_INPUT_LENGTH ];
  1334.   MPROG_DATA *mprg;
  1335.   char       *list;
  1336.   char       *start;
  1337.   char       *dupl;
  1338.   char       *end;
  1339.   int         i;
  1340.   for ( mprg = mob->pIndexData->mobprogs; mprg != NULL; mprg = mprg->next )
  1341.     if ( mprg->type & type )
  1342.       {
  1343. strcpy( temp1, mprg->arglist );
  1344. list = temp1;
  1345. for ( i = 0; i < strlen( list ); i++ )
  1346.   list[i] = LOWER( list[i] );
  1347. strcpy( temp2, arg );
  1348. dupl = temp2;
  1349. for ( i = 0; i < strlen( dupl ); i++ )
  1350.   dupl[i] = LOWER( dupl[i] );
  1351. if ( ( list[0] == 'p' ) && ( list[1] == ' ' ) )
  1352.   {
  1353.     list += 2;
  1354.     while ( ( start = strstr( dupl, list ) ) )
  1355.       if ( (start == dupl || *(start-1) == ' ' )
  1356.   && ( *(end = start + strlen( list ) ) == ' '
  1357.       || *end == 'n'
  1358.       || *end == 'r'
  1359.       || *end == '' ) )
  1360. {
  1361.   mprog_driver( mprg->comlist, mob, actor, obj, vo );
  1362.   break;
  1363. }
  1364.       else
  1365. dupl = start+1;
  1366.   }
  1367. else
  1368.   {
  1369.     list = one_argument( list, word );
  1370.     for( ; word[0] != ''; list = one_argument( list, word ) )
  1371.       while ( ( start = strstr( dupl, word ) ) )
  1372. if ( ( start == dupl || *(start-1) == ' ' )
  1373.     && ( *(end = start + strlen( word ) ) == ' '
  1374. || *end == 'n'
  1375. || *end == 'r'
  1376. || *end == '' ) )
  1377.   {
  1378.     mprog_driver( mprg->comlist, mob, actor, obj, vo );
  1379.     break;
  1380.   }
  1381. else
  1382.   dupl = start+1;
  1383.   }
  1384.       }
  1385.   return;
  1386. }
  1387. void mprog_percent_check( CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj,
  1388.  void *vo, int type)
  1389. {
  1390.  MPROG_DATA * mprg;
  1391.  for ( mprg = mob->pIndexData->mobprogs; mprg != NULL; mprg = mprg->next )
  1392.    if ( ( mprg->type & type )
  1393.        && ( number_percent( ) < atoi( mprg->arglist ) ) )
  1394.      {
  1395.        mprog_driver( mprg->comlist, mob, actor, obj, vo );
  1396.        if ( type != GREET_PROG && type != ALL_GREET_PROG )
  1397.  break;
  1398.      }
  1399.  return;
  1400. }
  1401. /* The triggers.. These are really basic, and since most appear only
  1402.  * once in the code (hmm. i think they all do) it would be more efficient
  1403.  * to substitute the code in and make the mprog_xxx_check routines global.
  1404.  * However, they are all here in one nice place at the moment to make it
  1405.  * easier to see what they look like. If you do substitute them back in,
  1406.  * make sure you remember to modify the variable names to the ones in the
  1407.  * trigger calls.
  1408.  */
  1409. void mprog_act_trigger( char *buf, CHAR_DATA *mob, CHAR_DATA *ch,
  1410.        OBJ_DATA *obj, void *vo)
  1411. {
  1412.   MPROG_ACT_LIST * tmp_act;
  1413.   if ( IS_NPC( mob )
  1414.       && ( mob->pIndexData->progtypes & ACT_PROG ) )
  1415.     {
  1416.       tmp_act = alloc_mem( sizeof( MPROG_ACT_LIST ) );
  1417.       if ( mob->mpactnum > 0 )
  1418. tmp_act->next = mob->mpact->next;
  1419.       else
  1420. tmp_act->next = NULL;
  1421.       mob->mpact      = tmp_act;
  1422.       mob->mpact->buf = str_dup( buf );
  1423.       mob->mpact->ch  = ch; 
  1424.       mob->mpact->obj = obj; 
  1425.       mob->mpact->vo  = vo; 
  1426.       mob->mpactnum++;
  1427.     }
  1428.   return;
  1429. }
  1430. void mprog_bribe_trigger( CHAR_DATA *mob, CHAR_DATA *ch, int amount )
  1431. {
  1432.   char        buf[ MAX_STRING_LENGTH ];
  1433.   MPROG_DATA *mprg;
  1434.   OBJ_DATA   *obj;
  1435.   if ( IS_NPC( mob )
  1436.       && ( mob->pIndexData->progtypes & BRIBE_PROG ) )
  1437.     {
  1438.       obj = create_object( get_obj_index( OBJ_VNUM_MONEY_SOME ), 0 );
  1439.       sprintf( buf, obj->short_descr, amount );
  1440.       free_string( obj->short_descr );
  1441.       obj->short_descr = str_dup( buf );
  1442.       obj->value[0]    = amount;
  1443.       obj_to_char( obj, mob );
  1444.       mob->gold -= amount;
  1445.       for ( mprg = mob->pIndexData->mobprogs; mprg != NULL; mprg = mprg->next )
  1446. if ( ( mprg->type & BRIBE_PROG )
  1447.     && ( amount >= atoi( mprg->arglist ) ) )
  1448.   {
  1449.     mprog_driver( mprg->comlist, mob, ch, obj, NULL );
  1450.     break;
  1451.   }
  1452.     }
  1453.   
  1454.   return;
  1455. }
  1456. void mprog_death_trigger( CHAR_DATA *mob )
  1457. {
  1458.  if ( IS_NPC( mob )
  1459.      && ( mob->pIndexData->progtypes & DEATH_PROG ) )
  1460.    {
  1461.      mprog_percent_check( mob, NULL, NULL, NULL, DEATH_PROG );
  1462.    }
  1463.  death_cry( mob );
  1464.  return;
  1465. }
  1466. void mprog_entry_trigger( CHAR_DATA *mob )
  1467. {
  1468.  if ( IS_NPC( mob )
  1469.      && ( mob->pIndexData->progtypes & ENTRY_PROG ) )
  1470.    mprog_percent_check( mob, NULL, NULL, NULL, ENTRY_PROG );
  1471.  return;
  1472. }
  1473. void mprog_fight_trigger( CHAR_DATA *mob, CHAR_DATA *ch )
  1474. {
  1475.  if ( IS_NPC( mob )
  1476.      && ( mob->pIndexData->progtypes & FIGHT_PROG ) )
  1477.    mprog_percent_check( mob, ch, NULL, NULL, FIGHT_PROG );
  1478.  return;
  1479. }
  1480. void mprog_give_trigger( CHAR_DATA *mob, CHAR_DATA *ch, OBJ_DATA *obj )
  1481. {
  1482.  char        buf[MAX_INPUT_LENGTH];
  1483.  MPROG_DATA *mprg;
  1484.  if ( IS_NPC( mob )
  1485.      && ( mob->pIndexData->progtypes & GIVE_PROG ) )
  1486.    for ( mprg = mob->pIndexData->mobprogs; mprg != NULL; mprg = mprg->next )
  1487.      {
  1488.        one_argument( mprg->arglist, buf );
  1489.        if ( ( mprg->type & GIVE_PROG )
  1490.    && ( ( !str_cmp( obj->name, mprg->arglist ) )
  1491.        || ( !str_cmp( "all", buf ) ) ) )
  1492.  {
  1493.    mprog_driver( mprg->comlist, mob, ch, obj, NULL );
  1494.    break;
  1495.  }
  1496.      }
  1497.  return;
  1498. }
  1499. void mprog_greet_trigger( CHAR_DATA *mob )
  1500. {
  1501.  CHAR_DATA *vmob;
  1502.  for ( vmob = mob->in_room->people; vmob != NULL; vmob = vmob->next_in_room )
  1503.    if ( IS_NPC( vmob )
  1504.        && mob != vmob
  1505.        && can_see( vmob, mob )
  1506.        && ( vmob->fighting == NULL )
  1507.        && IS_AWAKE( vmob )
  1508.        && ( vmob->pIndexData->progtypes & GREET_PROG) )
  1509.      mprog_percent_check( vmob, mob, NULL, NULL, GREET_PROG );
  1510.    else
  1511.      if ( IS_NPC( vmob )
  1512.  && ( vmob->fighting == NULL )
  1513.  && IS_AWAKE( vmob )
  1514.  && ( vmob->pIndexData->progtypes & ALL_GREET_PROG ) )
  1515.        mprog_percent_check( vmob, mob, NULL, NULL, ALL_GREET_PROG );
  1516.  return;
  1517. }
  1518. void mprog_hitprcnt_trigger( CHAR_DATA *mob, CHAR_DATA *ch)
  1519. {
  1520.  MPROG_DATA *mprg;
  1521.  if ( IS_NPC( mob )
  1522.      && ( mob->pIndexData->progtypes & HITPRCNT_PROG ) )
  1523.    for ( mprg = mob->pIndexData->mobprogs; mprg != NULL; mprg = mprg->next )
  1524.      if ( ( mprg->type & HITPRCNT_PROG )
  1525.  && ( ( 100*mob->hit / mob->max_hit ) < atoi( mprg->arglist ) ) )
  1526.        {
  1527.  mprog_driver( mprg->comlist, mob, ch, NULL, NULL );
  1528.  break;
  1529.        }
  1530.  
  1531.  return;
  1532. }
  1533. void mprog_random_trigger( CHAR_DATA *mob )
  1534. {
  1535.   if ( mob->pIndexData->progtypes & RAND_PROG)
  1536.     mprog_percent_check(mob,NULL,NULL,NULL,RAND_PROG);
  1537.   return;
  1538. }
  1539. void mprog_speech_trigger( char *txt, CHAR_DATA *mob )
  1540. {
  1541.   CHAR_DATA *vmob;
  1542.   for ( vmob = mob->in_room->people; vmob != NULL; vmob = vmob->next_in_room )
  1543.     if ( IS_NPC( vmob ) && ( vmob->pIndexData->progtypes & SPEECH_PROG ) )
  1544.       mprog_wordlist_check( txt, vmob, mob, NULL, NULL, SPEECH_PROG );
  1545.   
  1546.   return;
  1547. }