lurf/area/
lurf/build/testing/
lurf/log/
lurf/player/
lurf/player/backup/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *                                                                         *
 *  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.                                               *
 *                                                                         *
 *  Thanks to abaddon for proof-reading our comm.c and pointing out bugs.  *
 *  Any remaining bugs are, of course, our work, not his.  :)              *
 *                                                                         *
 *  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.                                                  *
 ***************************************************************************/

/*
 * 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
 */
#include <glib.h>

#include <sys/types.h>
#if defined(unix)
#include <sys/time.h>
#endif
#if defined(_WIN32)

#include <time.h>
#include <winsock2.h>

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

#include <crypt.h>
#include <merc.h>
#include <tables.h>
#include <interp.h>
#include <recycle.h>
#include <telnet.h>

#include <sys/stat.h>

#if	defined(unix)
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>
#endif

#include <unistd.h>
#if defined(unix)
#include <signal.h>
#include <sys/resource.h>	/* for RLIMIT_NOFILE */
#endif
#if defined(unix)
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

#if	defined(linux)
int	close		args( ( int fd ) );
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	gettimeofday	args( ( struct timeval *tp, struct timezone *tzp ) );
#endif

#if defined(unix)
int	close		args( ( int fd ) );
#endif
/*
 * Other local functions (OS-independent).
 */
bool	check_reconnect		args( ( DESCRIPTOR_DATA *d, char *name,
		bool fConn ) );
bool	check_kickoff		args( ( DESCRIPTOR_DATA *d, char *name,
		bool fConn ) );
bool	check_newbie_playing args( ( DESCRIPTOR_DATA *d, char *name ) );
bool	check_player_ID		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( ( DESCRIPTOR_DATA *d ) );
int     port,control;
void 	init_signals   		args( (void) );
void  lookup_address   args((DUMMY_ARG *dummyarg));  // Only threaded calls, please.
void 	do_auto_shutdown 	args( (void) );

/*
 * Snooper functions
 */
extern void remove_snooper args((CHAR_DATA *ch, CHAR_DATA *victim));
extern void add_descriptor args((DESCRIPTOR_DATA *d));
extern void remove_descriptor args((DESCRIPTOR_DATA *d));
extern bool    check_ban               args( (const GString *site, int type ) );
extern void removeAllSnoopers args((DESCRIPTOR_DATA *ch_desc));

/*
 * Bust a prompt (player settable prompt)
 * coded by Morgenes for Aldara Mud
 */
/* Colour scale char list - Calamar */


char *scale[SCALE_COLS] = {
	L_RED,
	L_BLUE,
	L_GREEN,
	YELLOW
};
extern FILE *		    fpReserve;		/* Reserved file handle		*/
extern bool		    god;		/* All new chars are gods!	*/
extern bool		    merc_down;		/* Shutdown			*/
extern bool		    wizlock;		/* Game is wizlocked		*/
extern bool            newlock;            /* Game is newlocked            */
extern char		    str_boot_time[MAX_INPUT_LENGTH];
extern char		    crypt_pwd[MAX_INPUT_LENGTH];
extern time_t		    current_time;	/* Time of this pulse		*/
extern time_t			boot_time;

#if defined(unix)
void sig_handler(int sig)
{
	switch(sig)
	{
		case SIGBUS:
			//log_string2("Sig handler SIGBUS.");
			//pthread_kill_other_threads_np();
            //do_auto_shutdown();
			break;
		case SIGTERM:
			//log_string2("Sig handler SIGTERM.");
			//pthread_kill_other_threads_np();
            //do_auto_shutdown();
			break;
		case SIGABRT:
			//log_string2("Sig handler SIGABRT");  
			//pthread_kill_other_threads_np();
            //do_auto_shutdown();
			break;
		case SIGSEGV:
			//log_string2("Sig handler SIGSEGV");
			//pthread_kill_other_threads_np();
            //do_auto_shutdown();
			break;
	}
}

void init_signals()
{
	signal(SIGBUS,sig_handler);
	signal(SIGTERM,sig_handler);
	signal(SIGABRT,sig_handler);
	signal(SIGSEGV,sig_handler);
}
#endif




/* Above is the old init_socket ... this one here may work right */
int init_socket(int port)
{
	int s;
	struct sockaddr_in sa;
	struct linger ld;
	int reuse = 1;

#if defined(_WIN32)
	char opt = 1;
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
 
	wVersionRequested = MAKEWORD( 2, 2 );
 
	err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 ) {
		/* Tell the user that we could not find a usable */
		/* WinSock DLL.                                  */
		bug("Ummm no can do!",0);
		exit(1);
	}
#endif
	//Set &sa to 0
	memset(&sa, 0, sizeof(sa));
	
	s = socket(AF_INET, SOCK_STREAM, 0);
	if (s < 0)
	{
		bug("Init-socket",0);
		exit(1);
	}

	sa.sin_family = AF_INET;
	sa.sin_port   = htons(port);
	sa.sin_addr.s_addr = htonl(INADDR_ANY);

#if defined(_WIN32)
	
	if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
	{
		bug ("setsockopt REUSEADDR",0);
		exit (1);
	}
#endif

#if defined(unix)
	ld.l_onoff = 1;
	ld.l_linger = 1000;

  	/*	
	*This option controls whether bind (see Setting Address) should permit
	* reuse of local addresses for this socket. If you enable this option,
	* you can actually have two sockets with the same Internet port number;
	* but the system won't allow you to use the two identically-named 
	* sockets in a way that would confuse the Internet. The reason for 
	* this option is that some higher-level Internet protocols, including 
	* FTP, require you to keep reusing the same port number.
	*/

	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		bug("setsockopt REUSEADDR",0);
		exit(1);
	}

	/*
	 * IF they are doing NOTHING, close them!
	 */
	if (setsockopt(s, SOL_SOCKET, SO_LINGER, &ld, sizeof(ld)) < 0)
	{
		bug("setsockopt LINGER",0);
		exit(1);
	}

#endif
	if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
	{
		//bug("bind",0);
		close(s);
		exit(1);
	}
	listen(s, 9);
	return(s);
}

/*
 * Shift the input buffer.
 */
void shift_buffer(DESCRIPTOR_DATA *d, int i)
{
	int j;

	while ( d->inbuf[i] == '\n' || d->inbuf[i] == '\r' )
		i++;
	for ( j = 0; ( d->inbuf[j] = d->inbuf[i+j] ) != '\0'; j++ )
		;
	return;
}

void shift_buffer_start(DESCRIPTOR_DATA *d, int start, int i)
{
	int j;

	while ( d->inbuf[i] == '\n' || d->inbuf[i] == '\r' )
		i++;
	for ( j = start; ( d->inbuf[j] = d->inbuf[i+j] ) != '\0'; j++ )
		;
	return;
}
/*
 * Transfer one line from input buffer to input line.
 */
void read_from_buffer( DESCRIPTOR_DATA *d )
{
	int i, k, offset;
	
    /*
	 * Check if we are in charge of local echo..
	 * then check if we are not playing..
	 */
	/*
     * 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;
	}
	
    //Check for Telnet Commands Here
	for (i = 0;d->inbuf[i] != '\0'; i++)
	{
		unsigned char c = d->inbuf[i];
		if (c == IAC)
		{
			offset = parse_telnetcommand(d);
            shift_buffer_start(d,i,offset);
        }
	}
    
    if (d->telnet_option[TELOPT_ECHO] == ACTIVE)
	{
		if (d->connected != CON_PLAYING)
			write_to_descriptor(d->descriptor,"*",0);
		else
			write_to_descriptor(d->descriptor,d->inbuf,0);
	}
    /*
     * 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 >= 30 && d->character && d->connected == CON_PLAYING )
			{
				if (d != NULL && d->character != NULL)
					sprintf( log_buf, "%s input spamming!", d->character->lasthost->str );
				else
					sprintf( log_buf, "%s input spamming!", d->host->str );
				log_string2( log_buf );
				logchan(log_buf, NULL, NULL,WIZ_SPAM,0, LEVEL_QUESTMAKER);
				write_to_descriptor( d->descriptor,
					"\n\r*** SPAM is Bad, Calm DOWN!!! ***\n\r", 0 );
				str_cpy( d->incomm, "quit" );
			}
			//don't add if they used note in the command
			if ( !strcmp(d->incomm, "note") )
				d->repeat--;
		}
	}
	
    /*
     * Do '!' substitution.
     */
	if ( d->incomm[0] == '!' )
		str_cpy( d->incomm, d->inlast );
	else
		str_cpy( d->inlast, d->incomm );

	shift_buffer(d,i);	
return;
}

#if defined(unix)

void excessive_cpu(int blx)
{
	CHAR_DATA *vch;
	CHAR_DATA *vch_next;
	
	for ( vch = char_list; vch != NULL; vch = vch_next )
	{
		vch_next = vch->next;
		
		if ( !IS_NPC(vch) )
		{
			send_to_char("Mud frozen: Autosave and quit.  Lurking Fear II will reboot in 2 seconds.\n\r",vch);
			interpret( vch, "quit" );
		}
	}
	abort();
}
#endif


void init_copyover_descriptor (DESCRIPTOR_DATA *dnew, int desc)
{
	dnew = new_descriptor();	
	
	dnew->descriptor = desc;

	dnew->connected = CON_GET_NAME;
	
}

