atd/area/
atd/build/
atd/clans/
atd/log/
atd/player/store/
atd/site/
atd/src/bin/
/******************************************************************************
 Snippet: Dynamic description generator.
 Author:  Richard Woolcock (aka KaVir).
 Date:    14th October 1999.
 ******************************************************************************
 This code is copyright (C) 1999 by Richard Woolcock.  It may be used and
 distributed freely, as long as you don't remove this copyright notice.
 ******************************************************************************

 [({clan} == {caitiff}) || ({clan} == {brujah})]
    You're a {clan}!

 VARIABLE_FUNCTION_STRING: Functions returning strings.
 VARIABLE_CONSTANT_STRING: Constant strings.
 VARIABLE_FUNCTION_NUMBER: Functions returning numbers.
 VARIABLE_CONSTANT_NUMBER: Constant numbers.

 Only the strings may be used within general text replacement.  Only the 
 numbers may be used within expressions.  You may have a string variable 
 and a number variable of the same name (in fact I recommend you do this).
 That's how the above example (with {clan}) would work - {clan} string 
 returns the name of the person's clan as a string, while the {clan} number 
 returns a number appropriate to that particular clan.

 void	io_parse	args( ( CHAR_DATA *ch, char *in_ptr, char *out_ptr ) );
 void	io_display	args( ( CHAR_DATA *ch, char text[] ) );
 void	io_main		args( ( CHAR_DATA *ch ) );
 int	io_calculate	args( ( CHAR_DATA *ch, char *calculation ) );
 ****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include <time.h>
#include "merc.h"

typedef enum
{
   VARIABLE_FUNCTION_STRING,
   VARIABLE_CONSTANT_STRING,
   VARIABLE_FUNCTION_NUMBER,
   VARIABLE_CONSTANT_NUMBER
} VARIABLE_TYPE;

typedef enum
{
   STATE_NONE,
   STATE_LEFT_SIGN,
   STATE_LEFT,
   STATE_DONE_LEFT,
   STATE_OPERATOR,
   STATE_RIGHT_SIGN,
   STATE_RIGHT
} STATE_TYPE;

typedef struct
{
   const char * variable;
   const VARIABLE_TYPE type;
   void       * replace;
} var_type;

/*********************************************************/
/*                 FUNCTION PROTOTYPES                   */
/*********************************************************/

static int	main_calc	( CHAR_DATA *ch, char calc_string[] );
bool		string_var	( char *var_ptr, char **out_ptr,
				  CHAR_DATA *ch, OBJ_DATA *obj );
bool		number_var	( char *var_ptr, char *out_ptr,
                                  CHAR_DATA *ch, OBJ_DATA *obj );
OBJ_DATA *	setup_variables	( CHAR_DATA *ch );
char     *      numberize args( ( int n ) );

extern const struct where_type  where_name [MAX_WEAR];

#define CFUN( fun )  char *fun( CHAR_DATA *ch, OBJ_DATA *obj )
#define IFUN( fun )  int   fun( CHAR_DATA *ch, OBJ_DATA *obj )

char *short_obj_desc( CHAR_DATA *ch, OBJ_DATA *obj, bool fShort )
{
    static char buf[MAX_STRING_LENGTH];
    char pre[MAX_STRING_LENGTH];

    buf[0] = '\0';

    pre[0] = '\0';

    if( IS_OBJ_STAT( obj, ITEM_INVIS) ) strcat( pre, "invisible " );
    if( IS_AFFECTED(ch, AFF_DETECT_MAGIC)
            && IS_OBJ_STAT(obj, ITEM_MAGIC ) ) strcat( pre, "shimmering ");
    if( IS_OBJ_STAT(obj, ITEM_GLOW ) ) strcat( pre, "glowing " );
    if( IS_OBJ_STAT(obj, ITEM_HUM ) )  strcat( pre, "humming " );

    switch( obj->item_type )
    {
    default: break;
    case ITEM_DRINK_CON:
        if ( !obj->value[0] ) strcat( pre, "empty " ); break;
    case ITEM_ARMOR:
        if( obj->value[0] )
	 {
	 int percent;

	 percent = PERCENTAGE( obj->value[4], 100);
                strcat( pre,
                percent <  10 ? "destroyed "     :
                percent <  20 ? "poor "          :
                percent <  30 ? "badly damaged " :
                        percent <  40 ? "damaged "       :
                        percent <  50 ? "worn "          :
                        percent <  80 ? "somewhat used " :
                        "new " );
         }
         break;
    }

    if( pre[0] != '\0' )
    {
            sprintf( buf, "%s %s%s", IS_VOWEL(pre[0]) ? "an" : "a", pre,
                     smash_article( STR(obj, short_descr) ) );
    }
    else
        strcat( buf, STR(obj,short_descr) );

    if ( obj->item_type == ITEM_DRINK_CON
         && IS_SET(obj->extra_flags, ITEM_INVENTORY)
          && obj->value[0] != 0 )
    {
            if ( obj->value[2] < 0 || obj->value[2] >= LIQ_MAX )
            {
                obj->value[2] = 0;
                bug( "Invalid liquid on object %d.", obj->pIndexData->vnum);
            }

            strcat( buf, " of " );
            strcat( buf, liq_table[obj->value[2]].liq_name );
    }

    return buf;
}

