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