dotd-2.3.7/area/
dotd-2.3.7/clans/
dotd-2.3.7/classes/
dotd-2.3.7/councils/
dotd-2.3.7/deity/
dotd-2.3.7/dict/
dotd-2.3.7/doc/mudprogs/
dotd-2.3.7/player/a/
dotd-2.3.7/player/g/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.0 (C) 1994, 1995, 1996 by Derek Snider             |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh and Tricops  |~'~.VxvxV.~'~*
 * ------------------------------------------------------------------------ *
 * 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				    *
 ****************************************************************************/

/*static char rcsid[] = "$Id: tables.c,v 1.40 2004/04/06 22:00:11 dotd Exp $";*/

#include <time.h>
#include <stdio.h>
#include <string.h>
#include "mud.h"

/*
 * Command functions.
 * Defined in act_*.c (mostly).
 */
#define ACMD DECLARE_DO_FUN
#define TABLES_C_ALL
#include "tables.h"
#undef TABLES_C_ALL
#undef ACMD

/*
 * Spell functions.
 * Defined in magic.c.
 */
#define ACMD DECLARE_SPELL_FUN
#define MAGIC_C_ALL
#include "magic.h"
#undef MAGIC_C_ALL
#undef ACMD

#if defined(KEY)
#undef KEY
#endif

#define KEY( literal, field, value )					\
				if ( !str_cmp( word, literal ) )	\
				{					\
				    field  = value;			\
				    fMatch = TRUE;			\
				    break;				\
				}


/* global variables */
int top_sn;
int top_herb;

SKILLTYPE *		skill_table	[MAX_SKILL];
struct	class_type *	class_table	[REAL_MAX_CLASS];
char *			title_table	[REAL_MAX_CLASS]
					[MAX_LEVEL+1]
					[2];
SKILLTYPE *		herb_table	[MAX_HERB];
LANG_DATA *		first_lang;
LANG_DATA *		last_lang;


char * const skill_tname[] =
{ "unknown", "Spell", "Skill", "Weapon", "Tongue", "Herb", "Lore", "PsiSpell" };


int get_skill_tname(char *tname)
{
    int x;

    for (x=1;x<SKILL_MAXTYPE;x++)
        if (!str_cmp(tname, skill_tname[x]))
            return x;

    return SKILL_UNKNOWN;
}

#define ACMD(func) if (!str_cmp( name, #func )) return func;
SPELL_FUN *spell_function( char *name )
{
    if ( !str_cmp( name, "reserved" ))		     return NULL;
    if ( !str_cmp( name, "spell_null" ))	     return spell_null;

#include "magic.h"

    return spell_notfound;
}

static DO_FUN *skill_function_a( const char *name )
{
#define TABLES_C_A
#include "tables.h"
#undef TABLES_C_A
    return skill_notfound;
}
static DO_FUN *skill_function_b( const char *name )
{
#define TABLES_C_B
#include "tables.h"
#undef TABLES_C_B
    return skill_notfound;
}
static DO_FUN *skill_function_c( const char *name )
{
#define TABLES_C_C
#include "tables.h"
#undef TABLES_C_C
    return skill_notfound;
}
static DO_FUN *skill_function_d( const char *name )
{
#define TABLES_C_D
#include "tables.h"
#undef TABLES_C_D
    return skill_notfound;
}
static DO_FUN *skill_function_e( const char *name )
{
#define TABLES_C_E
#include "tables.h"
#undef TABLES_C_E
    return skill_notfound;
}
static DO_FUN *skill_function_f( const char *name )
{
#define TABLES_C_F
#include "tables.h"
#undef TABLES_C_F
    return skill_notfound;
}
static DO_FUN *skill_function_g( const char *name )
{
#define TABLES_C_G
#include "tables.h"
#undef TABLES_C_G
    return skill_notfound;
}
static DO_FUN *skill_function_h( const char *name )
{
#define TABLES_C_H
#include "tables.h"
#undef TABLES_C_H
    return skill_notfound;
}
static DO_FUN *skill_function_i( const char *name )
{
#define TABLES_C_I
#include "tables.h"
#undef TABLES_C_I
    return skill_notfound;
}
static DO_FUN *skill_function_j( const char *name )
{
#define TABLES_C_J
#include "tables.h"
#undef TABLES_C_J
    return skill_notfound;
}
static DO_FUN *skill_function_k( const char *name )
{
#define TABLES_C_K
#include "tables.h"
#undef TABLES_C_K
    return skill_notfound;
}
static DO_FUN *skill_function_l( const char *name )
{
#define TABLES_C_L
#include "tables.h"
#undef TABLES_C_L
    return skill_notfound;
}
static DO_FUN *skill_function_m( const char *name )
{
#define TABLES_C_M
#include "tables.h"
#undef TABLES_C_M
    return skill_notfound;
}
static DO_FUN *skill_function_n( const char *name )
{
#define TABLES_C_N
#include "tables.h"
#undef TABLES_C_N
    return skill_notfound;
}
static DO_FUN *skill_function_o( const char *name )
{
#define TABLES_C_O
#include "tables.h"
#undef TABLES_C_O
    return skill_notfound;
}
static DO_FUN *skill_function_p( const char *name )
{
#define TABLES_C_P
#include "tables.h"
#undef TABLES_C_P
    return skill_notfound;
}
static DO_FUN *skill_function_q( const char *name )
{
#define TABLES_C_Q
#include "tables.h"
#undef TABLES_C_Q
    return skill_notfound;
}
static DO_FUN *skill_function_r( const char *name )
{
#define TABLES_C_R
#include "tables.h"
#undef TABLES_C_R
    return skill_notfound;
}
static DO_FUN *skill_function_s( const char *name )
{
#define TABLES_C_S
#include "tables.h"
#undef TABLES_C_S
    return skill_notfound;
}
static DO_FUN *skill_function_t( const char *name )
{
#define TABLES_C_T
#include "tables.h"
#undef TABLES_C_T
    return skill_notfound;
}
static DO_FUN *skill_function_u( const char *name )
{
#define TABLES_C_U
#include "tables.h"
#undef TABLES_C_U
    return skill_notfound;
}
static DO_FUN *skill_function_v( const char *name )
{
#define TABLES_C_V
#include "tables.h"
#undef TABLES_C_V
    return skill_notfound;
}
static DO_FUN *skill_function_w( const char *name )
{
#define TABLES_C_W
#include "tables.h"
#undef TABLES_C_W
    return skill_notfound;
}
static DO_FUN *skill_function_x( const char *name )
{
#define TABLES_C_X
#include "tables.h"
#undef TABLES_C_X
    return skill_notfound;
}
static DO_FUN *skill_function_y( const char *name )
{
#define TABLES_C_Y
#include "tables.h"
#undef TABLES_C_Y
    return skill_notfound;
}
static DO_FUN *skill_function_z( const char *name )
{
#define TABLES_C_Z
#include "tables.h"
#undef TABLES_C_Z
    return skill_notfound;
}
#undef ACMD