void init_descriptor( int control )
{
	/*static DESCRIPTOR_DATA d_zero;*/
	DESCRIPTOR_DATA *dnew;
	struct sockaddr_in sock;
	struct hostent *from;
	int desc;
	int size;
	int val;
	
	size = sizeof(sock);
	val = getsockname( control, (struct sockaddr *) &sock, (socklen_t *)&size );
	if ( ( desc = accept( control, (struct sockaddr *) &sock, (socklen_t *)&size) ) < 0 )
	{
		bug( "New_descriptor: accept",0 );
		return;
	}
#if defined(unix)	
#if !defined(FNDELAY)
#define FNDELAY O_NDELAY
#endif

	if ( fcntl( desc, F_SETFL, FNDELAY ) == -1 )
	{
		bug( "New_descriptor: fcntl: FNDELAY",0 );
		return;
	}
#endif
	dnew = new_descriptor();	
	/*init_descriptor (dnew,desc);*/

	dnew->descriptor = desc;

	dnew->connected  = CON_GET_NAME;
	dnew->s_state = TOP_LEVEL;

	size = sizeof(sock);
	if ( getpeername( desc, (struct sockaddr *) &sock, (socklen_t *)&size ) < 0 )
	{
		bug( "New_descriptor: getpeername",0 );
		dnew->host = g_string_assign(dnew->host,"(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.
		 */
		char *addr;

		addr = inet_ntoa(sock.sin_addr);

		sprintf( log_buf, "Sock.sinaddr:  %s", addr );
		log_string2( log_buf );
		logchan(log_buf, NULL, NULL,WIZ_SITES,0, LEVEL_QUESTMAKER);

		//problems here.. something wasn't initalised

		from = gethostbyaddr( (char *) &sock.sin_addr, sizeof(sock.sin_addr), AF_INET ); 
		if (!from)
			dnew->host = g_string_assign(dnew->host,addr);
		else
			dnew->host = g_string_assign(dnew->host,from->h_name);
	}
	/*
	 * 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 Lurking Fear II.\n\r",0);			
		write_to_descriptor(desc,"Someone has pissed us off, do not ask to lift the ban, \n\r",0);
		write_to_descriptor(desc,"Do not ask about the ban, do not bug us at all. Someone has\n\r",0);
		write_to_descriptor(desc,"Screwed you, I suggest find them and beat them to a pulp, because\n\r",0);
		write_to_descriptor(desc,"You WILL NOT CONNECT FROM THIS ISP. If you have caused the ban,\n\r",0);
		write_to_descriptor(desc,"YOU ARE NOT WELCOME HERE! FIND ANOTHER MUD AND GET LOST, YOU ARE HATED.\n\r",0);
		write_to_descriptor(desc,"You will only find your next ISP banned.\n\r",0);
		close( desc );
		free_descriptor(dnew);
		return;
	}

	/*
	 * Put Descriptor in descriptor_list 
	 */
	descriptor_list = g_slist_append(descriptor_list,dnew);

	/*
	 * Send the greeting.
	 */
	{
	extern char * help_greeting;
	if ( help_greeting[0] == '.' )
		write_to_buffer( dnew, help_greeting+1, 0 );
	else
		write_to_buffer( dnew, help_greeting  , 0 );

	mudsetting->last_proc_logged = 3076;
	}
	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 >= (signed int)sizeof(d->inbuf) - 10 )
	{
		if (d != NULL && d->character != NULL)
			sprintf( log_buf, "%s input overflow!", d->character->lasthost->str );
		else
			sprintf( log_buf, "%s input overflow!", d->host->str );
		logchan(log_buf, NULL, NULL,WIZ_SPAM,0, LEVEL_QUESTMAKER);
		log_string2( log_buf );
		
		write_to_descriptor( d->descriptor,
			"\n\r*** SPAM is bad, Calm DOWN!!! ***\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(_WIN32)
	for ( ; ; )
	{
		int nRead;
		
		nRead = recv( d->descriptor, d->inbuf + iStart,
				sizeof(d->inbuf) - 10 - iStart,0 );
		if ( nRead > 0 )
		{
			iStart += nRead;
			if ( d->inbuf[iStart-1] == '\n' || d->inbuf[iStart-1] == '\r' )
				break;
		}
		else if ( nRead == 0 )
		{
			log_string2( "EOF encountered on read." );
			logchan(log_buf, NULL, NULL,WIZ_SPAM,0, LEVEL_QUESTMAKER);
			close_socket(d);
			return FALSE;
		}
		else
		{
			//Bad read.. close the sucker..
			bug( "Read_from_descriptor",0 );
			close_socket(d);
			return FALSE;
		}
	}
#endif
	
#if defined(MSDOS) || defined(unix)
	for ( ; ; )
	{
		int nRead;
		
		nRead = read( d->descriptor, d->inbuf + iStart,
				sizeof(d->inbuf) - 10 - iStart );
		if ( nRead > 0 )
		{
			iStart += nRead;

			//if ( d->inbuf[iStart-1] == '\n' || d->inbuf[iStart-1] == '\r' )
			//	break;
		}
		else if ( nRead == 0 )
		{
			log_string2( "EOF encountered on read." );
			logchan(log_buf, NULL, NULL,WIZ_SPAM,0, LEVEL_QUESTMAKER);
			close_socket(d);
			return FALSE;
		}
		else if ( errno == EWOULDBLOCK )
			break;
		else
		{
			bug( "Read_from_descriptor",0 );
			close_socket(d);
			return FALSE;
		}
	}
#endif
	
	d->inbuf[iStart] = '\0';
	return TRUE;
}






/*
 * Deal with sockets that haven't logged in yet.
 */
void nanny( DESCRIPTOR_DATA *d, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	char kav[MAX_STRING_LENGTH];
	CHAR_DATA *ch;
	char *pwdnew;
	char *p;
	char *strtime;
	int char_age = 17;
	GSList	*desc_list;
	bool fOld,fDup = FALSE; 
	
	if (d->connected != CON_NOTE_TEXT)
	{
		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\n\rName: ", 0 );
				return;
			}

#if defined(unix)
			sprintf(kav,"grep -iw %s bad.names > /dev/null", argument);

			if(0==system(kav)) 
			{
				write_to_buffer(d,"\n\rDictionary name check: This name is in dictionary.\n\r",0);
				write_to_buffer( d, "Illegal name, try another.\n\r\n\rName: ", 0 );
				return;
			}
#endif
			sprintf(kav,"%s trying to connect.", argument);
			log_string2( kav );
			fOld = load_char_short( d, argument );
			if (Player_Error == TRUE)
			{
				Player_Error = FALSE;
				close_socket(d);
				return;
			}
			ch   = d->character;

			logchan(kav, NULL, NULL,WIZ_LOGINS,0,ch->level );

			if ( IS_SET(ch->act, PLR_DENY) )
			{
				sprintf( log_buf, "Denying access to %s@%s.", argument, ch->lasthost->str );
				log_string2( log_buf );
				logchan(log_buf, NULL, NULL,WIZ_LOGINS,0, LEVEL_QUESTMAKER);
				write_to_buffer( d, "You are denied access to Lurking Fear II.  Have a nice day.\n\r", 0 );
				close_socket( d );

				return;
			}
			else if ( IS_EXTRA(ch, EXTRA_BORN) && char_age < 15 )
			{
				char agebuf [MAX_INPUT_LENGTH];
				if (char_age == 14)
					sprintf(agebuf, "You cannot play for another year.\n\r" );
				else
					sprintf(agebuf, "You cannot play for another %d years.\n\r", 
							(15 - years_old(ch)) );
				write_to_buffer(d, agebuf, 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 Lurking Fear II.  Have a nice day.\n\r",0);			
				close_socket(d);
				return;
			}

			if ( check_reconnect( d, argument, FALSE ) )
			{
				fOld = TRUE;
			}
			else
			{
				/* Check max number of players - KaVir */

				DESCRIPTOR_DATA *dcheck_next;
				int countdesc = 0;
				int max_players = 150;

				for ( desc_list = descriptor_list; desc_list != NULL; desc_list = g_slist_next(desc_list) )
				{
					dcheck_next = (DESCRIPTOR_DATA*)desc_list->data;
					countdesc++;
				}

				/* wishful thinking :P */
				if ( countdesc > max_players && !IS_IMMORTAL(ch) )
				{
					write_to_buffer( d, "Too many players connected, please try again in a couple of minutes.\n\r", 0 );
					close_socket( d );
					return;
				}

				if ( wizlock && !IS_IMMORTAL(ch) )
				{
					write_to_buffer( d, "Lurking Fear II is temporarily BROKEN.  Please try again later.\n\r", 0 );
					close_socket( d );
					return;
				}
			}

			if ( fOld )
			{
				//Tell the client I'll do teh echoing for passwords
				send_reply(d,TC_WILL,TELOPT_ECHO);
				/* Old player */
				write_to_buffer( d, "Please enter password: ", 0 );

				d->connected = CON_GET_OLD_PASSWORD;
				return;
			}
			else
			{

				/* New player */
				if ( check_newbie_playing(d, argument ) )
				{
					write_to_buffer(d, "There is someone already on with that name. Please choose another!.\n\rName: ",0);
					return;
				}

				if (newlock)
				{
					write_to_buffer( d, "Lurking Fear II is temporarily newlocked.  Please try again later.\n\r", 0 );
					close_socket( d );
					return;
				}

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

				do_help (ch, " newname");
				sprintf( buf, "You want %s engraved on your tombstone (Y/N)? ", argument );
				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 defined(unix)
			if ( ch == NULL || (!IS_EXTRA(ch,EXTRA_NEWPASS) &&
						(ch->pcdata->pwd->len > 0 &&
						(strcmp( argument, ch->pcdata->pwd->str ) &&
						strcmp( crypt( argument, ch->pcdata->pwd->str ), ch->pcdata->pwd->str )))))
			{
				write_to_buffer( d, "Wrong password.\n\r", 0 );
				free_char( ch );
				close_socket( d );
				return;
			}
			else if ( ch == NULL || (IS_EXTRA(ch,EXTRA_NEWPASS) &&
						(ch->pcdata->pwd->len > 0 &&
						(strcmp( crypt( argument, ch->pcdata->pwd->str ), ch->pcdata->pwd->str )))))
			{
				write_to_buffer( d, "Wrong password.\n\r", 0 );
				free_char( ch );
				close_socket( d );
				return;
			}
#endif			
			//Tell the client to turn back on local echo
			send_reply(d,TC_WONT,TELOPT_ECHO);

			if ( check_reconnect( d, ch->name->str, TRUE ) )
			{
				fDup = TRUE;
				return;
			}

			if ( check_playing( d, ch->name->str ) )
			{
				fDup = TRUE;
				return;
			}

			if ( check_kickoff( d, ch->name->str, FALSE ) )
			{
				fDup = TRUE;
				return;
			}

			if ( check_player_ID( d, ch->name->str, FALSE ) )
			{
				fDup = TRUE;
				return;
			}
			/*** Avoid nasty duplication bug - KaVir */
			if (ch->level > 1)
			{
				sprintf(kav,ch->name->str);
				
				ch   = d->character;
				fOld = TRUE;
			}

			if ( !IS_EXTRA(ch,EXTRA_NEWPASS) && strlen(argument) > 1) {
				sprintf(kav,"%s %s",argument,argument);
				do_password(ch,kav);}

				if (IS_IMMORTAL(ch))
					sprintf( log_buf, "{W%s@%s has connected.{x", ch->name->str, ch->lasthost->str );
				else
					sprintf( log_buf, "%s@%s has connected.", ch->name->str, ch->lasthost->str );

				log_string2( log_buf );
				logchan(log_buf, NULL, NULL,WIZ_LOGINS,0,ch->level );

				/* In case we have level 4+ players from another merc mud, or 
				 * players who have somehow got file access and changed their pfiles.
				 */
				if ( ch->level > 3 && ch->trust == 0)
					ch->level = 3;
				else
				{
					if ( ch->level > MAX_LEVEL )
						ch->level = MAX_LEVEL;
					if ( ch->trust > MAX_LEVEL)
						ch->trust = MAX_LEVEL;
				}
				if (d->character->level == LEVEL_AVATAR)
				{
					d->connected = CON_READLOG;
					send_to_char("Press RETURN to continue:\n\r",d->character);
				}
				else
				{
					if ( IS_HERO(ch) )
						do_help( ch, "imotd" );
					do_help( ch, "motd" );
					d->connected = CON_READ_MOTD;
				}
				break;

		case CON_READLOG:

				if ( IS_HERO(ch) )
					do_help( ch, "imotd" );
				do_help( ch, "motd" );
				d->connected = CON_READ_MOTD;
				break;

		case CON_CONFIRM_NEW_NAME:
				switch ( *argument )
				{
					case 'y': case 'Y':
						sprintf( buf, "New character.\n\rGive me a password for %s: ",
								ch->name->str );
						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 );
						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;
				}

#if defined(unix)
				pwdnew = crypt( argument, ch->name->str );
#else
				pwdnew = argument;
#endif

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

				ch->pcdata->pwd	= g_string_assign(ch->pcdata->pwd, 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 );

				if ( strcmp( crypt( argument, ch->pcdata->pwd->str ), ch->pcdata->pwd->str ) )
				{
					write_to_buffer( d, "Passwords don't match.\n\rRetype password: ",
							0 );
					d->connected = CON_GET_NEW_PASSWORD;
					return;
				}
#endif	
				//Tell client to take over local echo
				send_reply(d,TC_WONT,TELOPT_ECHO);
				
				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;    break;
					case 'f': case 'F': ch->sex = SEX_FEMALE;  break;
					default:
							    write_to_buffer( d, "That's not a sex.\n\rWhat IS your sex? ", 0 );
							    return;
				}
				/*
				 * Taken out for now
				 write_to_buffer(d,"HardCore: This is a option if you want to take it, if your character dies after this screen, it is gone forever.\n\rDo you wish to be Hardcore? ",0);
				 d->connected = CON_HARDCORE;
				 */	
				/*
				 * So we can have normal players for now
				 */
				ch->pcdata->perm_str=number_range(10,16);
				ch->pcdata->perm_int=number_range(10,16);
				ch->pcdata->perm_wis=number_range(10,16);
				ch->pcdata->perm_dex=number_range(10,16);
				ch->pcdata->perm_con=number_range(10,16);
				sprintf( log_buf, "%s@%s new player.", ch->name->str, d->host->str );
				log_string2( log_buf );
				logchan(log_buf, NULL, NULL,WIZ_NEWBIE,0, LEVEL_QUESTMAKER);
				write_to_buffer( d, "\n\r", 2 );
				do_help( ch, "motd" );
				d->connected = CON_READ_MOTD;

				break;

		case CON_NOTE_TO:
				handle_con_note_to (d, argument);
				break;

		case CON_NOTE_SUBJECT:
				handle_con_note_subject (d, argument);
				break; /* subject */

		case CON_NOTE_EXPIRE:
				handle_con_note_expire (d, argument);
				break;

		case CON_NOTE_TEXT:
				handle_con_note_text (d, argument);
				break;

		case CON_NOTE_FINISH:
				handle_con_note_finish (d, argument);
				break;

		case CON_READ_MOTD:
				write_to_buffer( d,     "\n\rWelcome to Lurking Fear II.  Don't be afraid of the dark.\n\r\n\r",
						0 );
				// Load the rest of the player here to avid nasty dup bugs -dm

				if (ch->level > 1)
				{
					if (!fDup) 
					{
						/*
						 * Free Both Ch, and D->character...
						 * Were going to re-load them..
						 */
						char *tmpname = g_strdup(ch->name->str);

						free_char(ch);
						free_char(d->character);

						d->character = NULL;
						ch = NULL;

						fOld = load_char_obj( d, tmpname );
						g_free(tmpname);
						if (Player_Error == TRUE)
						{
							Player_Error = FALSE;
							close_socket(d);
							return;
						}
						ch = d->character;

						if ( fOld && ch->lasthost != NULL && ch->lasthost->len > 1 &&
								ch->lasttime != NULL && ch->lasttime->len)
						{
							sprintf(kav,"Last connected from %s at %s\n\r",ch->lasthost->str,ch->lasttime->str);
							write_to_buffer( d, kav, 0 );
						}
						else if ( fOld && ch->lasthost != NULL && ch->lasthost->len)
						{
							sprintf(kav,"Last connected from %s.\n\r",ch->lasthost->str);
							write_to_buffer( d, kav, 0 );
						}
					}
				}

				if (!fDup) 
				{
					ch->next	= char_list;
					char_list	= ch;
				}

				d->connected	= CON_PLAYING;

				if (ch->desc != NULL && ch->desc->host != NULL)
				{
					ch->lasthost = g_string_assign(ch->lasthost, ch->desc->host->str);
				}
				else
					ch->lasthost = g_string_assign(ch->lasthost,"(unknown)");
				strtime = ctime( &current_time );
				strtime[strlen(strtime)-1] = '\0';
				ch->lasttime = g_string_assign(ch->lasttime,strtime );

				/* delay SHIT */

				if (CAN_PK(ch))
				{
					do_help(ch,"wait timer");
					ch->delay_timer = 6;
				}

				if (IS_CLASS(ch, CLASS_VAMPIRE) && ch->level < 4  ) 
				{
					int ch_age = (get_age(ch) - 17) * 2;  /* hours calculation */
					ch->pcdata->rank = AGE_NEONATE;

					if      (ch_age >= 1500) ch->pcdata->rank = AGE_METHUSELAH;
					else if (ch_age >=  800) ch->pcdata->rank = AGE_ELDER;
					else if (ch_age >=  400) ch->pcdata->rank = AGE_ANCILLA;
					else if (ch_age >=  200) ch->pcdata->rank = AGE_NEONATE;
					else                     ch->pcdata->rank = AGE_CHILDE;
				}

				if ( ch->level == 0 )
				{
					ch->level	= 1;
					ch->exp	        = 100;
					ch->hit	        = ch->max_hit;
					ch->mana	= ch->max_mana;
					ch->move	= ch->max_move;
					ch->creature       = 0;
					ch->special     = 0;
					ch->gold        = 500;
					ch->pcdata->charpoints	= 20;
					set_title( ch, "the newbie mortal" );

					SET_BIT(ch->act, PLR_AUTOEXIT);
					ch->short_descr = g_string_assign(ch->short_descr,"");
					ch->long_descr = g_string_assign(ch->long_descr,"");
					ch->description = g_string_assign(ch->description,"");
					REMOVE_BIT(ch->deaf, CHANNEL_MSP);
					REMOVE_BIT(ch->deaf, CHANNEL_OOC);
					REMOVE_BIT(ch->deaf, CHANNEL_MUSIC);

					if (IS_SET(mudsetting->mud_setting, MS_CHAOS_NIGHT))
					{
						send_to_char("--------------------------------------------------------------------------------\n\r",ch);
						send_to_char("Welcome to Class Balancing Night! You are set with HP/MANA/PRIMAL, go bug a Imm \n\r",ch);
						send_to_char("about getting classed and have fun! Remember this is only to balance classes and\n\r",ch);
						send_to_char("all the original characters will be back to normal.\n\r",ch);
						send_to_char("--------------------------------------------------------------------------------\n\r\n\r",ch);
					}
					else
					{
						send_to_char("--------------------------------------------------------------------------------\n\r",ch);
						send_to_char("If you need help, try talking to the spirit of mud school!\n\r",ch);
						send_to_char("--------------------------------------------------------------------------------\n\r\n\r",ch);
						do_help (ch, "newstart");
					}
					char_to_room( ch, get_room_index( ROOM_VNUM_SCHOOL ) );
					do_look( ch, "auto" );
					if (IS_SET(mudsetting->mud_setting, MS_CHAOS_NIGHT))
					{
						ch->hit = 50000;
						ch->mana = 50000;
						ch->move = 50000;
						ch->practice = 8000;
						ch->race = 1;
						ch->level = 3;
						ch->exp = 900000;
						set_title( ch, "the newbie avatar" );
					}
				}
				else if (!IS_NPC(ch) && ch->pcdata->obj_vnum != 0)
				{
					if (ch->in_room != NULL) char_to_room( ch, ch->in_room );
					else char_to_room( ch, get_room_index( ROOM_VNUM_SCHOOL ) );
					bind_char(ch);
					break;
				}
				else if ( ch->in_room != NULL )
				{
					char_to_room( ch, ch->in_room );
					do_look( ch, "auto" );
				}
				else if ( IS_IMMORTAL(ch) )
				{
					char_to_room( ch, get_room_index( ROOM_VNUM_CHAT ) );
					do_look( ch, "auto" );
				}
				else
				{
					char_to_room( ch, get_room_index( ROOM_VNUM_TEMPLE ) );
					do_look( ch, "auto" );
				}

				if (!IS_IMMUNE(ch,IMM_VAMPIRE  ))  
					SET_BIT(ch->immune, IMM_VAMPIRE);
				if (!IS_IMMUNE(ch,IMM_WEREWOLF ))  
					SET_BIT(ch->immune, IMM_WEREWOLF);
				if (!IS_IMMUNE(ch,IMM_MAGE     ))  
					SET_BIT(ch->immune, IMM_MAGE   );

				/* Send MSP String if triggered */
				if ( IS_SET(ch->deaf, CHANNEL_MSP ))
				{
					int midnum;
					midnum = number_range( 0, MAX_MIDI );
					/*play Manson only one song for now.. */
					sprintf(buf,"\n\r!!MUSIC(%s T=music L=1 V=100 U=http://%s%s )\n\r",msp_midi_table[midnum].msp_string, msp_midi_table[midnum].msp_server, msp_midi_table[midnum].msp_dirinfo);
					write_to_buffer(d,buf,0);
				}
				//run check for followers
				if (IS_AVATAR(ch))
					ch->pcdata->followers = check_follower_count(ch);

				/* wwf char init */		
				if (IS_CLASS(ch,CLASS_SWWF))
					ch->pcdata->gnosis = (get_hours(ch) / 100);	
				act( "$n has entered the realm.", ch, NULL, NULL, TO_ROOM );
				do_board(ch, "");
				room_text(ch,">ENTER<");
				break;
	}
	
	mudsetting->last_proc_logged = 23;
	
	return;
}



/*
 * Parse a name for acceptability.
 */
bool check_parse_name( char *name )
{
    /*
     * Reserved words
     */
	/** traditional, and ex-Godwar names */
	if ( is_name( name," all auto immortal imm self someone gaia kavir rotain arkyn amoeba smokey admin guest user caine lilith abel absimilard veddartha zillah irad enoch haquim saulot ennoia arikel ashur sutekh troile camarilla sabbat inconnu assamite brujah cappadocian set gangrel lasombra malkav nosferatu ravnos toreador tremere tzimisce ventrue baali caitiff kaine cain kain followers set malkavian fianna fenris get silver fangs shadow lords bone gnawers ronin silverfang shadowlord bonegnawer akashic cult ecstasy cultecstasy cultofecstasy dreamspeakers order hermes orderhermes orderofhermes verbena sonsofether pheonix pheonixx phoenix strom maelstrom nimufu artemis jasmine belgerion blizzard loco unlinked" ) )
		return FALSE;
	
        // you would think this isn't necessary.... - dominion	
	if ( !str_suffix("Sux",name) || !str_suffix("Sucks",name)
		|| !str_prefix("Suck",name) || !str_prefix("Vamp",name)  
		|| !str_prefix("Shit",name) || !str_suffix("shit",name)
		|| !str_prefix("Ass",name)  || !str_suffix("ass",name)
		|| !str_prefix("Imp",name)  || !str_suffix("imp",name)
		|| !str_prefix("Impl",name) || !str_suffix("impl",name)
		|| !str_prefix("Girl",name) || !str_suffix("girl",name)
		|| !str_prefix("Boy",name)  || !str_suffix("boy",name)
		|| !str_suffix("man",name)  || !str_suffix("woman",name)
		|| !str_prefix("Fuck",name) || !str_suffix("fuck",name)
		|| !str_suffix("z",name)
		)
		return FALSE;               
	
	if ((str_cmp(capitalize(name),"Immortal"))
		&& (!str_suffix("Immortal",name) || !str_prefix("Imm",name)))
		return FALSE;
	
	if ((str_cmp(capitalize(name),"Caine"))
		&& (!str_suffix("Caine",name) || !str_prefix("Caine",name)))
		return FALSE;
	
	if ((str_cmp(capitalize(name),"Dominion"))
		&& (!str_suffix("Dominion",name) || !str_prefix("Dom",name)))
		return FALSE;
	
	if ((str_cmp(capitalize(name),"Jovie")) 
		&& (!str_suffix("Jovie",name)))
		return FALSE;
	
	if ((str_cmp(capitalize(name),"Spiral"))
		&& (!str_suffix("Spiral",name) || !str_prefix("Spiral",name)))  
		return FALSE;
	
	if ((str_cmp(capitalize(name),"Macabre"))
		&& (!str_suffix("Macabre",name) || !str_prefix("Macabre",name)))  
		return FALSE;
	
	if ((str_cmp(capitalize(name),"Viscera"))
		&& (!str_suffix("Viscera",name) || !str_prefix("Viscera",name)))  
		return FALSE;
	
    /*
     * Length restrictions.
     */
	if ( strlen(name) <  3 )
		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;
	}
	
    /*
     * 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;
	
	for ( ch = char_list; ch != NULL; ch = ch->next )
	{
		if ( !IS_NPC(ch) /*!IS_EXTRA(ch, EXTRA_SWITCH)*/
			&& ( !fConn || ch->desc == NULL )
			&&   !str_cmp( d->character->name->str, ch->name->str ) )
		{
			if ( fConn == FALSE )
			{
				d->character->pcdata->pwd = g_string_assign(d->character->pcdata->pwd, ch->pcdata->pwd->str );
			}
			else
			{
				free_char( d->character );
				d->character = ch;
				ch->desc	 = d;
				ch->timer	 = 0;
				send_to_char( "Reconnecting.\n\r", ch );
				if (IS_NPC(ch) || ch->pcdata->obj_vnum == 0)
					act( "$n has reconnected.", ch, NULL, NULL, TO_ROOM );
				sprintf( log_buf, "%s@%s reconnected.", ch->name->str, ch->lasthost->str );
				log_string2( log_buf );
				logchan(log_buf, NULL, NULL,WIZ_LINK,0, LEVEL_QUESTMAKER);
				d->connected = CON_PLAYING;
				//if (ch->pcdata->in_progress)
				//	free_note(ch->pcdata->in_progress);
			}
			return TRUE;
			mudsetting->last_proc_logged = 31;
	
		}
	}
	mudsetting->last_proc_logged = 32;
	
	return FALSE;
}

