/
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.
 */

/*
 * My NPC/object/room loading system is a bit slow, as you might have
 * noticed, this is because I did not put a high priority on bootup
 * speed but rather on ease of adding fields to NPC/object/room files.
 */

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

#include "sapphire.h"


/*
 * Prototypes
 */
static bool      load_dir_desc       ( ROOM_INDEX_DATA *, FILE *, int );
static bool      load_exit           ( ROOM_INDEX_DATA *, FILE *, int );
static int       get_obj_reset_list      ( char **, OBJ_RESET_DATA ** );


/*
 * Functions
 */
bool npc_load_inherit( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    pNPCIndex->iInherit = fget_number_2( pFile );

    if ( pNPCIndex->iInherit <= 5
      || pNPCIndex->iInherit > MAX_INDEX_NUMBER )
        sap_fatal( "NPC %d: Illegal NPC number `%d' for inherit.",
          pNPCIndex->iNumber, pNPCIndex->iInherit );

    return ( FALSE );
}


bool npc_load_imagefilename( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    return ( FALSE );
}


bool npc_load_names( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    int i;

    for ( i = 0; pNPCIndex->pNameList[i] != NULL; i++ )
        free_string( &pNPCIndex->pNameList[i] );

    free_mem( (void **) &pNPCIndex->pNameList );
    pNPCIndex->pNameList    = alloc_mem( ( sizeof( string ) * 2 ) );
    pNPCIndex->pNameList[0] = save_string( fget_string( pFile ) );
    pNPCIndex->pNameList[1] = NULL;
    return ( FALSE );
}


bool npc_load_shortdesc( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    free_string( &pNPCIndex->sShortDesc );
    pNPCIndex->sShortDesc = save_string( fget_string( pFile ) );
    return ( FALSE );
}


bool npc_load_desc( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    free_string( &pNPCIndex->sDescs[0] );
    free_string( &pNPCIndex->sDescs[1] );
    free_string( &pNPCIndex->sDescs[2] );
    free_string( &pNPCIndex->sDescs[3] );
    free_string( &pNPCIndex->sDescs[4] );
    pNPCIndex->sDescs[0] = save_string( fget_string( pFile ) );
    pNPCIndex->sDescs[1] = save_string( pNPCIndex->sDescs[0] );
    pNPCIndex->sDescs[2] = save_string( pNPCIndex->sDescs[0] );
    pNPCIndex->sDescs[3] = save_string( pNPCIndex->sDescs[0] );
    pNPCIndex->sDescs[4] = save_string( pNPCIndex->sDescs[0] );
    return ( FALSE );
}


bool npc_load_desc1( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    free_string( &pNPCIndex->sDescs[0] );
    pNPCIndex->sDescs[0] = save_string( fget_string( pFile ) );
    return ( FALSE );
}


bool npc_load_desc2( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    free_string( &pNPCIndex->sDescs[1] );
    pNPCIndex->sDescs[1] = save_string( fget_string( pFile ) );
    return ( FALSE );
}


bool npc_load_desc3( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    free_string( &pNPCIndex->sDescs[2] );
    pNPCIndex->sDescs[2] = save_string( fget_string( pFile ) );
    return ( FALSE );
}


bool npc_load_desc4( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    free_string( &pNPCIndex->sDescs[3] );
    pNPCIndex->sDescs[3] = save_string( fget_string( pFile ) );
    return ( FALSE );
}


bool npc_load_desc5( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    free_string( &pNPCIndex->sDescs[4] );
    pNPCIndex->sDescs[4] = save_string( fget_string( pFile ) );
    return ( FALSE );
}


bool npc_load_longdesc( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    char cBuf[MAX_INPUT];
    char *pString;
    char *pBuf;
    bool bWarn           = FALSE;

    pString              = fget_string( pFile );
    pBuf                 = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf             = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf         = remove_char_2( pBuf );

        if ( str_compare( cBuf, "FORMAT" ) == TRUE )
            pString      = format_string( pString );
        else
        {
            sap_warning( "NPC %d: Unknown string flag `%s'.",
              pNPCIndex->iNumber, cBuf );
            bWarn        = TRUE;
        }
    }

    free_string( &pNPCIndex->sLongDesc );
    pNPCIndex->sLongDesc = save_string( pString );
    return ( bWarn );
}


bool npc_load_npcflags( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    char cBuf[MAX_STRING];
    char *pBuf;
    int i;
    bool bWarn                        = FALSE;

    pBuf                              = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf                      = remove_char_2( pBuf );

        for ( i = 0; snNPCFlagsTable[i].pName[0] != '\0'; i++ )
        {
            if ( str_compare( snNPCFlagsTable[i].pName, cBuf ) == TRUE )
            {
                SET_FLAG( pNPCIndex->fNPCFlags,
                  snNPCFlagsTable[i].iNumber );
                break;
            }
        }

        if ( snNPCFlagsTable[i].pName[0] == '\0' )
        {
            sap_warning( "NPC %d: Unknown NPC flag `%s'.",
              pNPCIndex->iNumber, cBuf );
            bWarn                     = TRUE;
        }
    }

    return ( bWarn );
}


bool npc_load_partflags( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    char cBuf[MAX_STRING];
    char *pBuf;
    int i;
    bool bWarn                        = FALSE;

    pBuf                              = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf                      = remove_char_2( pBuf );

        for ( i = 0; snPartFlagsTable[i].pName[0] != '\0'; i++ )
        {
            if ( str_compare( snPartFlagsTable[i].pName, cBuf ) == TRUE )
            {
                SET_FLAG( pNPCIndex->fPartFlags,
                  snPartFlagsTable[i].iNumber );
                break;
            }
        }

        if ( snPartFlagsTable[i].pName[0] == '\0' )
        {
            sap_warning( "NPC %d: Unknown part flag `%s'.",
              pNPCIndex->iNumber, cBuf );
            bWarn                     = TRUE;
        }
    }

    return ( bWarn );
}


bool npc_load_actflags( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    char cBuf[MAX_STRING];
    char *pBuf;
    int i;
    bool bWarn                        = FALSE;

    pBuf                              = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf                      = remove_char_2( pBuf );

        for ( i = 0; snActFlagsTable[i].pName[0] != '\0'; i++ )
        {
            if ( str_compare( snActFlagsTable[i].pName, cBuf ) == TRUE )
            {
                SET_FLAG( pNPCIndex->fActFlags,
                  snActFlagsTable[i].iNumber );
                break;
            }
        }

        if ( snActFlagsTable[i].pName[0] == '\0' )
        {
            sap_warning( "NPC %d: Unknown action flag `%s'.",
              pNPCIndex->iNumber, cBuf );
            bWarn                     = TRUE;
        }
    }

    return ( bWarn );
}


bool npc_load_race( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    char *pRace;
    int i;

    if ( ( pNPCIndex->iRace = get_race_number(
      ( pRace = fget_word_2( pFile ) ) ) ) == 0 )
    {
        sap_warning( "NPC %d: Unknown race `%s'.", pNPCIndex->iNumber,
          pRace );
        pNPCIndex->iRace          = rRaceTable[0].iNumber;
        return ( TRUE );
    }

    for ( i = 0; rRaceTable[i].pName[0] != '\0'; i++ )
    {
        if ( rRaceTable[i].iNumber == pNPCIndex->iRace )
        {
            pNPCIndex->fActFlags |= rRaceTable[i].fActFlags;
            break;
        }
    }

    return ( FALSE );
}


bool npc_load_sex( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    char *pSex;

    if ( ( pNPCIndex->iSex = get_sex_number(
      ( pSex = fget_word_2( pFile ) ) ) ) == 0 )
    {
        sap_warning( "NPC %d: Unknown sex `%s'.",
          pNPCIndex->iNumber, pSex );
        pNPCIndex->iSex = snSexTable[0].iNumber;
        return ( TRUE );
     }

     return ( FALSE );
}


bool npc_load_haircolor( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    char *pHairColor;

    if ( ( pNPCIndex->iHairColor = get_hair_color_number(
      ( pHairColor = fget_word_2( pFile ) ) ) ) == 0 )
    {
        sap_warning( "NPC %d: Unknown hair color `%s'.",
          pNPCIndex->iNumber, pHairColor );
        pNPCIndex->iHairColor = snHairColorTable[0].iNumber;
        return ( TRUE );
    }

    return ( FALSE );
}


bool npc_load_eyecolor( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    char *pEyeColor;

    if ( ( pNPCIndex->iEyeColor = get_hair_color_number(
      ( pEyeColor = fget_word_2( pFile ) ) ) ) == 0 )
    {
        sap_warning( "NPC %d: Unknown eye color `%s'.",
          pNPCIndex->iNumber, pEyeColor );
        pNPCIndex->iEyeColor = snEyeColorTable[0].iNumber;
        return ( TRUE );
    }

    return ( FALSE );
}


bool npc_load_height( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    pNPCIndex->iHeight     = fget_number_2( pFile );
    return ( FALSE );
}


bool npc_load_weight( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    pNPCIndex->iWeight     = fget_number_2( pFile );
    return ( FALSE );
}


bool npc_load_maxcarry( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    pNPCIndex->iMaxCarry     = fget_number_2( pFile );

    if ( pNPCIndex->iMaxCarry < 0 )
    {
        sap_warning( "NPC %d: Max carry weight less then 0.",
          pNPCIndex->iNumber );
        pNPCIndex->iMaxCarry = 1;
        return ( TRUE );
    }

    return ( FALSE );
}


bool npc_load_level( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    pNPCIndex->iLevel     = fget_number_2( pFile );

    if ( pNPCIndex->iLevel > MAX_PLAYER_LEVEL )
    {
        sap_warning( "NPC %d: Level greater then %d.",
          pNPCIndex->iNumber, MAX_PLAYER_LEVEL );
        pNPCIndex->iLevel = MAX_PLAYER_LEVEL;
        return ( TRUE );
    }

    if ( pNPCIndex->iLevel < 1 )
    {
        sap_warning( "NPC %d: Level less then 1.", pNPCIndex->iNumber );
        pNPCIndex->iLevel = 1;
        return ( TRUE );
    }

    return ( FALSE );
}


bool npc_load_experience( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    bool bWarn             = FALSE;

    pNPCIndex->iExp[0]     = fget_number_2( pFile );

    if ( pNPCIndex->iExp[0] > 100 )
    {
        sap_warning( "NPC %d: Number of dice greater then 100.",
          pNPCIndex->iNumber );
        pNPCIndex->iExp[0] = 100;
        bWarn              = TRUE;
    }

    if ( pNPCIndex->iExp[0] < 0 )
    {
        sap_warning( "NPC %d: Number of dice less then 0.",
          pNPCIndex->iNumber );
        pNPCIndex->iExp[0] = 0;
        bWarn              = TRUE;
    }

    if ( fget_letter( pFile ) != 'd' )
    {
        sap_warning( "NPC %d: Incomplete dice.", pNPCIndex->iNumber );
        bWarn              = TRUE;
        goto end;
    }

    pNPCIndex->iExp[1]     = fget_number_2( pFile );

    if ( pNPCIndex->iExp[1] > 100 )
    {
        sap_warning( "NPC %d: Dice sides greater then 100.",
          pNPCIndex->iNumber );
        pNPCIndex->iExp[1] = 100;
        bWarn              = TRUE;
    }

    if ( pNPCIndex->iExp[1] < 0 )
    {
        sap_warning( "NPC %d: Dice sides less then 0.",
          pNPCIndex->iNumber );
        pNPCIndex->iExp[1] = 0;
        bWarn              = TRUE;
    }

    if ( fget_letter( pFile ) != '+' )
    {
        sap_warning( "NPC %d: Incomplete dice.", pNPCIndex->iNumber );
        bWarn              = TRUE;
        goto end;
    }

    pNPCIndex->iExp[2]     = fget_number_2( pFile );

    if ( pNPCIndex->iExp[2] > 1000 )
    {
        sap_warning( "NPC %d: Dice modifier greater then 1000.",
          pNPCIndex->iNumber );
        pNPCIndex->iExp[2] = 100;
        bWarn              = TRUE;
    }

    if ( pNPCIndex->iExp[2] < 0 )
    {
        sap_warning( "NPC %d: Dice modifier less then 0.",
          pNPCIndex->iNumber );
        pNPCIndex->iExp[2] = 0;
        bWarn              = TRUE;
    }

end:
    return ( bWarn );
}


