daleken/
daleken/data/notes/
daleken/data/player/
daleken/data/system/poses/
daleken/doc/Homepage/images/
daleken/log/
/*___________________________________________________________________________*
   )()(			  DalekenMUD 1.12 (C) 2000			)()(
   `]['		       by Martin Thomson, Lee Brooks,			`]['
    ||		       Ken Herbert and David Jacques			 ||
    || ----------------------------------------------------------------- ||
    || Envy Diku Mud improvements copyright (C) 1994 by Michael Quan,	 ||
    || David Love, Guilherme 'Willie' Arnold, and Mitchell Tse.		 ||
    || Merc 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.					 ||
    || ----------------------------------------------------------------- ||
    || Any use of this software must follow the licenses of the		 ||
    || creators.  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.					 ||
    || ----------------------------------------------------------------- ||
    ||                             save.c                                ||
    || Player saving and loading.                                        ||
 *_/<>\_________________________________________________________________/<>\_*/


#include "mud.h"
#include "event.h"
#include "db.h"
#if !defined( WIN32 )
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#endif

/*
 * Local functions.
 */
void fwrite_char	args( ( CHAR_DATA *ch, FILE *fp ) );
int fread_char		args( ( CHAR_DATA *ch, FILE *fp, int *version ) );

DECLARE_READ_FUN( read_char_affect	);
DECLARE_READ_FUN( read_obj_affect	);
DECLARE_READ_FUN( read_alias		);
DECLARE_READ_FUN( read_board		);
DECLARE_READ_FUN( read_clan		);
DECLARE_READ_FUN( read_event		);
DECLARE_READ_FUN( read_event_o		);
DECLARE_READ_FUN( read_exdesc_o		);
DECLARE_READ_FUN( read_magic		);
DECLARE_READ_FUN( read_mana		);
DECLARE_READ_FUN( read_max_mana		);
DECLARE_READ_FUN( read_multiclass	);
DECLARE_READ_FUN( read_perm_o		);
DECLARE_READ_FUN( read_race_o		);
DECLARE_READ_FUN( read_religion		);
DECLARE_READ_FUN( read_required_o	);
DECLARE_READ_FUN( read_skill		);
DECLARE_READ_FUN( read_spell_o		);
DECLARE_READ_FUN( read_values_o		);

/*
 * External stuff.
 */
extern char *daPrompt;
bool special_read	args( ( FILE *fp, struct file_read_type *read_table,
				void *vo ) );


/* Courtesy of Yaz of 4th Realm */
char *initial( const char *str )
{
    static char strint[2];

    strint[1] = '\0';
    strint[0] = LOWER( str[0] );
    return strint;
}


/*
 * Save a character and inventory.
 * Would be cool to save NPC's too for quest purposes,
 *   some of the infrastructure is provided.
 * Need means of loading vnum, that is ALL.
 */
void save_char_obj( CHAR_DATA *ch )
{
    FILE *fp;
    char strsave[MAX_INPUT_LENGTH];

    ch->save_time = current_time;
    if( IS_NPC( ch ) || ch->level < SysInfo->saveat
	|| xIS_SET( ch->act, PLR_NOSAVE ) )
	return;

    if( ch->desc && ch->desc->original )
	ch = ch->desc->original;

    /* player files parsed directories by Yaz 4th Realm */
    sprintf( strsave, "%s%c%s%s", PLAYER_DIR, LOWER( ch->name[0] ),
	     DIR_SEPARATOR, capitalize( ch->name ) );

    if( ( fp = open_file( strsave, "w", TRUE ) ) )
    {
/*	if( ch->desc )
	fprintf( fp, "## Host \"%s\";\n", ch->desc->host ); */
	write_next_item( fp, "Char", ch );
	fprintf( fp, "\neof\n\n" );
	close_file( fp );
    }
    else
    {
	/* Can't use bug here, it causes crashes since we have fpReserve
	 * closed.
	bug( "Save_char_obj: open_file %s: ", ch->name );
	 */
	perror( strsave );
    }

    return;
}


int get_orig_sex( CHAR_DATA *ch )
{
    int sex = ch->sex;
    AFFECT_DATA *af;

    if( !IS_AFFECTED( ch, AFF_POLYMORPH ) )
	return ch->sex;
    for( af = ch->affected; af; af = af->next )
    {
	if( xIS_SET( af->bitvector, AFF_POLYMORPH )
	    && af->location == APPLY_SEX )
	    sex -= af->modifier;
    }

    return sex;
}