/*
 * Kick off old connection.  KaVir.
 */
bool check_kickoff( DESCRIPTOR_DATA *d, char *name, bool fConn )
{
	CHAR_DATA *ch;
	
	for ( ch = char_list; ch != NULL; ch = ch->next )
	{
		if ( !IS_NPC(ch)
			&& ( !fConn || ch->desc == NULL )
			&&   !str_cmp( d->character->name->str, ch->name->str ) )
		{
			if ( fConn == FALSE )
			{
				d->character->pcdata->pwd = g_string_assign(d->character->pcdata->pwd, ch->pcdata->pwd->str );
			}
			else
			{
				free_char( d->character );
				d->character = ch;
				ch->desc	 = d;
				ch->timer	 = 0;
				send_to_char( "You take over your body, which was already in use.\n\r", ch );
				act( "...$n's body has been taken over by another spirit!", ch, NULL, NULL, TO_ROOM );
				sprintf( log_buf, "%s@%s kicking off old link.", ch->name->str, ch->lasthost->str );
				log_string2( log_buf );
				logchan(log_buf, NULL, NULL,WIZ_LINK,0, LEVEL_QUESTMAKER);
				d->connected = CON_PLAYING;
				if (ch->pcdata->in_progress)
					send_to_char("You have a note in progress. Type NWRITE to continue it.\n\r",ch);
			}
			return TRUE;
			mudsetting->last_proc_logged = 33;
	
		}
	}
	mudsetting->last_proc_logged = 34;
	
	return FALSE;
}


