R2b5/deity/
R2b5/gods/
R2b5/log/
R2b5/player/
/***************************************************************************
*   Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*   Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                          *
*   Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
*   Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                          *
*   In order to use any part of this Merc Diku Mud, you must comply with   *
*   both the original Diku license in 'license.doc' as well the Merc       *
*   license in 'license.txt'.  In particular, you may not remove either of *
*   these copyright notices.                                               *
*                                                                          *
*   Much time and thought has gone into this software and you are          *
*   benefitting.  We hope that you share your changes too.  What goes      *
*   around, comes around.                                                  *
***************************************************************************/
/***************************************************************************
*       ROM 2.4 is copyright 1993-1995 Russ Taylor                         *
*       ROM has been brought to you by the ROM consortium                  *
*           Russ Taylor (rtaylor@pacinfo.com)                              *
*           Gabrielle Taylor (gtaylor@pacinfo.com)                         *
*           Brian Moore (rom@rom.efn.org)                                  *
*       By using this code, you have agreed to follow the terms of the     *
*       ROM license, in the file 'rom.license'                             *
***************************************************************************/
/***************************************************************************
*       ROT 2.0 is copyright 1996-1999 by Russ Walsh                       *
*       By using this code, you have agreed to follow the terms of the     *
*       ROT license, in the file 'rot.license'                             *
***************************************************************************/

/*
 * This file contains all of the OS-dependent stuff:
 *   startup, signals, BSD sockets for tcp/ip, i/o, timing.
 *
 * The data flow for input is:
 *    Game_loop ---> Read_from_descriptor ---> Read
 *    Game_loop ---> Read_from_buffer
 *
 * The data flow for output is:
 *    Game_loop ---> Process_Output ---> Write_to_descriptor -> Write
 *
 * The OS-dependent functions are Read_from_descriptor and Write_to_descriptor.
 * -- Furey  26 Jan 1993
 */

#if defined(macintosh)
#include <types.h>
#else
	#include <sys/types.h>
	#if defined(WIN32)
		#include <sys/timeb.h>
	#else
		#include <sys/time.h>
		#include <unistd.h>
	#endif
#endif


/*
 * Socket and TCP/IP stuff.
 */
#if	defined( WIN32 )
#include <winsock.h>
#include "telnet.h"
const	char	echo_off_str	[] = { IAC, WILL, TELOPT_ECHO, '\0' };
const	char	echo_on_str	[] = { IAC, WONT, TELOPT_ECHO, '\0' };
const	char 	go_ahead_str	[] = { IAC, GA, '\0' };
#endif

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>

#include "merc.h"
#include "recycle.h"
#include "tables.h"
#include "interp.h"

/*
 * Signal handling.
 * Apollo has a problem with __attribute(atomic) in signal.h,
 *   I dance around it.
 */
#if defined(apollo) || defined(macintosh) || defined(MSDOS)
#define __attribute(x)
#endif

#if defined(unix) || defined(WIN32)
#include <signal.h>
#endif

#if defined(apollo)
#undef __attribute
#endif

/*
 * Malloc debugging stuff.
 */
#if defined(sun)
#undef MALLOC_DEBUG
#endif

#if defined(MALLOC_DEBUG)
#include <malloc.h>
extern	int	malloc_debug	args( ( int  ) );
extern	int	malloc_verify	args( ( void ) );
#endif


/*
 * Socket and TCP/IP stuff.
 */
#if	defined(macintosh) || defined(MSDOS)
const	char	echo_off_str	[] = { '\0' };
const	char	echo_on_str	[] = { '\0' };
const	char 	go_ahead_str	[] = { '\0' };
#endif

#if	defined(unix)
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "telnet.h"
const	char	echo_off_str	[] = { IAC, WILL, TELOPT_ECHO, '\0' };
const	char	echo_on_str	[] = { IAC, WONT, TELOPT_ECHO, '\0' };
const	char 	go_ahead_str	[] = { IAC, GA, '\0' };
#endif



/*
 * OS-dependent declarations.
 */

#if	defined(_AIX)
#include <sys/select.h>
int	accept		args( ( int s, struct sockaddr *addr, int *addrlen ) );
int	bind		args( ( int s, struct sockaddr *name, int namelen ) );
void	bzero		args( ( char *b, int length ) );
int	getpeername	args( ( int s, struct sockaddr *name, int *namelen ) );
int	getsockname	args( ( int s, struct sockaddr *name, int *namelen ) );
int	gettimeofday	args( ( struct timeval *tp, struct timezone *tzp ) );
int	listen		args( ( int s, int backlog ) );
int	setsockopt	args( ( int s, int level, int optname, void *optval,
			    int optlen ) );
int	socket		args( ( int domain, int type, int protocol ) );
#endif

#if	defined(apollo)
#include <unistd.h>
void	bzero		args( ( char *b, int length ) );
#endif

#if	defined(__hpux)
int	accept		args( ( int s, void *addr, int *addrlen ) );
int	bind		args( ( int s, const void *addr, int addrlen ) );
void	bzero		args( ( char *b, int length ) );
int	getpeername	args( ( int s, void *addr, int *addrlen ) );
int	getsockname	args( ( int s, void *name, int *addrlen ) );
int	gettimeofday	args( ( struct timeval *tp, struct timezone *tzp ) );
int	listen		args( ( int s, int backlog ) );
int	setsockopt	args( ( int s, int level, int optname,
 				const void *optval, int optlen ) );
int	socket		args( ( int domain, int type, int protocol ) );
#endif

#if	defined(interactive)
#include <net/errno.h>
#include <sys/fnctl.h>
#endif

#if	defined( WIN32 )
int    gettimeofday    args( ( struct timeval *tp, void *tzp ) );
#endif

#if	defined(linux)
/*
int	accept		args( ( int s, struct sockaddr *addr, int *addrlen ) );
int	bind		args( ( int s, struct sockaddr *name, int namelen ) );
*/
/* You may need to uncomment these next three lines, depending on your Linux */
/*
int	getpeername	args( ( int s, struct sockaddr *name, int *namelen ) );
int	getsockname	args( ( int s, struct sockaddr *name, int *namelen ) );
int	listen		args( ( int s, int backlog ) );
*/
int	close		args( ( int fd ) );
int	gettimeofday	args( ( struct timeval *tp, struct timezone *tzp ) );
// int	read		args( ( int fd, char *buf, int nbyte ) );
int	select		args( ( int width, fd_set *readfds, fd_set *writefds,
			    fd_set *exceptfds, struct timeval *timeout ) );
int	socket		args( ( int domain, int type, int protocol ) );
// int	write		args( ( int fd, char *buf, int nbyte ) );
#endif

#if	defined(macintosh)
#include <console.h>
#include <fcntl.h>
#include <unix.h>
struct	timeval
{
	time_t	tv_sec;
	time_t	tv_usec;
};
#if	!defined(isascii)
#define	isascii(c)		( (c) < 0200 )
#endif
static	long			theKeys	[4];

int	gettimeofday		args( ( struct timeval *tp, void *tzp ) );
#endif

#if	defined(MIPS_OS)
extern	int		errno;
#endif

#if	defined(MSDOS)
int	gettimeofday	args( ( struct timeval *tp, void *tzp ) );
int	kbhit		args( ( void ) );
#endif

#if	defined(NeXT)
int	close		args( ( int fd ) );
int	fcntl		args( ( int fd, int cmd, int arg ) );
#if	!defined(htons)
u_short	htons		args( ( u_short hostshort ) );
#endif
#if	!defined(ntohl)
u_long	ntohl		args( ( u_long hostlong ) );
#endif
int	read		args( ( int fd, char *buf, int nbyte ) );
int	select		args( ( int width, fd_set *readfds, fd_set *writefds,
			    fd_set *exceptfds, struct timeval *timeout ) );
int	write		args( ( int fd, char *buf, int nbyte ) );
#endif

#if	defined(sequent)
int	accept		args( ( int s, struct sockaddr *addr, int *addrlen ) );
int	bind		args( ( int s, struct sockaddr *name, int namelen ) );
int	close		args( ( int fd ) );
int	fcntl		args( ( int fd, int cmd, int arg ) );
int	getpeername	args( ( int s, struct sockaddr *name, int *namelen ) );
int	getsockname	args( ( int s, struct sockaddr *name, int *namelen ) );
int	gettimeofday	args( ( struct timeval *tp, struct timezone *tzp ) );
#if	!defined(htons)
u_short	htons		args( ( u_short hostshort ) );
#endif
int	listen		args( ( int s, int backlog ) );
#if	!defined(ntohl)
u_long	ntohl		args( ( u_long hostlong ) );
#endif
int	read		args( ( int fd, char *buf, int nbyte ) );
int	select		args( ( int width, fd_set *readfds, fd_set *writefds,
			    fd_set *exceptfds, struct timeval *timeout ) );
int	setsockopt	args( ( int s, int level, int optname, caddr_t optval,
			    int optlen ) );
int	socket		args( ( int domain, int type, int protocol ) );
int	write		args( ( int fd, char *buf, int nbyte ) );
#endif

/* This includes Solaris Sys V as well */
#if defined(solaris)
// int     accept          args( ( int s, struct sockaddr *addr, int *addrlen ) );
//int     bind            args( ( int s, struct sockaddr *name, int namelen ) );
// void    bzero           args( ( char *b, int length ) );
int     close           args( ( int fd ) );
// int     getpeername     args( ( int s, struct sockaddr *name, int *namelen ) );
// int     getsockname     args( ( int s, struct sockaddr *name, int *namelen ) );
//int   gettimeofday    args( ( struct timeval *tp, struct timezone *tzp ) );
// int     listen          args( ( int s, int backlog ) );
// int     read            args( ( int fd, char *buf, int nbyte ) );
int     select          args( ( int width, fd_set *readfds, fd_set *writefds,
                            fd_set *exceptfds, struct timeval *timeout ) );
// int setsockopt          args( ( int s, int level, int optname,
  //                           const char *optval, int optlen ) );
int     socket          args( ( int domain, int type, int protocol ) );
// int     write           args( ( int fd, char *buf, int nbyte ) );
#else
#if defined(sun)
int	accept		args( ( int s, struct sockaddr *addr, int *addrlen ) );
int	bind		args( ( int s, struct sockaddr *name, int namelen ) );
void	bzero		args( ( char *b, int length ) );
int	close		args( ( int fd ) );
int	getpeername	args( ( int s, struct sockaddr *name, int *namelen ) );
int	getsockname	args( ( int s, struct sockaddr *name, int *namelen ) );
int	gettimeofday	args( ( struct timeval *tp, struct timezone *tzp ) );
int	listen		args( ( int s, int backlog ) );
int	read		args( ( int fd, char *buf, int nbyte ) );
int	select		args( ( int width, fd_set *readfds, fd_set *writefds,
			    fd_set *exceptfds, struct timeval *timeout ) );
#if defined(SYSV)
int setsockopt		args( ( int s, int level, int optname,
			    const char *optval, int optlen ) );
#else
int	setsockopt	args( ( int s, int level, int optname, void *optval,
			    int optlen ) );
#endif
int	socket		args( ( int domain, int type, int protocol ) );
int	write		args( ( int fd, char *buf, int nbyte ) );
#endif
#endif

#if defined(ultrix)
int	accept		args( ( int s, struct sockaddr *addr, int *addrlen ) );
int	bind		args( ( int s, struct sockaddr *name, int namelen ) );
void	bzero		args( ( char *b, int length ) );
int	close		args( ( int fd ) );
int	getpeername	args( ( int s, struct sockaddr *name, int *namelen ) );
int	getsockname	args( ( int s, struct sockaddr *name, int *namelen ) );
int	gettimeofday	args( ( struct timeval *tp, struct timezone *tzp ) );
int	listen		args( ( int s, int backlog ) );
int	read		args( ( int fd, char *buf, int nbyte ) );
int	select		args( ( int width, fd_set *readfds, fd_set *writefds,
			    fd_set *exceptfds, struct timeval *timeout ) );
int	setsockopt	args( ( int s, int level, int optname, void *optval,
			    int optlen ) );
int	socket		args( ( int domain, int type, int protocol ) );
int	write		args( ( int fd, char *buf, int nbyte ) );
#endif



/*
 * Global variables.
 */
DESCRIPTOR_DATA *   descriptor_list;	/* All open descriptors		*/
DESCRIPTOR_DATA *   d_next;		/* Next descriptor in loop	*/
FILE *		    fpReserve;		/* Reserved file handle		*/
bool		    god;		/* All new chars are gods!	*/
bool		    merc_down;		/* Shutdown			*/
bool		    wizlock;		/* Game is wizlocked		*/
bool		    newlock;		/* Game is newlocked		*/
char		    str_boot_time[MIL];
time_t		    current_time;	/* time of this pulse */	
char		    clcode[ MIL ];
sh_int arena;
bool                MOBtrigger = TRUE;  /* act() switch                 */


/*
 * OS-dependent local functions.
 */
#if defined(macintosh) || defined(MSDOS)
void	game_loop_mac_msdos	args( ( void ) );
bool	read_from_descriptor	args( ( DESCRIPTOR_DATA *d ) );
bool	write_to_descriptor	args( ( int desc, char *txt, int length ) );
#endif

#if defined(unix) || defined(WIN32)
void	game_loop_unix		args( ( int control ) );
int	init_socket		args( ( int port ) );
void	init_descriptor		args( ( int control ) );
bool	read_from_descriptor	args( ( DESCRIPTOR_DATA *d ) );
bool	write_to_descriptor	args( ( int desc, char *txt, int length ) );
#endif




/*
 * Other local functions (OS-independent).
 */
bool	check_parse_name	args( ( char *name ) );
bool	check_reconnect		args( ( DESCRIPTOR_DATA *d, char *name,
				    bool fConn ) );
bool	check_playing		args( ( DESCRIPTOR_DATA *d, char *name ) );
int	main			args( ( int argc, char **argv ) );
void	nanny			args( ( DESCRIPTOR_DATA *d, char *argument ) );
bool	process_output		args( ( DESCRIPTOR_DATA *d, bool fPrompt ) );
void	read_from_buffer	args( ( DESCRIPTOR_DATA *d ) );
void	stop_idling		args( ( CHAR_DATA *ch ) );
void    bust_a_prompt           args( ( CHAR_DATA *ch ) );
int port, control;


int main( int argc, char **argv )
{
    struct timeval now_time;
	 bool fCopyOver = FALSE;

    /*
     * Memory debugging if needed.
     */
#if defined(MALLOC_DEBUG)
    malloc_debug( 2 );
#endif

    /*
     * Init time.
     */
    gettimeofday( &now_time, NULL );
    current_time 	= (time_t) now_time.tv_sec;
    strcpy( str_boot_time, ctime( &current_time ) );


    /*
     * Macintosh console initialization.
     */
#if defined(macintosh)
    console_options.nrows = 31;
    cshow( stdout );
    csetmode( C_RAW, stdin );
    cecho2file( "log file", 1, stderr );
#endif

    /*
     * Reserve one channel for our use.
     */
    if ( ( fpReserve = fopen( NULL_FILE, "r" ) ) == NULL )
    {
	perror( NULL_FILE );
	exit( 1 );
    }

    /*
     * Get the port number.
     */
    port = 4000;
    if ( argc > 1 )
    {
	if ( !is_number( argv[1] ) )
	{
	    fprintf( stderr, "Usage: %s [port #]", argv[0] );
	    exit( 1 );
	}
	else if ( ( port = atoi( argv[1] ) ) <= 1024 )
	{
	    fprintf( stderr, "Port numbers must be above 1024.\n" );
	    exit( 1 );
	}
	/* Are we recovering from a copyover? */
 	if (argv[2] && argv[2][0])
 	{
 		fCopyOver = TRUE;
 		control = atoi(argv[3]);
 	}
 	else
 		fCopyOver = FALSE;	
   }

    /*
     * Run the game.
     */
#if defined(macintosh) || defined(MSDOS)
    boot_db();
    log_string( "Merc is ready to rock." );
    game_loop_mac_msdos( );
#endif

#if defined(unix) || defined( WIN32 )

	if (!fCopyOver)
	    control = init_socket( port );

    boot_db();
    arena = FIGHT_OPEN;
    sprintf( log_buf, "RoT2.0 is ready to rock on port %d.", port );
    log_string( log_buf );

    if (fCopyOver)
    	copyover_recover();

    game_loop_unix( control ); 
#if !defined( WIN32 )
    close( control );
#else
    closesocket( control );
    WSACleanup();
#endif
#endif

    /*
     * That's all, folks.
     */
    log_string( "Normal termination of game." );
    exit( 0 );
    return 0;
}