DO_FUN *skill_function( char *name )
{
    switch( name[3] )
    {
    case 'a': return(skill_function_a(name)); break;
    case 'b': return(skill_function_b(name)); break;
    case 'c': return(skill_function_c(name)); break;
    case 'd': return(skill_function_d(name)); break;
    case 'e': return(skill_function_e(name)); break;
    case 'f': return(skill_function_f(name)); break;
    case 'g': return(skill_function_g(name)); break;
    case 'h': return(skill_function_h(name)); break;
    case 'i': return(skill_function_i(name)); break;
    case 'j': return(skill_function_j(name)); break;
    case 'k': return(skill_function_k(name)); break;
    case 'l': return(skill_function_l(name)); break;
    case 'm': return(skill_function_m(name)); break;
    case 'n': return(skill_function_n(name)); break;
    case 'o': return(skill_function_o(name)); break;
    case 'p': return(skill_function_p(name)); break;
    case 'q': return(skill_function_q(name)); break;
    case 'r': return(skill_function_r(name)); break;
    case 's': return(skill_function_s(name)); break;
    case 't': return(skill_function_t(name)); break;
    case 'u': return(skill_function_u(name)); break;
    case 'v': return(skill_function_v(name)); break;
    case 'w': return(skill_function_w(name)); break;
    case 'x': return(skill_function_x(name)); break;
    case 'y': return(skill_function_y(name)); break;
    case 'z': return(skill_function_z(name)); break;
    }
    return skill_notfound;
}

char *spell_name( SPELL_FUN *spell )
{
    if ( spell == spell_smaug )		    return "spell_smaug";
    if ( spell == spell_null )		    return "spell_null";

#define ACMD(func) if ( spell == func ) return #func
#include "magic.h"
#undef ACMD

    return "reserved";
}

char *skill_name( DO_FUN *skill )
{
#define ACMD(func) if ( skill == func ) return #func
#define TABLES_C_ALL
#include "tables.h"
#undef TABLES_C_ALL
#undef ACMD

    return "reserved";
}

bool load_class_file( const char *fname )
{
    char buf[MAX_STRING_LENGTH];
    const char *word = NULL;
    bool fMatch = FALSE;
    struct class_type *clt;
    sh_int cl = CLASS_NONE;
    int tlev = 0, i=0;
    FILE *fp;

    sprintf( buf, "%s%s", CLASS_DIR, fname );
    if ( ( fp = fopen( buf, "r" ) ) == NULL )
    {
	perror( buf );
	return FALSE;
    }

    CREATE( clt, struct class_type, 1 );

    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( "AttrPrime",	clt->attr_prime,	fread_number( fp )	);
	    KEY( "AttrString",	clt->attr_string,	fread_string( fp )	);
	    break;

	case 'C':
	    KEY( "Class",	cl,			fread_number( fp )	);
	    break;

	case 'E':
	    if ( !str_cmp( word, "End" ) )
	    {
		FCLOSE( fp );
		if ( cl < 0 || cl >= MAX_CLASS || !clt->who_name )
		{
                    boot_log("Load_class_file: Class (%s) bad/not found (%d)",
                             clt->who_name ? clt->who_name : "name not found", cl );
		    if ( clt->who_name )
			STRFREE( clt->who_name );
		    DISPOSE( clt );
		    return FALSE;
		}
                class_table[cl] = clt;
                boot_log( "Loaded class '%s'", clt->who_name );
                return TRUE;
	    }
	    KEY( "ExpBase",	clt->exp_base,	fread_number( fp )	);
	    KEY( "ExpPower",	clt->exp_power,	fread_number( fp )	);
	    break;

	case 'G':
	    KEY( "Guild",	clt->guild,		fread_number( fp )	);
	    break;

	case 'H':
	    KEY( "HpMax",	clt->hp_max,		fread_number( fp )	);
	    KEY( "HpMin",	clt->hp_min,		fread_number( fp )	);
	    KEY( "HpCLev",	clt->hp_const_lev,	fread_number( fp ) );
	    KEY( "HpCAdd",	clt->hp_const_add,	fread_number( fp ) );
	    break;

	case 'M':
	    KEY( "Mana",	clt->fMana,		fread_number( fp )	);
	    break;

	case 'N':
	    KEY( "Name",	clt->who_name,	fread_string( fp )	);
	    break;

	case 'S':
	    if ( !str_cmp( word, "Skill" ) )
	    {
                char *ln;
		int sn, lev=0, adp=0, mana=-1, beats=-1;

		word = fread_word( fp );

		ln = fread_line( fp );

		sscanf( ln, "%d %d %d %d", &lev, &adp, &mana, &beats );

		if ( lev == 0 && adp == 0 )
		{
		    lev = LEVEL_IMMORTAL;
		    adp = 95;
		}
		sn = skill_lookup( word );
		if ( cl < 0 || cl >= MAX_CLASS )
		{
		    boot_log( "load_class_file: Skill %s -- class bad/not found (%d)", word, cl );
                }
		else
		if ( !IS_VALID_SN(sn) )
		{
                    boot_log( "load_class_file: Skill %s unknown", word );
		}
		else
		{
		    skill_table[sn]->skill_level[cl] = lev;
		    skill_table[sn]->skill_adept[cl] = adp;
		    if ( mana != -1 )
			skill_table[sn]->class_mana[cl] = mana;
		    if ( beats != -1 )
			skill_table[sn]->class_beats[cl] = beats;
		}
		fMatch = TRUE;
		break;
	    }
	    KEY( "Skilladept",	clt->skill_adept,	fread_number( fp )	);
	    break;

	case 'T':
	    if ( !str_cmp( word, "Title" ) )
	    {
		if ( cl < 0 || cl >= MAX_CLASS )
		{
		    char *tmp;

                    boot_log( "load_class_file: Title -- clt bad/not found (%d)", cl );
		    tmp = fread_string_nohash( fp );
		    DISPOSE( tmp );
		    tmp = fread_string_nohash( fp );
		    DISPOSE( tmp );
		}
		else
		if ( tlev < MAX_LEVEL+1 )
		{
		    title_table[cl][tlev][0] = fread_string_nohash( fp );
		    title_table[cl][tlev][1] = fread_string_nohash( fp );
		    ++tlev;
		}
		else
		{
		    char *tmp;

		    boot_log( "load_class_file: Too many titles" );
		    tmp = fread_string_nohash( fp );
		    DISPOSE( tmp );
		    tmp = fread_string_nohash( fp );
		    DISPOSE( tmp );
		}
		fMatch = TRUE;
		break;
	    }
	    KEY( "Thac0",	clt->thac0_00,	fread_number( fp )	);
	    KEY( "Thac32",	clt->thac0_32,	fread_number( fp )	);
	    break;

	case 'W':
	    KEY( "Weapon",	clt->weapon,	fread_number( fp )	);
	    break;
	}
	if ( !fMatch )
	{
            boot_log( "load_class_file: no match: %s", word );
            fread_to_eol(fp);
	}
    }
    for (i=tlev;i<MAX_LEVEL;i++) {
      title_table[cl][i][0] = str_dup("UNKNOWN");
      title_table[cl][i][1] = str_dup("UNKNOWN");
    }
    return FALSE;
}