bool check_player_ID( DESCRIPTOR_DATA *d, char *name, bool fConn )
{
	CHAR_DATA *ch;
	
	for ( ch = char_list; ch != NULL; ch = ch->next )
	{
		if ( !IS_NPC(ch)
			&& ( ch->id ==  d->character->id )
			&& ( !fConn || ch->desc == NULL )
			&&   !str_cmp( d->character->name->str, ch->name->str ) )
		{
			free_char( d->character );
			d->character = ch;
			ch->desc	 = d;
			ch->timer	 = 0;
			send_to_char( "You take over your body, which was already in use.\n\r", ch );
			act( "...$n's body has been taken over by another spirit!", ch, NULL, NULL, TO_ROOM );
			sprintf( log_buf, "%s@%s kicking off old ID.", ch->name->str, ch->lasthost->str );
			log_string2( log_buf );
			logchan(log_buf, NULL, NULL,WIZ_LINK,0, LEVEL_QUESTMAKER);
			d->connected = CON_PLAYING;
			if (ch->pcdata->in_progress)
				send_to_char("You have a note in progress. Type NWRITE to continue it.\n\r",ch);
		   mudsetting->last_proc_logged = 35;
			return TRUE;
		}
	}
	
	mudsetting->last_proc_logged = 36;
	return FALSE;
}

bool check_newbie_playing( DESCRIPTOR_DATA *d, char *name)
{
	DESCRIPTOR_DATA *dold;
	GSList	*desc_list;
	
	for ( desc_list = descriptor_list; desc_list != NULL; desc_list = g_slist_next(desc_list) )
	{
		dold = (DESCRIPTOR_DATA*)desc_list->data;
		if ( dold != d  && dold->character != NULL 
			&& !str_cmp( name, dold->original ? dold->original->name->str : dold->character->name->str ) )
			return TRUE;
	}
	return FALSE;
}

/*
 * Check if already playing - KaVir.
 * Using kickoff code from Malice, as mine is v. dodgy.
 */
bool check_playing( DESCRIPTOR_DATA *d, char *name )
{
	DESCRIPTOR_DATA *dold;
	GSList	*desc_list;
	
	for ( desc_list = descriptor_list; desc_list != NULL; desc_list = g_slist_next(desc_list) )
	{
		dold = (DESCRIPTOR_DATA*)desc_list->data;
		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->str : dold->character->name->str ) )
		{
			char	buf [MAX_STRING_LENGTH];
			if ( d->character != NULL )
			{
				free_char( d->character );
				d->character = NULL;
			}
			send_to_char("This body has been taken over!\n\r",dold->character);
			d->connected = dold->connected;
			d->character = dold->character;
			d->character->desc = d;
			send_to_char( "You take over your body, which was already in use.\n\r", d->character );
			act( "$n doubles over in agony and $s eyes roll up into $s head.", d->character, NULL, NULL, TO_ROOM );
			act( "...$n's body has been taken over by another spirit!", d->character, NULL, NULL, TO_ROOM );
			dold->character=NULL;
			
			sprintf(buf,"Kicking off old connection %s@%s",d->character->name->str,d->host->str);
			log_string2(buf);
			logchan(log_buf, NULL, NULL,WIZ_LINK,0, LEVEL_QUESTMAKER);
			close_socket(dold);	/* Slam the old connection into the ether */
			if (d->character->pcdata->in_progress)
				send_to_char("You have a note in progress. Type NWRITE to continue it.\n\r",d->character);
			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 Limbo.", 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;
}

/*
 * 
 * Romish page to char 
 * 
 * 
 */

void page_to_char(const char *txt, CHAR_DATA *ch )
{
	GString *buf;
	GString *output;
	int 	xloop;
	
	if(IS_NPC(ch))
        return;
    
	buf = g_string_new(txt);
	output = g_string_new("");

    	if( txt > 0 && ch->desc )
	{
		if( IS_SET( ch->act, PLR_ANSI ) )
		{
			for( xloop = 0; xloop < buf->len; xloop++ )
			{
				if( buf->str[xloop] == '{' )
				{
					if (IS_SWWF(ch) && IS_ADDED(ch,ADDED_FRENZY))
						frenzy_colour( buf->str[xloop], ch, output );
					else
						colour( buf->str[xloop], ch, output );
					continue;
				}
				output = g_string_append_c(output,buf->str[xloop]);
			}			
			ch->desc->showstr_head  = g_string_new(buf->str);
			ch->desc->showstr_head = g_string_assign( ch->desc->showstr_head, buf->str );
			ch->desc->showstr_point = g_strdup(ch->desc->showstr_head->str);
			show_string( ch->desc, "" );
			g_string_free(ch->desc->showstr_head,TRUE);
			g_free( ch->desc->showstr_point);
		}
		else
		{
			for( xloop = 0; xloop < buf->len; xloop++ )
			{
				if( buf->str[xloop] == '{' )
					continue;

				output = g_string_append_c(output,buf->str[xloop]);
			}
			ch->desc->showstr_head  = g_string_new(buf->str);
			ch->desc->showstr_head = g_string_assign( ch->desc->showstr_head, buf->str );
			ch->desc->showstr_point = g_strdup(ch->desc->showstr_head->str);
			show_string( ch->desc, "" );
			g_string_free(ch->desc->showstr_head,TRUE);
			g_free( ch->desc->showstr_point);
		}
	}
	g_string_free(buf,TRUE);
	g_string_free(output,TRUE);
	return;
}


/* string pager */
void show_string(struct descriptor_data *d, char *input)
{
	char buffer[4*MAX_STRING_LENGTH];
	char buf[MAX_INPUT_LENGTH];
	register char *scan, *chk;
	int lines = 0, toggle = 1;
	int show_lines;
	
	one_argument(input,buf);
	if (buf[0] != '\0')
	{
		if (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)
					{
						d->showstr_head = 0;
					}
					d->showstr_point  = 0;
				}
			}
			return;
		}
	}
	return;
}



/*
 * The primary output interface for MSP sound output.

void sound(char *sound_name, int volume, int loop, int priority, char *sound_type, CHAR_DATA *ch, CHAR_DATA *victim, int type)
{

    char buf      [MAX_STRING_LENGTH];

    sprintf(buf, "!!SOUND(%s V=%d L=%d P=%d T=%s U=%s/%s/%s)",
                  sound_name, volume, loop, priority, sound_type, MSP_URL, sound_type, sound_name)
}
*/

// a little something something from Smaug! - Spiral
void ch_printf(CHAR_DATA *ch, char *fmt, ...)
{
    char buf[MAX_STRING_LENGTH];	/* better safe than sorry */
    va_list args;

    va_start(args, fmt);
    vsprintf(buf, fmt, args);
    va_end(args);
	
    send_to_char(buf, ch);
}

void  mxpconv(GString *output, const char *txt, CHAR_DATA *ch )
{
	GString *buffer;
	int x;
	bool fFound = FALSE;
	//int buf_count = 0;

	if( ch->desc && txt )
	{
		if( !IS_SET(ch->deaf, CHANNEL_MXP ) )
		{
			buffer = g_string_new(txt);
			for( x = 0; x < buffer->len; x++ )
			{
				if( buffer->str[x] == '<' )
					fFound = TRUE;
				if( buffer->str[x] == '>' && fFound == TRUE )
				{
					x++;
					fFound = FALSE;
				}
				if (fFound)
					continue;

				g_string_append_c(output, buffer->str[x]);
			}			
			g_string_append_c(output,'\0');
			g_string_free(buffer,TRUE);
		}
		else
			g_string_sprintf(output,"\033[1z%s",txt);
	}
	return;
}



void frenzy_colour( char type, CHAR_DATA *ch, GString *string )
{
	char	code[ 20 ];
	
	if( IS_NPC( ch ) )
		return;
	
	switch( type )
	{
		default:
			sprintf( code, CLEAR );
			break;
		case 'x':
			sprintf( code, C_B_RED );
			break;
		case 'b':
			sprintf( code, C_B_RED );
			break;
		case 'c':
			sprintf( code, C_B_RED );
			break;
		case 'g':
			sprintf( code, C_B_RED );
			break;
		case 'm':
			sprintf( code, C_B_RED );
			break;
		case 'r':
			sprintf( code, C_B_RED );
			break;
		case 'w':
			sprintf( code, C_B_RED );
			break;
		case 'y':
			sprintf( code, C_B_RED );
			break;
		case 'B':
			sprintf( code, C_B_RED );
			break;
		case 'C':
			sprintf( code, C_B_RED );
			break;
		case 'G':
			sprintf( code, C_B_RED );
			break;
		case 'M':
			sprintf( code, C_B_RED );
			break;
		case 'R':
			sprintf( code, C_B_RED );
			break;
		case 'W':
			sprintf( code, C_B_RED );
			break;
		case 'Y':
			sprintf( code, C_B_RED );
			break;
		case 'D':
			sprintf( code, C_B_RED );
			break;
		case '\242':
			sprintf( code, BLINK );
			break;
		case '{':
			sprintf( code, "%c", '{' );
			break;
	}
	
	string = g_string_append(string,code);	
	return;
}


void colour( char type, CHAR_DATA *ch, GString *output )
{
	char	code[ 20 ];
	
	if( IS_NPC( ch ) )
		return;
	
	if (type == '\0'){
		return;
	}

	switch( type )
	{
		default:
			sprintf( code, CLEAR );
			break;
		case 'x':
			sprintf( code, CLEAR );
			break;
		case 'b':
			sprintf( code, C_BLUE );
			break;
		case 'c':
			sprintf( code, C_CYAN );
			break;
		case 'g':
			sprintf( code, C_GREEN );
			break;
		case 'm':
			sprintf( code, C_MAGENTA );
			break;
		case 'r':
			sprintf( code, C_RED );
			break;
		case 'w':
			sprintf( code, C_WHITE );
			break;
		case 'y':
			sprintf( code, C_YELLOW );
			break;
		case 'B':
			sprintf( code, C_B_BLUE );
			break;
		case 'C':
			sprintf( code, C_B_CYAN );
			break;
		case 'G':
			sprintf( code, C_B_GREEN );
			break;
		case 'M':
			sprintf( code, C_B_MAGENTA );
			break;
		case 'R':
			sprintf( code, C_B_RED );
			break;
		case 'W':
			sprintf( code, C_B_WHITE );
			break;
		case 'Y':
			sprintf( code, C_B_YELLOW );
			break;
		case 'D':
			sprintf( code, C_D_GREY );
			break;
		case '\242':
			sprintf( code, BLINK );
			break;
		case '{':
			sprintf( code, "%c", '{' );
			break;
	}
	
	g_string_append(output,code);
	
	return;
}