int get_orig_race( CHAR_DATA *ch )
{
    int race = ch->race;
    AFFECT_DATA *af;

    if( !IS_AFFECTED( ch, AFF_POLYMORPH ) )
	return race;
    for( af = ch->affected; af; af = af->next )
    {
	if( xIS_SET( af->bitvector, AFF_POLYMORPH )
	    && af->location == APPLY_RACE )
	    race -= af->modifier;
    }
    return race;
}


/*
 * Load a char and inventory into a new ch structure.
 */
bool load_char_obj( DESCRIPTOR_DATA *d, const char *name )
{
    CHAR_DATA *ch;
    int i, status;
    bool found;

    char sorry_player[] =
	"********************************************************\n\r"
	"** One or more of the critical fields in your player  **\n\r"
	"** file were corrupted since you last played.  Please **\n\r"
	"** contact an administrator or programmer to          **\n\r"
	"** investigate the recovery of your characters.       **\n\r"
	"********************************************************\n\r";

    /* parsed player file directories by Yaz of 4th Realm */
    /* decompress if .gz file exists - Thx Alander */
#if defined( HAVE_GZIP ) && !defined( WIN32 )
    {
	struct stat tmp;

	sprintf( strArea, "%s%c%s%s.gz", PLAYER_DIR, LOWER( name[0] ),
		 DIR_SEPARATOR, capitalize( name ) );
	if( stat( strArea, &tmp ) == 0 )
	{
	    char buf[MAX_STRING_LENGTH];

	    sprintf( buf, "gzip -dfq %s", strArea );
	    system( buf );
	}
    }
#endif

    sprintf( strArea, "%s%c%s%s", PLAYER_DIR, LOWER( name[0] ),
	     DIR_SEPARATOR, capitalize( name ) );

    if( ( fpArea = open_file( strArea, "r", TRUE ) ) )
    {
	found = TRUE;

	ch = read_next_item( fpArea, &status );
	if( !ch || status < 0 )
	{
	    bug( "Load_char_obj:  %s section PLAYER corrupt.\n\r",
		 name );
	    write_to_buffer( d, sorry_player );

	    /*
	     * In case you are curious, it is ok to leave ch alone for
	     * close_socket to free.
	     * We want to now kick the bad character out as what we are missing
	     * are MANDATORY fields.  -Kahn
	     */
	    ch = new_character( TRUE );

	    xSET_BIT( ch->act, PLR_DENY );
	}

	close_file( fpArea );
	fpArea = NULL;
    }
    else
    {
	found = FALSE;

	ch = new_character( TRUE );

	ch->pcdata->prompt = str_dup( daPrompt );
	for( i = 0; i < MAX_BOARD; i++ )
	    ch->pcdata->last_note[i]	= 0;

	vzero( ch->act );
	xSET_BIT( ch->act, PLR_AUTOEXIT );
	xSET_BIT( ch->act, PLR_AUTOGOLD );
	xSET_BIT( ch->act, PLR_AUTOSPLIT );
	xSET_BIT( ch->act, PLR_BLANK );
	xSET_BIT( ch->act, PLR_COLOUR );
	xSET_BIT( ch->act, PLR_COMBINE );
	xSET_BIT( ch->act, PLR_PROMPT );
	ch->pcdata->pwd = str_dup( "" );
	ch->pcdata->immname = str_dup( "" );
	ch->pcdata->bamfin = str_dup( "" );
	ch->pcdata->bamfout = str_dup( "" );
	ch->pcdata->immskll = str_dup( "" );
	ch->pcdata->title = str_dup( "" );
	ch->pcdata->setmin = str_dup( "enters from the" );
	ch->pcdata->setmout = str_dup( "leaves" );
	ch->pcdata->perm_str = 15;
	ch->pcdata->perm_int = 15;
	ch->pcdata->perm_wis = 15;
	ch->pcdata->perm_dex = 15;
	ch->pcdata->perm_con = 15;
	ch->pcdata->condition[COND_THIRST] = 1000;
	ch->pcdata->condition[COND_FULL] = 1000;
	ch->pcdata->pagelen = 20;
	ch->pcdata->aliases = NULL;
	ch->pcdata->security = 0;
	ch->pcdata->pc_bits = 0;
	ch->pcdata->familiar = 0;
	ch->pcdata->blink = 0;
	ch->pcdata->killed = ch->pcdata->died = 0;
	ch->pcdata->religion = NULL;
	ch->pcdata->clan = NULL;
	ch->pcdata->clan_rank = RANK_NONE;
	ch->pcdata->quest = new_quest();
	ch->pcdata->language = LANG_COMMON;
	ch->practice = 300;
	ch->body_parts = BODY_PARTS_HUMAN;
	for( i = 0; i < MAGIC_MAX; i++ )
	{
	    ch->pcdata->perm_magic[i] = 2;
	    ch->max_mana[i] = 10;
	}
	for( i = 0; i < NUM_MULTI_CLASS; i++ )
	    ch->pcdata->multi_class[i] = CLASS_UNKNOWN;
    }

    d->character = ch;
    ch->desc = d;
    ch->name = str_dup( name );

    ch->pcdata->board = &board_table[0];
    ch->pcdata->switched = FALSE;

    return found;
}