void logfprint (char * fmt, ...)
{
	char buf [2*MSL];
	va_list args;
	va_start (args, fmt);
	vsprintf (buf, fmt, args);
	va_end (args);
	
	log_string (buf);
}


#if defined(unix) || defined(WIN32)
int init_socket( int port )
{
    static struct sockaddr_in sa_zero;
    struct sockaddr_in sa;
    int x = 1;
    int fd;

#if defined( WIN32 )
    WORD    wVersionRequested = MAKEWORD( 1, 1 );
    WSADATA wsaData;
    int err = WSAStartup( wVersionRequested, &wsaData ); 
    if ( err != 0 )
    {
	perror( "No useable WINSOCK.DLL" );
	exit( 1 );
    }    
#endif
    if ( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
    {
	perror( "Init_socket: socket" );
	exit( 1 );
    }

    if ( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
    (char *) &x, sizeof(x) ) < 0 )
    {
	perror( "Init_socket: SO_REUSEADDR" );
#if !defined( WIN32 )
	close( fd );
#else
	closesocket( fd );
#endif
	exit( 1 );
    }

#if defined(SO_DONTLINGER) && !defined(SYSV) && !defined(solaris)
    {
	struct	linger	ld;

	ld.l_onoff  = 1;
	ld.l_linger = 1000;

	if ( setsockopt( fd, SOL_SOCKET, SO_DONTLINGER,
	(char *) &ld, sizeof(ld) ) < 0 )
	{
	    perror( "Init_socket: SO_DONTLINGER" );
#if !defined( WIN32 )
	    close( fd );
#else
	    closesocket( fd );
#endif
	    exit( 1 );
	}
    }
#endif

    sa		    = sa_zero;
    sa.sin_family   = AF_INET;
    sa.sin_port	    = htons( port );

    if ( bind( fd, (struct sockaddr *) &sa, sizeof(sa) ) < 0 )
    {
	perror("Init socket: bind" );
#if !defined( WIN32 )
	close( fd );
#else
	closesocket( fd );
#endif
	exit(1);
    }


    if ( listen( fd, 3 ) < 0 )
    {
	perror("Init socket: listen");
#if !defined( WIN32 )
	close( fd );
#else
	closesocket( fd );
#endif
	exit(1);
    }

    return fd;
}
#endif



#if defined(macintosh) || defined(MSDOS)
void game_loop_mac_msdos( void )
{
    struct timeval last_time;
    struct timeval now_time;
    static DESCRIPTOR_DATA dcon;

    gettimeofday( &last_time, NULL );
    current_time = (time_t) last_time.tv_sec;

    /*
     * New_descriptor analogue.
     */
    dcon.descriptor	= 0;
    dcon.ansi		= TRUE;
    dcon.connected	= CON_GET_NAME;
    dcon.host		= str_dup( "localhost" );
    dcon.outsize	= 2000;
    dcon.outbuf		= alloc_mem( dcon.outsize );
    dcon.next		= descriptor_list;
    dcon.showstr_head	= NULL;
    dcon.showstr_point	= NULL;
    dcon.pEdit		= NULL;			/* OLC */
    dcon.pString	= NULL;			/* OLC */
    dcon.editor		= 0;			/* OLC */
    descriptor_list	= &dcon;

    /*
     * Send the greeting.
     */
    {
	extern char * help_greetinga;
	extern char * help_greetingb;
	extern char * help_greetingc;
	extern char * help_greetingd;
	extern char * help_greetinge;
	extern char * help_authors;
	extern char * help_login;
	switch (number_range(0,4))
	{
	    default:
		if ( help_greetinga[0] == '.' )
		    send_to_desc( help_greetinga+1, &dcon );
		else
		    send_to_desc( help_greetinga, &dcon );
		break;
	    case 0:
		if ( help_greetinga[0] == '.' )
		    send_to_desc( help_greetinga+1, &dcon );
		else
		    send_to_desc( help_greetinga, &dcon );
		break;
	    case 1:
		if ( help_greetingb[0] == '.' )
		    send_to_desc( help_greetingb+1, &dcon );
		else
		    send_to_desc( help_greetingb, &dcon );
		break;
	    case 2:
		if ( help_greetingc[0] == '.' )
		    send_to_desc( help_greetingc+1, &dcon );
		else
		    send_to_desc( help_greetingc, &dcon );
		break;
	    case 3:
		if ( help_greetingd[0] == '.' )
		    send_to_desc( help_greetingd+1, &dcon );
		else
		    send_to_desc( help_greetingd, &dcon );
		break;
	    case 4:
		if ( help_greetinge[0] == '.' )
		    send_to_desc( help_greetinge+1, &dcon );
		else
		    send_to_desc( help_greetinge, &dcon );
		break;
	}
	if ( help_authors[0] == '.' )
	    send_to_desc( help_authors+1, &dcon );
	else
	    send_to_desc( help_authors, &dcon );
	if ( help_login[0] == '.' )
	    send_to_desc( help_login+1, &dcon );
	else
	    send_to_desc( help_login, &dcon );
    }

    /* Main loop */
    while ( !merc_down )
    {
	DESCRIPTOR_DATA *d;

	/*
	 * Process input.
	 */
	for ( d = descriptor_list; d != NULL; d = d_next )
	{
	    d_next	= d->next;
	    d->fcommand	= FALSE;

#if defined(MSDOS)
	    if ( kbhit( ) )
#endif
	    {
		if ( d->character != NULL )
		    d->character->timer = 0;
		if ( !read_from_descriptor( d ) )
		{
		    if ( d->character != NULL)
			save_char_obj( d->character );
		    d->outtop	= 0;
		    close_socket( d );
		    continue;
		}
	    }

	    if (d->character != NULL && d->character->daze > 0)
		--d->character->daze;

	    if ( d->character != NULL && d->character->wait > 0 )
	    {
		--d->character->wait;
		continue;
	    }

	    read_from_buffer( d );
	    if ( d->incomm[0] != '\0' )
	    {
		d->fcommand	= TRUE;
		stop_idling( d->character );

	/* OLC */
	        if ( d->showstr_point )
	            show_string( d, d->incomm );
	        else
	        if ( d->pString )
	            string_add( d->character, d->incomm );
	        else
	            switch ( d->connected )
	            {
	                case CON_PLAYING:
			    if ( !run_olc_editor( d ) )
				substitute_alias( d, d->incomm );
			    break;
	                default:
			    nanny( d, d->incomm );
			    break;
	            }


		d->incomm[0]	= '\0';
	    }
	}



	/*
	 * Autonomous game motion.
	 */
	update_handler( FALSE );



	/*
	 * Output.
	 */
	for ( d = descriptor_list; d != NULL; d = d_next )
	{
	    d_next = d->next;

	    if ( ( d->fcommand || d->outtop > 0 ) )
	    {
		if ( !process_output( d, TRUE ) )
		{
		    if ( d->character != NULL && d->character->level > 1)
			save_char_obj( d->character );
		    d->outtop	= 0;
		    close_socket( d );
		}
	    }
	}



	/*
	 * Synchronize to a clock.
	 * Busy wait (blargh).
	 */
	now_time = last_time;
	for ( ; ; )
	{
	    int delta;

#if defined(MSDOS)
	    if ( kbhit( ) )
#endif
	    {
		if ( dcon.character != NULL )
		    dcon.character->timer = 0;
		if ( !read_from_descriptor( &dcon ) )
		{
		    if ( dcon.character != NULL && d->character->level > 1)
			save_char_obj( d->character );
		    dcon.outtop	= 0;
		    close_socket( &dcon );
		}
#if defined(MSDOS)
		break;
#endif
	    }

	    gettimeofday( &now_time, NULL );
	    delta = ( now_time.tv_sec  - last_time.tv_sec  ) * 1000 * 1000
		  + ( now_time.tv_usec - last_time.tv_usec );
	    if ( delta >= 1000000 / PULSE_PER_SECOND )
		break;
	}
	last_time    = now_time;
	current_time = (time_t) last_time.tv_sec;
    }

    return;
}
#endif



#if defined(unix) || defined(WIN32)
void game_loop_unix( int control )
{
    static struct timeval null_time;
    struct timeval last_time;

#if !defined( AmigaTCP ) && !defined( WIN32 )
    signal( SIGPIPE, SIG_IGN );
#endif
    gettimeofday( &last_time, NULL );
    current_time = (time_t) last_time.tv_sec;

    /* Main loop */
    while ( !merc_down )
    {
	fd_set in_set;
	fd_set out_set;
	fd_set exc_set;
	DESCRIPTOR_DATA *d;
	int maxdesc;

#if defined(MALLOC_DEBUG)
	if ( malloc_verify( ) != 1 )
	    abort( );
#endif

	/*
	 * Poll all active descriptors.
	 */
	FD_ZERO( &in_set  );
	FD_ZERO( &out_set );
	FD_ZERO( &exc_set );
	FD_SET( control, &in_set );
	maxdesc	= control;
	for ( d = descriptor_list; d; d = d->next )
	{
	    maxdesc = UMAX( maxdesc, d->descriptor );
	    FD_SET( d->descriptor, &in_set  );
	    FD_SET( d->descriptor, &out_set );
	    FD_SET( d->descriptor, &exc_set );
	}

	if ( select( maxdesc+1, &in_set, &out_set, &exc_set, &null_time ) < 0 )
	{
	    perror( "Game_loop: select: poll" );
	    exit( 1 );
	}

	/*
	 * New connection?
	 */
	if ( FD_ISSET( control, &in_set ) )
	    init_descriptor( control );

	FD_ZERO( &in_set  );
	FD_ZERO( &out_set );
	FD_ZERO( &exc_set );
	FD_SET( control, &in_set );
	maxdesc	= control;
	for ( d = descriptor_list; d; d = d->next )
	{
	    maxdesc = UMAX( maxdesc, d->descriptor );
	    FD_SET( d->descriptor, &in_set  );
	    FD_SET( d->descriptor, &out_set );
	    FD_SET( d->descriptor, &exc_set );
	}

	if ( select( maxdesc+1, &in_set, &out_set, &exc_set, &null_time ) < 0 )
	{
	    perror( "Game_loop: select: poll" );
	    exit( 1 );
	}

	if ( FD_ISSET( control, &in_set ) )
	    init_descriptor( control );

	/*
	 * Kick out the freaky folks.
	 */
	for ( d = descriptor_list; d != NULL; d = d_next )
	{
	    d_next = d->next;   
	    if ( FD_ISSET( d->descriptor, &exc_set ) )
	    {
		FD_CLR( d->descriptor, &in_set  );
		FD_CLR( d->descriptor, &out_set );
		if ( d->character && d->character->level > 1)
		    save_char_obj( d->character );
		d->outtop	= 0;
		close_socket( d );
	    }
	}

	/*
	 * Process input.
	 */
	for ( d = descriptor_list; d != NULL; d = d_next )
	{
	    d_next	= d->next;
	    d->fcommand	= FALSE;

	    if ( FD_ISSET( d->descriptor, &in_set ) )
	    {
		if ( d->character != NULL )
		    d->character->timer = 0;
		if ( !read_from_descriptor( d ) )
		{
		    FD_CLR( d->descriptor, &out_set );
		    if ( d->character != NULL && d->character->level > 1)
			save_char_obj( d->character );
		    d->outtop	= 0;
		    close_socket( d );
		    continue;
		}
	    }

	    if (d->character != NULL && d->character->daze > 0)
		--d->character->daze;

	    if ( d->character != NULL && d->character->wait > 0 )
	    {
		--d->character->wait;
		continue;
	    }

	    read_from_buffer( d );
	    if ( d->incomm[0] != '\0' )
	    {
		d->fcommand	= TRUE;
		stop_idling( d->character );

		/* OLC */
	if ( d->showstr_point )
	    show_string( d, d->incomm );
	else
	if ( d->pString )
	    string_add( d->character, d->incomm );
	else
	    switch ( d->connected )
	    {
	        case CON_PLAYING:
		    if ( !run_olc_editor( d ) )
    		        substitute_alias( d, d->incomm );
		    break;
	        default:

		    nanny( d, d->incomm );
                break;
          }

		d->incomm[0]	= '\0';
	    }
	}



	/*
	 * Autonomous game motion.
	 */
	update_handler( FALSE );



	/*
	 * Output.
	 */
	for ( d = descriptor_list; d != NULL; d = d_next )
	{
	    d_next = d->next;

	    if ( ( d->fcommand || d->outtop > 0 )
	    &&   FD_ISSET(d->descriptor, &out_set) )
	    {
		if ( !process_output( d, TRUE ) )
		{
		    if ( d->character != NULL && d->character->level > 1)
			save_char_obj( d->character );
		    d->outtop	= 0;
		    close_socket( d );
		}
	    }
	}



	/*
	 * Synchronize to a clock.
	 * Sleep( last_time + 1/PULSE_PER_SECOND - now ).
	 * Careful here of signed versus unsigned arithmetic.
	 */
#ifndef WIN32
	{
	    struct timeval now_time;
	    long secDelta;
	    long usecDelta;

	    gettimeofday( &now_time, NULL );
	    usecDelta	= ((int) last_time.tv_usec) - ((int) now_time.tv_usec)
			+ 1000000 / PULSE_PER_SECOND;
	    secDelta	= ((int) last_time.tv_sec ) - ((int) now_time.tv_sec );
	    while ( usecDelta < 0 )
	    {
		usecDelta += 1000000;
		secDelta  -= 1;
	    }

	    while ( usecDelta >= 1000000 )
	    {
		usecDelta -= 1000000;
		secDelta  += 1;
	    }

	    if ( secDelta > 0 || ( secDelta == 0 && usecDelta > 0 ) )
	    {
		struct timeval stall_time;

		stall_time.tv_usec = usecDelta;
		stall_time.tv_sec  = secDelta;
		if ( select( 0, NULL, NULL, NULL, &stall_time ) < 0 )
		{
		    perror( "Game_loop: select: stall" );
		    exit( 1 );
		}
	    }
	}
#else
	{
	    int times_up;
	    int nappy_time;
	    struct _timeb start_time;
	    struct _timeb end_time;
	    _ftime( &start_time );
	    times_up = 0;

	    while( times_up == 0 )
	    {
		_ftime( &end_time );
		if ( ( nappy_time =
		      (int) ( 1000 *
			     (double) ( ( end_time.time - start_time.time ) +
				       ( (double) ( end_time.millitm -
						   start_time.millitm ) /
					1000.0 ) ) ) ) >=
		    (double)( 1000 / PULSE_PER_SECOND ) )
		  times_up = 1;
		else
		{
		    Sleep( (int) ( (double) ( 1000 / PULSE_PER_SECOND ) -
				  (double) nappy_time ) );
		    times_up = 1;
		}
	    }
	}
#endif

	gettimeofday( &last_time, NULL );
	current_time = (time_t) last_time.tv_sec;
    }

    return;
}
#endif


