The effects of this snippet:

You gain the ability to set 5 variables from within mudprogs.
syntax: setvar # 
The ability to parse/compare variables with rval such as:
if name($n) == $i
The ability to create/use pointers anywhere in a prog.
Example:
say hi $n, I see you're a $n.race $n.class.
say Wow you're even level $n.level!

etc.


in mud.h the typical

typedef struct variable_data		VARIABLE_DATA;

struct	variable_data
{
    char *	v1;
    char *	v2;
    char *	v3;
    char *	v4;
    char *	v5;
};
extern	struct	variable_data		variable;


inside 

int mprog_do_ifcheck( char *ifcheck, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm )


After:
    if ( cvar[0] == '$' )
    {
	switch(cvar[1])
	{

Add in:
	    case '1':	chkchar = actor;		break;
	    case '2':	chkchar = actor;		break;
	    case '3':	chkchar = actor;		break;
	    case '4':	chkchar = actor;		break;
	    case '5':	chkchar = actor;		break;

After:
    rval = rval_translate(rval, mob, actor, obj, vo, rndm);

Add in:
    if ( !str_cmp(chck, "var1") )
    {
            bug( "setvar %s", rval);
            if (is_number(rval))
             return mprog_veval(atoi(variable.v1), opr, atoi(rval), mob);

            if (!str_cmp(variable.v1, rval))
             return TRUE;

            return FALSE;
    }
    if ( !str_cmp(chck, "var2") )
    {
            if (is_number(rval))
             return mprog_veval(atoi(variable.v2), opr, atoi(rval), mob);

            if (!str_cmp(variable.v2, rval))
             return TRUE;

            return FALSE;
    }
    if ( !str_cmp(chck, "var3") )
    {
            if (is_number(rval))
             return mprog_veval(atoi(variable.v3), opr, atoi(rval), mob);

            if (!str_cmp(variable.v3, rval))
             return TRUE;

            return FALSE;
    }
    if ( !str_cmp(chck, "var4") )
    {
            if (is_number(rval))
             return mprog_veval(atoi(variable.v4), opr, atoi(rval), mob);

            if (!str_cmp(variable.v4, rval))
             return TRUE;

            return FALSE;
    }
    if ( !str_cmp(chck, "var5") )
    {
            if (is_number(rval))
             return mprog_veval(atoi(variable.v5), opr, atoi(rval), mob);

            if (!str_cmp(variable.v5, rval))
             return TRUE;

            return FALSE;
    }

in mprog_do_command after:

  if ( !str_cmp( firstword, "break" ) )
    return BERR;

add in:

  str = parse_setvar( str, mob, actor, obj, vo, rndm );

  /* This chunk of code taken from mprog_process_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';

/* This is where to add in the check for "setvar" */
  if ( !str_cmp( firstword, "setvar" ) )
  {
    sh_int var;
    char *newtext;

    /* does not make it past this point, explore why */
    newtext = buf;
    newtext = one_argument( newtext, firstword );
    newtext = one_argument( newtext, firstword );
    var = atoi(firstword);
    str     = cmnd;
    switch(var)
    {
      default:
       progbug( mob, "Unknown setvar %s", firstword );
       return BERR;
      case 1:
       stralloc_printf( &variable.v1, "%s", newtext);
       break;
      case 2:
       stralloc_printf( &variable.v2, "%s", newtext);
       break;
      case 3:
       stralloc_printf( &variable.v3, "%s", newtext);
       break;
      case 4:
       stralloc_printf( &variable.v4, "%s", newtext);
       break;
      case 5:
       stralloc_printf( &variable.v5, "%s", newtext);
       break;
    }
  }


Before the interpret() call.

Inside: void mprog_translate( char ch, char *t, CHAR_DATA *mob, CHAR_DATA *actor,
                    OBJ_DATA *obj, void *vo, CHAR_DATA *rndm )

Add to the cases:

     case '1': 
	 strcpy( t, variable.v1 );
         break;
     case '2': 
	 strcpy( t, variable.v2 );
         break;
     case '3': 
	 strcpy( t, variable.v3 );
         break;
     case '4': 
	 strcpy( t, variable.v4 );
         break;
     case '5': 
	 strcpy( t, variable.v5 );
         break;


at the top of mud_prog.c add:
VARIABLE_DATA		variable;

  reset_variables();
add a call to that in mprog_driver just above
  iflevel = 0;
  global_prog_steps = 0;

The function itself is just:
void reset_variables()
{
   stralloc_printf( &variable.v1, "%s", "Unset");
   stralloc_printf( &variable.v2, "%s", "Unset");
   stralloc_printf( &variable.v3, "%s", "Unset");
   stralloc_printf( &variable.v4, "%s", "Unset");
   stralloc_printf( &variable.v5, "%s", "Unset");
   return;
}

also add a call to     reset_variables();
somewhere during your mud bootup process, so it initializes.

If you don't have stralloc_printf, you can get a copy from my site,
its fairly simple, just a mix of STRALLOC and STRFREE combined into
one with some va_printf joy added in to make it possible to add in formatting.

Add this in to mud_prog.c

char *parse_setvar( char *cmnd, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm )
{
  static char results[MSL*2];
  int x;
  CHAR_DATA *chkchar = NULL;
  OBJ_DATA *chkobj = NULL;
  
  results[0] = '\0';
  for ( x=0; cmnd[x] != '\0'; x++)
  { 
    chkchar = NULL;
    chkobj = NULL;
    if (cmnd[x] == '\0')
      return results;
    if (cmnd[x] != '$')
      add_letter( results, cmnd[x]);
    else
    {
       switch(cmnd[x+1])
       {
          default: 
           add_letter( results, cmnd[x]);  // Because the next letter is not a $ it will just take care of itself
           break;
	  case 'i':
           chkchar = mob;
           break;
	  case 'n':
           chkchar = actor;
           break;
	  case 't':
           chkchar = (CHAR_DATA *)vo;
           break;
	  case 'r':
           chkchar = rndm;
           break;
	  case 'o':
           chkobj = obj;
           break;
	  case 'p':
           chkobj = (OBJ_DATA *)vo;
           break;
       }
    }
    if (chkchar || chkobj)  // Ok, so one of them is valid, lets find out what the info we're looking at is.
    {
      x+=2; // skip over the identifier and go straight into whats next...
      if (cmnd[x] != '.' || cmnd[x] == '\0') //  not a period, so this isnt a pointer, just a variable.
      {
       add_letter( results, cmnd[x-2]); // Put this piece back
       add_letter( results, cmnd[x-1]); // Put this piece back
       add_letter( results, cmnd[x]); // Put this piece back
       if ( cmnd[x] == '\0')
         return results;
       continue; // and keep going.
      }
      else  // Ok, they used the right syntax, lets fight out what our 'word' is.
      {
         char word[MIL];;
         word[0] = '\0';
         x++;
         while ( isalpha(cmnd[x]) && cmnd[x] != '\0')  // Lets find the next single word.
         {
            add_letter( word, cmnd[x]);
            x++;
         }
           // If we get here, we assume we now have the word.
         if (chkchar != NULL)  // Begin looking for possible character matches.
         {
             if (!str_cmp( word, "name"))
             {
                 if (IS_NPC(chkchar))
                   strcat( results, format( "%s", chkchar->short_descr) );
                 else
                   strcat( results, format( "%s", chkchar->name ));
             }
             if (!str_cmp( word, "sex"))
             {
                 if (chkchar->sex == 2)
                   strcat( results, format( "%s", "female" ));
                 else
                   strcat( results, format( "%s", "male" ));
             }
             if (!str_cmp( word, "class"))
             {
                 strcat( results, format( "%s", npc_class[chkchar->class] ));
             }
             if (!str_cmp( word, "race"))
             {
                 strcat( results, get_race(chkchar) );
             }
             if (!str_cmp( word, "eyes"))
             {
                 strcat( results, format( "%s", eye_flags[chkchar->eyes] ));
             }
             if (!str_cmp( word, "lname"))
             {
                 strcat( results, format( "%s", IS_NPC(chkchar)? "" : chkchar->pcdata->lastname ));
             }
             if (!str_cmp( word, "hair"))
             {
                 strcat( results, get_hair(chkchar) );
             }
             if (!str_cmp( word, "skin"))
             {
                 strcat( results, format( "%s", skin_flags[chkchar->skin] ));
             }
             if (!str_cmp( word, "level"))
             {
                 strcat( results, itoa( chkchar->level) );
             }

             // add your own char checks at this point
         }
         if (chkobj != NULL)  // Then do objects.
         {
             if (!str_cmp( word, "level"))
             {
                 strcat( results, itoa( chkobj->level) );
             }
             // add your own obj checks at this point
         }
         if (cmnd[x] == '\0')
          return results;
         else
          add_letter( results, cmnd[x]);
      }
    }
  }
  return results;
}


Supportive functions you may not have and may need:

void add_letter( char *string, char letter)
{
  char buf[MIL];

  sprintf(buf, "%c", letter);
  strcat(string, buf);
  return;
}

void stralloc_printf( char **pointer, char *fmt, ...)
{
    char buf[MAX_STRING_LENGTH*2];	/* better safe than sorry */
    va_list args;

    va_start(args, fmt);
    vsprintf(buf, fmt, args);
    va_end(args);
	
    if (*pointer)
     STRFREE(*pointer);
    *pointer = STRALLOC( buf);
    return;
}

char *rval_translate( char *rval, CHAR_DATA *mob, CHAR_DATA *actor, OBJ_DATA *obj, void *vo, CHAR_DATA *rndm )
{
   CHAR_DATA *ch=NULL;
   OBJ_DATA *obj2=NULL;

   if (rval[0] != '$')
    return rval;

   switch(rval[1])
   {
	    case 'i':	ch = mob;			break;
	    case 'n':	ch = actor;			break;
	    case 't':	ch = (CHAR_DATA *)vo;		break;
	    case 'r':	ch = rndm;			break;
	    case 'o':	obj2 = obj;			break;
	    case 'p':	obj2 = (OBJ_DATA *)vo;		break;
	    case '1':	
                return variable.v1;
	    case '2':	
                return variable.v2;
	    case '3':	
                return variable.v3;
	    case '4':	
                return variable.v4;
	    case '5':	
                return variable.v5;
	    default:
		break;
   }
   if (ch)
     return IS_NPC(ch) ? ch->short_descr : ch->name;
   if (obj2)
     return obj2->short_descr;
   return "Tell a Staff Member you got this result and how";

}