void do_delet( CHAR_DATA *ch, const char *argument )
{
    send_to_char( "&RAre you INSANE?!?&n\n\r", ch );
    return;
}


void do_delete( CHAR_DATA *ch, const char *argument )
{
    char strsave[MAX_INPUT_LENGTH];
    DESCRIPTOR_DATA *d;
    HIGHEST_DATA *high;

    if( IS_NPC( ch ) )
	return;

    if( strcmp( crypt( argument, ch->pcdata->pwd ), ch->pcdata->pwd ) )
    {
	send_to_char( "That password is incorrect.\n\r", ch );
	return;
    }

    if( ch->position == POS_FIGHTING )
    {
	send_to_char( "No way! You are fighting.\n\r", ch );
	return;
    }

    if( ch->position < POS_STUNNED )
    {
	send_to_char( "You're not DEAD yet.\n\r", ch );
	return;
    }

    if( ch->desc && ch->desc->pString )
	string_add( ch, "@" );

    send_to_char( "PISS OFF!!!\n\r", ch );
    send_to_char( "   [We will miss you badly.]\n\r\n\r", ch );

    act( "$n has finally succumbed to sanity and has deleted.",
	 ch, NULL, NULL, TO_ROOM );
    sprintf( log_buf,
	     "%s has finally succumbed to sanity and has deleted.", ch->name );
    log_string( log_buf );
    wiznet( ch, WIZ_LOGINS, get_trust( ch ), log_buf );
    if( !IS_IMMORTAL( ch ) )
	talk_channel( NULL, log_buf, CHANNEL_INFO, "INFO" );

    sprintf( strsave, "%s%c%s%s", PLAYER_DIR, LOWER( ch->name[0] ),
	     DIR_SEPARATOR, capitalize( ch->name ) );
    {
#if !defined( WIN32 )
	struct stat tmp;
	if( stat( strsave, &tmp ) == 0 )
	{
#else
	FILE *fp;
	if( ( fp = open_file( strsave, "r", FALSE ) ) )
	{
	    close_file( fp );
#endif
	    sprintf( log_buf, "rm -f %s", strsave );
	    system( log_buf );
	}
	else
	{
	    send_to_char( "No need to concern yourself, you don't really exist.\n\r", ch );
	}
    }

    /*
     * Remove char from highest.
     */
    for( high = highest_first; high; high = high->next )
    {
	int i;
	if( str_cmp( high->type, "TopTen" )
	    && str_cmp( high->type, class_table[ch->class].name )
	    && str_cmp( high->type, race_table[ch->race].name ) )
	    continue;
	for( i = 0; i < 10; ++i )
	    if( high->entries[i] && high->entries[i]->level > 0
		&& !str_cmp( ch->name, high->entries[i]->name ) )
		break;
	if( i < 10 )
	    free_highent( high->entries[i] );
	for( ; i < 9; ++i )
	    high->entries[i] = high->entries[i+1];
	high->entries[9] = NULL;
    }

    /*
     * After extract_char the ch is no longer valid!
     */
    d = ch->desc;
    extract_char( ch, TRUE );
    if( d )
	close_socket( d );

    return;
}