Bug: The setclass command was the victim of a bad cut/paste
Danger: Medium - Blocks access to proper settings while providing false syntax information
Found by: Remcon
Fixed by: Samson
---
act_wiz.c
Locate the do_setclass function and replace it with:
/*
* Edit class information -Thoric
*/
void do_setclass( CHAR_DATA * ch, char *argument )
{
char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
FILE *fpList;
char classlist[256];
struct class_type *Class;
int cl, value, i;
set_char_color( AT_PLAIN, ch );
smash_tilde( argument );
argument = one_argument( argument, arg1 );
argument = one_argument( argument, arg2 );
if( arg1[0] == '\0' )
{
send_to_char( "Syntax: setclass <class> <field> <value>\n\r", ch );
send_to_char( "Syntax: setclass <class> create\n\r", ch );
send_to_char( "\n\rField being one of:\n\r", ch );
send_to_char( " name prime weapon guild thac0 thac32\n\r", ch );
send_to_char( " hpmin hpmax mana expbase mtitle ftitle\n\r", ch );
send_to_char( " second, deficient affected resist suscept skill\n\r", ch );
return;
}
if( is_number( arg1 ) && ( cl = atoi( arg1 ) ) >= 0 && cl < MAX_CLASS )
Class = class_table[cl];
else
{
Class = NULL;
for( cl = 0; cl < MAX_CLASS && class_table[cl]; cl++ )
{
if( !class_table[cl]->who_name )
continue;
if( !str_cmp( class_table[cl]->who_name, arg1 ) )
{
Class = class_table[cl];
break;
}
}
}
if( !str_cmp( arg2, "create" ) && Class )
{
send_to_char( "That class already exists!\n\r", ch );
return;
}
if( !Class && str_cmp( arg2, "create" ) )
{
send_to_char( "No such class.\n\r", ch );
return;
}
if( !str_cmp( arg2, "create" ) )
{
if( MAX_PC_CLASS >= MAX_CLASS )
{
send_to_char( "You need to up MAX_CLASS in mud and make clean.\n\r", ch );
return;
}
if( ( create_new_class( MAX_PC_CLASS, arg1 ) ) == FALSE )
{
send_to_char( "Couldn't create a new class.\n\r", ch );
return;
}
write_class_file( MAX_PC_CLASS );
MAX_PC_CLASS++;
snprintf( classlist, 256, "%s%s", CLASS_DIR, CLASS_LIST );
if( !( fpList = fopen( classlist, "w" ) ) )
{
bug( "%s", "Can't open class list for writing." );
return;
}
for( i = 0; i < MAX_PC_CLASS; i++ )
fprintf( fpList, "%s%s.class\n", CLASSDIR, class_table[i]->who_name );
fprintf( fpList, "%s", "$\n" );
fclose( fpList );
fpList = NULL;
send_to_char( "Done.\n\r", ch );
return;
}
if( !argument )
{
send_to_char( "You must specify an argument.\n\r", ch );
return;
}
if( !str_cmp( arg2, "skill" ) )
{
SKILLTYPE *skill;
int sn, level, adept;
argument = one_argument( argument, arg2 );
if( ( sn = skill_lookup( arg2 ) ) > 0 )
{
skill = get_skilltype( sn );
argument = one_argument( argument, arg2 );
level = atoi( arg2 );
argument = one_argument( argument, arg2 );
adept = atoi( arg2 );
skill->skill_level[cl] = level;
skill->skill_adept[cl] = adept;
write_class_file( cl );
ch_printf( ch, "Skill \"%s\" added at level %d and %d%%.\n\r", skill->name, level, adept );
}
else
ch_printf( ch, "No such skill as %s.\n\r", arg2 );
return;
}
if( !str_cmp( arg2, "name" ) )
{
char buf[256];
snprintf( buf, 256, "%s%s.class", CLASSDIR, Class->who_name );
STRFREE( Class->who_name );
Class->who_name = STRALLOC( capitalize( argument ) );
ch_printf( ch, "class %s renamed to %s.\n\r", arg1, argument );
write_class_file( cl );
unlink( buf );
snprintf( classlist, 256, "%s%s", CLASS_DIR, CLASS_LIST );
if( !( fpList = fopen( classlist, "w" ) ) )
{
bug( "%s", "Can't open class list for writing." );
return;
}
for( i = 0; i < MAX_PC_CLASS; i++ )
fprintf( fpList, "%s%s.class\n", CLASSDIR, class_table[i]->who_name );
fprintf( fpList, "%s", "$\n" );
fclose( fpList );
fpList = NULL;
return;
}
if( !str_cmp( arg2, "affected" ) )
{
if( !argument || argument[0] == '\0' )
{
send_to_char( "Usage: setclass <class> affected <flag> [flag]...\n\r", ch );
return;
}
while( argument[0] != '\0' )
{
argument = one_argument( argument, arg2 );
value = get_aflag( arg2 );
if( value < 0 || value > MAX_BITS )
ch_printf( ch, "Unknown flag: %s\n\r", arg2 );
else
xTOGGLE_BIT( Class->affected, value );
}
send_to_char( "Done.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "resist" ) )
{
if( !argument || argument[0] == '\0' )
{
send_to_char( "Usage: setclass <class> resist <flag> [flag]...\n\r", ch );
return;
}
while( argument[0] != '\0' )
{
argument = one_argument( argument, arg2 );
value = get_risflag( arg2 );
if( value < 0 || value > 31 )
ch_printf( ch, "Unknown flag: %s\n\r", arg2 );
else
TOGGLE_BIT( Class->resist, 1 << value );
}
send_to_char( "Done.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "suscept" ) )
{
if( !argument || argument[0] == '\0' )
{
send_to_char( "Usage: setclass <class> suscept <flag> [flag]...\n\r", ch );
return;
}
while( argument[0] != '\0' )
{
argument = one_argument( argument, arg2 );
value = get_risflag( arg2 );
if( value < 0 || value > 31 )
ch_printf( ch, "Unknown flag: %s\n\r", arg2 );
else
TOGGLE_BIT( Class->suscept, 1 << value );
}
send_to_char( "Done.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "second" ) )
{
int x = get_atype( argument );
if( x < APPLY_STR || ( x > APPLY_CON && x != APPLY_LCK ) )
send_to_char( "Invalid second attribute!\n\r", ch );
else
{
Class->attr_second = x;
send_to_char( "Second attribute set.\n\r", ch );
}
return;
}
if( !str_cmp( arg2, "deficient" ) )
{
int x = get_atype( argument );
if( x < APPLY_STR || ( x > APPLY_CON && x != APPLY_LCK ) )
send_to_char( "Invalid deficient attribute!\n\r", ch );
else
{
Class->attr_deficient = x;
send_to_char( "Deficient attribute set.\n\r", ch );
write_class_file( cl );
}
return;
}
if( !str_cmp( arg2, "prime" ) )
{
int x = get_atype( argument );
if( x < APPLY_STR || ( x > APPLY_CON && x != APPLY_LCK ) )
send_to_char( "Invalid prime attribute!\n\r", ch );
else
{
Class->attr_prime = x;
send_to_char( "Prime attribute set.\n\r", ch );
write_class_file( cl );
}
return;
}
if( !str_cmp( arg2, "weapon" ) )
{
Class->weapon = atoi( argument );
send_to_char( "Starting weapon set.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "guild" ) )
{
Class->guild = atoi( argument );
send_to_char( "Guild set.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "thac0" ) )
{
Class->thac0_00 = atoi( argument );
send_to_char( "thac0 set.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "thac32" ) )
{
Class->thac0_32 = atoi( argument );
send_to_char( "thac32 set.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "hpmin" ) )
{
Class->hp_min = atoi( argument );
send_to_char( "Min HP gain set.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "hpmax" ) )
{
Class->hp_max = atoi( argument );
send_to_char( "Max HP gain set.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "mana" ) )
{
if( UPPER( argument[0] ) == 'Y' )
Class->fMana = TRUE;
else
Class->fMana = FALSE;
send_to_char( "Mana flag toggled.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "expbase" ) )
{
Class->exp_base = atoi( argument );
send_to_char( "Base EXP set.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "mtitle" ) )
{
char arg3[MAX_INPUT_LENGTH];
int x;
argument = one_argument( argument, arg3 );
if( arg3[0] == '\0' || argument[0] == '\0' )
{
send_to_char( "Syntax: setclass <class> mtitle <level> <title>\n\r", ch );
return;
}
if( ( x = atoi( arg3 ) ) < 0 || x > MAX_LEVEL )
{
send_to_char( "Invalid level.\n\r", ch );
return;
}
STRFREE( title_table[cl][x][SEX_MALE] );
title_table[cl][x][SEX_MALE] = STRALLOC( argument );
send_to_char( "Done.\n\r", ch );
write_class_file( cl );
return;
}
if( !str_cmp( arg2, "ftitle" ) )
{
char arg3[MAX_INPUT_LENGTH], arg4[MAX_INPUT_LENGTH];
int x;
argument = one_argument( argument, arg3 );
argument = one_argument( argument, arg4 );
if( arg3[0] == '\0' || argument[0] == '\0' )
{
send_to_char( "Syntax: setclass <class> ftitle <level> <title>\n\r", ch );
return;
}
if( ( x = atoi( arg4 ) ) < 0 || x > MAX_LEVEL )
{
send_to_char( "Invalid level.\n\r", ch );
return;
}
STRFREE( title_table[cl][x][SEX_FEMALE] );
/*
* Bug fix below -Shaddai
*/
title_table[cl][x][SEX_FEMALE] = STRALLOC( argument );
send_to_char( "Done\n\r", ch );
write_class_file( cl );
return;
}
do_setclass( ch, "" );
}
When the setclass command was fixed originally it was cut and pasted from the same code in the version of AFKMud which was current at the time. This was a big oops. The syntax message said there were options which were available that weren't, and the actual code was missing cases for options that should have been available. This should be corrected now.