/
Sapphire/bin/
Sapphire/db/
Sapphire/db/OLC_rooms/
Sapphire/db/abi/
Sapphire/db/em_src/
Sapphire/db/helps/
Sapphire/db/helps/emman/ifunc/
Sapphire/db/npcs/Tatt/
Sapphire/db/objects/Tatt/
Sapphire/db/q_data/
Sapphire/db/rooms/Tatt/
Sapphire/doc/
Sapphire/doc/em/
Sapphire/etc/
Sapphire/src/abic/
Sapphire/src/areacon/
Sapphire/src/client/
Sapphire/src/embc/
Sapphire/src/emi/
Sapphire/src/emi/test/
Sapphire/src/include/
Sapphire/src/sapphire/em/
Sapphire/src/tcon/
/*
 * Copyright (C) 1995-1997 Christopher D. Granz
 *
 * This header may not be removed.
 *
 * Refer to the file "License" included in this package for further
 * information and before using any of the following.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "sapphire.h"


/*
 * Prototypes
 */

#define OD                                                      OBJ_DATA

static void      fprint_pc_data                 ( FILE *, CHAR_DATA * );
static void      fprint_stats                   ( FILE *, STAT_DATA * );
static void      fprint_known                   ( FILE *, CHAR_DATA * );
static void      fprint_object                   ( FILE *, OBJ_DATA * );
static void      fread_pc_data                  ( FILE *, CHAR_DATA * );
static void      fread_stats                    ( FILE *, STAT_DATA * );
static void      fread_known                    ( FILE *, CHAR_DATA * );
static OD *      fread_object                   ( FILE *, CHAR_DATA * );

#undef OD


/*
 * Globals
 */
ROOM_INDEX_DATA *                                         pStartingRoom;


/*
 * Functions
 */

/*
 * Save one PC to file.
 */
void save_pc( CHAR_DATA *pChar )
{
    /* OBJ_DATA *pObj; */
    FILE *pFile;
    char cFilename[MAX_INPUT];

    if ( IS_NPC( pChar ) || IS_GUEST( pChar ) )
        return;

    sprintf( cFilename, "%s%s.plr", pPlayerDir,
      capit( pChar->pPCData->sName ) );
    pFile = open_file( cFilename, "w", TRUE );

    fprintf( pFile, "@PC_DATA\n" );
    fprint_pc_data( pFile, pChar );
    fprintf( pFile, "\n@STATS\n" );
    fprint_stats( pFile, pChar->pStats );
    fprintf( pFile, "\n@KNOWN\n" );
    fprint_known( pFile, pChar );

    /* for ( pObj = pChar->pInven; pObj; pObj = pObj->pNextContent )
    {
        fprintf( pFile, "\n@ITEM\n" );
        fprint_object( pFile, pObj );
    } */

    fprintf( pFile, "\n@END\n" );

    close_file( pFile );
}


/*
 * Load one PC from file.
 */
CHAR_DATA *load_pc( char *pName )
{
    char cFilename[MAX_INPUT];
    CHAR_DATA *pChar;
    FILE *pFile;
    char *pBuf;

    sprintf( cFilename, "%s%s.plr", pPlayerDir, capit( pName ) );

    if ( ( pFile = open_file( cFilename, "r", FALSE ) ) == NULL )
        return ( NULL );

    pChar                      = new_pc( );
    pChar->pPCData->sName      = save_string( capit( pName ) );

    for ( ; ; )
    {
        if ( fget_letter( pFile ) != '@' )
        {
            sap_error( "Symbol `@' missing from file." );
            free_char( &pChar );
            close_file( pFile );
            return ( NULL );
        }

        pBuf                   = ( feof( pFile ) ? "END"
                                 : fget_word( pFile ) );

        if ( str_compare( pBuf, "PC_DATA" ) == TRUE )
            fread_pc_data( pFile, pChar );
        else if ( str_compare( pBuf, "STATS" ) == TRUE )
            fread_stats( pFile, pChar->pStats );
        else if ( str_compare( pBuf, "KNOWN" ) == TRUE )
            fread_known( pFile, pChar );
        else if ( str_compare( pBuf, "ITEM" ) == TRUE )
        {
            OBJ_DATA *pObj     = fread_object( pFile, pChar );

            pObj->pCarriedBy   = pChar;
            pObj->pNextContent = pChar->pInven;
            pChar->pInven      = pObj;
        }
        else if ( str_compare( pBuf, "END" ) == TRUE )
        {
            close_file( pFile );
            return ( pChar );
        }
        else
        {
            sap_error( "Unknown section `%s'.", pBuf );
            close_file( pFile );
            free_char( &pChar );
            return ( NULL );
        }
    }

    close_file( pFile );
    return ( NULL );
}