bool npc_load_alignment( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    pNPCIndex->iAlignment     = fget_number_2( pFile );

    if ( pNPCIndex->iAlignment > 1000 )
    {
        sap_warning( "NPC %d: Level greater then 1000.",
          pNPCIndex->iNumber );
        pNPCIndex->iAlignment = 1000;
        return ( TRUE );
    }

    if ( pNPCIndex->iAlignment < -1000 )
    {
        sap_warning( "NPC %d: Level less then -1000.",
          pNPCIndex->iNumber );
        pNPCIndex->iAlignment = -1000;
        return ( TRUE );
    }

    return ( FALSE );
}


bool npc_load_position( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    char *pBuf;
    int i;

    pBuf                         = fget_word_2( pFile );

    for ( i = 0; snPositionTable[i].pName[0] != '\0'; i++ )
    {
        if ( str_compare( snPositionTable[i].pName, pBuf ) == TRUE )
        {
            pNPCIndex->iPosition = snPositionTable[i].iNumber;
            return ( FALSE );
        }
    }

    sap_warning( "NPC %d: Unknown position `%s'.", pNPCIndex->iNumber,
      pBuf );
    pNPCIndex->iPosition         = NUMBER_POSITION_STANDING;
    return ( TRUE );
}


bool npc_load_gold( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    pNPCIndex->iGold = fget_number_2( pFile );
    return ( FALSE );
}


bool npc_load_wander( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    pNPCIndex->iWander     = fget_number_2( pFile );

    if ( pNPCIndex->iWander > 100 )
    {
        sap_warning( "NPC %d: Percent chance of wander greater then 100.",
          pNPCIndex->iNumber );
        pNPCIndex->iWander = 100;
        return ( TRUE );
    }

    if ( pNPCIndex->iWander < 0 )
    {
        sap_warning( "NPC %d: Percent chance of wander less then 0.",
          pNPCIndex->iNumber );
        pNPCIndex->iWander = 0;
        return ( TRUE );
    }

    return ( FALSE );
}


