area/
build/testing/
log/
player/
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 <merc.h>
#include <tables.h>
#include <interp.h>
#include <recycle.h>

#include <sys/stat.h>
#include <fcntl.h>
//#include <signal.h>

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

#if defined( WIN32 )
#include <sys/timeb.h> /*for _ftime(), uses _timeb struct*/
#endif

#if defined(unix)
#include <signal.h>
#include <unistd.h>
#include <sys/resource.h>	/* for RLIMIT_NOFILE */
#endif

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

#if	defined(interactive)
#include <net/errno.h>
#include <sys/fcntl.h>
#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(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

extern void	stop_idling		args( ( CHAR_DATA *ch ) );
extern void	init_descriptor		args( ( int control ) );
extern bool	read_from_descriptor	args( ( DESCRIPTOR_DATA *d ) );
extern void	nanny			args( ( DESCRIPTOR_DATA *d, char *argument ) );
extern bool	process_output		args( ( DESCRIPTOR_DATA *d, bool fPrompt ) );
extern void	read_from_buffer	args( ( DESCRIPTOR_DATA *d ) );

/*
 * Global variables.

DESCRIPTOR_DATA *   descriptor_free;	
DESCRIPTOR_DATA *   descriptor_list;	
 */
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;
extern int		    world_affects;	/* World Affect bits		*/
extern bool		    MOBtrigger;    /* act() switch                 */
extern int     port,control;
extern void	game_loop_unix		args( ( int control ) );
extern int	init_socket		args( ( int port ) );

void init_memory_chunck args(());

/*
 * OS-dependent local functions.
 */
#if defined(_WIN32)
void	game_loop_unix		args( ( int control ) );
bool	read_from_descriptor	args( ( DESCRIPTOR_DATA *d ) );
void	init_descriptor		args( ( int control ) );
bool	write_to_descriptor	args( ( int desc, char *txt, int length ) );
#endif

extern void my_log_handler args((const gchar *log_domain,GLogLevelFlags log_level, const gchar *message, gpointer user_data));
extern void glib_crit_handler args((const gchar *log_domain,GLogLevelFlags log_level, const gchar *message, gpointer user_data));