static void fprint_pc_data( FILE *pFile, CHAR_DATA *pChar )
{
    fprintf( pFile, "LL %ld\n", pChar->pPCData->tLastLogin );

    if ( pChar->pPCData->sPassword[0] != '\0' )
    {
        fprintf( pFile, "PW " );
        fput_string( pFile, "%s", pChar->pPCData->sPassword );
        fputc( '\n', pFile );
    }

    if ( pChar->pPCData->sPrompt[0] != '\0' )
    {
        fprintf( pFile, "P " );
        fput_string( pFile, "%s", pChar->pPCData->sPrompt );
        fputc( '\n', pFile );
    }

    if ( pChar->sLongDesc[0] != '\0' )
    {
        fprintf( pFile, "LD " );
        fput_string( pFile, "%s", pChar->sLongDesc );
        putc( '\n', pFile );
    }

    if ( pChar->fPartFlags != 0 )
        fprintf( pFile, "PF %ld\n", pChar->fPartFlags );

    if ( pChar->fActFlags != 0 )
        fprintf( pFile, "AF %ld\n", pChar->fActFlags );

    if ( pChar->pPCData->fChanFlags != 0 )
        fprintf( pFile, "CF %ld\n", pChar->pPCData->fChanFlags );

    if ( pChar->iLevel != 0 )
        fprintf( pFile, "L %d\n", pChar->iLevel );

    if ( pChar->iAlignment != 0 )
        fprintf( pFile, "A %d\n", pChar->iAlignment );

    if ( pChar->iRace != 0 )
        fprintf( pFile, "R %d\n", pChar->iRace );

    if ( pChar->iSex != 0 )
        fprintf( pFile, "S %d\n", pChar->iSex );

    if ( pChar->iHairColor != 0 )
        fprintf( pFile, "HC %d\n", pChar->iHairColor );

    if ( pChar->iEyeColor != 0 )
        fprintf( pFile, "EC %d\n", pChar->iEyeColor );

    if ( pChar->iHeight != 0 )
        fprintf( pFile, "H %d\n", pChar->iHeight );

    if ( pChar->iWeight != 0 )
        fprintf( pFile, "W %d\n", pChar->iWeight );

    if ( pChar->iMaxCarry != 0 )
        fprintf( pFile, "MC %d\n", pChar->iMaxCarry );

    if ( pChar->iHP != 0 )
        fprintf( pFile, "HP %d\n", pChar->iHP );

    if ( pChar->iMP != 0 )
        fprintf( pFile, "MP %d\n", pChar->iMP );

    if ( pChar->iMV != 0 )
        fprintf( pFile, "MV %d\n", pChar->iMV );

    if ( pChar->iPosition != 0 )
        fprintf( pFile, "PO %d\n", pChar->iPosition );

    if ( pChar->iGold != 0 )
        fprintf( pFile, "G %ld\n", pChar->iGold );

    if ( pChar->pInRoom != NULL && pChar->pInRoom != uDefaultRoom.pRoom )
        fprintf( pFile, "RO %ld\n", pChar->pInRoom->iNumber );

    fprintf( pFile, "END\n" );
}