bool npc_load_stats( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    char cBuf[MAX_INPUT];
    char *pBuf;
    char c;
    int iNumber;
    bool bWarn          = FALSE;

    pBuf                = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf            = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf        = remove_char_2( pBuf );

        if ( str_compare( cBuf, "STR" ) == TRUE )
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "dD\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Number of dice greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Number of dice less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatStr[0] = iNumber;

            if ( LOWER( ( c = next_char( pBuf ) ) ) != 'd' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, c, "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Dice sides greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice sides less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatStr[1] = iNumber;

            if ( next_char( pBuf ) != '+' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, '+', "\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 2000 )
            {
                sap_warning( "NPC %d: Dice modifier greater then 2000.",
                  pNPCIndex->iNumber );
                iNumber = 2000;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice modifier less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatStr[2] = iNumber;
        }
        else if ( str_compare( cBuf, "INT" ) == TRUE )
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "dD\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Number of dice greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Number of dice less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatInt[0] = iNumber;

            if ( LOWER( ( c = next_char( pBuf ) ) ) != 'd' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, c, "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Dice sides greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice sides less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatInt[1] = iNumber;

            if ( next_char( pBuf ) != '+' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, '+', "\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 2000 )
            {
                sap_warning( "NPC %d: Dice modifier greater then 2000.",
                  pNPCIndex->iNumber );
                iNumber = 2000;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice modifier less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatInt[2] = iNumber;
        }
        else if ( str_compare( cBuf, "WIS" ) == TRUE )
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "dD\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Number of dice greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Number of dice less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatWis[0] = iNumber;

            if ( LOWER( ( c = next_char( pBuf ) ) ) != 'd' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, c, "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Dice sides greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice sides less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatWis[1] = iNumber;

            if ( next_char( pBuf ) != '+' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, '+', "\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 2000 )
            {
                sap_warning( "NPC %d: Dice modifier greater then 2000.",
                  pNPCIndex->iNumber );
                iNumber = 2000;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice modifier less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatWis[2] = iNumber;
        }
        else if ( str_compare( cBuf, "DEX" ) == TRUE )
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "dD\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Number of dice greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Number of dice less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatDex[0] = iNumber;

            if ( LOWER( ( c = next_char( pBuf ) ) ) != 'd' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, c, "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Dice sides greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice sides less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatDex[1] = iNumber;

            if ( next_char( pBuf ) != '+' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, '+', "\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 2000 )
            {
                sap_warning( "NPC %d: Dice modifier greater then 2000.",
                  pNPCIndex->iNumber );
                iNumber = 2000;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice modifier less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatDex[2] = iNumber;
        }
        else if ( str_compare( cBuf, "CON" ) == TRUE )
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "dD\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Number of dice greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Number of dice less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatCon[0] = iNumber;

            if ( LOWER( ( c = next_char( pBuf ) ) ) != 'd' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, c, "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Dice sides greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice sides less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatCon[1] = iNumber;

            if ( next_char( pBuf ) != '+' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, '+', "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 2000 )
            {
                sap_warning( "NPC %d: Dice modifier greater then 2000.",
                  pNPCIndex->iNumber );
                iNumber = 2000;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice modifier less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatCon[2] = iNumber;
        }
        else if ( str_compare( cBuf, "CHA" ) == TRUE )
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "dD\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Number of dice greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Number of dice less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatCha[0] = iNumber;

            if ( LOWER( ( c = next_char( pBuf ) ) ) != 'd' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, c, "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Dice sides greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice sides less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatCha[1] = iNumber;

            if ( next_char( pBuf ) != '+' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, '+', "\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 2000 )
            {
                sap_warning( "NPC %d: Dice modifier greater then 2000.",
                  pNPCIndex->iNumber );
                iNumber = 2000;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice modifier less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatCha[2] = iNumber;
        }
        else if ( str_compare( cBuf, "LUC" ) == TRUE )
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "dD\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Number of dice greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Number of dice less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatLuc[0] = iNumber;

            if ( LOWER( ( c = next_char( pBuf ) ) ) != 'd' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, c, "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Dice sides greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice sides less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatLuc[1] = iNumber;

            if ( next_char( pBuf ) != '+' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, '+', "\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 2000 )
            {
                sap_warning( "NPC %d: Dice modifier greater then 2000.",
                  pNPCIndex->iNumber );
                iNumber = 2000;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice modifier less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatLuc[2] = iNumber;
        }
        else if ( str_compare( cBuf, "HP" ) == TRUE )
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "dD\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Number of dice greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Number of dice less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatHP[0]  = iNumber;

            if ( LOWER( ( c = next_char( pBuf ) ) ) != 'd' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, c, "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Dice sides greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice sides less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatHP[1]  = iNumber;

            if ( next_char( pBuf ) != '+' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, '+', "\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 2000 )
            {
                sap_warning( "NPC %d: Dice modifier greater then 2000.",
                  pNPCIndex->iNumber );
                iNumber = 2000;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice modifier less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatHP[2]  = iNumber;
        }
        else if ( str_compare( cBuf, "MP" ) == TRUE )
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "dD\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Number of dice greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Number of dice less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatMP[0]  = iNumber;

            if ( LOWER( ( c = next_char( pBuf ) ) ) != 'd' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, c, "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Dice sides greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice sides less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatMP[1]  = iNumber;

            if ( next_char( pBuf ) != '+' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, '+', "\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 2000 )
            {
                sap_warning( "NPC %d: Dice modifier greater then 2000.",
                  pNPCIndex->iNumber );
                iNumber = 2000;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice modifier less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatMP[2]  = iNumber;
        }
        else if ( str_compare( cBuf, "MV" ) == TRUE )
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "dD\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Number of dice greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Number of dice less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatMV[0]  = iNumber;

            if ( LOWER( ( c = next_char( pBuf ) ) ) != 'd' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, c, "+\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 100 )
            {
                sap_warning( "NPC %d: Dice sides greater then 100.",
                  pNPCIndex->iNumber );
                iNumber = 100;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice sides less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatMV[1]  = iNumber;

            if ( next_char( pBuf ) != '+' )
            {
                sap_warning( "NPC %d: Incomplete dice.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                continue;
            }

            pBuf        = edit_str( pBuf, cBuf, '+', "\n\r\t " );
            iNumber     = atoi( cBuf );

            if ( iNumber > 2000 )
            {
                sap_warning( "NPC %d: Dice modifier greater then 2000.",
                  pNPCIndex->iNumber );
                iNumber = 2000;
                bWarn   = TRUE;
            }

            if ( iNumber < 0 )
            {
                sap_warning( "NPC %d: Dice modifier less then 0.",
                  pNPCIndex->iNumber );
                iNumber = 0;
                bWarn   = TRUE;
            }

            pNPCIndex->VarStats.iStatMV[2]  = iNumber;
        }
        else
        {
            pBuf        = edit_str( pBuf, cBuf, ' ', "\n\r\t " );
            sap_warning( "NPC %d: Unknown stat `%s'.",
              pNPCIndex->iNumber, cBuf );
            bWarn                       = TRUE;
        }
    }

    return ( bWarn );
}


bool npc_load_program( NPC_INDEX_DATA *pNPCIndex, FILE *pFile )
{
    PROGRAM_DATA *pProgram;
    SCRIPT_DATA *pScript;
    TRIGGER_DATA *pTrigger;
    TRIGGER_ARG_DATA *pTriggerArg;
    char *pStr    = fget_string_3( pFile, '{', '}' );
    char *pBak    = pStr;
    char cBuf[MAX_STRING];
    char cBuf2[MAX_STRING];
    char *pBuf;
    char c;
    int i;
    bool bWarn    = FALSE;

    pProgram      = alloc_mem( sizeof( *pProgram ) );

    pNPCIndex->pProgram = pProgram;

    while ( next_char( pStr ) != '\0' )
    {
        pStr      = edit_str( pStr, cBuf, ' ', "\n\r\t " );

        if ( str_compare( cBuf, "TRIGGER" ) == TRUE )
        {
            pStr      = edit_str( pStr, cBuf, ' ', "\n\r\t " );

            for ( pScript = pProgram->pScripts; pScript != NULL;
              pScript = pScript->pNext )
            {
                if ( str_compare( pScript->pName, cBuf ) == TRUE )
                    break;
            }

            if ( pScript != NULL )
            {
                sap_error(
                  "NPC %d: Multiple blocks with the name `%s' in script.",
                  pNPCIndex->iNumber, cBuf );
                bWarn = TRUE;
                goto end;
            }

            pScript               = alloc_mem( sizeof( *pScript ) );
            pScript->pName        = str_dup( cBuf );

            pStr      = edit_str( pStr, cBuf, ' ', "\n\r\t " );

            if ( str_compare( cBuf, "enabled" ) == TRUE )
                pScript->bDisabled = FALSE;
            else if ( str_compare( cBuf, "disabled" ) == TRUE )
                pScript->bDisabled = TRUE;
            else
            {
                str_free( pScript->pName );
                free_mem( (void **) &pScript );
                sap_error( "NPC %d: Unknown enabled flag in script.",
                  pNPCIndex->iNumber );
                bWarn = TRUE;
                goto end;
            }

            do
            {
                pStr  = edit_str( pStr, cBuf, ' ', "(\n\r\t " );

                if ( next_char( pStr ) != '(' )
                {
                    TRIGGER_DATA *pTriggerNext;
                    TRIGGER_ARG_DATA *pTriggerArgNext;

                    for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                      pTrigger = pTriggerNext )
                    {
                        pTriggerNext        = pTrigger->pNext;

                        for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                          pTriggerArg = pTriggerArgNext )
                        {
                            pTriggerArgNext = pTriggerArg->pNext;

                            str_free( pTriggerArg->pArg );
                            free_mem( (void **) &pTriggerArg );
                        }

                        free_mem( (void **) &pTrigger );
                    }

                    str_free( pScript->pName );
                    free_mem( (void **) &pScript );
                    sap_error(
                      "NPC %d: Trigger missing `(' symbol in script.",
                      pNPCIndex->iNumber );
                    bWarn = TRUE;
                    goto end;
                }

                for ( i = 0; snNPCScriptTriggerTable[i].pName[0] != '\0';
                  i++ )
                {
                    if ( str_compare( cBuf,
                      snNPCScriptTriggerTable[i].pName ) == TRUE )
                        break;
                }

                if ( snNPCScriptTriggerTable[i].pName[0] == '\0' )
                {
                    TRIGGER_DATA *pTriggerNext;
                    TRIGGER_ARG_DATA *pTriggerArgNext;

                    for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                      pTrigger = pTriggerNext )
                    {
                        pTriggerNext        = pTrigger->pNext;

                        for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                          pTriggerArg = pTriggerArgNext )
                        {
                            pTriggerArgNext = pTriggerArg->pNext;

                            str_free( pTriggerArg->pArg );
                            free_mem( (void **) &pTriggerArg );
                        }

                        free_mem( (void **) &pTrigger );
                    }

                    str_free( pScript->pName );
                    free_mem( (void **) &pScript );
                    sap_error(
                      "NPC %d: Unknown trigger type `%s' in script.",
                      pNPCIndex->iNumber, cBuf );
                    bWarn = TRUE;
                    goto end;
                }

                pTrigger              = alloc_mem( sizeof( *pTrigger ) );
                pTrigger->iTrigger    = snNPCScriptTriggerTable[i].iNumber;
                pStr                  = edit_str( pStr, cBuf, '(', ")" );
                pBuf                  = remove_spaces( cBuf );

                if ( next_char( pStr ) != ')' )
                {
                    TRIGGER_DATA *pTriggerNext;
                    TRIGGER_ARG_DATA *pTriggerArgNext;

                    free_mem( (void **) &pTrigger );

                    for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                      pTrigger = pTriggerNext )
                    {
                        pTriggerNext        = pTrigger->pNext;

                        for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                          pTriggerArg = pTriggerArgNext )
                        {
                            pTriggerArgNext = pTriggerArg->pNext;

                            str_free( pTriggerArg->pArg );
                            free_mem( (void **) &pTriggerArg );
                        }

                        free_mem( (void **) &pTrigger );
                    }

                    str_free( pScript->pName );
                    free_mem( (void **) &pScript );
                    sap_error(
                      "NPC %d: Trigger missing `)' symbol in script.",
                      pNPCIndex->iNumber );
                    bWarn = TRUE;
                    goto end;
                }

                switch ( pTrigger->iTrigger )
                {
                  case NUMBER_NPC_TRIGGER_CREATED:
                      break;

                  case NUMBER_NPC_TRIGGER_RANDOM :
                      if ( is_number( pBuf ) != TRUE )
                      {
                          TRIGGER_DATA *pTriggerNext;
                          TRIGGER_ARG_DATA *pTriggerArgNext;

                          free_mem( (void **) &pTrigger );

                          for ( pTrigger = pScript->pTriggers; pTrigger;
                            pTrigger = pTriggerNext )
                          {
                              pTriggerNext        = pTrigger->pNext;

                              for ( pTriggerArg = pTrigger->pArgs;
                                pTriggerArg; pTriggerArg = pTriggerArgNext )
                              {
                                  pTriggerArgNext = pTriggerArg->pNext;

                                  str_free( pTriggerArg->pArg );
                                  free_mem( (void **) &pTriggerArg );
                              }

                              free_mem( (void **) &pTrigger );
                          }

                          str_free( pScript->pName );
                          free_mem( (void **) &pScript );
                          sap_warning( "NPC %d: Non-number argument for "
                            "trigger in script.", pNPCIndex->iNumber );
                          bWarn = TRUE;
                          goto end;
                      }

                      pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );
                      pTriggerArg->pArg = alloc_mem( 1 );
                      *( (intt *) pTriggerArg->pArg ) = (intt) atoi( pBuf );

                      pTrigger->pArgs                 = pTriggerArg;
                      break;

                  case NUMBER_NPC_TRIGGER_MESSAGE:
                  case NUMBER_NPC_TRIGGER_EMOTE  :
                  case NUMBER_NPC_TRIGGER_SAY    :
                  case NUMBER_NPC_TRIGGER_TELL   :
                  case NUMBER_NPC_TRIGGER_YELL   :
                      if ( str_compare( pBuf, "all" ) == TRUE )
                      {
                          pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );

                          pTriggerArg->iType          = 1;
                          pTriggerArg->pArg           = EMPTY_STRING;
                          pTrigger->pArgs             = pTriggerArg;
                          break;
                      }

                      while ( *pBuf != '\0' )
                      {
                          pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );

                          pBuf = edit_str( pBuf, cBuf2, ' ', "\n\r\t " );

                          if ( next_char( pBuf ) == '"' )
                          {
                              if ( str_compare( cBuf2, "exact" ) == TRUE )
                                  pTriggerArg->iType = 2;
                              else if ( str_compare( cBuf2, "prefix" )
                                == TRUE )
                                  pTriggerArg->iType = 3;
                              else if ( str_compare( cBuf2, "infix" )
                                == TRUE )
                                  pTriggerArg->iType = 4;
                              else if ( str_compare( cBuf2, "suffix" )
                                == TRUE )
                                  pTriggerArg->iType = 5;
                              else
                              {
                                  sap_warning( "NPC %d: Unknown comparison "
                                    "type for trigger argument in script.",
                                    pNPCIndex->iNumber );
                                  bWarn = TRUE;
                                  pTriggerArg->iType = 2;
                                  continue;
                              }

                              pBuf           = make_string( pBuf, cBuf2 );
                              pBuf           = remove_char_2( pBuf );

                              if ( cBuf2[0] == '\0' )
                              {
                                  sap_warning( "NPC %d: Empty string for "
                                    "trigger argument in script.",
                                    pNPCIndex->iNumber );
                                  bWarn = TRUE;
                                  pTriggerArg->pArg   = EMPTY_STRING;
                                  continue;
                              }

                              pTriggerArg->pArg  = str_dup( cBuf2 );
                          }

                          if ( ( c = next_char( pBuf ) ) == ',' )
                              pBuf               = remove_char_2( pBuf );
                          else if ( c != '\0' )
                          {
                              sap_warning( "NPC %d: Missing `,' for "
                                "trigger argument list in script.",
                                pNPCIndex->iNumber );
                              bWarn = TRUE;
                          }

                          pTriggerArg->pNext     = pTrigger->pArgs;
                          pTrigger->pArgs        = pTriggerArg;
                      }

                      break;

                  default                        :
                      pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );

                      pTriggerArg->pArg          = str_dup( pBuf );
                      pTrigger->pArgs            = pTriggerArg;
                      break;
                }

                pStr                  = remove_char_2( pStr );

                pTrigger->pNext       = pScript->pTriggers;
                pScript->pTriggers    = pTrigger;
            }
            while ( ( c = next_char( pStr ) ) != '{' && c != '\0' );

            if ( next_char( pStr ) != '{' )
            {
                TRIGGER_DATA *pTriggerNext;
                TRIGGER_ARG_DATA *pTriggerArgNext;

                for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                  pTrigger = pTriggerNext )
                {
                    pTriggerNext        = pTrigger->pNext;

                    for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                      pTriggerArg = pTriggerArgNext )
                    {
                        pTriggerArgNext = pTriggerArg->pNext;

                        str_free( pTriggerArg->pArg );
                        free_mem( (void **) &pTriggerArg );
                    }

                    free_mem( (void **) &pTrigger );
                }

                str_free( pScript->pName );
                free_mem( (void **) &pScript );
                sap_error(
                  "NPC %d: Trigger missing `{' symbol in script.",
                  pNPCIndex->iNumber );
                bWarn = TRUE;
                break;
            }

            pStr             = edit_str_plus( pStr, cBuf, '{', '}' );

            if ( next_char( pStr ) != '}' )
            {
                TRIGGER_DATA *pTriggerNext;
                TRIGGER_ARG_DATA *pTriggerArgNext;

                for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                  pTrigger = pTriggerNext )
                {
                    pTriggerNext        = pTrigger->pNext;

                    for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                      pTriggerArg = pTriggerArgNext )
                    {
                        pTriggerArgNext = pTriggerArg->pNext;

                        str_free( pTriggerArg->pArg );
                        free_mem( (void **) &pTriggerArg );
                    }

                    free_mem( (void **) &pTrigger );
                }

                str_free( pScript->pName );
                free_mem( (void **) &pScript );
                sap_error(
                  "NPC %d: Trigger missing `}' symbol in script.",
                  pNPCIndex->iNumber );
                bWarn = TRUE;
                break;
            }

            pStr             = remove_char_2( pStr );
            pScript->pScript = alloc_mem( ( i = npc_script_translate(
                                 pScript, cBuf ) ) );
            memcpy( pScript->pScript, cBuf, i );
            pScript->iCodeSize  = i;

            pScript->pNext      = pProgram->pScripts;
            pProgram->pScripts  = pScript;
        }
        else if ( str_compare( cBuf, "USES" ) == TRUE )
        {
            GENERIC_DATA *pGen;
            QUEST_DATA *pQuestData;
            char *pBuf2;
            char c;

            pStr = edit_str( pStr, cBuf, ' ', ";" );

            if ( *pStr != ';' )
            {
                sap_error(
                  "NPC %d: Syntax error in script quest data reference.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                goto end;
            }

            pStr++;
            pBuf2       = cBuf;

            do
            {
                pBuf2     = edit_str( pBuf2, cBuf2, ' ', ",\n\r\t " );

                if ( ( c = next_char( pBuf2 ) ) != ',' && c != '\0' )
                {
                    sap_error( "NPC %d: "
                      "Syntax error in script quest data reference.",
                      pNPCIndex->iNumber );
                    bWarn   = TRUE;
                    goto end;
                }
                else if ( c == ',' )
                    pBuf2 = remove_char_2( pBuf2 );

                for ( pQuestData = pQuestDataList; pQuestData != NULL;
                  pQuestData = pQuestData->pNext )
                {
                    if ( strcmp( pQuestData->sName, cBuf2 ) == 0 )
                    {
                        for ( pGen = pProgram->pQuestDataList; pGen;
                          pGen = pGen->pNext )
                        {
                            if ( pGen->pData == pQuestData )
                                break;
                        }

                        if ( pGen != NULL )
                        {
                            sap_warning(
                              "NPC %d: Multiply referenced quest data.",
                              pNPCIndex->iNumber );
                            bWarn   = TRUE;
                            break;
                        }

                        pGen        = alloc_mem( sizeof( *pGen ) );
                        pGen->pData = pQuestData;

                        pGen->pNext = pProgram->pQuestDataList;
                        pProgram->pQuestDataList = pGen;
                        break;
                    }
                }
            }
            while ( next_char( pBuf2 ) != '\0' );
        }
        else
        {
            QUEST_VAR_DATA *pVar;

            pVar        = alloc_mem( sizeof( *pVar ) );

            if ( str_compare( cBuf, "number" ) == TRUE )
                pVar->iType = NUMBER_VAR_NUMBER;
            else if ( str_compare( cBuf, "string" ) == TRUE )
                pVar->iType = NUMBER_VAR_STRING;
            else if ( str_compare( cBuf, "character_pointer" ) == TRUE )
                pVar->iType = NUMBER_VAR_POINTER_CHAR;
            else if ( str_compare( cBuf, "object_pointer" ) == TRUE )
                pVar->iType = NUMBER_VAR_POINTER_OBJ;
            else if ( str_compare( cBuf, "room_pointer" ) == TRUE )
                pVar->iType = NUMBER_VAR_POINTER_ROOM;
            else
            {
                free_mem( (void **) &pVar );
                sap_error( "NPC %d: Unknown keyword `%s' in script.",
                  pNPCIndex->iNumber, cBuf );
                bWarn   = TRUE;
                break;
            }

            pStr        = edit_str( pStr, cBuf, ' ', ";\n\r\t " );

            if ( next_char( pStr ) != ';' )
            {
                free_mem( (void **) &pVar );
                sap_error(
                  "NPC %d: Syntax error in script variable declaration.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                goto end;
            }

            pStr        = remove_char_2( pStr );

            if ( cBuf[0] == '\0' || ( !isalpha( cBuf[0] )
              && cBuf[0] != '_' ) )
            {
                free_mem( (void **) &pVar );
                sap_error( "NPC %d: Illegal name for script variable.",
                  pNPCIndex->iNumber );
                bWarn   = TRUE;
                goto end;
            }

            for ( i = 0; cBuf[i] != '\0'; i++ )
            {
                if ( !isalnum( cBuf[i] ) && cBuf[i] != '_' )
                {
                    free_mem( (void **) &pVar );
                    sap_error( "NPC %d: Illegal name for script variable.",
                      pNPCIndex->iNumber );
                    bWarn = TRUE;
                    goto end;
                }
            }

            pVar->sName = save_string( cBuf );

            if ( pVar->iType == NUMBER_VAR_STRING )
                pVar->uData.s    = EMPTY_STRING;

            pVar->pNext          = pProgram->pQuestVars;
            pProgram->pQuestVars = pVar;
        }
    }

end:
    if ( pBak != EMPTY_STRING )
        free_mem( (void **) &pBak );

    return ( bWarn );
}


bool obj_load_inherit( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    pObjIndex->iInherit = fget_number_2( pFile );

    if ( pObjIndex->iInherit <= 5
      || pObjIndex->iInherit > MAX_INDEX_NUMBER )
        sap_fatal( "Object %d: Illegal object number `%d' for inherit.",
          pObjIndex->iNumber, pObjIndex->iInherit );

    return ( FALSE );
}


bool obj_load_imagefilename( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    return ( FALSE );
}


bool obj_load_names( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    int i;

    for ( i = 0; pObjIndex->pNameList[i] != NULL; i++ )
        free_string( &pObjIndex->pNameList[i] );

    free_mem( (void **) &pObjIndex->pNameList );
    pObjIndex->pNameList    = alloc_mem( ( sizeof( string ) * 2 ) );
    pObjIndex->pNameList[0] = save_string( fget_string( pFile ) );
    pObjIndex->pNameList[1] = NULL;
    return ( FALSE );
}


bool obj_load_shortdesc( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    free_string( &pObjIndex->sShortDesc );
    pObjIndex->sShortDesc = save_string( fget_string( pFile ) );
    return ( FALSE );
}


bool obj_load_desc( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    free_string( &pObjIndex->sDesc );
    pObjIndex->sDesc = save_string( fget_string( pFile ) );
    return ( FALSE );
}


bool obj_load_longdesc( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    char cBuf[MAX_INPUT];
    char *pString;
    char *pBuf;
    bool bWarn           = FALSE;

    pString              = fget_string( pFile );
    pBuf                 = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf             = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf         = remove_char_2( pBuf );

        if ( str_compare( cBuf, "FORMAT" ) == TRUE )
            pString      = format_string( pString );
        else
        {
            sap_warning( "Object %d: Unknown string flag `%s'.",
              pObjIndex->iNumber, cBuf );
            bWarn        = TRUE;
        }
    }

    free_string( &pObjIndex->sLongDesc );
    pObjIndex->sLongDesc = save_string( pString );
    return ( bWarn );
}


bool obj_load_itemtype( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    char *pBuf                   = fget_word_2( pFile );
    int i;

    for ( i = 0; snItemTypeTable[i].pName[0] != '\0'; i++ )
    {
        if ( str_compare( snItemTypeTable[i].pName, pBuf ) == TRUE )
        {
            pObjIndex->iItemType = snItemTypeTable[i].iNumber;
            break;
        }
    }

    if ( snItemTypeTable[i].pName[0] == '\0' )
    {
        sap_error( "Object %d: Unknown item type `%s'.",
          pObjIndex->iNumber, pBuf );
        return ( TRUE );
    }

    return ( FALSE );
}


bool obj_load_objectflags( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    char cBuf[MAX_STRING];
    char *pBuf;
    int i;
    bool bWarn                        = FALSE;

    pBuf                              = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf                      = remove_char_2( pBuf );

        for ( i = 0; snObjectFlagsTable[i].pName[0] != '\0'; i++ )
        {
            if ( str_compare( snObjectFlagsTable[i].pName, cBuf )
              == TRUE )
            {
                SET_FLAG( pObjIndex->fObjFlags,
                  snObjectFlagsTable[i].iNumber );
                break;
            }
        }

        if ( snObjectFlagsTable[i].pName[0] == '\0' )
        {
            sap_warning( "Object %d: Unknown object flag `%s'.",
              pObjIndex->iNumber, cBuf );
            bWarn                     = TRUE;
        }
    }

    if ( !IS_SET( pObjIndex->fObjFlags, FLAG_OBJECT_CLOSABLE )
      && IS_SET( pObjIndex->fObjFlags, FLAG_OBJECT_CLOSED ) )
    {
        sap_warning(
          "Object %d: Closed flag set on non-closable object.",
          pObjIndex->iNumber );
        REMOVE_FLAG( pObjIndex->fObjFlags, FLAG_OBJECT_CLOSED );
        bWarn                         = TRUE;
    }

    if ( !IS_SET( pObjIndex->fObjFlags, FLAG_OBJECT_CLOSABLE )
      && IS_SET( pObjIndex->fObjFlags, FLAG_OBJECT_LOCKED ) )
    {
        sap_warning(
          "Object %d: Locked flag set on non-closable object.",
          pObjIndex->iNumber );
        REMOVE_FLAG( pObjIndex->fObjFlags, FLAG_OBJECT_LOCKED );
        bWarn                         = TRUE;
    }
    else if ( !IS_SET( pObjIndex->fObjFlags, FLAG_OBJECT_CLOSED )
      && IS_SET( pObjIndex->fObjFlags, FLAG_OBJECT_LOCKED ) )
    {
        sap_warning( "Object %d: Locked flag set on non-closed object.",
          pObjIndex->iNumber );
        REMOVE_FLAG( pObjIndex->fObjFlags, FLAG_OBJECT_LOCKED );
        bWarn                         = TRUE;
    }

    if ( bWarn == TRUE )
        return ( TRUE );
    else
        return ( FALSE );
}


bool obj_load_level( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    pObjIndex->iLevel     = fget_number_2( pFile );

    if ( pObjIndex->iLevel > MAX_PLAYER_LEVEL )
    {
        sap_error( "Object %d: Level greater then %d.",
          pObjIndex->iNumber, MAX_PLAYER_LEVEL );
        pObjIndex->iLevel = MAX_PLAYER_LEVEL;
        return ( TRUE );
    }

    if ( pObjIndex->iLevel < 1 )
    {
        sap_error( "Object %d: Level less then 1.", pObjIndex->iNumber );
        pObjIndex->iLevel = 1;
        return ( TRUE );
    }

    return ( FALSE );
}


bool obj_load_weight( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    pObjIndex->iWeight     = fget_number_2( pFile );

    if ( pObjIndex->iLevel > 999 )
    {
        sap_error( "Object %d: Weight greater then 999.",
          pObjIndex->iNumber );
        pObjIndex->iWeight = 999;
        return ( TRUE );
    }

    if ( pObjIndex->iLevel < 0 )
    {
        sap_error( "Object %d: Weight less then 0.",
          pObjIndex->iNumber );
        pObjIndex->iWeight = 1;
        return ( TRUE );
    }

    return ( FALSE );
}


bool obj_load_size( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    char *pBuf;
    int i;

    pBuf                     = fget_word_2( pFile );

    for ( i = 0; snSizeTable[i].pName[0] != '\0'; i++ )
    {
        if ( str_compare( snSizeTable[i].pName, pBuf ) == TRUE )
        {
            pObjIndex->iSize = snSizeTable[i].iNumber;
            return ( FALSE );
        }
    }

    sap_warning( "Object %d: Unknown size `%s'.", pObjIndex->iNumber,
      pBuf );
    pObjIndex->iSize         = snSizeTable[0].iNumber;
    return ( TRUE );
}


bool obj_load_cost( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    pObjIndex->iCost = fget_number_2( pFile );
    return ( FALSE );
}


bool obj_load_condition( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    pObjIndex->iCondition = fget_number_2( pFile );

    if ( pObjIndex->iCondition > 100 )
    {
        sap_warning( "Object %d: Condition greater then 100.",
          pObjIndex->iNumber );
        pObjIndex->iCondition = 100;
        return ( TRUE );
    }

    if ( pObjIndex->iCondition < 1 )
    {
        sap_warning( "Object %d: Condition less then 1.",
          pObjIndex->iNumber );
        pObjIndex->iCondition = 1;
        return ( TRUE );
    }

    return ( FALSE );
}


bool obj_load_material( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    char *pBuf;
    int i;

    pBuf                         = fget_word_2( pFile );

    for ( i = 0; snMaterialTable[i].pName[0] != '\0'; i++ )
    {
        if ( str_compare( snMaterialTable[i].pName, pBuf ) == TRUE )
        {
            pObjIndex->iMaterial = snMaterialTable[i].iNumber;
            return ( FALSE );
        }
    }

    sap_warning( "Object %d: Unknown material type `%s'.",
      pObjIndex->iNumber, pBuf );
    pObjIndex->iMaterial         = snMaterialTable[0].iNumber;
    return ( TRUE );
}


bool obj_load_values( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    char cBuf[MAX_INPUT];
    char *pBuf;
    int i                           = 0;
    bool bWarn                      = FALSE;

    pBuf                            = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        if ( i == 6 )
        {
            sap_warning( "Object %d: Too many value settings.",
              pObjIndex->iNumber );
            bWarn                   = TRUE;
            break;
        }

        pBuf = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf                    = remove_char_2( pBuf );

        if ( is_number( cBuf ) != TRUE )
        {
            sap_warning( "Object %d: Non-number as value[%d] setting.",
              pObjIndex->iNumber, ++i );
            bWarn                   = TRUE;
        }
        else
            pObjIndex->iValues[i++] = atol( cBuf );
    }

    return ( bWarn );
}


bool obj_load_stringvalue( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    char cBuf[MAX_INPUT];
    char *pString;
    char *pBuf;
    bool bWarn        = FALSE;

    pString           = fget_string( pFile );
    pBuf              = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf          = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf      = remove_char_2( pBuf );

        if ( str_compare( cBuf, "FORMAT" ) == TRUE )
            pString   = format_string( pString );
        else
        {
            sap_warning( "Object %d: Unknown string flag `%s'.",
              pObjIndex->iNumber, cBuf );
            bWarn     = TRUE;
        }
    }

    free_string( &pObjIndex->sValue );
    pObjIndex->sValue = save_string( pString );
    return ( bWarn );
}


bool obj_load_program( OBJ_INDEX_DATA *pObjIndex, FILE *pFile )
{
    PROGRAM_DATA *pProgram;
    SCRIPT_DATA *pScript;
    TRIGGER_DATA *pTrigger;
    TRIGGER_ARG_DATA *pTriggerArg;
    char *pStr    = fget_string_3( pFile, '{', '}' );
    char *pBak    = pStr;
    char cBuf[MAX_STRING];
    char cBuf2[MAX_STRING];
    char *pBuf;
    char c;
    int i;
    bool bWarn    = FALSE;

    pProgram      = alloc_mem( sizeof( *pProgram ) );

    pObjIndex->pProgram = pProgram;

    while ( next_char( pStr ) != '\0' )
    {
        pStr      = edit_str( pStr, cBuf, ' ', "\n\r\t " );

        if ( str_compare( cBuf, "TRIGGER" ) == TRUE )
        {
            pStr      = edit_str( pStr, cBuf, ' ', "\n\r\t " );

            for ( pScript = pProgram->pScripts; pScript != NULL;
              pScript = pScript->pNext )
            {
                if ( str_compare( pScript->pName, cBuf ) == TRUE )
                    break;
            }

            if ( pScript != NULL )
            {
                sap_error( "Object %d: Multiple blocks with the name "
                  "`%s' in script.", pObjIndex->iNumber, cBuf );
                bWarn = TRUE;
                goto end;
            }

            pScript               = alloc_mem( sizeof( *pScript ) );
            pScript->pName        = str_dup( cBuf );

            pStr      = edit_str( pStr, cBuf, ' ', "\n\r\t " );

            if ( str_compare( cBuf, "enabled" ) == TRUE )
                pScript->bDisabled = FALSE;
            else if ( str_compare( cBuf, "disabled" ) == TRUE )
                pScript->bDisabled = TRUE;
            else
            {
                str_free( pScript->pName );
                free_mem( (void **) &pScript );
                sap_error( "Object %d: Unknown enabled flag in script.",
                  pObjIndex->iNumber );
                bWarn = TRUE;
                goto end;
            }

            do
            {
                pStr  = edit_str( pStr, cBuf, ' ', "(\n\r\t " );

                if ( next_char( pStr ) != '(' )
                {
                    TRIGGER_DATA *pTriggerNext;
                    TRIGGER_ARG_DATA *pTriggerArgNext;

                    for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                      pTrigger = pTriggerNext )
                    {
                        pTriggerNext        = pTrigger->pNext;

                        for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                          pTriggerArg = pTriggerArgNext )
                        {
                            pTriggerArgNext = pTriggerArg->pNext;

                            str_free( pTriggerArg->pArg );
                            free_mem( (void **) &pTriggerArg );
                        }

                        free_mem( (void **) &pTrigger );
                    }

                    str_free( pScript->pName );
                    free_mem( (void **) &pScript );
                    sap_error(
                      "Object %d: Trigger missing `(' symbol in script.",
                      pObjIndex->iNumber );
                    bWarn = TRUE;
                    goto end;
                }

                for ( i = 0; snNPCScriptTriggerTable[i].pName[0] != '\0';
                  i++ )
                {
                    if ( str_compare( cBuf,
                      snNPCScriptTriggerTable[i].pName ) == TRUE )
                        break;
                }

                if ( snNPCScriptTriggerTable[i].pName[0] == '\0' )
                {
                    TRIGGER_DATA *pTriggerNext;
                    TRIGGER_ARG_DATA *pTriggerArgNext;

                    for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                      pTrigger = pTriggerNext )
                    {
                        pTriggerNext        = pTrigger->pNext;

                        for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                          pTriggerArg = pTriggerArgNext )
                        {
                            pTriggerArgNext = pTriggerArg->pNext;

                            str_free( pTriggerArg->pArg );
                            free_mem( (void **) &pTriggerArg );
                        }

                        free_mem( (void **) &pTrigger );
                    }

                    str_free( pScript->pName );
                    free_mem( (void **) &pScript );
                    sap_error(
                      "Object %d: Unknown trigger type `%s' in script.",
                      pObjIndex->iNumber, cBuf );
                    bWarn = TRUE;
                    goto end;
                }

                pTrigger              = alloc_mem( sizeof( *pTrigger ) );
                pTrigger->iTrigger    = snNPCScriptTriggerTable[i].iNumber;
                pStr                  = edit_str( pStr, cBuf, '(', ")" );
                pBuf                  = remove_spaces( cBuf );

                if ( next_char( pStr ) != ')' )
                {
                    TRIGGER_DATA *pTriggerNext;
                    TRIGGER_ARG_DATA *pTriggerArgNext;

                    free_mem( (void **) &pTrigger );

                    for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                      pTrigger = pTriggerNext )
                    {
                        pTriggerNext        = pTrigger->pNext;

                        for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                          pTriggerArg = pTriggerArgNext )
                        {
                            pTriggerArgNext = pTriggerArg->pNext;

                            str_free( pTriggerArg->pArg );
                            free_mem( (void **) &pTriggerArg );
                        }

                        free_mem( (void **) &pTrigger );
                    }

                    str_free( pScript->pName );
                    free_mem( (void **) &pScript );
                    sap_error(
                      "Object %d: Trigger missing `)' symbol in script.",
                      pObjIndex->iNumber );
                    bWarn = TRUE;
                    goto end;
                }

                switch ( pTrigger->iTrigger )
                {
                  case NUMBER_OBJ_TRIGGER_RANDOM:
                      if ( is_number( pBuf ) != TRUE )
                      {
                          TRIGGER_DATA *pTriggerNext;
                          TRIGGER_ARG_DATA *pTriggerArgNext;

                          free_mem( (void **) &pTrigger );

                          for ( pTrigger = pScript->pTriggers; pTrigger;
                            pTrigger = pTriggerNext )
                          {
                              pTriggerNext        = pTrigger->pNext;

                              for ( pTriggerArg = pTrigger->pArgs;
                                pTriggerArg; pTriggerArg = pTriggerArgNext )
                              {
                                  pTriggerArgNext = pTriggerArg->pNext;

                                  str_free( pTriggerArg->pArg );
                                  free_mem( (void **) &pTriggerArg );
                              }

                              free_mem( (void **) &pTrigger );
                          }

                          str_free( pScript->pName );
                          free_mem( (void **) &pScript );
                          sap_warning( "Object %d: Non-number argument "
                            "for trigger in script.", pObjIndex->iNumber );
                          bWarn = TRUE;
                          goto end;
                      }

                      pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );
                      pTriggerArg->pArg = alloc_mem( 1 );
                      *( (intt *) pTriggerArg->pArg ) = (intt) atoi( pBuf );

                      pTrigger->pArgs                 = pTriggerArg;
                      break;

                  case NUMBER_OBJ_TRIGGER_SAY   :
                      if ( str_compare( pBuf, "all" ) == TRUE )
                      {
                          pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );

                          pTriggerArg->iType          = 1;
                          pTriggerArg->pArg           = EMPTY_STRING;
                          pTrigger->pArgs             = pTriggerArg;
                          break;
                      }

                      while ( *pBuf != '\0' )
                      {
                          pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );

                          pBuf = edit_str( pBuf, cBuf2, ' ', "\n\r\t " );

                          if ( next_char( pBuf ) == '"' )
                          {
                              if ( str_compare( cBuf2, "exact" ) == TRUE )
                                  pTriggerArg->iType = 2;
                              else if ( str_compare( cBuf2, "prefix" )
                                == TRUE )
                                  pTriggerArg->iType = 3;
                              else if ( str_compare( cBuf2, "infix" )
                                == TRUE )
                                  pTriggerArg->iType = 4;
                              else if ( str_compare( cBuf2, "suffix" )
                                == TRUE )
                                  pTriggerArg->iType = 5;
                              else
                              {
                                  sap_warning(
                                    "Object %d: Unknown comparison type "
                                    "for trigger argument in script.",
                                    pObjIndex->iNumber );
                                  bWarn = TRUE;
                                  pTriggerArg->iType = 2;
                                  continue;
                              }

                              pBuf           = make_string( pBuf, cBuf2 );
                              pBuf           = remove_char_2( pBuf );

                              if ( cBuf2[0] == '\0' )
                              {
                                  sap_warning( "Object %d: Empty string "
                                    "for trigger argument in script.",
                                    pObjIndex->iNumber );
                                  bWarn = TRUE;
                                  pTriggerArg->pArg   = EMPTY_STRING;
                                  continue;
                              }

                              pTriggerArg->pArg  = str_dup( cBuf2 );
                          }

                          if ( ( c = next_char( pBuf ) ) == ',' )
                              pBuf               = remove_char_2( pBuf );
                          else if ( c != '\0' )
                          {
                              sap_warning( "Object %d: Missing `,' for "
                                "trigger argument list in script.",
                                pObjIndex->iNumber );
                              bWarn = TRUE;
                          }

                          pTriggerArg->pNext     = pTrigger->pArgs;
                          pTrigger->pArgs        = pTriggerArg;
                      }

                      break;

                  default                       :
                      pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );

                      pTriggerArg->pArg          = str_dup( pBuf );
                      pTrigger->pArgs            = pTriggerArg;
                      break;
                }

                pStr                  = remove_char_2( pStr );

                pTrigger->pNext       = pScript->pTriggers;
                pScript->pTriggers    = pTrigger;
            }
            while ( ( c = next_char( pStr ) ) != '{' && c != '\0' );

            if ( next_char( pStr ) != '{' )
            {
                TRIGGER_DATA *pTriggerNext;
                TRIGGER_ARG_DATA *pTriggerArgNext;

                for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                  pTrigger = pTriggerNext )
                {
                    pTriggerNext        = pTrigger->pNext;

                    for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                      pTriggerArg = pTriggerArgNext )
                    {
                        pTriggerArgNext = pTriggerArg->pNext;

                        str_free( pTriggerArg->pArg );
                        free_mem( (void **) &pTriggerArg );
                    }

                    free_mem( (void **) &pTrigger );
                }

                str_free( pScript->pName );
                free_mem( (void **) &pScript );
                sap_error(
                  "Object %d: Trigger missing `{' symbol in script.",
                  pObjIndex->iNumber );
                bWarn = TRUE;
                break;
            }

            pStr             = edit_str_plus( pStr, cBuf, '{', '}' );

            if ( next_char( pStr ) != '}' )
            {
                TRIGGER_DATA *pTriggerNext;
                TRIGGER_ARG_DATA *pTriggerArgNext;

                for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                  pTrigger = pTriggerNext )
                {
                    pTriggerNext        = pTrigger->pNext;

                    for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                      pTriggerArg = pTriggerArgNext )
                    {
                        pTriggerArgNext = pTriggerArg->pNext;

                        str_free( pTriggerArg->pArg );
                        free_mem( (void **) &pTriggerArg );
                    }

                    free_mem( (void **) &pTrigger );
                }

                str_free( pScript->pName );
                free_mem( (void **) &pScript );
                sap_error(
                  "Object %d: Trigger missing `}' symbol in script.",
                  pObjIndex->iNumber );
                bWarn = TRUE;
                break;
            }

            pStr             = remove_char_2( pStr );
            pScript->pScript = alloc_mem( ( i = obj_script_translate(
                                 pScript, cBuf ) ) );
            memcpy( pScript->pScript, cBuf, i );
            pScript->iCodeSize  = i;

            pScript->pNext      = pProgram->pScripts;
            pProgram->pScripts  = pScript;
        }
        else
        {
            QUEST_VAR_DATA *pVar;

            pVar        = alloc_mem( sizeof( *pVar ) );

            if ( str_compare( cBuf, "number" ) == TRUE )
                pVar->iType = NUMBER_VAR_NUMBER;
            else if ( str_compare( cBuf, "string" ) == TRUE )
                pVar->iType = NUMBER_VAR_STRING;
            else if ( str_compare( cBuf, "character_pointer" ) == TRUE )
                pVar->iType = NUMBER_VAR_POINTER_CHAR;
            else if ( str_compare( cBuf, "object_pointer" ) == TRUE )
                pVar->iType = NUMBER_VAR_POINTER_OBJ;
            else if ( str_compare( cBuf, "room_pointer" ) == TRUE )
                pVar->iType = NUMBER_VAR_POINTER_ROOM;
            else
            {
                free_mem( (void **) &pVar );
                sap_error( "Object %d: Unknown keyword `%s' in script.",
                  pObjIndex->iNumber, cBuf );
                bWarn   = TRUE;
                break;
            }

            pStr        = edit_str( pStr, cBuf, ' ', ";\n\r\t " );

            if ( next_char( pStr ) != ';' )
            {
                free_mem( (void **) &pVar );
                sap_error( "Object %d: "
                  "Syntax error in script variable declaration.",
                  pObjIndex->iNumber );
                bWarn   = TRUE;
                goto end;
            }

            pStr        = remove_char_2( pStr );

            if ( cBuf[0] == '\0' || ( !isalpha( cBuf[0] )
              && cBuf[0] != '_' ) )
            {
                free_mem( (void **) &pVar );
                sap_error( "Object %d: Illegal name for script variable.",
                  pObjIndex->iNumber );
                bWarn   = TRUE;
                goto end;
            }

            for ( i = 0; cBuf[i] != '\0'; i++ )
            {
                if ( !isalnum( cBuf[i] ) && cBuf[i] != '_' )
                {
                    free_mem( (void **) &pVar );
                    sap_error(
                      "Object %d: Illegal name for script variable.",
                      pObjIndex->iNumber );
                    bWarn = TRUE;
                    goto end;
                }
            }

            pVar->sName = save_string( cBuf );

            if ( pVar->iType == NUMBER_VAR_STRING )
                pVar->uData.s    = EMPTY_STRING;

            pVar->pNext          = pProgram->pQuestVars;
            pProgram->pQuestVars = pVar;
        }
    }