void colourconv( GString *output, GString *txt, CHAR_DATA *ch )
{
	int	xloop;
	
	if( ch->desc && txt )
	{
		if( IS_SET( ch->act, PLR_ANSI ) )
		{
			for( xloop = 0; xloop < txt->len; xloop++ )
			{
				if( txt->str[xloop] == '{' )
				{
					xloop++;
					if (IS_SWWF(ch) && IS_ADDED(ch,ADDED_FRENZY))
						frenzy_colour( txt->str[xloop], ch, output );
					else	
						colour( txt->str[xloop], ch, output );
					continue;
				}
				output = g_string_append_c(output,txt->str[xloop]);
			}			
		}
		else
		{
			for( xloop=0; xloop < txt->len; xloop++ )
			{
				if( txt->str[xloop] == '{' )
				{
					xloop++;
					continue;
				}
				g_string_append_c(output, txt->str[xloop]);
			}
		}
	}
	return;
}
/*
 * The primary output interface for formatted output.
 */
void act( const char *format, CHAR_DATA *ch, const void *arg1, const void *arg2, int type )
{
	static char * const he_she	[] = { "it",  "he",  "she" };
	static char * const him_her	[] = { "it",  "him", "her" };
	static char * const his_her	[] = { "its", "his", "her" };
		
	GString *buf;
	GString *mxpbuf;
	char fname    [MAX_INPUT_LENGTH];
	CHAR_DATA     *to;
    CHAR_DATA *to_old;
	CHAR_DATA     *vch = (CHAR_DATA *) arg2;
    CHAR_DATA *familiar = NULL;
    CHAR_DATA *wizard = NULL;

	OBJ_DATA      *obj1 = (OBJ_DATA  *) arg1;
	OBJ_DATA      *obj2 = (OBJ_DATA  *) arg2;
	OBJ_DATA      *to_obj;
	const char    *str;
	gchar         *i;
	GString          *pbuff;
	GString          *buffer;
	bool          fColour = FALSE;
    bool is_fam;
	bool is_ok;
    /*
     * Discard null and zero-length messages.
     */
	
	buf = g_string_new("");
	if ( format == NULL || format[0] == '\0' )
		return;
	
	if (ch == NULL || ch->in_room == NULL )
		return;
	
	to = ch->in_room->people;
	if ( type == TO_VICT )
	{
		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 )
	{

		buf = g_string_assign(buf,"");

		is_fam = FALSE;
		to_old = to;

		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;
		if ( type == TO_NOTVICTBR && (IS_SET(to->act, PLR_BRIEF) || (to == ch || to == vch))) continue;
		
		if ( to->desc == NULL && IS_NPC(to) && (wizard = to->wizard) != NULL )
		{
	    	if (!IS_NPC(wizard) && ((familiar=wizard->pcdata->familiar) != NULL)
			&& familiar == to)
	    	{
				if (to->in_room == ch->in_room && 
		    		wizard->in_room != to->in_room)
				{
		    		to = wizard;
		    		is_fam = TRUE;
				}
	    	}
		}

		if ( to->desc == NULL || !IS_AWAKE(to) )
		{
	    	if (is_fam) 
	    		to = to_old;
	    	continue;
		}
		
		if (ch->in_room->vnum == ROOM_VNUM_IN_OBJECT)
		{
			is_ok = FALSE;
			
			if (!IS_NPC(ch) && ch->pcdata->chobj != NULL && 
				ch->pcdata->chobj->in_room != NULL &&
				!IS_NPC(to) && to->pcdata->chobj != NULL && 
				to->pcdata->chobj->in_room != NULL &&
				ch->in_room == to->in_room)
				is_ok = TRUE; else is_ok = FALSE;
			
			if (!IS_NPC(ch) && ch->pcdata->chobj != NULL && 
				ch->pcdata->chobj->in_obj != NULL &&
				!IS_NPC(to) && to->pcdata->chobj != NULL && 
				to->pcdata->chobj->in_obj != NULL &&
				ch->pcdata->chobj->in_obj == to->pcdata->chobj->in_obj)
				is_ok = TRUE; else is_ok = FALSE;

			if (!is_ok)
				continue;
		}
		
		str	= format;
		while ( *str != '\0' )
		{
			if ( *str != '$' )
			{
				buf = g_string_append_c(buf,*str);
				++str;
				continue;
			}
			fColour = TRUE;
			++str;
			
			if ( arg2 == NULL && *str >= 'A' && *str <= 'Z' )
			{
				bug( "Act: missing arg2 for code %d.", *str );
				i = g_strdup(" <@@@> ");
			}
			else
			{
				switch ( *str )
				{
					default:  bug( "Act: bad code %d.", *str );
						i = g_strdup(" <@@@> ");				break;
		/* Thx alex for 't' idea */
					case 't': i = (gchar*)g_strdup((gchar*)arg1);				break;
					case 'T': i = (gchar*)g_strdup((gchar*)arg2);          			break;
					case 'X': 
						  mxpbuf = g_string_new("");
						  mxpconv(mxpbuf,(char *) arg2,to);
						  i = g_strdup(mxpbuf->str);
						  g_string_free(mxpbuf,TRUE);
						  break;

					case 'n': i = g_strdup(PERS( ch,  to  ));				break;
					case 'N': i = g_strdup(PERS( vch, to  ));				break;
					case 'e': i = g_strdup(he_she  [URANGE(0, ch  ->sex, 2)]);	break;
					case 'E': i = g_strdup(he_she  [URANGE(0, vch ->sex, 2)]);	break;
					case 'm': i = g_strdup(him_her [URANGE(0, ch  ->sex, 2)]);	break;
					case 'M': i = g_strdup(him_her [URANGE(0, vch ->sex, 2)]);	break;
					case 's': i = g_strdup(his_her [URANGE(0, ch  ->sex, 2)]);	break;
					case 'S': i = g_strdup(his_her [URANGE(0, vch ->sex, 2)]);	break;
						
					case 'p':
						i = can_see_obj( to, obj1 )
							? ( (obj1->chobj != NULL && obj1->chobj == to)
								? g_strdup("you") : g_strdup(obj1->short_descr->str))
							: g_strdup("something");
						break;
						
					case 'P':
						i = can_see_obj( to, obj2 )
							? ( (obj2->chobj != NULL && obj2->chobj == to)
								? g_strdup("you") : g_strdup(obj2->short_descr->str))
							: g_strdup("something");
						break;
						
					case 'd':
						if ( arg2 == NULL || ((char *) arg2)[0] == '\0' )
						{
							i = g_strdup("door");
						}
						else
						{
							one_argument( (char *) arg2, fname );
							i = g_strdup(fname);
						}
						break;
				}
			}

			++str;
			buf = g_string_append(buf,i);
			g_free(i);
		}
		buf = g_string_append(buf,"\n\r\0");
 
		pbuff = g_string_new("");
		buffer = g_string_new(buf->str);
		colourconv( pbuff, buffer, to);

		if ( to->desc != NULL )
		{
			if (is_fam)
			{
	    		if (to->in_room != ch->in_room && 
					familiar != NULL && familiar->in_room == ch->in_room)
					send_to_char("[ ", to);
	    		else
	    		{
					to = to_old;
					continue;
	    		}
			}
			
			write_to_buffer( to->desc, pbuff->str, 0);
				
		}
		else
		{
			if (IS_NPC(to))
			{
				if ( MOBtrigger )
					mp_act_trigger( buf->str, to, ch, arg1, arg2, TRIG_ACT );
			}
		}
		g_string_free(pbuff,TRUE);	
		g_string_free(buffer,TRUE);	
		if ( HAS_PROG(to->in_room, TRIG_ACT) )
        	rprog_act_trigger(buf->str, to->in_room, ch, (OBJ_DATA *)arg1, (void *)arg2, TRIG_ACT);
      	
      	for ( to_obj = to->in_room->contents; to_obj;	to_obj = to_obj->next_content )
       	{
			if ( HAS_PROG(to_obj->pIndexData, TRIG_ACT) )
        	 	oprog_act_trigger(buf->str, to_obj, ch, (OBJ_DATA *)arg1, (void *)arg2, TRIG_ACT);
    	}
		
		if (is_fam)
			to = to_old;
		
			
	}	
	g_string_free(buf,TRUE);
	return;
}

void act2( const char *format, CHAR_DATA *ch, const void *arg1, const void *arg2, int type )
{
	static char * const he_she	[] = { "it",  "he",  "she" };
	static char * const him_her	[] = { "it",  "him", "her" };
	static char * const his_her	[] = { "its", "his", "her" };
	
	OBJ_DATA      *to_obj;
	
	char buf[MAX_STRING_LENGTH];
	CHAR_DATA *to;
    CHAR_DATA *to_old;
	CHAR_DATA *vch = (CHAR_DATA *) arg2;

    CHAR_DATA *familiar = NULL;
    CHAR_DATA *wizard = NULL;

	OBJ_DATA *obj1 = (OBJ_DATA  *) arg1;
	OBJ_DATA *obj2 = (OBJ_DATA  *) arg2;
	const char *str;
	const char *i = NULL;
	char *point;
	GString *pbuff;
	GString *buffer;
	bool fColour = FALSE;

    bool is_fam;
	bool is_ok;
    /*
     * Discard null and zero-length messages.
     */
	if ( format == NULL || format[0] == '\0' )
		return;
	
	to = ch->in_room->people;

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

	for ( ; to != NULL; to = to->next_in_room )
	{

		is_fam = FALSE;
		to_old = to;

		/*
		if ( (!IS_NPC(to) && to->desc == NULL )
			||   ( IS_NPC(to) && !HAS_TRIGGER(to, TRIG_ACT) ))
			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;

		if ( to->desc == NULL && IS_NPC(to) && (wizard = to->wizard) != NULL )
		{
	    	if (!IS_NPC(wizard) && ((familiar=wizard->pcdata->familiar) != NULL)
			&& familiar == to)
	    	{
				if (to->in_room == ch->in_room && 
		    		wizard->in_room != to->in_room)
				{
		    		to = wizard;
		    		is_fam = TRUE;
				}
	    	}
		}



		if ( to->desc == NULL || !IS_AWAKE(to) )
		{
	    	if (is_fam) 
	    		to = to_old;
	    	continue;
		}
		
		if (ch->in_room->vnum == ROOM_VNUM_IN_OBJECT)
		{
			is_ok = FALSE;
			
			if (!IS_NPC(ch) && ch->pcdata->chobj != NULL && 
				ch->pcdata->chobj->in_room != NULL &&
				!IS_NPC(to) && to->pcdata->chobj != NULL && 
				to->pcdata->chobj->in_room != NULL &&
				ch->in_room == to->in_room)
				is_ok = TRUE; else is_ok = FALSE;
			
			if (!IS_NPC(ch) && ch->pcdata->chobj != NULL && 
				ch->pcdata->chobj->in_obj != NULL &&
				!IS_NPC(to) && to->pcdata->chobj != NULL && 
				to->pcdata->chobj->in_obj != NULL &&
				ch->pcdata->chobj->in_obj == to->pcdata->chobj->in_obj)
				is_ok = TRUE; else is_ok = FALSE;

			if (!is_ok)
			{
/*
		if (is_fam) to = to_old;
*/
				continue;
			}
		}
		
		point	= buf;
		str	= format;
		while ( *str != '\0' )
		{
			if ( *str != '$' )
			{
				*point++ = *str++;
				continue;
			}
			fColour = TRUE;
			++str;
			
			if ( arg2 == NULL && *str >= 'A' && *str <= 'Z' )
			{
/*
		bug( "Act: missing arg2 for code %d.", *str );
*/
				i = " <@@@> ";
			}
			else
			{
				switch ( *str )
				{
					default:  i = " "; break;
					case 'n': if ( ch != NULL ) i = PERS( ch,  to  );
						else i = " ";
						break;
					case 'N': if ( vch != NULL ) i = PERS( vch,  to  );
						else i = " ";
						break;
					case 'e': if ( ch != NULL ) i=he_she  [URANGE(0, ch  ->sex, 2)];
						else i = " ";
						break;
					case 'E': if (vch != NULL ) i=he_she  [URANGE(0, vch  ->sex,2)];
						else i = " ";
						break;
					case 'm': if ( ch != NULL ) i=him_her [URANGE(0, ch  ->sex, 2)];
						else i = " ";
						break;
					case 'M': if (vch != NULL ) i=him_her [URANGE(0, vch  ->sex,2)];
						else i = " ";
						break;
					case 's': if ( ch != NULL ) i=his_her [URANGE(0, ch  ->sex, 2)];
						else i = " ";
						break;
					case 'S': if (vch != NULL ) i=his_her [URANGE(0, vch  ->sex,2)];
						else i = " ";
						break;
					case 'p':
						if (obj1 != NULL)
						{
							i = can_see_obj( to, obj1 )
								? ( (obj1->chobj != NULL && obj1->chobj == to)
									? "you" : obj1->short_descr->str)
								: "something";
						}
						else i = " ";
						break;
						
					case 'P':
						if (obj2 != NULL)
						{
							i = can_see_obj( to, obj2 )
								? ( (obj2->chobj != NULL && obj2->chobj == to)
									? "you" : obj2->short_descr->str)
								: "something";
						}
						else i = " ";
						break;
				}
			}
			
			++str;
			while ( ( *point = *i ) != '\0' )
				++point, ++i;
		}
		
		*point++ = '\n';
		*point++ = '\r';
		*point   = '\0';

		pbuff = g_string_new("");
		buffer = g_string_new(buf);

		colourconv( pbuff, buffer, to );

		if ( to->desc != NULL )
		{
			if (is_fam)
			{
	    		if (to->in_room != ch->in_room && 
				familiar != NULL && familiar->in_room == ch->in_room)
				send_to_char("[ ", to);
	    	else
	    	{
				to = to_old;
				continue;
	    	}
		}
			write_to_buffer( to->desc, pbuff->str, 0);
		}
		else
		{
			if (IS_NPC(to))
			{
				if ( MOBtrigger )
					mp_act_trigger( buf, to, ch, arg1, arg2, TRIG_ACT );
			}	
		}
		g_string_free(pbuff,TRUE);
		g_string_free(buffer,TRUE);
		if ( HAS_PROG(to->in_room, TRIG_ACT) )
        	rprog_act_trigger(buf, to->in_room, ch, (OBJ_DATA *)arg1, (void *)arg2, TRIG_ACT);
      	
      	for ( to_obj = to->in_room->contents; to_obj;	to_obj = to_obj->next_content )
       	{
			if ( HAS_PROG(to_obj->pIndexData, TRIG_ACT) )
        	 	oprog_act_trigger(buf, to_obj, ch, (OBJ_DATA *)arg1, (void *)arg2, TRIG_ACT);
    	}
		if (is_fam)
			to = to_old;
		 
		
	}
	return;
}