static void fprint_stats( FILE *pFile, STAT_DATA *pStats )
{
    if ( pStats->iStatStr != 0 )
        fprintf( pFile, "S %d\n", pStats->iStatStr );

    if ( pStats->iStatInt != 0 )
        fprintf( pFile, "I %d\n", pStats->iStatInt );

    if ( pStats->iStatWis != 0 )
        fprintf( pFile, "W %d\n", pStats->iStatWis );

    if ( pStats->iStatDex != 0 )
        fprintf( pFile, "D %d\n", pStats->iStatDex );

    if ( pStats->iStatCon != 0 )
        fprintf( pFile, "C %d\n", pStats->iStatCon );

    if ( pStats->iStatCha != 0 )
        fprintf( pFile, "CH %d\n", pStats->iStatCha );

    if ( pStats->iStatLuc != 0 )
        fprintf( pFile, "L %d\n", pStats->iStatLuc );

    if ( pStats->iStatHP != 0 )
        fprintf( pFile, "HP %d\n", pStats->iStatHP );

    if ( pStats->iStatMP != 0 )
        fprintf( pFile, "MP %d\n", pStats->iStatMP );

    if ( pStats->iStatMV != 0 )
        fprintf( pFile, "MV %d\n", pStats->iStatMV );

    fprintf( pFile, "END\n" );
}


static void fprint_known( FILE *pFile, CHAR_DATA *pChar )
{
    KNOWN_PERSON_DATA *pKnownPerson;
    KNOWN_EXIT_DATA *pKnownExit;

    if ( IS_NPC( pChar ) || pChar->iLevel >= BUILDER_LEVEL )
    {
        fprintf( pFile, "END\n" );
        return;
    }

    for ( pKnownPerson = pChar->pPCData->pKnownPeople; pKnownPerson;
      pKnownPerson = pKnownPerson->pNext )
    {
        fprintf( pFile, "P " );
        fput_string( pFile, "%s", pKnownPerson->sName );
        fprintf( pFile, " %ld\n", (long) pKnownPerson->tIntroduced );
    }

    for ( pKnownExit = pChar->pPCData->pKnownExits; pKnownExit != NULL;
      pKnownExit = pKnownExit->pNext )
    {
        fprintf( pFile, "E %ld %d %ld\n", pKnownExit->pRoom->iNumber,
          (int) pKnownExit->iDir, (long) pKnownExit->tDiscovered );
    }

    fprintf( pFile, "END\n" );
}


static void fprint_object( FILE *pFile, OBJ_DATA *pObj )
{
    fprintf( pFile, "NUMBER     %ld\n", pObj->pObjIndex->iNumber );
    fprintf( pFile, "END\n" );
}


