/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// * * -----------------------------------------------------------| (0...0) * * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( * * -----------------------------------------------------------| {o o} * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~* * Tricops and Fireblade | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Table load/save Module * ****************************************************************************/ #include <stdio.h> #include <string.h> #include <dlfcn.h> #include "mud.h" SKILLTYPE *skill_table[MAX_SKILL]; const SKILLTYPE *skill_table_bytype[MAX_SKILL]; /* * Function used by qsort to sort skills; sorts by name, not case sensitive. */ int skill_comp( SKILLTYPE ** sk1, SKILLTYPE ** sk2 ) { SKILLTYPE *skill1 = ( *sk1 ); SKILLTYPE *skill2 = ( *sk2 ); if( !skill1 && skill2 ) return 1; if( skill1 && !skill2 ) return -1; if( !skill1 && !skill2 ) return 0; // Sort without regard to case. return strcasecmp( skill1->name, skill2->name ); } /* * Function used by qsort to sort skills; sorts by type, * then by name, not case sensitive. */ int skill_comp_bytype( SKILLTYPE ** sk1, SKILLTYPE ** sk2 ) { SKILLTYPE *skill1 = ( *sk1 ); SKILLTYPE *skill2 = ( *sk2 ); if( !skill1 && skill2 ) return 1; if( skill1 && !skill2 ) return -1; if( !skill1 && !skill2 ) return 0; // sort by type, first if( skill1->type < skill2->type ) return -1; if( skill1->type > skill2->type ) return 1; // Sort without regard to case. return strcasecmp( skill1->name, skill2->name ); } /* * Sort the skill table with qsort */ void sort_skill_table( ) { int i; log_string( "Sorting skill table..." ); qsort( &skill_table[1], num_skills - 1, sizeof( SKILLTYPE * ), ( int ( * )( const void *, const void * ) )skill_comp ); log_string( "Creating skill table sorted by type..." ); // first, refresh the bytype table from the skill table for( i = 0; i < MAX_SKILL; ++i ) { skill_table_bytype[i] = skill_table[i]; } qsort( &skill_table_bytype[1], num_skills - 1, sizeof( SKILLTYPE * ), ( int ( * )( const void *, const void * ) )skill_comp_bytype ); } /* * Remap slot numbers to sn values */ void remap_slot_numbers( ) { SKILLTYPE *skill; SMAUG_AFF *aff; char tmp[32]; int sn; log_string( "Remapping slots to sns" ); for( sn = 0; sn <= num_skills; ++sn ) { if( ( skill = skill_table[sn] ) != NULL ) { for( aff = skill->first_affect; aff; aff = aff->next ) if( aff->location == APPLY_WEAPONSPELL || aff->location == APPLY_WEARSPELL || aff->location == APPLY_REMOVESPELL || aff->location == APPLY_STRIPSN || aff->location == APPLY_RECURRINGSPELL ) { snprintf( tmp, 32, "%d", slot_lookup( atoi( aff->modifier ) ) ); DISPOSE( aff->modifier ); aff->modifier = str_dup( tmp ); } } } } int get_skill( const char *skilltype ) { if( !str_cmp( skilltype, "Racial" ) ) return SKILL_RACIAL; if( !str_cmp( skilltype, "Spell" ) ) return SKILL_SPELL; if( !str_cmp( skilltype, "Skill" ) ) return SKILL_SKILL; if( !str_cmp( skilltype, "Weapon" ) ) return SKILL_WEAPON; if( !str_cmp( skilltype, "Tongue" ) ) return SKILL_TONGUE; if( !str_cmp( skilltype, "Herb" ) ) return SKILL_HERB; return SKILL_UNKNOWN; } SKILLTYPE *fread_skill( FILE * fp ) { const char *word; bool fMatch; bool got_info = false; SKILLTYPE *skill; int x; CREATE( skill, SKILLTYPE, 1 ); skill->slot = 0; skill->min_mana = 0; skill->guild = -1; skill->target = 0; skill->spell_sector = 0; for( ;; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = false; switch ( UPPER( word[0] ) ) { case '*': fMatch = true; fread_to_eol( fp ); break; case 'A': if( !str_cmp( word, "Affect" ) ) { SMAUG_AFF *aff; CREATE( aff, SMAUG_AFF, 1 ); aff->duration = str_dup( fread_word( fp ) ); aff->location = fread_number( fp ); aff->modifier = str_dup( fread_word( fp ) ); aff->bitvector = fread_number( fp ); if( !got_info ) { for( x = 0; x < 32; ++x ) { if( IS_SET( aff->bitvector, 1 << x ) ) { aff->bitvector = x; break; } } if( x == 32 ) aff->bitvector = -1; } LINK( aff, skill->first_affect, skill->last_affect, next, prev ); fMatch = true; break; } break; case 'C': if( !str_cmp( word, "Class" ) ) { fread_number( fp ); fread_number( fp ); fread_number( fp ); fMatch = true; break; } if( !str_cmp( word, "Code" ) ) { skill->skill_fun_name = fread_string_nohash( fp ); fMatch = true; break; } KEY( "Components", skill->components, fread_string_nohash( fp ) ); break; case 'D': KEY( "Dammsg", skill->noun_damage, fread_string_nohash( fp ) ); KEY( "Dice", skill->dice, fread_string_nohash( fp ) ); KEY( "Diechar", skill->die_char, fread_string_nohash( fp ) ); KEY( "Dieroom", skill->die_room, fread_string_nohash( fp ) ); KEY( "Dievict", skill->die_vict, fread_string_nohash( fp ) ); KEY( "Difficulty", skill->difficulty, fread_number( fp ) ); break; case 'E': if( !str_cmp( word, "End" ) ) { if( skill->saves != 0 && SPELL_SAVE( skill ) == SE_NONE ) { bug( "%s (%s): Has saving throw (%d) with no saving effect.", __FUNCTION__, skill->name, skill->saves ); SET_SSAV( skill, SE_NEGATE ); } return skill; } break; case 'F': if( !str_cmp( word, "Flags" ) ) { skill->flags = fread_number( fp ); /* * convert to new style -Thoric */ if( !got_info ) { skill->info = skill->flags & ( BV11 - 1 ); if( IS_SET( skill->flags, OLD_SF_SAVE_NEGATES ) ) { if( IS_SET( skill->flags, OLD_SF_SAVE_HALF_DAMAGE ) ) { SET_SSAV( skill, SE_QUARTERDAM ); REMOVE_BIT( skill->flags, OLD_SF_SAVE_HALF_DAMAGE ); } else SET_SSAV( skill, SE_NEGATE ); REMOVE_BIT( skill->flags, OLD_SF_SAVE_NEGATES ); } else if( IS_SET( skill->flags, OLD_SF_SAVE_HALF_DAMAGE ) ) { SET_SSAV( skill, SE_HALFDAM ); REMOVE_BIT( skill->flags, OLD_SF_SAVE_HALF_DAMAGE ); } skill->flags >>= 11; } fMatch = true; break; } break; case 'G': KEY( "Guild", skill->guild, fread_number( fp ) ); break; case 'H': KEY( "Hitchar", skill->hit_char, fread_string_nohash( fp ) ); KEY( "Hitdest", skill->hit_dest, fread_string_nohash( fp ) ); KEY( "Hitroom", skill->hit_room, fread_string_nohash( fp ) ); KEY( "Hitvict", skill->hit_vict, fread_string_nohash( fp ) ); break; case 'I': KEY( "Immchar", skill->imm_char, fread_string_nohash( fp ) ); KEY( "Immroom", skill->imm_room, fread_string_nohash( fp ) ); KEY( "Immvict", skill->imm_vict, fread_string_nohash( fp ) ); if( !str_cmp( word, "Info" ) ) { skill->info = fread_number( fp ); got_info = true; fMatch = true; break; } break; case 'M': KEY( "Mana", skill->min_mana, fread_number( fp ) ); if( !str_cmp( word, "Minlevel" ) ) { fread_to_eol( fp ); fMatch = true; break; } /* * */ if( !str_cmp( word, "Minpos" ) ) { fMatch = true; skill->minimum_position = fread_number( fp ); if( skill->minimum_position < 100 ) { switch ( skill->minimum_position ) { default: case 0: case 1: case 2: case 3: case 4: break; case 5: skill->minimum_position = 6; break; case 6: skill->minimum_position = 8; break; case 7: skill->minimum_position = 9; break; case 8: skill->minimum_position = 12; break; case 9: skill->minimum_position = 13; break; case 10: skill->minimum_position = 14; break; case 11: skill->minimum_position = 15; break; } } else skill->minimum_position -= 100; break; } KEY( "Misschar", skill->miss_char, fread_string_nohash( fp ) ); KEY( "Missroom", skill->miss_room, fread_string_nohash( fp ) ); KEY( "Missvict", skill->miss_vict, fread_string_nohash( fp ) ); break; case 'N': KEY( "Name", skill->name, fread_string_nohash( fp ) ); break; case 'P': KEY( "Participants", skill->participants, fread_number( fp ) ); break; case 'R': KEY( "Range", skill->range, fread_number( fp ) ); KEY( "Rounds", skill->beats, fread_number( fp ) ); if( !str_cmp( word, "Race" ) ) { fread_number( fp ); fread_number( fp ); fread_number( fp ); fMatch = true; break; } break; case 'S': KEY( "Saves", skill->saves, fread_number( fp ) ); KEY( "Slot", skill->slot, fread_number( fp ) ); KEY( "Ssector", skill->spell_sector, fread_number( fp ) ); break; case 'T': KEY( "Target", skill->target, fread_number( fp ) ); KEY( "Teachers", skill->teachers, fread_string_nohash( fp ) ); KEY( "Type", skill->type, get_skill( fread_word( fp ) ) ); break; case 'V': KEY( "Value", skill->value, fread_number( fp ) ); break; case 'W': KEY( "Wearoff", skill->msg_off, fread_string_nohash( fp ) ); break; } if( !fMatch ) { bug( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( fp ); } } } void load_skill_table( ) { FILE *fp; if( ( fp = fopen( SKILL_FILE, "r" ) ) != NULL ) { num_skills = 0; for( ;; ) { char letter; char *word; letter = fread_letter( fp ); if( letter == '*' ) { fread_to_eol( fp ); continue; } if( letter != '#' ) { bug( "%s: # not found.", __FUNCTION__ ); break; } word = fread_word( fp ); if( !str_cmp( word, "SKILL" ) ) { if( num_skills >= MAX_SKILL ) { bug( "%s: more skills than MAX_SKILL %d", __FUNCTION__, MAX_SKILL ); fclose( fp ); fp = NULL; return; } skill_table[num_skills++] = fread_skill( fp ); continue; } else if( !str_cmp( word, "END" ) ) break; else { bug( "%s: bad section.", __FUNCTION__ ); continue; } } fclose( fp ); fp = NULL; } else { perror( SKILL_FILE ); bug( "Cannot open %s", SKILL_FILE ); exit( 0 ); } }