end:
    if ( pBak != EMPTY_STRING )
        free_mem( (void **) &pBak );

    return ( bWarn );
}


bool room_load_imagefilename( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    char *pBuf                 = fget_string( pFile );
    int i;

    if ( ( i = get_file_type( pBuf ) ) != FILE_TYPE_GIF
      && i != FILE_TYPE_JPEG )
    {
        sap_warning( "Room %d: Unknown image file format.",
          pRoomIndex->iNumber );
        return ( TRUE );
    }

    free_string( &pRoomIndex->sImageFilename );
    pRoomIndex->sImageFilename = save_string( pBuf );
    return ( FALSE );
}


bool room_load_title( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    free_string( &pRoomIndex->sTitle );
    pRoomIndex->sTitle = save_string( fget_string( pFile ) );
    return ( FALSE );
}


bool room_load_desc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    char cBuf[MAX_INPUT];
    char *pString;
    char *pBuf;
    bool bWarn        = FALSE;

    pString           = fget_string( pFile );
    pBuf              = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf          = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf      = remove_char_2( pBuf );

        if ( str_compare( cBuf, "FORMAT" ) == TRUE )
            pString   = format_string( pString );
        else
        {
            sap_warning( "Room %d: Unknown string flag `%s'.",
              pRoomIndex->iNumber, cBuf );
            bWarn     = TRUE;
        }
    }

    free_string( &pRoomIndex->sDesc );
    pRoomIndex->sDesc = save_string( pString );
    return ( bWarn );
}