static void fread_pc_data( FILE *pFile, CHAR_DATA *pChar )
{
    char *pBuf;
    int i, i2;
    bool bFoundMatch;

    for ( ; ; )
    {
        bFoundMatch   = FALSE;
        pBuf          = fget_word( pFile );

        if ( str_compare( pBuf, "END" ) == TRUE )
            break;

        KEY(   "LASTLOGIN", pChar->pPCData->tLastLogin,
          fget_number( pFile ) );
        KEY(   "LL",        pChar->pPCData->tLastLogin,
          fget_number( pFile ) );
        SSKEY( "PASSWORD",  pChar->pPCData->sPassword,
          fget_string( pFile ) );
        SSKEY( "PW",        pChar->pPCData->sPassword,
          fget_string( pFile ) );
        SSKEY( "PROMPT",    pChar->pPCData->sPrompt,
          fget_string( pFile ) );
        SSKEY( "P",         pChar->pPCData->sPrompt,
          fget_string( pFile ) );
        SSKEY( "LONGDESC",  pChar->sLongDesc,  fget_string( pFile ) );
        SSKEY( "LD",        pChar->sLongDesc,  fget_string( pFile ) );
        KEY(   "PARTFLAGS", pChar->fPartFlags, fget_number( pFile ) );
        KEY(   "PF",        pChar->fPartFlags, fget_number( pFile ) );
        KEY(   "ACTFLAGS",  pChar->fActFlags,  fget_number( pFile ) );
        KEY(   "AF",        pChar->fActFlags,  fget_number( pFile ) );
        KEY(   "CHANFLAGS", pChar->pPCData->fChanFlags,
          fget_number( pFile ) );
        KEY(   "CF",        pChar->pPCData->fChanFlags,
          fget_number( pFile ) );
        KEY(   "LEVEL",     pChar->iLevel,     fget_number( pFile ) );
        KEY(   "L",         pChar->iLevel,     fget_number( pFile ) );
        KEY(   "ALIGNMENT", pChar->iAlignment, fget_number( pFile ) );
        KEY(   "A",         pChar->iAlignment, fget_number( pFile ) );
        KEY(   "RACE",      pChar->iRace,      fget_number( pFile ) );
        KEY(   "R",         pChar->iRace,      fget_number( pFile ) );
        KEY(   "SEX",       pChar->iSex,       fget_number( pFile ) );
        KEY(   "S",         pChar->iSex,       fget_number( pFile ) );
        KEY(   "HAIRCOLOR", pChar->iHairColor, fget_number( pFile ) );
        KEY(   "HC",        pChar->iHairColor, fget_number( pFile ) );
        KEY(   "EYECOLOR",  pChar->iEyeColor,  fget_number( pFile ) );
        KEY(   "EC",        pChar->iEyeColor,  fget_number( pFile ) );
        KEY(   "HEIGHT",    pChar->iHeight,    fget_number( pFile ) );
        KEY(   "H",         pChar->iHeight,    fget_number( pFile ) );
        KEY(   "WEIGHT",    pChar->iWeight,    fget_number( pFile ) );
        KEY(   "W",         pChar->iWeight,    fget_number( pFile ) );
        KEY(   "MAXCARRY",  pChar->iMaxCarry,  fget_number( pFile ) );
        KEY(   "MC",        pChar->iMaxCarry,  fget_number( pFile ) );
        KEY(   "HP",        pChar->iHP,        fget_number( pFile ) );
        KEY(   "MP",        pChar->iMP,        fget_number( pFile ) );
        KEY(   "MV",        pChar->iMV,        fget_number( pFile ) );
        KEY(   "POSITION",  pChar->iPosition,  fget_number( pFile ) );
        KEY(   "PO",        pChar->iPosition,  fget_number( pFile ) );
        KEY(   "GOLD",      pChar->iGold,      fget_number( pFile ) );
        KEY(   "G",         pChar->iGold,      fget_number( pFile ) );
        KEY(   "ROOM",      pStartingRoom,
          get_room_index( fget_number( pFile ) ) );
        KEY(   "RO",        pStartingRoom,
          get_room_index( fget_number( pFile ) ) );

        if ( bFoundMatch != TRUE )
            sap_warning( "No match for `%s'.", pBuf );
    }

    if ( pStartingRoom == NULL )
        pStartingRoom     = uDefaultRoom.pRoom;

    if ( pChar->iLevel < 1 )
        pChar->iLevel     = 1;
    else if ( pChar->iLevel > IMP_LEVEL )
        pChar->iLevel     = IMP_LEVEL;

    if ( pChar->iAlignment < -1000 )
        pChar->iAlignment = 1;
    else if ( pChar->iAlignment > 1000 )
        pChar->iAlignment = 1000;

    if ( get_race_string( pChar->iRace )[0] == '\0' )
        pChar->iRace      = rRaceTable[0].iNumber;

    if ( get_sex_string( pChar->iSex )[0] == '\0' )
        pChar->iSex       = snSexTable[0].iNumber;

    i                     = get_race_index( pChar->iRace );

    for ( i2 = 0; rRaceTable[i].iHairColors[i2] != 0; i2++ )
    {
        if ( rRaceTable[i].iHairColors[i2] == pChar->iHairColor )
            break;
    }

    if ( rRaceTable[i].iHairColors[i2] == 0 )
        pChar->iHairColor = rRaceTable[i].iHairColors[0];

    for ( i2 = 0; rRaceTable[i].iEyeColors[i2] != 0; i2++ )
    {
        if ( rRaceTable[i].iEyeColors[i2] == pChar->iEyeColor )
            break;
    }

    if ( rRaceTable[i].iEyeColors[i2] == 0 )
        pChar->iEyeColor  = rRaceTable[i].iEyeColors[0];

    if ( pChar->iHeight < rRaceTable[i].iUpperLowerHeights[1] )
        pChar->iHeight    = rRaceTable[i].iUpperLowerHeights[1];
    else if ( pChar->iHeight > rRaceTable[i].iUpperLowerHeights[0] )
        pChar->iHeight    = rRaceTable[i].iUpperLowerHeights[0];

    if ( pChar->iWeight < rRaceTable[i].iUpperLowerWeights[1] )
        pChar->iWeight    = rRaceTable[i].iUpperLowerWeights[1];
    else if ( pChar->iWeight > rRaceTable[i].iUpperLowerWeights[0] )
        pChar->iWeight    = rRaceTable[i].iUpperLowerWeights[0];

    if ( pChar->iHP < 0 )
        pChar->iHP        = 0;
    else if ( pChar->iHP > 9999 )
        pChar->iHP        = 9999;

    if ( pChar->iMP < 0 )
        pChar->iMP        = 0;
    else if ( pChar->iMP > 9999 )
        pChar->iMP        = 9999;

    if ( pChar->iMV < 0 )
        pChar->iMV        = 0;
    else if ( pChar->iMV > 9999 )
        pChar->iMV        = 9999;

    if ( pChar->iPosition != NUMBER_POSITION_DYING
      && pChar->iPosition != NUMBER_POSITION_SLEEPING
      && pChar->iPosition != NUMBER_POSITION_RESTING
      && pChar->iPosition != NUMBER_POSITION_SITTING
      && pChar->iPosition != NUMBER_POSITION_STANDING )
        pChar->iPosition  = NUMBER_POSITION_STANDING;
}