#if defined(unix) || defined( WIN32 )
void init_descriptor( int control )
{
    char buf[MAX_STRING_LENGTH];
    DESCRIPTOR_DATA *dnew;
    struct sockaddr_in sock;
    struct hostent *from;
    int desc;
    int size;

    size = sizeof(sock);
    getsockname( control, (struct sockaddr *) &sock, &size );
    if ( ( desc = accept( control, (struct sockaddr *) &sock, &size) ) < 0 )
    {
	perror( "New_descriptor: accept" );
	return;
    }

#if !defined(FNDELAY)
#define FNDELAY O_NDELAY
#endif

#if !defined( AmigaTCP ) && !defined( WIN32 )
    if ( fcntl( desc, F_SETFL, FNDELAY ) == -1 )
    {
	perror( "New_descriptor: fcntl: FNDELAY" );
	return;
    }
#endif

    /*
     * Cons a new descriptor.
     */
    dnew = new_descriptor();

    dnew->descriptor	= desc;
    dnew->ansi		= TRUE;
    dnew->connected	= CON_GET_NAME;
    dnew->showstr_head	= NULL;
    dnew->showstr_point = NULL;
    dnew->outsize	= 2000;
    dnew->pEdit		= NULL;			/* OLC */
    dnew->pString	= NULL;			/* OLC */
    dnew->editor	= 0;			/* OLC */
    dnew->outbuf	= alloc_mem( dnew->outsize );

    size = sizeof(sock);
    if ( getpeername( desc, (struct sockaddr *) &sock, &size ) < 0 )
    {
	perror( "New_descriptor: getpeername" );
	dnew->host = str_dup( "(unknown)" );
    }
    else
    {
	/*
	 * Would be nice to use inet_ntoa here but it takes a struct arg,
	 * which ain't very compatible between gcc and system libraries.
	 */
	int addr;

	addr = ntohl( sock.sin_addr.s_addr );
	sprintf( buf, "%d.%d.%d.%d",
	    ( addr >> 24 ) & 0xFF, ( addr >> 16 ) & 0xFF,
	    ( addr >>  8 ) & 0xFF, ( addr       ) & 0xFF
	    );
	sprintf( log_buf, "Sock.sinaddr:  %s", buf );
	log_string( log_buf );
	from = gethostbyaddr( (char *) &sock.sin_addr,
	    sizeof(sock.sin_addr), AF_INET );
	dnew->host = str_dup( from ? from->h_name : buf );
    }
	
    /*
     * Swiftest: I added the following to ban sites.  I don't
     * endorse banning of sites, but Copper has few descriptors now
     * and some people from certain sites keep abusing access by
     * using automated 'autodialers' and leaving connections hanging.
     *
     * Furey: added suffix check by request of Nickel of HiddenWorlds.
     */
    if ( check_ban(dnew->host,BAN_ALL))
    {
	write_to_descriptor( desc,
	    "Your site has been banned from this mud.\n\r", 0 );
#if !defined( WIN32 )
	    close( desc );
#else
	    closesocket( desc );
#endif
	free_descriptor(dnew);
	return;
    }
    /*
     * Init descriptor data.
     */
    dnew->next			= descriptor_list;
    descriptor_list		= dnew;

    /*
     * Send the greeting.
     */
    {
	extern char * help_greetinga;
	extern char * help_greetingb;
	extern char * help_greetingc;
	extern char * help_greetingd;
	extern char * help_greetinge;
	extern char * help_authors;
	extern char * help_login;
	switch (number_range(0,4))
	{
	    default:
		if ( help_greetinga[0] == '.' )
		    send_to_desc( help_greetinga+1, dnew );
		else
		    send_to_desc( help_greetinga, dnew );
		break;
	    case 0:
		if ( help_greetinga[0] == '.' )
		    send_to_desc( help_greetinga+1, dnew );
		else
		    send_to_desc(help_greetinga, dnew );
		break;
	    case 1:
		if ( help_greetingb[0] == '.' )
		    send_to_desc( help_greetingb+1, dnew );
		else
		    send_to_desc( help_greetingb, dnew );
		break;
	    case 2:
		if ( help_greetingc[0] == '.' )
		    send_to_desc( help_greetingc+1, dnew );
		else
		    send_to_desc( help_greetingc, dnew );
		break;
	    case 3:
		if ( help_greetingd[0] == '.' )
		    send_to_desc( help_greetingd+1, dnew );
		else
		    send_to_desc( help_greetingd, dnew );
		break;
	    case 4:
		if ( help_greetinge[0] == '.' )
		    send_to_desc( help_greetinge+1,dnew );
		else
		    send_to_desc( help_greetinge, dnew );
		break;
	}
	if ( help_authors[0] == '.' )
	    send_to_desc( help_authors+1, dnew );
	else
	    send_to_desc( help_authors, dnew );
	if ( help_login[0] == '.' )
	    send_to_desc( help_login+1, dnew );
	else
	    send_to_desc( help_login, dnew );
    }
    return;
}
#endif


void close_socket( DESCRIPTOR_DATA *dclose )
{
    CHAR_DATA *ch;

    if ( dclose->outtop > 0 )
	process_output( dclose, FALSE );

    if ( dclose->snoop_by != NULL )
    {
	write_to_buffer( dclose->snoop_by,
	    "Your victim has left the game.\n\r", 0 );
    }

    {
	DESCRIPTOR_DATA *d;

	for ( d = descriptor_list; d != NULL; d = d->next )
	{
	    if ( d->snoop_by == dclose )
		d->snoop_by = NULL;
	}
    }

    if ( ( ch = dclose->character ) != NULL )
    {
	sprintf( log_buf, "Closing link to %s.", ch->name );
	log_string( log_buf );
	if ( dclose->connected == CON_PLAYING )
	{
	    act( "$n has lost $s link.", ch, NULL, NULL, TO_ROOM );
	    wiznet("Net death has claimed $N.",ch,NULL,WIZ_LINKS,0,0);
            {
               char buf[MAX_STRING_LENGTH];
               act( buf, ch, NULL, NULL, TO_ALL );
            }
	    ch->desc = NULL;
	}
	else
	{
  	    nuke_pets( dclose->character );
	    free_char( dclose->original ? dclose->original : dclose->character );
	}
    }

    if ( d_next == dclose )
	d_next = d_next->next;   

    if ( dclose == descriptor_list )
    {
	descriptor_list = descriptor_list->next;
    }
    else
    {
	DESCRIPTOR_DATA *d;

	for ( d = descriptor_list; d && d->next != dclose; d = d->next )
	    ;
	if ( d != NULL )
	    d->next = dclose->next;
	else
	    bug( "Close_socket: dclose not found.", 0 );
    }

#if !defined( WIN32 )
    close( dclose->descriptor );
#else
    closesocket( dclose->descriptor );
#endif

    free_descriptor(dclose);
#if defined(MSDOS) || defined(macintosh)
    exit(1);
#endif
    return;
}



bool read_from_descriptor( DESCRIPTOR_DATA *d )
{
    int iStart;

    /* Hold horses if pending command already. */
    if ( d->incomm[0] != '\0' )
	return TRUE;

    /* Check for overflow. */
    iStart = strlen(d->inbuf);
    if ( iStart >= sizeof(d->inbuf) - 10 )
    {
	sprintf( log_buf, "%s input overflow!", d->host );
	log_string( log_buf );
	write_to_descriptor( d->descriptor,
	    "\n\r*** PUT A LID ON IT!!! ***\n\r", 0 );
	return FALSE;
    }

    /* Snarf input. */
#if defined(macintosh)
    for ( ; ; )
    {
	int c;
	c = getc( stdin );
	if ( c == '\0' || c == EOF )
	    break;
	putc( c, stdout );
	if ( c == '\r' )
	    putc( '\n', stdout );
	d->inbuf[iStart++] = c;
	if ( iStart > sizeof(d->inbuf) - 10 )
	    break;
    }
#endif

#if defined(MSDOS) || defined(unix) || defined(WIN32)
    for ( ; ; )
    {
	int nRead;

#if !defined( WIN32 )
	nRead = read( d->descriptor, d->inbuf + iStart,
		     sizeof( d->inbuf ) - 10 - iStart );
#else
	nRead = recv( d->descriptor, d->inbuf + iStart,
		     sizeof( d->inbuf ) - 10 - iStart, 0 );
#endif
	
	if ( nRead > 0 )
	{
	    iStart += nRead;
	    if ( d->inbuf[iStart-1] == '\n' || d->inbuf[iStart-1] == '\r' )
		break;
	}
	else if ( nRead == 0 )
	{
	    log_string( "EOF encountered on read." );
	    return FALSE;
	}
#if !defined( AmigaTCP ) && !defined( WIN32 )
        else if ( errno == EWOULDBLOCK || errno == EAGAIN )
	    break;
#endif
#if defined( WIN32 )
        else if ( WSAGetLastError() == WSAEWOULDBLOCK || errno == EAGAIN )
	    break;
#endif
	else
	{
	    perror( "Read_from_descriptor" );
	    return FALSE;
	}
    }
#endif

    d->inbuf[iStart] = '\0';
    return TRUE;
}



/*
 * Transfer one line from input buffer to input line.
 */
void read_from_buffer( DESCRIPTOR_DATA *d )
{
    int i, j, k;

    /*
     * Hold horses if pending command already.
     */
    if ( d->incomm[0] != '\0' )
	return;

    /*
     * Look for at least one new line.
     */
    for ( i = 0; d->inbuf[i] != '\n' && d->inbuf[i] != '\r'; i++ )
    {
	if ( d->inbuf[i] == '\0' )
	    return;
    }

    /*
     * Canonical input processing.
     */
    for ( i = 0, k = 0; d->inbuf[i] != '\n' && d->inbuf[i] != '\r'; i++ )
    {
	if ( k >= MAX_INPUT_LENGTH - 2 )
	{
	    write_to_descriptor( d->descriptor, "Line too long.\n\r", 0 );

	    /* skip the rest of the line */
	    for ( ; d->inbuf[i] != '\0'; i++ )
	    {
		if ( d->inbuf[i] == '\n' || d->inbuf[i] == '\r' )
		    break;
	    }
	    d->inbuf[i]   = '\n';
	    d->inbuf[i+1] = '\0';
	    break;
	}

	if ( d->inbuf[i] == '\b' && k > 0 )
	    --k;
	else if ( isascii(d->inbuf[i]) && isprint(d->inbuf[i]) )
	    d->incomm[k++] = d->inbuf[i];
    }

    /*
     * Finish off the line.
     */
    if ( k == 0 )
	d->incomm[k++] = ' ';
    d->incomm[k] = '\0';

    /*
     * Deal with bozos with #repeat 1000 ...
     */

    if ( k > 1 || d->incomm[0] == '!' )
    {
    	if ( d->incomm[0] != '!' && strcmp( d->incomm, d->inlast ) )
	{
	    d->repeat = 0;
	}
	else
	{
            if (++d->repeat >= 25 && d->character
                && d->connected == CON_PLAYING)
            {
                sprintf (log_buf, "%s input spamming!", d->host);
                log_string (log_buf);
                wiznet ("Spam spam spam $N spam spam spam spam spam!",
                        d->character, NULL, WIZ_SPAM, 0,
                        get_trust (d->character));
                if (d->incomm[0] == '!')
                    wiznet (d->inlast, d->character, NULL, WIZ_SPAM, 0,
                            get_trust (d->character));
                else
                    wiznet (d->incomm, d->character, NULL, WIZ_SPAM, 0,
                            get_trust (d->character));

                d->repeat = 0;
/*
        write_to_descriptor( d->descriptor,
            "\n\r*** PUT A LID ON IT!!! ***\n\r", 0 );
        strcpy( d->incomm, "quit" );
*/
            }
        }
    }


    /*
     * Do '!' substitution.
     */
    if ( d->incomm[0] == '!' )
	{
		if( d->connected == CON_PLAYING )
			strcpy( d->incomm, d->inlast );
		else
			strcpy( d->incomm, " " );
	}
    else
		strcpy( d->inlast, d->incomm );

    /*
     * Shift the input buffer.
     */
    while ( d->inbuf[i] == '\n' || d->inbuf[i] == '\r' )
	i++;
    for ( j = 0; ( d->inbuf[j] = d->inbuf[i+j] ) != '\0'; j++ )
	;
    return;
}


/*
* Low level output function.
*/
bool process_output( DESCRIPTOR_DATA *d, bool fPrompt )
{
	extern bool merc_down;
	
	/*
	* Bust a prompt.
	*/
	//	  if ( !merc_down )
	//	  {
	if (fPrompt && !merc_down && d->showstr_point)
		write_to_buffer(d,"[Hit Return to continue]\n\r",0);
	else if (fPrompt && !merc_down && d->connected == CON_PLAYING)
	{
		CHAR_DATA *ch;
		CHAR_DATA *victim;
		
		if( d->pString )
			write_to_buffer( d, "> ", 2 );			
		else
		{
			ch = d->character;
			
			/* battle prompt */
			if ((victim = ch->fighting) != NULL && can_see(ch,victim))
			{
				int percent;
				char wound[100];
				char *pbuff;
				char buf[MAX_STRING_LENGTH];
				char buffer[MAX_STRING_LENGTH*2];
				
				if (victim->max_hit > 0) 
					percent = victim->hit * 100 / victim->max_hit;
				else
					percent = -1;
				
				if (percent >= 100)
					sprintf(wound,"is in excellent condition.");
				else if (percent >= 90)
					sprintf(wound,"has a few scratches.");
				else if (percent >= 75)
					sprintf(wound,"has some small wounds and bruises.");
				else if (percent >= 50)
					sprintf(wound,"has quite a few wounds.");
				else if (percent >= 30)
					sprintf(wound,"has some big nasty wounds and scratches.");
				else if (percent >= 15)
					sprintf(wound,"looks pretty hurt.");
				else if (percent >= 0)
					sprintf(wound,"is in awful condition.");
				else
					sprintf(wound,"is bleeding to death.");
				
				sprintf(buf,"%s %s \n\r", 
					IS_NPC(victim) ? victim->short_descr : victim->name,wound);
				buf[0]	= UPPER( buf[0] );
				pbuff	= buffer;
				colourconv( pbuff, buf, d->character );
				write_to_buffer( d, buffer, 0);
			}
			
			ch = d->original ? d->original : d->character;
			if (!IS_SET(ch->comm, COMM_COMPACT) )
				write_to_buffer( d, "\n\r", 2 );
			
			
			if ( IS_SET(ch->comm, COMM_PROMPT) )
				bust_a_prompt( d->character );
			
			if (IS_SET(ch->comm,COMM_TELNET_GA))
				write_to_buffer(d,go_ahead_str,0);
		}
	}
	// }
	/*
	* Short-circuit if nothing to write.
	*/
	if ( d->outtop == 0 )
		return TRUE;
	
		/*
		* Snoop-o-rama.
	*/
	if ( d->snoop_by != NULL )
	{
		if (d->character != NULL)
			write_to_buffer( d->snoop_by, d->character->name,0);
		write_to_buffer( d->snoop_by, "> ", 2 );
		write_to_buffer( d->snoop_by, d->outbuf, d->outtop );
	}
	
	/*
	* OS-dependent output.
	*/
	if ( !write_to_descriptor( d->descriptor, d->outbuf, d->outtop ) )
	{
		d->outtop = 0;
		return FALSE;
	}
	else
	{
		d->outtop = 0;
		return TRUE;
	}
}

/*
 * Bust a prompt (player settable prompt)
 * coded by Morgenes for Aldara Mud
 */
