/* * 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 <fcntl.h> #include <netdb.h> #include <time.h> #include <signal.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/telnet.h> #include <arpa/inet.h> #include "sapphire.h" /* * Prototypes */ #define CD CHAR_DATA static bool illegal_name ( char * ); static CD * new_guest ( void ); #undef CD /* * Functions */ /* * Init the telnet socket. */ void init_telnet_socket( int iPort ) { struct sockaddr_in sSA; int iX = 1; if ( ( sTelnetControl = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) sap_fatal( "Create socket: %s.", strerror( errno ) ); if ( setsockopt( sTelnetControl, SOL_SOCKET, SO_REUSEADDR, (char *) &iX, sizeof( iX ) ) < 0 ) sap_fatal( "Set socket option: %s.", strerror( errno ) ); zero_out( &sSA, sizeof( sSA ) ); sSA.sin_family = AF_INET; sSA.sin_port = htons( iPort ); if ( bind( sTelnetControl, (struct sockaddr *) &sSA, sizeof( sSA ) ) < 0 ) sap_fatal( "Bind: %s.", strerror( errno ) ); if ( listen( sTelnetControl, 3 ) < 0 ) sap_fatal( "Listen: %s.", strerror( errno ) ); } /* * Init the binary socket. */ void init_binary_socket( int iPort ) { struct sockaddr_in sSA; int iX = 1; if ( ( sBinaryControl = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) sap_fatal( "Create socket: %s.", strerror( errno ) ); if ( setsockopt( sBinaryControl, SOL_SOCKET, SO_REUSEADDR, (char *) &iX, sizeof( iX ) ) < 0 ) sap_fatal( "Set socket option: %s.", strerror( errno ) ); zero_out( &sSA, sizeof( sSA ) ); sSA.sin_family = AF_INET; sSA.sin_port = htons( iPort ); if ( bind( sBinaryControl, (struct sockaddr *) &sSA, sizeof( sSA ) ) < 0 ) sap_fatal( "Bind: %s.", strerror( errno ) ); if ( listen( sBinaryControl, 3 ) < 0 ) sap_fatal( "Listen: %s.", strerror( errno ) ); } /* * Accept a new connection. */ void accept_connection( void ) { TERM_DATA *pTermNew; struct sockaddr_in sSock; struct hostent *pHost; char cBuf[MAX_STRING]; char *pBuf; int iSize; sapsocket sSocket; iSize = sizeof( sSock ); sSocket = accept( sTelnetControl, (struct sockaddr *) &sSock, &iSize ); if ( sSocket < 0 ) { sap_error( "Accept: %s.", strerror( errno ) ); return; } if ( fcntl( sSocket, F_SETFL, FNDELAY ) < 0 ) { sap_error( "Set descriptor option: %s.", strerror( errno ) ); close( sSocket ); return; } if ( pTermFree == NULL ) pTermNew = alloc_mem( sizeof( *pTermNew ) ); else { pTermNew = pTermFree; pTermFree = pTermFree->pNext; } pTermNew->sTelnetSocket = sSocket; pTermNew->sBinarySocket = -1; pTermNew->iTermType = CLIENT_GENERIC; pTermNew->iOutBufferSize = 2048; pTermNew->iInBufferSize = ( MAX_INPUT * 4 ); pTermNew->pOutBuffer = alloc_mem( pTermNew->iOutBufferSize ); pTermNew->pOutLast = alloc_mem( MAX_STRING ); pTermNew->pInBuffer = alloc_mem( pTermNew->iInBufferSize ); pTermNew->pInCommand = alloc_mem( MAX_INPUT ); pTermNew->iConState = CON_MAIN_MENU; pTermNew->iBinaryMode = BIN_MODE_FILENAME; pTermNew->pCurrentDir = EMPTY_STRING; pTermNew->bLocalEcho = FALSE; pTermNew->iPageLines = 22; if ( getpeername( sSocket, (struct sockaddr *) &sSock, &iSize ) < 0 ) { sap_error( "Get peer name: %s.", strerror( errno ) ); pBuf = NULL; pHost = NULL; pTermNew->pHostname = str_dup( "(unknown)" ); } else { pBuf = inet_ntoa( sSock.sin_addr ); pHost = gethostbyaddr( (char *) &sSock.sin_addr.s_addr, sizeof( sSock.sin_addr.s_addr ), AF_INET ); pTermNew->pHostname = str_dup( ( pHost ? pHost->h_name : pBuf ) ); } snprintf( cBuf, MAX_STRING, "\n Connection established with: %s", pTermNew->pHostname ); if ( pHost != NULL && pBuf != NULL ) { strcat( cBuf, "\n (" ); strcat( cBuf, pBuf ); strcat( cBuf, ")" ); } lprintf( cBuf ); pTermNew->pNext = pTermList; pTermList = pTermNew; term_send_string( pTermNew, "%sDo you have local echo on? ", COPYRIGHT_NOTICE ); pTermNew->iConState = CON_SAPPHIRE_IDENT; } /* * Accept a Sapphire compatible client. */ void accept_binary_connection( void ) { TERM_DATA *pTerm; struct sockaddr_in sSock; struct hostent *pHost; char cBuf[MAX_STRING]; char *pBuf; char *pBuf2; int iSize; sapsocket sSocket; iSize = sizeof( sSock ); sSocket = accept( sBinaryControl, (struct sockaddr *) &sSock, &iSize ); if ( sSocket < 0 ) { sap_error( "Accept: %s.", strerror( errno ) ); return; } if ( fcntl( sSocket, F_SETFL, FNDELAY ) < 0 ) { sap_error( "Set descriptor option: %s.", strerror( errno ) ); close( sSocket ); return; } if ( getpeername( sSocket, (struct sockaddr *) &sSock, &iSize ) < 0 ) { sap_error( "Get peer name: %s.", strerror( errno ) ); close( sSocket ); return; } else { pBuf = inet_ntoa( sSock.sin_addr ); pHost = gethostbyaddr( (char *) &sSock.sin_addr.s_addr, sizeof( sSock.sin_addr.s_addr ), AF_INET ); pBuf2 = ( pHost != NULL ? pHost->h_name : pBuf ); } for ( pTerm = pTermList; pTerm != NULL; pTerm = pTerm->pNext ) { if ( pTerm->iConState == CON_SAPPHIRE_IDENT && strcmp( pTerm->pHostname, pBuf2 ) == 0 ) break; } if ( pTerm == NULL ) { snprintf( cBuf, MAX_STRING, "\n\r" "Server: This port is used for binary transfers only; " "please use port %d.\n\r\n\r", iTelnetPort ); iSize = strlen( cBuf ); if ( write( sSocket, cBuf, iSize ) < 0 ) sap_error( "Write: %s.", strerror( errno ) ); close( sSocket ); return; } snprintf( cBuf, MAX_STRING, "\n Sapphire compatible client identified for: %s", pTerm->pHostname ); if ( pHost != NULL && pBuf != NULL ) { strcat( cBuf, "\n (" ); strcat( cBuf, pBuf ); strcat( cBuf, ")" ); } lprintf( cBuf ); pTerm->iTermType = CLIENT_SAPPHIRE_COMPATIBLE; pTerm->sBinarySocket = sSocket; pTerm->bLocalEcho = TRUE; pTerm->iPageLines = 10; pTerm->iConState = CON_GET_NAME; term_send_string( pTerm, "\n\r\n\r" "[Sapphire compatible client identified]\n\r\n\r%s" "\n\rBy what name do you wish to be known? ", pGreeting ); write_file( pTerm, get_file_type( pLoginScreenFilename ), pLoginScreenFilename ); } /* * Close a connection. */ void close_connection( TERM_DATA **ppTermClose ) { TERM_DATA *pTermClose = *ppTermClose; TERM_DATA *pTerm; CHAR_DATA *pChar; if ( pTermClose->pChildP != NULL ) { kill( pTermClose->pChildP->pPid, SIGKILL ); pTermClose->pChildP = NULL; } if ( pTermClose->pOutBuffer[0] != '\0' || pTermClose->pBinData != NULL ) flush_buffer( *ppTermClose ); pChar = pTermClose->pChar; if ( pTermClose->pControlled != NULL ) { pTermClose->pControlled->pTerm = NULL; if ( pChar != NULL ) { char_to_room( pChar, uDefaultRoom.pRoom ); send_game_message( "~h appears out of nothingness.", MESSAGE_DEST_ROOM, TRUE, pChar, NULL, pChar->pInRoom, TRUE, NUMBER_POSITION_RESTING, pChar ); } } if ( pChar != NULL ) { if ( !IS_GUEST( pChar ) ) iNumberPlayers--; if ( pTermClose->iConState == CON_PLAYING && !IS_GUEST( pChar ) ) { send_game_message( "~c's image shimers for a moment.", MESSAGE_DEST_ROOM, TRUE, pChar, NULL, pChar->pInRoom, FALSE, NUMBER_POSITION_RESTING, pChar ); pChar->pTerm = NULL; } else free_char( &pChar ); } if ( pTermClose == pTermList ) pTermList = pTermClose->pNext; else { for ( pTerm = pTermList; pTerm && pTerm->pNext != pTermClose; pTerm = pTerm->pNext ); #ifdef DEBUG if ( pTerm != NULL ) pTerm->pNext = pTermClose->pNext; else sap_debug( "Terminal not found." ); #else pTerm->pNext = pTermClose->pNext; #endif } lprintf( "\n Closing connection to: %s", pTermClose->pHostname ); close( pTermClose->sTelnetSocket ); if ( pTermClose->iTermType == CLIENT_SAPPHIRE_COMPATIBLE ) close( pTermClose->sBinarySocket ); free_mem( (void **) &pTermClose->pOutBuffer ); free_mem( (void **) &pTermClose->pInBuffer ); free_mem( (void **) &pTermClose->pInCommand ); if ( pTermClose->pEditString != NULL ) free_mem( (void **) &pTermClose->pEditString ); str_free( pTermClose->pHostname ); str_free( pTermClose->pCurrentDir ); zero_out( pTermClose, sizeof( *pTermClose ) ); /* * Recycling of terminal sturctures in vital in the current code, * (it expects that it can still access a terminal structure even * after it is no longer in use) if you remove the recycling code * you can bet that there will be problems. */ pTermClose->pNext = pTermFree; pTermFree = pTermClose; *ppTermClose = NULL; } /* * Reads one line of input from the descriptor and stores it in * the input buffer (pInBuffer). */ bool read_string( TERM_DATA *pTerm ) { int i, iRead = 0; if ( pTerm->pInCommand[0] != '\0' ) return ( TRUE ); i = strlen( pTerm->pInBuffer ); if ( i >= ( pTerm->iInBufferSize - 1 ) ) { lprintf( "%s input overflow!", pTerm->pHostname ); write_string_buffer( pTerm, "\n\r\aServer: Input overflow!\n\r" ); return ( FALSE ); } for ( ; ; ) { iRead = read( pTerm->sTelnetSocket, ( pTerm->pInBuffer + i ), ( pTerm->iInBufferSize - i - 1 ) ); if ( iRead > 0 ) { i += iRead; if ( pTerm->pInBuffer[i - 1] == '\n' || pTerm->pInBuffer[i - 1] == '\r' ) { if ( pTerm->bLocalEcho != TRUE ) write_string_buffer( pTerm, "\n\r" ); break; } } else if ( iRead == 0 ) return ( FALSE ); else if ( errno == EAGAIN /* EWOULDBLOCK */ ) break; else if ( errno == EINTR ) continue; else { /* sap_error( "Read: %s.", strerror( errno ) ); */ return ( FALSE ); } } pTerm->pInBuffer[i] = '\0'; return ( TRUE ); } bool read_binary_data( TERM_DATA *pTerm ) { int i = 0; int iRead = 0; for ( ; ; ) { iRead = read( pTerm->sTelnetSocket, &i, 1 ); if ( iRead > 0 ) { /* For now we do processing right here. */ switch ( i ) { case BIN_CMD_FILENAME_MODE: pTerm->iBinaryMode = BIN_MODE_FILENAME; break; case BIN_CMD_FILE_MODE : pTerm->iBinaryMode = BIN_MODE_FILE; break; default : break; } } else if ( iRead == 0 ) return ( FALSE ); else if ( errno == EAGAIN /* EWOULDBLOCK */ ) break; else if ( errno == EINTR ) continue; else { /* sap_error( "Read: %s.", strerror( errno ) ); */ return ( FALSE ); } } return ( TRUE ); } void read_string_buffer( TERM_DATA *pTerm ) { int i = 0; int iComm = 0; if ( pTerm->pInCommand[0] != '\0' ) return; while ( pTerm->pInBuffer[i] != '\n' && pTerm->pInBuffer[i] != '\r' ) { if ( pTerm->pInBuffer[i++] == '\0' ) return; } i = 0; while ( pTerm->pInBuffer[i] != '\n' && pTerm->pInBuffer[i] != '\r' ) { if ( i >= ( MAX_INPUT - 2 ) ) { write_string( pTerm, "Server: Line too long.\n\r" ); pTerm->pInBuffer[i++] = '\n'; pTerm->pInBuffer[i] = '\0'; break; } if ( pTerm->pInBuffer[i] == '\b' && iComm > 0 ) iComm--; else if ( isascii( pTerm->pInBuffer[i] ) ) pTerm->pInCommand[iComm++] = pTerm->pInBuffer[i]; i++; } if ( iComm == '\0' ) pTerm->pInCommand[iComm++] = ' '; pTerm->pInCommand[iComm] = '\0'; while ( pTerm->pInBuffer[i] == '\n' || pTerm->pInBuffer[i] == '\r' ) i++; for ( iComm = 0; pTerm->pInBuffer[iComm] != '\0'; iComm++ ) pTerm->pInBuffer[iComm] = pTerm->pInBuffer[i + iComm]; } bool write_string( TERM_DATA *pTerm, char *pText ) { int iLength = strlen( pText ); do { errno = 0; write( pTerm->sTelnetSocket, pText, iLength ); } while ( errno == EINTR ); if ( errno != 0 ) { sap_error( "Write: %s.", strerror( errno ) ); return ( FALSE ); } return ( TRUE ); } bool write_binary_data( TERM_DATA *pTerm ) { int iWrite; do { errno = 0; iWrite = write( pTerm->sBinarySocket, pTerm->pBinTransfering, ( pTerm->lBinRemainSize > MAX_BIN_TRANSFER_BLOCK ? MAX_BIN_TRANSFER_BLOCK : pTerm->lBinRemainSize ) ); } while ( errno == EINTR ); if ( errno != 0 ) { sap_error( "Write: %s.", strerror( errno ) ); return ( FALSE ); } pTerm->pBinTransfering += iWrite; pTerm->lBinRemainSize -= iWrite; return ( TRUE ); } void clear_binary_transfer( TERM_DATA *pTerm ) { if ( pTerm->pBinData == NULL ) return; pTerm->pBinTransfering = NULL; pTerm->lBinRemainSize = 0; free_mem( (void **) &pTerm->pBinData ); } void write_string_buffer( TERM_DATA *pTerm, char *pText ) { int iLength = strlen( pText ); int iOutSize; if ( iLength >= MAX_STRING ) { sap_error( "Terminal buffer: String too long." ); return; } strcpy( pTerm->pOutLast, pText ); iOutSize = strlen( pTerm->pOutBuffer ); /* * Expand the buffer as needed. */ while ( iOutSize + iLength >= pTerm->iOutBufferSize ) { int iNewSize; if ( pTerm->iOutBufferSize > MAX_OUTBUF_SIZE ) { sap_error( "Terminal buffer: Overflow; closing." ); close_connection( &pTerm ); return; } iNewSize = ( pTerm->iOutBufferSize << 1 ); /* Times 2 */ pTerm->pOutBuffer = realloc_mem( pTerm->pOutBuffer, iNewSize ); pTerm->iOutBufferSize = iNewSize; } strcpy( pTerm->pOutBuffer + iOutSize, pText ); } /* * Begins sending a file to a Sapphire compatible client. */ void write_file( TERM_DATA *pTerm, intt iFileType, char *pFilename ) { int i; if ( pTerm->pBinData != NULL ) return; switch ( pTerm->iBinaryMode ) { case BIN_MODE_FILENAME: i = ( strlen( pFilename ) + 3 ); pTerm->pBinData = alloc_mem( i ); pTerm->pBinData[0] = BIN_CMD_SENDING_FILENAME; pTerm->pBinData[1] = iFileType; strcpy( (char *) &pTerm->pBinData[2], pFilename ); pTerm->pBinTransfering = pTerm->pBinData; pTerm->lBinRemainSize = i; break; case BIN_MODE_FILE : break; default : break; } } void rewrite_string_buffer( TERM_DATA *pTerm ) { write_string_buffer( pTerm, pTerm->pOutLast ); } /* * Force a write of all data in the string buffer and binary buffer. */ void flush_buffer( TERM_DATA *pTerm ) { if ( pTerm->iTermType != CLIENT_SAPPHIRE_COMPATIBLE ) { if ( pTerm->pOutBuffer[0] == '\0' ) return; write_string( pTerm, pTerm->pOutBuffer ); pTerm->pOutBuffer[0] = '\0'; } else { if ( pTerm->pOutBuffer[0] != '\0' ) { write_string( pTerm, pTerm->pOutBuffer ); pTerm->pOutBuffer[0] = '\0'; } if ( pTerm->pBinData != NULL ) clear_binary_transfer( pTerm ); } } void term_send_string( TERM_DATA *pTerm, char *pFormat, ... ) { va_list pArgs; char cStr[MAX_STRING]; if ( pTerm == NULL ) return; va_start( pArgs, pFormat ); vsnprintf( cStr, MAX_STRING, pFormat, pArgs ); write_string_buffer( pTerm, cStr ); va_end( pArgs ); } /* * Send a string to a character. */ void send_string( CHAR_DATA *pChar, char *pFormat, ... ) { va_list pArgs; char cStr[MAX_STRING]; if ( pChar == NULL || pChar->pTerm == NULL || ( pChar->pTerm->iConState != CON_PLAYING && pChar->pTerm->iConState != CON_NPC_EDITOR && pChar->pTerm->iConState != CON_OBJECT_EDITOR && pChar->pTerm->iConState != CON_ROOM_EDITOR ) ) return; va_start( pArgs, pFormat ); vsnprintf( cStr, MAX_STRING, pFormat, pArgs ); write_string_buffer( pChar->pTerm, cStr ); va_end( pArgs ); } /* * Send a formated message to multiple destinations. */ void send_game_message( char *pFormat, long lDest, ... ) { ROOM_INDEX_DATA *pRoom; CHAR_DATA *pChar; CHAR_DATA *pChar2; CHAR_DATA *pCharBuf; va_list vlVarArgs; va_list vlBak; char cBuf[MAX_STRING] = ""; int i; int iPos; bool bTrigger; bool bHide; va_start( vlVarArgs, lDest ); switch ( lDest ) { case MESSAGE_DEST_CHAR : pChar = va_arg( vlVarArgs, CHAR_DATA * ); iPos = va_arg( vlVarArgs, long ); #ifdef DEBUG if ( pChar == NULL ) { wcdebug( "Null character." ); break; } #endif if ( pChar->iPosition < iPos ) break; expand_game_symbols( pFormat, cBuf, pChar, vlVarArgs ); send_string( pChar, "%s\n\r", cBuf ); break; case MESSAGE_DEST_VICTOM: bTrigger = ( va_arg( vlVarArgs, long ) > 0 ? TRUE : FALSE ); pChar = va_arg( vlVarArgs, CHAR_DATA * ); pChar2 = va_arg( vlVarArgs, CHAR_DATA * ); iPos = va_arg( vlVarArgs, long ); #ifdef DEBUG if ( pChar == NULL || pChar2 == NULL ) { wcdebug( "Null character." ); break; } #endif if ( pChar2->iPosition < iPos ) break; expand_game_symbols( pFormat, cBuf, pChar2, vlVarArgs ); if ( pChar2->pTerm != NULL && ( ( i = ( strlen( pChar2->pTerm->pOutBuffer ) - 2 ) ) < 0 || pChar2->pTerm->pOutBuffer[i] != '\n' ) ) send_string( pChar2, "\n\r%s\n\r", cBuf ); else send_string( pChar2, "%s\n\r", cBuf ); if ( bTrigger == TRUE ) check_char_trigger( NUMBER_NPC_TRIGGER_MESSAGE, pChar, NULL, pChar2, cBuf ); break; case MESSAGE_DEST_ROOM : bTrigger = ( va_arg( vlVarArgs, long ) > 0 ? TRUE : FALSE ); pChar = va_arg( vlVarArgs, CHAR_DATA * ); pChar2 = va_arg( vlVarArgs, CHAR_DATA * ); pRoom = va_arg( vlVarArgs, ROOM_INDEX_DATA * ); bHide = va_arg( vlVarArgs, long ); iPos = va_arg( vlVarArgs, long ); vlBak = vlVarArgs; #ifdef DEBUG if ( pRoom == NULL ) { wcdebug( "Null room." ); break; } #endif if ( bTrigger == TRUE ) { expand_game_symbols( pFormat, cBuf, NULL, vlVarArgs ); check_room_trigger( NUMBER_ROOM_TRIGGER_MESSAGE, pChar, pRoom, cBuf ); for ( pCharBuf = pRoom->pPeople; pCharBuf != NULL; pCharBuf = pCharBuf->pNextInRoom ) { if ( pCharBuf != pChar && pCharBuf != pChar2 && pCharBuf->iPosition >= iPos ) { if ( bHide == TRUE && visable_char( pChar, pCharBuf ) != TRUE ) continue; vlVarArgs = vlBak; expand_game_symbols( pFormat, cBuf, pCharBuf, vlVarArgs ); if ( pCharBuf->pTerm != NULL && ( ( i = strlen( pCharBuf->pTerm->pOutBuffer ) - 2 ) < 0 || pCharBuf->pTerm->pOutBuffer[i] != '\n' ) ) send_string( pCharBuf, "\n\r%s\n\r", cBuf ); else send_string( pCharBuf, "%s\n\r", cBuf ); check_char_trigger( NUMBER_NPC_TRIGGER_MESSAGE, pChar, NULL, pCharBuf, cBuf ); } } } else { for ( pCharBuf = pRoom->pPeople; pCharBuf != NULL; pCharBuf = pCharBuf->pNextInRoom ) { if ( pCharBuf != pChar && pCharBuf != pChar2 && pCharBuf->iPosition >= iPos ) { if ( bHide == TRUE && visable_char( pChar, pCharBuf ) != TRUE ) continue; vlVarArgs = vlBak; expand_game_symbols( pFormat, cBuf, pCharBuf, vlVarArgs ); if ( pCharBuf->pTerm != NULL && ( ( i = strlen( pCharBuf->pTerm->pOutBuffer ) - 2 ) < 0 || pCharBuf->pTerm->pOutBuffer[i] != '\n' ) ) send_string( pCharBuf, "\n\r%s\n\r", cBuf ); else send_string( pCharBuf, "%s\n\r", cBuf ); } } } break; #ifdef DEBUG default : wcdebug( "Unknown destination." ); break; #endif } va_end( vlVarArgs ); } void expand_game_symbols( char *p, char *pBuf, CHAR_DATA *pChar, va_list vlVarArgs ) { CHAR_DATA *pCharBuf; OBJ_DATA *pObj; char *pBak = pBuf; char *pStr; long l; /* * I know that having two code blocks that are almost identical is * a bit messy but this function is called offen and I don't want to * slow it down with having to do checks all over the place. */ if ( pChar == NULL ) goto room; while ( *p != '\0' ) { if ( *p == '~' ) { switch ( *++p ) { case '~': *pBuf++ = '~'; break; case 'c': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); #ifdef DEBUG if ( pCharBuf->pInRoom == NULL ) { wcdebug( "Character not in room." ); break; } #endif if ( visable_char( pCharBuf, pChar ) != TRUE ) pStr = "someone"; else if ( knows_char( pChar, pCharBuf ) == TRUE ) { if ( IS_NPC( pCharBuf ) ) { if ( IS_SET( pCharBuf->pNPCData->fNPCFlags, FLAG_NPC_SPECIAL ) ) pStr = pCharBuf->pNPCData->sShortDesc; else if ( count_npcs( pCharBuf->pInRoom, pCharBuf->pNPCData ) < 2 ) { pStr = pCharBuf->pNPCData->sShortDesc; strcpy( pBuf, "the " ); pBuf += 4; } else { pStr = pCharBuf->pNPCData->sShortDesc; strcpy( pBuf, "a " ); pBuf += 2; } } else pStr = pCharBuf->pPCData->sName; } else if ( ( count_race( pCharBuf->pInRoom, pCharBuf->iRace ) - ( pChar->iRace == pCharBuf->iRace ? 1 : 0 ) ) < 2 ) { pStr = uncapit( get_race_string( pCharBuf->iRace ) ); strcpy( pBuf, "the " ); pBuf += 4; } else pStr = uncapit( get_race_string_2( pCharBuf->iRace ) ); strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; case 'h': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); #ifdef DEBUG if ( pCharBuf->pInRoom == NULL ) { wcdebug( "Character not in room." ); break; } #endif if ( visable_char( pCharBuf, pChar ) != TRUE ) pStr = "someone"; else if ( knows_char( pChar, pCharBuf ) == TRUE ) { if ( IS_NPC( pCharBuf ) ) { if ( IS_SET( pCharBuf->pNPCData->fNPCFlags, FLAG_NPC_SPECIAL ) ) pStr = pCharBuf->pNPCData->sShortDesc; else { pStr = pCharBuf->pNPCData->sShortDesc; strcpy( pBuf, "a " ); pBuf += 2; } } else pStr = pCharBuf->pPCData->sName; } else pStr = uncapit( get_race_string_2( pCharBuf->iRace ) ); strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; case 's': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); pStr = ( pCharBuf->iSex == NUMBER_SEX_MALE ? "his" : "hers" ); strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; case 'e': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); strcpy( pBuf, ( pCharBuf->iSex == NUMBER_SEX_MALE ? "his" : "her" ) ); pBuf += 3; break; case 'x': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); strcpy( pBuf, ( pCharBuf->iSex == NUMBER_SEX_MALE ? "him" : "her" ) ); pBuf += 3; break; case 'r': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); strcpy( pBuf, get_race_string( pCharBuf->iRace ) ); pBuf += 3; break; case 'g': break; case 'o': pObj = va_arg( vlVarArgs, OBJ_DATA * ); if ( visable_object( pObj, pChar ) != TRUE ) pStr = "something"; else if ( IS_SET( pObj->fObjFlags, FLAG_OBJECT_SPECIAL ) ) pStr = pObj->sShortDesc; else { pStr = pObj->sShortDesc; strcpy( pBuf, "a " ); pBuf += 2; } strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; case 'b': pObj = va_arg( vlVarArgs, OBJ_DATA * ); if ( visable_object( pObj, pChar ) != TRUE ) pStr = "something"; else if ( IS_SET( pObj->fObjFlags, FLAG_OBJECT_SPECIAL ) ) pStr = pObj->sShortDesc; else { pStr = pObj->sShortDesc; strcpy( pBuf, "the " ); pBuf += 4; } strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; case 'j': pObj = va_arg( vlVarArgs, OBJ_DATA * ); if ( visable_object( pObj, pChar ) != TRUE ) pStr = "something"; else if ( IS_SET( pObj->fObjFlags, FLAG_OBJECT_SPECIAL ) ) pStr = pObj->sShortDesc; else { pStr = pObj->sShortDesc; strcpy( pBuf, "your " ); pBuf += 5; } strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; #ifdef DEBUG default : wcdebug( "Unknown symbol `~%c'.", *p ); break; #endif } } else if ( *p == '$' ) { switch ( *++p ) { case '$': *pBuf++ = '$'; break; case 'i': l = va_arg( vlVarArgs, long ); sprintf( pBuf, "%ld", l ); while ( *pBuf != '\0' ) pBuf++; break; case 's': pStr = va_arg( vlVarArgs, char * ); strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; #ifdef DEBUG default : wcdebug( "Unknown symbol `$%c'.", *p ); break; #endif } } else *pBuf++ = *p; p++; } while ( !isalpha( *pBak ) && *pBak != '\0' ) pBak++; *pBak = UPPER( *pBak ); return; room: while ( *p != '\0' ) { if ( *p == '~' ) { switch ( *++p ) { case '~': *pBuf++ = '~'; break; case 'c': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); #ifdef DEBUG if ( pCharBuf->pInRoom == NULL ) { wcdebug( "Character not in room." ); break; } #endif if ( IS_NPC( pCharBuf ) ) { if ( IS_SET( pCharBuf->pNPCData->fNPCFlags, FLAG_NPC_SPECIAL ) ) pStr = pCharBuf->pNPCData->sShortDesc; else if ( count_npcs( pCharBuf->pInRoom, pCharBuf->pNPCData ) < 2 ) { pStr = pCharBuf->pNPCData->sShortDesc; strcpy( pBuf, "the " ); pBuf += 4; } else { pStr = pCharBuf->pNPCData->sShortDesc; strcpy( pBuf, "a " ); pBuf += 2; } } else pStr = pCharBuf->pPCData->sName; strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; case 'h': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); #ifdef DEBUG if ( pCharBuf->pInRoom == NULL ) { wcdebug( "Character not in room." ); break; } #endif if ( IS_NPC( pCharBuf ) ) { if ( IS_SET( pCharBuf->pNPCData->fNPCFlags, FLAG_NPC_SPECIAL ) ) pStr = pCharBuf->pNPCData->sShortDesc; else { pStr = pCharBuf->pNPCData->sShortDesc; strcpy( pBuf, "a " ); pBuf += 2; } } else pStr = pCharBuf->pPCData->sName; strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; case 's': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); pStr = ( pCharBuf->iSex == NUMBER_SEX_MALE ? "his" : "hers" ); strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; case 'e': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); strcpy( pBuf, ( pCharBuf->iSex == NUMBER_SEX_MALE ? "his" : "her" ) ); pBuf += 3; break; case 'x': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); strcpy( pBuf, ( pCharBuf->iSex == NUMBER_SEX_MALE ? "him" : "her" ) ); pBuf += 3; break; case 'r': pCharBuf = va_arg( vlVarArgs, CHAR_DATA * ); strcpy( pBuf, get_race_string( pCharBuf->iRace ) ); pBuf += 3; break; case 'g': break; case 'o': pObj = va_arg( vlVarArgs, OBJ_DATA * ); if ( IS_SET( pObj->fObjFlags, FLAG_OBJECT_SPECIAL ) ) pStr = pObj->sShortDesc; else { pStr = pObj->sShortDesc; strcpy( pBuf, "a " ); pBuf += 2; } strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; case 'b': pObj = va_arg( vlVarArgs, OBJ_DATA * ); if ( IS_SET( pObj->fObjFlags, FLAG_OBJECT_SPECIAL ) ) pStr = pObj->sShortDesc; else { pStr = pObj->sShortDesc; strcpy( pBuf, "the " ); pBuf += 4; } strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; case 'j': pObj = va_arg( vlVarArgs, OBJ_DATA * ); if ( IS_SET( pObj->fObjFlags, FLAG_OBJECT_SPECIAL ) ) pStr = pObj->sShortDesc; else { pStr = pObj->sShortDesc; strcpy( pBuf, "your " ); pBuf += 5; } strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; #ifdef DEBUG default : wcdebug( "Unknown symbol `~%c'.", *p ); break; #endif } } else if ( *p == '$' ) { switch ( *++p ) { case '$': *pBuf++ = '$'; break; case 'i': l = va_arg( vlVarArgs, long ); sprintf( pBuf, "%ld", l ); while ( *pBuf != '\0' ) pBuf++; break; case 's': pStr = va_arg( vlVarArgs, char * ); strcpy( pBuf, pStr ); pBuf += strlen( pStr ); break; #ifdef DEBUG default : wcdebug( "Unknown symbol `$%c'.", *p ); break; #endif } } else *pBuf++ = *p; p++; } while ( !isalpha( *pBak ) && *pBak != '\0' ) pBak++; *pBak = UPPER( *pBak ); } bool process_output( TERM_DATA *pTerm ) { CHAR_DATA *pChar; #if 0 CHAR_DATA *pVictim; #endif if ( bRunning ) { if ( pTerm->pPageString != NULL ) { term_send_string( pTerm, "\n\r%s[Press Enter to continue]%s ", make_ansi_code( ANSI_CODEREF_SGR_DSET, "0;44", NULL, pTerm ), make_ansi_code( ANSI_CODEREF_SGR_DSET, "0", NULL, pTerm ) ); goto end; } if ( pTerm->ppEditString != NULL ) { if ( pTerm->pOutBuffer[0] == '\0' ) term_send_string( pTerm, "Edit %ld: ", pTerm->iEditLine ); else term_send_string( pTerm, "\n\rEdit %ld: ", pTerm->iEditLine ); goto end; } switch ( pTerm->iConState ) { case CON_PLAYING : pChar = ( pTerm->pControlled != NULL ? pTerm->pControlled : pTerm->pChar ); #if 0 if ( ( pVictim = pChar->pFighting ) != NULL ) { int iPercent; if ( pVictim->pStats->iStatHP > 0 ) iPercent = ( pVictim->iHP * 100 / pVictim->pStats->iStatHP ); else iPercent = -1; if ( IS_NPC( pVictim ) ) { if ( !IS_SET( pVictim->pNPCData->fNPCFlags, FLAG_NPC_SPECIAL ) ) { strcpy( cBuf, "The " ); strcat( cBuf, pVictim->pNPCData->sShortDesc ); } else strcpy( cBuf, pVictim->pNPCData->sShortDesc ); } else strcpy( cBuf, pVictim->pPCData->sName ); cBuf[0] = UPPER( cBuf[0] ); iPercent = round( iPercent, 15 ); switch ( iPercent ) { case 100: strcat( cBuf, "is in excellent condition.\n\r" ); break; case 85 : strcat( cBuf, "has a few cuts and scratches.\n\r" ); break; case 70 : strcat( cBuf, "has some slight wounds.\n\r" ); break; case 55 : strcat( cBuf, "has quite a few wounds.\n\r" ); break; case 40 : strcat( cBuf, "has many large wounds.\n\r" ); break; case 25 : strcat( cBuf, "looks very weak.\n\r" ); break; case 10 : strcat( cBuf, "is in awful condition.\n\r" ); break; default : strcat( cBuf, "is bleeding to death.\n\r" ); break; } strcat( cBuf, "\n\r" ); write_string_buffer( pTerm, cBuf ); } #endif term_send_string( pTerm, "\n\r%s ", format_prompt( pChar, pTerm->pChar->pPCData->sPrompt ) ); break; case CON_NPC_EDITOR : if ( pTerm->uEdit.pEditNPC != NULL ) term_send_string( pTerm, "\n\r[NPC Edit: %ld]> ", pTerm->uEdit.pEditNPC->iNumber ); else term_send_string( pTerm, "\n\r[NPC Edit]> " ); break; case CON_OBJECT_EDITOR: if ( pTerm->uEdit.pEditObject != NULL ) term_send_string( pTerm, "\n\r[Object Edit: %ld]> ", pTerm->uEdit.pEditObject->iNumber ); else term_send_string( pTerm, "\n\r[Object Edit]> " ); break; case CON_ROOM_EDITOR : if ( pTerm->uEdit.pEditRoom != NULL ) term_send_string( pTerm, "\n\r[Room Edit: %ld]> ", pTerm->uEdit.pEditRoom->iNumber ); else term_send_string( pTerm, "\n\r[Room Edit]> " ); break; case CON_SYSTEM_SHELL : term_send_string( pTerm, "%sssh:~/%s$%s ", make_ansi_code( ANSI_CODEREF_SGR_DSET, "0;33", NULL, pTerm ), pTerm->pCurrentDir, make_ansi_code( ANSI_CODEREF_SGR_DSET, "0", NULL, pTerm ) ); break; default : break; } } end: if ( pTerm->pOutBuffer[0] == '\0' ) return ( TRUE ); if ( write_string( pTerm, pTerm->pOutBuffer ) == FALSE ) return ( FALSE ); else { pTerm->pOutBuffer[0] = '\0'; return ( TRUE ); } } /* * Deals with input from terminals that have not logged in yet. */ void process_login( TERM_DATA *pTerm, char *pArg ) { extern ROOM_INDEX_DATA *pStartingRoom; TERM_DATA *pTerm2; CHAR_DATA *pChar; char cArg[MAX_INPUT]; char cBuf[MAX_STRING]; char *pName; int i, i2, i3; one_arg( pArg, cArg ); cBuf[0] = '\0'; pChar = pTerm->pChar; if ( pChar != NULL ) pName = pChar->pPCData->sName; else pName = EMPTY_STRING; switch ( pTerm->iConState ) { case ( CON_SAPPHIRE_IDENT ): pTerm->iConState = CON_GET_LOCAL_ECHO_ON; process_login( pTerm, pArg ); break; case ( CON_GET_LOCAL_ECHO_ON ): if ( cArg[0] == '\0' ) { term_send_string( pTerm, "\n\rPlease answer yes or no: " ); break; } if ( str_prefix( cArg, "Yes" ) == TRUE ) pTerm->bLocalEcho = TRUE; else if ( str_prefix( cArg, "No" ) == TRUE ) pTerm->bLocalEcho = FALSE; else { term_send_string( pTerm, "\n\rPlease answer yes or no: " ); break; } term_send_string( pTerm, "\n\rDoes your client have full " "ANSI support (not just color)? " ); pTerm->iConState = CON_GET_CLIENT_TYPE; break; case ( CON_GET_CLIENT_TYPE ): if ( cArg[0] == '\0' ) { term_send_string( pTerm, "\n\rPlease answer yes or no: " ); break; } if ( str_prefix( cArg, "Yes" ) == TRUE ) pTerm->iTermType = CLIENT_ANSI_COMPATIBLE; else if ( str_prefix( cArg, "No" ) == TRUE ) pTerm->iTermType = CLIENT_GENERIC; else { term_send_string( pTerm, "\n\rPlease answer yes or no: " ); break; } term_send_string( pTerm, "%s\n\r", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ) ); if ( iMode == MODE_RPG ) { term_send_string( pTerm, "%s\n\rBy what name do you wish to be known? ", pGreeting ); pTerm->iConState = CON_GET_NAME; } else { term_send_string( pTerm, "__ Main Menu __\n\r" "\n\r" " 1) Login\n\r" " 2) Disconnect\n\r" " 3) Player List\n\r" "\n\r" "Choose an option: " ); pTerm->iConState = CON_MAIN_MENU; } break; case ( CON_MAIN_MENU ) : if ( cArg[0] == '\0' ) { term_send_string( pTerm, "\n\rChoose an option: " ); break; } switch ( atoi( cArg ) ) { case 1: term_send_string( pTerm, "%s\n\r%s\n\rBy what name do you wish to be known? ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), pGreeting ); pTerm->iConState = CON_GET_NAME; break; case 2: term_send_string( pTerm, "Farewell.\n\r" ); close_connection( &pTerm ); break; case 3: cBuf[0] = '\0'; setup_string_pager( pTerm ); for ( pTerm2 = pTermList; pTerm2; pTerm2 = pTerm2->pNext ) { if ( pTerm2->pChar != NULL && pTerm2->iConState == CON_PLAYING && !IS_GUEST( pTerm2->pChar ) ) { sprintf( cBuf, "%s\n\r", pTerm2->pChar->pPCData->sName ); page_string( pTerm, cBuf ); } } if ( cBuf[0] == '\0' ) { term_send_string( pTerm, "No one is playing at the moment.\n\r" ); } finish_string_pager( pTerm ); term_send_string( pTerm, "\n\rChoose an option: " ); break; default: term_send_string( pTerm, "That is not a valid option.\n\r" "\n\rChoose an option: " ); break; } break; case ( CON_GET_NAME ) : if ( cArg[0] == '\0' ) { term_send_string( pTerm, "\n\rName: " ); break; } if ( illegal_name( cArg ) == TRUE ) { term_send_string( pTerm, "\n\rNo, that name will not do.\n\r" ); term_send_string( pTerm, "\n\rPlease choose a different name: " ); return; } if ( iMode == MODE_RPG && str_compare( cArg, "Guest" ) == TRUE ) { pChar = new_guest( ); pTerm->pChar = pChar; pChar->pTerm = pTerm; term_send_string( pTerm, "%s\n\r%s\n\r%s[Press Enter to continue]%s ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), pMOTD, make_ansi_code( ANSI_CODEREF_SGR_DSET, "0;44", NULL, pTerm ), make_ansi_code( ANSI_CODEREF_SGR_DSET, "0", NULL, pTerm ) ); pTerm->iConState = CON_READ_MOTD; return; } /* * (PCs are always at 0 in the hash list.) */ for ( pChar = ppCharList[0]; pChar; pChar = pChar->pNext ) { if ( !IS_NPC( pChar ) && str_compare( pChar->pPCData->sName, cArg ) == TRUE ) { pTerm->pChar = pChar; term_send_string( pTerm, "\n\rWhat is the password? " ); pTerm->iConState = CON_RECONNECT; return; } } iNumberPlayers++; if ( ( pChar = load_pc( cArg ) ) == NULL ) { if ( iNumberPlayers > iMaxPlayers ) { term_send_string( pTerm, "\n\rServer: Sorry, the maximum number of players for" "this server has been exceeded.\n\r " "Please try again later.\n\r" ); close_connection( &pTerm ); break; } pChar = new_pc( ); pChar->pPCData->sName = save_string( cap_first( cArg ) ); pTerm->pChar = pChar; pChar->pTerm = pTerm; term_send_string( pTerm, "\n\rPlease enter the character creation code: " ); pTerm->iConState = CON_GET_CREATION_CODE; break; } pTerm->pChar = pChar; pChar->pTerm = pTerm; if ( pChar->iLevel < BUILDER_LEVEL && iNumberPlayers > iMaxPlayers ) { term_send_string( pTerm, "\n\rServer: Sorry, the maximum number of players for" "this server has been exceeded.\n\r " "Please try again later.\n\r" ); close_connection( &pTerm ); break; } term_send_string( pTerm, "\n\rWhat is the password? " ); pTerm->iConState = CON_GET_PASSWORD; break; case ( CON_GET_CREATION_CODE ): if ( strcmp( cCreationCode, pArg ) != 0 ) { term_send_string( pTerm, "\n\r" "That is not the correct character creation code.\n\r" ); close_connection( &pTerm ); return; } /* * Enter character creation. */ term_send_string( pTerm, "\n\rEntering character creation system.\n\r" ); term_send_string( pTerm, "\n\rGive me a password for this character: " ); pTerm->iConState = CON_GET_PASSWORD; break; case ( CON_GET_PASSWORD ): if ( pChar->iLevel > 0 ) { char *pPass = pChar->pPCData->sPassword; if ( pPass[0] != '\0' && strcmp( pPass, crypt( pArg, pPass ) ) ) { term_send_string( pTerm, "\n\rI now see that you are not who you say you are " "... Goodbye.\n\r" ); pChar->pInRoom = NULL; close_connection( &pTerm ); return; } term_send_string( pTerm, "%s\n\r%s\n\r%s[Press Enter to continue]%s ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), pMOTD, make_ansi_code( ANSI_CODEREF_SGR_DSET, "0;44", NULL, pTerm ), make_ansi_code( ANSI_CODEREF_SGR_DSET, "0", NULL, pTerm ) ); pTerm->iConState = CON_READ_MOTD; } else { i = strlen( pArg ); if ( i < 5 ) { term_send_string( pTerm, "\n\r" "A password must be aleast 5 characters long.\n\r" "\n\rPassword: " ); break; } if ( i > 25 ) { term_send_string( pTerm, "\n\r" "A password may be no more then 25 characters long." "\n\r\n\rPassword: " ); break; } pChar->pPCData->sPassword = save_string( crypt( pArg, pName ) ); /* * Goto the character creation menu. */ term_send_string( pTerm, "%s" "\n\r__ Character Creation Menu __\n\r" "\n\r" " 1) Choose race. Race: %s\n\r" " 2) Roll stats. Stats rolled: %s\n\r" " 3) Choose sex. Sex: %s\n\r" " 4) Finish creation.\n\r" "\n\r" "Choose an option: ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), ( pChar->iRace == 0 ? "None" : get_race_string( pChar->iRace ) ), ( pChar->pStats->iStatStr == 0 ? "No" : "Yes" ), ( pChar->iSex == 0 ? "None" : get_sex_string( pChar->iSex ) ) ); pTerm->iConState = CON_CREATION_MENU; } break; case ( CON_CREATION_MENU ): if ( cArg[0] == '\0' ) { term_send_string( pTerm, "\n\rChoose an option: " ); break; } switch ( atoi( cArg ) ) { case 1: for ( i = 0; rRaceTable[i].pName[0] != '\0'; i++ ) { if ( rRaceTable[i].bPCRace == TRUE ) { strcat( cBuf, " " ); strcat( cBuf, rRaceTable[i].pName ); } } term_send_string( pTerm, "%s\n\rThe following races are " "available:\n\r %s\n\r\n\rRace: ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), cBuf ); pTerm->iConState = CON_GET_RACE; break; case 2: if ( pChar->iRace == 0 ) { term_send_string( pTerm, "You must select your race first.\n\r" "\n\rChoose an option: " ); break; } roll_stats( pChar->pStats ); modify_stats( pChar->pStats, pChar->iRace ); term_send_string( pTerm, "%s\n\r" " Strength : %d\n\r" " Intelligence : %d\n\r" " Wisdom : %d\n\r" " Dexterity : %d\n\r" " Constitution : %d\n\r" " Charisma : %d\n\r" " Luck : %d\n\r" "\n\r" " Hit Points : %d\n\r" " Magic Points : %d\n\r" " Movement Points : %d\n\r" "\n\rAre these stats OK? ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), pChar->pStats->iStatStr, pChar->pStats->iStatInt, pChar->pStats->iStatWis, pChar->pStats->iStatDex, pChar->pStats->iStatCon, pChar->pStats->iStatCha, pChar->pStats->iStatLuc, pChar->pStats->iStatHP, pChar->pStats->iStatMP, pChar->pStats->iStatMV ); pTerm->iConState = CON_ROLL_STATS; break; case 3: term_send_string( pTerm, "%s\n\rSex (Male/Female)? ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ) ); pTerm->iConState = CON_GET_SEX; break; case 4: if ( pChar->iRace == 0 || pChar->pStats->iStatStr == 0 || pChar->iSex == 0 ) { term_send_string( pTerm, "You must fill in all the fields first.\n\r" "\n\rChoose an option: " ); break; } #if 0 if ( pChar->iRace == 0 ) { term_send_string( pTerm, "You need to select a race first.\n\r" "\n\rChoose an option: " ); break; } if ( pChar->pStats->iStatStr == 0 ) { term_send_string( pTerm, "You need to roll some stats first.\n\r" "\n\rChoose an option: " ); break; } if ( pChar->iSex == 0 ) { term_send_string( pTerm, "You need to select a sex first.\n\r" "\n\rChoose an option: " ); break; } #endif term_send_string( pTerm, "%s\n\r%s\n\r%s[Press Enter to continue]%s ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), pMOTD, make_ansi_code( ANSI_CODEREF_SGR_DSET, "0;44", NULL, pTerm ), make_ansi_code( ANSI_CODEREF_SGR_DSET, "0", NULL, pTerm ) ); pTerm->iConState = CON_READ_MOTD; break; default: term_send_string( pTerm, "That is not a valid option.\n\r" "\n\rChoose an option: " ); break; } break; case ( CON_GET_RACE ) : if ( cArg[0] == '\0' ) { term_send_string( pTerm, "\n\rRace: " ); break; } for ( i = 0; rRaceTable[i].pName[0] != '\0'; i++ ) { if ( str_prefix( cArg, rRaceTable[i].pName ) == TRUE && rRaceTable[i].bPCRace == TRUE ) { pChar->iRace = rRaceTable[i].iNumber; pChar->fActFlags = rRaceTable[i].fActFlags; pChar->pStats->iStatStr = 0; /* * Goto the character creation menu. */ term_send_string( pTerm, "%s" "\n\r__ Character Creation Menu __\n\r" "\n\r" " 1) Choose race. Race: %s\n\r" " 2) Roll stats. Stats rolled: %s\n\r" " 3) Choose sex. Sex: %s\n\r" " 4) Finish creation.\n\r" "\n\r" "Choose an option: ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), ( pChar->iRace == 0 ? "None" : get_race_string( pChar->iRace ) ), ( pChar->pStats->iStatStr == 0 ? "No" : "Yes" ), ( pChar->iSex == 0 ? "None" : get_sex_string( pChar->iSex ) ) ); pTerm->iConState = CON_CREATION_MENU; return; } } term_send_string( pTerm, "\n\rI do not know the race you are refering to.\n\r" "\n\rRace: " ); break; case ( CON_ROLL_STATS ) : if ( cArg[0] == '\0' ) { term_send_string( pTerm, "\n\rAre these stats OK? " ); break; } if ( str_prefix( cArg, "No" ) == TRUE ) { roll_stats( pChar->pStats ); modify_stats( pChar->pStats, pChar->iRace ); term_send_string( pTerm, "%s\n\r" " Strength : %d\n\r" " Intelligence : %d\n\r" " Wisdom : %d\n\r" " Dexterity : %d\n\r" " Constitution : %d\n\r" " Charisma : %d\n\r" " Luck : %d\n\r" "\n\r" " Hit Points : %d\n\r" " Magic Points : %d\n\r" " Movement Points : %d\n\r" "\n\rAre these stats OK? ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), pChar->pStats->iStatStr, pChar->pStats->iStatInt, pChar->pStats->iStatWis, pChar->pStats->iStatDex, pChar->pStats->iStatCon, pChar->pStats->iStatCha, pChar->pStats->iStatLuc, pChar->pStats->iStatHP, pChar->pStats->iStatMP, pChar->pStats->iStatMV ); } else if ( str_prefix( cArg, "Yes" ) == TRUE ) { /* * Goto the character creation menu. */ term_send_string( pTerm, "%s" "\n\r__ Character Creation Menu __\n\r" "\n\r" " 1) Choose race. Race: %s\n\r" " 2) Roll stats. Stats rolled: %s\n\r" " 3) Choose sex. Sex: %s\n\r" " 4) Finish creation.\n\r" "\n\r" "Choose an option: ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), ( pChar->iRace == 0 ? "None" : get_race_string( pChar->iRace ) ), ( pChar->pStats->iStatStr == 0 ? "No" : "Yes" ), ( pChar->iSex == 0 ? "None" : get_sex_string( pChar->iSex ) ) ); pTerm->iConState = CON_CREATION_MENU; } else term_send_string( pTerm, "\n\rYes or no? " ); break; case ( CON_GET_SEX ) : if ( cArg[0] == '\0' ) { term_send_string( pTerm, "\n\rSex: " ); break; } if ( str_prefix( cArg, "Male" ) == TRUE ) pChar->iSex = NUMBER_SEX_MALE; else if ( str_prefix( cArg, "Female" ) == TRUE ) pChar->iSex = NUMBER_SEX_FEMALE; else { term_send_string( pTerm, "\n\rThat is not a sex.\n\r" ); term_send_string( pTerm, "\n\rSex: " ); return; } #if 0 i = get_race_index( pChar->iRace ); /* if ( rRaceTable[i].iHairColors[1] == 0 ) { pChar->iEyeColor = rRaceTable[i].iHairColors[0]; write_string_buffer( pTerm, "\n\rSex (Male/Female)? " ); pTerm->iConState = CON_GET_EYE_COLOR; return; } */ strcpy( cBuf, "\n\rThe following values have no affect on the game.\n\r" ); strcat( cBuf, "\n\rThe following hair colors are available for your race:" "\n\r " ); for ( i2 = 0; rRaceTable[i].iHairColors[i2]; i2++ ) { for ( i3 = 0; snHairColorTable[i3].pName[0] != '\0'; i3++ ) { if ( rRaceTable[i].iHairColors[i2] == snHairColorTable[i3].iNumber ) { strcat( cBuf, " " ); strcat( cBuf, snHairColorTable[i3].pName ); } } } strcat( cBuf, "\n\r" ); write_string_buffer( pTerm, cBuf ); write_string_buffer( pTerm, "\n\rHair Color: " ); pTerm->iConState = CON_GET_HAIR_COLOR; #endif term_send_string( pTerm, "%s" "\n\r__ Character Creation Menu __\n\r" "\n\r" " 1) Choose race. Race: %s\n\r" " 2) Roll stats. Stats rolled: %s\n\r" " 3) Choose sex. Sex: %s\n\r" " 4) Finish creation.\n\r" "\n\r" "Choose an option: ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), ( pChar->iRace == 0 ? "None" : get_race_string( pChar->iRace ) ), ( pChar->pStats->iStatStr == 0 ? "No" : "Yes" ), ( pChar->iSex == 0 ? "None" : get_sex_string( pChar->iSex ) ) ); pTerm->iConState = CON_CREATION_MENU; break; case ( CON_GET_HAIR_COLOR ): if ( cArg[0] == '\0' ) { term_send_string( pTerm, "\n\rHair Color: " ); break; } i = get_race_index( pChar->iRace ); for ( i2 = 0; snHairColorTable[i2].pName[0] != '\0'; i2++ ) { if ( str_prefix( cArg, snHairColorTable[i2].pName ) == TRUE ) { for ( i3 = 0; rRaceTable[i].iHairColors[i3] != 0; i3++ ) { if ( snHairColorTable[i2].iNumber == rRaceTable[i].iHairColors[i3] ) { pChar->iHairColor = snHairColorTable[i].iNumber; term_send_string( pTerm, "%s\n\r%s\n\r%s[Press Enter to continue]%s ", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ), pMOTD, make_ansi_code( ANSI_CODEREF_SGR_DSET, "0;44", NULL, pTerm ), make_ansi_code( ANSI_CODEREF_SGR_DSET, "0", NULL, pTerm ) ); pTerm->iConState = CON_READ_MOTD; return; } } } } term_send_string( pTerm, "\n\rI do not know the hair color you are refering to.\n\r" "\n\rHair Color: " ); break; case ( CON_READ_MOTD ) : if ( pChar->iLevel < 1 ) { pChar->iLevel = 1; pChar->iHP = pChar->pStats->iStatHP; pChar->iMP = pChar->pStats->iStatMP; pChar->iMV = pChar->pStats->iStatMV; pChar->iPosition = NUMBER_POSITION_STANDING; pChar->iMaxCarry = ( pChar->pStats->iStatStr - 2 ); pStartingRoom = uDefaultRoom.pRoom; } else { if ( ( pChar = load_pc( pName ) ) != NULL ) { pTerm->pChar->pInRoom = NULL; free_char( &pTerm->pChar ); pTerm->pChar = pChar; pChar->pTerm = pTerm; } } pChar->pPCData->tLastLogin = tCurrentTime; pTerm->iConState = CON_PLAYING; char_to_room( pChar, pStartingRoom ); send_game_message( "~h appears in a puff of smoke.", MESSAGE_DEST_ROOM, TRUE, pChar, NULL, pChar->pInRoom, TRUE, NUMBER_POSITION_RESTING, pChar ); lprintf( "%s has entered the game.", pName ); term_send_string( pTerm, "%s\n\r", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ) ); cmd_look( pChar, "" ); break; case ( CON_RECONNECT ): { char *pPass = pChar->pPCData->sPassword; if ( pPass[0] != '\0' && strcmp( pPass, crypt( pArg, pPass ) ) ) { term_send_string( pTerm, "\n\rI now see that you are not who you say you are " "... Goodbye.\n\r" ); pTerm->pChar = NULL; close_connection( &pTerm ); return; } send_game_message( "~c's image shimers for a moment.", MESSAGE_DEST_ROOM, TRUE, pChar, NULL, pChar->pInRoom, FALSE, NUMBER_POSITION_RESTING, pChar ); if ( pChar->pTerm == NULL ) term_send_string( pTerm, "%s\n\rReconnected.\n\r", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ) ); else { term_send_string( pTerm, "%s\n\rOld connection broken.\n\r", make_ansi_code( ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ) ); pChar->pTerm->pChar = NULL; term_send_string( pChar->pTerm, "\n\rYour connection has been broken by a new " "connection.\n\r" ); close_connection( &pChar->pTerm ); } pChar->pTerm = pTerm; pTerm->iConState = CON_PLAYING; } break; #ifdef DEBUG default : wcdebug( "Unknown connected state: %d. Closing connection.", pTerm->iConState ); close_connection( &pTerm ); break; #endif } } static bool illegal_name( char *pName ) { int iLength; int i, i2; iLength = strlen( pName ); if ( iLength > 12 || iLength < 2 || sp_legal_string( pName ) == FALSE ) return ( TRUE ); if ( str_compare( pName, "North" ) == TRUE || str_compare( pName, "South" ) == TRUE || str_compare( pName, "East" ) == TRUE || str_compare( pName, "West" ) == TRUE || str_compare( pName, "Up" ) == TRUE || str_compare( pName, "Down" ) == TRUE || str_compare( pName, "NorthEast" ) == TRUE || str_compare( pName, "SouthWest" ) == TRUE || str_compare( pName, "NorthWest" ) == TRUE || str_compare( pName, "SouthEast" ) == TRUE || str_compare( pName, "NE" ) == TRUE || str_compare( pName, "SW" ) == TRUE || str_compare( pName, "NW" ) == TRUE || str_compare( pName, "SE" ) == TRUE || str_compare( pName, "Everyone" ) == TRUE || str_compare( pName, "Everybody" ) == TRUE || str_compare( pName, "Party" ) == TRUE || str_compare( pName, "Save" ) == TRUE || str_compare( pName, "Quit" ) == TRUE ) return ( TRUE ); for ( i = 0; pName[i] != '\0'; i++ ) { for ( i2 = 0; cLetterTable[i2] != '\0'; i2++ ) { if ( pName[i] == cLetterTable[i2] ) break; } if ( cLetterTable[i2] == '\0' ) return ( TRUE ); } return ( FALSE ); } static CHAR_DATA *new_guest( void ) { static intt iGuestNum; CHAR_DATA *pChar; char cBuf[128]; pChar = new_pc( ); snprintf( cBuf, 128, "Guest%u", (unsigned int) iGuestNum ); pChar->pPCData->sName = save_string( cBuf ); pChar->pPCData->bGuest = TRUE; iGuestNum++; return ( pChar ); } /* * Simplified ANSI code interface. */ char *make_ansi_code( int iCodeRef, char *pArg1, char *pArg2, TERM_DATA *pTerm ) { char *pBuf = new_buffer( ); if ( pTerm != NULL && pTerm->iTermType != CLIENT_ANSI_COMPATIBLE ) return ( EMPTY_STRING ); switch ( iCodeRef ) { case ANSI_CODEREF_CC_SET : sprintf( pBuf, "\033[%s;%sH", pArg1, pArg2 ); break; case ANSI_CODEREF_CC_UP : sprintf( pBuf, "\033[%sA", pArg1 ); break; case ANSI_CODEREF_CC_DOWN : sprintf( pBuf, "\033[%sB", pArg1 ); break; case ANSI_CODEREF_CC_FORWARD : sprintf( pBuf, "\033[%sC", pArg1 ); break; case ANSI_CODEREF_CC_BACK : sprintf( pBuf, "\033[%sD", pArg1 ); break; case ANSI_CODEREF_EF_CSCREEN : strcpy( pBuf, "\033[2J" ); break; case ANSI_CODEREF_EF_CLINE : strcpy( pBuf, "\033[K" ); break; case ANSI_CODEREF_SGR_DSET : sprintf( pBuf, "\033[%sm", pArg1 ); break; case ANSI_CODEREF_SGR_SSET : sprintf( pBuf, "\033[=%s;7h", pArg1 ); break; case ANSI_CODEREF_SGR_SRSET : sprintf( pBuf, "\033[=%s;7l", pArg1 ); break; case ANSI_CODEREF_KR_REASSIGN: sprintf( pBuf, "\033[%s;%sp", pArg1, pArg2 ); break; case ANSI_CODEREF_OTHER : strcpy( pBuf, pArg1 ); break; default : return ( EMPTY_STRING ); } return ( pBuf ); } /* * End of comm.c */