static void fread_stats( FILE *pFile, STAT_DATA *pStats )
{
    char *pBuf;
    bool bFoundMatch;

    for ( ; ; )
    {
        bFoundMatch = FALSE;
        pBuf        = fget_word( pFile );

        if ( str_compare( pBuf, "END" ) == TRUE )
            break;

        KEY( "STR", pStats->iStatStr, fget_number( pFile ) );
        KEY( "S",   pStats->iStatStr, fget_number( pFile ) );
        KEY( "INT", pStats->iStatInt, fget_number( pFile ) );
        KEY( "I",   pStats->iStatInt, fget_number( pFile ) );
        KEY( "WIS", pStats->iStatWis, fget_number( pFile ) );
        KEY( "W",   pStats->iStatWis, fget_number( pFile ) );
        KEY( "DEX", pStats->iStatDex, fget_number( pFile ) );
        KEY( "D",   pStats->iStatDex, fget_number( pFile ) );
        KEY( "CON", pStats->iStatCon, fget_number( pFile ) );
        KEY( "C",   pStats->iStatCon, fget_number( pFile ) );
        KEY( "CHA", pStats->iStatCha, fget_number( pFile ) );
        KEY( "CH",  pStats->iStatCha, fget_number( pFile ) );
        KEY( "LUC", pStats->iStatLuc, fget_number( pFile ) );
        KEY( "L",   pStats->iStatLuc, fget_number( pFile ) );
        KEY( "HP",  pStats->iStatHP,  fget_number( pFile ) );
        KEY( "MP",  pStats->iStatMP,  fget_number( pFile ) );
        KEY( "MV",  pStats->iStatMV,  fget_number( pFile ) );

        if ( bFoundMatch != TRUE )
            sap_warning( "No match for `%s'.", pBuf );
    }

    if ( pStats->iStatStr < 0 )
        pStats->iStatStr  = 0;
    else if ( pStats->iStatStr > 100 )
        pStats->iStatStr  = 100;

    if ( pStats->iStatInt < 0 )
        pStats->iStatInt  = 0;
    else if ( pStats->iStatInt > 100 )
        pStats->iStatInt  = 100;

    if ( pStats->iStatWis < 0 )
        pStats->iStatWis  = 0;
    else if ( pStats->iStatWis > 100 )
        pStats->iStatWis  = 100;

    if ( pStats->iStatDex < 0 )
        pStats->iStatDex  = 0;
    else if ( pStats->iStatDex > 100 )
        pStats->iStatDex  = 100;

    if ( pStats->iStatCon < 0 )
        pStats->iStatCon  = 0;
    else if ( pStats->iStatCon > 100 )
        pStats->iStatCon  = 100;

    if ( pStats->iStatCha < 0 )
        pStats->iStatCha  = 0;
    else if ( pStats->iStatCha > 100 )
        pStats->iStatCha  = 100;

    if ( pStats->iStatLuc < 0 )
        pStats->iStatLuc  = 0;
    else if ( pStats->iStatLuc > 100 )
        pStats->iStatLuc  = 100;

    if ( pStats->iStatHP < 0 )
        pStats->iStatHP   = 0;
    else if ( pStats->iStatHP > 100 )
        pStats->iStatHP   = 100;

    if ( pStats->iStatMP < 0 )
        pStats->iStatMP   = 0;
    else if ( pStats->iStatMP > 100 )
        pStats->iStatMP   = 100;

    if ( pStats->iStatMV < 0 )
        pStats->iStatMV   = 0;
    else if ( pStats->iStatMV > 100 )
        pStats->iStatMV   = 100;
}