void kavitem( const char *format, CHAR_DATA *ch, const void *arg1, const void *arg2, int type )
{
	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 kav[MAX_INPUT_LENGTH];
	CHAR_DATA *to;
	CHAR_DATA *vch = (CHAR_DATA *) arg2;
	OBJ_DATA *obj1 = (OBJ_DATA  *) arg1;
	const char *str;
	const char *i = NULL;
	char *point;
	GString *pbuff;
	GString *buffer;
	bool fColour = FALSE;
	bool is_ok;
	
    /*
     * Discard null and zero-length messages.
     */
	if ( format == NULL || format[0] == '\0' )
		return;
	
	to = ch->in_room->people;
	if ( type == TO_VICT )
	{
		if ( vch == NULL )
		{
			bug( "Act: null vch with TO_VICT.", 0 );
			return;
		}
		to = vch->in_room->people;
	}
	
	for ( ; to != NULL; to = to->next_in_room )
	{
		if ( to->desc == NULL || !IS_AWAKE(to) )
			continue;
		
		if (ch->in_room->vnum == ROOM_VNUM_IN_OBJECT)
		{
			is_ok = FALSE;
			
			if (!IS_NPC(ch) && ch->pcdata->chobj != NULL && 
				ch->pcdata->chobj->in_room != NULL &&
				!IS_NPC(to) && to->pcdata->chobj != NULL && 
				to->pcdata->chobj->in_room != NULL &&
				ch->in_room == to->in_room)
				is_ok = TRUE; else is_ok = FALSE;
			
			if (!IS_NPC(ch) && ch->pcdata->chobj != NULL && 
				ch->pcdata->chobj->in_obj != NULL &&
				!IS_NPC(to) && to->pcdata->chobj != NULL && 
				to->pcdata->chobj->in_obj != NULL &&
				ch->pcdata->chobj->in_obj == to->pcdata->chobj->in_obj)
				is_ok = TRUE; else is_ok = FALSE;
			
			if (!is_ok) 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;
			
			if ( arg2 == NULL && *str >= 'A' && *str <= 'Z' )
				i = "";
			else
			{
				switch ( *str )
				{
					default:  i = "";					break;
					case 'n': i = PERS( ch,  to  );				break;
					case 'e': i = he_she  [URANGE(0, ch  ->sex, 2)];	break;
					case 'm': i = him_her [URANGE(0, ch  ->sex, 2)];	break;
					case 's': i = his_her [URANGE(0, ch  ->sex, 2)];	break;
					case 'p':
						i = can_see_obj( to, obj1 )
							? ( (obj1->chobj != NULL && obj1->chobj == to)
								? "you" : obj1->short_descr->str)
							: "something";
						break;
						
					case 'o':
						if (obj1 != NULL) sprintf(kav,"%s's",obj1->short_descr->str);
						i = can_see_obj( to, obj1 )
							? ( (obj1->chobj != NULL && obj1->chobj == to)
								? "your" : kav)
							: "something's";
						break;
						
				}
			}
			
			++str;
			while ( ( *point = *i ) != '\0' )
				++point, ++i;
		}
		
		*point++ = '\n';
		*point++ = '\r';
		*point   = '\0';
		pbuff = g_string_new("");
		buffer = g_string_new(buf);
		colourconv( pbuff, buffer, to );
		write_to_buffer( to->desc, pbuff->str, 0 );
		g_string_free(pbuff,TRUE);
		g_string_free(buffer,TRUE);
	}
	
	return;
}