/*
 * Load in all the class files.
 */
void load_classes( )
{
    FILE *fpList;
    const char *filename;
    char classlist[256];

    sprintf( classlist, "%s%s", CLASS_DIR, CLASS_LIST );
    if ( ( fpList = fopen( classlist, "r" ) ) == NULL )
    {
        perror( classlist );
        exit( 1 );
    }

    for ( ; ; )
    {
        filename = feof( fpList ) ? "$" : fread_word( fpList );
        if ( filename[0] == '$' )
            break;

        if ( !load_class_file( filename ) )
        {
            boot_log( "Cannot load class file: %s", filename );
        }
    }

    FCLOSE( fpList );
    return;
}

void write_class_file( sh_int cl )
{
    FILE *fpout;
    char buf[MAX_STRING_LENGTH];
    char filename[MAX_INPUT_LENGTH];
    struct class_type *clt = class_table[cl];
    int x, y;

    sprintf( filename, "%s%s.class", CLASS_DIR, clt->who_name );
    if ( (fpout=fopen(filename, "w")) == NULL )
    {
	sprintf( buf, "Cannot open: %s for writing", filename );
	bug( buf, 0 );
	return;
    }
    fprintf( fpout, "Name        %s~\n",	clt->who_name		);
    fprintf( fpout, "Class       %d\n",		cl			);
    fprintf( fpout, "AttrPrime   %d\n",		clt->attr_prime	        );
    if (clt->attr_string)
	fprintf( fpout, "AttrString  %s~\n",       	clt->attr_string	);
    fprintf( fpout, "Weapon      %d\n",		clt->weapon		);
    fprintf( fpout, "Guild       %d\n",		clt->guild		);
    fprintf( fpout, "Skilladept  %d\n",		clt->skill_adept	);
    fprintf( fpout, "Thac0       %d\n",		clt->thac0_00		);
    fprintf( fpout, "Thac32      %d\n",		clt->thac0_32		);
    fprintf( fpout, "Hpmin       %d\n",		clt->hp_min		);
    fprintf( fpout, "Hpmax       %d\n",		clt->hp_max		);
    fprintf( fpout, "HpCLev      %d\n",		clt->hp_const_lev	);
    fprintf( fpout, "HpCAdd      %d\n",		clt->hp_const_add	);
    fprintf( fpout, "Mana        %d\n",		clt->fMana		);
    fprintf( fpout, "ExpBase     %ld\n",	clt->exp_base		);
    fprintf( fpout, "ExpPower    %ld\n",	clt->exp_power	);
    for ( x = 0; x < top_sn; x++ )
    {
        if ( !skill_table[x]->name || skill_table[x]->name[0] == '\0' )
            break;
        y = skill_table[x]->skill_level[cl];
        if ( y < LEVEL_IMMORTAL && y > 0 )
            fprintf( fpout, "Skill '%s' %d %d %d %d\n",
                     skill_table[x]->name,
                     skill_table[x]->skill_level[cl],
		     skill_table[x]->skill_adept[cl],
		     skill_table[x]->class_mana[cl],
		     skill_table[x]->class_beats[cl]);
    }
    for ( x = 0; x <= MAX_LEVEL; x++ )
        fprintf( fpout, "Title\n%s~\n%s~\n",
                 title_table[cl][x][0], title_table[cl][x][1] );
    fprintf( fpout, "End\n" );
    FCLOSE( fpout );
}

/*
 * 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 strcmp( skill1->name, skill2->name );
}

int skill_comp_sn( 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 ( skill1->slot>skill2->slot );
}

/*
 * Sort the skill table with qsort
 */
void sort_skill_table()
{
    log_string_plus( "Sorting skill table...", LOG_NORMAL, LEVEL_LOG_CSET, SEV_INFO );
    qsort( &skill_table[1], top_sn-1, sizeof( SKILLTYPE * ),
		(int(*)(const void *, const void *)) skill_comp );
}
void sort_skill_table_sn()
{
    log_string_plus( "Sorting skill table by sn...", LOG_NORMAL, LEVEL_LOG_CSET, SEV_INFO );
    qsort( &skill_table[1], top_sn-1, sizeof( SKILLTYPE * ),
		(int(*)(const void *, const void *)) skill_comp_sn );
}

/*
 * Write skill data to a file
 */
#if defined(USE_DB) || defined(START_DB)
void save_skill_table()
{
    db_insert_skills();
}

void save_herb_table()
{
    db_insert_herbs();
}

void save_commands()
{
    db_insert_commands();
}

void save_socials()
{
    db_insert_socials();
}