int main( int argc, char **argv )
{
	struct timeval now_time;
     /*
     * Memory debugging if needed.
     */
#if defined(MALLOC_DEBUG)
	malloc_debug( 2 );
#endif
	
#ifdef RLIMIT_NOFILE
#ifndef min
# define min(a,b)     (((a) < (b)) ? (a) : (b))
#endif
	{ 
		struct  rlimit rlp;
		(void)getrlimit(RLIMIT_NOFILE, &rlp);
		rlp.rlim_cur=min(rlp.rlim_max,FD_SETSIZE);
		(void)setrlimit(RLIMIT_NOFILE, &rlp);
	}
#endif
	
    /*
     * Init time and encryption.
     */
	init_memory_chunck();
	
	g_log_set_handler (g_log_domain_glib, G_LOG_LEVEL_INFO, my_log_handler, NULL);
	g_log_set_handler (g_log_domain_glib, G_LOG_LEVEL_CRITICAL, glib_crit_handler, NULL);
	
	gettimeofday( &now_time, NULL );
	current_time = (time_t) now_time.tv_sec;
	boot_time = current_time;
	str_cpy( str_boot_time, ctime( &current_time ) );
	str_cpy( crypt_pwd, "Don't bother." );
	
    /*
     * Reserve one channel for our use.
     */
	if ( ( fpReserve = fopen( NULL_FILE, "r" ) ) == NULL )
	{
		bug( "NULL_FILE",0 );
		exit( 1 );
	}
	
    /*
     * Get the port number.
     */
	port = 4040;  /*  Lurking Fear II on port 4040  */
	if ( argc > 1 )
	{
		if ( !is_number( argv[1] ) )
		{
			fprintf( stderr, "Usage: %s [port #]\n", argv[0] );
			exit( 1 );
		}
		else if ( ( port = atoi( argv[1] ) ) <= 1024 )
		{
			fprintf( stderr, "Port number must be above 1024.\n" );
			exit( 1 );
		}
		if (argv[2] && argv[2][0])
		{
			fCopyOver = TRUE;
			control = atoi(argv[3]);
		}
		else
			fCopyOver = FALSE;
	}
	
    /*
     * Run the game.
     */
#if defined(_WIN32)
	control = init_socket(port);
    boot_db( );
	log_string2( "Lurking Fear II is locked, cocked and ready to rock." );
	game_loop_unix(control);
#endif
	
#if defined(unix)
	if (!fCopyOver) 
	{
		control = init_socket(port);
    }
    //init_signals(); /*For the use of the signal handler. -Ferric */
    /*control = init_socket( port );*/
	boot_db( );
	sprintf( log_buf, "Lurking Fear II is rip, raring, and ready to go on port %d.", port );
	log_string2( log_buf );
	/* set the copyover varibles */
	copyover_set = FALSE;
	copyover_time = 0;
	game_loop_unix( control );
	close( control );
#endif
	
    /*
     * That's all, folks.
     */
	log_string2( "Normal termination of game." );
	exit( 0 );
	return 0;
}
void game_loop_unix( int control )
{
	static struct timeval null_time;
	struct timeval last_time;
	GSList *desc_list;
	//15 seconds to wait on people
	unsigned int seconds = 15;

#if defined(unix)
	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;
/* kavirpoint
	maxdesc	= control * 2;
*/		desc_list = descriptor_list;

		while ( desc_list != NULL )
		{
			d = (DESCRIPTOR_DATA*)desc_list->data;
			maxdesc = UMAX( maxdesc, d->descriptor );
			FD_SET( d->descriptor, &in_set  );
			FD_SET( d->descriptor, &out_set );
			FD_SET( d->descriptor, &exc_set );
			desc_list = g_slist_next(desc_list);
		}
		g_slist_free(desc_list);

		//Timeout for blocking
		null_time.tv_sec = seconds;
		null_time.tv_usec = 0;

		if ( select( FD_SETSIZE, &in_set, &out_set, &exc_set, &null_time ) < 0 )
		{
			bug( "Game_loop: select: poll",0 );
			exit( 1 );
		}
		
	/*
	 * New connection?
	 */
		if ( FD_ISSET( control, &in_set ) )
			init_descriptor( control );
		
	/*
	 * Kick out the freaky folks. If thier socket has a exception.
	 */
		while ( desc_list != NULL )
		{
			d = (DESCRIPTOR_DATA*)desc_list->data;
			if ( FD_ISSET( d->descriptor, &exc_set ) )
			{
				FD_CLR( d->descriptor, &in_set  );
				FD_CLR( d->descriptor, &out_set );
				if ( d->character && d->connected == CON_PLAYING)
					save_char_obj( d->character );
				d->outbuf = g_string_assign(d->outbuf,"");;
				close_socket( d );
				log_string2("Socket Exception Caught");
			}
			desc_list = g_slist_next(desc_list);
		}
		g_slist_free(desc_list);
	/*
	 * Process input.
	 */
	 	for ( desc_list = descriptor_list; desc_list != NULL; desc_list = g_slist_next(desc_list) )
		{
			d = (DESCRIPTOR_DATA*)desc_list->data;
			d->fcommand	= FALSE;
			
			if ( FD_ISSET( d->descriptor, &in_set ) )
			{
				if ( d->character != NULL )
					d->character->timer = 0;
				
				/*
				 * Transfer all data incomming to d->incom
				 * if we had a issue with read_from_descriptor..
				 * close thier connection.
				 */
				if ( !read_from_descriptor( d ) )
				{
					FD_CLR( d->descriptor, &out_set );
					if ( d->character != NULL && d->connected == CON_PLAYING )
						save_char_obj( d->character );
					d->outbuf = g_string_assign(d->outbuf,"");;
					close_socket( d );
					continue;
				}
			}
			
			if ( d->character != NULL && d->character->wait > 0 )
			{
				--d->character->wait;
				continue;
			}
			
			/*
			 * Transfer the data from d->incom to d->incomm
			 */
			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( );
		
		
		
	/*
	 * Output.
	 */
		for ( desc_list = descriptor_list; desc_list != NULL; desc_list = g_slist_next(desc_list) )
		{
			d = (DESCRIPTOR_DATA*)desc_list->data;
			
			if ( ( d->fcommand || d->outbuf->len > 0 )
				&&   FD_ISSET(d->descriptor, &out_set) )
			{
				if ( !process_output( d, TRUE ) )
				{
					//Added d->connected = playing from Rom
					if ( d->character != NULL && d->connected == CON_PLAYING )
						save_char_obj( d->character );
					d->outbuf = g_string_assign(d->outbuf,"");;
					close_socket( d );
				}
			}
		}
		
		
	/*
	 * Synchronize to a clock.
	 * Sleep( last_time + 1/PULSE_PER_SECOND - now ).
	 * Careful here of signed versus unsigned arithmetic.
	 */
#if defined(unix)
		{
			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 )
				{
					bug( "Game_loop: select: stall",0 );
					exit( 1 );
				}
			}
		}
#endif
#if defined(_WIN32)
			{
	    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;
}