void bust_a_prompt( DESCRIPTOR_DATA *d )
{
	CHAR_DATA *ch;
	CHAR_DATA *victim;
	CHAR_DATA *tank;
	GString   *str;
	GString   *i;
	char      *strtime;
	int xloop;
	GString   *buf;
	GString   *buf2;
	bool      is_fighting = TRUE;
	
	if ( ( ch = d->character ) == NULL ) return;
	if ( ch->pcdata == NULL )
	{
		send_to_char( "\n\r\n\r", ch );
		return;
	}
	if ( ch->position == POS_FIGHTING && ch->cprompt->str[0] == '\0' )
	{
		if ( ch->prompt->str[0] == '\0' )
		{
			send_to_char( "\n\r\n\r", ch );
			return;
		}
		is_fighting = FALSE;
	}
	else if ( ch->position != POS_FIGHTING && ch->prompt->str[0] == '\0' )
	{
		send_to_char( "\n\r\n\r", ch );
		return;
	}
	
	if ( ch->position == POS_FIGHTING && is_fighting )
		if (d->original)
			str = g_string_new(d->original->cprompt->str); 
		else
			str = g_string_new(d->character->cprompt->str);
	else
		if (d->original)
			str = g_string_new(d->original->prompt->str);
		else
			str = g_string_new(d->character->prompt->str);

	buf = g_string_new("");
	buf2 = g_string_new("");
	i = g_string_new("");

	for( xloop = 0; xloop < str->len; xloop++ )
	{
		if( str->str[xloop] != '%' )
		{
			buf = g_string_append_c(buf,str->str[xloop]);	
			continue;
		}
		xloop++;
		switch( str->str[xloop] )
		{
			default :
				i = g_string_assign(i," "); break;
			case 'h' :
				g_string_sprintf( buf2, "%d", ch->hit );
				COL_SCALE(buf2, ch, ch->hit, ch->max_hit);
				i = g_string_assign(i,buf2->str); break;
			case 'H' :
				g_string_sprintf( buf2, "{C%d{x", ch->max_hit );
				i = g_string_assign(i,buf2->str); break;
			case 'm' :
				g_string_sprintf( buf2, "%d", ch->mana             );
				COL_SCALE(buf2, ch, ch->mana, ch->max_mana);
				i = g_string_assign(i,buf2->str); break;
			case 'M' :
				g_string_sprintf( buf2, "{C%d{x", ch->max_mana         );
				i = g_string_assign(i,buf2->str); break;

			case 'i' :
				if (IS_SET(ch->act,PLR_WIZINVIS)) 
				{
					g_string_sprintf( buf2, "%d", ch->invis_level) ;
				}
				else
					g_string_sprintf(buf2,"0");

				i = g_string_assign(i,buf2->str); break;

			case 'I' :
				if (IS_SET(ch->act,PLR_INCOG)) 
					g_string_sprintf(buf2,"Y");
				else
					g_string_sprintf(buf2,"N");
				i = g_string_assign(i,buf2->str); break;

			case 'v' :
				g_string_sprintf( buf2, "%d", ch->move             ); 
				COL_SCALE(buf2, ch, ch->move, ch->max_move);
				i = g_string_assign(i,buf2->str); break;
			case 'V' :
				g_string_sprintf( buf2, "{C%d{x", ch->max_move         );
				i = g_string_assign(i,buf2->str); break;
			case 'D' :
				if (time_info.hour > 6 && time_info.hour < 18)
				{
					buf2 = g_string_assign(buf2,"None");
				}
				else
				{
					switch (weather_info[ch->in_room->sector_type].moon)
					{
						default:
							buf2 = g_string_assign(buf2,"None");
							break;
						case MOON_FULL:
							buf2 = g_string_assign(buf2,"Full");
							break;
						case MOON_NEW:
							buf2 = g_string_assign(buf2,"New");
							break;
						case MOON_1_QUART:
							buf2 = g_string_assign(buf2,"1st");
							break;
						case MOON_LAST_QUART:
							buf2 = g_string_assign(buf2,"Last");
							break;
					}
				}
				i = g_string_assign(i,buf2->str);
				break;
			case 't' :
				strtime                    = ctime( &current_time );
				strtime[strlen(strtime)-1] = '\0';
				g_string_sprintf( buf2, "%s", strtime         );
				ADD_COLOUR(ch, buf2, L_CYAN);
				i = g_string_assign(i,buf2->str); break;
			case 'T' :
				g_string_sprintf( buf2, "%d:%s %s", time_info.hour,(time_info.half_hour == 30 ? "30" : "00"),         
						time_info.hour >= 12 ? "pm" : "am");
				ADD_COLOUR(ch, buf2, L_CYAN);
				i = g_string_assign(i,buf2->str); break;
			case 'x' :
				g_string_sprintf( buf2, "%d", ch->exp              );
				COL_SCALE(buf2, ch, ch->exp, 1000);
				i = g_string_assign(i,buf2->str); break;
			case 'g' :
				g_string_sprintf( buf2, "%d", ch->gold             );
				ADD_COLOUR(ch, buf2, L_CYAN);
				i = g_string_assign(i,buf2->str); break;
			case 'q' :
				g_string_sprintf( buf2, "%d", ch->pcdata->quest    );
				ADD_COLOUR(ch, buf2, L_CYAN);
				i = g_string_assign(i,buf2->str); break;
			case 'f' :
				if ( ( victim = ch->fighting ) == NULL )
				{
					buf2 = g_string_assign( buf2, "N/A" );
					ADD_COLOUR(ch, buf2, L_CYAN);
				}
				else
				{
					if ((victim->hit*100/victim->max_hit) < 17)
					{
						buf2 = g_string_assign(buf2, "Crippled");
						ADD_COLOUR(ch, buf2, L_RED);}
					else if ((victim->hit*100/victim->max_hit) < 34)
					{
						buf2 = g_string_assign(buf2, "Mauled");ADD_COLOUR(ch, buf2, L_RED);}
					else if ((victim->hit*100/victim->max_hit) < 51)
					{
						buf2 = g_string_assign(buf2, "Wounded");ADD_COLOUR(ch, buf2, L_BLUE);}
					else if ((victim->hit*100/victim->max_hit) < 68)
					{
						buf2 = g_string_assign(buf2, "Injured");ADD_COLOUR(ch, buf2, L_GREEN);}
					else if ((victim->hit*100/victim->max_hit) < 85)
					{
						buf2 = g_string_assign(buf2, "Hurt");ADD_COLOUR(ch, buf2, YELLOW);}
					else if ((victim->hit*100/victim->max_hit) < 100)
					{
						buf2 = g_string_assign(buf2, "Bruised");ADD_COLOUR(ch, buf2, YELLOW);}
					else if ((victim->hit*100/victim->max_hit) >= 100)
					{
						buf2 = g_string_assign(buf2, "Perfect");ADD_COLOUR(ch, buf2, L_CYAN);}
				}
				i = g_string_assign(i,buf2->str); break;
			case 'F' :
				if ( ( victim = ch->fighting ) == NULL )
				{
					buf2 = g_string_assign( buf2, "N/A" );
					ADD_COLOUR(ch, buf2, L_CYAN);
				}
				else if ( ( tank = victim->fighting ) == NULL )
				{
					buf2 = g_string_assign( buf2, "N/A" );
					ADD_COLOUR(ch, buf2, L_CYAN);
				}
				else
				{
					if ((tank->hit*100/tank->max_hit) < 17)
					{buf2 = g_string_assign(buf2, "Crippled");ADD_COLOUR(ch, buf2, L_RED);}
					else if ((tank->hit*100/tank->max_hit) < 34)
					{buf2 = g_string_assign(buf2, "Mauled");ADD_COLOUR(ch, buf2, L_RED);}
					else if ((tank->hit*100/tank->max_hit) < 51)
					{buf2 = g_string_assign(buf2, "Wounded");ADD_COLOUR(ch, buf2, L_BLUE);}
					else if ((tank->hit*100/tank->max_hit) < 68)
					{buf2 = g_string_assign(buf2, "Injured");ADD_COLOUR(ch, buf2, L_GREEN);}
					else if ((tank->hit*100/tank->max_hit) < 85)
					{buf2 = g_string_assign(buf2, "Hurt");ADD_COLOUR(ch, buf2, YELLOW);}
					else if ((tank->hit*100/tank->max_hit) < 100)
					{buf2 = g_string_assign(buf2, "Bruised");ADD_COLOUR(ch, buf2, YELLOW);}
					else if ((tank->hit*100/tank->max_hit) >= 100)
					{buf2 = g_string_assign(buf2, "Perfect");ADD_COLOUR(ch, buf2, L_CYAN);}
				}
				i = g_string_assign(i,buf2->str); break;
			case 'n' :
				if ( ( victim = ch->fighting ) == NULL )
					buf2 = g_string_assign( buf2, "N/A" );
				else
				{
					if ( IS_AFFECTED(victim, AFF_POLYMORPH) )
						buf2 = g_string_assign(buf2, victim->morph->str);
					else if ( IS_NPC(victim) )
						buf2 = g_string_assign(buf2, victim->short_descr->str);
					else
						buf2 = g_string_assign(buf2, victim->name->str);
					buf2->str[0] = UPPER(buf2->str[0]);
				}
				i = g_string_assign(i,buf2->str); break;
			case 'N' :
				if ( ( victim = ch->fighting ) == NULL )
					buf2 = g_string_assign( buf2, "N/A" );
				else if ( ( tank = victim->fighting ) == NULL )
					buf2 = g_string_assign( buf2, "N/A" );
				else
				{
					if ( ch == tank )
						buf2 = g_string_assign(buf2, "You");
					else if ( IS_AFFECTED(tank, AFF_POLYMORPH) )
						buf2 = g_string_assign(buf2, tank->morph->str);
					else if ( IS_NPC(victim) )
						buf2 = g_string_assign(buf2, tank->short_descr->str);
					else
						buf2 = g_string_assign(buf2, tank->name->str);
					buf2->str[0] = UPPER(buf2->str[0]);
				}
				i = g_string_assign(i,buf2->str); break;
			case 'a' :
				g_string_sprintf( buf2, "%s", IS_GOOD( ch ) ? "good"
						: IS_EVIL( ch ) ? "evil" : "neutral" );
				ADD_COLOUR(ch, buf2, L_CYAN);
				i = g_string_assign(i,buf2->str); break;
			case 'A' :
				g_string_sprintf( buf2, "%d", ch->alignment        );
				ADD_COLOUR(ch, buf2, L_CYAN);
				i = g_string_assign(i,buf2->str); break;
			case 'r' :
				if( ch->in_room )
					g_string_sprintf( buf2, "%s", ch->in_room->name  );
				else
					g_string_sprintf( buf2, " "                      );
				ADD_COLOUR(ch, buf2, L_CYAN);
				i = g_string_assign(i,buf2->str); break;
			case 'R' :
				if (!IS_NPC(ch) && (IS_CLASS(ch, CLASS_WEREWOLF) || IS_CLASS(ch, CLASS_VAMPIRE)))
				{
					g_string_sprintf( buf2, "%d", ch->pcdata->stats[UNI_RAGE]);
					ADD_COLOUR(ch, buf2, D_RED);
				}
				else if (!IS_NPC(ch) && IS_SWWF(ch))
				{
					g_string_sprintf( buf2, "%d", ch->pcdata->rage_points);
					ADD_COLOUR(ch, buf2, D_RED);
				}
				else buf2 = g_string_assign( buf2, "0" );
				i = g_string_assign(i,buf2->str); break;
			case 'b' :
				g_string_sprintf( buf2, "%d", ch->beast );
				ADD_COLOUR(ch, buf2, L_CYAN);
				i = g_string_assign(i,buf2->str); break;
			case 'B' :
				if (!IS_NPC(ch) && IS_CLASS(ch, CLASS_VAMPIRE))
				{
					g_string_sprintf( buf2, "%d", ch->pcdata->condition[COND_THIRST] );
					ADD_COLOUR(ch, buf2, D_RED);
				}
				else buf2 = g_string_assign( buf2, "0" );
				i = g_string_assign(i,buf2->str); break;
			case 'c' :
				g_string_sprintf( buf2, "%d", char_ac(ch) );
				i = g_string_assign(i,buf2->str); break;
			case 'C' :
				g_string_sprintf( buf2, "%d", ch->paradox[0]);
				i = g_string_assign(i,buf2->str); break;
			case 'p' :
				g_string_sprintf( buf2, "%d", char_hitroll(ch) );
				COL_SCALE(buf2, ch, char_hitroll(ch), 200);
				i = g_string_assign(i,buf2->str); break;
			case 'P' :
				g_string_sprintf( buf2, "%d", char_damroll(ch) );
				COL_SCALE(buf2, ch, char_damroll(ch), 200);
				i = g_string_assign(i,buf2->str); break;
			case 's' :
				if (ch->race <= 0 ) buf2 = g_string_assign(buf2,"Avatar");
				else if (ch->race <= 4 ) buf2 = g_string_assign(buf2,"Lesser God");
				else if (ch->race <= 9 ) buf2 = g_string_assign(buf2,"Demigod");
				else if (ch->race <= 14) buf2 = g_string_assign(buf2,"Greater God");
				else if (ch->race <= 19) buf2 = g_string_assign(buf2,"GrandImmortal");
				else if (ch->race <= 24) buf2 = g_string_assign(buf2,"ElderImmortal");
				else                     buf2 = g_string_assign(buf2,"Immort Legend");
				i = g_string_assign(i,buf2->str); break;
			case 'S' :
				g_string_sprintf( buf2, "%d", ch->race );
				i = g_string_assign(i,buf2->str); break;
			case 'o' :
				if (!IS_NPC(ch) && ch->pcdata->stage[2]+25 >= ch->pcdata->stage[1]
						&& ch->pcdata->stage[1] > 0)
				{
					g_string_sprintf( buf2, "yes" );
					ADD_COLOUR(ch, buf2, WHITE);
				}
				else buf2 = g_string_assign( buf2, "no" );
				i = g_string_assign(i,buf2->str); break;
			case 'O' :
				if ( ( victim = ch->pcdata->partner ) == NULL )
					buf2 = g_string_assign( buf2, "no" );
				else if (!IS_NPC(victim) && victim != NULL && victim->pcdata->stage[1] > 0
						&& victim->pcdata->stage[2]+25 >= victim->pcdata->stage[1])
				{
					g_string_sprintf( buf2, "yes" );
					ADD_COLOUR(ch, buf2, WHITE);
				}
				else buf2 = g_string_assign( buf2, "no" );
				i = g_string_assign(i,buf2->str); break;
			case 'l' :
				if ( ( victim = ch->pcdata->partner ) == NULL )
					buf2 = g_string_assign( buf2, "Nobody" );
				else
				{
					if ( IS_AFFECTED(victim, AFF_POLYMORPH) )
						buf2 = g_string_assign(buf2, victim->morph->str);
					else if ( IS_NPC(victim) )
						buf2 = g_string_assign(buf2, victim->short_descr->str);
					else
						buf2 = g_string_assign(buf2, victim->name->str);
					buf2->str[0] = UPPER(buf2->str[0]);
				}
				i = g_string_assign(i,buf2->str); break;
			case '%' :
				g_string_sprintf( buf2, "%%");
				i = g_string_assign(i,buf2->str); break;
		}
		/*
		 * Add buf2 and increment buf2's lenth to xloop
		 */
		buf = g_string_append(buf,i->str);	
	}

	i = g_string_assign(i,buf->str);
	buf = g_string_assign(buf,"");
	colourconv(buf,i,d->character);
	write_to_buffer( d, buf->str, 0 );
	g_string_free(buf,TRUE);
	g_string_free(buf2,TRUE);
	g_string_free(i,TRUE);
	g_string_free(str,TRUE);

	return;
}

/*
 * Append onto an output buffer.
 */
void write_to_buffer( DESCRIPTOR_DATA *d, const char *txt, int length )
{
	GString *buf;
	
	buf = g_string_new(txt);
	
	if (length > 0 && length <= buf->len)
	{
		buf = g_string_erase(buf,length,buf->len - length);
	}
	if ( d->outbuf->len == 0 )
	{
		if ( !d->fcommand )
		{
			d->outbuf = g_string_assign(d->outbuf,"\n\r");
		}
	}
	if (g_string_append(d->outbuf,buf->str) == NULL)
	{
		g_string_free(buf,TRUE);
		return;
	}
	g_string_free(buf,TRUE);
	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, 4096 );
#if defined(unix)
		if ( ( nWrite = write( desc, txt + iStart, nBlock ) ) < 0 )
		{ 
			bug( "Write_to_descriptor",0 ); 
			return FALSE; 
		}
#endif
#if defined(_WIN32)
		if ( ( nWrite = send( desc, txt + iStart, nBlock, 0 ) ) < 0 )
		{ 
			bug( "Write_to_descriptor",0 ); 
			return FALSE; 
		}
#endif
	} 
	
	return TRUE;
}


/*
 * Write to one char, new colour version, by Lope.
 */