#else
void fwrite_skill( FILE *fpout, SKILLTYPE *skill )
{
    SMAUG_AFF *aff;

    fprintf( fpout, "Name         %s~\n",	skill->name	);
    fprintf( fpout, "Type         %s\n",	skill_tname[skill->type] );
    fprintf( fpout, "Flags        %d\n",	skill->flags	);

    /*
    skill->dam_type = SPELL_DAMAGE(skill);
    skill->act_type = SPELL_ACTION(skill);
    skill->power_type = SPELL_POWER(skill);
    skill->class_type = SPELL_CLASS(skill);
    REMOVE_BIT(skill->flags, BV00);
    REMOVE_BIT(skill->flags, BV01);
    REMOVE_BIT(skill->flags, BV02);
    REMOVE_BIT(skill->flags, BV03);
    REMOVE_BIT(skill->flags, BV04);
    REMOVE_BIT(skill->flags, BV05);
    REMOVE_BIT(skill->flags, BV06);
    REMOVE_BIT(skill->flags, BV07);
    REMOVE_BIT(skill->flags, BV08);
    REMOVE_BIT(skill->flags, BV09);
    REMOVE_BIT(skill->flags, BV10);
    */

    if ( SPELL_DAMAGE(skill) )
        fprintf( fpout, "DamType      %d\n",	skill->dam_type );
    if ( SPELL_ACTION(skill) )
        fprintf( fpout, "ActType      %d\n",	skill->act_type );
    if ( SPELL_POWER(skill) )
        fprintf( fpout, "PowerType    %d\n",	skill->power_type );
    if ( SPELL_CLASS(skill) )
        fprintf( fpout, "ClassType    %d\n",	skill->class_type );
    if ( SPELL_SAVE(skill) )
        fprintf( fpout, "SaveType     %d\n",	skill->save_type);

    if ( skill->target )
        fprintf( fpout, "Target       %d\n",	skill->target	);
    if ( skill->minimum_position )
        fprintf( fpout, "Minpos       %d\n",	skill->minimum_position );
    if ( skill->slot )
        fprintf( fpout, "Slot         %d\n",	skill->slot	);
    if ( skill->min_mana )
        fprintf( fpout, "Mana         %d\n",	skill->min_mana );
    if ( skill->beats )
	fprintf( fpout, "Rounds       %d\n",	skill->beats	);
    if ( skill->guild != -1 )
        fprintf( fpout, "Guild        %d\n",	skill->guild	);
    if ( skill->skill_fun )
        fprintf( fpout, "Code         %s\n",	skill_name(skill->skill_fun) );
    else
        if ( skill->spell_fun )
            fprintf( fpout, "Code         %s\n",	spell_name(skill->spell_fun) );
    fprintf( fpout, "Dammsg       %s~\n",	skill->noun_damage );
    if ( skill->msg_off && skill->msg_off[0] != '\0' )
        fprintf( fpout, "Wearoff      %s~\n",	skill->msg_off	);
    if ( skill->msg_off_room && skill->msg_off_room[0] != '\0' )
        fprintf( fpout, "Wearoffroom  %s~\n",	skill->msg_off_room );
    if ( skill->msg_off_soon && skill->msg_off_soon[0] != '\0' )
        fprintf( fpout, "Wearoffsoon  %s~\n",	skill->msg_off_soon );
    if ( skill->msg_off_soon_room && skill->msg_off_soon_room[0] != '\0' )
        fprintf( fpout, "WearoffsoonR %s~\n",	skill->msg_off_soon_room );

    if ( skill->hit_char && skill->hit_char[0] != '\0' )
        fprintf( fpout, "Hitchar      %s~\n",	skill->hit_char );
    if ( skill->hit_vict && skill->hit_vict[0] != '\0' )
        fprintf( fpout, "Hitvict      %s~\n",	skill->hit_vict );
    if ( skill->hit_room && skill->hit_room[0] != '\0' )
        fprintf( fpout, "Hitroom      %s~\n",	skill->hit_room );

    if ( skill->miss_char && skill->miss_char[0] != '\0' )
        fprintf( fpout, "Misschar     %s~\n",	skill->miss_char );
    if ( skill->miss_vict && skill->miss_vict[0] != '\0' )
        fprintf( fpout, "Missvict     %s~\n",	skill->miss_vict );
    if ( skill->miss_room && skill->miss_room[0] != '\0' )
        fprintf( fpout, "Missroom     %s~\n",	skill->miss_room );

    if ( skill->die_char && skill->die_char[0] != '\0' )
        fprintf( fpout, "Diechar      %s~\n",	skill->die_char );
    if ( skill->die_vict && skill->die_vict[0] != '\0' )
        fprintf( fpout, "Dievict      %s~\n",	skill->die_vict );
    if ( skill->die_room && skill->die_room[0] != '\0' )
        fprintf( fpout, "Dieroom      %s~\n",	skill->die_room );

    if ( skill->imm_char && skill->imm_char[0] != '\0' )
        fprintf( fpout, "Immchar      %s~\n",	skill->imm_char );
    if ( skill->imm_vict && skill->imm_vict[0] != '\0' )
        fprintf( fpout, "Immvict      %s~\n",	skill->imm_vict );
    if ( skill->imm_room && skill->imm_room[0] != '\0' )
        fprintf( fpout, "Immroom      %s~\n",	skill->imm_room );

    if ( skill->abs_char && skill->abs_char[0] != '\0' )
        fprintf( fpout, "Abschar      %s~\n",	skill->abs_char );
    if ( skill->abs_vict && skill->abs_vict[0] != '\0' )
        fprintf( fpout, "Absvict      %s~\n",	skill->abs_vict );
    if ( skill->abs_room && skill->abs_room[0] != '\0' )
        fprintf( fpout, "Absroom      %s~\n",	skill->abs_room );

    if ( skill->corpse_string && skill->corpse_string[0] != '\0' )
    {
        fprintf( fpout, "CorpseStr    %s~\n",	skill->corpse_string );
        fprintf( fpout, "CorpseStg    %d\n",	skill->corpse_stage );
    }
    if ( skill->dice && skill->dice[0] != '\0' )
        fprintf( fpout, "Dice         %s~\n",	skill->dice );
    if ( skill->value )
        fprintf( fpout, "Value        %d\n",	skill->value );
    if ( skill->difficulty )
        fprintf( fpout, "Difficulty   %d\n",	skill->difficulty );
    if ( skill->participants )
        fprintf( fpout, "Participants %d\n",	skill->participants );

    if ( skill->part_start_char && skill->part_start_char[0] != '\0')
        fprintf( fpout, "PartStartCh  %s~\n",	skill->part_start_char );
    if ( skill->part_start_room && skill->part_start_room[0] != '\0')
        fprintf( fpout, "PartStartRm  %s~\n",	skill->part_start_room );

    if ( skill->part_end_char && skill->part_end_char[0] != '\0')
        fprintf( fpout, "PartEndCh    %s~\n",	skill->part_end_char );
    if ( skill->part_end_vict && skill->part_end_vict[0] != '\0')
        fprintf( fpout, "PartEndVict  %s~\n",	skill->part_end_vict );
    if ( skill->part_end_room && skill->part_end_room[0] != '\0')
        fprintf( fpout, "PartEndRm    %s~\n",	skill->part_end_room );
    if ( skill->part_end_caster && skill->part_end_caster[0] != '\0')
        fprintf( fpout, "PartEndCast  %s~\n",	skill->part_end_caster );

    if ( skill->part_miss_char && skill->part_miss_char[0] != '\0')
        fprintf( fpout, "PartMissCh   %s~\n",	skill->part_miss_char );
    if ( skill->part_miss_room && skill->part_miss_room[0] != '\0')
        fprintf( fpout, "PartMissRm   %s~\n",	skill->part_miss_room );

    if ( skill->part_abort_char && skill->part_abort_char[0] != '\0')
        fprintf( fpout, "PartAbortCh  %s~\n",	skill->part_abort_char );

    if ( skill->components && skill->components[0] != '\0' )
        fprintf( fpout, "Components   %s~\n",	skill->components );
    if ( skill->teachers && skill->teachers[0] != '\0' )
        fprintf( fpout, "Teachers     %s~\n",	skill->teachers );
    for ( aff = skill->affects; aff; aff = aff->next )
    {
        if (aff->location == APPLY_IMMUNESPELL && IS_VALID_SN(atoi(aff->modifier)))
            fprintf( fpout, "Affect       '%s' %d '%d' %d\n",
                     aff->duration, aff->location, skill_table[atoi(aff->modifier)]->slot, aff->bitvector );
        else
            fprintf( fpout, "Affect       '%s' %d '%s' %d\n",
                     aff->duration, aff->location, aff->modifier, aff->bitvector );
    }

    if ( skill->type != SKILL_HERB )
    {
        int y;
        int min = 1000;

        for ( y = 0; y < MAX_CLASS; y++ )
            if ( skill->skill_level[y] < min )
                min = skill->skill_level[y];

        fprintf( fpout, "Minlevel     %d\n",	min		);
    }
    fprintf( fpout, "End\n\n" );
}