void bust_a_prompt (CHAR_DATA * ch)
{
    char buf[MAX_STRING_LENGTH];
    char buf2[MAX_STRING_LENGTH];
    const char *str;
    const char *i;
    char *point;
    char *pbuff;
    char buffer[MAX_STRING_LENGTH * 2];
    char doors[MAX_INPUT_LENGTH];
    EXIT_DATA *pexit;
    bool found;
    const char *dir_name[] = {"north","east","south","west","up","down"};
    int door;

    point = buf;
    str = ch->prompt;
    if (str == NULL || str[0] == '\0')
    {
        sprintf (buf, "{p<%dhp %dm %dmv>{x %s",
                 ch->hit, ch->mana, ch->move, ch->prefix);
        send_to_char (buf, ch);
        return;
    }

    if (IS_SET (ch->comm, COMM_AFK))
    {
        send_to_char ("<{yAFK{x> ", ch);
        return;
    }

    while (*str != '\0')
    {
        if (*str != '%')
        {
            *point++ = *str++;
            continue;
        }
        ++str;
        switch (*str)
        {
            default:
                i = " ";
                break;
            case 'e':
                found = FALSE;
                doors[0] = '\0';
                for (door = 0; door < 6; door++)
                {
                    if ((pexit = ch->in_room->exit[door]) != NULL
                        && pexit->u1.to_room != NULL
                        && (can_see_room (ch, pexit->u1.to_room)
                            || (IS_AFFECTED (ch, AFF_INFRARED)
                                && !IS_AFFECTED (ch, AFF_BLIND)))
                        && !IS_SET (pexit->exit_info, EX_CLOSED))
                    {
                        found = TRUE;
                        strcat (doors, dir_name[door]);
                    }
                }
                if (!found)
                    strcat (buf, "none");
                sprintf (buf2, "%s", doors);
                i = buf2;
                break;
            case 'c': sprintf (buf2, "%s", "\n\r"); i = buf2; break;
            case 'h': sprintf (buf2, "%d", ch->hit); i = buf2; break;
            case 'q': 

if ( global_prq && global_xpq && global_damq    ){ sprintf (buf2, "PRQx2 XPx2 DAMx2"); i = buf2; break; }
else if ( !global_prq && !global_xpq && !global_damq ){ sprintf (buf2, "off"); i = buf2; break; }
if ( global_xpq && global_damq   ){ sprintf (buf2, "XPx2 DAMx2"); i = buf2; break; }
else if ( !global_xpq && !global_damq ){ sprintf (buf2, "off"); i = buf2; break; }
if ( global_xpq && global_prq    ){ sprintf (buf2, "XPx2 PRx2"); i = buf2; break; }
else if ( !global_xpq && !global_prq  ){ sprintf (buf2, "off"); i = buf2; break; }
if ( global_damq && global_prq   ){ sprintf (buf2, "DAMx2 PRx2"); i = buf2; break; }
else if ( !global_damq && !global_prq ){ sprintf (buf2, "off"); i = buf2; break; }
if ( global_damq  ){ sprintf (buf2, "DAMx2"); i = buf2; break; }
else if ( !global_damq ){ sprintf (buf2, "off"); i = buf2; break; }
if ( global_prq   ){ sprintf (buf2, "PRx2"); i = buf2; break; }
else if ( !global_prq  ){ sprintf (buf2, "off"); i = buf2; break; }
if ( global_xpq   ){ sprintf (buf2, "XPx2"); i = buf2; break; }
else if ( !global_xpq  ){ sprintf (buf2, "off"); i = buf2; break; }

            case 'H':
                sprintf (buf2, "%d", ch->max_hit);
                i = buf2;
                break;
            case 'm':
                sprintf (buf2, "%d", ch->mana);
                i = buf2;
                break;
            case 'M':
                sprintf (buf2, "%d", ch->max_mana);
                i = buf2;
                break;
            case 'v':
                sprintf (buf2, "%d", ch->move);
                i = buf2;
                break;
            case 'V':
                sprintf (buf2, "%d", ch->max_move);
                i = buf2;
                break;
            case 'x':
                sprintf (buf2, "%ld", ch->exp);
                i = buf2;
                break;
            case 'X':
                sprintf (buf2, "%ld", IS_NPC (ch) ? 0 :
                         (ch->level + 1) * exp_per_level (ch,
                                                          ch->pcdata->
                                                          points) - ch->exp);
                i = buf2;
                break;
            case 'g':
                sprintf (buf2, "%ld", ch->gold);
                i = buf2;
                break;
            case 's':
                sprintf (buf2, "%ld", ch->silver);
                i = buf2;
                break;
            case 'S':
                if ( IS_STANCE( ch, STANCE_BULL ) )
                sprintf (buf2, "%d Bull", ch->stance[5]);
                if ( IS_STANCE( ch, STANCE_CRAB ) )
                sprintf (buf2, "%d Crab", ch->stance[3]);
                if ( IS_STANCE( ch, STANCE_CRANE ) )
                sprintf (buf2, "%d Crane", ch->stance[2]);
                if ( IS_STANCE( ch, STANCE_MONGOOSE ) )
                sprintf (buf2, "%d Mongoose", ch->stance[4]);
                if ( IS_STANCE( ch, STANCE_MONKEY ) )
                sprintf (buf2, "%d Monkey", ch->stance[9]);
                if ( IS_STANCE( ch, STANCE_SWALLOW ) )
                sprintf (buf2, "%d Swallow", ch->stance[10]);
                if ( IS_STANCE( ch, STANCE_MANTIS ) )
                sprintf (buf2, "%d Mantis", ch->stance[6]);
                if ( IS_STANCE( ch, STANCE_DRAGON ) )
                sprintf (buf2, "%d Dragon", ch->stance[7]);
                if ( IS_STANCE( ch, STANCE_TIGER ) )
                sprintf (buf2, "%d Tiger", ch->stance[8]);
                if ( IS_STANCE( ch, STANCE_SERPENT ) )
                sprintf (buf2, "%d Serpent", ch->stance[1]);
                if ( IS_STANCE( ch, STANCE_NONE ) )
                sprintf (buf2, "%d Boxing", ch->stance[-1]);
                else if ( IS_STANCE( ch, STANCE_NORMAL ) )
                sprintf (buf2, "%d Street Fighter", ch->stance[0]);
                i = buf2;
                break;
            case 'P':
	        if ( ch->pet != NULL )
                if ( IS_STANCE( ch->pet, STANCE_BULL ) )
                sprintf (buf2, "%d Bull", ch->pet->stance[5]);
                if ( IS_STANCE( ch->pet, STANCE_CRAB ) )
                sprintf (buf2, "%d Crab", ch->pet->stance[3]);
                if ( IS_STANCE( ch->pet, STANCE_CRANE ) )
                sprintf (buf2, "%d Crane", ch->pet->stance[2]);
                if ( IS_STANCE( ch->pet, STANCE_MONGOOSE ) )
                sprintf (buf2, "%d Mongoose", ch->pet->stance[4]);
                if ( IS_STANCE( ch->pet, STANCE_MONKEY ) )
                sprintf (buf2, "%d Monkey", ch->pet->stance[9]);
                if ( IS_STANCE( ch->pet, STANCE_SWALLOW ) )
                sprintf (buf2, "%d Swallow", ch->pet->stance[10]);
                if ( IS_STANCE( ch->pet, STANCE_MANTIS ) )
                sprintf (buf2, "%d Mantis", ch->pet->stance[6]);
                if ( IS_STANCE( ch->pet, STANCE_DRAGON ) )
                sprintf (buf2, "%d Dragon", ch->pet->stance[7]);
                if ( IS_STANCE( ch->pet, STANCE_TIGER ) )
                sprintf (buf2, "%d Tiger", ch->pet->stance[8]);
                if ( IS_STANCE( ch->pet, STANCE_SERPENT ) )
                sprintf (buf2, "%d Serpent", ch->pet->stance[1]);
                if ( IS_STANCE( ch->pet, STANCE_NONE ) )
                sprintf (buf2, "%d Boxing", ch->pet->stance[-1]);
                else if ( IS_STANCE( ch->pet, STANCE_NORMAL ) )
                sprintf (buf2, "%d Street Fighter", ch->pet->stance[0]);
                i = buf2;
                break;
            case 'a':
                if (ch->level > 9)
                    sprintf (buf2, "%d", ch->alignment);
                else
                    sprintf (buf2, "%s",
                             IS_GOOD (ch) ? "good" : IS_EVIL (ch) ? "evil" :
                             "neutral");
                i = buf2;
                break;
            case 'r':
                if (ch->in_room != NULL)
                    sprintf (buf2, "%s",
                             ((!IS_NPC
                               (ch) && IS_SET (ch->act, PLR_HOLYLIGHT))
                              || (!IS_AFFECTED (ch, AFF_BLIND)
                                  && !room_is_dark (ch->
                                                    in_room))) ? ch->in_room->
                             name : "darkness");
                else
                    sprintf (buf2, " ");
                i = buf2;
                break;
            case 'R':
                if (IS_IMMORTAL (ch) && ch->in_room != NULL)
                    sprintf (buf2, "%d", ch->in_room->vnum);
                else
                    sprintf (buf2, " ");
                i = buf2;
                break;
            case 'z':
                if (IS_IMMORTAL (ch) && ch->in_room != NULL)
                    sprintf (buf2, "%s", ch->in_room->area->name);
                else
                    sprintf (buf2, " ");
                i = buf2;
                break;
            case '%':
                sprintf (buf2, "%%");
                i = buf2;
                break;
            case 'o':
                sprintf (buf2, "%s", olc_ed_name (ch));
                i = buf2;
                break;
            case 'O':
                sprintf (buf2, "%s", olc_ed_vnum (ch));
                i = buf2;
                break;
        }
        ++str;
        while ((*point = *i) != '\0')
            ++point, ++i;
    }
    *point = '\0';
    pbuff = buffer;
    colourconv (pbuff, buf, ch);
    write_to_buffer (ch->desc, buffer, 0);

    if (ch->prefix[0] != '\0')
        write_to_buffer (ch->desc, ch->prefix, 0);
    return;
}



/*
 * Append onto an output buffer.
 */
void write_to_buffer( DESCRIPTOR_DATA *d, const char *txt, int length )
{
    /*
     * Find length in case caller didn't.
     */
    if ( length <= 0 )
	length = strlen(txt);

    /*
     * Initial \n\r if needed.
     */
    if ( d->outtop == 0 && !d->fcommand )
    {
	d->outbuf[0]	= '\n';
	d->outbuf[1]	= '\r';
	d->outtop	= 2;
    }

    /*
     * Expand the buffer as needed.
     */
    while ( d->outtop + length >= d->outsize )
    {
	char *outbuf;
/*
        if (d->outsize >= 32000)
	{
	    bug("Buffer overflow. Closing.\n\r",0);
	    close_socket(d);
	    return;
 	} */

     if ( ( 2 * d->outsize) > 63000 )
     {
        bug("Write_to_buffer:  outsize too large:  %d", d->outsize);
        return;
     }

	outbuf      = alloc_mem( 2 * d->outsize );
	strncpy( outbuf, d->outbuf, d->outtop );
	free_mem( d->outbuf, d->outsize );
	d->outbuf   = outbuf;
	d->outsize *= 2;
    }

    /*
     * Copy.
     */
    strncpy( d->outbuf + d->outtop, txt, length );
    d->outtop += length;
    return;
}


/*
 * Lowest level output function.
 * Write a block of text to the file descriptor.
 * If this gives errors on very long blocks (like 'ofind all'),
 *   try lowering the max block size.
 */
bool write_to_descriptor( int desc, char *txt, int length )
{
    int iStart;
    int nWrite;
    int nBlock;

#if defined(macintosh) || defined(MSDOS)
    if ( desc == 0 )
	desc = 1;
#endif

    if ( length <= 0 )
	length = strlen(txt);

    for ( iStart = 0; iStart < length; iStart += nWrite )
    {
	nBlock = UMIN( length - iStart, 2048 );
#if !defined( WIN32 )
	if ( ( nWrite = write( desc, txt + iStart, nBlock ) ) < 0 )
#else
	if ( ( nWrite = send( desc, txt + iStart, nBlock , 0) ) < 0 )
#endif
	    { perror( "Write_to_descriptor" ); return FALSE; }
    } 

    return TRUE;
}


/*
 * Deal with sockets that haven't logged in yet.
 */
