/*****************************************************************************
* DikuMUD (C) 1990, 1991 by: *
* Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen, *
* and Katja Nyboe. *
*---------------------------------------------------------------------------*
* MERC 2.1 (C) 1992, 1993 by: *
* Michael Chastain, Michael Quan, and Mitchell Tse. *
*---------------------------------------------------------------------------*
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider. *
* Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, *
* gorog, Grishnakh, Nivek, Tricops, and Fireblade. *
*---------------------------------------------------------------------------*
* SMAUG 1.7 FUSS by: Samson and others of the SMAUG community. *
* Their contributions are greatly appreciated. *
*---------------------------------------------------------------------------*
* LoP (C) 2006, 2007, 2008 by: the LoP team. *
*---------------------------------------------------------------------------*
* Table load/save Module *
*****************************************************************************/
#include <stdio.h>
#include <string.h>
#if !defined(WIN32)
#include <dlfcn.h>
#else
#include <windows.h>
#define dlsym( handle, name ) ( (void*)GetProcAddress( (HINSTANCE) (handle), (name) ) )
#define dlerror() GetLastError()
#endif
#include "h/mud.h"
SKILLTYPE *new_skill( void );
bool load_race_file( const char *fname );
bool can_use_slot( int slot );
char *help_fix( char *text );
char *un_fix_help( char *text );
void add_skill_help( SKILLTYPE *skill, bool update );
/* global variables */
int top_sn;
int top_herb;
int top_pers;
int MAX_PC_CLASS;
int MAX_PC_RACE;
SKILLTYPE *skill_table[MAX_SKILL];
SKILLTYPE *herb_table[MAX_HERB];
SKILLTYPE *pers_table[MAX_PERS];
LANG_DATA *first_lang, *last_lang;
const char *const skill_tname[] =
{
"unknown", "Spell", "Skill", "Weapon", "Tongue",
"Herb", "Personal", "Deleted"
};
SPELL_FUN *spell_function( char *name )
{
void *funHandle;
#if !defined(WIN32)
const char *error;
#else
DWORD error;
#endif
funHandle = dlsym( sysdata.dlHandle, name );
if( ( error = dlerror() ) )
{
bug( "Error locating %s in symbol table. %s", name, error );
return spell_notfound;
}
return (SPELL_FUN*)funHandle;
}
DO_FUN *skill_function( char *name )
{
void *funHandle;
#if !defined(WIN32)
const char *error;
#else
DWORD error;
#endif
funHandle = dlsym( sysdata.dlHandle, name );
if( ( error = dlerror() ) )
{
bug( "Error locating %s in symbol table. %s", name, error );
return skill_notfound;
}
return (DO_FUN*)funHandle;
}
/* Function used by qsort to sort skills */
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;
if( skill1->type < skill2->type )
return -1;
if( skill1->type > skill2->type )
return 1;
return strcasecmp( skill1->name, skill2->name );
}
/* Sort the skill table with qsort */
void sort_skill_table( void )
{
if( top_sn <= 0 )
return;
log_string( "Sorting skill table..." );
qsort( &skill_table[0], top_sn, sizeof( SKILLTYPE * ), ( int ( * )( const void *, const void * ) )skill_comp );
}
/* Remap slot numbers to sn values */
void remap_slot_numbers( void )
{
SKILLTYPE *skill;
SMAUG_AFF *aff;
char tmp[32];
int sn;
log_string( "Remapping slots to sns" );
gsn_first_spell = -1;
gsn_first_skill = -1;
gsn_first_weapon = -1;
gsn_first_tongue = -1;
gsn_top_sn = top_sn;
for( sn = 0; sn <= top_sn; sn++ )
{
if( ( skill = skill_table[sn] ) )
{
if( gsn_first_spell == -1 && skill->type == SKILL_SPELL )
gsn_first_spell = sn;
else if( gsn_first_skill == -1 && skill->type == SKILL_SKILL )
gsn_first_skill = sn;
else if( gsn_first_weapon == -1 && skill->type == SKILL_WEAPON )
gsn_first_weapon = sn;
else if( gsn_first_tongue == -1 && skill->type == SKILL_TONGUE )
gsn_first_tongue = sn;
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 )
{
snprintf( tmp, sizeof( tmp ), "%d", slot_lookup( atoi( aff->modifier ) ) );
STRFREE( aff->modifier );
aff->modifier = STRALLOC( tmp );
}
}
}
}
}
/* Write skill data to a file */
void fwrite_skill( FILE *fp, SKILLTYPE *skill )
{
SMAUG_AFF *aff;
int modifier;
fprintf( fp, "Name %s~\n", skill->name );
fprintf( fp, "Type %s\n", skill_tname[skill->type] );
if( skill->tmpspell )
fprintf( fp, "%s\n", "Spell" );
if( skill->damage )
fprintf( fp, "SDamage %s~\n", spell_damage[skill->damage] );
if( skill->action )
fprintf( fp, "SAction %s~\n", spell_action[skill->action] );
if( skill->Class )
fprintf( fp, "SClass %s~\n", spell_class[skill->Class] );
if( skill->power )
fprintf( fp, "SPower %s~\n", spell_power[skill->power] );
if( skill->save )
fprintf( fp, "SSave %s~\n", spell_save_effect[skill->save] );
if( !xIS_EMPTY( skill->flags ) )
fprintf( fp, "Flags %s~\n", ext_flag_string( &skill->flags, spell_flag ) );
if( skill->target )
fprintf( fp, "Target %s~\n", target_type[skill->target] );
if( skill->minimum_position )
fprintf( fp, "Minpos %s~\n", pos_names[skill->minimum_position] );
if( !xIS_EMPTY( skill->spell_sector ) )
fprintf( fp, "Ssector %s~\n", ext_flag_string( &skill->spell_sector, sect_flags ) );
if( skill->saves )
fprintf( fp, "Saves %d\n", skill->saves );
if( skill->slot != -1 )
fprintf( fp, "Slot %d\n", skill->slot );
if( skill->req_skill != -1 && is_valid_sn( skill->req_skill ) && skill_table[ skill->req_skill ] )
fprintf( fp, "ReqSkill '%s'\n", skill_table[ skill->req_skill ]->name );
if( skill->min_mana )
fprintf( fp, "Mana %d\n", skill->min_mana );
if( skill->beats )
fprintf( fp, "Rounds %d\n", skill->beats );
if( skill->range )
fprintf( fp, "Range %d\n", skill->range );
if( skill->skill_fun && skill->skill_fun_name )
fprintf( fp, "Code %s\n", skill->skill_fun_name );
else if( skill->spell_fun && skill->spell_fun_name )
fprintf( fp, "Code %s\n", skill->spell_fun_name );
if( skill->noun_damage )
fprintf( fp, "Dammsg %s~\n", skill->noun_damage );
if( skill->msg_off )
fprintf( fp, "Wearoff %s~\n", skill->msg_off );
if( skill->hit_char )
fprintf( fp, "Hitchar %s~\n", skill->hit_char );
if( skill->hit_vict )
fprintf( fp, "Hitvict %s~\n", skill->hit_vict );
if( skill->hit_room )
fprintf( fp, "Hitroom %s~\n", skill->hit_room );
if( skill->hit_dest )
fprintf( fp, "Hitdest %s~\n", skill->hit_dest );
if( skill->miss_char )
fprintf( fp, "Misschar %s~\n", skill->miss_char );
if( skill->miss_vict )
fprintf( fp, "Missvict %s~\n", skill->miss_vict );
if( skill->miss_room )
fprintf( fp, "Missroom %s~\n", skill->miss_room );
if( skill->die_char )
fprintf( fp, "Diechar %s~\n", skill->die_char );
if( skill->die_vict )
fprintf( fp, "Dievict %s~\n", skill->die_vict );
if( skill->die_room )
fprintf( fp, "Dieroom %s~\n", skill->die_room );
if( skill->imm_char )
fprintf( fp, "Immchar %s~\n", skill->imm_char );
if( skill->imm_vict )
fprintf( fp, "Immvict %s~\n", skill->imm_vict );
if( skill->imm_room )
fprintf( fp, "Immroom %s~\n", skill->imm_room );
if( skill->abs_char )
fprintf( fp, "Abschar %s~\n", skill->abs_char );
if( skill->abs_vict )
fprintf( fp, "Absvict %s~\n", skill->abs_vict );
if( skill->abs_room )
fprintf( fp, "Absroom %s~\n", skill->abs_room );
if( skill->dice )
fprintf( fp, "Dice %s~\n", skill->dice );
if( skill->value )
fprintf( fp, "Value %d\n", skill->value );
if( skill->difficulty )
fprintf( fp, "Difficulty %d\n", skill->difficulty );
if( skill->participants )
fprintf( fp, "Participants %d\n", skill->participants );
if( skill->components )
fprintf( fp, "Components %s~\n", skill->components );
if( skill->teachers )
fprintf( fp, "Teachers %s~\n", skill->teachers );
if( skill->htext )
fprintf( fp, "HText %s~\n", help_fix( skill->htext ) );
for( aff = skill->first_affect; aff; aff = aff->next )
{
fprintf( fp, "Affect '%s' '%s' %d ",
aff->duration ? aff->duration : "0", aff->location ? a_types[aff->location % REVERSE_APPLY] : "0",
aff->location >= REVERSE_APPLY ? 1 : 0 );
modifier = atoi( aff->modifier );
if( ( ( aff->location % REVERSE_APPLY ) >= APPLY_WEAPONSPELL
&& ( aff->location % REVERSE_APPLY ) <= APPLY_STRIPSN )
&& is_valid_sn( modifier ) )
fprintf( fp, "'%d' ", skill_table[modifier]->slot );
/* Change it back to a string */
else if( ( ( ( aff->location % REVERSE_APPLY ) == APPLY_RESISTANT
|| ( aff->location % REVERSE_APPLY ) == APPLY_IMMUNE
|| ( aff->location % REVERSE_APPLY ) == APPLY_SUSCEPTIBLE
|| ( aff->location % REVERSE_APPLY ) == APPLY_ABSORB ) )
&& modifier >= 0 && modifier < RIS_MAX )
fprintf( fp, "'%s' ", ris_flags[modifier] );
else if( ( aff->location % REVERSE_APPLY ) == APPLY_EXT_AFFECT
&& modifier >= 0 && modifier < AFF_MAX )
fprintf( fp, "'%s' ", a_flags[modifier] );
else
fprintf( fp, "'%s' ", aff->modifier );
if( ( aff->location % REVERSE_APPLY ) == APPLY_EXT_AFFECT
&& aff->bitvector >= 0 && aff->bitvector < AFF_MAX )
fprintf( fp, "'%s'\n", a_flags[aff->bitvector] );
else if( ( aff->location % REVERSE_APPLY ) == APPLY_STAT
&& aff->bitvector >= 0 && aff->bitvector < STAT_MAX )
fprintf( fp, "'%s'\n", stattypes[aff->bitvector] );
else
fprintf( fp, "'%d'\n", aff->bitvector );
}
fprintf( fp, "End\n\n" );
}
/* Save the skill table to disk */
void save_skill_table( bool autosave )
{
int x;
FILE *fp;
if( autosave && !sysdata.autosaveskills )
return;
if( !( fp = fopen( SKILL_FILE, "w" ) ) )
{
bug( "%s: Can't open %s for writting", __FUNCTION__, SKILL_FILE );
perror( SKILL_FILE );
return;
}
for( x = 0; x < top_sn; x++ )
{
if( !skill_table[x]->name || skill_table[x]->name[0] == '\0' || skill_table[x]->type == SKILL_DELETED )
continue;
fprintf( fp, "#SKILL\n" );
fwrite_skill( fp, skill_table[x] );
}
fprintf( fp, "#END\n" );
fclose( fp );
fp = NULL;
}
/* Save the herb table to disk */
void save_herb_table( bool autosave )
{
int x;
FILE *fp;
if( autosave && !sysdata.autosaveskills )
return;
if( !( fp = fopen( HERB_FILE, "w" ) ) )
{
bug( "Can't open %s for writting", HERB_FILE );
perror( HERB_FILE );
return;
}
for( x = 0; x < top_herb; x++ )
{
if( !herb_table[x]->name || herb_table[x]->name[0] == '\0' || herb_table[x]->type == SKILL_DELETED )
continue;
fprintf( fp, "#HERB\n" );
fwrite_skill( fp, herb_table[x] );
}
fprintf( fp, "#END\n" );
fclose( fp );
fp = NULL;
}
void save_pers_table( bool autosave )
{
int x;
FILE *fp;
if( autosave && !sysdata.autosaveskills )
return;
if( !( fp = fopen( PERSONAL_FILE, "w" ) ) )
{
bug( "Can't open %s for writting", PERSONAL_FILE );
perror( PERSONAL_FILE );
return;
}
for( x = 0; x < top_pers; x++ )
{
if( !pers_table[x]->name || pers_table[x]->name[0] == '\0' || pers_table[x]->type == SKILL_DELETED )
continue;
fprintf( fp, "#PERSONAL\n" );
fwrite_skill( fp, pers_table[x] );
}
fprintf( fp, "#END\n" );
fclose( fp );
fp = NULL;
}
int get_skill( char *skilltype )
{
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;
if( !str_cmp( skilltype, "Personal" ) )
return SKILL_PERSONAL;
if( !str_cmp( skilltype, "Deleted" ) )
return SKILL_DELETED;
return SKILL_UNKNOWN;
}
SKILLTYPE *fread_skill( FILE *fp )
{
SKILLTYPE *skill;
const char *word;
bool fMatch;
int value;
char *infoflags, flag[MSL];
if( !( skill = new_skill( ) ) )
{
bug( "%s: failed to create a new skill.", __FUNCTION__ );
return NULL;
}
for( ;; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = false;
switch( UPPER( word[0] ) )
{
case '*':
fMatch = true;
fread_to_eol( fp );
break;
case 'A':
KEY( "Abschar", skill->abs_char, fread_string( fp ) );
KEY( "Absroom", skill->abs_room, fread_string( fp ) );
KEY( "Absvict", skill->abs_vict, fread_string( fp ) );
if( !str_cmp( word, "Affect" ) )
{
SMAUG_AFF *aff;
char modifier[MIL];
bool dadd = false;
CREATE( aff, SMAUG_AFF, 1 );
aff->duration = STRALLOC( fread_word( fp ) );
infoflags = fread_word( fp );
if( str_cmp( infoflags, "0" ) )
{
/* Change blood to mana */
if( !str_cmp( infoflags, "Blood" ) )
infoflags = (char *)"Mana";
value = get_flag( infoflags, a_types, APPLY_MAX );
if( value < 0 || value >= APPLY_MAX )
{
bug( "%s(%s): Unknown apply %s",
__FUNCTION__, skill->name ? skill->name : "Unknown", infoflags );
aff->location = 0;
dadd = true;
}
else
aff->location = value;
}
else
aff->location = 0;
value = fread_number( fp );
if( value == 1 )
aff->location += REVERSE_APPLY;
infoflags = fread_word( fp );
if( ( aff->location % REVERSE_APPLY ) == APPLY_EXT_AFFECT )
{
value = get_flag( infoflags, a_flags, AFF_MAX );
if( value < 0 || value >= AFF_MAX )
{
bug( "%s(%s): Unknown affect %s", __FUNCTION__, skill->name ? skill->name : "Unknown",
infoflags );
aff->modifier = STRALLOC( "-1" );
dadd = true;
}
else
{
snprintf( modifier, sizeof( modifier ), "%d", value );
aff->modifier = STRALLOC( modifier );
}
}
else if( ( aff->location % REVERSE_APPLY ) == APPLY_RESISTANT
|| ( aff->location % REVERSE_APPLY ) == APPLY_IMMUNE
|| ( aff->location % REVERSE_APPLY ) == APPLY_SUSCEPTIBLE
|| ( aff->location % REVERSE_APPLY ) == APPLY_ABSORB )
{
value = get_flag( infoflags, ris_flags, RIS_MAX );
if( value < 0 || value >= RIS_MAX )
{
bug( "%s(%s): Unknown %s %s", __FUNCTION__, skill->name ? skill->name : "Unknown",
a_types[aff->location % REVERSE_APPLY], infoflags );
aff->modifier = STRALLOC( "-1" );
dadd = true;
}
else
{
snprintf( modifier, sizeof( modifier ), "%d", value );
aff->modifier = STRALLOC( modifier );
}
}
else
aff->modifier = STRALLOC( infoflags );
aff->bitvector = -1;
infoflags = fread_word( fp );
if( str_cmp( infoflags, "-1" ) )
{
if( ( aff->location % REVERSE_APPLY ) == APPLY_STAT )
{
value = get_flag( infoflags, stattypes, STAT_MAX );
if( value < 0 || value >= STAT_MAX )
{
bug( "%s(%s): Unknown stat %s",
__FUNCTION__, skill->name ? skill->name : "Unknown", infoflags );
dadd = true;
}
else
aff->bitvector = value;
}
else
{
value = get_flag( infoflags, a_flags, AFF_MAX );
if( value < 0 || value >= AFF_MAX )
{
bug( "%s(%s): Unknown affect %s",
__FUNCTION__, skill->name ? skill->name : "Unknown", infoflags );
dadd = true;
}
else
aff->bitvector = value;
}
}
if( !dadd )
LINK( aff, skill->first_affect, skill->last_affect, next, prev );
else
{
bug( "%s(%s): Something is bad in affect and it won't be added.",
__FUNCTION__, skill->name ? skill->name : "Unknown" );
STRFREE( aff->duration );
STRFREE( aff->modifier );
DISPOSE( aff );
}
fMatch = true;
break;
}
break;
case 'C':
if ( !str_cmp( word, "Code" ) )
{
SPELL_FUN *spellfun;
DO_FUN *dofun;
char *w = fread_word( fp );
fMatch = true;
if( !str_prefix( "do_", w ) && ( dofun = skill_function(w) ) != skill_notfound )
{
skill->skill_fun = dofun;
skill->skill_fun_name = STRALLOC(w);
}
else if( str_prefix( "do_", w ) && ( spellfun = spell_function(w) ) != spell_notfound )
{
skill->spell_fun = spellfun;
skill->spell_fun_name = STRALLOC(w);
}
else
{
bug( "%s(%s): unknown code %s", __FUNCTION__, skill->name ? skill->name : "Unknown", w );
skill->spell_fun = spell_null;
}
break;
}
KEY( "Components", skill->components, fread_string( fp ) );
break;
case 'D':
KEY( "Dammsg", skill->noun_damage, fread_string( fp ) );
KEY( "Dice", skill->dice, fread_string( fp ) );
KEY( "Diechar", skill->die_char, fread_string( fp ) );
KEY( "Dieroom", skill->die_room, fread_string( fp ) );
KEY( "Dievict", skill->die_vict, fread_string( fp ) );
KEY( "Difficulty", skill->difficulty, fread_number( fp ) );
break;
case 'E':
if( !str_cmp( word, "End" ) )
{
if( !skill->skill_fun && !skill->spell_fun )
bug( "%s(%s): No skill or spell code set.", __FUNCTION__, skill->name ? skill->name : "Unknown" );
if( skill->htext && skill->htext[0] == '.' && skill->htext[1] == ' ' )
{
char *tmptext = un_fix_help( skill->htext );
STRSET( skill->htext, tmptext );
}
if( skill->saves != 0 && SPELL_SAVE( skill ) == SE_NONE )
{
bug( "%s(%s): Has saving throw (%d) with no saving effect.",
__FUNCTION__, skill->name ? skill->name : "Unknown", skill->saves );
SET_SSAV( skill, SE_NEGATE );
}
add_skill_help( skill, false );
return skill;
}
break;
case 'F':
WEXTKEY( "Flags", skill->flags, fp, spell_flag, SF_MAX );
break;
case 'H':
KEY( "HText", skill->htext, fread_string( fp ) );
KEY( "Hitchar", skill->hit_char, fread_string( fp ) );
KEY( "Hitdest", skill->hit_dest, fread_string( fp ) );
KEY( "Hitroom", skill->hit_room, fread_string( fp ) );
KEY( "Hitvict", skill->hit_vict, fread_string( fp ) );
break;
case 'I':
KEY( "Immchar", skill->imm_char, fread_string( fp ) );
KEY( "Immroom", skill->imm_room, fread_string( fp ) );
KEY( "Immvict", skill->imm_vict, fread_string( fp ) );
break;
case 'M':
KEY( "Mana", skill->min_mana, fread_number( fp ) );
SKEY( "Minpos", skill->minimum_position, fp, pos_names, POS_MAX );
KEY( "Misschar", skill->miss_char, fread_string( fp ) );
KEY( "Missroom", skill->miss_room, fread_string( fp ) );
KEY( "Missvict", skill->miss_vict, fread_string( fp ) );
break;
case 'N':
KEY( "Name", skill->name, fread_string( 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, "ReqSkill" ) )
{
int sn;
infoflags = fread_word( fp );
if( ( sn = skill_lookup( infoflags ) ) < 0 )
bug( "%s: unknown skill (%s).", __FUNCTION__, infoflags );
else
skill->req_skill = sn;
fMatch = true;
break;
}
break;
case 'S':
if( !str_cmp( word, "Spell" ) )
{
skill->tmpspell = true;
fMatch = true;
break;
}
SKEY( "SDamage", skill->damage, fp, spell_damage, SD_MAX );
SKEY( "SAction", skill->action, fp, spell_action, SA_MAX );
SKEY( "SClass", skill->Class, fp, spell_class, SC_MAX );
SKEY( "SPower", skill->power, fp, spell_power, SP_MAX );
SKEY( "SSave", skill->save, fp, spell_save_effect, SE_MAX );
KEY( "Saves", skill->saves, fread_number( fp ) );
KEY( "Slot", skill->slot, fread_number( fp ) );
WEXTKEY( "Ssector", skill->spell_sector, fp, sect_flags, SECT_MAX );
break;
case 'T':
SKEY( "Target", skill->target, fp, target_type, TAR_MAX );
if( !str_cmp( word, "Teachers" ) )
{
char modifier[MSL];
modifier[0] = '\0';
infoflags = fread_flagstring( fp );
while( infoflags && infoflags[0] != '\0' )
{
infoflags = one_argument( infoflags, flag );
if( skill->type == SKILL_PERSONAL )
{
if( !valid_pfile( flag ) )
bug( "%s: [%s] doesn't have a matching pfile for teacher, for skill [%s].", __FUNCTION__, flag, skill->name ? skill->name : "Unknown" );
else
mudstrlcat( modifier, flag, sizeof( modifier ) );
}
else
{
if( get_mob_index( atoi( flag ) ) || skill->type == SKILL_PERSONAL )
mudstrlcat( modifier, flag, sizeof( modifier ) );
else
bug( "%s: [%s] isn't a valid teacher for skill [%s].", __FUNCTION__, flag,
skill->name ? skill->name : "Unknown" );
}
}
skill->teachers = STRALLOC( modifier );
fMatch = true;
break;
}
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( fp ) );
break;
}
if( !fMatch )
{
bug( "%s: no match: %s", __FUNCTION__, word );
fread_to_eol( fp );
}
}
}
void load_skill_table( void )
{
FILE *fp;
if( !( fp = fopen( SKILL_FILE, "r" ) ) )
{
perror( SKILL_FILE );
bug( "%s: Can't open %s", __FUNCTION__, SKILL_FILE );
exit( 0 );
}
top_sn = 0;
for( ;; )
{
char letter;
char *word;
letter = fread_letter( fp );
if( letter == '*' )
{
fread_to_eol( fp );
continue;
}
if( letter != '#' )
{
bug( "%s: (%c) found instead of a #.", __FUNCTION__, letter );
break;
}
word = fread_word( fp );
if( !str_cmp( word, "SKILL" ) )
{
if( top_sn >= MAX_SKILL )
{
bug( "%s: more skills than MAX_SKILL %d", __FUNCTION__, MAX_SKILL );
fclose( fp );
fp = NULL;
return;
}
skill_table[top_sn++] = fread_skill( fp );
continue;
}
else if( !str_cmp( word, "END" ) )
break;
else
{
bug( "%s: bad section (%s).", __FUNCTION__, word );
fread_to_eol( fp );
continue;
}
}
fclose( fp );
fp = NULL;
}
void load_herb_table( void )
{
FILE *fp;
if( !( fp = fopen( HERB_FILE, "r" ) ) )
{
bug( "%s: Can't open %s", __FUNCTION__, HERB_FILE );
exit( 0 );
}
top_herb = 0;
for( ;; )
{
char letter;
char *word;
letter = fread_letter( fp );
if( letter == '*' )
{
fread_to_eol( fp );
continue;
}
if( letter != '#' )
{
bug( "%s: (%c) found instead of a #.", __FUNCTION__, letter );
break;
}
word = fread_word( fp );
if( !str_cmp( word, "HERB" ) )
{
if( top_herb >= MAX_HERB )
{
bug( "%s: more herbs than MAX_HERB %d", __FUNCTION__, MAX_HERB );
fclose( fp );
fp = NULL;
return;
}
herb_table[top_herb++] = fread_skill( fp );
if( herb_table[top_herb - 1]->slot == -1 )
herb_table[top_herb - 1]->slot = top_herb - 1;
continue;
}
else if( !str_cmp( word, "END" ) )
break;
else
{
bug( "%s: bad section (%s).", __FUNCTION__, word );
fread_to_eol( fp );
continue;
}
}
fclose( fp );
fp = NULL;
}
void load_pers_table( void )
{
FILE *fp;
top_pers = 0;
if( !( fp = fopen( PERSONAL_FILE, "r" ) ) )
{
bug( "%s: Can't open %s", __FUNCTION__, PERSONAL_FILE );
return; /* This file isn't to big of a deal if it is missing */
}
for( ;; )
{
char letter;
char *word;
letter = fread_letter( fp );
if( letter == '*' )
{
fread_to_eol( fp );
continue;
}
if( letter != '#' )
{
bug( "%s: (%c) found instead of a #.", __FUNCTION__, letter );
break;
}
word = fread_word( fp );
if( !str_cmp( word, "PERSONAL" ) )
{
if( top_pers >= MAX_PERS )
{
bug( "%s: more personals than MAX_PERS %d", __FUNCTION__, MAX_PERS );
fclose( fp );
fp = NULL;
return;
}
pers_table[top_pers++] = fread_skill( fp );
if( pers_table[top_pers - 1]->slot == -1 )
pers_table[top_pers - 1]->slot = top_pers - 1;
continue;
}
else if( !str_cmp( word, "END" ) )
break;
else
{
bug( "%s: bad section (%s).", __FUNCTION__, word );
fread_to_eol( fp );
continue;
}
}
fclose( fp );
fp = NULL;
}
void free_tongues( void )
{
LANG_DATA *lang;
LCNV_DATA *lcnv;
while( ( lang = last_lang ) )
{
while( ( lcnv = lang->last_precnv ) )
{
UNLINK( lcnv, lang->first_precnv, lang->last_precnv, next, prev );
STRFREE( lcnv->old );
STRFREE( lcnv->lnew );
DISPOSE( lcnv );
}
while( ( lcnv = lang->last_cnv ) )
{
UNLINK( lcnv, lang->first_cnv, lang->last_cnv, next, prev );
STRFREE( lcnv->old );
STRFREE( lcnv->lnew );
DISPOSE( lcnv );
}
STRFREE( lang->name );
STRFREE( lang->alphabet );
UNLINK( lang, first_lang, last_lang, next, prev );
DISPOSE( lang );
}
}
/* Tongues / Languages loading/saving functions - Altrag */
void fread_cnv( FILE *fp, LCNV_DATA **first_cnv, LCNV_DATA **last_cnv )
{
LCNV_DATA *cnv;
char letter;
for( ;; )
{
letter = fread_letter( fp );
if( letter == '~' || letter == EOF )
break;
ungetc( letter, fp );
CREATE( cnv, LCNV_DATA, 1 );
cnv->old = STRALLOC( fread_word( fp ) );
cnv->olen = strlen( cnv->old );
cnv->lnew = STRALLOC( fread_word( fp ) );
cnv->nlen = strlen( cnv->lnew );
fread_to_eol( fp );
LINK( cnv, *first_cnv, *last_cnv, next, prev );
}
}
void load_tongues( void )
{
FILE *fp;
LANG_DATA *lng;
char *word, letter;
if( !( fp = fopen( TONGUE_FILE, "r" ) ) )
{
perror( TONGUE_FILE );
return;
}
for( ;; )
{
letter = fread_letter( fp );
if( letter == EOF )
return;
else if( letter == '*' )
{
fread_to_eol( fp );
continue;
}
else if( letter != '#' )
{
bug( "%s: Letter '%c' not #.", __FUNCTION__, letter );
exit( 0 );
}
word = fread_word( fp );
if( !str_cmp( word, "end" ) )
break;
fread_to_eol( fp );
CREATE( lng, LANG_DATA, 1 );
lng->name = STRALLOC( word );
fread_cnv( fp, &lng->first_precnv, &lng->last_precnv );
lng->alphabet = fread_string( fp );
fread_cnv( fp, &lng->first_cnv, &lng->last_cnv );
fread_to_eol( fp );
LINK( lng, first_lang, last_lang, next, prev );
}
fclose( fp );
fp = NULL;
}
void fwrite_langs( void )
{
FILE *fp;
LANG_DATA *lng;
LCNV_DATA *cnv;
if( !( fp = fopen( TONGUE_FILE, "w" ) ) )
{
perror( TONGUE_FILE );
return;
}
for( lng = first_lang; lng; lng = lng->next )
{
fprintf( fp, "#%s\n", lng->name );
for( cnv = lng->first_precnv; cnv; cnv = cnv->next )
fprintf( fp, "'%s' '%s'\n", cnv->old, cnv->lnew );
fprintf( fp, "~\n%s~\n", lng->alphabet );
for( cnv = lng->first_cnv; cnv; cnv = cnv->next )
fprintf( fp, "'%s' '%s'\n", cnv->old, cnv->lnew );
fprintf( fp, "\n" );
}
fprintf( fp, "#end\n\n" );
fclose( fp );
fp = NULL;
}