/*
 * Save the skill table to disk
 */
void save_skill_table()
{
    int x;
    FILE *fpout;

    if ( (fpout=fopen( SKILL_FILE, "w" )) == NULL )
    {
	bug( "Cannot open skills.dat for writting" );
	perror( SKILL_FILE );
	return;
    }

    for ( x = 0; x < top_sn; x++ )
    {
	if ( !skill_table[x]->name || skill_table[x]->name[0] == '\0' )
	   break;
	fprintf( fpout, "#SKILL\n" );
	fwrite_skill( fpout, skill_table[x] );
    }
    fprintf( fpout, "#END\n" );
    FCLOSE( fpout );
}

/*
 * Save the herb table to disk
 */
void save_herb_table()
{
    int x;
    FILE *fpout;

    if ( (fpout=fopen( HERB_FILE, "w" )) == NULL )
    {
	bug( "Cannot open herbs.dat for writting" );
	perror( HERB_FILE );
	return;
    }

    for ( x = 0; x < top_herb; x++ )
    {
	if ( !herb_table[x]->name || herb_table[x]->name[0] == '\0' )
	   break;
	fprintf( fpout, "#HERB\n" );
	fwrite_skill( fpout, herb_table[x] );
    }
    fprintf( fpout, "#END\n" );
    FCLOSE( fpout );
}

/*
 * Save the socials to disk
 */
void save_socials()
{
    FILE *fpout;
    SOCIALTYPE *social;
    int x;

    if ( (fpout=fopen( SOCIAL_FILE, "w" )) == NULL )
    {
	bug( "Cannot open socials.dat for writting" );
	perror( SOCIAL_FILE );
	return;
    }

    for ( x = 0; x < 27; x++ )
    {
	for ( social = social_index[x]; social; social = social->next )
	{
	    if ( !social->name || social->name[0] == '\0' )
	    {
		bug( "Save_socials: blank social in hash bucket %d", x );
		continue;
	    }
	    fprintf( fpout, "#SOCIAL\n" );
            fprintf( fpout, "Name        %s~\n",	social->name );
            if ( social->position != POS_RESTING )
                fprintf( fpout, "Position    %d\n",     social->position );
            if ( social->mob_response )
                fprintf( fpout, "MobResponse %s~\n",    social->mob_response );
	    if ( social->char_no_arg )
		fprintf( fpout, "CharNoArg   %s~\n",	social->char_no_arg );
	    else
	        bug( "Save_socials: NULL char_no_arg in hash bucket %d", x );
	    if ( social->others_no_arg )
		fprintf( fpout, "OthersNoArg %s~\n",	social->others_no_arg );
	    if ( social->char_found )
		fprintf( fpout, "CharFound   %s~\n",	social->char_found );
	    if ( social->others_found )
		fprintf( fpout, "OthersFound %s~\n",	social->others_found );
	    if ( social->vict_found )
		fprintf( fpout, "VictFound   %s~\n",	social->vict_found );
	    if ( social->char_auto )
		fprintf( fpout, "CharAuto    %s~\n",	social->char_auto );
	    if ( social->others_auto )
		fprintf( fpout, "OthersAuto  %s~\n",	social->others_auto );
	    if ( social->not_found )
		fprintf( fpout, "NotFound    %s~\n",	social->not_found );
	    fprintf( fpout, "End\n\n" );
	}
    }
    fprintf( fpout, "#END\n" );
    FCLOSE( fpout );
}