void nanny( DESCRIPTOR_DATA *d, char *argument )
{
    DESCRIPTOR_DATA *dt; 
    DESCRIPTOR_DATA *d_old, *d_next;
    MUD_DATA *pmud;
    char buf[MSL];
    char newbuf[MSL];
    char arg[MIL];
    char strsave[MIL];
    CHAR_DATA *ch;
    CHAR_DATA *victim;
    char *pwdnew;
    char *p;
    char *strtime;
    int iClass,race,i,weapon;
    int pos;
    bool fOld;

    while ( isspace(*argument) )
	argument++;

    ch = d->character;

    switch ( d->connected )
    {

    default:
	bug( "Nanny: bad d->connected %d.", d->connected );
	close_socket( d );
	return;

case CON_GET_NAME:
	if ( argument[0] == '\0' )
	{
	    close_socket( d );
	    return;
	}

	argument[0] = UPPER(argument[0]);
	if ( !check_parse_name( argument ) )
	{
	    write_to_buffer( d, "Illegal name, try another.\n\r", 0 );
	    write_to_buffer( d, "(If you've used this name here before, and are no\n\r", 0 );
	    write_to_buffer( d, " longer able to, it may be because we've added a\n\r", 0 );
	    write_to_buffer( d, " new mobile that uses the same name. Log in with\n\r", 0 );
	    write_to_buffer( d, " a new name, and let an IMM know, and we will fix it.)\n\r", 0 );
	    write_to_buffer( d, "\n\rName: ", 0 );
	    return;
	}

	fOld = load_char_obj( d, argument );
	ch   = d->character;

	if (IS_SET(ch->act, PLR_DENY))
	{
	    sprintf( log_buf, "Denying access to %s@%s.", argument, d->host );
	    log_string( log_buf );
	    write_to_buffer( d, "You are denied access.\n\r", 0 );
	    close_socket( d );
	    return;
	}

	if (check_ban(d->host,BAN_PERMIT) && !IS_SET(ch->act,PLR_PERMIT))
	{
	    write_to_buffer(d,"Your site has been banned from this mud.\n\r",0);
	    close_socket(d);
	    return;
	}
/*
	if (check_adr(d->host,BAN_PERMIT) && (ch->level > 101) )
	{
	    write_to_buffer(d,"Immortals are not allowed to connect from your site.\n\r",0);
	    close_socket(d);
	    return;
	}
*/
	if (IS_SET(ch->comm, COMM_WIPED ) )
	{
	    close_socket( d );
	    return;
	}

	if ( check_reconnect( d, argument, FALSE ) )
	{
	    fOld = TRUE;
	}
	else
	{
	    if ( wizlock && !IS_IMMORTAL(ch)) 
	    {
		write_to_buffer( d, "The game is wizlocked.\n\r", 0 );
		close_socket( d );
		return;
	    }
	}

	if ( fOld )
	{
	    /* Old player */
	    write_to_buffer( d, "Password: ", 0 );
	    write_to_buffer( d, echo_off_str, 0 );
	    d->connected = CON_GET_OLD_PASSWORD;
	    return;
	}
	else
	{
	    /* New player */
 	    if (newlock)
	    {
                write_to_buffer( d, "The game is newlocked.\n\r", 0 );
                close_socket( d );
                return;
            }

	    if (check_ban(d->host,BAN_NEWBIES))
	    {
		write_to_buffer(d,
		    "New players are not allowed from your site.\n\r",0);
		close_socket(d);
		return;
	    }

	    sprintf( buf, "NOTICE: 'RoT2' REQUIRES role-playing type names, If your\n\r");
	    write_to_buffer( d, buf, 0 );
	    sprintf( buf, "chosen name does not conform to this, an IMM *WILL* delete you.\n\r");
	    write_to_buffer( d, buf, 0 );
	    sprintf( buf, "Did I get that right, %s (Y/N)? ", argument );
	    /* Stop multiple logins of the same name */
            for (dt=descriptor_list; dt != NULL; dt=dt->next)
                  if (d != dt && dt->character != NULL
                  && !str_cmp(dt->character->name,ch->name))
                  {
                    write_to_buffer(d,"Sorry, that name is being used.\n\r",0);
                    write_to_buffer(d,"Please select another name: ",0);
		    nuke_pets( d->character );
                    free_char( d->character );
                    d->character = NULL;
                    return;
                   }    
	    write_to_buffer( d, buf, 0 );
	    d->connected = CON_CONFIRM_NEW_NAME;
	    return;
	}
	break;

case CON_GET_OLD_PASSWORD:
#if defined(unix)
	write_to_buffer( d, "\n\r", 2 );
#endif

	if ( strcmp( crypt( argument, ch->pcdata->pwd ), ch->pcdata->pwd ))
	{
	    write_to_buffer( d, "Wrong password.\n\r", 0 );
	    close_socket( d );
	    return;
	}
 
	write_to_buffer( d, echo_on_str, 0 );

	if (check_playing(d,ch->name))
	    return;

	ch->pcdata->socket = str_dup( d->host );
	if ( check_reconnect( d, ch->name, TRUE ) )
	    return;

	sprintf( log_buf, "%s@%s has joined 'RoT2'", ch->name, d->host );
	log_string( log_buf );
	wiznet(log_buf,NULL,NULL,WIZ_SITES,0,get_trust(ch));
        SET_BIT(ch->act, PLR_COLOUR);
	ch->pcdata->socket = str_dup( d->host );

	if (IS_SET(ch->act, PLR_SECOND ) || IS_SET(ch->act, PLR_THIRD  ) )
	{
	    long act;

	    act = ch->act;
    	    sprintf( strsave, "%s%s", PLAYER_DIR, capitalize( ch->name ) );
	    sprintf(newbuf, "%s", str_dup( ch->pcdata->pwd ));
	    sprintf( argument, "%s", capitalize( ch->name ) );
	    nuke_pets( d->character );
	    free_char( d->character );
	    d->character = NULL;
	    fOld = load_char_reroll( d, argument );
	    ch   = d->character;
	    free_string( ch->pcdata->pwd );
	    ch->pcdata->pwd	= str_dup( newbuf );
	    newbuf[0] = '\0';
		if (IS_SET(act, PLR_SECOND ) )
			 ch->pcdata->tier = 1; 		
	    else
			 ch->pcdata->tier = 2; 		
	    ch->pcdata->socket = str_dup( d->host );
	    write_to_buffer( d, echo_on_str, 0 );
/*
	    write_to_buffer(d,"The following races are available:\n\r\n\r",0);
 */
	    pos = 0;
/*
	    for ( race = 1; race_table[race].name != NULL; race++ )
	    {
		if (!race_table[race].pc_race)
		    break;
		sprintf(newbuf, "%6s%-24s", " ", race_table[race].name);
		write_to_buffer(d,newbuf,0);
		pos++;
		if (pos >= 2) {
		    write_to_buffer(d,"\n\r",1);
		    pos = 0;
		}
	    }
 */
	    newbuf[0] = '\0';
	    // write_to_buffer(d,"What is your race (help for more information)? ",0);
	write_to_buffer( d, "What is your sex (M/F)? ", 0 );
	    d->connected = CON_GET_NEW_SEX;
	    break;
	}
       if (IS_IMMORTAL(ch)) {
           write_to_buffer(d, "Would you like to login (W)izi, (I)ncog, or (N)ormal? ", 0);
	    d->connected = CON_GET_WIZI;
          break;
       } else {
	    do_help( ch, "motd" );
	    d->connected = CON_READ_MOTD;
        }

	for (pos = 0; pos < MAX_DUPES; pos++)
	{
	    if (ch->pcdata->dupes[pos] == NULL)
		break;

	    if ( ( victim = get_char_mortal( ch, str_dup(ch->pcdata->dupes[pos]) ) ) != NULL )
		force_quit(victim, "");
	}

	check_robbed( ch );

	break;

/* RT code for breaking link */
 
case CON_BREAK_CONNECT:
	switch( *argument )
	{
	case 'y' : case 'Y':
            for ( d_old = descriptor_list; d_old != NULL; d_old = d_next )
	    {
		d_next = d_old->next;
		if (d_old == d || d_old->character == NULL)
		    continue;

		if (str_cmp(ch->name,d_old->original ?
		    d_old->original->name : d_old->character->name))
		    continue;

		close_socket(d_old);
	    }
	    ch->pcdata->socket = str_dup( d->host );
	    if (check_reconnect(d,ch->name,TRUE))
	    	return;
	    write_to_buffer(d,"Reconnect attempt failed.\n\rName: ",0);
            if ( d->character != NULL )
            {
		nuke_pets( d->character );
                free_char( d->character );
                d->character = NULL;
            }
	    d->connected = CON_GET_NAME;
	    break;

	case 'n' : case 'N':
	    write_to_buffer(d,"Name: ",0);
            if ( d->character != NULL )
            {
		nuke_pets( d->character );
                free_char( d->character );
                d->character = NULL;
            }
	    d->connected = CON_GET_NAME;
	    break;

	default:
	    write_to_buffer(d,"Please type Y or N? ",0);
	    break;
	}
	break;

case CON_CONFIRM_NEW_NAME:
	switch ( *argument )
	{
	case 'y': case 'Y':
	    sprintf( buf, "New character.\n\rGive me a password for %s: %s",
		ch->name, echo_off_str );
            SET_BIT(ch->act, PLR_COLOUR);
	    ch->pcdata->socket = str_dup( d->host );
	    write_to_buffer( d, buf, 0 );
	    d->connected = CON_GET_NEW_PASSWORD;
	    break;

	case 'n': case 'N':
	    write_to_buffer( d, "Ok, what IS it, then? ", 0 );
	    nuke_pets( d->character );
	    free_char( d->character );
	    d->character = NULL;
	    d->connected = CON_GET_NAME;
	    break;

	default:
		write_to_buffer( d, "Please type Yes or No: ", 0 );
	    break;
	}
	break;

case CON_GET_NEW_PASSWORD:
#if defined(unix)
	write_to_buffer( d, "\n\r", 2 );
#endif

	if ( strlen(argument) < 5 )
	{
	    write_to_buffer( d,
		"Password must be at least five characters long.\n\rPassword: ",
		0 );
	    return;
	}

	pwdnew = crypt( argument, ch->name );
	for ( p = pwdnew; *p != '\0'; p++ )
	{
	    if ( *p == '~' )
	    {
		write_to_buffer( d,
		    "New password not acceptable, try again.\n\rPassword: ",
		    0 );
		return;
	    }
	}

	free_string( ch->pcdata->pwd );
	ch->pcdata->pwd	= str_dup( pwdnew );
	write_to_buffer( d, "Please retype password: ", 0 );
	d->connected = CON_CONFIRM_NEW_PASSWORD;
	break;

case CON_CONFIRM_NEW_PASSWORD:
#if defined(unix)
	write_to_buffer( d, "\n\r", 2 );
#endif

	if ( strcmp( crypt( argument, ch->pcdata->pwd ), ch->pcdata->pwd ) )
	{
	    write_to_buffer( d, "Passwords don't match.\n\rRetype password: ",
		0 );
	    d->connected = CON_GET_NEW_PASSWORD;
	    return;
	}
	
	write_to_buffer( d, "What is your sex (M/F)? ", 0 );
    d->connected = CON_GET_NEW_SEX;
    break;

case CON_GET_NEW_SEX:
	switch ( argument[0] )
	{
	case 'm': case 'M': ch->sex = SEX_MALE;    
			    ch->pcdata->true_sex = SEX_MALE;
			    break;
	case 'f': case 'F': ch->sex = SEX_FEMALE; 
			    ch->pcdata->true_sex = SEX_FEMALE;
			    break;

	default:
	    write_to_buffer( d, "That's not a sex.\n\rWhat IS your sex? ", 0 );
	    return;
	}

	//	write_to_buffer( d, "Which side do you wish to join: (L)ight, (S)hadow, or (N)eutral?\n\r",0);
	write_to_buffer( d, "What is your alignment (L/S/N)? ",0);
	d->connected = CON_GET_ALIGNMENT;
	break;

case CON_GET_ALIGNMENT:
	switch( argument[0])
	{
	    case 'l' : case 'L' : ch->alignment = 750;  break;
	    case 'n' : case 'N' : ch->alignment = 0;	break;
	    case 's' : case 'S' : ch->alignment = -750; break;
	    default:
		write_to_buffer(d,"That's not a valid alignment.\n\r",0);
		write_to_buffer(d,"Which alignment (L/N/S)? ",0);
		return;
	}

	ch->pcdata->socket = str_dup( d->host );
	write_to_buffer( d, echo_on_str, 0 );
	pos = 0;
	newbuf[0] = '\0';
	write_to_buffer(d,"The following races are available:\n\r\n\r",0);
	pos = 0;
	for ( race = 1; race_table[race].name != NULL; race++ )
	{
	    if (!race_table[race].pc_race)
		break;
	    sprintf(newbuf, "%6s%-24s", " ", race_table[race].name);
	    write_to_buffer(d,newbuf,0);
	    pos++; 
	    if (pos >= 2) { 
		write_to_buffer(d,"\n\r",1);
		pos = 0;
	    } 
	}
	newbuf[0] = '\0';
	write_to_buffer(d,"\n\r\n\r",0);
	write_to_buffer(d,"What is your race (help for more information)? ",0);
	d->connected = CON_GET_NEW_RACE;
	break;

case CON_GET_NEW_RACE:
	one_argument(argument,arg);


	if (!strcmp(arg,"help"))
	{
	    argument = one_argument(argument,arg);
	    if (argument[0] == '\0')
		do_help(ch,"race help");
	    else
		do_help(ch,argument);
            write_to_buffer(d,
		"What is your race (help for more information)? ",0);
	    break;
  	}

	race = race_lookup(argument);

	if (race == 0 || !race_table[race].pc_race)
	{
	    write_to_buffer(d,"That is not a valid race.\n\r",0);
            write_to_buffer(d,"The following races are available:\n\r  ",0);
            for ( race = 1; race_table[race].name != NULL; race++ )
            {
            	if (!race_table[race].pc_race)
                    break;
            	write_to_buffer(d,race_table[race].name,0);
            	write_to_buffer(d," ",1);
            }
            write_to_buffer(d,"\n\r",0);
            write_to_buffer(d,
		"What is your race? (help for more information) ",0);
	    break;
	}

        ch->race = race;
	/* initialize stats */
	for (i = 0; i < MAX_STATS; i++)
	    ch->perm_stat[i] = pc_race_table[race].stats[i];
	ch->affected_by = ch->affected_by|race_table[race].aff;
	ch->shielded_by = ch->shielded_by|race_table[race].shd;
	ch->imm_flags	= ch->imm_flags|race_table[race].imm;
	ch->res_flags	= ch->res_flags|race_table[race].res;
	ch->vuln_flags	= ch->vuln_flags|race_table[race].vuln;
	ch->form	= race_table[race].form;
	ch->parts	= race_table[race].parts;

	/* add skills */
	for (i = 0; i < 5; i++)
	{
	    if (pc_race_table[race].skills[i] == NULL)
	 	break;
	    group_add(ch,pc_race_table[race].skills[i],FALSE);
	}
	/* add cost */
	ch->pcdata->points = pc_race_table[race].points;
	ch->size = pc_race_table[race].size;

	//Choose Class
		write_to_buffer( d, echo_on_str, 0 );
	if (ch->pcdata->tier >= 2)
	write_to_buffer(d,"The following primary classes are available:\n\r\n\r",0);
	else
	write_to_buffer(d,"The following classes are available:\n\r\n\r",0);
	if (ch->pcdata->tier < 1) {
	    ch->pcdata->tier = 0;
	    for ( iClass = 0; iClass < MCLT_1; iClass++ )
	    {
		write_to_buffer(d,"      ",0);
		write_to_buffer(d,class_table[iClass].name,0);
		write_to_buffer(d,"\n\r",1);
	    }
	} else {
	    for ( iClass = MCLT_1; iClass < MAX_CLASS; iClass++ )
	    {
		write_to_buffer(d,"      ",0);
		write_to_buffer(d,class_table[iClass].name,0);
		write_to_buffer(d,"\n\r",1);
	    }
	}
	write_to_buffer(d,"\n\r\n\r",0);
	if (ch->pcdata->tier >= 2)
	    write_to_buffer(d,"What is your PRIMARY class ? ",0);
	else
	    write_to_buffer(d,"What is your class ? ",0);
	d->connected = CON_GET_NEW_CLASS;
	break;

case CON_GET_NEW_CLASS:
	iClass = class_lookup(argument);

	if ( iClass == -1 )
	{
	    write_to_buffer( d,
		"That's not a class.\n\rWhat IS your class? ", 0 );
	    return;
	}
	if (ch->pcdata->tier < 1) 
	{
	    if (iClass >= (MCLT_1)) 
		{
		write_to_buffer( d,
		    "That's not a first tier class.\n\rWhat IS your class? ", 0 );
		return;
	    }
	} 
	else if (ch->pcdata->tier < 2) 
	{
	    if (iClass < (MCLT_1)) 
		{
		write_to_buffer( d,
		    "That's not a second tier class.\n\rWhat IS your class? ", 0 );
		return;
	    }
	}
	else 
	{
	    if (iClass < (MCLT_1)) 
		{
		write_to_buffer( d,
		    "That's not a second tier class.\n\rWhat IS your class? ", 0 );
		return;
	    }
	}
        ch->class = iClass;
	if (ch->pcdata->tier == 0) {
	    ch->newbie = 1;
	}

	if (ch->pcdata->tier == 2) 
	{
	write_to_buffer( d, echo_on_str, 0 );
	write_to_buffer(d,"The following secondary classes are available:\n\r\n\r",0);
	 for ( iClass = 0; iClass < MCLT_1; iClass++ )
	    {
		if (iClass == (ch->class - (MCLT_1)))
		    continue;
		write_to_buffer(d,"      ",0);
		write_to_buffer(d,class_table[iClass].name,0);
		write_to_buffer(d,"\n\r",1);
	    }
	    write_to_buffer(d,"\n\r\n\r",0);
	    write_to_buffer(d,"What is your SECONDARY class ? ",0);
	    d->connected = CON_GET_SECOND_CLASS;
	    break;
	}

	if (ch->pcdata->tier == 3) 
	{
	write_to_buffer( d, echo_on_str, 0 );
	write_to_buffer(d,"The following secondary classes are available:\n\r\n\r",0);
	 for ( iClass = 0; iClass < MAX_CLASS; iClass++ )
	    {
		if (iClass == (ch->clasb))
		    continue;
		write_to_buffer(d,"      ",0);
		write_to_buffer(d,class_table[iClass].name,0);
		write_to_buffer(d,"\n\r",1);
	    }
	    write_to_buffer(d,"\n\r\n\r",0);
	    write_to_buffer(d,"What is your SECONDARY class ? ",0);
	    d->connected = CON_GET_SECOND_CLASS;
	    break;
	}

	sprintf( log_buf, "%s@%s new player.", ch->name, d->host );
	log_string( log_buf );
	wiznet("Newbie alert!  $N sighted.",ch,NULL,WIZ_NEWBIE,0,0);
        wiznet(log_buf,NULL,NULL,WIZ_SITES,0,get_trust(ch));

	write_to_buffer(d,"\n\r",0);

        group_add(ch,"rom basics",FALSE);
        group_add(ch,class_table[ch->class].base_group,FALSE);
	if (ch->pcdata->tier == 1)
        ch->pcdata->learned[gsn_recall] = 50;
	if (ch->pcdata->tier == 2)
	    group_add(ch,class_table[ch->clasb].base_group,FALSE);
	    ch->pcdata->learned[gsn_recall] = 75;
	if (ch->pcdata->tier == 3)
	    group_add(ch,class_table[ch->clasb].base_group,FALSE);
	    ch->pcdata->learned[gsn_recall] = 95;
	write_to_buffer(d,"Do you wish to customize this character?\n\r",0);
	write_to_buffer(d,"Customization takes time, but allows a wider range of skills and abilities.\n\r",0);
	write_to_buffer(d,"Customize (Y/N)? ",0);
	d->connected = CON_DEFAULT_CHOICE;
	break;
	
case CON_GET_SECOND_CLASS:
	iClass = class_lookup(argument);

	if ( iClass == -1 )
	{
	    write_to_buffer( d,
		"That's not a class.\n\rWhat IS your secondary class? ", 0 );
	    return;
	}
	if ( iClass >= ( MCLT_1 ) && ( ch->pcdata->tier != 3 ) ) {
	    write_to_buffer( d,
		"That's not a first tier class.\n\rWhat IS your secondary class? ", 0 );
	    return;
	}
	if (iClass == (ch->class - (MCLT_1))) {
	    write_to_buffer( d,
		"You cannot choose the first tier equivalent of your primary class.\n\r", 0);
	    write_to_buffer( d,
		"What IS your secondary class? ", 0 );
	    return;
	}
        ch->clasb = iClass;
	sprintf( log_buf, "%s@%s new player.", ch->name, d->host );
	log_string( log_buf );
	wiznet("Newbie alert!  $N sighted.",ch,NULL,WIZ_NEWBIE,0,0);
        wiznet(log_buf,NULL,NULL,WIZ_SITES,0,get_trust(ch));

	write_to_buffer( d, "\n\r", 2 );

		write_to_buffer(d,"\n\r",0);

        group_add(ch,"rom basics",FALSE);
        group_add(ch,class_table[ch->class].base_group,FALSE);
	if (ch->pcdata->tier == 1)
        ch->pcdata->learned[gsn_recall] = 50;
	if (ch->pcdata->tier == 2)
	    group_add(ch,class_table[ch->clasb].base_group,FALSE);
	    ch->pcdata->learned[gsn_recall] = 75;
	if (ch->pcdata->tier == 3)
	    group_add(ch,class_table[ch->clasb].base_group,FALSE);
	    ch->pcdata->learned[gsn_recall] = 95;
	write_to_buffer(d,"Do you wish to customize this character?\n\r",0);
	write_to_buffer(d,"Customization takes time, but allows a wider range of skills and abilities.\n\r",0);
	write_to_buffer(d,"Customize (Y/N)? ",0);
	d->connected = CON_DEFAULT_CHOICE;
	break;

case CON_DEFAULT_CHOICE:
	write_to_buffer(d,"\n\r",2);
        switch ( argument[0] )
        {
        case 'y': case 'Y': 
	    ch->gen_data = new_gen_data();
	    ch->gen_data->points_chosen = ch->pcdata->points;
	    do_help(ch,"group header");
	    list_group_costs(ch);
	    write_to_buffer(d,"You already have the following skills:\n\r",0);
	    do_skills(ch,"");
	    do_bskills(ch,"");
	    do_help(ch,"menu choice");
	    d->connected = CON_GEN_GROUPS;
	    break;
        case 'n': case 'N': 
	    group_add(ch,class_table[ch->class].default_group,TRUE);
	    if (ch->pcdata->tier == 2)
		group_add(ch,class_table[ch->clasb].default_group,TRUE);
            write_to_buffer( d, "\n\r", 2 );
	    write_to_buffer(d,
		"Please pick a weapon from the following choices:\n\r",0);
	    buf[0] = '\0';
	    for ( i = 0; weapon_table[i].name != NULL; i++)
		if (ch->pcdata->learned[*weapon_table[i].gsn] > 0)
		{
		    strcat(buf,weapon_table[i].name);
		    strcat(buf," ");
		}
	    strcat(buf,"\n\rYour choice? ");
	    write_to_buffer(d,buf,0);
            d->connected = CON_PICK_WEAPON;
            break;
        default:
            write_to_buffer( d, "Please answer (Y/N)? ", 0 );
            return;
        }
	break;

case CON_PICK_WEAPON:
	write_to_buffer(d,"\n\r",2);
	weapon = weapon_lookup(argument);
	if (weapon == -1 || ch->pcdata->learned[*weapon_table[weapon].gsn] <= 0)
	{
	    write_to_buffer(d,
		"That's not a valid selection. Choices are:\n\r",0);
            buf[0] = '\0';
            for ( i = 0; weapon_table[i].name != NULL; i++)
                if (ch->pcdata->learned[*weapon_table[i].gsn] > 0)
                {
                    strcat(buf,weapon_table[i].name);
		    strcat(buf," ");
                }
            strcat(buf,"\n\rYour choice? ");
            write_to_buffer(d,buf,0);
	    return;
	}

	ch->pcdata->learned[*weapon_table[weapon].gsn] = 40;
	write_to_buffer(d,"\n\r",2);
	do_help(ch,"motd");
	d->connected = CON_READ_MOTD;
	break;

case CON_GEN_GROUPS:
	send_to_char("\n\r",ch);
       	if (!str_cmp(argument,"done"))
       	{
	    sprintf(buf,"Creation points: %d\n\r",ch->pcdata->points);
	    send_to_char(buf,ch);
	    sprintf(buf,"Experience per level: %ld\n\r",
	            (long)exp_per_level(ch,ch->gen_data->points_chosen));
	    if (ch->pcdata->points < 40)
		ch->train = (40 - ch->pcdata->points + 1) / 2;
	    free_gen_data(ch->gen_data);
	    ch->gen_data = NULL;
	    send_to_char(buf,ch);
            write_to_buffer( d, "\n\r", 2 );
            write_to_buffer(d,
                "Please pick a weapon from the following choices:\n\r",0);
            buf[0] = '\0';
            for ( i = 0; weapon_table[i].name != NULL; i++)
                if (ch->pcdata->learned[*weapon_table[i].gsn] > 0)
                {
                    strcat(buf,weapon_table[i].name);
		    strcat(buf," ");
                }
            strcat(buf,"\n\rYour choice? ");
            write_to_buffer(d,buf,0);
            d->connected = CON_PICK_WEAPON;
            break;
        }

        if (!parse_gen_groups(ch,argument))
        send_to_char(
        "Choices are: list,learned,premise,add,drop,info,help, and done.\n\r"
        ,ch);

        do_help(ch,"menu choice");
        break;

case CON_READ_IMOTD:
	write_to_buffer(d,"\n\r",2);
        do_help( ch, "motd" );
        d->connected = CON_READ_MOTD;
	break;

    case CON_GET_WIZI:
        write_to_buffer(d, "\n\r", 2);
        switch (*argument) {
            case 'w': case 'W':
                ch->invis_level = ch->level;
                break; // Finish this state and do MOTD stuff..
            case 'i': case 'I':
                ch->incog_level = ch->level;
                break; // Finish this state and do MOTD stuff..
            case 'n': case 'N':
                ch->incog_level = 0;
                ch->invis_level = 0;
                break; // Finish this state and do MOTD stuff..
            default:
                write_to_buffer(d,
                    "That is not a choice. What IS your choice? ", 0);
                return; // Stay in this state to choose again.
        }
	do_help( ch, "imotd" );
        d->connected = CON_READ_IMOTD;
        // End of CON_GET_WIZI.
    break;

case CON_READ_MOTD:
        if ( ch->pcdata == NULL || ch->pcdata->pwd[0] == '\0')
        {
            write_to_buffer( d, "Warning! Null password!\n\r",0 );
            write_to_buffer( d, "Please report old password with bug.\n\r",0);
            write_to_buffer( d,
                "Type 'password null <new password>' to fix.\n\r",0);
        }

	write_to_buffer( d, 
    "\n\rWelcome to RoT 2.0,  Please do not feed the twits.\n\r",
	    0 );
	ch->next	= char_list;
	char_list	= ch;
	d->connected	= CON_PLAYING;
	reset_char(ch);

	if ( ch->level == 0 )
	{

	    ch->perm_stat[class_table[ch->class].attr_prime] += 3;
	    if (ch->pcdata->tier == 2)
		{
		ch->perm_stat[class_table[ch->clasb].attr_prime] =
	    UMIN(ch->perm_stat[class_table[ch->clasb].attr_prime] + 2, 25);
		}
	    if (ch->pcdata->tier == 3)
		{
		ch->perm_stat[class_table[ch->clasb].attr_prime] =
	    UMIN(ch->perm_stat[class_table[ch->clasb].attr_prime] + 2.12, 25.12);
		}
		

	    ch->level	= 1;
	    ch->exp	= exp_per_level(ch,ch->pcdata->points);
	    ch->hit	= ch->max_hit;
	    ch->mana	= ch->max_mana;
	    ch->move	= ch->max_move;
	    if (ch->pcdata->tier == 3) { ch->train	 = 45; ch->practice = 50; }
	    else if (ch->pcdata->tier == 2) { ch->train	 = 40; ch->practice = 45; }
	    else if (ch->pcdata->tier == 1) { ch->train	 = 35; ch->practice = 40; }
	    else { ch->train	 = 30; ch->practice = 35; }
            ch->pcdata->camp = 3001; /* Default camp site vnum */
	    sprintf( buf, "the %s",
		title_table [ch->class] [ch->level]
		[ch->sex == SEX_FEMALE ? 1 : 0] );
	    set_title( ch, buf );

	    do_outfit(ch,"");
	    obj_to_char(create_object(get_obj_index(OBJ_VNUM_MAP),0),ch);
	    obj_to_char(create_object(get_obj_index(OBJ_VNUM_WMAP),0),ch);
	    obj_to_char(create_object(get_obj_index(OBJ_VNUM_EMAP),0),ch);
	    obj_to_char(create_object(get_obj_index(OBJ_VNUM_QPOUCH),0),ch);
	    do_pack(ch, ch->name);
	    do_autoall(ch, "");
	    char_to_room( ch, get_room_index( ROOM_VNUM_SCHOOL ) );
	    send_to_char("\n\r",ch);
	    do_help(ch,"NEWBIE INFO");
	    send_to_char("\n\r",ch);
	}
	else if ( ch->in_room != NULL )
	{
	    char_to_room( ch, ch->in_room );
	}
	else if ( IS_IMMORTAL(ch) )
	{
	    char_to_room( ch, get_room_index( ROOM_VNUM_CHAT ) );
	}
	else
	{
	    if ( ch->alignment <0 )
		char_to_room( ch, get_room_index( ROOM_VNUM_TEMPLEB ) );
	    else
		char_to_room( ch, get_room_index( ROOM_VNUM_TEMPLE ) );
	}

	act( "$n has entered the game.", ch, NULL, NULL, TO_ROOM );
	do_look( ch, "auto" );

	wiznet("$N has left real life behind.",ch,NULL,
		WIZ_LOGINS,WIZ_SITES,get_trust(ch));

	if (ch->pet != NULL)
	{
	    char_to_room(ch->pet,ch->in_room);
	    act("$n has entered the game.",ch->pet,NULL,NULL,TO_ROOM);
	}

	do_unread(ch,"");

	check_robbed( ch );

	break;

case CON_MUD_GET_NAME:
	if (argument[0] == '\0')
	{
	    write_to_buffer( d, "Aborted.\n\r", 0);
	    ch->next		= char_list;
	    char_list		= ch;
	    d->connected	= CON_PLAYING;
	    char_to_room( ch, ch->was_in_room );
            if ( ch->pmud != NULL )
            {
                free_mud(ch->pmud);
                ch->pmud = NULL;
            }
	    break;
	}
	smash_tilde( argument );
	
	pmud			= new_mud();
	pmud->next		= NULL;
	pmud->sender		= str_dup( ch->name );
	pmud->date		= str_dup( "" );
	pmud->name		= str_dup( "" );
	pmud->base		= str_dup( "" );
	pmud->address		= str_dup( "" );
	pmud->port		= 0;
	ch->pmud		= pmud;

	buf[0] = '\0';
	sprintf(buf, "%s{x", argument);
	free_string( ch->pmud->name );
	ch->pmud->name = str_dup( buf );
	buf[0] = '\0';
	send_to_char( "\n\r{GEnter the code base for the mud:{x\n\r",ch );
        send_to_char( "{Gie: {RRoT, ROM, Smaug, Merc{x\n\r\n\r",ch );
	send_to_char( "  {YBase:{x ",ch);
	d->connected	= CON_MUD_GET_BASE;
	break;

case CON_MUD_GET_BASE:
	if (argument[0] == '\0')
        {
            write_to_buffer( d, "Aborted.\n\r", 0);
            ch->next            = char_list;
            char_list           = ch;
            d->connected        = CON_PLAYING;
            char_to_room( ch, ch->was_in_room );
	    if ( ch->pmud != NULL )
	    {
		free_mud(ch->pmud);
		ch->pmud = NULL;
	    }
            break;
        }
	smash_tilde( argument );

        buf[0] = '\0';
        sprintf(buf, "%s{x", argument);
        free_string( ch->pmud->base );
        ch->pmud->base = str_dup( buf );
        buf[0] = '\0';
        send_to_char( "\n\r{GEnter the address for the mud, do not enter the port number yet:{x\n\r",ch );
        send_to_char( "{Gie: {Rmud.rot.com{x\n\r\n\r",ch );
        send_to_char( "  {YAddress:{x ",ch);
	d->connected	= CON_MUD_GET_ADDRESS;
	break;

case CON_MUD_GET_ADDRESS:
	if (argument[0] == '\0')
        {
            write_to_buffer( d, "Aborted.\n\r", 0);
            ch->next            = char_list;
            char_list           = ch;
            d->connected        = CON_PLAYING;
            char_to_room( ch, ch->was_in_room );
            if ( ch->pmud != NULL )
            {
                free_mud(ch->pmud);
                ch->pmud = NULL;
            }
            break;
        }
	smash_tilde( argument );

        buf[0] = '\0';
        sprintf(buf, "%s{x", argument);
        free_string( ch->pmud->address );
        ch->pmud->address = str_dup( buf );
        buf[0] = '\0';
        send_to_char( "\n\r{GEnter the port for the mud:{x\n\r",ch );
        send_to_char( "{Gie: {R9000{x\n\r\n\r",ch );
        send_to_char( "  {YPort:{x ",ch);
        d->connected    = CON_MUD_GET_PORT;
        break;

case CON_MUD_GET_PORT:
        if (argument[0] == '\0')
        {
            write_to_buffer( d, "Aborted.\n\r", 0);
            ch->next            = char_list;
            char_list           = ch;
            d->connected        = CON_PLAYING;
            char_to_room( ch, ch->was_in_room );
            if ( ch->pmud != NULL )
            {
                free_mud(ch->pmud);
                ch->pmud = NULL;
            }
            break;
        }

	if (!is_number(argument) || (atoi(argument) < 1)
	|| (atoi(argument) > 9999))
	{
	    send_to_char( "\n\r{RThat's NOT a valid port.\n\r", ch );
	    send_to_char( "\n\r{GEnter the port for the mud:{x\n\r",ch );
	    send_to_char( "{Gie: {R9000{x\n\r\n\r",ch );
	    send_to_char( "  {YPort:{x ",ch);
	    d->connected	= CON_MUD_GET_PORT;
	    break;
	}
        ch->pmud->port = atoi(argument);

	send_to_char( "\n\r{GSave the above to the mud ads list?{x\n\r\n\r",ch );
	send_to_char( "  {Y(Y/N)?{x ",ch);
	d->connected	= CON_MUD_SAVE;
	break;

case CON_MUD_SAVE:
        write_to_buffer(d,"\n\r",2);
        switch ( argument[0] )
        {
        case 'y': case 'Y': 
	    ch->pmud->next		= NULL;
	    strtime			= ctime( &current_time );
	    strtime[strlen(strtime)-1]	= '\0';
	    ch->pmud->date		= str_dup( strtime );
	    ch->pmud->date_stamp	= current_time;

	    append_mud(ch->pmud);
	    ch->pmud = NULL;
            ch->next            = char_list; 
            char_list           = ch; 
            d->connected        = CON_PLAYING; 
            char_to_room( ch, ch->was_in_room ); 
	    break;
        case 'n': case 'N': 
            write_to_buffer( d, "Aborted.\n\r", 0);
            ch->next            = char_list;
            char_list           = ch;
            d->connected        = CON_PLAYING;
            char_to_room( ch, ch->was_in_room );
            if ( ch->pmud != NULL )
            {
                free_mud(ch->pmud);
                ch->pmud = NULL;
            }
            break;
        default:
            send_to_char( "  {Y(Y/N)?{x ",ch);
            return;
        }
        break;

case CON_REROLL:
#if defined(unix)
	write_to_buffer( d, "\n\r", 2 );
#endif

	sprintf( log_buf, "%s@%s is recreating.", ch->name, d->host );
	log_string( log_buf );
	wiznet(log_buf,NULL,NULL,WIZ_SITES,0,get_trust(ch));
	ch->pcdata->socket = str_dup( d->host );

	{
	    long act;

	    act = ch->act;
    	    sprintf( strsave, "%s%s", PLAYER_DIR, capitalize( ch->name ) );
	    sprintf(newbuf, "%s", str_dup( ch->pcdata->pwd ));
	    sprintf( argument, "%s", capitalize( ch->name ) );
	    nuke_pets( d->character );
	    free_char( d->character );
	    d->character = NULL;
	    fOld = load_char_reroll( d, argument );
	    ch   = d->character;
	    free_string( ch->pcdata->pwd );
	    ch->pcdata->pwd	= str_dup( newbuf );
	    newbuf[0] = '\0';
		if (IS_SET(act, PLR_SECOND ) )
		ch->pcdata->tier = 1;
	    else if (IS_SET(act, PLR_THIRD ) )
		ch->pcdata->tier = 2;
	    else if (IS_SET(act, PLR2_FOURTH ) )
		ch->pcdata->tier = 3; 
	    else
		ch->pcdata->tier = 0;
	    ch->pcdata->socket = str_dup( d->host );
	    write_to_buffer( d, echo_on_str, 0 );
	    pos = 0;
		newbuf[0] = '\0';
		write_to_buffer(d,"What is your sex? ",0);
		d->connected = CON_GET_NEW_SEX;
	}
	break;
    }
    return;
}



