bast/
bast/area/
bast/backup/
bast/clans/
bast/doc/MSP/
bast/doc/OLC11/
bast/doc/OLC11/doc/
bast/doc/OLC11/options/
bast/log/
bast/mobprogs/
bast/player/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, David   *
 *  Love, Guilherme 'Willie' Arnold, and Mitchell Tse.                     *
 *                                                                         *
 *  EnvyMud 2.0 improvements copyright (C) 1995 by Michael Quan and        *
 *  Mitchell Tse.                                                          *
 *                                                                         *
 *  EnvyMud 2.2 improvements copyright (C) 1996, 1997 by Michael Quan.     *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

#if defined( macintosh )
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"

#if !defined( macintosh )
extern  int     _filbuf	        args( (FILE *) );
#endif

#if !defined( ultrix ) && !defined( apollo )
#include <memory.h>
#endif



#if defined(KEY)
#undef KEY
#endif

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

#define SKEY( string, field )                       \
                if ( !str_cmp( word, string ) )     \
                {                                   \
                    free_string( field );           \
                  field = fread_string( fp, &stat); \
                    fMatch = TRUE;                  \
                    break;                          \
                }



/*
 * Globals.
 */

/* The social table.  New socials contributed by Katrina and Binky */
SOC_INDEX_DATA *	soc_index_hash	[ MAX_WORD_HASH ];

/* Class table.  See class files in the 'classes' directory */
struct  class_type *    class_table     [ MAX_CLASS ];


CLAN_DATA *             clan_first = NULL;
CLAN_DATA *             clan_last  = NULL;



/*
 * New code for loading classes from file.
 */
bool fread_class( char *filename )
{
    FILE               *fp;
    char               *word;
    struct  class_type *class;
    char                buf [ MAX_STRING_LENGTH ];
    bool                fMatch;
    int                 stat;
    int                 number = -1;

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

    class = alloc_mem ( sizeof( CLASS_TYPE ) );

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

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

	case 'A':
            KEY( "AtrPrm", class->attr_prime, fread_number( fp, &stat ) );
	    break;

	case 'C':
            KEY( "Cla", number, fread_number( fp, &stat ) );

	    if ( number < 0 || number >= MAX_CLASS )
	    {
		sprintf( buf, "Fread_class: bad class  '%s'.", filename );
		bug ( buf, 0 );
		return FALSE;
	    }
	    break;

	case 'E':
	    if ( !str_cmp( word, "End" ) )
	    {
		fclose( fp );
		class_table[number] = class;
		return TRUE;
	    }
	    break;

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

	case 'H':
            KEY( "Hpmin", class->hp_min, fread_number( fp, &stat ) );
            KEY( "Hpmax", class->hp_max, fread_number( fp, &stat ) );
	    break;

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

	case 'N':
            SKEY( "Nm", class->name );
	    break;

	case 'S':
            KEY( "SkllAdpt", class->skill_adept, fread_number( fp, &stat ) );

	    if ( !str_cmp( word, "Skll" ) )
	    {
		int sn;
		int value;
                char *word;

		value = fread_number( fp, &stat );
		sn    = skill_lookup( (word = fread_word( fp, &stat )) );
		if ( sn < 0 )
                {
		    bug( "Fread_class: unknown skill:", 0 );
                    log_string( word );
                }
		else
		    skills_table[sn].skill_level[number] = value;
		fMatch = TRUE;
	    }
	    else if ( !str_cmp( word, "Spll" ) )
	    {
		int sn;
		int value;
                char *word;

		value = fread_number( fp, &stat );
		sn    = spell_lookup( (word = fread_word( fp, &stat )) );
		if ( sn < 0 )
                {
		    bug( "Fread_class: unknown spell:", 0 );
                    log_string( word );
                }
		else
                {
                    if( value <= MAX_CIRCLE )
                    {
		      spells_table[sn].spell_circle[number] = value;
                    }
                    else
                    {
                      bug( "Spell in class file has level greater than MAX_CIRCLE", 0 );
                      spells_table[sn].spell_circle[number] = MAX_CIRCLE - 1;
                    }
                }
		fMatch = TRUE;
	    }

	    break;

	case 'T':
	    KEY( "Thac0", class->thac0_00, fread_number( fp, &stat ) );
	    KEY( "Thac47", class->thac0_47, fread_number( fp, &stat ) );
	    break;

	case 'W':
	    SKEY( "WhoNm", class->who_name );
	    KEY( "Wpn", class->weapon, fread_number( fp, &stat ) );
	    break;
	}

	if ( !fMatch )
	{
            bugf( "load_class_file: no match: %s", word );
	}
    }

    return FALSE;
}