/*********************************************************************/
/**************************** PURE STRING ****************************/
/*********************************************************************/


CFUN( get_name )    { return ( ch->name ); }
CFUN( get_he_she )  { return HE_SHE(ch);   }
CFUN( get_him_her ) { return HIM_HER(ch);  }
CFUN( get_his_her ) { return HIS_HER(ch);  }
CFUN( obj_where_text )
{
    static char buf [MAX_INPUT_LENGTH];

    if ( !obj ) return "";

    if ( obj->in_obj )
    {
        sprintf( buf, "inside his %s",
                 short_obj_desc(ch,obj->in_obj,FALSE) );
        return buf;
    }
    if ( obj->carried_by == ch )
    {
       if ( obj->wear_loc >= WEAR_LIGHT && obj->wear_loc < MAX_WEAR )
       {
           sprintf( buf, where_name[obj->wear_loc].r_name, HIS_HER(ch) );
         return &buf[2];
       }
   }
   return "";
}

/*********************************************************************/
/**************************** PURE NUMBER ****************************/
/*********************************************************************/

IFUN( get_class )   { return ( ch->class ); }

/*********************************************************************/
/********************** BOTH STRING AND NUMBER ***********************/
/*********************************************************************/

IFUN( get_wpn )            { return ( !obj ); }
CFUN( get_wpn_text )  { return  obj ? short_obj_desc(ch,obj,FALSE) : "fist" ; }

IFUN( wpn_type )      { return  obj ? obj->value[3] : 0; }
CFUN( wpn_type_text ) { return  numberize(wpn_type(ch,obj)); }

IFUN( wpn_dam )       { return  obj ? obj->value[2] : 0; }
CFUN( wpn_dam_text )  { return  numberize(wpn_dam(ch,obj)); }

IFUN( wpn_where )      { return obj ? obj->wear_loc : -1; }
CFUN( wpn_where_text ) { return obj_where_text( ch, obj ); }

IFUN( get_generation ) { return GET_GEN(ch); }
CFUN( get_generation_text)
{
   switch ( GET_GEN(ch) )
   {
      default: return "bugged";
      case 15: return "15th";
      case 14: return "14th";
      case 13: return "13th";
      case 12: return "12th";
      case 11: return "11th";
      case 10: return "10th";
      case  9: return "9th";
      case  8: return "8th";
      case  7: return "7th";
      case  6: return "6th";
      case  5: return "5th";
      case  4: return "4th";
      case  3: return "3rd";
      case  2: return "2nd";
      case  1: return "1st";
   }
}


CFUN( get_attribute_str_text ) { return numberize(get_curr_str(ch)); }
IFUN( get_attribute_str      ) { return get_curr_str(ch); }

CFUN( get_attribute_int_text ) { return numberize(get_curr_int(ch)); }
IFUN( get_attribute_int      ) { return get_curr_int(ch); }

CFUN( get_attribute_wis_text ) { return numberize(get_curr_wis(ch)); }
IFUN( get_attribute_wis      ) { return get_curr_wis(ch); }

CFUN( get_attribute_dex_text ) { return numberize(get_curr_dex(ch)); }
IFUN( get_attribute_dex      ) { return get_curr_dex(ch); }

CFUN( get_attribute_con_text ) { return numberize(get_curr_con(ch)); }
IFUN( get_attribute_con      ) { return get_curr_con(ch); }