bool room_load_roomflags( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    char cBuf[MAX_STRING];
    char *pBuf;
    int i;
    bool bWarn    = FALSE;

    pBuf          = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf      = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf  = remove_char_2( pBuf );

        for ( i = 0; snRoomFlagsTable[i].pName[0] != '\0'; i++ )
        {
            if ( str_compare( snRoomFlagsTable[i].pName, cBuf ) == TRUE )
            {
                SET_FLAG( pRoomIndex->fRoomFlags,
                  snRoomFlagsTable[i].iNumber );
                break;
            }
        }

        if ( snRoomFlagsTable[i].pName[0] == '\0' )
        {
            sap_warning( "Room %d: Unknown room flag `%s'.",
              pRoomIndex->iNumber, cBuf );
            bWarn = TRUE;
        }
    }

    return ( bWarn );
}


bool room_load_sector( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    char *pBuf;
    int i;

    pBuf                            = fget_word_2( pFile );

    for ( i = 0; snSectorTable[i].pName[0] != '\0'; i++ )
    {
        if ( str_compare( snSectorTable[i].pName, pBuf ) == TRUE )
        {
            pRoomIndex->iSectorType = snSectorTable[i].iNumber;
            return ( FALSE );
        }
    }

    sap_warning( "Room %d: Unknown sector type `%s'.",
      pRoomIndex->iNumber, pBuf );
    pRoomIndex->iSectorType         = snSectorTable[0].iNumber;
    return ( TRUE );
}