/*
 * Load in all the class files.
 */ 
void load_classes( void )
{
    FILE *fpList;
    char *filename;
    char  fname     [ MAX_STRING_LENGTH ];
    char  classlist [ MAX_STRING_LENGTH ];
    int   stat;
    
    sprintf( classlist, "%s%s", CLASS_DIR, CLASS_LIST );
    if ( !( fpList = fopen( classlist, "r" ) ) )
    {
        perror( classlist );
        exit( 1 );
    }

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

        if ( !fread_class( fname ) )
        {
          bugf( "Cannot load class file: %s", fname );
        }
    }
    fclose( fpList );

    return;
}

void save_class( int num )
{
    FILE                    *fp;
    const struct class_type *class	= class_table[num];
    char                     buf  	[ MAX_STRING_LENGTH ];
    char                     filename	[ MAX_INPUT_LENGTH  ];
    int                      level;
    int                      sn;

    sprintf( filename, "%s.class", class->name );
    sprintf( buf, "%s%s", CLASS_DIR, filename );

    fclose( fpReserve );

    if ( !( fp = fopen( buf, "w" ) ) )
    {
        bugf( "Cannot open: %s for writing", filename );
    }
    else
    {
	fprintf( fp, "Nm          %s~\n",        class->name	    );
	fprintf( fp, "WhoNm       %s~\n",        class->who_name    );
	fprintf( fp, "Cla         %d\n",         num		    );
	fprintf( fp, "AtrPrm      %d\n",         class->attr_prime  );
	fprintf( fp, "Wpn         %d\n",         class->weapon	    );
	fprintf( fp, "Guild       %d\n",         class->guild	    );
	fprintf( fp, "Sklladpt    %d\n",         class->skill_adept );
	fprintf( fp, "Thac0       %d\n",         class->thac0_00    );
	fprintf( fp, "Thac47      %d\n",         class->thac0_47    );
	fprintf( fp, "Hpmin       %d\n",         class->hp_min	    );
	fprintf( fp, "Hpmax       %d\n",         class->hp_max	    );
	fprintf( fp, "Mana        %d\n",         class->fMana	    );

	for ( sn = 0; sn < MAX_SKILL; sn++ )
	{
	    if ( !skills_table[sn].name )
		break;

	    if ( ( level = skills_table[sn].skill_level[num] ) < LEVEL_IMMORTAL )
		fprintf( fp, "Skll        %2d '%s'\n",
					level, skills_table[sn].name );
	}

	for ( sn = 0; sn < MAX_SPELL; sn++ )
	{
	    if ( !spells_table[sn].name )
		break;

	    if ( ( level = spells_table[sn].spell_circle[num] ) < MAX_CIRCLE )
		fprintf( fp, "Spll        %2d '%s'\n",
					level, spells_table[sn].name );
	}

	fprintf( fp, "End\n" );

	fclose( fp );
    }

    fpReserve = fopen( NULL_FILE, "r" );
    return;
}

void save_classes( void )
{
    int class;

    for ( class = 0; class < MAX_CLASS; class++ )
      save_class( class );

    return;
}



/*
 * Add a social to the social index table                       - Thoric
 * Hashed and insert sorted.
 */
void add_social( SOC_INDEX_DATA *social )
{
    SOC_INDEX_DATA *tmp;
    SOC_INDEX_DATA *prev;
    int             hash;
    int             x;

    if ( !social )
    {
	bug( "Add_social: NULL social", 0 );
	return;
    }

    if ( !social->name )
    {
	bug( "Add_social: NULL social->name", 0 );
	return;
    }

    if ( !social->char_no_arg )
    {
	bug( "Add_social: NULL social->char_no_arg", 0 );
	return;
    }

    /* make sure the name is all lowercase */
    for ( x = 0; social->name[x] != '\0'; x++ )
	social->name[x] = LOWER( social->name[x] );

    if ( social->name[0] < 'a' || social->name[0] > 'z' )
	hash = 0;
    else
	hash = ( social->name[0] - 'a' ) + 1;

    if ( !( prev = tmp = soc_index_hash[hash] ) )
    {
	social->next = soc_index_hash[hash];
	soc_index_hash[hash] = social;
	return;
    }

    for ( ; tmp; tmp = tmp->next )
    {
	if ( !( x = strcmp( social->name, tmp->name ) ) )
	{
	    bug( "Add_social: trying to add duplicate name to bucket %d", hash);
	    free_social( social );
	    return;
	}
	else
	if ( x < 0 )
	{
	    if ( tmp == soc_index_hash[hash] )
	    {
		social->next = soc_index_hash[hash];
		soc_index_hash[hash] = social;
		return;
	    }
	    prev->next = social;
	    social->next = tmp;
	    return;
	}
	prev = tmp;
    }

    /* add to end */
    prev->next = social;
    social->next = NULL;
    return;
}