/*********************************************************/

#define STRING_FUNCTION(f) VARIABLE_FUNCTION_STRING, (void *) (f)
#define STRING_CONSTANT(f) VARIABLE_CONSTANT_STRING, (void *) (f)
#define NUMBER_FUNCTION(f) VARIABLE_FUNCTION_NUMBER, (void *) (f)
#define NUMBER_CONSTANT(f) VARIABLE_CONSTANT_NUMBER, (void *) (f)
#define END_OF_LIST        VARIABLE_CONSTANT_NUMBER, NULL

/*********************************************************/
/*                 VARIABLE TABLE                        */
/*********************************************************/

const var_type var_table[] =
{
   /* Pure string functions */
   { "name",		STRING_FUNCTION(get_name) },
   { "he/she",		STRING_FUNCTION(get_he_she) },
   { "him/her",		STRING_FUNCTION(get_him_her) },
   { "his/her",		STRING_FUNCTION(get_his_her) },

   /* Pure number functions */
   { "class",		NUMBER_FUNCTION(get_class) },
   { "mortal",		NUMBER_CONSTANT(CLASS_NONE) },
   { "vampire",		NUMBER_CONSTANT(CLASS_VAMPIRE) },
   { "werewolf",	NUMBER_CONSTANT(CLASS_WEREWOLF) },
   { "mage",		NUMBER_CONSTANT(CLASS_MAGE) },
   { "demon",		NUMBER_CONSTANT(CLASS_DEMON) },
   { "monk",            NUMBER_CONSTANT(CLASS_MONK) },
   { "priest",          NUMBER_CONSTANT(CLASS_PRIEST) },
   { "ninja",           NUMBER_CONSTANT(CLASS_NINJA) },
   { "angel",           NUMBER_CONSTANT(CLASS_ANGEL) },
   { "drow",            NUMBER_CONSTANT(CLASS_DROW) },
   { "true",		NUMBER_CONSTANT(1) },
   { "false",		NUMBER_CONSTANT(0) },

   /* String AND number functions */
   { "generation",	STRING_FUNCTION(get_generation_text) },
   { "generation",	NUMBER_FUNCTION(get_generation) },
   { "strength",	STRING_FUNCTION(get_attribute_str_text) },
   { "strength",	NUMBER_FUNCTION(get_attribute_str) },
   { "intellect",       STRING_FUNCTION(get_attribute_int_text) },
   { "intellect",	NUMBER_FUNCTION(get_attribute_int) },
   { "wisdom",   	STRING_FUNCTION(get_attribute_wis_text) },
   { "wisdom",   	NUMBER_FUNCTION(get_attribute_wis) },
   { "dexterity",	STRING_FUNCTION(get_attribute_dex_text) },
   { "dexterity",	NUMBER_FUNCTION(get_attribute_dex) },
   { "constitution",    STRING_FUNCTION(get_attribute_con_text) },
   { "constitution",    NUMBER_FUNCTION(get_attribute_con) },
   { "get.weapon",	STRING_FUNCTION(get_wpn_text) },
   { "get.weapon",	NUMBER_FUNCTION(get_wpn) },
   { "weapon.type",	STRING_FUNCTION(wpn_type_text) },
   { "weapon.type",	NUMBER_FUNCTION(wpn_type) },
   { "weapon.damage",	STRING_FUNCTION(wpn_dam_text) },
   { "weapon.damage",	NUMBER_FUNCTION(wpn_dam) },
   { "wpn.where",	STRING_FUNCTION(wpn_where_text) },
   { "wpn.where",	NUMBER_FUNCTION(wpn_where) },

   { NULL,  END_OF_LIST } /* Always leave this at end */
};

/*********************************************************/

static jmp_buf jBuf;
static int s_iIndex;
static int s_iLevel;

int io_calculate( CHAR_DATA *ch, char *calculation )
{
   int iResult;

   s_iIndex = -1;
   s_iLevel = 0;

   if ( setjmp( jBuf ) )
   {
      return 0; /* Unable to perform calculation */
   }

   if ( calculation[0] == '\0' )
   {
      return 0; /* Unable to perform calculation */
   }

   iResult = main_calc( ch, calculation );

   if ( s_iLevel != 1 )
   {
      ch_printf( ch, "\nNon-matching brackets.\n");
      return 0;
   }

   s_iIndex = -1;
   s_iLevel = 0;

   return ( iResult );
}