bool room_load_temperature( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    pRoomIndex->iTemperature     = fget_number_2( pFile );

    if ( pRoomIndex->iTemperature > 1000 )
    {
        sap_warning( "Room %d: Temperature greater then 1000.",
          pRoomIndex->iNumber );
        pRoomIndex->iTemperature = 1000;
        return ( TRUE );
    }

    if ( pRoomIndex->iTemperature < -1000 )
    {
        sap_warning( "Room %d: Temperature less then -1000.",
          pRoomIndex->iNumber );
        pRoomIndex->iTemperature = -1000;
        return ( TRUE );
    }

    return ( FALSE );
}


static bool load_dir_desc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile,
                           int iDir )
{
    char cBuf[MAX_INPUT];
    char *pString;
    char *pBuf;
    bool bWarn                  = FALSE;

    pString                     = fget_string( pFile );
    pBuf                        = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf                    = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf                = remove_char_2( pBuf );

        if ( str_compare( cBuf, "FORMAT" ) == TRUE )
            pString             = format_string( pString );
        else
        {
            sap_warning( "Room %d: Unknown string flag `%s'.",
              pRoomIndex->iNumber, cBuf );
            bWarn               = TRUE;
        }
    }

    free_string( &pRoomIndex->sDirDescs[iDir] );
    pRoomIndex->sDirDescs[iDir] = save_string( pString );
    return ( bWarn );
}


bool room_load_northdesc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_dir_desc( pRoomIndex, pFile, 0 ) );
}


bool room_load_southdesc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_dir_desc( pRoomIndex, pFile, 1 ) );
}


bool room_load_eastdesc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_dir_desc( pRoomIndex, pFile, 2 ) );
}


bool room_load_westdesc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_dir_desc( pRoomIndex, pFile, 3 ) );
}


bool room_load_updesc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_dir_desc( pRoomIndex, pFile, 4 ) );
}


bool room_load_downdesc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_dir_desc( pRoomIndex, pFile, 5 ) );
}


bool room_load_northeastdesc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_dir_desc( pRoomIndex, pFile, 6 ) );
}


bool room_load_southwestdesc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_dir_desc( pRoomIndex, pFile, 7 ) );
}


bool room_load_northwestdesc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_dir_desc( pRoomIndex, pFile, 8 ) );
}


bool room_load_southeastdesc( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_dir_desc( pRoomIndex, pFile, 9 ) );
}


static bool load_exit( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile,
                       int iDoor )
{
    char cBuf[MAX_STRING];
    char *pBuf;
    int i;
    bool bWarn                                = FALSE;

    pRoomIndex->eExits[iDoor].uRoom.iNumber   = fget_number( pFile );

    if ( pRoomIndex->eExits[iDoor].uRoom.iNumber <= 5
      || pRoomIndex->eExits[iDoor].uRoom.iNumber > MAX_INDEX_NUMBER )
        sap_fatal( "Room %d: Illegal room number `%d' in exit.",
          pRoomIndex->iNumber, pRoomIndex->eExits[iDoor].uRoom.iNumber );

    pBuf                                      = fget_word_2( pFile );

    if ( str_compare( pBuf, "STANDARD" ) == TRUE )
    {
        pRoomIndex->eExits[iDoor].iExitType   = NUMBER_EXIT_STANDARD;
        return ( FALSE );
    }
    if ( str_compare( pBuf, "SHARED" ) == TRUE )
    {
        pRoomIndex->eExits[iDoor].bShared     = TRUE;
        return ( FALSE );
    }
    else if ( str_compare( pBuf, "DOOR" ) == TRUE )
    {
        pRoomIndex->eExits[iDoor].iExitType   = NUMBER_EXIT_DOOR;

        for ( i = 0; pRoomIndex->eExits[iDoor].pDoorNames[i] != NULL; i++ )
            free_string( &pRoomIndex->eExits[iDoor].pDoorNames[i] );

        free_mem( (void **) &pRoomIndex->eExits[iDoor].pDoorNames );
        pRoomIndex->eExits[iDoor].pDoorNames  = alloc_mem( sizeof( string )
                                                  * 2 );
        pRoomIndex->eExits[iDoor].pDoorNames[0] = save_string(
                                                    fget_string( pFile ) );
        pRoomIndex->eExits[iDoor].pDoorNames[1] = NULL;
        pBuf         = fget_string_2( pFile, '[', ']' );

        while ( next_char( pBuf ) != '\0' )
        {
            pBuf     = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

            if ( next_char( pBuf ) == ',' )
                pBuf = remove_char_2( pBuf );

            if ( str_compare( cBuf, "CLOSED" ) == TRUE )
                SET_FLAG( pRoomIndex->eExits[iDoor].fOrigFlags,
                  FLAG_DOOR_CLOSED );
            else if ( str_compare( cBuf, "LOCKED" ) == TRUE )
                SET_FLAG( pRoomIndex->eExits[iDoor].fOrigFlags,
                  FLAG_DOOR_LOCKED );
            else if ( str_compare( cBuf, "HIDDEN" ) == TRUE )
                SET_FLAG( pRoomIndex->eExits[iDoor].fOrigFlags,
                  FLAG_DOOR_HIDDEN );
            else if ( str_compare( cBuf, "LEVEL" ) == TRUE )
            {
                pBuf = edit_str( pBuf, cBuf, ' ', "\n\r\t " );
                pRoomIndex->eExits[iDoor].iLevel = atoi( cBuf );

                if ( pRoomIndex->eExits[iDoor].iLevel < 1 )
                {
                    sap_warning( "Room %d: Door level less then 1.",
                      pRoomIndex->iNumber );
                    pRoomIndex->eExits[iDoor].iLevel = 1;
                    bWarn                     = TRUE;
                }

                if ( pRoomIndex->eExits[iDoor].iLevel > MAX_PLAYER_LEVEL )
                {
                    sap_warning( "Room %d: Door level higher then %d.",
                      pRoomIndex->iNumber, MAX_PLAYER_LEVEL );
                    pRoomIndex->eExits[iDoor].iLevel = MAX_PLAYER_LEVEL;
                    bWarn                     = TRUE;
                }
            }
            else if ( str_compare( cBuf, "KEY" ) == TRUE )
            {
                pBuf = edit_str( pBuf, cBuf, ' ', "\n\r\t " );
                pRoomIndex->eExits[iDoor].uKey.iNumber = atoi( cBuf );

                if ( pRoomIndex->eExits[iDoor].uKey.iNumber <= 5
                  || pRoomIndex->eExits[iDoor].uKey.iNumber
                  > MAX_INDEX_NUMBER )
                    sap_fatal(
                      "Room %d: Illegal object number `%d' for door key.",
                      pRoomIndex->iNumber,
                      pRoomIndex->eExits[iDoor].uKey.iNumber );
            }
            else
            {
                sap_warning( "Room %d: Unknown door flag `%s'.",
                  pRoomIndex->iNumber, cBuf );
                bWarn                         = TRUE;
            }
        }

        pRoomIndex->eExits[iDoor].iResetTime  = fget_number_2( pFile );
    }
    else
    {
        sap_warning( "Room %d: Unknown exit type `%s'.",
          pRoomIndex->iNumber, pBuf );
        return ( TRUE );
    }

    pRoomIndex->eExits[iDoor].fCurrFlags
                              = pRoomIndex->eExits[iDoor].fOrigFlags;
    return ( bWarn );
}