/*
 * Save the social_table_tables to disk. -Toric
 */
void save_socials( void )
{
    FILE           *fpout;
    SOC_INDEX_DATA *social;
    int             x;
    char            strsave [ MAX_INPUT_LENGTH ];

    fclose( fpReserve );

    sprintf( strsave, "%s%s", SYSTEM_DIR, SOCIAL_FILE );

    if ( !( fpout = fopen( strsave, "w" ) ) )
    {
	bug( "Cannot open SOCIALS.TXT for writting", 0 );
	perror( SOCIAL_FILE );
	return;
    }

    for ( x = 0; x < 27; x++ )
    {
	for ( social = soc_index_hash[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->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 );
	    fprintf( fpout, "End\n\n" );
	}
    }

    fprintf( fpout, "#END\n" );
    fclose( fpout );

    fpReserve = fopen( NULL_FILE, "r" );
    return;
}

/*
 * Clear a new social.
 */
void clear_social( SOC_INDEX_DATA *soc )
{
    static SOC_INDEX_DATA soc_zero;

    *soc			= soc_zero;
    soc->name			= NULL;
    soc->char_no_arg		= NULL;
    soc->others_no_arg		= NULL;
    soc->char_found		= NULL;
    soc->others_found		= NULL;
    soc->vict_found		= NULL;
    soc->char_auto		= NULL;
    soc->others_auto		= NULL;
    return;
}

/*
 * Take a social data from the free list and clean it out.
 */
SOC_INDEX_DATA *new_social( void )
{
    SOC_INDEX_DATA *soc;

    soc		= alloc_perm( sizeof( SOC_INDEX_DATA ) );

    clear_social( soc );

    return soc;
}

/*
 * Remove a social from it's hash index                         - Thoric
 */
void unlink_social( SOC_INDEX_DATA *social )
{
    SOC_INDEX_DATA *tmp;
    SOC_INDEX_DATA *tmp_next;
    int             hash;

    if ( !social )
    {
        bug( "Unlink_social: NULL social", 0 );
        return;
    }

    if ( !islower( social->name[0] ) )
        hash = 0;
    else
        hash = ( social->name[0] - 'a' ) + 1;

    if ( social == ( tmp = soc_index_hash[hash] ) )
    {
        soc_index_hash[hash] = tmp->next;
        return;
    }

    for ( ; tmp; tmp = tmp_next )
    {
        tmp_next = tmp->next;
        if ( social == tmp_next )
        {
            tmp->next = tmp_next->next;
            return;
        }
    }

    return;
}

/*
 * Free a social structure
 */
void free_social( SOC_INDEX_DATA *social )
{
    free_string( social->name          );
    free_string( social->char_no_arg   );
    free_string( social->others_no_arg );
    free_string( social->char_found    );
    free_string( social->others_found  );
    free_string( social->vict_found    );
    free_string( social->char_auto     );
    free_string( social->others_auto   );

    free_mem( social, sizeof( SOC_INDEX_DATA ) );
    return;
}

void fread_social( FILE *fp )
{
    char           *word;
    SOC_INDEX_DATA *social;
    char            buf [ MAX_STRING_LENGTH ];
    bool            fMatch;
    int             stat;

    social = new_social( );

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

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

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

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

	case 'N':
	    SKEY( "Name", social->name );
	    break;

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

	case 'V':
	    SKEY( "VictFound", social->vict_found );
	    break;
	}
	
	if ( !fMatch )
	{
            sprintf( buf, "Fread_social: no match: %s", word );
	    bug( buf, 0 );
	}
    }

    return;
}

