/****************************************************************************** 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; }