static int main_calc( CHAR_DATA *ch, char calc_string[] )
{
   STATE_TYPE eState     = STATE_NONE;
   int        iLeft      = 0;
   int        iRight     = 0;
   bool       bLeftNeg   = FALSE;
   bool       bRightNeg  = FALSE;
   char       chOperator = 0;
   bool       bGLEqual   = FALSE;

   s_iLevel++;

   while ( calc_string[++s_iIndex] != '\0' )
   {
      switch ( calc_string[s_iIndex] )
      {
         case '0': case '1': case '2': case '3': case '4': 
         case '5': case '6': case '7': case '8': case '9': 
            switch ( eState )
            {
               case STATE_LEFT_SIGN:
                  bLeftNeg = TRUE;
               case STATE_NONE:
               case STATE_LEFT:
               case STATE_DONE_LEFT: /* TBD - check this */
                  eState = STATE_LEFT;
                  if ( bLeftNeg == TRUE ) iLeft = 0 - iLeft; /* Make positive */
                  iLeft *= 10;
                  iLeft += (int) (calc_string[s_iIndex] - '0');
                  if ( bLeftNeg == TRUE ) iLeft = 0 - iLeft; /* Make negative */
                  break;
               case STATE_RIGHT_SIGN:
                  bRightNeg = TRUE;
               case STATE_OPERATOR:
               case STATE_RIGHT:
                  eState = STATE_RIGHT;
                  if ( bRightNeg == TRUE ) iRight = 0 - iRight; /* Make positive */
                  iRight *= 10;
                  iRight += (int) (calc_string[s_iIndex] - '0');
                  if ( bRightNeg == TRUE ) iRight = 0 - iRight; /* Make negative */
                  break;
            }
            break;

         case '+': case '-': case '*': case '/':
            if ( eState == STATE_RIGHT )
            {
               switch ( chOperator )
               {
                  case '+':
                     iLeft = iLeft + iRight;
                     break;
                  case '-':
                     iLeft = iLeft - iRight;
                     break;
                  case '*':
                     iLeft = iLeft * iRight;
                     break;
                  case '/':
                     if ( iRight == 0 )
                     {
                        stc("\nDivision by zero.\n", ch );
                        longjmp( jBuf, 1 );
                     }
                     iLeft = iLeft / iRight;
                     break;
                  default:
                     stc("\nInvalid position of closed bracket.\n", ch );
                     longjmp( jBuf, 1 );
               }
               bRightNeg = FALSE;
               iRight = 0;
               eState = STATE_OPERATOR;
            }
            else if ( eState == STATE_NONE && calc_string[s_iIndex] == '-' )
            {
               bLeftNeg = TRUE;
               eState = STATE_LEFT_SIGN;
            }
            else if ( eState == STATE_OPERATOR && calc_string[s_iIndex] == '-' )
            {
               bRightNeg = TRUE;
               eState = STATE_RIGHT_SIGN;
            }
            else if ( eState > STATE_OPERATOR )
            {
               stc("\nInvalid position of operator.\n", ch );
               longjmp( jBuf, 1 );
            }
            else
            {
               eState = STATE_OPERATOR;
               chOperator = calc_string[s_iIndex];
            }
            break;

         case '=': case '!':
            if ( calc_string[s_iIndex+1] != '=' )
            {
               ch_printf(ch,"\nInvalid operator '%c'.\n", calc_string[s_iIndex] );
               longjmp( jBuf, 1 );
            }
            ++s_iIndex;
            if ( eState == STATE_RIGHT )
            {
               switch ( chOperator )
               {
                  case '=':
                     iLeft = (iLeft == iRight);
                     break;
                  case '!':
                     iLeft = (iLeft != iRight);
                     break;
                  default:
                     stc("\nInvalid position of closed bracket.\n", ch );
                     longjmp( jBuf, 1 );
               }
               bRightNeg = FALSE;
               iRight = 0;
            }
            else if ( eState > STATE_OPERATOR )
            {
               stc("\nInvalid position of operator.\n", ch );
               longjmp( jBuf, 1 );
            }
            else
            {
               eState = STATE_OPERATOR;
               chOperator = calc_string[s_iIndex-1];
            }
            break;

         case '<': case '>':
            if ( calc_string[s_iIndex+1] == '=' )
            {
               ++s_iIndex;
               bGLEqual = TRUE;
            }
            if ( eState == STATE_RIGHT )
            {
               switch ( chOperator )
               {
                  case '[':
                     iLeft = (iLeft <= iRight);
                     break;
                  case '<':
                     iLeft = (iLeft < iRight);
                     break;
                  case ']':
                     iLeft = (iLeft >= iRight);
                     break;
                  case '>':
                     iLeft = (iLeft > iRight);
                     break;
                  default:
                     stc("\nInvalid position of closed bracket.\n", ch );
                     longjmp( jBuf, 1 );
               }
               bRightNeg = FALSE;
               iRight = 0;
            }
            else if ( eState > STATE_OPERATOR )
            {
               stc("\nInvalid position of operator.\n", ch );
               longjmp( jBuf, 1 );
            }
            else
            {
               eState = STATE_OPERATOR;
               if ( bGLEqual )
               {
                  if ( calc_string[s_iIndex-1] == '<' )
                  {
                     chOperator = '[';
                  }
                  else /* calc_string[s_iIndex-1] == '>' */
                  {
                     chOperator = ']';
                  }
               }
               else
               {
                  chOperator = calc_string[s_iIndex];
               }
            }
            bGLEqual = FALSE;
            break;

         case '&':
            if ( calc_string[s_iIndex+1] != '&' )
            {
               ch_printf(ch,"\nInvalid operator '%c'.\n",calc_string[s_iIndex]);
               longjmp( jBuf, 1 );
            }
            ++s_iIndex;
            if ( eState == STATE_RIGHT )
            {
               switch ( chOperator )
               {
                  case '&':
                     iLeft = (iLeft && iRight);
                     break;
                  default:
                     stc("\nInvalid position of closed bracket.\n",ch );
                     longjmp( jBuf, 1 );
               }
               bRightNeg = FALSE;
               iRight = 0;
            }
            else if ( eState > STATE_OPERATOR )
            {
               stc("\nInvalid position of operator.\n",ch );
               longjmp( jBuf, 1 );
            }
            else
            {
               eState = STATE_OPERATOR;
               chOperator = calc_string[s_iIndex-1];
            }
            break;

         case '|':
            if ( calc_string[s_iIndex+1] != '|' )
            {
                ch_printf( ch,"\nInvalid operator '%c'.\n",
                           calc_string[s_iIndex] );
               longjmp( jBuf, 1 );
            }
            ++s_iIndex;
            if ( eState == STATE_RIGHT )
            {
               switch ( chOperator )
               {
                  case '|':
                     iLeft = (iLeft || iRight);
                     break;
                  default:
                     stc("\nInvalid position of closed bracket.\n",ch );
                     longjmp( jBuf, 1 );
               }
               bRightNeg = FALSE;
               iRight = 0;
            }
            else if ( eState > STATE_OPERATOR )
            {
               stc("\nInvalid position of operator.\n",ch );
               longjmp( jBuf, 1 );
            }
            else
            {
               eState = STATE_OPERATOR;
               chOperator = calc_string[s_iIndex-1];
            }
            break;

         case ' ':
            break;

         case '(':
            if ( eState == STATE_NONE )
            {
               iLeft = main_calc( ch, calc_string );
               eState = STATE_DONE_LEFT;
            }
            else if ( eState == STATE_OPERATOR )
            {
               iRight = main_calc( ch, calc_string );
               eState = STATE_RIGHT;
            }
            else
            {
               stc("\nInvalid position of open bracket.\n",ch );
               longjmp( jBuf, 1 );
            }
            break;

         case ')':
            s_iLevel--;
            if ( eState == STATE_DONE_LEFT || eState == STATE_LEFT )
            {
               return ( iLeft );
            }
            if ( eState != STATE_RIGHT )
            {
               stc("\nInvalid position of closed bracket.\n",ch );
               longjmp( jBuf, 1 );
            }
            switch ( chOperator )
            {
               case '+': return ( iLeft + iRight );
               case '-': return ( iLeft - iRight );
               case '*': return ( iLeft * iRight );
               case '/': 
                  if ( iRight == 0 )
                  {
                     stc("\nDivision by zero.\n", ch );
                     longjmp( jBuf, 1 );
                  }
                  return ( iLeft / iRight );
               case '=': return ( iLeft == iRight );
               case '!': return ( iLeft != iRight );
               case '<': return ( iLeft < iRight );
               case '>': return ( iLeft > iRight );
               case '[': return ( iLeft <= iRight );
               case ']': return ( iLeft >= iRight );
               case '&': return ( iLeft && iRight );
               case '|': return ( iLeft || iRight );
            }
            stc("\nInvalid position of closed bracket.\n",ch );
            longjmp( jBuf, 1 );

         case '\0':
            if ( s_iLevel > 1 )
            {
               ch_printf(ch,"\nInvalid character '%d'.\n", calc_string[s_iIndex] );
               longjmp( jBuf, 1 );
            }
            stc("\nDone.\n",ch );
            longjmp( jBuf, 1 );


         default: /* zzz */
            ch_printf(ch,"\nInvalid character '%c'.\n", calc_string[s_iIndex] );
            longjmp( jBuf, 1 );
      }
   };

   if ( s_iLevel != 1 )
   {
       stc("\nNon-matching brackets.\n", ch );
       longjmp( jBuf, 1 );
   }

   if ( eState != STATE_RIGHT )
   {
      if ( eState == STATE_DONE_LEFT || eState == STATE_LEFT )
      {
         return ( iLeft );
      }
      stc("\nInvalid calc_string.\n", ch );
      longjmp( jBuf, 1 );
   }
   switch ( chOperator )
   {
      case '+': return ( iLeft + iRight );
      case '-': return ( iLeft - iRight );
      case '*': return ( iLeft * iRight );
      case '/': 
         if ( iRight == 0 )
         {
            stc("\nDivision by zero.\n", ch );
            longjmp( jBuf, 1 );
         }
         return ( iLeft / iRight );
      case '=': return ( iLeft == iRight );
      case '!': return ( iLeft != iRight );
      case '<': return ( iLeft < iRight );
      case '>': return ( iLeft > iRight );
      case '[': return ( iLeft <= iRight );
      case ']': return ( iLeft >= iRight );
      case '&': return ( iLeft && iRight );
      case '|': return ( iLeft || iRight );
   }
   stc("\nInvalid calculation.\n", ch );

   return 0;
}