/*
 * Save the commands to disk
 */
void save_commands()
{
    FILE *fpout;
    CMDTYPE *command;
    int x;

    if ( (fpout=fopen( COMMAND_FILE, "w" )) == NULL )
    {
	bug( "Cannot open commands.dat for writing" );
	perror( COMMAND_FILE );
	return;
    }

    for ( x = 0; x < 126; x++ )
    {
	for ( command = command_hash[x]; command; command = command->next )
	{
	    if ( !command->name || command->name[0] == '\0' )
	    {
		bug( "Save_commands: blank command in hash bucket %d", x );
		continue;
	    }
	    fprintf( fpout, "#COMMAND\n" );
	    fprintf( fpout, "Name        %s~\n", command->name		);
	    fprintf( fpout, "Code        %s\n",	 skill_name(command->do_fun) );
            if (command->position!=0)
                fprintf( fpout, "Position    %d\n",	 command->position	);
            if (command->level!=0)
                fprintf( fpout, "Level       %d\n",	 command->level		);
            if (command->log!=0)
                fprintf( fpout, "Log         %d\n",	 command->log		);
            if (command->flags!=0)
                fprintf( fpout, "Flags       %d\n",	 command->flags  	);
	    fprintf( fpout, "End\n\n" );
	}
    }
    fprintf( fpout, "#END\n" );
    FCLOSE( fpout );
}
#endif

#ifdef USE_DB

void load_skill_table()
{
    db_load_skill_table();
}

void load_herb_table()
{
    db_load_herb_table();
}

void load_commands()
{
    db_load_commands();
}

void load_socials()
{
    db_load_socials();
}

#else
SKILLTYPE *fread_skill( FILE *fp )
{
    char buf[MAX_STRING_LENGTH];
    const char *word = NULL;
    bool fMatch = FALSE;
    SKILLTYPE *skill;
    int x;

    CREATE( skill, SKILLTYPE, 1 );
    for ( x = 0; x < MAX_CLASS; x++ )
    {
	skill->skill_level[x] = LEVEL_IMMORTAL;
	skill->skill_adept[x] = 95;
	skill->class_mana[x] = -1;
        skill->class_beats[x] = -1;
    }
    skill->guild = -1;

    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_nohash( fp ) );
            KEY( "Absroom",	skill->abs_room,	fread_string_nohash( fp ) );
	    KEY( "Absvict",	skill->abs_vict,	fread_string_nohash( fp ) );
	    KEY( "ActType",	skill->act_type,   	fread_number( fp ) );
	    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 );
                if (aff->location == APPLY_IMMUNESPELL)
                {
                    sprintf(buf, "%d", slot_lookup( atoi( fread_word( fp ) ) ));
                    aff->modifier = str_dup( buf );
                }
                else
                    aff->modifier = str_dup( fread_word( fp ) );
		aff->bitvector = fread_number( fp );
		aff->next = skill->affects;
		skill->affects = aff;
		fMatch = TRUE;
		break;
	    }
	    break;

	case 'C':
	    if ( !str_cmp( word, "Class" ) )
	    {
/*
		class_index clt = fread_number( fp );

		skill->skill_level[clt] = fread_number( fp );
		skill->skill_adept[clt] = fread_number( fp );
		fMatch = TRUE;
		break;
*/
		bug("Throwback... skills.dat has Class entry...");
	    }
            KEY( "ClassType",	skill->class_type,   	fread_number( fp ) );
	    if ( !str_cmp( word, "Code" ) )
	    {
		SPELL_FUN *spellfun;
		DO_FUN	  *dofun;
		char	  *w = fread_word(fp);

		fMatch = TRUE;
		if ( (spellfun=spell_function(w)) != spell_notfound )
		   skill->spell_fun = spellfun;
		else
		if ( (dofun=skill_function(w)) != skill_notfound )
		   skill->skill_fun = dofun;
		else
		{
		   sprintf( buf, "fread_skill: unknown skill/spell %s", w );
		   bug( buf, 0 );
		   skill->spell_fun = spell_null;
		}
		break;
	    }
	    KEY( "Code",	skill->spell_fun, spell_function(fread_word(fp)) );
	    KEY( "Components",	skill->components,	fread_string_nohash( fp ) );
	    KEY( "CorpseStr",	skill->corpse_string,	fread_string_nohash( fp ) );
	    KEY( "CorpseStg",	skill->corpse_stage,	fread_number( fp ) );
	    break;

	case 'D':
	    KEY( "DamType",	skill->dam_type,   	fread_number( fp ) );
            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" ) )
	    {
		for ( x = 0; x < MAX_CLASS; x++ )
		{
                    if (skill->class_mana[x] == -1)
			skill->class_mana[x] = skill->min_mana;
		    if (skill->class_beats[x] == -1)
			skill->class_beats[x] = skill->beats;
		}
		return skill;
	    }
	    break;

	case 'F':
	    KEY( "Flags",	skill->flags,		fread_number( fp ) );
	    break;

	case 'G':
	    KEY( "Guild",	skill->guild,		fread_number( fp ) );
	    break;

	case 'H':
	    KEY( "Hitchar",	skill->hit_char,	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 ) );
	    break;

	case 'M':
	    KEY( "Mana",	skill->min_mana,	fread_number( fp ) );
	    if ( !str_cmp( word, "Minlevel" ) )
	    {
		fread_to_eol( fp );
		fMatch = TRUE;
		break;
	    }
	    KEY( "Minpos",	skill->minimum_position, fread_number( fp ) );
	    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 ) );
	    KEY( "PartStartCh",	skill->part_start_char, fread_string_nohash( fp ) );
	    KEY( "PartStartRm",	skill->part_start_room, fread_string_nohash( fp ) );
	    KEY( "PartEndChar",	skill->part_end_char,   fread_string_nohash( fp ) );
	    KEY( "PartEndVict",	skill->part_end_vict,   fread_string_nohash( fp ) );
	    KEY( "PartEndRm",	skill->part_end_room,   fread_string_nohash( fp ) );
	    KEY( "PartEndCast",	skill->part_end_caster, fread_string_nohash( fp ) );
	    KEY( "PartMissCh",	skill->part_miss_char,  fread_string_nohash( fp ) );
	    KEY( "PartMissRm",	skill->part_miss_room,  fread_string_nohash( fp ) );
            KEY( "PartAbortCh",	skill->part_abort_char, fread_string_nohash( fp ) );
	    KEY( "PowerType",	skill->power_type,   	fread_number( fp ) );
	    break;

	case 'R':
	    KEY( "Rounds",	skill->beats,		fread_number( fp ) );
	    break;

	case 'S':
	    KEY( "Slot",	skill->slot,		fread_number( fp ) );
	    KEY( "Saves",	skill->save_type,   	fread_number( fp ) );
	    KEY( "SaveType",	skill->save_type,   	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_tname(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 ) );
	    KEY( "Wearoffroom",	skill->msg_off_room,	fread_string_nohash( fp ) );
	    KEY( "Wearoffsoon",	skill->msg_off_soon,	fread_string_nohash( fp ) );
	    KEY( "WearoffsoonR",skill->msg_off_soon_room, fread_string_nohash( fp ) );
	    break;
	}

	if ( !fMatch )
	{
            sprintf( buf, "Fread_skill: no match: %s", word );
            fread_to_eol(fp);
	    bug( buf, 0 );
	}
    }
}