/*
 * Parse a name for acceptability.
 */
bool check_parse_name( char *name )
{
    int e;
    /*
     * Reserved words.
     */
    if ( is_name( name, 
"asdf all auto immortal immortals self someone something the you demise balance circle loner honor phuq this mud gay buzz biotch delos shimtis lobo thunder cosm none quit null natas aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm nnn ooo ppp qqq rrr sss ttt uuu vvv www xxx yyy zzz asdf fdsa qwer queer jkl lkj poiuy cyber coke psy") )
	return FALSE;
	
    if (str_cmp(capitalize(name),"Alander") && (!str_prefix("Alan",name)
    || !str_suffix("Alander",name)))
	return FALSE;

    /*
     * Cursing
     */

    for ( e = 1; e < MAX_CLAN; e++)
    {
	if (!str_prefix(clan_table[e].name, name))
	    return FALSE;
    }
    if (!str_infix("immortal",name))
	return FALSE;
    if (!str_infix(" ", name))
	return FALSE;
    if (!str_infix("fuck",name))
	return FALSE;
    if (!str_infix("shit",name))
        return FALSE;
    if (!str_infix("asshole",name))
        return FALSE;
    if (!str_infix("pussy",name))
        return FALSE;
    /*
     * Length restrictions.
     */
     
    if ( strlen(name) <  2 )
	return FALSE;

#if defined(MSDOS)
    if ( strlen(name) >  8 )
	return FALSE;
#endif

#if defined(macintosh) || defined(unix)
    if ( strlen(name) > 12 )
	return FALSE;
#endif

    /*
     * Alphanumerics only.
     * Lock out IllIll twits.
     */
    {
	char *pc;
	bool fIll,adjcaps = FALSE,cleancaps = FALSE;
 	int total_caps = 0;

	fIll = TRUE;
	for ( pc = name; *pc != '\0'; pc++ )
	{
	    if ( !isalpha(*pc) )
		return FALSE;

	    if ( isupper(*pc)) /* ugly anti-caps hack */
	    {
		if (adjcaps)
		    cleancaps = TRUE;
		total_caps++;
		adjcaps = TRUE;
	    }
	    else
		adjcaps = FALSE;

	    if ( LOWER(*pc) != 'i' && LOWER(*pc) != 'l' )
		fIll = FALSE;
	}

	if ( fIll )
	    return FALSE;

	if (cleancaps || (total_caps > (strlen(name)) / 2 && strlen(name) < 3))
	    return FALSE;
    }

    /*
     * Prevent players from naming themselves after mobs.
     */
    {
	extern MOB_INDEX_DATA *mob_index_hash[MAX_KEY_HASH];
	MOB_INDEX_DATA *pMobIndex;
	int iHash;

	for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
	{
	    for ( pMobIndex  = mob_index_hash[iHash];
		  pMobIndex != NULL;
		  pMobIndex  = pMobIndex->next )
	    {
		if ( is_name( name, pMobIndex->player_name ) )
		    return FALSE;
	    }
	}
    }

    return TRUE;
}