/*********************************************************/

void io_parse( CHAR_DATA *ch, char *in_ptr, char *out_ptr )
{
   char var_buf[256];
   int  var_count = 0;
   bool var_name = FALSE;
   char calc_buf[256];
   int  calc_count = 0;
   bool calc_name = FALSE;
   int  nest_text = 0;
   int  valid_nest = 0;
   OBJ_DATA *obj;

   obj = setup_variables( ch );

   while ( *in_ptr )
   {
      switch ( *in_ptr )
      {
         default:
            if ( valid_nest != nest_text )
            {
               in_ptr++;
            }
            else if ( var_name )
            {
               var_buf[var_count++] = *in_ptr++;
            }
            else if ( calc_name )
            {
               calc_buf[calc_count++] = *in_ptr++;
            }
            else
            {
               *out_ptr++ = *in_ptr++;
            }
            break;
         case '{':
            if ( valid_nest != nest_text )
            {
               in_ptr++;
               break;
            }
            in_ptr++;
            var_buf[var_count=0] = '\0';
            if ( var_name )
                stc( "Nested variable names not allowed.\n\r", ch );
            var_name = TRUE;
            break;
         case '}':
            if ( valid_nest != nest_text )
            {
               in_ptr++;
               break;
            }
            if ( !var_name )
                stc( "Variable terminator without variable.\n\r", ch );
            var_buf[var_count] = '\0';
            in_ptr++;
            var_name = FALSE;
            if ( calc_name )
            {
               number_var( &var_buf[0], &calc_buf[calc_count],ch,obj  );
               calc_count = strlen( calc_buf );
            }
            else
               string_var( &var_buf[0], &out_ptr,ch,obj ); /* String variable */
            break;
         case '[':
            if ( valid_nest != nest_text )
            {
               in_ptr++;
               break;
            }
            in_ptr++;
            calc_buf[calc_count=0] = '\0';
            if ( calc_name )
                stc( "Nested calculations not allowed.\n\r", ch );
            calc_name = TRUE;
            break;
         case ']':
            if ( valid_nest != nest_text )
            {
               nest_text++;
               in_ptr++;
               break;
            }
            if ( !calc_name )
                stc( "Calculation terminator without calculation.\n\r", ch );
            calc_buf[calc_count] = '\0';
            in_ptr++;
            nest_text++;
            valid_nest += !!io_calculate( ch, &calc_buf[0] );
            calc_name = FALSE;
            break;
         case '|':
            if ( --nest_text < 0 )
            {
               stc( "Conditional terminator without condition.\n\r", ch );
               nest_text = 0;
            }
            if ( valid_nest > nest_text ) valid_nest = nest_text;
            in_ptr++;
            break;
      }
   }
   *out_ptr = '\0';
}

