/*
* Copyright (C) 1995-1997 Christopher D. Granz
*
* This header may not be removed.
*
* Refer to the file "License" included in this package for further
* information and before using any of the following.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <time.h>
#include <fcntl.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include "sapphire.h"
#include "emerald.h"
/*
* Prototypes
*/
#define NPCID NPC_INDEX_DATA
#define OID OBJ_INDEX_DATA
#define RID ROOM_INDEX_DATA
#define NPCRD NPC_RESET_DATA
#define ORD OBJ_RESET_DATA
#define OD OBJ_DATA
static void main_loop ( void );
static void update ( void );
static void translate_numbers ( void );
static OD * translate_obj_resets ( ORD *, RID * );
static void free_obj_reset_list ( ORD ** );
static int npc_inherit ( NPCID * );
static int obj_inherit ( OID * );
static int fix_exit ( RID *, int );
#undef NPCID
#undef OID
#undef RID
#undef NPCRD
#undef ORD
#undef OD
/*
* Globals
*/
extern char * pStrBuffersBegin;
extern char * pStrBuffers;
extern int iMaxStrBuffers;
extern int iNumStrBuffers;
extern int iMaxFragments;
extern bool bIsPrompt;
#include <kvm.h>
#include <sys/param.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
/*
* Functions
*/
int main( int iArgCount, char *pArgV[], char *pEnvV[] )
{
struct timeval tTimeNow;
struct rlimit rl;
bool bLogToScreen = FALSE;
if ( pArgV[1] == NULL )
{
fprintf( stderr, "\nUsage: %s <boot file> [-l]\n", pArgV[0] );
return ( 0 );
}
if ( pArgV[2] != NULL && pArgV[2][0] == '-' )
{
if ( pArgV[2][1] == 'l' && pArgV[2][2] == '\0' )
bLogToScreen = TRUE;
else
{
fprintf( stderr, "\nInvalid switch: `%s'.\n", pArgV[2] );
return ( 1 );
}
}
pLogFile = stdout;
bErrorsFound = FALSE;
bWarningsFound = FALSE;
bStrComparing = FALSE;
/*
* Set max coredump size.
*/
getrlimit( RLIMIT_CORE, &rl );
rl.rlim_cur = rl.rlim_max;
setrlimit( RLIMIT_CORE, &rl );
init_signal_handlers( );
pProgramName = str_dup( pArgV[0] );
pBootFilename = str_dup( pArgV[1] );
gettimeofday( &tTimeNow, NULL );
tCurrentTime = (time_t) tTimeNow.tv_sec;
init_random( );
load_config( pBootFilename );
if ( iTelnetPort <= 1024 || iBinaryPort <= 1024
|| iMUDCommPort <= 1024 )
sap_fatal( "Port numbers must be above 1024." );
if ( iTelnetPort == iBinaryPort || iTelnetPort == iMUDCommPort
|| iBinaryPort == iMUDCommPort )
sap_fatal(
"Telnet, binary and MUD-Comm ports must be different." );
/*
* Initialize memory based on settings from the config file.
*/
mem_init( );
atexit( mem_clean_up );
/*
* Create a log file (if needed).
*/
if ( bLogToScreen != TRUE )
log_init( );
fprintf( stderr, COPYRIGHT_NOTICE );
if ( bLogToScreen != TRUE )
fprintf( stderr, "Making inititial outgoing MUD-Comm connections."
" Please wait ...\n" );
load_mudcomm_file( pMUDCommFilename );
if ( bLogToScreen != TRUE )
fprintf( stderr,
"Finished making inititial outgoing MUD-Comm connections.\n\n" );
lprintf(
"\n Finished making initital outgoing MUD-Comm connections." );
if ( bLogToScreen != TRUE )
fprintf( stderr, "Opening telnet socket. Please wait ...\n" );
init_telnet_socket( iTelnetPort );
if ( bLogToScreen != TRUE )
fprintf( stderr, "Telnet socket successfully opened.\n\n" );
lprintf( "Telnet socket successfully opened." );
if ( bLogToScreen != TRUE )
fprintf( stderr, "Opening binary socket. Please wait ...\n" );
init_binary_socket( iBinaryPort );
if ( bLogToScreen != TRUE )
fprintf( stderr, "Binary socket successfully opened.\n\n" );
lprintf( "Binary socket successfully opened." );
if ( bLogToScreen != TRUE )
fprintf( stderr, "Opening MUD-Comm socket. Please wait ...\n" );
init_mudcomm_socket( iMUDCommPort );
if ( bLogToScreen != TRUE )
fprintf( stderr, "MUD-Comm socket successfully opened.\n\n" );
lprintf( "MUD-Comm socket successfully opened." );
if ( bLogToScreen != TRUE )
fprintf( stderr, "Loading database files. Please wait ...\n" );
load_database( );
if ( bLogToScreen != TRUE )
fprintf( stderr, "All database files successfully loaded.\n\n" );
lprintf( "All database files successfully loaded." );
if ( bLogToScreen != TRUE )
fprintf( stderr,
"Ready to run (pid %ld) using ports %d, %d and %d.\n",
(long) getpid( ), iTelnetPort, iBinaryPort, iMUDCommPort );
lprintf( "\n "
"Ready to run (pid %ld) using ports %d, %d and %d.",
(long) getpid( ), iTelnetPort, iBinaryPort, iMUDCommPort );
bRunning = TRUE;
main_loop( );
if ( sTelnetControl > -1 )
close( sTelnetControl );
if ( sBinaryControl > -1 )
close( sBinaryControl );
if ( bLogToScreen != TRUE )
fprintf( stderr, "Game Over.\n" );
lprintf( "Game Over.\n" );
return ( 0 );
}
static void main_loop( void )
{
static time_t tWaitTime;
struct timeval tNullTime;
struct timeval tStallTime;
struct timeval tTime;
TERM_DATA *pTerm;
TERM_DATA *pTermNext;
MUD_COMM_DATA *pMUDComm;
MUD_COMM_DATA *pMUDCommNext;
CHILDP_DATA *pChild;
CHILDP_DATA *pChildNext;
fd_set fdsStdin;
fd_set fdsTelnetIn;
fd_set fdsTelnetOut;
fd_set fdsTelnetExc;
fd_set fdsBinaryIn;
fd_set fdsBinaryOut;
fd_set fdsBinaryExc;
fd_set fdsMUDCommIn;
fd_set fdsMUDCommOut;
fd_set fdsMUDCommExc;
sapsocket sTopTelnet;
sapsocket sTopBinary;
sapsocket sTopMUDComm;
int i;
if ( setjmp( jbReboot ) != 0 ) /* Not currently used. */
bRunning = TRUE;
zero_out( &tNullTime, sizeof( tNullTime ) );
tStallTime.tv_sec = 0;
tStallTime.tv_usec = ( lLoopStallTime / 3 );
tWaitTime = 0;
while ( bRunning == TRUE )
{
/*
* Deal with reading stdin if the user is in command mode.
*/
if ( bIsPrompt == TRUE )
{
FD_ZERO( &fdsStdin );
FD_SET( STDIN_FILENO, &fdsStdin );
if ( select( ( STDIN_FILENO + 1 ), &fdsStdin, NULL, NULL,
&tNullTime ) < 0 )
sap_error( "Poll: %s.", strerror( errno ) );
if ( FD_ISSET( STDIN_FILENO, &fdsStdin ) )
process_mucs_cmd( );
}
if ( gettimeofday( &tTime, NULL ) < 0 )
sap_fatal( "Get time: %s.", strerror( errno ) );
tCurrentTime = (time_t) tTime.tv_sec;
/*
* Poll all socket descriptors.
*/
FD_ZERO( &fdsTelnetIn );
FD_ZERO( &fdsTelnetOut );
FD_ZERO( &fdsTelnetExc );
FD_ZERO( &fdsBinaryIn );
FD_ZERO( &fdsBinaryOut );
FD_ZERO( &fdsBinaryExc );
FD_ZERO( &fdsMUDCommIn );
FD_ZERO( &fdsMUDCommOut );
FD_ZERO( &fdsMUDCommExc );
FD_SET( sTelnetControl, &fdsTelnetIn );
FD_SET( sBinaryControl, &fdsBinaryIn );
FD_SET( sMUDCommControl, &fdsMUDCommIn );
sTopTelnet = sTelnetControl;
sTopBinary = sBinaryControl;
sTopMUDComm = sMUDCommControl;
for ( pTerm = pTermList; pTerm != NULL; pTerm = pTerm->pNext )
{
sTopTelnet = ( sTopTelnet > pTerm->sTelnetSocket
? sTopTelnet : pTerm->sTelnetSocket );
FD_SET( pTerm->sTelnetSocket, &fdsTelnetIn );
FD_SET( pTerm->sTelnetSocket, &fdsTelnetOut );
FD_SET( pTerm->sTelnetSocket, &fdsTelnetExc );
if ( pTerm->iTermType == CLIENT_SAPPHIRE_COMPATIBLE )
{
sTopBinary = ( sTopBinary > pTerm->sBinarySocket
? sTopBinary : pTerm->sBinarySocket );
FD_SET( pTerm->sBinarySocket, &fdsBinaryIn );
FD_SET( pTerm->sBinarySocket, &fdsBinaryOut );
FD_SET( pTerm->sBinarySocket, &fdsBinaryExc );
}
}
for ( pMUDComm = pMUDCommList; pMUDComm != NULL;
pMUDComm = pMUDComm->pNext )
{
sTopMUDComm = ( sTopMUDComm > pMUDComm->sMUDCommSocket
? sTopMUDComm : pMUDComm->sMUDCommSocket );
FD_SET( pMUDComm->sMUDCommSocket, &fdsMUDCommIn );
FD_SET( pMUDComm->sMUDCommSocket, &fdsMUDCommOut );
FD_SET( pMUDComm->sMUDCommSocket, &fdsMUDCommExc );
}
do
{
errno = 0;
select( ( sTopBinary + 1 ), &fdsBinaryIn, &fdsBinaryOut,
&fdsBinaryExc, &tStallTime );
}
while ( errno == EINTR );
if ( errno != 0 )
sap_error( "Poll: %s.", strerror( errno ) );
do
{
errno = 0;
select( ( sTopTelnet + 1 ), &fdsTelnetIn, &fdsTelnetOut,
&fdsTelnetExc, &tStallTime );
}
while ( errno == EINTR );
if ( errno != 0 )
sap_error( "Poll: %s.", strerror( errno ) );
do
{
errno = 0;
select( ( sTopMUDComm + 1 ), &fdsMUDCommIn, &fdsMUDCommOut,
&fdsMUDCommExc, &tStallTime );
}
while ( errno == EINTR );
if ( errno != 0 )
sap_error( "Poll: %s.", strerror( errno ) );
/*
* Deal with new connections.
*/
if ( FD_ISSET( sTelnetControl, &fdsTelnetIn ) )
accept_connection( );
if ( FD_ISSET( sBinaryControl, &fdsBinaryIn ) )
accept_binary_connection( );
if ( FD_ISSET( sMUDCommControl, &fdsMUDCommIn ) )
accept_mudcomm_connection( );
for ( pTerm = pTermList; pTerm != NULL; pTerm = pTermNext )
{
pTermNext = pTerm->pNext;
if ( FD_ISSET( pTerm->sTelnetSocket, &fdsTelnetExc ) )
{
FD_CLR( pTerm->sTelnetSocket, &fdsTelnetIn );
FD_CLR( pTerm->sTelnetSocket, &fdsTelnetOut );
pTerm->pOutBuffer[0] = '\0';
clear_binary_transfer( pTerm );
close_connection( &pTerm );
continue;
}
if ( pTerm->iTermType == CLIENT_SAPPHIRE_COMPATIBLE
&& FD_ISSET( pTerm->sBinarySocket, &fdsBinaryExc ) )
{
FD_CLR( pTerm->sBinarySocket, &fdsBinaryIn );
FD_CLR( pTerm->sBinarySocket, &fdsBinaryOut );
pTerm->pOutBuffer[0] = '\0';
clear_binary_transfer( pTerm );
close_connection( &pTerm );
}
}
for ( pMUDComm = pMUDCommList; pMUDComm; pMUDComm = pMUDCommNext )
{
pMUDCommNext = pMUDComm->pNext;
if ( FD_ISSET( pMUDComm->sMUDCommSocket, &fdsMUDCommExc ) )
{
FD_CLR( pMUDComm->sMUDCommSocket, &fdsMUDCommIn );
FD_CLR( pMUDComm->sMUDCommSocket, &fdsMUDCommOut );
close_mudcomm_connection( &pMUDComm );
continue;
}
}
free_buffers( );
/*
* Input.
*/
for ( pTerm = pTermList; pTerm != NULL; pTerm = pTermNext )
{
pTermNext = pTerm->pNext;
pTerm->bFoundCmd = FALSE;
if ( FD_ISSET( pTerm->sTelnetSocket, &fdsTelnetIn )
&& read_string( pTerm ) != TRUE )
{
FD_CLR( pTerm->sTelnetSocket, &fdsTelnetOut );
pTerm->pOutBuffer[0] = '\0';
clear_binary_transfer( pTerm );
close_connection( &pTerm );
continue;
}
/*
* If a terminal has a child running all input is sent
* directly to the child's stdin; no buffering is done.
*/
if ( pTerm->pChildP != NULL )
{
write( pTerm->pChildP->iStdin[1], pTerm->pInBuffer,
strlen( pTerm->pInBuffer ) );
pTerm->pInBuffer[0] = '\0';
continue;
}
if ( pTerm->iTermType == CLIENT_SAPPHIRE_COMPATIBLE
&& FD_ISSET( pTerm->sBinarySocket, &fdsBinaryIn )
&& read_binary_data( pTerm ) != TRUE )
{
FD_CLR( pTerm->sBinarySocket, &fdsBinaryOut );
pTerm->pOutBuffer[0] = '\0';
clear_binary_transfer( pTerm );
close_connection( &pTerm );
continue;
}
/*
* Get the next command.
*/
read_string_buffer( pTerm );
if ( pTerm->pInCommand[0] != '\0' )
{
if ( pTerm->pPageString != NULL )
{
pTerm->bFoundCmd = TRUE;
process_page_string( pTerm, pTerm->pInCommand );
}
else if ( pTerm->ppEditString != NULL )
{
pTerm->bFoundCmd = TRUE;
process_text_editor_string( pTerm,
pTerm->pInCommand );
}
else
{
switch ( pTerm->iConState )
{
case CON_PLAYING :
pTerm->bFoundCmd = TRUE;
process_cmd( ( pTerm->pControlled != NULL
? pTerm->pControlled : pTerm->pChar ),
pTerm->pInCommand );
break;
case CON_NPC_EDITOR :
pTerm->bFoundCmd = TRUE;
process_npc_editor_cmd( pTerm,
pTerm->pInCommand );
break;
case CON_OBJECT_EDITOR:
pTerm->bFoundCmd = TRUE;
process_object_editor_cmd( pTerm,
pTerm->pInCommand );
break;
case CON_ROOM_EDITOR :
pTerm->bFoundCmd = TRUE;
process_room_editor_cmd( pTerm,
pTerm->pInCommand );
break;
case CON_SYSTEM_SHELL :
pTerm->bFoundCmd = TRUE;
process_shell_cmd( pTerm, pTerm->pInCommand );
break;
default :
process_login( pTerm, pTerm->pInCommand );
break;
}
}
if ( pTerm->pInCommand != NULL )
{
pTerm->pInCommand[0] = '\0';
pTermNext = pTerm->pNext;
}
}
}
for ( pMUDComm = pMUDCommList; pMUDComm; pMUDComm = pMUDCommNext )
{
pMUDCommNext = pMUDComm->pNext;
if ( FD_ISSET( pMUDComm->sMUDCommSocket, &fdsMUDCommIn )
&& read_mudcomm_data( pMUDComm ) != TRUE )
{
FD_CLR( pMUDComm->sMUDCommSocket, &fdsMUDCommOut );
close_mudcomm_connection( &pMUDComm );
continue;
}
if ( pMUDComm->iInBufSize == 0 )
continue;
if ( pMUDComm->iConState == MUD_COMM_CON_IDENT )
{
MUD_COMM_DATA *pMUDComm2;
char cBuf[MAX_STRING];
strncpy( cBuf, pMUDComm->pInBuffer, MAX_STRING );
cBuf[MAX_STRING - 1] = '\0';
/*
* Hmm... a MUD with no name? I don't think so.
*/
if ( cBuf[0] == '\0' )
close_mudcomm_connection( &pMUDComm );
else
{
for ( pMUDComm2 = pMUDCommList; pMUDComm2 != NULL;
pMUDComm2 = pMUDComm2->pNext )
{
/*
* We don't want to have two connections from the
* same MUD :)
*/
if ( strcmp( cBuf, pMUDComm2->pMUDName ) == 0 )
{
close_mudcomm_connection( &pMUDComm2 );
break;
}
}
pMUDComm->pMUDName = str_dup( cap_first( cBuf ) );
pMUDComm->iConState = MUD_COMM_CON_READY;
}
}
else if ( pMUDComm->iConState == MUD_COMM_CON_READY )
{
switch ( pMUDComm->pInBuffer[0] )
{
case MUD_COMM_CMD_WIZ_CHANNEL :
mudcomm_cmd_wiz_channel( pMUDComm );
break;
case MUD_COMM_CMD_CHAT_CHANNEL:
mudcomm_cmd_chat_channel( pMUDComm );
break;
case MUD_COMM_CMD_TELL_CHANNEL:
mudcomm_cmd_tell_channel( pMUDComm );
break;
case MUD_COMM_CMD_MAIL :
mudcomm_cmd_mail( pMUDComm );
break;
case MUD_COMM_CMD_WHO :
mudcomm_cmd_who( pMUDComm );
break;
case MUD_COMM_CMD_USERS :
mudcomm_cmd_users( pMUDComm );
break;
case MUD_COMM_CMD_REPLY_MAIL :
mudcomm_cmd_reply_mail( pMUDComm );
break;
case MUD_COMM_CMD_REPLY_TELL :
mudcomm_cmd_reply_tell( pMUDComm );
break;
case MUD_COMM_CMD_REPLY_WHO :
mudcomm_cmd_reply_who( pMUDComm );
break;
case MUD_COMM_CMD_REPLY_USERS :
mudcomm_cmd_reply_users( pMUDComm );
break;
default : break;
}
}
pMUDComm->iInBufSize = 0;
}
free_buffers( );
/*
* If at least PULSE_HEART_BEAT seconds have gone by; update.
*/
if ( tCurrentTime > ( tWaitTime + PULSE_HEART_BEAT - 1 ) )
{
update( );
tWaitTime = tCurrentTime;
}
/*
* Deal with zombie processes.
*/
for ( pChild = pChildren; pChild != NULL; pChild = pChildNext )
{
pChildNext = pChild->pNext;
if ( die_child( pChild, &i ) == TRUE )
{
for ( pTerm = pTermList; pTerm; pTerm = pTerm->pNext )
{
if ( pTerm->pChildP == pChild )
{
pTerm->iConState = pTerm->iConStateOld;
pTerm->pChildP = NULL;
pTerm->bFoundCmd = TRUE;
break;
}
}
}
}
/*
* Output.
*/
for ( pTerm = pTermList; pTerm != NULL; pTerm = pTermNext )
{
pTermNext = pTerm->pNext;
if ( ( pTerm->bFoundCmd != FALSE
|| pTerm->pOutBuffer[0] != '\0' )
&& FD_ISSET( pTerm->sTelnetSocket, &fdsTelnetOut )
&& process_output( pTerm ) == FALSE )
{
pTerm->pOutBuffer[0] = '\0';
clear_binary_transfer( pTerm );
close_connection( &pTerm );
continue;
}
if ( pTerm->iTermType == CLIENT_SAPPHIRE_COMPATIBLE
&& pTerm->pBinData != NULL
&& FD_ISSET( pTerm->sBinarySocket, &fdsBinaryOut ) )
{
if ( write_binary_data( pTerm ) == FALSE )
{
pTerm->pOutBuffer[0] = '\0';
clear_binary_transfer( pTerm );
close_connection( &pTerm );
}
else if ( pTerm->lBinRemainSize == 0 )
clear_binary_transfer( pTerm );
}
}
for ( pMUDComm = pMUDCommList; pMUDComm; pMUDComm = pMUDCommNext )
{
pMUDCommNext = pMUDComm->pNext;
if ( FD_ISSET( pMUDComm->sMUDCommSocket, &fdsMUDCommOut )
&& process_mudcomm_output( pMUDComm ) != TRUE )
{
close_mudcomm_connection( &pMUDComm );
continue;
}
}
/*
* Stall to save CPU time.
*
do
{
errno = 0;
select( 0, NULL, NULL, NULL, &tStallTime );
}
while ( errno == EINTR );
if ( errno != 0 )
sap_error( "Stall: %s.", strerror( errno ) ); */
}
}
static void update( void )
{
free_buffers( );
if ( iCreationCodeTimer > 0 )
iCreationCodeTimer--;
/*
* Put together a new creation code if needed.
*/
if ( iCreationCodeTimer == 0 )
{
int i;
iCreationCodeTimer = 300;
cCreationCode[0] = '\0';
for ( i = 0; i < 6; i++ )
strcat( cCreationCode,
pCreationCodeTable[random_range( 0, CCNP )] );
}
game_update( );
free_buffers( );
}
void process_mucs_cmd( void )
{
struct sigaction sSignalAction;
MUD_COMM_DATA *pMUDComm;
TERM_DATA *pTerm;
char c, c2;
c = getc( stdin );
if ( c != '\n' )
for ( c2 = getc( stdin ); c2 != '\n'; c2 = getc( stdin ) );
switch ( c )
{
case '0' :
fprintf( stderr, "[Main Control Menu]\n"
"\n"
" 1) Exit menu\n"
" 2) Shutdown\n"
"\n"
" 3) Show connected sockets\n"
" 4) Show character creation code\n"
"\n"
" 5) Enter shell (`%s')\n"
#ifdef DEBUG
" 6) Core dump\n"
#endif
, pShellProgramName );
break;
case '1' :
bIsPrompt = FALSE;
/*
* Setup the original handler again.
*/
sSignalAction.sa_handler = &sigint_handler;
sSignalAction.sa_mask = 0;
sSignalAction.sa_flags = 0;
sigaction( SIGINT, &sSignalAction, NULL );
return;
case '2' :
if ( pLogFile != stdout )
fprintf( stderr, "Server shutdown.\n" );
lprintf( "Server shutdown." );
for ( pTerm = pTermList; pTerm != NULL; pTerm = pTerm->pNext )
{
write_string_buffer( pTerm, "\n\rServer shutdown.\n\r" );
tflush( pTerm );
}
exit( 0 );
break;
case '3' :
if ( pTermList == NULL && pMUDCommList == NULL )
{
fprintf( stderr,
"There are currently no connected sockets.\n" );
break;
}
for ( pTerm = pTermList; pTerm != NULL; pTerm = pTerm->pNext )
fprintf( stderr, "[%3d %3d] %-50.50s\n",
pTerm->sTelnetSocket, pTerm->sBinarySocket,
pTerm->pHostname );
for ( pMUDComm = pMUDCommList; pMUDComm != NULL;
pMUDComm = pMUDComm->pNext )
fprintf( stderr, "[%3d ] %-50.50s\n",
pMUDComm->sMUDCommSocket, pMUDComm->pHostname );
break;
case '4' :
if ( iCreationCodeTimer < 0 )
{
fprintf( stderr,
"Character creation codes are not activated.\n" );
break;
}
fprintf( stderr, "The current character creation code is: %s\n",
cCreationCode );
iCreationCodeTimer = 300;
break;
case '5' :
if ( pShellProgramName == NULL )
{
fprintf( stderr, "No shell program is currently setup.\n" );
break;
}
if ( fork( ) == 0 )
{
char *pArg[1] = { NULL };
for ( pTerm = pTermList; pTerm; pTerm = pTerm->pNext )
{
close( pTerm->sTelnetSocket );
if ( pTerm->sBinarySocket > -1 )
close( pTerm->sBinarySocket );
}
for ( pMUDComm = pMUDCommList; pMUDComm != NULL;
pMUDComm = pMUDComm->pNext )
close( pMUDComm->sMUDCommSocket );
if ( sTelnetControl > -1 )
close( sTelnetControl );
if ( sBinaryControl > -1 )
close( sBinaryControl );
if ( sMUDCommControl > -1 )
close( sMUDCommControl );
if ( pLogFile != stdout )
fclose( pLogFile );
if ( execv( pShellProgramName, pArg ) < 0 )
exit( 1 );
}
else
{
int iExitValue;
if ( wait( &iExitValue ) < 0 )
sap_error( "Wait: %s.", strerror( errno ) );
if ( WIFSIGNALED( iExitValue ) )
#ifdef DEBUG
fprintf( stderr,
"Shell program `%s' terminated do to signal %d.\n",
pShellProgramName, WTERMSIG( iExitValue ) );
#else
fprintf( stderr, "The shell program (`%s') failed.\n",
pShellProgramName );
#endif
break;
}
case '\0':
case '\n':
case '\r':
fprintf( stderr, "%s> ", pMUDName );
return;
default :
fprintf( stderr,
"Invalid option. Type `0' for a list of options.\n" );
break;
}
fprintf( stderr, "\n%s> ", pMUDName );
fflush( stderr );
}
void load_config( char *pFilename )
{
FILE *pFile;
FILE *pFile2;
char *pBuf;
char c[2] = { '\0', '\0' };
int i;
bool bFoundMatch;
if ( ( pFile = fopen( pFilename, "r" ) ) == NULL )
sap_fatal( "%s: %s.", pFilename, strerror( errno ) );
iTelnetPort = 4000;
iBinaryPort = 4001;
iMUDCommPort = 4444;
iMaxPlayers = 32;
iMode = MODE_GENERIC;
iMemoryMode = MEMORY_MODE_NORMAL;
iMaxStrBuffers = 256;
lStringSpace = ( 512 * 64 );
iMaxFragments = 64;
lLoopStallTime = 120000;
lEmMaxTime = 200000;
iHashListSize = 1024;
iCreationCodeTimer = -1;
pTempDir = str_dup( "../tmp/" );
pMUDCommFilename = str_dup( "../etc/mudcomm.hosts" );
pShellProgramName = str_dup( "/bin/sh" );
pLogDir = str_dup( "../log/" );
pPlayerDir = str_dup( "../plr/" );
pShellDir = str_dup( "../ssh/" );
pLoginScreenFilename = str_dup( "login.jpg" );
pXWordFilename = str_dup( "../db/xwords.bad" );
pGreetingFilename = str_dup( "../db/greeting.txt" );
pGoodbyeFilename = str_dup( "../db/goodbye.txt" );
pMOTDFilename = str_dup( "../db/motd.txt" );
pEmDir = str_dup( "../db/em_obj/" );
pImageDir = str_dup( "../db/images/" );
pHelpDir = str_dup( "../db/helps/" );
pNPCDir = str_dup( "../db/npcs/" );
pObjectDir = str_dup( "../db/objects/" );
pRoomDir = str_dup( "../db/rooms/" );
pZoneDir = str_dup( "../db/zones/" );
pQuestDataDir = str_dup( "../db/quest_data/" );
pEmUsageFilename = str_dup( "../sav/emfunc.txt" );
pMUDName = str_dup( "Sapphire" );
uDefaultRoom.iNumber = 1000;
iMaxShowCount = 7;
bEmFuncUsage = FALSE;
iEmInterpStackSize = 64;
iEmVarStackSize = 64;
for ( ; ; )
{
bFoundMatch = FALSE;
c[0] = fget_letter( pFile );
if ( c[0] == '/' )
{
if ( getc( pFile ) != '/' )
sap_fatal( "Unknown symbol `%s'.", c );
while ( c[0] != '\n' )
{
if ( feof( pFile ) != 0 )
sap_fatal( "Read file: Unexpected EOF." );
c[0] = getc( pFile );
}
}
else if ( c[0] == '$' )
{
pBuf = ( feof( pFile ) ? "END"
: sfget_word( pFile ) );
if ( str_compare( pBuf, "END" ) == TRUE )
break;
KEY( "TELNET_PORT", iTelnetPort, fget_number( pFile ) );
KEY( "BINARY_PORT", iBinaryPort, fget_number( pFile ) );
KEY( "MUD_COMM_PORT", iMUDCommPort, fget_number( pFile ) );
KEY( "MAX_PLAYERS", iMaxPlayers, fget_number( pFile ) );
KEY( "STRING_BUFFERS",iMaxStrBuffers,
fget_number( pFile ) );
KEY( "STRING_SPACE", lStringSpace, fget_number( pFile ) );
KEY( "MAX_FRAGMENTS", iMaxFragments, fget_number( pFile ) );
KEY( "LOOP_STALL_TIME",
lLoopStallTime, fget_number( pFile ) );
KEY( "HASH_LIST_SIZE",
iHashListSize, fget_number( pFile ) );
SDKEY( "XWORD_FILE", pXWordFilename,
sfget_string( pFile ) );
SDKEY( "GREETING_FILE", pGreetingFilename,
sfget_string( pFile ) );
SDKEY( "GOODBYE_FILE", pGoodbyeFilename,
sfget_string( pFile ) );
SDKEY( "LOGIN_SCREEN", pLoginScreenFilename,
sfget_string( pFile ) );
SDKEY( "MUD_COMM_FILE", pMUDCommFilename,
sfget_string( pFile ) );
SDKEY( "MOTD_FILE", pMOTDFilename, sfget_string( pFile ) );
SDKEY( "TEMP_DIR", pTempDir, sfget_string( pFile ) );
SDKEY( "IMAGE_DIR", pImageDir, sfget_string( pFile ) );
SDKEY( "HELP_DIR", pHelpDir, sfget_string( pFile ) );
SDKEY( "NPC_DIR", pNPCDir, sfget_string( pFile ) );
SDKEY( "OBJECT_DIR", pObjectDir, sfget_string( pFile ) );
SDKEY( "ROOM_DIR", pRoomDir, sfget_string( pFile ) );
SDKEY( "ZONE_DIR", pZoneDir, sfget_string( pFile ) );
SDKEY( "QUEST_DATA_DIR",pQuestDataDir, sfget_string( pFile ) );
SDKEY( "PLAYER_DIR", pPlayerDir, sfget_string( pFile ) );
SDKEY( "LOG_DIR", pLogDir, sfget_string( pFile ) );
SDKEY( "SHELL_DIR", pShellDir, sfget_string( pFile ) );
SDKEY( "SHELL_PROGRAM", pShellProgramName,
sfget_string( pFile ) );
SDKEY( "MUD_NAME", pMUDName, sfget_string( pFile ) );
KEY( "DEFAULT_ROOM", uDefaultRoom.iNumber,
fget_number( pFile ) );
KEY( "MAX_SHOW_COUNT",iMaxShowCount, fget_number( pFile ) );
SDKEY( "EM_DIR", pEmDir,
sfget_string( pFile ) );
KEY( "EM_INTERP_STACK_SIZE", iEmInterpStackSize,
fget_number( pFile ) );
KEY( "EM_VAR_STACK_SIZE", iEmVarStackSize,
fget_number( pFile ) );
KEY( "EM_MAX_TIME", lEmMaxTime,
fget_number( pFile ) );
SDKEY( "EM_USAGE_FILE", pEmUsageFilename,
sfget_string( pFile ) );
if ( str_compare( pBuf, "EM_REPORT_USAGE" ) == TRUE )
{
bFoundMatch = TRUE;
pBuf = sfget_word( pFile );
if ( str_compare( pBuf, "TRUE" ) == TRUE )
bEmFuncUsage = TRUE;
else
bEmFuncUsage = FALSE;
}
if ( str_compare( pBuf, "GAME_MODE" ) == TRUE )
{
bFoundMatch = TRUE;
pBuf = sfget_word( pFile );
if ( str_compare( pBuf, "GENERIC" ) == TRUE )
iMode = MODE_GENERIC;
else if ( str_compare( pBuf, "RPG" ) == TRUE )
{
iMode = MODE_RPG;
iCreationCodeTimer = 0;
}
else
sap_error( "Unknown game mode `%s'.", pBuf );
}
if ( str_compare( pBuf, "MEMORY_MODE" ) == TRUE )
{
bFoundMatch = TRUE;
pBuf = sfget_word( pFile );
if ( str_compare( pBuf, "DISK" ) == TRUE )
iMemoryMode = MEMORY_MODE_DISK;
else if ( str_compare( pBuf, "COMPACT" ) == TRUE )
iMemoryMode = MEMORY_MODE_COMPACT;
else if ( str_compare( pBuf, "NORMAL" ) == TRUE )
iMemoryMode = MEMORY_MODE_NORMAL;
else if ( str_compare( pBuf, "LARGE" ) == TRUE )
iMemoryMode = MEMORY_MODE_LARGE;
else
sap_error( "Unknown memory mode `%s'.", pBuf );
}
if ( bFoundMatch == FALSE )
sap_error( "No match for `%s'.", pBuf );
}
else
sap_fatal( "Unknown symbol `%c'.", c[0] );
}
fclose( pFile );
if ( iMaxFragments <= 0 )
{
sap_warning( "Invalid maximum string fragments (%d).",
iMaxFragments );
iMaxFragments = 1;
}
/*
* See if the shell program name given is valid.
*/
if ( ( pFile2 = fopen( pShellProgramName, "r" ) ) == NULL )
{
sap_warning( "Invalid shell program (`%s').",
pShellProgramName );
if ( pShellProgramName[0] != '\0' )
free_mem( (void **) &pShellProgramName );
}
fclose( pFile2 );
/*
* See if the login image file is a known format.
*/
if ( ( i = get_file_type( pLoginScreenFilename ) ) != FILE_TYPE_GIF
&& i != FILE_TYPE_JPEG )
{
sap_warning( "Unknown image file format." );
str_free( pLoginScreenFilename );
pLoginScreenFilename = EMPTY_STRING;
}
/*
* Check Emerald memory variables.
*/
if ( iEmVarStackSize < 1 )
{
sap_warning( "Invalid Emerald variable stack size (%d).",
iEmVarStackSize );
iEmVarStackSize = 1;
}
if ( iEmInterpStackSize < 1 )
{
sap_warning( "Invalid Emerald interpreter stack size (%d).",
iEmInterpStackSize );
iEmInterpStackSize = 1;
}
}
void load_mudcomm_file( char *pFilename )
{
FILE *pFile;
char *pHostname;
char *pBuf;
char c[2];
int iPort;
if ( ( pFile = open_file( pFilename, "r", FALSE ) ) == NULL )
return;
for ( ; ; )
{
if ( feof( pFile ) != 0 )
break;
c[0] = fget_letter( pFile );
if ( feof( pFile ) != 0 )
break;
if ( c[0] == '#' )
{
do
{
if ( feof( pFile ) != 0 )
sap_fatal( "Read file: Unexpected EOF." );
c[0] = getc( pFile );
}
while ( c[0] != '\n' );
}
else
{
ungetc( c[0], pFile );
pBuf = fget_word( pFile );
pHostname = fget_word( pFile );
iPort = fget_number( pFile );
if ( make_mudcomm_connection( pBuf, pHostname, iPort ) < 0 )
lprintf( "\n [MUD-Comm] Connection failed to: %s %d",
pHostname, iPort );
}
free_buffers( );
}
close_file( pFile );
}
/*
* Deals with reading in all the database files.
*/
void load_database( void )
{
FILE *pFile;
int i;
bStrComparing = TRUE;
/*
* Load XWords.
*/
{
XWORD_DATA *pXWord;
char *pBuf;
pFile = open_file( pXWordFilename, "r", TRUE );
for ( ; ; )
{
pBuf = fget_word( pFile );
if ( pBuf[0] == '$' )
break;
if ( feof( pFile ) != 0 )
sap_fatal( "Read file: Unexpected EOF." );
pXWord = alloc_mem( sizeof( *pXWord ) );
pXWord->pWord = str_dup( pBuf );
pXWord->pNext = pXWordList;
pXWordList = pXWord;
}
close_file( pFile );
}
str_free( pXWordFilename );
/*
* Load the greeting, goodbye and MOTD.
*/
{
pFile = open_file( pGreetingFilename, "r", TRUE );
pGreeting = str_dup( fget_string( pFile ) );
str_free( pGreetingFilename );
close_file( pFile );
pFile = open_file( pGoodbyeFilename, "r", TRUE );
pGoodbye = str_dup( fget_string( pFile ) );
str_free( pGoodbyeFilename );
close_file( pFile );
pFile = open_file( pMOTDFilename, "r", TRUE );
pMOTD = str_dup( fget_string( pFile ) );
str_free( pMOTDFilename );
close_file( pFile );
}
load_em_objects( pEmDir );
error_check( );
em_translate( );
str_free( pEmUsageFilename );
if ( ( i = em_find_func( "main" ) ) >= 0 )
{
stack_init( );
em_call_func( i );
stack_free( );
}
ppNPCIndexList = alloc_mem( sizeof( *ppNPCIndexList )
* iHashListSize );
ppObjIndexList = alloc_mem( sizeof( *ppObjIndexList )
* iHashListSize );
ppRoomIndexList = alloc_mem( sizeof( *ppRoomIndexList )
* iHashListSize );
ppCharList = alloc_mem( sizeof( *ppCharList )
* iHashListSize );
ppObjList = alloc_mem( sizeof( *ppObjList )
* iHashListSize );
/*
* Create the system objects which numbers 1-5 are reserved for.
*/
{
OBJ_INDEX_DATA *pObjIndex;
pObjIndex = alloc_mem( sizeof( *pObjIndex ) );
pObjIndex->iNumber = OBJECT_NUMBER_GOLD;
pObjIndex->iItemType = NUMBER_ITEM_GOLD;
pObjIndex->iLevel = 1;
pObjIndex->iSize = NUMBER_SIZE_MEDIUM;
pObjIndex->iCondition = 100;
pObjIndex->iMaterial = NUMBER_MATERIAL_UNDEFINED;
i = ( OBJECT_NUMBER_GOLD % iHashListSize );
pObjIndex->pNext = ppObjIndexList[i];
ppObjIndexList[i] = pObjIndex;
pObjIndex = alloc_mem( sizeof( *pObjIndex ) );
pObjIndex->iNumber = OBJECT_NUMBER_CORPSE;
pObjIndex->iItemType = NUMBER_ITEM_CORPSE;
pObjIndex->iLevel = 1;
pObjIndex->iSize = NUMBER_SIZE_MEDIUM;
pObjIndex->iCondition = 100;
pObjIndex->iMaterial = NUMBER_MATERIAL_UNDEFINED;
i = ( OBJECT_NUMBER_CORPSE % iHashListSize );
pObjIndex->pNext = ppObjIndexList[i];
ppObjIndexList[i] = pObjIndex;
}
load_quest_data( pQuestDataDir );
load_helps( pHelpDir );
load_npcs( pNPCDir );
load_objects( pObjectDir );
load_rooms( pRoomDir );
load_zones( pZoneDir );
#if 0
str_free( pHelpDir ); /* OLC needs this strings :) */
str_free( pNPCDir );
str_free( pObjectDir );
str_free( pRoomDir );
str_free( pZoneDir );
str_free( pQuestDataDir );
#endif
translate_numbers( );
uDefaultRoom.pRoom = get_room_index( ( i = uDefaultRoom.iNumber ) );
if ( uDefaultRoom.pRoom == NULL )
sap_fatal( "No such room with the number `%d' for default.", i );
bStrComparing = FALSE;
}
/*
* Load Emerald object files.
*/
void load_em_objects( char *pDirName )
{
struct dirent *pDirEntry;
DIR *pDir;
DIR *pDir2;
char cBuf[1024];
if ( ( pDir = opendir( pDirName ) ) == NULL )
sap_fatal( "Open directory: %s: %s.", pDirName,
strerror( errno ) );
if ( readdir( pDir ) == NULL )
sap_fatal( "Open directory: %s: Not a directory.", pDirName );
readdir( pDir );
while ( ( pDirEntry = readdir( pDir ) ) != NULL )
{
strcpy( cBuf, pDirName );
strcat( cBuf, pDirEntry->d_name );
/*
* If this is a directory, recurse into it.
*/
if ( ( pDir2 = opendir( cBuf ) ) != NULL )
{
if ( readdir( pDir2 ) != NULL )
{
strcat( cBuf, "/" );
load_em_objects( cBuf );
continue;
}
closedir( pDir2 );
}
if ( em_load_obj_file( cBuf, FALSE ) < 0 )
{
print_error( );
/* exit( 1 ); */
}
}
closedir( pDir );
}
/*
* Load in all the help pages.
*/
void load_helps( char *pDirName )
{
struct dirent *pDirEntry;
HELP_DATA *pNewHelp;
FILE *pFile;
DIR *pDir;
DIR *pDir2;
char cBuf[1024];
char *pBuf;
char c;
int i;
if ( ( pDir = opendir( pDirName ) ) == NULL )
sap_fatal( "Open directory: %s: %s.", pDirName,
strerror( errno ) );
if ( readdir( pDir ) == NULL )
sap_fatal( "Open directory: %s: Not a directory.", pDirName );
readdir( pDir );
while ( ( pDirEntry = readdir( pDir ) ) != NULL )
{
strcpy( cBuf, pDirName );
strcat( cBuf, pDirEntry->d_name );
/*
* If this is a directory, recurse into it.
*/
if ( ( pDir2 = opendir( cBuf ) ) != NULL )
{
if ( readdir( pDir2 ) != NULL )
{
strcat( cBuf, "/" );
load_helps( cBuf );
continue;
}
closedir( pDir2 );
}
pFile = open_file( cBuf, "r", TRUE );
/*
* Don't bother with helps that have no keywords.
*/
if ( ( c = fget_letter( pFile ) ) == '#' )
{
close_file( pFile );
continue;
}
else
ungetc( c, pFile );
i = 0;
pNewHelp = alloc_mem( sizeof( *pNewHelp ) );
for ( i = 0; ; i++ )
{
if ( ( c = fget_letter( pFile ) ) == '#' )
break;
else
ungetc( c, pFile );
pBuf = fget_string( pFile );
if ( get_help( pBuf ) != NULL )
sap_fatal( "Help keyword `%s' duplicated.", pBuf );
pNewHelp->pKeywords = realloc_mem( pNewHelp->pKeywords,
( sizeof( string ) * ( i + 2 ) ) );
pNewHelp->pKeywords[i] = save_string( pBuf );
pNewHelp->pKeywords[i + 1] = NULL;
}
pNewHelp->iLevel = fget_number( pFile );
pNewHelp->sText = save_string( fget_string( pFile ) );
fget_string_2( pFile, '[', ']' ); /* temp */
pNewHelp->pNext = pHelpList;
pHelpList = pNewHelp;
close_file( pFile );
free_buffers( );
}
closedir( pDir );
}
/*
* Load in all the NPCs (Non-Player Characters).
*/
void load_npcs( char *pDirName )
{
struct dirent *pDirEntry;
NPC_INDEX_DATA *pNewNPCIndex;
FILE *pFile;
DIR *pDir;
DIR *pDir2;
char cBuf[1024];
char *pBuf;
int iNumber = 0;
int i, i2;
bool bFoundMatch;
if ( ( pDir = opendir( pDirName ) ) == NULL )
sap_fatal( "Open directory: %s: %s.", pDirName,
strerror( errno ) );
if ( readdir( pDir ) == NULL )
sap_fatal( "Open directory: %s: Not a directory.", pDirName );
readdir( pDir );
while ( ( pDirEntry = readdir( pDir ) ) != NULL )
{
strcpy( cBuf, pDirName );
strcat( cBuf, pDirEntry->d_name );
/*
* If this is a directory, recurse into it.
*/
if ( ( pDir2 = opendir( cBuf ) ) != NULL )
{
if ( readdir( pDir2 ) != NULL )
{
strcat( cBuf, "/" );
load_npcs( cBuf );
continue;
}
closedir( pDir2 );
}
pFile = open_file( cBuf, "r", TRUE );
if ( fget_letter( pFile ) != '#' )
sap_fatal( "Syntax error in file." );
pBuf = fget_word( pFile );
if ( is_number( pBuf ) == TRUE )
{
iNumber = atoi( pBuf );
if ( iNumber <= 5 || iNumber > MAX_INDEX_NUMBER )
sap_fatal( "Illegal NPC number `%d'.", iNumber );
if ( get_npc_index( iNumber ) != NULL )
sap_fatal( "More then one NPC with the number `%d'.",
iNumber );
}
else if ( strcmp( pBuf, "COMMENT" ) == 0 )
{
close_file( pFile );
continue;
}
else
sap_fatal( "Unknown symbol `%s'.", pBuf );
pNewNPCIndex = alloc_mem( sizeof( *pNewNPCIndex ) );
zero_out( pNewNPCIndex, sizeof( *pNewNPCIndex ) );
pNewNPCIndex->iNumber = iNumber;
pNewNPCIndex->pNameList = alloc_mem( sizeof( string ) * 2 );
pNewNPCIndex->pNameList[0] = EMPTY_STRING;
pNewNPCIndex->pNameList[1] = NULL;
pNewNPCIndex->sShortDesc = save_string( "(no short description)" );
for ( i = 0; i < 5; i++ )
pNewNPCIndex->sDescs[i] = save_string( "(no description)" );
pNewNPCIndex->sLongDesc = save_string( "(no long description)" );
pNewNPCIndex->iLevel = 1;
pNewNPCIndex->iRace = rRaceTable[0].iNumber;
pNewNPCIndex->fActFlags = rRaceTable[0].fActFlags;
pNewNPCIndex->iSex = snSexTable[0].iNumber;
pNewNPCIndex->iHairColor = rRaceTable[0].iHairColors[0];
pNewNPCIndex->iEyeColor = rRaceTable[0].iEyeColors[0];
pNewNPCIndex->iHeight = rRaceTable[0].iUpperLowerHeights[1];
pNewNPCIndex->iWeight = rRaceTable[0].iUpperLowerWeights[1];
pNewNPCIndex->iPosition = NUMBER_POSITION_STANDING;
for ( i = 0; i < 3; i++ )
{
pNewNPCIndex->VarStats.iStatStr[i] = 0;
pNewNPCIndex->VarStats.iStatInt[i] = 0;
pNewNPCIndex->VarStats.iStatWis[i] = 0;
pNewNPCIndex->VarStats.iStatDex[i] = 0;
pNewNPCIndex->VarStats.iStatCon[i] = 0;
pNewNPCIndex->VarStats.iStatCha[i] = 0;
pNewNPCIndex->VarStats.iStatLuc[i] = 0;
pNewNPCIndex->VarStats.iStatHP[i] = 0;
pNewNPCIndex->VarStats.iStatMP[i] = 0;
pNewNPCIndex->VarStats.iStatMV[i] = 0;
}
for ( ; ; )
{
bFoundMatch = FALSE;
pBuf = fget_word_2( pFile );
if ( pBuf[0] == '\0' )
sap_fatal( "Error in file." );
if ( pBuf[0] == '*' )
{
char c;
do
{
if ( feof( pFile ) != 0 )
sap_fatal( "Read file: Unexpected EOF." );
c = getc( pFile );
if ( c == '\n' )
lCurrentLine++;
}
while ( c != '\n' );
continue;
}
if ( str_compare( pBuf, "END" ) == TRUE )
break;
for ( i = 0; npclLoadTable[i].pField[0] != '\0'; i++ )
{
if ( str_compare( pBuf, npclLoadTable[i].pField ) == TRUE )
{
( *npclLoadTable[i].pFunc ) ( pNewNPCIndex, pFile );
bFoundMatch = TRUE;
}
}
if ( bFoundMatch == FALSE )
sap_fatal( "NPC %d: No match for `%s'.", iNumber, pBuf );
if ( fget_letter( pFile ) != ';' )
sap_fatal( "NPC %d: Missing semi-colon for `%s'.",
iNumber, pBuf );
}
iNumber %= iHashListSize;
pNewNPCIndex->pNext = ppNPCIndexList[iNumber];
ppNPCIndexList[iNumber] = pNewNPCIndex;
i = get_race_index( pNewNPCIndex->iRace );
for ( i2 = 0; rRaceTable[i].iHairColors[i2] != 0; i2++ )
{
if ( rRaceTable[i].iHairColors[i2]
== pNewNPCIndex->iHairColor )
break;
}
if ( rRaceTable[i].iHairColors[i2] == 0 )
{
sap_warning( "NPC %d: Invalid hair color for race.",
pNewNPCIndex->iNumber );
pNewNPCIndex->iHairColor = rRaceTable[i].iHairColors[0];
}
for ( i2 = 0; rRaceTable[i].iEyeColors[i2] != 0; i2++ )
{
if ( rRaceTable[i].iEyeColors[i2] == pNewNPCIndex->iEyeColor )
break;
}
if ( rRaceTable[i].iEyeColors[i2] == 0 )
{
sap_warning( "NPC %d: Invalid eye color for race.",
pNewNPCIndex->iNumber );
pNewNPCIndex->iEyeColor = rRaceTable[i].iEyeColors[0];
}
if ( pNewNPCIndex->iHeight > rRaceTable[i].iUpperLowerHeights[0] )
{
sap_warning( "NPC %d: Height greater then race limit.",
pNewNPCIndex->iNumber );
pNewNPCIndex->iHeight = rRaceTable[i].iUpperLowerHeights[0];
}
else if ( pNewNPCIndex->iHeight
< rRaceTable[i].iUpperLowerHeights[1] )
{
sap_warning( "NPC %d: Height less then race limit.",
pNewNPCIndex->iNumber );
pNewNPCIndex->iHeight = rRaceTable[i].iUpperLowerHeights[1];
}
if ( pNewNPCIndex->iWeight > rRaceTable[i].iUpperLowerWeights[0] )
{
sap_warning( "NPC %d: Weight greater then race limit.",
pNewNPCIndex->iNumber );
pNewNPCIndex->iWeight = rRaceTable[i].iUpperLowerWeights[0];
}
else if ( pNewNPCIndex->iWeight
< rRaceTable[i].iUpperLowerWeights[1] )
{
sap_warning( "NPC %d: Weight less then race limit.",
pNewNPCIndex->iNumber );
pNewNPCIndex->iWeight = rRaceTable[i].iUpperLowerWeights[1];
}
close_file( pFile );
free_buffers( );
}
closedir( pDir );
}
/*
* Load in all the objects/items.
*/
void load_objects( char *pDirName )
{
struct dirent *pDirEntry;
OBJ_INDEX_DATA *pNewObjIndex;
FILE *pFile;
DIR *pDir;
DIR *pDir2;
char cBuf[1025];
char *pBuf;
int iNumber = 0;
int i;
bool bFoundMatch;
if ( ( pDir = opendir( pDirName ) ) == NULL )
sap_fatal( "Open directory: %s: %s.", pDirName,
strerror( errno ) );
if ( readdir( pDir ) == NULL )
sap_fatal( "Open directory: %s: Not a directory.", pDirName );
readdir( pDir );
while ( ( pDirEntry = readdir( pDir ) ) != NULL )
{
strcpy( cBuf, pDirName );
strcat( cBuf, pDirEntry->d_name );
/*
* If this is a directory, recurse into it.
*/
if ( ( pDir2 = opendir( cBuf ) ) != NULL )
{
if ( readdir( pDir2 ) != NULL )
{
strcat( cBuf, "/" );
load_objects( cBuf );
continue;
}
closedir( pDir2 );
}
pFile = open_file( cBuf, "r", TRUE );
if ( fget_letter( pFile ) != '#' )
sap_fatal( "Syntax error in file." );
pBuf = fget_word( pFile );
if ( is_number( pBuf ) == TRUE )
{
iNumber = atoi( pBuf );
if ( iNumber <= 5 || iNumber > MAX_INDEX_NUMBER )
sap_fatal( "Illegal object number `%d'.", iNumber );
if ( get_object_index( iNumber ) != NULL )
sap_fatal( "More then one object with the number `%d'.",
iNumber );
}
else if ( strcmp( pBuf, "COMMENT" ) == 0 )
{
close_file( pFile );
continue;
}
else
sap_fatal( "Unknown symbol `%s'.", pBuf );
pNewObjIndex = alloc_mem( sizeof( *pNewObjIndex ) );
zero_out( pNewObjIndex, sizeof( *pNewObjIndex ) );
pNewObjIndex->iNumber = iNumber;
pNewObjIndex->pNameList = alloc_mem( sizeof( string ) * 2 );
pNewObjIndex->pNameList[0] = EMPTY_STRING;
pNewObjIndex->pNameList[1] = NULL;
pNewObjIndex->sShortDesc = save_string( "(no short description)" );
pNewObjIndex->sDesc = save_string( "(no description)" );
pNewObjIndex->sLongDesc = save_string( "(no long description)" );
pNewObjIndex->iItemType = snItemTypeTable[0].iNumber;
pNewObjIndex->iLevel = 1;
pNewObjIndex->iSize = NUMBER_SIZE_MEDIUM;
pNewObjIndex->iCondition = 100;
pNewObjIndex->iMaterial = snMaterialTable[0].iNumber;
pNewObjIndex->sValue = EMPTY_STRING;
for ( ; ; )
{
bFoundMatch = FALSE;
pBuf = fget_word_2( pFile );
if ( pBuf[0] == '\0' )
sap_fatal( "Error in file." );
if ( pBuf[0] == '*' )
{
char c;
do
{
if ( feof( pFile ) != 0 )
sap_fatal( "Read file: Unexpected EOF." );
c = getc( pFile );
if ( c == '\n' )
lCurrentLine++;
}
while ( c != '\n' );
continue;
}
if ( str_compare( pBuf, "END" ) == TRUE )
break;
for ( i = 0; olLoadTable[i].pField[0] != '\0'; i++ )
{
if ( str_compare( pBuf, olLoadTable[i].pField ) == TRUE )
{
( *olLoadTable[i].pFunc ) ( pNewObjIndex, pFile );
bFoundMatch = TRUE;
}
}
if ( bFoundMatch == FALSE )
sap_fatal( "Object %d: No match for `%s'.", iNumber,
pBuf );
if ( fget_letter( pFile ) != ';' )
sap_fatal( "Object %d: Missing semi-colon for `%s'.",
iNumber, pBuf );
}
if ( pNewObjIndex->iItemType != NUMBER_ITEM_LIGHT
&& IS_SET( pNewObjIndex->fObjFlags, FLAG_OBJECT_LIT ) )
{
sap_warning( "Object %d: Lit flag set on object that is "
"not of type `Light'.", pNewObjIndex->iNumber );
REMOVE_FLAG( pNewObjIndex->fObjFlags, FLAG_OBJECT_LIT );
}
iNumber %= iHashListSize;
pNewObjIndex->pNext = ppObjIndexList[iNumber];
ppObjIndexList[iNumber] = pNewObjIndex;
close_file( pFile );
free_buffers( );
}
closedir( pDir );
}
/*
* Load in all the rooms.
*/
void load_rooms( char *pDirName )
{
struct dirent *pDirEntry;
ROOM_INDEX_DATA *pNewRoomIndex;
FILE *pFile;
DIR *pDir;
DIR *pDir2;
char cBuf[1025];
char *pBuf;
int iNumber = 0;
int i;
bool bFoundMatch;
if ( ( pDir = opendir( pDirName ) ) == NULL )
sap_fatal( "Open directory: %s: %s.", pDirName,
strerror( errno ) );
if ( readdir( pDir ) == NULL )
sap_fatal( "Open directory: %s: Not a directory.", pDirName );
readdir( pDir );
while ( ( pDirEntry = readdir( pDir ) ) != NULL )
{
strcpy( cBuf, pDirName );
strcat( cBuf, pDirEntry->d_name );
/*
* If this is a directory, recurse into it.
*/
if ( ( pDir2 = opendir( cBuf ) ) != NULL )
{
if ( readdir( pDir2 ) != NULL )
{
strcat( cBuf, "/" );
load_rooms( cBuf );
continue;
}
closedir( pDir2 );
}
pFile = open_file( cBuf, "r", TRUE );
if ( fget_letter( pFile ) != '#' )
sap_fatal( "Syntax error in file." );
pBuf = fget_word( pFile );
if ( is_number( pBuf ) == TRUE )
{
iNumber = atoi( pBuf );
if ( iNumber <= 5 || iNumber > MAX_INDEX_NUMBER )
sap_fatal( "Illegal room number `%d'.", iNumber );
if ( get_room_index( iNumber ) != NULL )
sap_fatal( "More then one room with the number `%d'.",
iNumber );
}
else if ( strcmp( pBuf, "COMMENT" ) == 0 )
{
close_file( pFile );
continue;
}
else
sap_fatal( "Unknown symbol `%s'.", pBuf );
pNewRoomIndex = alloc_mem( sizeof( *pNewRoomIndex ) );
zero_out( pNewRoomIndex, sizeof( *pNewRoomIndex ) );
pNewRoomIndex->iNumber = iNumber;
for ( i = 0; i < 10; i++ )
{
pNewRoomIndex->sDirDescs[i] = EMPTY_STRING;
pNewRoomIndex->eExits[i].pDoorNames = alloc_mem( ( sizeof(
string ) * 2 ) );
pNewRoomIndex->eExits[i].pDoorNames[0] = EMPTY_STRING;
pNewRoomIndex->eExits[i].pDoorNames[1] = NULL;
pNewRoomIndex->eExits[i].sFound = EMPTY_STRING;
}
pNewRoomIndex->sImageFilename = EMPTY_STRING;
pNewRoomIndex->sTitle = save_string( "(no title)" );
pNewRoomIndex->sDesc = save_string( "(no description)" );
pNewRoomIndex->iSectorType = snSectorTable[0].iNumber;
pNewRoomIndex->iTemperature = 60;
for ( ; ; )
{
bFoundMatch = FALSE;
pBuf = fget_word_2( pFile );
if ( pBuf[0] == '\0' )
sap_fatal( "Error in file." );
if ( pBuf[0] == '*' )
{
char c;
do
{
if ( feof( pFile ) != 0 )
sap_fatal( "Read file: Unexpected EOF." );
c = getc( pFile );
if ( c == '\n' )
lCurrentLine++;
}
while ( c != '\n' );
continue;
}
if ( str_compare( pBuf, "END" ) == TRUE )
break;
for ( i = 0; rlLoadTable[i].pField[0] != '\0'; i++ )
{
if ( str_compare( pBuf, rlLoadTable[i].pField ) == TRUE )
{
( *rlLoadTable[i].pFunc ) ( pNewRoomIndex, pFile );
bFoundMatch = TRUE;
}
}
if ( bFoundMatch == FALSE )
sap_fatal( "Room %d: No match for `%s'.", iNumber,
pBuf );
if ( fget_letter( pFile ) != ';' )
sap_fatal( "Room %d: Missing semi-colon for `%s'.",
iNumber, pBuf );
}
iNumber %= iHashListSize;
pNewRoomIndex->pNext = ppRoomIndexList[iNumber];
ppRoomIndexList[iNumber] = pNewRoomIndex;
close_file( pFile );
free_buffers( );
}
closedir( pDir );
}
/*
* Load in all the zone data.
*/
void load_zones( char *pDirName )
{
struct dirent *pDirEntry;
ZONE_DATA *pNewZone;
FILE *pFile;
DIR *pDir;
DIR *pDir2;
char cBuf[1025];
char *pBuf;
int i;
bool bFoundMatch;
if ( ( pDir = opendir( pDirName ) ) == NULL )
sap_fatal( "Open directory: %s: %s.", pDirName,
strerror( errno ) );
if ( readdir( pDir ) == NULL )
sap_fatal( "Open directory: %s: Not a directory.", pDirName );
readdir( pDir );
while ( ( pDirEntry = readdir( pDir ) ) != NULL )
{
strcpy( cBuf, pDirName );
strcat( cBuf, pDirEntry->d_name );
/*
* If this is a directory, recurse into it.
*/
if ( ( pDir2 = opendir( cBuf ) ) != NULL )
{
if ( readdir( pDir2 ) != NULL )
{
strcat( cBuf, "/" );
load_zones( cBuf );
continue;
}
closedir( pDir2 );
}
pFile = open_file( cBuf, "r", TRUE );
if ( fget_letter( pFile ) != '#' )
sap_fatal( "Syntax error in file." );
pBuf = fget_string( pFile );
pNewZone = alloc_mem( sizeof( *pNewZone ) );
zero_out( pNewZone, sizeof( *pNewZone ) );
pNewZone->sName = save_string( pBuf );
pNewZone->sAuthor = EMPTY_STRING;
for ( ; ; )
{
bFoundMatch = FALSE;
pBuf = fget_word_2( pFile );
if ( pBuf[0] == '\0' )
sap_fatal( "Error in file." );
if ( pBuf[0] == '*' )
{
char c;
do
{
if ( feof( pFile ) != 0 )
sap_fatal( "Read file: Unexpected EOF." );
c = getc( pFile );
if ( c == '\n' )
lCurrentLine++;
}
while ( c != '\n' );
continue;
}
if ( str_compare( pBuf, "END" ) == TRUE )
break;
for ( i = 0; zlLoadTable[i].pField[0] != '\0'; i++ )
{
if ( str_compare( pBuf, zlLoadTable[i].pField ) == TRUE )
{
( *zlLoadTable[i].pFunc ) ( pNewZone, pFile );
bFoundMatch = TRUE;
}
}
if ( bFoundMatch == FALSE )
sap_fatal( "Zone `%s': No match for `%s'.",
pNewZone->sName, pBuf );
if ( fget_letter( pFile ) != ';' )
sap_fatal( "Zone `%s': Missing semi-colon for `%s'.",
pNewZone->sName, pBuf );
}
pNewZone->pNext = pZoneList;
pZoneList = pNewZone;
close_file( pFile );
free_buffers( );
}
closedir( pDir );
}
/*
* Load in all the quest data.
*/
void load_quest_data( char *pDirName )
{
struct dirent *pDirEntry;
QUEST_DATA *pNewQuestData;
QUEST_VAR_DATA *pVar;
QUEST_VAR_DATA *pVar2;
FILE *pFile;
DIR *pDir;
DIR *pDir2;
char cBuf[1025];
char *pBuf;
char *pBuf2;
int i;
if ( ( pDir = opendir( pDirName ) ) == NULL )
sap_fatal( "Open directory: %s: %s.", pDirName,
strerror( errno ) );
if ( readdir( pDir ) == NULL )
sap_fatal( "Open directory: %s: Not a directory.", pDirName );
readdir( pDir );
while ( ( pDirEntry = readdir( pDir ) ) != NULL )
{
strcpy( cBuf, pDirName );
strcat( cBuf, pDirEntry->d_name );
/*
* If this is a directory, recurse into it.
*/
if ( ( pDir2 = opendir( cBuf ) ) != NULL )
{
if ( readdir( pDir2 ) != NULL )
{
strcat( cBuf, "/" );
load_zones( cBuf );
continue;
}
closedir( pDir2 );
}
pFile = open_file( cBuf, "r", TRUE );
pBuf = fget_word( pFile );
if ( fget_letter( pFile ) != '{' )
sap_fatal( "Syntax error in file." );
if ( !isalpha( pBuf[0] ) && pBuf[0] != '_' )
sap_fatal( "Illegal quest data name `%s'.", pBuf );
for ( i = 0; pBuf[i] != '\0'; i++ )
{
if ( !isalnum( pBuf[i] ) && pBuf[i] != '_' )
sap_fatal( "Illegal quest data name `%s'.", pBuf );
}
for ( pNewQuestData = pQuestDataList; pNewQuestData != NULL;
pNewQuestData = pNewQuestData->pNext )
{
if ( strcmp( pNewQuestData->sName, pBuf ) == 0 )
sap_fatal( "Quest data `%s' multiply defined.", pBuf );
}
pNewQuestData = alloc_mem( sizeof( *pNewQuestData ) );
zero_out( pNewQuestData, sizeof( *pNewQuestData ) );
pNewQuestData->sName = save_string( pBuf );
for ( ; ; )
{
pBuf = fget_word_2( pFile );
if ( pBuf[0] == '\0' )
sap_fatal( "Error in file." );
if ( pBuf[0] == '*' )
{
char c;
do
{
if ( feof( pFile ) != 0 )
sap_fatal( "Read file: Unexpected EOF." );
c = getc( pFile );
if ( c == '\n' )
lCurrentLine++;
}
while ( c != '\n' );
continue;
}
if ( str_compare( pBuf, "}" ) == TRUE )
break;
pVar = alloc_mem( sizeof( *pVar ) );
zero_out( pVar, sizeof( *pVar ) );
if ( str_compare( pBuf, "number" ) == TRUE )
pVar->iType = NUMBER_VAR_NUMBER;
else if ( str_compare( pBuf, "string" ) == TRUE )
pVar->iType = NUMBER_VAR_STRING;
else if ( str_compare( pBuf, "character_pointer" ) == TRUE )
pVar->iType = NUMBER_VAR_POINTER_CHAR;
else if ( str_compare( pBuf, "object_pointer" ) == TRUE )
pVar->iType = NUMBER_VAR_POINTER_OBJ;
else if ( str_compare( pBuf, "room_pointer" ) == TRUE )
pVar->iType = NUMBER_VAR_POINTER_ROOM;
else
sap_fatal( "Quest data `%s': Unknown variable type `%s'.",
pNewQuestData->sName, pBuf );
pBuf2 = fget_word_2( pFile );
if ( pBuf2[0] == '\0' || ( !isalpha( pBuf2[0] )
&& pBuf2[0] != '_' ) )
{
free_mem( (void **) &pVar );
sap_error(
"Quest data `%s': Illegal variable name for `%s'.",
pNewQuestData->sName, pBuf );
continue;
}
for ( i = 0; pBuf2[i] != '\0'; i++ )
{
if ( !isalnum( pBuf2[i] ) && pBuf2[i] != '_' )
{
free_mem( (void **) &pVar );
sap_error(
"Quest data `%s': Illegal variable name for `%s'.",
pNewQuestData->sName, pBuf );
break;
}
}
if ( pBuf2[i] != '\0' )
continue;
for ( pVar2 = pNewQuestData->pVars; pVar2 != NULL;
pVar2 = pVar2->pNext )
{
if ( strcmp( pVar2->sName, pBuf2 ) == 0 )
{
free_mem( (void **) &pVar );
sap_warning( "Quest data `%s': "
"More then one variable with the name `%s'.",
pNewQuestData->sName, pBuf );
break;
}
}
if ( pVar2 != NULL )
continue;
pVar->sName = save_string( pBuf2 );
if ( pVar->iType == NUMBER_VAR_STRING )
pVar->uData.s = EMPTY_STRING;
pVar->pNext = pNewQuestData->pVars;
pNewQuestData->pVars = pVar;
if ( fget_letter( pFile ) != ';' )
sap_fatal( "Quest data `%s': Missing semi-colon for `%s'.",
pNewQuestData->sName, pBuf );
}
pNewQuestData->pNext = pQuestDataList;
pQuestDataList = pNewQuestData;
close_file( pFile );
free_buffers( );
}
closedir( pDir );
}
/*
* After all the NPCs, objects and rooms are loaded
* this function is called to go through and translate
* all the numbers that are referencing other NPCs,
* objects or rooms into pointers to the actaul structures.
* This function also performs inititial resets.
*/
static void translate_numbers( void )
{
NPC_INDEX_DATA *pNPCIndex;
OBJ_INDEX_DATA *pObjIndex;
ROOM_INDEX_DATA *pRoom;
NPC_RESET_DATA *pNPCReset;
NPC_RESET_DATA *pPrevNPCReset;
OBJ_RESET_DATA *pObjReset;
OBJ_RESET_DATA *pPrevObjReset;
CHAR_DATA *pChar;
OBJ_DATA *pObj;
OBJ_DATA *pTemp;
OBJ_DATA *pPrev;
int i;
for ( i = 0; i < iHashListSize; i++ )
{
for ( pNPCIndex = ppNPCIndexList[i]; pNPCIndex != NULL;
pNPCIndex = pNPCIndex->pNext )
npc_inherit( pNPCIndex );
}
for ( i = 0; i < iHashListSize; i++ )
{
for ( pObjIndex = ppObjIndexList[i]; pObjIndex != NULL;
pObjIndex = pObjIndex->pNext )
obj_inherit( pObjIndex );
}
for ( i = 0; i < iHashListSize; i++ )
{
for ( pRoom = ppRoomIndexList[i]; pRoom; pRoom = pRoom->pNext )
{
int i2;
for ( i2 = 0; i2 < 10; i2++ )
fix_exit( pRoom, i2 );
}
}
for ( i = 0; i < iHashListSize; i++ )
{
for ( pRoom = ppRoomIndexList[i]; pRoom; pRoom = pRoom->pNext )
{
pPrevNPCReset = NULL;
pPrevObjReset = NULL;
for ( pNPCReset = pRoom->pNPCResets; pNPCReset != NULL; )
{
if ( ( pNPCIndex =
get_npc_index( pNPCReset->u1.iNumber ) ) == NULL )
sap_fatal( "Room %d: No NPC with the number `%d'.",
pRoom->iNumber, pNPCReset->u1.iNumber );
pNPCReset->u1.pNPCIndex = pNPCIndex;
pNPCReset->bAlive = TRUE;
pNPCReset->iResetTimer = -1;
pChar = new_npc( pNPCIndex, NULL );
pChar->pNPCData->pReset = pNPCReset;
pChar->pInven = translate_obj_resets(
pNPCReset->pInvenResets,
pRoom );
for ( pPrev = NULL, pTemp = pChar->pInven; pTemp != NULL;
pPrev = pTemp, pTemp = pTemp->pNextContent );
pTemp = translate_obj_resets(
pNPCReset->pEqResets, pRoom );
if ( pPrev == NULL )
pChar->pInven = pTemp;
else
pPrev->pNextContent = pTemp;
for ( pTemp = pChar->pInven; pTemp != NULL;
pTemp = pTemp->pNextContent )
pTemp->pCarriedBy = pChar;
char_to_room( pChar, pRoom );
#if 0
/*
* Delete resets that have reset times lower then zero.
* ...
* We don't delete one-time only resets anymore because
* we need them for OLC saving.
*/
if ( pNPCReset->iResetTime < 0 )
{
if ( pPrevNPCReset == NULL )
{
pRoom->pNPCResets = pNPCReset->pNext;
free_obj_reset_list( &pNPCReset->pInvenResets );
free_obj_reset_list( &pNPCReset->pEqResets );
free_mem( (void **) &pNPCReset );
pNPCReset = pRoom->pNPCResets;
}
else
{
pPrevNPCReset->pNext = pNPCReset->pNext;
free_obj_reset_list( &pNPCReset->pInvenResets );
free_obj_reset_list( &pNPCReset->pEqResets );
free_mem( (void **) &pNPCReset );
pNPCReset = pPrevNPCReset->pNext;
}
pChar->pNPCData->pReset = NULL;
pPrevNPCReset = pNPCReset;
}
else
#endif
{
pPrevNPCReset = pNPCReset;
pNPCReset = pNPCReset->pNext;
}
}
for ( pObjReset = pRoom->pObjResets; pObjReset != NULL; )
{
if ( ( pObjIndex =
get_object_index( pObjReset->u1.iNumber ) ) == NULL )
sap_fatal(
"Room %d: No object with the number `%d'.",
pRoom->iNumber, pObjReset->u1.iNumber );
pObjReset->u1.pObjIndex = pObjIndex;
pObjReset->bAlive = TRUE;
pObjReset->iResetTimer = -1;
if ( pObjIndex->iItemType != NUMBER_ITEM_CONTAINER
&& pObjReset->pContentResets != NULL )
{
sap_warning(
"Room %d: Object placed in non-container object.",
pRoom->iNumber );
free_obj_reset_list( &pObjReset->pContentResets );
}
pObj = new_object( pObjIndex, NULL );
pObj->pReset = pObjReset;
pObj->pContains = translate_obj_resets(
pObjReset->pContentResets,
pRoom );
for ( pTemp = pObj->pContains; pTemp != NULL;
pTemp = pTemp->pNextContent )
pTemp->pInObj = pObj;
obj_to_room( pObj, pRoom );
#if 0
/*
* Delete resets that have reset times lower then zero.
* This makes one-time only objects possible :)
* ...
* We don't delete one-time only resets anymore because
* we need them for OLC saving.
*/
if ( pObjReset->iResetTime < 0 )
{
if ( pPrevObjReset == NULL )
{
pRoom->pObjResets = pObjReset->pNext;
free_obj_reset_list( &pObjReset->pContentResets );
free_mem( (void **) &pObjReset );
pObjReset = pRoom->pObjResets;
}
else
{
pPrevObjReset->pNext = pObjReset->pNext;
free_obj_reset_list( &pObjReset->pContentResets );
free_mem( (void **) &pObjReset );
pObjReset = pPrevObjReset->pNext;
}
pObj->pReset = NULL;
pPrevObjReset = pObjReset;
}
else
#endif
{
pPrevObjReset = pObjReset;
pObjReset = pObjReset->pNext;
}
}
}
}
}
static OBJ_DATA *translate_obj_resets( OBJ_RESET_DATA *pObjResets,
ROOM_INDEX_DATA *pRoom )
{
OBJ_INDEX_DATA *pObjIndex;
OBJ_RESET_DATA *pObjReset = pObjResets;
OBJ_RESET_DATA *pPrevObjReset = NULL;
OBJ_DATA *pNewObjects = NULL;
OBJ_DATA *pObj;
OBJ_DATA *pTemp;
while ( pObjReset != NULL )
{
if ( ( pObjIndex = get_object_index( pObjReset->u1.iNumber ) )
== NULL )
sap_fatal( "Room %d: No object with the number `%d'.",
pRoom->iNumber, pObjReset->u1.iNumber );
pObjReset->u1.pObjIndex = pObjIndex;
pObjReset->bAlive = TRUE;
pObjReset->iResetTimer = -1;
if ( pObjIndex->iItemType != NUMBER_ITEM_CONTAINER
&& pObjReset->pContentResets != NULL )
{
sap_warning(
"Room %d: Object placed in non-container object.",
pRoom->iNumber );
free_obj_reset_list( &pObjReset->pContentResets );
}
pObj = new_object( pObjIndex, NULL );
pObj->pReset = pObjReset;
pObj->pContains = translate_obj_resets(
pObjReset->pContentResets,
pRoom );
for ( pTemp = pObj->pContains; pTemp; pTemp = pTemp->pNextContent )
pTemp->pInObj = pObj;
pObj->pNextContent = pNewObjects;
pNewObjects = pObj;
#if 0
/*
* Delete resets that have reset times lower then zero.
* ...
* We don't delete one-time only resets anymore because
* we need them for OLC saving.
*/
if ( pObjReset->iResetTime < 0 )
{
if ( pPrevObjReset == NULL )
{
pRoom->pObjResets = pObjReset->pNext;
free_obj_reset_list( &pObjReset->pContentResets );
free_mem( (void **) &pObjReset );
pObjReset = pObjResets;
}
else
{
pPrevObjReset->pNext = pObjReset->pNext;
free_obj_reset_list( &pObjReset->pContentResets );
free_mem( (void **) &pObjReset );
pObjReset = pPrevObjReset->pNext;
}
pObj->pReset = NULL;
pPrevObjReset = pObjReset;
}
else
#endif
{
pPrevObjReset = pObjReset;
pObjReset = pObjReset->pNext;
}
}
return ( pNewObjects );
}
/*
* Frees a linked list of object resets.
*/
static void free_obj_reset_list( OBJ_RESET_DATA **ppObjReset )
{
OBJ_RESET_DATA *pObjReset;
OBJ_RESET_DATA *pObjResetNext;
for ( pObjReset = *ppObjReset; pObjReset; pObjReset = pObjResetNext )
{
pObjResetNext = pObjReset->pNext;
free_obj_reset_list( &pObjReset->pContentResets );
free_mem( (void **) &pObjReset );
}
*ppObjReset = NULL;
}
/*
* Do an NPC inheritence.
*/
static int npc_inherit( NPC_INDEX_DATA *pNPCIndex )
{
NPC_INDEX_DATA *pNPCIndexBuf;
int i;
if ( pNPCIndex->iInherit <= 0 )
return ( -1 );
pNPCIndexBuf = get_npc_index( pNPCIndex->iInherit );
if ( pNPCIndexBuf == NULL )
sap_fatal( "NPC %d: No NPC with number `%d' to inherit from.",
pNPCIndex->iNumber, pNPCIndex->iInherit );
if ( pNPCIndexBuf->iInherit > 0 )
sap_fatal( "NPC %d: Inheriting from inherited NPC.",
pNPCIndex->iNumber );
if ( pNPCIndex->pProgram == NULL && pNPCIndexBuf->pProgram != NULL )
{
GENERIC_DATA *pGen;
GENERIC_DATA *pGen2;
QUEST_VAR_DATA *pVar;
QUEST_VAR_DATA *pVar2;
PROGRAM_DATA *pProgram;
SCRIPT_DATA *pScript;
SCRIPT_DATA *pScript2;
TRIGGER_DATA *pTrigger;
TRIGGER_DATA *pTrigger2;
TRIGGER_ARG_DATA *pTriggerArg;
TRIGGER_ARG_DATA *pTriggerArg2;
pProgram = alloc_mem( sizeof( *pProgram ) );
pNPCIndex->pProgram = pProgram;
for ( pGen = pNPCIndexBuf->pProgram->pQuestDataList; pGen != NULL;
pGen = pGen->pNext )
{
pGen2 = alloc_mem( sizeof( *pGen2 ) );
pGen2->pData = pGen->pData;
pGen2->pNext = pProgram->pQuestDataList;
pProgram->pQuestDataList = pGen2;
}
for ( pVar = pNPCIndexBuf->pProgram->pQuestVars; pVar != NULL;
pVar = pVar->pNext )
{
pVar2 = alloc_mem( sizeof( *pVar2 ) );
pVar2->iType = pVar->iType;
pVar2->sName = save_string( pVar->sName );
if ( pVar2->iType == NUMBER_VAR_STRING )
pVar2->uData.s = EMPTY_STRING;
pVar2->pNext = pProgram->pQuestVars;
pProgram->pQuestVars = pVar2;
}
for ( pScript = pNPCIndexBuf->pProgram->pScripts; pScript != NULL;
pScript = pScript->pNext )
{
pScript2 = alloc_mem( sizeof( *pScript2 ) );
for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
pTrigger = pTrigger->pNext )
{
pTrigger2 = alloc_mem( sizeof( *pTrigger2 ) );
for ( pTriggerArg = pTrigger->pArgs; pTriggerArg != NULL;
pTriggerArg = pTriggerArg->pNext )
{
pTriggerArg2 = alloc_mem( sizeof( *pTriggerArg2 ) );
pTriggerArg2->iType = pTriggerArg->iType;
switch ( pTrigger->iTrigger )
{
case NUMBER_NPC_TRIGGER_RANDOM:
pTriggerArg2->pArg = alloc_mem( 1 );
*pTriggerArg2->pArg = *pTriggerArg->pArg;
break;
default :
pTriggerArg2->pArg = str_dup(
pTriggerArg->pArg );
break;
}
pTriggerArg2->pNext = pTrigger2->pArgs;
pTrigger2->pArgs = pTriggerArg2;
}
pTrigger2->iTrigger = pTrigger->iTrigger;
pTrigger2->pNext = pScript2->pTriggers;
pScript2->pTriggers = pTrigger2;
}
pScript2->pScript = alloc_mem( pScript->iCodeSize );
memcpy( pScript2->pScript,
pScript->pScript, pScript->iCodeSize );
pScript2->iCodeSize = pScript->iCodeSize;
pScript2->pName = str_dup( pScript->pName );
pScript2->bDisabled = pScript->bDisabled;
pScript2->pNext = pProgram->pScripts;
pProgram->pScripts = pScript2;
}
}
if ( pNPCIndex->pNameList[0] == EMPTY_STRING )
{
for ( i = 0; pNPCIndexBuf->pNameList[i] != NULL; i++ );
pNPCIndex->pNameList = alloc_mem( sizeof( string )
* ( i + 1 ) );
for ( i = 0; pNPCIndexBuf->pNameList[i] != NULL; i++ )
pNPCIndex->pNameList[i] = save_string(
pNPCIndexBuf->pNameList[i] );
}
if ( pNPCIndex->sShortDesc == EMPTY_STRING )
pNPCIndex->sShortDesc = pNPCIndexBuf->sShortDesc;
for ( i = 0; i < 5; i++ )
{
if ( pNPCIndex->sDescs[i] == EMPTY_STRING )
pNPCIndex->sDescs[i] = pNPCIndexBuf->sDescs[i];
}
if ( pNPCIndex->sLongDesc == EMPTY_STRING )
pNPCIndex->sLongDesc = pNPCIndexBuf->sLongDesc;
if ( pNPCIndex->fNPCFlags == 0 )
pNPCIndex->fNPCFlags = pNPCIndexBuf->fNPCFlags;
if ( pNPCIndex->fPartFlags == 0 )
pNPCIndex->fPartFlags = pNPCIndexBuf->fPartFlags;
if ( pNPCIndex->fActFlags == 0 )
pNPCIndex->fActFlags = pNPCIndexBuf->fActFlags;
if ( pNPCIndex->iLevel == 1 )
pNPCIndex->iLevel = pNPCIndexBuf->iLevel;
if ( pNPCIndex->iAlignment == 0 )
pNPCIndex->iAlignment = pNPCIndexBuf->iAlignment;
if ( pNPCIndex->iRace == rRaceTable[0].iNumber )
pNPCIndex->iRace = pNPCIndexBuf->iRace;
i = get_race_index( pNPCIndex->iRace );
if ( pNPCIndex->iSex == snSexTable[0].iNumber )
pNPCIndex->iSex = pNPCIndexBuf->iSex;
if ( pNPCIndex->iHairColor == rRaceTable[i].iHairColors[0] )
pNPCIndex->iHairColor = pNPCIndexBuf->iHairColor;
if ( pNPCIndex->iEyeColor == rRaceTable[i].iEyeColors[0] )
pNPCIndex->iEyeColor = pNPCIndexBuf->iEyeColor;
if ( pNPCIndex->iHeight == 65 )
pNPCIndex->iHeight = pNPCIndexBuf->iHeight;
if ( pNPCIndex->iWeight == 130 )
pNPCIndex->iWeight = pNPCIndexBuf->iWeight;
if ( pNPCIndex->iMaxCarry == 0 )
pNPCIndex->iMaxCarry = pNPCIndexBuf->iMaxCarry;
if ( pNPCIndex->iPosition == NUMBER_POSITION_STANDING )
pNPCIndex->iPosition = pNPCIndexBuf->iPosition;
if ( pNPCIndex->iGold == 0 )
pNPCIndex->iGold = pNPCIndexBuf->iGold;
for ( i = 0; i < 3; i++ )
{
if ( pNPCIndex->VarStats.iStatStr[1] == 0 )
pNPCIndex->VarStats.iStatStr[i]
= pNPCIndexBuf->VarStats.iStatStr[i];
if ( pNPCIndex->VarStats.iStatInt[1] == 0 )
pNPCIndex->VarStats.iStatInt[i]
= pNPCIndexBuf->VarStats.iStatInt[i];
if ( pNPCIndex->VarStats.iStatWis[1] == 0 )
pNPCIndex->VarStats.iStatWis[i]
= pNPCIndexBuf->VarStats.iStatWis[i];
if ( pNPCIndex->VarStats.iStatDex[1] == 0 )
pNPCIndex->VarStats.iStatDex[i]
= pNPCIndexBuf->VarStats.iStatDex[i];
if ( pNPCIndex->VarStats.iStatCon[1] == 0 )
pNPCIndex->VarStats.iStatCon[i]
= pNPCIndexBuf->VarStats.iStatCon[i];
if ( pNPCIndex->VarStats.iStatCha[1] == 0 )
pNPCIndex->VarStats.iStatCha[i]
= pNPCIndexBuf->VarStats.iStatCha[i];
if ( pNPCIndex->VarStats.iStatLuc[1] == 0 )
pNPCIndex->VarStats.iStatLuc[i]
= pNPCIndexBuf->VarStats.iStatLuc[i];
if ( pNPCIndex->VarStats.iStatHP[1] == 0 )
pNPCIndex->VarStats.iStatHP[i]
= pNPCIndexBuf->VarStats.iStatHP[i];
if ( pNPCIndex->VarStats.iStatMP[1] == 0 )
pNPCIndex->VarStats.iStatMP[i]
= pNPCIndexBuf->VarStats.iStatMP[i];
if ( pNPCIndex->VarStats.iStatMV[1] == 0 )
pNPCIndex->VarStats.iStatMV[i]
= pNPCIndexBuf->VarStats.iStatMV[i];
if ( pNPCIndex->iExp[1] == 0 )
pNPCIndex->iExp[i] = pNPCIndexBuf->iExp[i];
}
return ( 0 );
}
/*
* Do an object inheritence.
*/
static int obj_inherit( OBJ_INDEX_DATA *pObjIndex )
{
OBJ_INDEX_DATA *pObjIndexBuf;
int i;
if ( pObjIndex->iInherit <= 0 )
return ( -1 );
pObjIndexBuf = get_object_index( pObjIndex->iInherit );
if ( pObjIndexBuf == NULL )
sap_fatal( "Object %d: No object with number `%d' to inherit.",
pObjIndex->iNumber, pObjIndex->iInherit );
if ( pObjIndexBuf->iInherit > 0 )
sap_fatal( "Object %d: Inheriting from inherited object.",
pObjIndex->iNumber );
if ( pObjIndex->pProgram == NULL && pObjIndexBuf->pProgram != NULL )
{
GENERIC_DATA *pGen;
GENERIC_DATA *pGen2;
QUEST_VAR_DATA *pVar;
QUEST_VAR_DATA *pVar2;
PROGRAM_DATA *pProgram;
SCRIPT_DATA *pScript;
SCRIPT_DATA *pScript2;
TRIGGER_DATA *pTrigger;
TRIGGER_DATA *pTrigger2;
TRIGGER_ARG_DATA *pTriggerArg;
TRIGGER_ARG_DATA *pTriggerArg2;
pProgram = alloc_mem( sizeof( *pProgram ) );
pObjIndex->pProgram = pProgram;
for ( pGen = pObjIndexBuf->pProgram->pQuestDataList; pGen != NULL;
pGen = pGen->pNext )
{
pGen2 = alloc_mem( sizeof( *pGen2 ) );
pGen2->pData = pGen->pData;
pGen2->pNext = pProgram->pQuestDataList;
pProgram->pQuestDataList = pGen2;
}
for ( pVar = pObjIndexBuf->pProgram->pQuestVars; pVar != NULL;
pVar = pVar->pNext )
{
pVar2 = alloc_mem( sizeof( *pVar2 ) );
pVar2->iType = pVar->iType;
pVar2->sName = save_string( pVar->sName );
if ( pVar2->iType == NUMBER_VAR_STRING )
pVar2->uData.s = EMPTY_STRING;
pVar2->pNext = pProgram->pQuestVars;
pProgram->pQuestVars = pVar2;
}
for ( pScript = pObjIndexBuf->pProgram->pScripts; pScript != NULL;
pScript = pScript->pNext )
{
pScript2 = alloc_mem( sizeof( *pScript2 ) );
for ( pTrigger = pScript->pTriggers; pTrigger != NULL;
pTrigger = pTrigger->pNext )
{
pTrigger2 = alloc_mem( sizeof( *pTrigger2 ) );
for ( pTriggerArg = pTrigger->pArgs; pTriggerArg != NULL;
pTriggerArg = pTriggerArg->pNext )
{
pTriggerArg2 = alloc_mem( sizeof( *pTriggerArg2 ) );
pTriggerArg2->iType = pTriggerArg->iType;
switch ( pTrigger->iTrigger )
{
case NUMBER_OBJ_TRIGGER_RANDOM:
pTriggerArg2->pArg = alloc_mem( 1 );
*pTriggerArg2->pArg = *pTriggerArg->pArg;
break;
default :
pTriggerArg2->pArg = str_dup(
pTriggerArg->pArg );
break;
}
pTriggerArg2->pNext = pTrigger2->pArgs;
pTrigger2->pArgs = pTriggerArg2;
}
pTrigger2->iTrigger = pTrigger->iTrigger;
pTrigger2->pNext = pScript2->pTriggers;
pScript2->pTriggers = pTrigger2;
}
pScript2->pScript = alloc_mem( pScript->iCodeSize );
memcpy( pScript2->pScript,
pScript->pScript, pScript->iCodeSize );
pScript2->iCodeSize = pScript->iCodeSize;
pScript2->pName = str_dup( pScript->pName );
pScript2->bDisabled = pScript->bDisabled;
pScript2->pNext = pProgram->pScripts;
pProgram->pScripts = pScript2;
}
}
if ( pObjIndex->pNameList[0] == EMPTY_STRING )
{
for ( i = 0; pObjIndexBuf->pNameList[i] != NULL; i++ );
pObjIndex->pNameList = alloc_mem( sizeof( string )
* ( i + 1 ) );
for ( i = 0; pObjIndexBuf->pNameList[i] != NULL; i++ )
pObjIndex->pNameList[i] = save_string(
pObjIndexBuf->pNameList[i] );
}
if ( pObjIndex->sShortDesc == EMPTY_STRING )
pObjIndex->sShortDesc = pObjIndexBuf->sShortDesc;
if ( pObjIndex->sDesc == EMPTY_STRING )
pObjIndex->sDesc = pObjIndexBuf->sDesc;
if ( pObjIndex->sLongDesc == EMPTY_STRING )
pObjIndex->sLongDesc = pObjIndexBuf->sLongDesc;
if ( pObjIndex->fObjFlags == 0 )
pObjIndex->fObjFlags = pObjIndexBuf->fObjFlags;
if ( pObjIndex->iItemType == snItemTypeTable[0].iNumber )
pObjIndex->iItemType = pObjIndexBuf->iItemType;
if ( pObjIndex->iLevel == 1 )
pObjIndex->iLevel = pObjIndexBuf->iLevel;
if ( pObjIndex->iWeight == 0 )
pObjIndex->iWeight = pObjIndexBuf->iWeight;
if ( pObjIndex->iSize == NUMBER_SIZE_MEDIUM )
pObjIndex->iSize = pObjIndexBuf->iSize;
if ( pObjIndex->iCost == 0 )
pObjIndex->iCost = pObjIndexBuf->iCost;
if ( pObjIndex->iCondition == 1 )
pObjIndex->iCondition = pObjIndexBuf->iCondition;
if ( pObjIndex->iMaterial == snMaterialTable[0].iNumber )
pObjIndex->iMaterial = pObjIndexBuf->iMaterial;
for ( i = 0; i < 6; i++ )
{
if ( pObjIndex->iValues[i] == 0 )
pObjIndex->iValues[i] = pObjIndexBuf->iValues[i];
}
if ( pObjIndex->sValue == EMPTY_STRING )
pObjIndex->sValue = pObjIndexBuf->sValue;
return ( 0 );
}
static int fix_exit( ROOM_INDEX_DATA *pRoom, int i )
{
ROOM_INDEX_DATA *pToRoom;
int iNumber;
int iRev;
if ( pRoom->eExits[i].uRoom.iNumber == 0 )
return ( -1 );
if ( ( pToRoom = get_room_index(
pRoom->eExits[i].uRoom.iNumber ) ) == NULL )
sap_fatal( "Room %d: No room with the number `%d' for exit.",
pRoom->iNumber, pRoom->eExits[i].uRoom.iNumber );
pRoom->eExits[i].uRoom.pRoom = pToRoom;
if ( pRoom->eExits[i].bShared == TRUE )
{
switch ( i )
{
case 0 : iRev = 1; break;
case 1 : iRev = 0; break;
case 2 : iRev = 3; break;
case 3 : iRev = 2; break;
case 4 : iRev = 5; break;
case 5 : iRev = 4; break;
case 6 : iRev = 7; break;
case 7 : iRev = 6; break;
case 8 : iRev = 9; break;
case 9 : iRev = 8; break;
/* This should never happen. */
default: iRev = 0; break;
}
if ( pToRoom->eExits[iRev].uRoom.iNumber == 0 )
sap_fatal( "Room %d: Cannot share from non-existent exit.",
pRoom->iNumber );
if ( pToRoom->eExits[iRev].bShared == TRUE )
sap_fatal( "Room %d: Sharing from shared exit.",
pRoom->iNumber );
pRoom->eExits[i].uKey.iNumber = pToRoom->eExits[iRev].uKey.iNumber;
pRoom->eExits[i].iExitType = pToRoom->eExits[iRev].iExitType;
pRoom->eExits[i].iResetTime = pToRoom->eExits[iRev].iResetTime;
pRoom->eExits[i].fOrigFlags = pToRoom->eExits[iRev].fOrigFlags;
pRoom->eExits[i].fCurrFlags = pToRoom->eExits[iRev].fCurrFlags;
pRoom->eExits[i].iLevel = pToRoom->eExits[iRev].iLevel;
}
/*
* Keys.
*/
if ( pRoom->eExits[i].uRoom.pRoom && pRoom->eExits[i].uKey.iNumber )
{
if ( ( pRoom->eExits[i].uKey.pObjKey = get_object_index(
( iNumber = pRoom->eExits[i].uKey.iNumber ) ) ) == NULL )
sap_fatal(
"Room %d: No object with the number `%d' for door key.",
pRoom->iNumber, iNumber );
if ( pRoom->eExits[i].uKey.pObjKey->iItemType != NUMBER_ITEM_KEY )
sap_warning( "Room %d: Object used for door key is not of "
"item type `Key'.", pRoom->iNumber );
}
return ( 0 );
}
/*
* End of main.c
*/