bool room_load_exitnorth( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_exit( pRoomIndex, pFile, 0 ) );
}


bool room_load_exitsouth( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_exit( pRoomIndex, pFile, 1 ) );
}


bool room_load_exiteast( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_exit( pRoomIndex, pFile, 2 ) );
}


bool room_load_exitwest( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_exit( pRoomIndex, pFile, 3 ) );
}


bool room_load_exitup( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_exit( pRoomIndex, pFile, 4 ) );
}


bool room_load_exitdown( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_exit( pRoomIndex, pFile, 5 ) );
}


bool room_load_exitnortheast( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_exit( pRoomIndex, pFile, 6 ) );
}


bool room_load_exitsouthwest( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_exit( pRoomIndex, pFile, 7 ) );
}


bool room_load_exitnorthwest( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_exit( pRoomIndex, pFile, 8 ) );
}


bool room_load_exitsoutheast( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    return ( load_exit( pRoomIndex, pFile, 9 ) );
}


static int get_obj_reset_list( char **ppSrc, OBJ_RESET_DATA **ppList )
{
    OBJ_RESET_DATA *pReset;
    char *pBuf                 = new_buffer( );
    char *pSrc                 = *ppSrc;
    char cBuf[MAX_STRING];
    int i;

    if ( next_char( pSrc ) != '[' )
        return ( -1 );

    pSrc                       = edit_str_plus( pSrc, pBuf, '[', ']' );

    if ( next_char( pSrc ) != ']' )
        return ( -2 );

    *ppSrc                     = remove_char_2( pSrc );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf                   = edit_str( pBuf, cBuf, ' ', "[\n\r\t " );

        if ( is_number( cBuf ) != TRUE )
            return ( -3 );

        i                      = atoi( cBuf );

        if ( i <= 5 || i > MAX_INDEX_NUMBER )
            return ( -4 );

        pReset                 = alloc_mem( sizeof( *pReset ) );
        pReset->u1.iNumber     = i;

        if ( ( i = get_obj_reset_list( &pBuf, &pReset->pContentResets ) )
          < 0 )
            return ( i );

        if ( next_char( pBuf ) == ',' )
            pBuf               = remove_char_2( pBuf );

        pReset->pNext          = *ppList;
        *ppList                = pReset;
    }

    return ( 0 );
}


bool room_load_npcs( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    /* FILE *pFile2; */
    NPC_RESET_DATA *pNewReset;
    char cBuf[MAX_STRING];
    char *pBuf;
    int i;
    bool bWarn                    = FALSE;

    pBuf                          = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf = edit_str( pBuf, cBuf, ' ', "[\n\r\t " );
        pNewReset                 = alloc_mem( sizeof( *pNewReset ) );

        if ( is_number( cBuf ) == FALSE )
        {
            sap_fatal( "Room %d: Non-number `%s' for NPC number.",
              pRoomIndex->iNumber, cBuf );
            bWarn                 = TRUE;
        }
        else
            pNewReset->u1.iNumber = atoi( cBuf );

        if ( pNewReset->u1.iNumber <= 5
          || pNewReset->u1.iNumber > MAX_INDEX_NUMBER )
        {
            sap_fatal( "Room %d: Illegal NPC number `%d' for reset.",
              pRoomIndex->iNumber, pNewReset->u1.iNumber );
            bWarn                 = TRUE;
        }

        if ( ( i = get_obj_reset_list( &pBuf, &pNewReset->pInvenResets ) )
          < 0 )
        {
            sap_error( "Room %d: Error %d.", pRoomIndex->iNumber, i );
            bWarn                 = TRUE;
        }

        if ( ( i = get_obj_reset_list( &pBuf, &pNewReset->pEqResets ) )
          < 0 )
        {
            sap_error( "Room %d: Error %d.", pRoomIndex->iNumber, i );
            bWarn                 = TRUE;
        }

        pBuf = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf                  = remove_char_2( pBuf );

        if ( is_number( cBuf ) == FALSE )
        {
            sap_error( "Room %d: Non-number `%s' for NPC reset time.",
              pRoomIndex->iNumber, cBuf );
            bWarn                 = TRUE;
        }
        else
            pNewReset->iResetTime = atoi( cBuf );

        pNewReset->pNext          = pRoomIndex->pNPCResets;
        pRoomIndex->pNPCResets    = pNewReset;
    }

    return ( bWarn );
}


bool room_load_objects( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    /* FILE *pFile2; */
    OBJ_RESET_DATA *pNewReset;
    char cBuf[MAX_STRING];
    char *pBuf;
    int i;
    bool bWarn                    = FALSE;

    pBuf                          = fget_string_2( pFile, '[', ']' );

    while ( next_char( pBuf ) != '\0' )
    {
        pBuf = edit_str( pBuf, cBuf, ' ', "[\n\r\t " );
        pNewReset                 = alloc_mem( sizeof( *pNewReset ) );

        if ( is_number( cBuf ) == FALSE )
        {
            sap_fatal( "Room %d: Non-number `%s' for object number.",
              pRoomIndex->iNumber, cBuf );
            bWarn                 = TRUE;
        }
        else
            pNewReset->u1.iNumber = atoi( cBuf );

        if ( pNewReset->u1.iNumber <= 5
          || pNewReset->u1.iNumber > MAX_INDEX_NUMBER )
        {
            sap_fatal( "Room %d: Illegal object number `%d' for reset.",
              pRoomIndex->iNumber, pNewReset->u1.iNumber );
            bWarn                 = TRUE;
        }

        if ( ( i = get_obj_reset_list( &pBuf,
          &pNewReset->pContentResets ) ) < 0 )
        {
            sap_error( "Room %d: Error %d.", pRoomIndex->iNumber, i );
            bWarn                 = TRUE;
        }

        pBuf = edit_str( pBuf, cBuf, ' ', ",\n\r\t " );

        if ( next_char( pBuf ) == ',' )
            pBuf                  = remove_char_2( pBuf );

        if ( is_number( cBuf ) == FALSE )
        {
            sap_error( "Room %d: Non-number `%s' for object reset time.",
              pRoomIndex->iNumber, cBuf );
            bWarn                 = TRUE;
        }
        else
            pNewReset->iResetTime = atoi( cBuf );

        pNewReset->pNext          = pRoomIndex->pObjResets;
        pRoomIndex->pObjResets    = pNewReset;
    }

    return ( bWarn );
}