bool string_var( char *var_ptr, char **out_ptr, CHAR_DATA *ch, OBJ_DATA *obj )
{
    int i = -1;

    while ( var_table[++i].variable != NULL )
    {
        if ( !strcmp( var_ptr, var_table[i].variable ) )
        {
            char *replace_ptr = NULL;

            switch ( var_table[i].type )
            {
            case VARIABLE_FUNCTION_STRING:
                replace_ptr = ((char*(*)())(var_table[i].replace))(ch,obj);
                break;
            case VARIABLE_CONSTANT_STRING:
                replace_ptr = var_table[i].replace;
                break;
            default: 
		continue; /* Cannot resolve numbers */
            }

            while ( *replace_ptr ) *(*out_ptr)++ = *replace_ptr++;

            return TRUE;
        }
    }
    return FALSE;
}

bool number_var( char *var_ptr, char *out_ptr, CHAR_DATA *ch, OBJ_DATA *obj )
{
    int i = -1;

    while ( var_table[++i].variable != NULL )
    {
        if ( !strcmp( var_ptr, var_table[i].variable ) )
        {
            int   replace_num = 0;
            char  replace_buf[64];
            char *replace_ptr = &replace_buf[0];

            switch ( var_table[i].type )
            {
            case VARIABLE_FUNCTION_NUMBER:
                replace_num = ((int(*)())(var_table[i].replace))(ch,obj);
                break;
            case VARIABLE_CONSTANT_NUMBER:
                replace_num = (int) var_table[i].replace;
               break;
            default: 
		continue; /* Cannot resolve strings */
            }

            sprintf( replace_ptr, "%d", replace_num );

            while ( (*out_ptr++ = *replace_ptr++) );

            return TRUE;
        }
    }
    return FALSE;
}