/*
 * Look for link-dead player to reconnect.
 */
bool check_reconnect( DESCRIPTOR_DATA *d, char *name, bool fConn )
{
    CHAR_DATA *ch;
    char buf[MSL];

    for ( ch = char_list; ch != NULL; ch = ch->next )
    {
	if ( !IS_NPC(ch)
	&&   (!fConn || ch->desc == NULL)
	&&   !str_cmp( d->character->name, ch->name ) )
	{
	    if ( fConn == FALSE )
	    {
		free_string( d->character->pcdata->pwd );
		d->character->pcdata->pwd = str_dup( ch->pcdata->pwd );
	    }
	    else
	    {
		OBJ_DATA *obj;
		nuke_pets( d->character );
		free_char( d->character );
		d->character = ch;
		ch->desc	 = d;
		ch->timer	 = 0;

		if (!str_cmp(ch->name,"Artimus"))
		{
		    send_to_char("Welcome back Artimus.\n\r",ch);
sprintf( buf, "Reconnecting.  You have {R%d{x tells waiting.\n\r", ch->tells );
		    send_to_char( buf, ch );
		    send_to_char("Type 'replay' to see tells.\n\r",ch);
		}
		else if(ch->tells)
		{
		    sprintf( buf, "Reconnecting.  You have {R%d{x tells waiting.\n\r",
			ch->tells );
		    send_to_char( buf, ch );
		    send_to_char("Type 'replay' to see tells.\n\r",ch);
		}
		else
		{
			send_to_char("Reconnecting.  You have no tells waiting.\n\r",ch);
		}
		act( "$n has reconnected.", ch, NULL, NULL, TO_ROOM );
		if ((obj = get_eq_char(ch,WEAR_LIGHT)) != NULL
		&&  obj->item_type == ITEM_LIGHT && obj->value[2] != 0)
		    --ch->in_room->light;

		sprintf( log_buf, "%s@%s reconnected.", ch->name, d->host );
		log_string( log_buf );
		wiznet("$N groks the fullness of $S link.",
		    ch,NULL,WIZ_LINKS,0,0);
		d->connected = CON_PLAYING;
	    }
	    return TRUE;
	}
    }

    return FALSE;
}



/*
 * Check if already playing.
 */
bool check_playing( DESCRIPTOR_DATA *d, char *name )
{
    DESCRIPTOR_DATA *dold;

    for ( dold = descriptor_list; dold; dold = dold->next )
    {
	if ( dold != d
	&&   dold->character != NULL
	&&   dold->connected != CON_GET_NAME
	&&   dold->connected != CON_GET_OLD_PASSWORD
	&&   !str_cmp( name, dold->original
	         ? dold->original->name : dold->character->name ) )
	{
	    write_to_buffer( d, "That character is already playing.\n\r",0);
	    write_to_buffer( d, "Do you wish to connect anyway (Y/N)?",0);
	    d->connected = CON_BREAK_CONNECT;
	    return TRUE;
	}
    }

    return FALSE;
}



void stop_idling( CHAR_DATA *ch )
{
    if ( ch == NULL
    ||   ch->desc == NULL
    ||   ch->desc->connected != CON_PLAYING
    ||   ch->was_in_room == NULL 
    ||   ch->in_room != get_room_index(ROOM_VNUM_LIMBO))
	return;

    ch->timer = 0;
    char_from_room( ch );
    char_to_room( ch, ch->was_in_room );
    ch->was_in_room	= NULL;
    act( "$n has returned from the void.", ch, NULL, NULL, TO_ROOM );
    return;
}



/*
 * Write to one char.
 */
void send_to_char_bw( const char *txt, CHAR_DATA *ch )
{
    if ( txt != NULL && ch->desc != NULL )
        write_to_buffer( ch->desc, txt, strlen(txt) );
    return;
}

/*
 * Write to one char, new colour version, by Lope.
 */
void send_to_char( const char *txt, CHAR_DATA *ch )
{
    const	char 	*point;
    		char 	*point2;
    		char 	buf[ MAX_STRING_LENGTH*4 ];
		int	skip = 0;

    buf[0] = '\0';
    point2 = buf;
    if( txt && ch->desc )
	{
	    if( IS_SET( ch->act, PLR_COLOUR ) )
	    {
		for( point = txt ; *point ; point++ )
	        {
		    if( *point == '{' )
		    {
			point++;
			skip = colour( *point, ch, point2 );
			while( skip-- > 0 )
			    ++point2;
			continue;
		    }
		    *point2 = *point;
		    *++point2 = '\0';
		}			
		*point2 = '\0';
        	write_to_buffer( ch->desc, buf, point2 - buf );
	    }
	    else
	    {
		for( point = txt ; *point ; point++ )
	        {
		    if( *point == '{' )
		    {
			point++;
			continue;
		    }
		    *point2 = *point;
		    *++point2 = '\0';
		}
		*point2 = '\0';
        	write_to_buffer( ch->desc, buf, point2 - buf );
	    }
	}
    return;
}

void send_to_desc( const char *txt, DESCRIPTOR_DATA *d )
{
    const	char 	*point;
    		char 	*point2;
    		char 	buf[ MAX_STRING_LENGTH*4 ];
		int	skip = 0;

    buf[0] = '\0';
    point2 = buf;
    if( txt && d )
 	{
 	    if( d->ansi == TRUE )
 	    {
 		for( point = txt ; *point ; point++ )
 	        {
 		    if( *point == '{' )
 		    {
 			point++;
 			skip = colour( *point, NULL, point2 );
 			while( skip-- > 0 )
 			    ++point2;
 			continue;
 		    }
 		    *point2 = *point;
 		    *++point2 = '\0';
 		}			
 		*point2 = '\0';
         	write_to_buffer( d, buf, point2 - buf );
 	    }
 	    else
 	    {
 		for( point = txt ; *point ; point++ )
 	        {
 		    if( *point == '{' )
 		    {
 			point++;
 			continue;
 		    }
 		    *point2 = *point;
 		    *++point2 = '\0';
 		}
 		*point2 = '\0';
         	write_to_buffer( d, buf, point2 - buf );
 	    }
 	}
     return;
}

/*
 * Send a page to one char.
 */
void page_to_char_bw( const char *txt, CHAR_DATA *ch )
{
    if ( txt == NULL || ch->desc == NULL)
	return;

    if (ch->lines == 0 )
    {
	send_to_char(txt,ch);
	return;
    }
	
#if defined(macintosh)
	send_to_char(txt,ch);
#else
    ch->desc->showstr_head = alloc_mem(strlen(txt) + 1);
    strcpy(ch->desc->showstr_head,txt);
    ch->desc->showstr_point = ch->desc->showstr_head;
    show_string(ch->desc,"");
#endif
}

void page_to_char (const char *txt, CHAR_DATA * ch)
{
    const char *point;
    char *point2;
    char buf[MAX_STRING_LENGTH * 4];
    int skip = 0;

#if defined(macintosh)
    send_to_char (txt, ch);
#else
    buf[0] = '\0';
    point2 = buf;
    if (txt && ch->desc)
    {
        if (IS_SET (ch->act, PLR_COLOUR))
        {
            for (point = txt; *point; point++)
            {
                if (*point == '{')
                {
                    point++;
                    skip = colour (*point, ch, point2);
                    while (skip-- > 0)
                        ++point2;
                    continue;
                }
                *point2 = *point;
                *++point2 = '\0';
            }
            *point2 = '\0';
            ch->desc->showstr_head = alloc_mem (strlen (buf) + 1);
            strcpy (ch->desc->showstr_head, buf);
            ch->desc->showstr_point = ch->desc->showstr_head;
            show_string (ch->desc, "");
        }
        else
        {
            for (point = txt; *point; point++)
            {
                if (*point == '{')
                {
                    point++;
                    continue;
                }
                *point2 = *point;
                *++point2 = '\0';
            }
            *point2 = '\0';
            ch->desc->showstr_head = alloc_mem (strlen (buf) + 1);
            strcpy (ch->desc->showstr_head, buf);
            ch->desc->showstr_point = ch->desc->showstr_head;
            show_string (ch->desc, "");
        }
    }
#endif
    return;
}

/* string pager */
void show_string(struct descriptor_data *d, char *input)
{
    char buffer[4*MSL];
    char buf[MIL];
    register char *scan, *chk;
    int lines = 0, toggle = 1;
    int show_lines;

    one_argument(input,buf);
    if (buf[0] != '\0')
    {
	if (d->showstr_head)
	{
	    free_string(d->showstr_head);
	    d->showstr_head = 0;
	}
    	d->showstr_point  = 0;
	return;
    }

    if (d->character)
	show_lines = d->character->lines;
    else
	show_lines = 0;

    for (scan = buffer; ; scan++, d->showstr_point++)
    {
	if (((*scan = *d->showstr_point) == '\n' || *scan == '\r')
	    && (toggle = -toggle) < 0)
	    lines++;

	else if (!*scan || (show_lines > 0 && lines >= show_lines))
	{
	    *scan = '\0';
	    write_to_buffer(d,buffer,strlen(buffer));
	    for (chk = d->showstr_point; isspace(*chk); chk++);
	    {
		if (!*chk)
		{
		    if (d->showstr_head)
        	    {
            		free_string(d->showstr_head);
            		d->showstr_head = 0;
        	    }
        	    d->showstr_point  = 0;
    		}
	    }
	    return;
	}
    }
    return;
}
	