void load_socials( void )
{
    FILE *fp;
    int   stat;
    char  strsave [ MAX_INPUT_LENGTH ];

    sprintf( strsave, "%s%s", SYSTEM_DIR, SOCIAL_FILE );

    if ( !( fp = fopen( strsave, "r" ) ) )
    {
	bug( "Cannot open SOCIALS.TXT", 0 );
	exit( 0 );
    }

    for ( ; ; )
    {
	char letter;
	char *word;

	letter = fread_letter( fp );

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

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

	word = fread_word( fp, &stat );
	if ( !str_cmp( word, "SOCIAL" ) )
	{
	    fread_social( fp );
	    continue;
	}
	else
	if ( !str_cmp( word, "END" ) )
	    break;
	else
	{
	    bug( "Load_socials: bad section.", 0 );
	    continue;
	}
    }
    
    fclose( fp );
    return;
}



/*
 * Get pointer to clan structure from clan name. -Toric
 */
CLAN_DATA *get_clan( const char *name )
{
    CLAN_DATA *clan;
    
    for ( clan = clan_first; clan; clan = clan->next )
       if ( !str_cmp( name, clan->name ) )
         return clan;
    return NULL;
}

/*
 * New code for loading clans from file.
 */
bool fread_clan( CLAN_DATA *clan, FILE *fp )
{
    char *word;
    bool  fMatch;
    int   stat;

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

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

	case 'C':
            SKEY( "Chieftain",   clan->chieftain );
            KEY( "Class",        clan->class,     fread_number( fp, &stat ) );
            KEY( "ClanHeros",    clan->clanheros, fread_number( fp, &stat ) );
            KEY( "ClanType",     clan->clan_type, fread_number( fp, &stat ) );
            KEY( "ClanObjOne",   clan->clanobj1,  fread_number( fp, &stat ) );
            KEY( "ClanObjTwo",   clan->clanobj2,  fread_number( fp, &stat ) );
            KEY( "ClanObjThree", clan->clanobj3,  fread_number( fp, &stat ) );
	    break;

	case 'D':
            SKEY( "Desc",    clan->description );
            KEY( "Donation", clan->donation,  fread_number( fp, &stat ) );
	    break;

	case 'E':
	    if ( !str_cmp( word, "End" ) )
		return TRUE;
	    break;

	case 'I':
            KEY( "IllegalPK",   clan->illegal_pk,  fread_number( fp, &stat ) );
	    break;

	case 'M':
            KEY( "Members",     clan->members, fread_number( fp, &stat ) );
            KEY( "MKills",      clan->mkills,  fread_number( fp, &stat ) );
            KEY( "MDeaths",     clan->mdeaths, fread_number( fp, &stat ) );
            SKEY( "Motto",      clan->motto );
	    break;

	case 'N':
            SKEY( "Name",      clan->name    );
	    break;

	case 'O':
            SKEY( "Overlord", clan->overlord );
	    break;

	case 'P':
            KEY( "PKills",  clan->pkills,  fread_number( fp, &stat ) );
            KEY( "PDeaths", clan->pdeaths, fread_number( fp, &stat ) );
	    break;

	case 'R':
            KEY( "Recall",  clan->recall,  fread_number( fp, &stat ) );
	    break;

	case 'S':
            KEY( "Score",     clan->score,     fread_number( fp, &stat ) );
            KEY( "Subchiefs", clan->subchiefs, fread_number( fp, &stat ) );
	    break;

	case 'W':
            SKEY( "WhoName",   clan->who_name    );
	    break;

	}

	if ( !fMatch )
	{
            bugf( "Load_clan_file: no match: %s", word );
	}
    }

    return FALSE;
}

bool load_clan_file( char *filename )
{
    CLAN_DATA *clan;
    FILE      *fp;
    int        stat;
    char       buf [ MAX_STRING_LENGTH ];

    sprintf( buf, "%s%s", CLAN_DIR, filename );
    if ( !( fp = fopen( buf, "r" ) ) )
    {
        perror( buf );
        return FALSE;
    }

    clan = alloc_mem ( sizeof( CLAN_DATA ) );
    clan->filename = str_dup( filename );

    for ( ; ; )
    {
	char *word;
	char letter;

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

	if ( letter != '#' )
	{
	    bug( "Load_clan_file: # not found.", 0 );
	    free_mem( clan, sizeof( CLAN_DATA ) );
	    break;
	}

	word = fread_word( fp, &stat );

	if ( !str_cmp( word, "CLAN" ) )
	{
	    fread_clan( clan, fp );

	    if ( !clan_first )
		clan_first	= clan;
	    else
		clan_last->next	= clan;
	    clan->next		= NULL;
	    clan_last		= clan;

	    break;
	}
	else if ( !str_cmp( word, "END"  ) )				break;
	else
	{
	    bugf( "Load_clan_file: bad section: %s.", word );
	    free_mem( clan, sizeof( CLAN_DATA ) );
	    break;
	}
    }
    fclose( fp );

    return TRUE;
}

