Palrich
red@smileyface.com
Head Imp, Divine Blood telnet://divineblood.tetradine.com:4000

I hacked this up to do what one of my builders wanted.  It's kind of neat, so
I rewrote it to work with stock code+OLC1.81.  I'm not sure how it'll do with
other OLC's. Basically it uses the phrase of a mobprog as a regular expression,
checks it against speech text, and stores the first 3 matches in $a, $b, and
$c.
So you add the prog with trigger REGEX and phrase "my name is (\w+)"
Then the body of the prog is,
  say Why hello there, $a.
When the player says "My name is bob", the mob says "Why hello there, bob"
Pretty simple and all.
If you use something like this a lot, you should store the compiled regexprec
rather than building and freeing it every time, because this here is hugely
inefficient.

// At the top of mob_prog.c
#include <regex.h>

// ... then in the global scope
char match[3][MAX_INPUT_LENGTH];

// Inside expand_arg
      case 'a':
        i = match[0];  break;
      case 'b':
        i = match[1];  break;
      case 'c':
        i = match[2];  break;

//somewhere toward the bottom of mob_prog.c
void mp_regex_trigger(char *argument, CHAR_DATA *mob, CHAR_DATA *ch)
{
  regex_t exprec;
  int nmemb = 3, i;
  regmatch_t memb[nmemb];
  MPROG_LIST *prg;
  for (prg = mob->pIndexData->mprogs; prg != NULL; prg = prg->next)
    if ( prg->trig_type == TRIG_REGEXP)
    {
      regcomp(&exprec, prg->trig_phrase, REG_EXTENDED|REG_ICASE);
      if (!regexec(&exprec, argument, nmemb, memb, 0))
      {
        for (i = 0; i < nmemb && memb[i+1].rm_so > -1; i++)
        {
          memcpy(match[i], argument+memb[i+1].rm_so,
            memb[i+1].rm_eo-memb[i+1].rm_so);
          match[i][memb[i+1].rm_eo-memb[i+1].rm_so] = '\0';
        }
        program_flow(prg->vnum, prg->code, mob, ch, arg1, arg2);
      }
      regfree(&exprec);
      return;
    }
}

// merc.h, with the other TRIG_*s
#define TRIG_REGEX	(Q)

// merc.h, with the other mp trigger function definitions
void mp_regex_trigger(char *argument, CHAR_DATA *mob, CHAR_DATA *ch);


// tables.c, in mprog_flags
    {	"regex",		TRIG_REGEX,		TRUE    },

//mob_cmds.c, inside mprog_type_to_name
    case TRIG_REGEX:	      	return "REGEX";

//act_comm.c, under the check for TRIG_SPEECH
          if (IS_NPC(mob) && HAS_TRIGGER( mob, TRIG_REGEX))
            mp_regex_trigger(argument,mob,ch);