void send_to_char( const char *txt, CHAR_DATA *ch )
{
	GString *buf;
	GString *output;
	int 	xloop;
	CHAR_DATA *wizard;
	CHAR_DATA *familiar;

	/* If they are writing a note do they need to see womething?*/
	//if (ch->desc != NULL && !IS_NPC(ch) && ch->desc->connected == CON_NOTE_TEXT)
	//	return;

	buf = g_string_new(txt);
	output = g_string_new("");
	if( txt )
	{
		if( IS_SET( ch->act, PLR_ANSI ) )
		{
			for(xloop = 0; xloop < buf->len; xloop++ )
			{
				/*
				 * Sending to Color *point might become uninitalized
				 */
				if( buf->str[xloop] == '{' )
				{
					xloop++;
					if (IS_SWWF(ch) && IS_ADDED(ch,ADDED_FRENZY))
						frenzy_colour( buf->str[xloop], ch, output );
					else
						colour( buf->str[xloop], ch, output );
					continue;
				}
				output = g_string_append_c(output,buf->str[xloop]);
			}			
			if ( ch->desc == NULL && IS_NPC(ch) && (wizard = ch->wizard) != NULL )
			{
				if (!IS_NPC(wizard) && (familiar = wizard->pcdata->familiar) != NULL 
						&& familiar == ch && ch->in_room != wizard->in_room)
				{
					xloop++;
					//SET_BIT(wizard->extra, EXTRA_CAN_SEE);
					send_to_char("<- ",wizard);
					if ( buf != NULL && wizard->desc != NULL ){
						write_to_buffer( wizard->desc, buf->str, 0 );
					}
					//REMOVE_BIT(wizard->extra, EXTRA_CAN_SEE);
					g_string_free(buf,TRUE);
					g_string_free(output,TRUE);
					return;
				}
			}
			if ( ch->desc )
				write_to_buffer( ch->desc, output->str, 0 );

		}
		else
		{
			for(xloop = 0; xloop < buf->len; xloop++ )
			{
				if( buf->str[xloop] == '{' )
				{
					xloop++;
					continue;
				}
				output = g_string_append_c(output,buf->str[xloop]);
			}

			if ( ch->desc == NULL && IS_NPC(ch) && (wizard = ch->wizard) != NULL )
			{
				if (!IS_NPC(wizard) && (familiar = wizard->pcdata->familiar) != NULL 
						&& familiar == ch && ch->in_room != wizard->in_room)
				{
					//SET_BIT(wizard->extra, EXTRA_CAN_SEE);
					send_to_char("<- ",wizard);
					if ( buf != NULL && wizard->desc != NULL )
						write_to_buffer( wizard->desc, buf->str, 0 );
					//REMOVE_BIT(wizard->extra, EXTRA_CAN_SEE);
					g_string_free(buf,TRUE);
					g_string_free(output,TRUE);
					return;
				}
			}
			if ( ch->desc )
				write_to_buffer( ch->desc, output->str, 0 );
		}
	}
	g_string_free(buf,TRUE);
	g_string_free(output,TRUE);
	return;
}

/*
 * Rip apart massive strings in to smaller strings..
 * parsing \n\r
 */
int parse_snoop_string(GString *SnoopString, GString *output, int Start)
{
	int x;
	int Return_Count = 0;

	for (x = Start; x < output->len; x++)
	{
		if (output->str[x] == '\n')
		{
			g_string_append(SnoopString,"\n\r");
			x += 2;
			Return_Count = x;
			break;
		}
		g_string_append_c(SnoopString,output->str[x]);
	}

	if (x == output->len)
		Return_Count = output->len;

	return Return_Count;
}

/*
 * Process snooping information
 */
void write_to_snooper( DESCRIPTOR_DATA *d, GString *output)
{
	GSList *InputBuffer;
	GSList *DisplayBuffer;
	GString *SnoopString;
	GString *DisplayString;
	int x = 0;

	InputBuffer = NULL;
	DisplayBuffer = NULL;

	while (x < output->len)
	{
		SnoopString = g_string_new("");
		x = parse_snoop_string(SnoopString,output,x);
		InputBuffer = g_slist_append(InputBuffer,SnoopString);
	}

	for (DisplayBuffer = InputBuffer; DisplayBuffer != NULL; DisplayBuffer = g_slist_next(DisplayBuffer))
	{
		DisplayString = (GString *)DisplayBuffer->data;
		if (g_strncasecmp(DisplayString->str,"?>", 2))
		{
			g_string_prepend(DisplayString,"?>");
			write_to_buffer(d,DisplayString->str,0);
		}
	}
	g_slist_free(InputBuffer);
	g_slist_free(DisplayBuffer);
	return;
}

/*
 * Low level output function.
 */
bool process_output( DESCRIPTOR_DATA *d, bool fPrompt )
{
	extern bool merc_down;
	GString *pbuff;
	GString *buffer;
    /*
     * Bust a prompt.
     */
    if(!merc_down)
    {
    if ( d->showstr_point )
	    write_to_buffer( d, "[Hit Return to continue]\n\r", 0 );
    else if ( fPrompt && d->connected == CON_PLAYING )
	{
		CHAR_DATA *ch;
		CHAR_DATA *victim;
		
		ch = d->original ? d->original : d->character;
		if ( IS_SET(ch->act, PLR_BLANK) )
			write_to_buffer( d, "\n\r", 0 );
		
		if (IS_SET(ch->act, PLR_PROMPT) && IS_EXTRA(ch, EXTRA_PROMPT))
			bust_a_prompt( d );
		else if ( IS_SET(ch->act, PLR_PROMPT) )
		{
			GString *buf;
			GString *cond;
			GString *hit_str;
			GString *mana_str;
			GString *move_str;
			GString *exp_str;

			buf = g_string_new("");
			cond = g_string_new("");
			hit_str = g_string_new("");
			mana_str = g_string_new("");
			move_str = g_string_new("");
			exp_str = g_string_new("");

			
			ch = d->character;
			if (IS_HEAD(ch,LOST_HEAD) || IS_EXTRA(ch,EXTRA_OSWITCH))
			{
				g_string_sprintf(exp_str, "%d ", ch->exp);
				COL_SCALE(exp_str, ch, ch->exp, 1000);
/*
	        sprintf( buf, "[%s exp] <?hp ?m ?mv> ",exp_str );
*/
				g_string_sprintf( buf, "<[%sX] [?H ?M ?V]> {x",exp_str->str );
			}
			else if (ch->position == POS_FIGHTING)
			{
				if ( (victim = ch->fighting) != NULL);
				{		
					if ((victim->hit*100/victim->max_hit) < 17)
					{
						cond = g_string_assign(cond, "Crippled");
						ADD_COLOUR(ch, cond, L_RED);
					}
					else if ((victim->hit*100/victim->max_hit) < 34)
					{
						cond = g_string_assign(cond, "Mauled");
						ADD_COLOUR(ch, cond, L_RED);
					}
					else if ((victim->hit*100/victim->max_hit) < 51)
					{
						cond = g_string_assign(cond, "Wounded");
						ADD_COLOUR(ch, cond, L_BLUE); 
					}
					else if ((victim->hit*100/victim->max_hit) < 68)
					{
						cond = g_string_assign(cond, "Injured");
						ADD_COLOUR(ch, cond, L_GREEN);
					}
					else if ((victim->hit*100/victim->max_hit) < 85) 
					{
						cond = g_string_assign(cond, "Hurt");
						ADD_COLOUR(ch, cond, YELLOW);
					}
					else if ((victim->hit*100/victim->max_hit) < 100)
					{
						cond = g_string_assign(cond, "Bruised");
						ADD_COLOUR(ch, cond, YELLOW);
					}
					else if ((victim->hit*100/victim->max_hit) >= 100)
					{
						cond = g_string_assign(cond, "Perfect");
						ADD_COLOUR(ch, cond, L_CYAN);
					}
					g_string_sprintf(hit_str, "%d", ch->hit);
					COL_SCALE(hit_str, ch, ch->hit, ch->max_hit);
					g_string_sprintf(mana_str, "%d", ch->mana);
					COL_SCALE(mana_str, ch, ch->mana, ch->max_mana);
					g_string_sprintf(move_str, "%d", ch->move);
					COL_SCALE(move_str, ch, ch->move, ch->max_move);
/*
		sprintf( buf, "[%s] <%shp %sm %smv> ", cond, hit_str, mana_str, move_str );
*/
					g_string_sprintf( buf, "<[%s] [%sH %sM %sV]> {x ", cond->str, hit_str->str, mana_str->str, move_str->str );
				}
			}
			else
			{
				g_string_sprintf(hit_str, "%d", ch->hit);
				COL_SCALE(hit_str, ch, ch->hit, ch->max_hit);
				g_string_sprintf(mana_str, "%d", ch->mana);
				COL_SCALE(mana_str, ch, ch->mana, ch->max_mana);
				g_string_sprintf(move_str, "%d", ch->move);
				COL_SCALE(move_str, ch, ch->move, ch->max_move);
				g_string_sprintf(exp_str, "%d", ch->exp);
				COL_SCALE(exp_str, ch, ch->exp, 1000);
/*
	        sprintf( buf, "[%s exp] <%shp %sm %smv> ",exp_str, hit_str, mana_str, move_str );
	        sprintf( buf, "<[%sX] [%sH %sM %sV]> ",exp_str, hit_str, mana_str, move_str );
*/
				g_string_sprintf( buf, "<[%s] [%sH %sM %sV]> {x ",exp_str->str, hit_str->str, mana_str->str, move_str->str );
			}
			pbuff = g_string_new("");
			buffer = g_string_new(buf->str);

			colourconv( pbuff, buffer, ch);

			write_to_buffer( d, pbuff->str, 0);

			g_string_free(buf,TRUE);
			g_string_free(cond,TRUE);
			g_string_free(hit_str,TRUE);
			g_string_free(mana_str,TRUE);
			g_string_free(move_str,TRUE);
			g_string_free(exp_str,TRUE);
			g_string_free(buffer,TRUE);
			g_string_free(pbuff,TRUE);

		}
	}
	
    }
    /*
     * Short-circuit if nothing to write.
     */
	if ( d->outbuf->len == 0 )
		return TRUE;
	

    	/*
     	* Snoop-o-rama.
     	*/
	if ( d->snoop_by != NULL && g_slist_length(d->snoop_by) > 0 )
	{
		GSList *desc_list = NULL;
		DESCRIPTOR_DATA *snooper;

		for ( desc_list = d->snoop_by; desc_list != NULL; desc_list = g_slist_next(desc_list) )
		{
			snooper = (DESCRIPTOR_DATA*)desc_list->data;
			write_to_snooper( snooper, d->outbuf );
		}
	}
	
    /*
     * OS-dependent output.
     */
	if ( !write_to_descriptor( d->descriptor, d->outbuf->str, 0 ) )
	{
		d->outbuf = g_string_assign(d->outbuf,"");
		return FALSE;
	}
	else
	{
		d->outbuf = g_string_assign(d->outbuf,"");
		return TRUE;
	}
}

void close_socket( DESCRIPTOR_DATA *dclose )
{
	CHAR_DATA *ch;
	char log_buf[MSL];
	
	if ( dclose->outbuf->len > 0 )
		process_output( dclose, FALSE );
	
	if (dclose->character != NULL)
		remove_snooper(dclose->character, dclose->character);

	if ( dclose->snoop_by != NULL && g_slist_length(dclose->snoop_by) > 0)
	{
		removeAllSnoopers(dclose);
		g_slist_free(dclose->snoop_by);
	}
	
	if ( dclose->character != NULL && dclose->connected == CON_PLAYING && IS_NPC(dclose->character) ) 
			do_return(dclose->character,"");
	
	if ( ( ch = dclose->character ) != NULL )
	{
		sprintf( log_buf, "Closing link to %s.", ch->name->str );
		log_string2( log_buf );
		logchan(log_buf, NULL, NULL,WIZ_LINK,0, LEVEL_JUDGE);
		if ( dclose->connected == CON_PLAYING 
			|| ((dclose->connected >= CON_NOTE_TO )
				&& (dclose->connected <= CON_NOTE_FINISH)))
		{
			if (IS_NPC(ch) || ch->pcdata->obj_vnum == 0)
				act( "$n has lost $s link.", ch, NULL, NULL, TO_ROOM );
			ch->desc = NULL;
		}
	}

	remove_descriptor(dclose);
	
#if defined(unix)
	close( dclose->descriptor );
#endif

#if defined(_WIN32)
	closesocket(dclose->descriptor);
#endif
	free_descriptor(dclose);	
	return;
}