/*
 * Load in all the clan files.
 */ 
void load_clans( void )
{
    FILE *fpList;
    char *filename;
    char  fname		[ MAX_STRING_LENGTH ];
    char  clanslist	[ MAX_STRING_LENGTH ];
    int   stat;
    
    clan_first  = NULL;
    clan_last   = NULL;

    log_string( "Loading clans..." );

    sprintf( clanslist, "%s%s", CLAN_DIR, CLANS_LIST );
    if ( !( fpList = fopen( clanslist, "r" ) ) )
    {
        perror( clanslist );
        exit( 1 );
    }

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

        if ( !load_clan_file( fname ) )
        {
          bugf( "Cannot load clan file: %s", fname );
        }
    }
    fclose( fpList );

    return;
}

void save_clan_list( void )
{
    FILE      *fp;
    CLAN_DATA *clan;
    char       clanslist	[ MAX_STRING_LENGTH ];

    sprintf( clanslist, "%s%s", CLAN_DIR, CLANS_LIST );

    fclose( fpReserve );

    if ( !( fp = fopen( clanslist, "w" ) ) )
    {
        bug( "Save_clan_list: fopen", 0 );
        perror( clanslist );
	return;
    }

    for ( clan = clan_first; clan; clan = clan->next )
	fprintf( fp, "%s\n", clan->filename );

    fprintf( fp, "$\n" );
    fclose( fp );

    fpReserve = fopen( NULL_FILE, "r" );

    return;
}

/*
 * New code for writing a clan to a file.
 */
void save_clan( CLAN_DATA *clan )
{
    FILE                    *fp;
    char                     buf	[ MAX_STRING_LENGTH ];

    if ( !clan->filename )
	return;
    
    sprintf( buf, "%s%s", CLAN_DIR, clan->filename );

    fclose( fpReserve );

    if ( !( fp = fopen( buf, "w" ) ) )
    {
        bugf( "Cannot open: %s for writing", clan->filename );
    }
    else
    {
	fprintf( fp, "#CLAN\n"						    );
	fprintf( fp, "WhoName       %s~\n",        clan->who_name	    );
	fprintf( fp, "Name          %s~\n",        clan->name		    );
	fprintf( fp, "Motto         %s~\n",        clan->motto		    );
	fprintf( fp, "Desc          %s~\n", fix_string( clan->description ) );
	fprintf( fp, "Overlord      %s~\n",        clan->overlord	    );
	fprintf( fp, "Chieftain     %s~\n",        clan->chieftain	    );
	fprintf( fp, "PKills        %d\n",         clan->pkills		    );
	fprintf( fp, "PDeaths       %d\n",         clan->pdeaths	    );
	fprintf( fp, "MKills        %d\n",         clan->mkills		    );
	fprintf( fp, "MDeaths       %d\n",         clan->mdeaths	    );
	fprintf( fp, "IllegalPK     %d\n",         clan->illegal_pk	    );
	fprintf( fp, "Score         %d\n",         clan->score		    );
	fprintf( fp, "ClanType      %d\n",         clan->clan_type	    );
	fprintf( fp, "Clanheros     %d\n",         clan->clanheros	    );
	fprintf( fp, "Subchiefs     %d\n",         clan->subchiefs	    );
	fprintf( fp, "Members       %d\n",         clan->members	    );
	fprintf( fp, "ClanObjOne    %d\n",         clan->clanobj1	    );
	fprintf( fp, "ClanObjTwo    %d\n",         clan->clanobj2	    );
	fprintf( fp, "ClanObjThree  %d\n",         clan->clanobj3	    );
	fprintf( fp, "Recall        %d\n",         clan->recall 	    );
	fprintf( fp, "Donation      %d\n",         clan->donation	    );
	fprintf( fp, "Class         %d\n",         clan->class  	    );
	fprintf( fp, "End\n"						    );
	fprintf( fp, "#END\n"						    );

	fclose( fp );
    }

    fpReserve = fopen( NULL_FILE, "r" );

    return;
}