bool room_load_program( ROOM_INDEX_DATA *pRoomIndex, FILE *pFile )
{
    PROGRAM_DATA *pProgram;
    SCRIPT_DATA *pScript;
    TRIGGER_DATA *pTrigger;
    TRIGGER_ARG_DATA *pTriggerArg;
    char *pStr    = fget_string_3( pFile, '{', '}' );
    char *pBak    = pStr;
    char cBuf[MAX_STRING];
    char cBuf2[MAX_STRING];
    char *pBuf;
    char c;
    int i;
    bool bWarn    = FALSE;

    pProgram      = alloc_mem( sizeof( *pProgram ) );

    pRoomIndex->pProgram = pProgram;

    while ( next_char( pStr ) != '\0' )
    {
        pStr      = edit_str( pStr, cBuf, ' ', "\n\r\t " );

        if ( str_compare( cBuf, "TRIGGER" ) == TRUE )
        {
            pStr      = edit_str( pStr, cBuf, ' ', "\n\r\t " );

            for ( pScript = pProgram->pScripts; pScript != NULL;
              pScript = pScript->pNext )
            {
                if ( str_compare( pScript->pName, cBuf ) == TRUE )
                    break;
            }

            if ( pScript != NULL )
            {
                sap_error(
                  "Room %d: Multiple blocks with the name `%s' in script.",
                  pRoomIndex->iNumber, cBuf );
                bWarn = TRUE;
                goto end;
            }

            pScript               = alloc_mem( sizeof( *pScript ) );
            pScript->pName        = str_dup( cBuf );

            pStr      = edit_str( pStr, cBuf, ' ', "\n\r\t " );

            if ( str_compare( cBuf, "enabled" ) == TRUE )
                pScript->bDisabled = FALSE;
            else if ( str_compare( cBuf, "disabled" ) == TRUE )
                pScript->bDisabled = TRUE;
            else
            {
                str_free( pScript->pName );
                free_mem( (void **) &pScript );
                sap_error( "Room %d: Unknown enabled flag in script.",
                  pRoomIndex->iNumber );
                bWarn = TRUE;
                goto end;
            }

            do
            {
                pStr  = edit_str( pStr, cBuf, ' ', "(\n\r\t " );

                if ( next_char( pStr ) != '(' )
                {
                    TRIGGER_DATA *pTriggerNext;
                    TRIGGER_ARG_DATA *pTriggerArgNext;

                    for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                      pTrigger = pTriggerNext )
                    {
                        pTriggerNext        = pTrigger->pNext;

                        for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                          pTriggerArg = pTriggerArgNext )
                        {
                            pTriggerArgNext = pTriggerArg->pNext;

                            str_free( pTriggerArg->pArg );
                            free_mem( (void **) &pTriggerArg );
                        }

                        free_mem( (void **) &pTrigger );
                    }

                    str_free( pScript->pName );
                    free_mem( (void **) &pScript );
                    sap_error(
                      "Room %d: Trigger missing `(' symbol in script.",
                      pRoomIndex->iNumber );
                    bWarn = TRUE;
                    goto end;
                }

                for ( i = 0; snRoomScriptTriggerTable[i].pName[0] != '\0';
                  i++ )
                {
                    if ( str_compare( cBuf,
                      snRoomScriptTriggerTable[i].pName ) == TRUE )
                        break;
                }

                if ( snRoomScriptTriggerTable[i].pName[0] == '\0' )
                {
                    TRIGGER_DATA *pTriggerNext;
                    TRIGGER_ARG_DATA *pTriggerArgNext;

                    for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                      pTrigger = pTriggerNext )
                    {
                        pTriggerNext        = pTrigger->pNext;

                        for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                          pTriggerArg = pTriggerArgNext )
                        {
                            pTriggerArgNext = pTriggerArg->pNext;

                            str_free( pTriggerArg->pArg );
                            free_mem( (void **) &pTriggerArg );
                        }

                        free_mem( (void **) &pTrigger );
                    }

                    str_free( pScript->pName );
                    free_mem( (void **) &pScript );
                    sap_error(
                      "Room %d: Unknown trigger type `%s' in script.",
                      pRoomIndex->iNumber, cBuf );
                    bWarn = TRUE;
                    goto end;
                }

                pTrigger            = alloc_mem( sizeof( *pTrigger ) );
                pTrigger->iTrigger  = snRoomScriptTriggerTable[i].iNumber;
                pStr                = edit_str( pStr, cBuf, '(', ")" );
                pBuf                = remove_spaces( cBuf );

                if ( next_char( pStr ) != ')' )
                {
                    TRIGGER_DATA *pTriggerNext;
                    TRIGGER_ARG_DATA *pTriggerArgNext;

                    free_mem( (void **) &pTrigger );

                    for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                      pTrigger = pTriggerNext )
                    {
                        pTriggerNext        = pTrigger->pNext;

                        for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                          pTriggerArg = pTriggerArgNext )
                        {
                            pTriggerArgNext = pTriggerArg->pNext;

                            str_free( pTriggerArg->pArg );
                            free_mem( (void **) &pTriggerArg );
                        }

                        free_mem( (void **) &pTrigger );
                    }

                    str_free( pScript->pName );
                    free_mem( (void **) &pScript );
                    sap_error(
                      "Room %d: Trigger missing `)' symbol in script.",
                      pRoomIndex->iNumber );
                    bWarn = TRUE;
                    goto end;
                }

                switch ( pTrigger->iTrigger )
                {
                  case NUMBER_ROOM_TRIGGER_RANDOM :
                      if ( is_number( pBuf ) != TRUE )
                      {
                          TRIGGER_DATA *pTriggerNext;
                          TRIGGER_ARG_DATA *pTriggerArgNext;

                          free_mem( (void **) &pTrigger );

                          for ( pTrigger = pScript->pTriggers; pTrigger;
                            pTrigger = pTriggerNext )
                          {
                              pTriggerNext        = pTrigger->pNext;

                              for ( pTriggerArg = pTrigger->pArgs;
                                pTriggerArg; pTriggerArg = pTriggerArgNext )
                              {
                                  pTriggerArgNext = pTriggerArg->pNext;

                                  str_free( pTriggerArg->pArg );
                                  free_mem( (void **) &pTriggerArg );
                              }

                              free_mem( (void **) &pTrigger );
                          }

                          str_free( pScript->pName );
                          free_mem( (void **) &pScript );
                          sap_warning( "Room %d: Non-number argument for "
                            "trigger in script.", pRoomIndex->iNumber );
                          bWarn = TRUE;
                          goto end;
                      }

                      pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );
                      pTriggerArg->pArg = alloc_mem( 1 );
                      *( (intt *) pTriggerArg->pArg ) = (intt) atoi( pBuf );

                      pTrigger->pArgs                 = pTriggerArg;
                      break;

                  case NUMBER_ROOM_TRIGGER_MESSAGE:
                  case NUMBER_ROOM_TRIGGER_EMOTE  :
                  case NUMBER_ROOM_TRIGGER_SAY    :
                  case NUMBER_ROOM_TRIGGER_YELL   :
                      if ( str_compare( pBuf, "all" ) == TRUE )
                      {
                          pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );

                          pTriggerArg->iType          = 1;
                          pTriggerArg->pArg           = EMPTY_STRING;
                          pTrigger->pArgs             = pTriggerArg;
                          break;
                      }

                      while ( *pBuf != '\0' )
                      {
                          pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );

                          pBuf = edit_str( pBuf, cBuf2, ' ', "\n\r\t " );

                          if ( next_char( pBuf ) == '"' )
                          {
                              if ( str_compare( cBuf2, "exact" ) == TRUE )
                                  pTriggerArg->iType = 2;
                              else if ( str_compare( cBuf2, "prefix" )
                                == TRUE )
                                  pTriggerArg->iType = 3;
                              else if ( str_compare( cBuf2, "infix" )
                                == TRUE )
                                  pTriggerArg->iType = 4;
                              else if ( str_compare( cBuf2, "suffix" )
                                == TRUE )
                                  pTriggerArg->iType = 5;
                              else
                              {
                                  sap_warning( "Room %d: Unknown "
                                    "comparison type for trigger argument "
                                    "in script.",
                                    pRoomIndex->iNumber );
                                  bWarn = TRUE;
                                  pTriggerArg->iType = 2;
                                  continue;
                              }

                              pBuf           = make_string( pBuf, cBuf2 );
                              pBuf           = remove_char_2( pBuf );

                              if ( cBuf2[0] == '\0' )
                              {
                                  sap_warning( "Room %d: Empty string for "
                                    "trigger argument in script.",
                                    pRoomIndex->iNumber );
                                  bWarn = TRUE;
                                  pTriggerArg->pArg   = EMPTY_STRING;
                                  continue;
                              }

                              pTriggerArg->pArg  = str_dup( cBuf2 );
                          }

                          if ( ( c = next_char( pBuf ) ) == ',' )
                              pBuf               = remove_char_2( pBuf );
                          else if ( c != '\0' )
                          {
                              sap_warning( "Room %d: Missing `,' for "
                                "trigger argument list in script.",
                                pRoomIndex->iNumber );
                              bWarn = TRUE;
                          }

                          pTriggerArg->pNext     = pTrigger->pArgs;
                          pTrigger->pArgs        = pTriggerArg;
                      }

                      break;

                  default                        :
                      pTriggerArg = alloc_mem( sizeof( *pTriggerArg ) );

                      pTriggerArg->pArg          = str_dup( pBuf );
                      pTrigger->pArgs            = pTriggerArg;
                      break;
                }

                pStr                  = remove_char_2( pStr );

                pTrigger->pNext       = pScript->pTriggers;
                pScript->pTriggers    = pTrigger;
            }
            while ( ( c = next_char( pStr ) ) != '{' && c != '\0' );

            if ( next_char( pStr ) != '{' )
            {
                TRIGGER_DATA *pTriggerNext;
                TRIGGER_ARG_DATA *pTriggerArgNext;

                for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                  pTrigger = pTriggerNext )
                {
                    pTriggerNext        = pTrigger->pNext;

                    for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                      pTriggerArg = pTriggerArgNext )
                    {
                        pTriggerArgNext = pTriggerArg->pNext;

                        str_free( pTriggerArg->pArg );
                        free_mem( (void **) &pTriggerArg );
                    }

                    free_mem( (void **) &pTrigger );
                }

                str_free( pScript->pName );
                free_mem( (void **) &pScript );
                sap_error(
                  "Room %d: Trigger missing `{' symbol in script.",
                  pRoomIndex->iNumber );
                bWarn = TRUE;
                break;
            }

            pStr             = edit_str_plus( pStr, cBuf, '{', '}' );

            if ( next_char( pStr ) != '}' )
            {
                TRIGGER_DATA *pTriggerNext;
                TRIGGER_ARG_DATA *pTriggerArgNext;

                for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
                  pTrigger = pTriggerNext )
                {
                    pTriggerNext        = pTrigger->pNext;

                    for ( pTriggerArg = pTrigger->pArgs; pTriggerArg;
                      pTriggerArg = pTriggerArgNext )
                    {
                        pTriggerArgNext = pTriggerArg->pNext;

                        str_free( pTriggerArg->pArg );
                        free_mem( (void **) &pTriggerArg );
                    }

                    free_mem( (void **) &pTrigger );
                }

                str_free( pScript->pName );
                free_mem( (void **) &pScript );
                sap_error(
                  "Room %d: Trigger missing `}' symbol in script.",
                  pRoomIndex->iNumber );
                bWarn = TRUE;
                break;
            }

            pStr             = remove_char_2( pStr );
            pScript->pScript = alloc_mem( ( i = room_script_translate(
                                 pScript, cBuf ) ) );
            memcpy( pScript->pScript, cBuf, i );
            pScript->iCodeSize  = i;

            pScript->pNext      = pProgram->pScripts;
            pProgram->pScripts  = pScript;
        }
        else if ( str_compare( cBuf, "USES" ) == TRUE )
        {
            GENERIC_DATA *pGen;
            QUEST_DATA *pQuestData;
            char *pBuf2;
            char c;

            pStr = edit_str( pStr, cBuf, ' ', ";" );

            if ( *pStr != ';' )
            {
                sap_error(
                  "Room %d: Syntax error in script quest data reference.",
                  pRoomIndex->iNumber );
                bWarn   = TRUE;
                goto end;
            }

            pStr++;
            pBuf2       = cBuf;

            do
            {
                pBuf2     = edit_str( pBuf2, cBuf2, ' ', ",\n\r\t " );

                if ( ( c = next_char( pBuf2 ) ) != ',' && c != '\0' )
                {
                    sap_error( "Room %d: "
                      "Syntax error in script quest data reference.",
                      pRoomIndex->iNumber );
                    bWarn   = TRUE;
                    goto end;
                }
                else if ( c == ',' )
                    pBuf2 = remove_char_2( pBuf2 );

                for ( pQuestData = pQuestDataList; pQuestData != NULL;
                  pQuestData = pQuestData->pNext )
                {
                    if ( strcmp( pQuestData->sName, cBuf2 ) == 0 )
                    {
                        for ( pGen = pProgram->pQuestDataList; pGen;
                          pGen = pGen->pNext )
                        {
                            if ( pGen->pData == pQuestData )
                                break;
                        }

                        if ( pGen != NULL )
                        {
                            sap_warning(
                              "Room %d: Multiply referenced quest data.",
                              pRoomIndex->iNumber );
                            bWarn   = TRUE;
                            break;
                        }

                        pGen        = alloc_mem( sizeof( *pGen ) );
                        pGen->pData = pQuestData;

                        pGen->pNext = pProgram->pQuestDataList;
                        pProgram->pQuestDataList = pGen;
                        break;
                    }
                }
            }
            while ( next_char( pBuf2 ) != '\0' );
        }
        else
        {
            QUEST_VAR_DATA *pVar;

            pVar        = alloc_mem( sizeof( *pVar ) );

            if ( str_compare( cBuf, "number" ) == TRUE )
                pVar->iType = NUMBER_VAR_NUMBER;
            else if ( str_compare( cBuf, "string" ) == TRUE )
                pVar->iType = NUMBER_VAR_STRING;
            else if ( str_compare( cBuf, "character_pointer" ) == TRUE )
                pVar->iType = NUMBER_VAR_POINTER_CHAR;
            else if ( str_compare( cBuf, "object_pointer" ) == TRUE )
                pVar->iType = NUMBER_VAR_POINTER_OBJ;
            else if ( str_compare( cBuf, "room_pointer" ) == TRUE )
                pVar->iType = NUMBER_VAR_POINTER_ROOM;
            else
            {
                free_mem( (void **) &pVar );
                sap_error( "Room %d: Unknown keyword `%s' in script.",
                  pRoomIndex->iNumber, cBuf );
                bWarn   = TRUE;
                break;
            }

            pStr        = edit_str( pStr, cBuf, ' ', ";\n\r\t " );

            if ( next_char( pStr ) != ';' )
            {
                free_mem( (void **) &pVar );
                sap_error(
                  "Room %d: Syntax error in script variable declaration.",
                  pRoomIndex->iNumber );
                bWarn   = TRUE;
                goto end;
            }

            pStr        = remove_char_2( pStr );

            if ( cBuf[0] == '\0' || ( !isalpha( cBuf[0] )
              && cBuf[0] != '_' ) )
            {
                free_mem( (void **) &pVar );
                sap_error( "Room %d: Illegal name for script variable.",
                  pRoomIndex->iNumber );
                bWarn   = TRUE;
                goto end;
            }

            for ( i = 0; cBuf[i] != '\0'; i++ )
            {
                if ( !isalnum( cBuf[i] ) && cBuf[i] != '_' )
                {
                    free_mem( (void **) &pVar );
                    sap_error(
                      "Room %d: Illegal name for script variable.",
                      pRoomIndex->iNumber );
                    bWarn = TRUE;
                    goto end;
                }
            }

            pVar->sName = save_string( cBuf );

            if ( pVar->iType == NUMBER_VAR_STRING )
                pVar->uData.s    = EMPTY_STRING;

            pVar->pNext          = pProgram->pQuestVars;
            pProgram->pQuestVars = pVar;
        }
    }

end:
    if ( pBak != EMPTY_STRING )
        free_mem( (void **) &pBak );

    return ( bWarn );
}


/*
 * End of load.c
 */