void load_skill_table()
{
    FILE *fp;

    if ( ( fp = fopen( SKILL_FILE, "r" ) ) != NULL )
    {
	top_sn = 0;
	for ( ;; )
	{
	    char letter;
	    char *word;

	    letter = fread_letter( fp );
	    if ( letter == '*' )
	    {
		fread_to_eol( fp );
		continue;
	    }

	    if ( letter != '#' )
	    {
                bug( "Load_skill_table: # not found." );
		break;
	    }

	    word = fread_word( fp );
            if ( !str_cmp( word, "SKILL"      ) )
	    {
		if ( top_sn >= MAX_SKILL )
		{
		    bug( "load_skill_table: more skills than MAX_SKILL %d", MAX_SKILL );
		    FCLOSE( fp );
		    return;
		}
		skill_table[top_sn++] = fread_skill( fp );
		continue;
	    }
	    else
	    if ( !str_cmp( word, "END"	) )
	        break;
	    else
	    {
                bug( "Load_skill_table: bad section." );
		continue;
	    }
	}
	FCLOSE( fp );
    }
    else
    {
	bug( "Cannot open skills.dat" );
 	exit(0);
    }
}

void load_herb_table()
{
    FILE *fp;

    if ( ( fp = fopen( HERB_FILE, "r" ) ) != NULL )
    {
	top_herb = 0;
	for ( ;; )
	{
	    char letter;
	    char *word;

	    letter = fread_letter( fp );
	    if ( letter == '*' )
	    {
		fread_to_eol( fp );
		continue;
	    }

	    if ( letter != '#' )
	    {
		bug( "Load_herb_table: # not found." );
		break;
	    }

	    word = fread_word( fp );
            if ( !str_cmp( word, "HERB"      ) )
	    {
		if ( top_herb >= MAX_HERB )
		{
		    bug( "load_herb_table: more herbs than MAX_HERB %d", MAX_HERB );
		    FCLOSE( fp );
		    return;
		}
		herb_table[top_herb++] = fread_skill( fp );
		if ( herb_table[top_herb-1]->slot == 0 )
		    herb_table[top_herb-1]->slot = top_herb-1;
		continue;
	    }
	    else
	    if ( !str_cmp( word, "END"	) )
	        break;
	    else
	    {
                bug( "Load_herb_table: bad section." );
		continue;
	    }
	}
	FCLOSE( fp );
    }
    else
    {
	bug( "Cannot open herbs.dat" );
 	exit(0);
    }
}

void fread_social( FILE *fp )
{
    char buf[MAX_STRING_LENGTH];
    const char *word = NULL;
    bool fMatch = FALSE;
    SOCIALTYPE *social;

    CREATE( social, SOCIALTYPE, 1 );

    social->position = POS_RESTING;

    for ( ;; )
    {
	word   = feof( fp ) ? "End" : fread_word( fp );
	fMatch = FALSE;

	switch ( UPPER(word[0]) )
	{
	case '*':
	    fMatch = TRUE;
	    fread_to_eol( fp );
	    break;

	case 'C':
	    KEY( "CharNoArg",	social->char_no_arg,	fread_string_nohash(fp) );
	    KEY( "CharFound",	social->char_found,	fread_string_nohash(fp) );
	    KEY( "CharAuto",	social->char_auto,	fread_string_nohash(fp) );
	    break;

	case 'E':
	    if ( !str_cmp( word, "End" ) )
	    {
		if ( !social->name )
		{
		    bug( "Fread_social: Name not found" );
		    free_social( social );
		    return;
		}
		if ( !social->char_no_arg )
		{
		    bug( "Fread_social: CharNoArg not found" );
		    free_social( social );
		    return;
		}
		add_social( social );
		return;
	    }
	    break;

        case 'M':
            KEY( "MobResponse", social->mob_response,   fread_string_nohash(fp) );
            break;

	case 'N':
	    KEY( "Name",	social->name,		fread_string_nohash(fp) );
	    KEY( "NotFound",	social->not_found,	fread_string_nohash(fp) );
	    break;

	case 'O':
	    KEY( "OthersNoArg",	social->others_no_arg,	fread_string_nohash(fp) );
	    KEY( "OthersFound",	social->others_found,	fread_string_nohash(fp) );
	    KEY( "OthersAuto",	social->others_auto,	fread_string_nohash(fp) );
	    break;

	case 'P':
            KEY( "Position",	social->position,	fread_number(fp) );
            break;

	case 'V':
	    KEY( "VictFound",	social->vict_found,	fread_string_nohash(fp) );
	    break;
	}

	if ( !fMatch )
	{
            sprintf( buf, "Fread_social: no match: %s", word );
            fread_to_eol(fp);
	    bug( buf, 0 );
	}
    }
}