static void fread_known( FILE *pFile, CHAR_DATA *pChar )
{
    char *pBuf;
    bool bFoundMatch;

    for ( ; ; )
    {
        bFoundMatch      = FALSE;
        pBuf             = fget_word( pFile );

        if ( str_compare( pBuf, "END" ) == TRUE )
            break;

        if ( str_compare( pBuf, "PERSON" ) == TRUE
          || str_compare( pBuf, "P" ) == TRUE )
        {
            KNOWN_PERSON_DATA *pKnownPerson;

            bFoundMatch  = TRUE;
            pKnownPerson = alloc_mem( sizeof( *pKnownPerson ) );

            pKnownPerson->sName = save_string( fget_string( pFile ) );
            pKnownPerson->tIntroduced    = fget_number( pFile );

            pKnownPerson->pNext = pChar->pPCData->pKnownPeople;
            pChar->pPCData->pKnownPeople = pKnownPerson;
        }

        if ( str_compare( pBuf, "EXIT" ) == TRUE
          || str_compare( pBuf, "E" ) == TRUE )
        {
            ROOM_INDEX_DATA *pRoom;
            KNOWN_EXIT_DATA *pKnownExit;

            bFoundMatch  = TRUE;

            if ( ( pRoom = get_room_index( fget_number( pFile ) ) )
              == NULL )
                continue;

            pKnownExit   = alloc_mem( sizeof( *pKnownExit ) );

            pKnownExit->pRoom   = get_room_index( fget_number( pFile ) );
            pKnownExit->tDiscovered      = fget_number( pFile );

            pKnownExit->pNext   = pChar->pPCData->pKnownExits;
            pChar->pPCData->pKnownExits  = pKnownExit;
        }

        if ( bFoundMatch != TRUE )
            sap_warning( "No match for `%s'.", pBuf );
    }
}


static OBJ_DATA *fread_object( FILE *pFile, CHAR_DATA *pChar )
{
    OBJ_INDEX_DATA *pObjIndex;
    OBJ_DATA *pObj      = NULL;
    char *pBuf;
    int iNumber;
    bool bFoundMatch;

    for ( ; ; )
    {
        bFoundMatch     = FALSE;
        pBuf            = fget_word( pFile );

        if ( str_compare( pBuf, "END" ) == TRUE )
            break;

        if ( str_compare( pBuf, "NUMBER" ) == TRUE )
        {
            iNumber     = atoi( pBuf );

            if ( ( pObjIndex = get_object_index( iNumber ) ) == NULL )
                sap_warning( "Unknown object number `%d'.", iNumber );
            else
                pObj    = new_object( pObjIndex, pChar );

            bFoundMatch = TRUE;
        }

        if ( bFoundMatch != TRUE )
            sap_warning( "No match for `%s'.", pBuf );
    }

    return ( pObj );
}


/*
 * End of plr_save.c
 */