/* quick sex fixer */
void fix_sex(CHAR_DATA *ch)
{
    if (ch->sex < 0 || ch->sex > 2)
    	ch->sex = IS_NPC(ch) ? 0 : ch->pcdata->true_sex;
}

void act (const char *format, CHAR_DATA *ch, const void *arg1, const void *arg2,
	  int type)
{
    /* to be compatible with older code */
    act_new(format,ch,arg1,arg2,type,POS_RESTING);
}


char *force_wrap( char *oldstring )
{
    int i;
    int lastreturn;
    char *rdesc;
    static char xbuf[MSL];
    xbuf[0]='\0';
    i=0;
    lastreturn = 0;

    for (rdesc = oldstring; *rdesc; rdesc++)
    {
    if (*rdesc=='\n' || *rdesc=='\r')
	lastreturn = i;
    if (i == lastreturn+59 || (i > 54 + lastreturn && *rdesc==' '))
    { 
	xbuf[i] = '\n'; i++; xbuf[i] = '\r'; i++; lastreturn = i; }
	xbuf[i]=*rdesc;
    if (*rdesc == '~')
    { 
	xbuf[i] = '\0'; break; }
	if (xbuf[i] == '\0')
    { 
	break; 
    }
	i++; 
    }
	xbuf[i] = '\0'; 
    return xbuf; 
}


void act_new (const char *format, CHAR_DATA * ch, const void *arg1, const void *arg2, int type, int min_pos)
{
    static char *const he_she[] = { "it", "he", "she" };
    static char *const him_her[] = { "it", "him", "her" };
    static char *const his_her[] = { "its", "his", "her" };

    char buf[MAX_STRING_LENGTH];
    char fname[MAX_INPUT_LENGTH];
    CHAR_DATA *to;
    CHAR_DATA *vch = (CHAR_DATA *) arg2;
    OBJ_DATA *obj1 = (OBJ_DATA *) arg1;
    OBJ_DATA *obj2 = (OBJ_DATA *) arg2;
    const char *str;
    const char *i;
    char *point;
    char *pbuff;
    char buffer[MSL * 2];
    bool fColour = FALSE;


    /*
     * Discard null and zero-length messages.
     */
    if (format == NULL || format[0] == '\0')
        return;

    /* discard null rooms and chars */
    if (ch == NULL || ch->in_room == NULL)
        return;

    to = ch->in_room->people;
    if (type == TO_VICT)
    {
        if (vch == NULL)
        {
		vch = ch;
        }
        if (vch == NULL)
        {
            bug ("Act: null vch with TO_VICT.", 0);
            return;
        }


        if (vch->in_room == NULL)
            return;

        to = vch->in_room->people;
    }

    for (; to != NULL; to = to->next_in_room)
    {
        if ((!IS_NPC (to) && to->desc == NULL)
            || (IS_NPC (to) && !HAS_TRIGGER (to, TRIG_ACT))
            || to->position < min_pos)
            continue;

        if ((type == TO_CHAR) && to != ch)
            continue;
        if (type == TO_VICT && (to != vch || to == ch))
            continue;
        if (type == TO_ROOM && to == ch)
            continue;
        if (type == TO_NOTVICT && (to == ch || to == vch))
            continue;

        point = buf;
        str = format;
        while (*str != '\0')
        {
            if (*str != '$')
            {
                *point++ = *str++;
                continue;
            }
            fColour = TRUE;
            ++str;
            i = " <@@@> ";

            if (arg2 == NULL && *str >= 'A' && *str <= 'Z')
            {
                bug ("Act: missing arg2 for code %d.", *str);
                i = " <@@@> ";
            }
            else
            {
                switch (*str)
                {
                	/* Added checking of pointers to each case after
                	 * reading about the bug on Edwin's page.
                	 * JR -- 10/15/00
                	 */
                    default:
                        bug ("Act: bad code %d.", *str);
                        i = " <@@@> ";
                        break;
                        /* Thx alex for 't' idea */
                    case 't':
                    	if (arg1)
                    		i = (char *) arg1;
             			else
             				bug("Act: bad code $t for 'arg1'",0);
			            break;
                    case 'T':
                    	if (arg2)
                        	i = (char *) arg2;
                        else
                        	bug("Act: bad code $T for 'arg2'",0);
                        break;
                    case 'n':
                    	if (ch && to)
                        	i = PERS (ch, to);
                        else
                        	bug("Act: bad code $n for 'ch' or 'to'",0);
                        break;
                    case 'N':
                    	if (vch && to)
                        	i = PERS (vch, to);
                        else
                        	bug("Act: bad code $N for 'vch' or 'to'",0);
                        break;
                    case 'e':
                    	if (ch)
                        	i = he_she[URANGE (0, ch->sex, 2)];
                        else
                        	bug("Act: bad code $e for 'ch'",0);
                        break;
                    case 'E':
                    	if (vch)
                        	i = he_she[URANGE (0, vch->sex, 2)];
                        else
                        	bug("Act: bad code $E for 'vch'",0);
                        break;
                    case 'm':
                    	if (ch)
                        	i = him_her[URANGE (0, ch->sex, 2)];
                        else
                        	bug("Act: bad code $m for 'ch'",0);
                        break;
                    case 'M':
                    	if (vch)
                        	i = him_her[URANGE (0, vch->sex, 2)];
                        else
                        	bug("Act: bad code $M for 'vch'",0);
                        break;
                    case 's':
                    	if (ch)
                        	i = his_her[URANGE (0, ch->sex, 2)];
                        else
                        	bug("Act: bad code $s for 'ch'",0);
                        break;
                    case 'S':
                    	if (vch)
                        	i = his_her[URANGE (0, vch->sex, 2)];
                        else
                        	bug("Act: bad code $S for 'vch'",0);
                        break;
                    case 'p':
                    	if (to && obj1)
                        	i = can_see_obj (to, obj1)
                            ? obj1->short_descr : "something";
                        else
                        	bug("Act: bad code $p for 'to' or 'obj1'",0);
                        break;
                    case 'P':
                    	if (to && obj2)
                        	i = can_see_obj (to, obj2)
                            ? obj2->short_descr : "something";
                        else
                        	bug("Act: bad code $P for 'to' or 'obj2'",0);
                        break;
                    case 'd':
                        if (arg2 == NULL || ((char *) arg2)[0] == '\0')
                        {
                            i = "door";
                        }
                        else
                        {
                            one_argument ((char *) arg2, fname);
                            i = fname;
                        }
                        break;
			    case 'v':
				i = obj1->short_descr;
				break;

			    case 'V':
				i = obj2->short_descr;
				break;
		    case 'g':
			if ( ch->alignment < 0 ) { i = "Belan"; }
			else { i = "Thoth"; }
			if (!IS_NPC(ch)) {
				if (ch->pcdata->deity) { 
					i = ch->pcdata->deity->name; 
					}
			}
			break;
                }
            }

            ++str;
            while ((*point = *i) != '\0')
                ++point, ++i;
        }

        *point++ = '\n';
        *point++ = '\r';
        *point = '\0';
		if (buf[0] == 123)
        	buf[2] = UPPER (buf[2]);
		else
        	buf[0] = UPPER (buf[0]);
        pbuff = buffer;
        colourconv (pbuff, buf, to);
		if (to->desc && (to->desc->connected == CON_PLAYING))
			write_to_buffer( to->desc, buffer, 0); /* changed to buffer to reflect prev. fix */
        else if (MOBtrigger)
            mp_act_trigger (buf, to, ch, arg1, arg2, TRIG_ACT);
    }
    return;
}

int colour (char type, CHAR_DATA * ch, char *string)
{
    PC_DATA *col;
    char code[20];
    char *p = '\0';

    if (ch && IS_NPC (ch))
        return (0);

    col = ch ? ch->pcdata : NULL;

    switch (type)
    {
        default:
            strcpy (code, CLEAR);
            break;
        case 'x':
            strcpy (code, CLEAR);
            break;
        case 'p':
            if (col->prompt[2])
                sprintf (code, "\033[%d;3%dm%c", col->prompt[0],
                         col->prompt[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->prompt[0], col->prompt[1]);
            break;
        case 's':
            if (col->room_title[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->room_title[0], col->room_title[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->room_title[0],
                         col->room_title[1]);
            break;
        case 'S':
            if (col->room_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->room_text[0], col->room_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->room_text[0],
                         col->room_text[1]);
            break;
        case 'd':
            if (col->gossip[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->gossip[0], col->gossip[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->gossip[0], col->gossip[1]);
            break;
        case '9':
            if (col->gossip_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->gossip_text[0], col->gossip_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->gossip_text[0],
                         col->gossip_text[1]);
            break;
        case 'Z':
            if (col->wiznet[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->wiznet[0], col->wiznet[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->wiznet[0], col->wiznet[1]);
            break;
        case 'o':
            if (col->room_exits[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->room_exits[0], col->room_exits[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->room_exits[0],
                         col->room_exits[1]);
            break;
        case 'O':
            if (col->room_things[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->room_things[0], col->room_things[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->room_things[0],
                         col->room_things[1]);
            break;
        case 'i':
            if (col->immtalk_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->immtalk_text[0], col->immtalk_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm",
                         col->immtalk_text[0], col->immtalk_text[1]);
            break;
        case 'I':
            if (col->immtalk_type[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->immtalk_type[0], col->immtalk_type[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm",
                         col->immtalk_type[0], col->immtalk_type[1]);
            break;
        case '2':
            if (col->fight_yhit[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->fight_yhit[0], col->fight_yhit[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->fight_yhit[0],
                         col->fight_yhit[1]);
            break;
        case '3':
            if (col->fight_ohit[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->fight_ohit[0], col->fight_ohit[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->fight_ohit[0],
                         col->fight_ohit[1]);
            break;
        case '4':
            if (col->fight_thit[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->fight_thit[0], col->fight_thit[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->fight_thit[0],
                         col->fight_thit[1]);
            break;
        case '5':
            if (col->fight_skill[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->fight_skill[0], col->fight_skill[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->fight_skill[0],
                         col->fight_skill[1]);
            break;
        case '1':
            if (col->fight_death[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->fight_death[0], col->fight_death[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->fight_death[0],
                         col->fight_death[1]);
            break;
        case '6':
            if (col->say[2])
                sprintf (code, "\033[%d;3%dm%c", col->say[0], col->say[1],
                         '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->say[0], col->say[1]);
            break;
        case '7':
            if (col->say_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->say_text[0], col->say_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->say_text[0],
                         col->say_text[1]);
            break;
        case 'k':
            if (col->tell[2])
                sprintf (code, "\033[%d;3%dm%c", col->tell[0], col->tell[1],
                         '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->tell[0], col->tell[1]);
            break;
        case 'K':
            if (col->tell_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->tell_text[0], col->tell_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->tell_text[0],
                         col->tell_text[1]);
            break;
        case 'l':
            if (col->reply[2])
                sprintf (code, "\033[%d;3%dm%c", col->reply[0],
                         col->reply[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->reply[0], col->reply[1]);
            break;
        case 'L':
            if (col->reply_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->reply_text[0], col->reply_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->reply_text[0],
                         col->reply_text[1]);
            break;
        case 'n':
            if (col->gtell_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->gtell_text[0], col->gtell_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->gtell_text[0],
                         col->gtell_text[1]);
            break;
        case 'N':
            if (col->gtell_type[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->gtell_type[0], col->gtell_type[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->gtell_type[0],
                         col->gtell_type[1]);
            break;
        case 'a':
            if (col->auction[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->auction[0], col->auction[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->auction[0],
                         col->auction[1]);
            break;
        case 'A':
            if (col->auction_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->auction_text[0], col->auction_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->auction_text[0],
                         col->auction_text[1]);
            break;
        case 'q':
            if (col->question[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->question[0], col->question[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->question[0],
                         col->question[1]);
            break;
        case 'Q':
            if (col->question_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->question_text[0], col->question_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm",
                         col->question_text[0], col->question_text[1]);
            break;
        case 'f':
            if (col->answer[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->answer[0], col->answer[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->answer[0], col->answer[1]);
            break;
        case 'F':
            if (col->answer_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->answer_text[0], col->answer_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->answer_text[0],
                         col->answer_text[1]);
            break;
        case 'e':
            if (col->music[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->music[0], col->music[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->music[0], col->music[1]);
            break;
        case 'E':
            if (col->music_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->music_text[0], col->music_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->music_text[0],
                         col->music_text[1]);
            break;
        case 'h':
            if (col->quote[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->quote[0], col->quote[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->quote[0], col->quote[1]);
            break;
        case 'H':
            if (col->quote_text[2])
                sprintf (code, "\033[%d;3%dm%c",
                         col->quote_text[0], col->quote_text[1], '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->quote_text[0],
                         col->quote_text[1]);
            break;
        case 'j':
            if (col->info[2])
                sprintf (code, "\033[%d;3%dm%c", col->info[0], col->info[1],
                         '\a');
            else
                sprintf (code, "\033[%d;3%dm", col->info[0], col->info[1]);
            break;
        case 'b':
            strcpy (code, C_BLUE);
            break;
        case 'c':
            strcpy (code, C_CYAN);
            break;
        case 'g':
            strcpy (code, C_GREEN);
            break;
        case 'm':
            strcpy (code, C_MAGENTA);
            break;
        case 'r':
            strcpy (code, C_RED);
            break;
        case 'w':
            strcpy (code, C_WHITE);
            break;
        case 'y':
            strcpy (code, C_YELLOW);
            break;
        case 'B':
            strcpy (code, C_B_BLUE);
            break;
        case 'C':
            strcpy (code, C_B_CYAN);
            break;
        case 'G':
            strcpy (code, C_B_GREEN);
            break;
        case 'M':
            strcpy (code, C_B_MAGENTA);
            break;
        case 'R':
            strcpy (code, C_B_RED);
            break;
        case 'W':
            strcpy (code, C_B_WHITE);
            break;
        case 'Y':
            strcpy (code, C_B_YELLOW);
            break;
        case 'D':
            strcpy (code, C_D_GREY);
            break;
        case '*':
            sprintf (code, "%c", '\a');
            break;
        case '/':
            strcpy (code, "\n\r");
            break;
        case '-':
            sprintf (code, "%c", '~');
            break;
        case '{':
            sprintf (code, "%c", '{');
            break;
    }

    p = code;
    while (*p != '\0')
    {
        *string = *p++;
        *++string = '\0';
    }

    return (strlen (code));
}

void colourconv (char *buffer, const char *txt, CHAR_DATA * ch)
{
    const char *point;
    int skip = 0;

    if (ch && ch->desc && txt)
    {
        if (IS_SET (ch->act, PLR_COLOUR))
        {
            for (point = txt; *point; point++)
            {
                if (*point == '{')
                {
                    point++;
					if (*point != '\n') {
                    	skip = colour (*point, ch, buffer);
                    	while (skip-- > 0)
                       		++buffer;
                    	continue;
					}
                }
                *buffer = *point;
                *++buffer = '\0';
            }
            *buffer = '\0';
        }
        else
        {
            for (point = txt; *point; point++)
            {
                if (*point == '{')
                {
                    point++;
                    continue;
                }
                *buffer = *point;
                *++buffer = '\0';
            }
            *buffer = '\0';
        }
    }
    return;
}

/*
 * Non *nix support functions.
 */
#if defined(macintosh) || defined(WIN32)
int gettimeofday( struct timeval *tp, void *tzp )
{
    tp->tv_sec  = time( NULL );
    tp->tv_usec = 0;

	return tp->tv_sec;
}
#endif

void printf_to_char (CHAR_DATA *ch, char *fmt, ...)
{
	char buf [MAX_STRING_LENGTH];
	va_list args;
	va_start (args, fmt);
	vsprintf (buf, fmt, args);
	va_end (args);
	send_to_char (buf, ch);
}