void load_socials()
{
    FILE *fp;

    if ( ( fp = fopen( SOCIAL_FILE, "r" ) ) != NULL )
    {
	top_sn = 0;
	for ( ;; )
	{
	    char letter;
	    char *word;

	    letter = fread_letter( fp );
	    if ( letter == '*' )
	    {
		fread_to_eol( fp );
		continue;
	    }

	    if ( letter != '#' )
	    {
                bug( "Load_socials: # not found." );
		break;
	    }

	    word = fread_word( fp );
            if ( !str_cmp( word, "SOCIAL"      ) )
	    {
                fread_social( fp );
	    	continue;
	    }
	    else
	    if ( !str_cmp( word, "END"	) )
	        break;
	    else
	    {
                bug( "Load_socials: bad section." );
		continue;
	    }
	}
	FCLOSE( fp );
    }
    else
    {
	bug( "Cannot open %s", SOCIAL_FILE );
 	exit(0);
    }
}


void fread_command( FILE *fp )
{
    char buf[MAX_STRING_LENGTH];
    const char *word = NULL;
    bool fMatch = FALSE;
    CMDTYPE *command;

    CREATE( command, CMDTYPE, 1 );

    command->position = 0;
    command->level    = 0;
    command->log      = 0;
    command->flags    = 0;

    for ( ;; )
    {
	word   = feof( fp ) ? "End" : fread_word( fp );
	fMatch = FALSE;

	switch ( UPPER(word[0]) )
	{
	case '*':
	    fMatch = TRUE;
	    fread_to_eol( fp );
	    break;

	case 'C':
	    KEY( "Code",	command->do_fun,	skill_function(fread_word(fp)) );
	    break;

	case 'E':
	    if ( !str_cmp( word, "End" ) )
	    {
		if ( !command->name )
		{
		    bug( "Fread_command: Name not found" );
		    free_command( command );
		    return;
		}
		if ( !command->do_fun )
		{
		    bug( "Fread_command: Function not found" );
		    free_command( command );
		    return;
		}
		if ( command->do_fun == skill_notfound )
		{
		    command->level = MAX_LEVEL;
		}
		add_command( command );
		return;
	    }
	    break;

	case 'F':
            KEY( "Flags",	command->flags,		fread_number(fp) );
            break;

	case 'L':
	    KEY( "Level",	command->level,		fread_number(fp) );
	    KEY( "Log",		command->log,		fread_number(fp) );
	    break;

	case 'N':
	    KEY( "Name",	command->name,		fread_string_nohash(fp) );
	    break;

	case 'P':
	    KEY( "Position",	command->position,	fread_number(fp) );
	    break;
	}

	if ( !fMatch )
	{
            sprintf( buf, "Fread_command: no match: %s", word );
            fread_to_eol(fp);
	    bug( buf, 0 );
	}
    }
}

void load_commands()
{
    FILE *fp;

    if ( ( fp = fopen( COMMAND_FILE, "r" ) ) != NULL )
    {
	top_sn = 0;
	for ( ;; )
	{
	    char letter;
	    char *word;

	    letter = fread_letter( fp );
	    if ( letter == '*' )
	    {
		fread_to_eol( fp );
		continue;
	    }

	    if ( letter != '#' )
	    {
                bug( "Load_commands: # not found." );
		break;
	    }

	    word = fread_word( fp );
            if ( !str_cmp( word, "COMMAND"      ) )
	    {
                fread_command( fp );
	    	continue;
	    }
	    else
	    if ( !str_cmp( word, "END"	) )
	        break;
	    else
	    {
                bug( "Load_commands: bad section." );
		continue;
	    }
	}
	FCLOSE( fp );
    }
    else
    {
	bug( "Cannot open commands.dat" );
 	exit(0);
    }

}
#endif

void save_classes()
{
    sh_int x;

    for ( x = FIRST_CLASS; x < MAX_CLASS; x++ )
      write_class_file( x );
}

/*
 * 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 = str_dup(fread_word(fp));
	cnv->olen = strlen(cnv->old);
	cnv->newstr = str_dup(fread_word(fp));
	cnv->nlen = strlen(cnv->newstr);
	fread_to_eol(fp);
	LINK(cnv, *first_cnv, *last_cnv, next, prev);
    }
}

void load_tongues()
{
    FILE *fp;
    LANG_DATA *lng;
    char *word;
    char letter;

    if (!(fp=fopen(TONGUE_FILE, "r")))
    {
	perror("Load_tongues");
	return;
    }
    for (;;)
    {
	letter = fread_letter(fp);
	if (letter == EOF)
	{
	    fclose(fp);
	    return;
	}
	else if (letter == '*')
	{
	    fread_to_eol(fp);
	    continue;
	}
	else if (letter != '#')
	{
	    bug("Letter '%c' not #.", letter);
	    exit(0);
	}
	word = fread_word(fp);
	if (!str_cmp(word, "end"))
	{
	    fclose(fp);
	    return;
	}
	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);
    return;
}

void fwrite_langs(void)
{
    FILE *fp;
    LANG_DATA *lng;
    LCNV_DATA *cnv;

    if (!(fp=fopen(TONGUE_FILE, "w")))
    {
	perror("fwrite_langs");
	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->newstr);
	fprintf(fp, "~\n%s~\n", lng->alphabet);
	for (cnv = lng->first_cnv; cnv; cnv = cnv->next)
	    fprintf(fp, "'%s' '%s'\n", cnv->old, cnv->newstr);
	fprintf(fp, "\n");
    }
    fprintf(fp, "#end\n\n");
    fclose(fp);
    return;
}

void free_langs(void)
{
    LANG_DATA *lng;
    LCNV_DATA *cnv;

    while ((lng = first_lang))
    {
	UNLINK(lng, first_lang, last_lang, next, prev);
	STRFREE(lng->name);
        STRFREE(lng->alphabet);
	while ((cnv = lng->first_precnv))
	{
	    UNLINK(cnv, lng->first_precnv, lng->last_precnv, next, prev);
	    if (cnv->old)
		DISPOSE(cnv->old);
	    if (cnv->newstr)
		DISPOSE(cnv->newstr);
            DISPOSE(cnv);
	}
	while ((cnv = lng->first_cnv))
	{
	    UNLINK(cnv, lng->first_cnv, lng->last_cnv, next, prev);
	    if (cnv->old)
		DISPOSE(cnv->old);
	    if (cnv->newstr)
		DISPOSE(cnv->newstr);
            DISPOSE(cnv);
	}
	DISPOSE(lng);
    }
}