void do_makeclan( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *rch;
    CLAN_DATA *clan;
    char       filename [ MAX_STRING_LENGTH ];
    char       who_name [ MAX_STRING_LENGTH ];

    rch = get_char( ch );

    if ( !authorized( rch, "makeclan" ) )
        return;

    if ( argument[0] == '\0' )
    {
        send_to_char( "Syntax: makeclan <clan name>\n\r", ch );
        return;
    }

    one_argument( argument, who_name );
    who_name[14] = '\0';

    sprintf( filename, "%s.clan", who_name );

    clan = alloc_mem ( sizeof( CLAN_DATA ) );
    if ( !clan_first )
	clan_first		= clan;
    else
	clan_last->next		= clan;
	clan->next		= NULL;
	clan_last		= clan;

    clan->filename		= str_dup( filename );
    clan->who_name		= str_dup( who_name );
    clan->name			= str_dup( argument );
    clan->motto			= str_dup( "" );
    clan->description		= str_dup( "" );
    clan->overlord		= str_dup( "" );
    clan->chieftain		= str_dup( "" );
    clan->subchiefs		= 0;
    clan->clanheros		= 0;
    clan->members		= 0;
    clan->recall		= 3001;
    clan->donation		= 0;
    clan->class			= 0;
    clan->mkills		= 0;
    clan->mdeaths		= 0;
    clan->pkills		= 0;
    clan->pdeaths		= 0;
    clan->illegal_pk		= 0;
    clan->score			= 0;
    clan->clan_type		= 0;
    clan->clanobj1		= 0;
    clan->clanobj2		= 0;
    clan->clanobj3		= 0;

    return;
}

// Veygoth - sets a players skills to minimum values
// if they gain a new skill or if they gain a level.
// skills start out at an initial value of 25 and increase
// by a minimum of one point per level.
// Does not lower skills already above the minimum.
void set_skills( CHAR_DATA *ch )
{
    int sn;

    if( IS_NPC( ch ))
      return;

    for( sn = 0; sn < MAX_SKILL; sn++ )
    {
        if( ch->level >= skills_table[sn].skill_level[ch->class] )
          if( ch->pcdata->skl_lrn[sn] <= 24 + ch->level )
              ch->pcdata->skl_lrn[sn] = 24 + ch->level ;
    }

    return;
}

void skill_practice( CHAR_DATA *ch, int sn )
{
    char buf[MAX_STRING_LENGTH];

    if( IS_NPC( ch ))
        return;

    // Have to be below the max and below 95% and make a successful
    // skill check and be able to have the skill.
    if( ch->pcdata->skl_lrn[sn] < ( 26 +
        ((ch->level - skills_table[sn].skill_level[ch->class] ) * 2 ))
        && ch->level >= skills_table[sn].skill_level[ch->class]
        && ch->pcdata->skl_lrn[sn] < MAX_SKILL_ADEPT
        && number_percent() <= 1 )
     {
          ch->pcdata->skl_lrn[sn]++;
          sprintf( buf, "&+cYe feel yer skill in %s improving.&n\n\r",
            skills_table[sn].name );
          send_to_char( buf, ch ); 
    }

     return;
}

// Initialize newbie spells to base values - Veygoth
void set_spells( CHAR_DATA *ch )
{
    int sn;

    if( IS_NPC( ch ))
      return;

    for( sn = 0; sn < MAX_SPELL; sn++ )
    {
        if( spells_table[sn].spell_circle[ch->class] == 1
           && ch->pcdata->spl_lrn[sn] < BASE_SPELL_ADEPT)
              ch->pcdata->spl_lrn[sn] = BASE_SPELL_ADEPT;
    }

    return;
}

void spell_practice( CHAR_DATA *ch, int sn )
{
    char buf[MAX_STRING_LENGTH];

    if( IS_NPC( ch ))
        return;

    // Have to be below the max and below 95% and make a successful
    // spell check and be able to have the spell.
    if( ch->pcdata->spl_lrn[sn] < MAX_SPELL_ADEPT
        && number_percent() <= 5 )
     {
          ch->pcdata->spl_lrn[sn]++;
          sprintf( buf, "&+cYe feel yer skill in %s improving.&n\n\r",
            spells_table[sn].name );
          send_to_char( buf, ch ); 
    }

     return;
}