void io_display( CHAR_DATA *ch, char text[] )
{
    int align = 0;
    int i;

    while ( *text )
    {
        switch ( *text )
        {
        default:               
            ch_printf(  ch,"%c", *text );
            break;
        case '[':
            ch_printf(  ch,"\n");
            for ( i = 0; i < align; i++ ) stc( "   ",ch );
            stc( "[",ch );
            break;
         case ']':
            stc( "]\n",ch );
            align++;
            for ( i = 0; i < align; i++ ) stc( "   ",ch );
            break;
         case '|':
            stc( "\n",ch );
            align--;
            for ( i = 0; i < align; i++ ) stc( "   ",ch );
            stc( "|",ch );
            break;
      }
      text++;
   }
   stc( "\n",ch );
}

void io_main( CHAR_DATA *ch )
{
   char in_buf  [256];
   char out_buf [256];

   in_buf[0] = '\0';
   out_buf[0] = '\0';
   strcpy( in_buf, 
           "Hello there {name}!"
           "Your current strength is {strength}.");

//   io_display( ch, in_buf );

   io_parse( ch, in_buf, out_buf );

   ch_printf( ch, "String:[%s]\n\r", out_buf );
}

OBJ_DATA * setup_variables ( CHAR_DATA *ch )
{
   OBJ_DATA *obj,  *obj2, *wpn;

   wpn = NULL;
   
   for ( obj = ch->carrying; obj; obj = obj->next_content )
   {
      if ( obj->item_type == ITEM_WEAPON )
      {
         wpn = obj;
         break;
      }
   }

   if ( wpn )
       return wpn;

   for ( obj = ch->carrying; obj; obj = obj->next_content )
   {
      for ( obj2 = obj->contains; obj2; obj2 = obj2->next_content )
      {
         if ( obj2->item_type == ITEM_WEAPON )
         {
            wpn = obj2;
            break;
         }
      }
   }

   return wpn;
}