v05i031: Tron - Multiplayer Game, Part01/02

Dan Heller argv at island.uu.net
Wed Nov 22 12:12:32 AEST 1989


Submitted-by: Helmut Hoenig <hoenig at informatik.uni-kl.de>
Posting-number: Volume 5, Issue 31
Archive-name: tron/part01

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  read_me.txt makefile tron_server.c
# Wrapped by hoenig at incas on Thu Nov 16 14:22:40 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'read_me.txt' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'read_me.txt'\"
else
echo shar: Extracting \"'read_me.txt'\" \(4246 characters\)
sed "s/^X//" >'read_me.txt' <<'END_OF_FILE'
X
X     ++++++++++++
X     +++ TRON +++      - an XWindows game
X     ++++++++++++        (colored or black&white)
X
Xby Helmut Hoenig (MAY-1988)
X
X
X     This is an X-version of the well  known  light-race  of
Xthe  TRON-film.  I  actually wrote that program to get a bit
Xmore familiar with X and with communication between programs
Xthrough  sockets. (That should be an excuse for writing pro-
Xgrams with such a bad structure.) But at least it  runs  and
Xbesides  the  programming-experience I got, we already had a
Xlot of fun with it.
X
X     After we tested the program for more  than  a  year,  I
Xfinally  decided  to  post  it.  To play that game you need:
XUNIX, XWindows X11R3, a C-compiler, a lot of include-files.
X
X     The makefile will help you to  compile  the  4  source-
Xfiles  into the 2 binary-files "tron_server" and "tron_run".
XThese files have to be available in the  same  directory  on
Xevery   host,   where  the  program  should  be  used  (e.g.
X/usr/games), since the programs are getting  started  via  a
Xremote  shell  using a system()-call.  (see "tron_server.c",
Xline 284ff)
X
X
X+++ HOW IT WORKS +++ (you might skip this if it works)
X
X     The "tron_server"-program is used to start  the  system
Xup.   I also call it the master.  In the startup-sequence, a
X"tron_run"-program is started for each  player  (usually  on
Xdifferent  hosts).  Each program connects itself to the mas-
Xter. Through that stream-connection, the master is  able  to
Xsend  commands  to  the  players  (e.g.  start game) and the
Xplayers can answer with the number  of  rounds  they  played
Xuntil they were busted.
X
X     After   the   startup-sequence,   we   have   a   star-
Xconfiguration  of  the  players  and the master. Each player
Xsends the port-number of an  additional  datagram-socket  to
Xthe  master, which is used during the game. The master opens
Xa window to select the players and start the game. When  the
Xgame  gets  started, every player-program receives the port-
Xnumber and host of the next player. In that way a  datagram-
Xpaket, produced by the first player, can be send around in a
Xring.
X
X     No effort (except a timeout, which ends the  game)  has
Xbeen  made to recover from missing datagrams, since it seems
Xthat they don't get lost on our system. They just come a bit
Xlate sometimes and then there's no sense in playing anyway.
X
X
X+++ WHAT TO KNOW +++
X
X     The game is made for up to 8 players. At least  one  of
Xthem has to be human.
X
X     The players control their racers by mouse or  keyboard.
XThe keys to use are available from the program.
X
X     Even if you play with the keyboard, you've got to place
Xyour  racer with the mouse (and middle button) in the field.
XIt starts running in the direction of  your  mouse.  If  you
Xwait  a  few  seconds,  the  racers are automatically placed
Xunder your mouse and the game starts.
X
X     For each player you can  enter  the  display-  and  the
Xhost-name  (separated by a '^', e.g. 'display:0.0^host'). If
Xthere is no display-name given  the  host  is  used  for  an
Xauto-player only (e.g. '^host').  As you usually play on the
Xhost of the display, a single name is enough to select  host
Xand   display.    (So  the  usual  command-line  looks  like
X'tron_server host1 host2 ^auto_player1 ...)  You  might  get
Xproblems  in the starting up sequence, if there are too many
Xauto-players on the same host.
X
X
X+++ PROBLEMS +++
X
X     On our  system,  we  sometimes  have  problems  in  the
Xstartup-sequence  as  there  seem  to  be  a  lot  processes
Xenvolved when starting the remote-shells.  It  happen,  that
Xthe  startup  fails,  when there are too many players (auto-
Xplayers) on the same host.  To avoid that it is possible  to
Xlet  the  server  sleep some seconds between the starting of
Xplayers by the option '-s<seconds>'.
X
X     When controlling with the mouse, you might get problems
Xwith  your  window-manager,  if  it  grabs  combinations  of
Xshift/control and mouse-buttons. Play with keyboards or kill
Xthe window-manager in that case.
X
X
X+++ HAVE FUN +++
X
X	Helmut Hoenig
X
XPS.:
X
XTRON runs on our system with suns and MicroVaxes. It is
Xtested on 3 kinds of monochrom-displays and a colored one.
X
XPlease let me know if TRON runs on your system !
XMy address:
X	hoenig at informatik.uni-kl.de
END_OF_FILE
if test 4246 -ne `wc -c <'read_me.txt'`; then
    echo shar: \"'read_me.txt'\" unpacked with wrong size!
fi
# end of 'read_me.txt'
fi
if test -f 'makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile'\"
else
echo shar: Extracting \"'makefile'\" \(889 characters\)
sed "s/^X//" >'makefile' <<'END_OF_FILE'
X# Tron consists of 2 program files. The 'tron_server' is used to start up
X# the system. It starts a 'tron_run'-program for each player. For that it
X# gets the file-name of it through the TRON_RUN_FILE-Macro. That name has
X# to be the same on every host (e.g. /usr/games).
X# The SOCKET_NAME-Macro is used, but not really nescessary.
X
XCFLAGS = -g
XOBJ1 =	tron_run.o texter.o helps.o
XOBJ2 =	tron_server.o texter.o helps.o
X
Xmain:	tron_run tron_server
X
Xtron_run:	$(OBJ1)
X	$(CC) $(CFLAGS) $(OBJ1) -lX11 -o tron_run
X
Xtron_server:	$(OBJ2)
X	$(CC) $(CFLAGS) $(OBJ2) -lX11 -o tron_server
X
Xtron_run.o:	grey_maps.h messages.h header.h
X
Xtron_server.o:	messages.h header.h
X		$(CC) $(CFLAGS) \
X		-DSOCKET_NAME=\"tron\" \
X		-DTRON_RUN_FILE=\"~hoenig/sockets/tron_run\" \
X		-c tron_server.c
X
Xtexter.o:	header.h
X		$(CC) $(CFLAGS) \
X		-DFONT_NAME=\"-*-courier-bold-r-normal--24-*-*-*-*-*-*-*\"	\
X		-c texter.c
END_OF_FILE
if test 889 -ne `wc -c <'makefile'`; then
    echo shar: \"'makefile'\" unpacked with wrong size!
fi
# end of 'makefile'
fi
if test -f 'tron_server.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tron_server.c'\"
else
echo shar: Extracting \"'tron_server.c'\" \(19352 characters\)
sed "s/^X//" >'tron_server.c' <<'END_OF_FILE'
X/*     This program was written by Helmut Hoenig	*/
X/*        in May of 1988 at the Unitversity of		*/
X/*   Kaiserslautern, Germany. It may be copied freely.	*/
X
X#define	moremessages	0
X
X#include <X11/Xlib.h>
X#include <stdio.h>
X#include <strings.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/uio.h>
X#include <sys/time.h>
X#include <netinet/in.h>
X#include <netdb.h>
X
X#include "header.h"
X#include "messages.h"
X
Xshort	readshort();
X
X#define	HMAX		8
Xint	max;	/* when starting the system, this is the actual number of players */
X
Xint	messflag;
X#define	MAXPLAYERS	10
X
X/* fields for result-messages */
Xstatic	int	points[MAXPLAYERS];
Xstatic	int	place[MAXPLAYERS];
Xstatic	int	count[MAXPLAYERS];
Xstatic	int	sorted[MAXPLAYERS];
Xstatic	char	tscreen[20][80];
Xstatic	int	lines;
Xstatic	int	players;
X
Xstruct hostent	*hostaddr[HMAX];
Xint		active[HMAX]={ 0,0,0,0,0,0,0,0 };
Xint		auto_only[HMAX]={ 0,0,0,0,0,0,0,0 };
X
Xchar		host_name[HMAX][20];
Xchar		disp_name[HMAX][20];
X
Xint		sockets[HMAX],ports[HMAX];
Xlong		play_time[HMAX];
Xstruct	sockaddr_in	rsin[HMAX];
Xint			rsinlen[HMAX];
Xint			socks[HMAX];
X
X
Xchar	*my_host;		/* eigener hostname */
X
Xstruct	servent	*sp;
X
Xstruct	sockaddr_in sin;
Xint	mastersocket;
X
Xchar	*getenv();
X
Xlong	packet_count = 0;
Xint	data_error=0;
Xint	g_count=0;
Xint	match;
X
XDisplay	*display;
XScreen	*screen;
Xchar	dispname[20];
Xextern	XFontStruct	*(finfo[]);
Xextern	Window		aw;
Xint	waiting;
XXEvent	event;
X#define	FID	0
X
Xusage()
X{
X	printf("\n\nusage:\ttron_server [ option ] <player_list>\n");
X	printf("\n\t-v      - prints some additional messages in starting sequence.\n");
X	printf("\t-h      - prints this.\n");
X	printf("\t-s<sec> - to sleep <sec> seconds after the start of each players.\n");
X	printf("\n<player_list>: List with the display_names and/or host_names of the players.\n");
X	printf("  If only one name per player is given, the display is the display of the host.\n");
X	printf("  Otherwise you can write <display_name>'^'<host_name> to get a special display.\n");
X	printf("  An empty display-name stands for an automatic player. (e.g. ^host)\n");
X	printf("\n");
X}
X
Xmain(argc,argv)
X	int	argc;
X	char	*argv[];
X{	int	i,j;
X	char	command[200];
X	int	test;
X	int	waitflag=0;
X	char	*ptr;
X	char	*disp_arg=NULL;
XXSetWindowAttributes    attrib;
X
X/*********************************************************************
X * At first, the host-names of the command-line are tested.	     *
X * If there is a display for the player (no auto-player), the server *
X * tests the possibility of opening XWindows on the display. If that *
X * fails or a display is used twice, the player is ignored.	     *
X * ==> In the end, there should be at least 2 correct names.	     *
X *********************************************************************/
X
X	max=0;
X	messflag=0;
X	printf("\nTRON - programmed by Helmut Hoenig. (MAY-1988)\n");
X	printf("startup-sequence at the following displays:\n");
X
X	if (argc==1)
X	{	usage();
X		exit();
X	};
X 
X	for (i=1;i<argc;i++)
X	{   if (strcmp("-v",argv[i])==0)		messflag=1;
X	    else if (strncmp("-s",argv[i],2)==0)	waitflag=atoi(&argv[i][2]);
X	    else if ((strcmp("-",argv[i])==0)||(strcmp("-h",argv[i])==0))
X	    {		usage();
X		    	exit();
X	    }
X	    else if (strcmp("-display",argv[i])==0)	disp_arg = argv[++i];
X	    else if (max<HMAX)
X	    {	ptr = index(argv[i],'^');
X		if (ptr==NULL)
X		{	if ((ptr=index(argv[i],':'))==NULL)
X			{
X	/* a single host-name is extended by ":0.0" to the display-name */
X			strcpy(host_name[max],argv[i]);
X				strcpy(disp_name[max],argv[i]);
X				strcat(disp_name[max],":0.0");
X			}
X			else
X			{
X	/* in display-names the host-names are the string up to the ':' */
X				strncpy(host_name[max],argv[i],ptr-argv[i]);
X				host_name[max][ptr-argv[i]+1]='\0';
X				strcpy(disp_name[max],argv[i]);
X				if ((ptr=index(argv[i],'.'))==NULL)
X				{	strcat(disp_name[max],".0");
X				}
X			}
X		}
X		else
X		{
X	/* if host- and display is given the display-name, the display-name
X	   might be extended to a '*:*.0'-form. */
X			strcpy(host_name[max],ptr+1);
X			if (ptr==argv[i])
X			{
X		/* A missing display-name indicates an auto-player. */
X				strcpy(disp_name[max],host_name[max]);
X				strcat(disp_name[max],"-0");
X			}
X			else
X			{   *ptr ='\0';
X			    strcpy(disp_name[max],argv[i]);
X			    if ((ptr=index(argv[i],':'))==NULL)
X			    {	strcat(disp_name[max],":0.0");
X			    }
X			    else
X			    {	if ((ptr=index(argv[i],'.'))==NULL)
X				{	strcat(disp_name[max],".0");
X				}
X			    }
X			}
X		}
X
X	/* after extending names: check, if the argument is a host-name. */
X		hostaddr[max]=gethostbyname(host_name[max]);
X		if (hostaddr[max]==NULL)
X		{	printf("*** %s is not a host.\n",host_name[max]);
X		}
X		else
X		{
X	/* check the display-name */
X		do
X		{	for (j=0;j<max;j++)
X			{	if (strcmp(disp_name[j],disp_name[max])==NULL)	break;
X			}
X
X			if (j==max)
X			{   if (index(disp_name[max],'-')!=NULL)
X			    {
X		/* Name of Auto-Player is O.K. */
X			    	printf("%2d: auto-player %s\n",max+1,disp_name[max]);
X			    	auto_only[max++]=1;
X			    }
X			    else
X			    {
X			    	if ((display=XOpenDisplay(disp_name[max]))==NULL)
X				{	printf("XWindows ??? ");
X				}
X				else
X		/* Display is O.K. */
X				{   XCloseDisplay(display);
X				}
X				if (strncmp(disp_name[max],host_name[max],strlen(host_name[max]))==NULL)
X						printf("%2d: %s\n",max+1,disp_name[max]);
X				else
X						printf("%2d: %s (%s)\n",max+1,disp_name[max],host_name[max]);
X				auto_only[max++]=0;
X			    }
X			    break;
X			}
X			else
X			{
X		/* disp_name[max] already used. is it for an auto-player ? */
X				if (index(disp_name[max],'-')!=NULL)
X				{	disp_name[max][strlen(disp_name[max])-1]++;
X				}
X				else
X				{	printf("display %s used twice.\n",disp_name[max]);
X					break;
X				}
X			}
X		}
X		while(j<max);
X		};
X	    }
X	}
X
X	if (max<2)
X	{	fprintf(stderr,"*** But there should be at least 2 players. ***\n");
X		usage();
X		exit(0);
X	};
X
X/***************************************************************
X * After name-checking is done, a streamsocket is created      *
X * where the player-programs can connect to. A socket_name is  *
X * *NOT* nescessary as the server tells the clients his        *
X * socket-number as a parameter.			       *
X ***************************************************************/
X
X	my_host=getenv("HOST");
X
X/* Erzeugung eines Streamsockets in der Domain AF_INET */
X	mastersocket=streamsocket();
X
X/* Information ueber den Service mit Namen "service" */
X	if ((sp=getservbyname(SOCKET_NAME,0))==0)
X	{	fprintf(stderr,"#%s: socket not found by name.\n",my_host);
X		init_addr(&sin,my_host,htons((short)22222));
X	}
X	else
X/* Initialisieren der Struktur sockaddr_in */
X	{	bzero(&sin,sizeof sin);
X		sin.sin_family=AF_INET;
X		sin.sin_port= sp->s_port;
X		sin.sin_addr.s_addr= INADDR_ANY;
X	};
X
X/* Namensbindung an den Socket */
X	if (bind ( mastersocket,&sin,sizeof sin)<0)
X	{	fprintf(stderr,"### #%s: error in bind.\n",my_host);
X		do
X		{	sin.sin_port++;
X		}
X		while (bind (mastersocket,&sin,sizeof sin)<0);
X		fprintf(stderr,"### #%s: port %d selected as an alternative.\n",my_host,ntohs(sin.sin_port));
X	};
X	if (messflag)	printf("*** master-socket is %s@%d. ***\n",my_host,(int)ntohs(sin.sin_port));
X
X/* Einrichten einer Warteschlange */
X	listen(mastersocket,max);
X
X/******************************************************************
X * The 'tron_run'-Program will now be started on each player-host.*
X * A Bell-Signal is given on each display.			  *
X ******************************************************************/
X
X	for (i=0;i<max;i++)
X	{	play_time[i]=0;
X		if (!auto_only[i])
X		{	if ((display=XOpenDisplay(disp_name[i]))!=NULL)
X			{	XBell(display,60);
X				XCloseDisplay(display);
X			}
X		}
X
X/***********************************************************************************
X the following command is now prepared to be executed by system():
X'<foreign_host> <file_name> <my_host> <mastersocket> <count> <message_flag> &'
Xwith	<foreign_host>	- host for a player
X	<file_name>	- name of the 'tron_run'-binary-file on that host
X			  the macro TRON_RUN_FILE from the top off that source-file is used.
X	<my_host>	- my host   (for the stream-connection)
X	<mastersocket>	- my socket (for the stream-connection)
X	<display>	- the display, usually <foreign_host>:0.0
X	<count>		- to get the players in an order
X	<messageflag>	- to produce additional messages by the players
X***********************************************************************************/
X		sprintf(command,"%s '%s %s %d %s %d %d' &",
X			host_name[i],
X			TRON_RUN_FILE,
X			my_host,
X			(int)ntohs(sin.sin_port),
X			disp_name[i],
X			i,
X			messflag);
X
X		if (messflag)	printf("#%s: starting up %s on %s.\n",my_host,disp_name[i],host_name[i]);
X#if (moremessages)
X		printf("%s\n",command);
X#endif
X		system(command);
X		if (waitflag)
X		{	printf("sleeping %d seconds.\n",waitflag);
X			fflush(stdout);
X			sleep(waitflag);
X		}
X	}
X
X	printf("#%s: %d clients started.\n",my_host,max);
X
X/********************************************************************************
X * The server waits, until all players are started and connected to the server. *
X * Each Player-Program returns a port-number, which it uses in the game.	*
X ********************************************************************************/
X
X	for (i=0;i<max;i++)
X	{	int	j,count,auto_player;
X
X		rsinlen[i]=sizeof rsin[i];
X		socks[i]=accept(mastersocket,&rsin[i],&rsinlen[i]);
X		count=readint(socks[i]);	/*** that's the <count>-argument
X						     of the player's command-line. ***/
X		sockets[count]=socks[i];
X		ports[count]=(int)readshort(sockets[count]);
X		auto_player = readint(sockets[count]);
X		if (auto_player!=auto_only[count])
X		{	fprintf(stderr,"*** no XWindows on %s -> auto-player-mode only\n",disp_name[count]);
X			auto_only[count]=auto_player;
X		};
X		if (messflag)	printf("#%s: connection %s@%d established.\n",my_host,disp_name[count],ports[count]);
X	};
X	printf("#%s: all clients connected.\n",my_host);
X
X	close(mastersocket);
X
X/**********************************************************
X * After all players are running, a window can be openend *
X * to select who is really playing.			  *
X **********************************************************/
X 
X	if ((display=XOpenDisplay(disp_arg))==NULL)
X	{	fprintf(stderr,"*** %s: Can't open display.\n",my_host);
X		exit(0);
X	};
X	screen=XScreenOfDisplay(display,DefaultScreen(display));
X	init_texter();
X
X	aw=XCreateSimpleWindow(display,RootWindowOfScreen(screen),
X			20,50,26 * CharWidth(FID),(max+3+7) * CharHeight(FID),
X			4,XBlackPixelOfScreen(screen),XWhitePixelOfScreen(screen));
X	attrib.override_redirect = 1;
X	XChangeWindowAttributes(display,aw,CWOverrideRedirect,&attrib);
X	XSelectInput(display,aw,ExposureMask | ButtonPressMask);
X
X/*************************************************************************
X * The next loop is executed, until QUIT is selected in the main menu.   *
X * You have to wait until a match is ended to get back to the main menu. *
X *************************************************************************/
X	for(;;)
X	{	long	tp1,tp2;
X
X		if (data_error)
X			prepare_message();
X		else
X			prepare_scores();
X		send_scores();
X
X		if (match)
X		{	int	root_x,root_y,x,y;
X			Window	root,child;
X			int	mask;
X
X			sleep(2);
X	/***********************************************************
X	 * you CAN STOP a match by holding down the left AND right *
X	 * button on your mouse, befor the next game starts.       *
X	 ***********************************************************/
X
X			XQueryPointer(display,ROOT,&root,&child,&root_x,&root_y,&x,&y,&mask);
X			if ((mask & Button3Mask) && (mask & Button1Mask))
X			{	match=0;
X				sprintf(tscreen[0],"Match ended.");
X				send_scores();
X			};	
X		};
X
X		if (!match)
X		{
X			XMapRaised(display,aw);
X			waiting=1;
X			do
X			{
X				XWindowEvent(display,aw,ExposureMask | ButtonPressMask,&event);
X				aw_event(event.type);
X			}
X			while(waiting);
X			XUnmapWindow(display,aw);
X		};
X		tp1=time((long)0);
X		send_game_start();
X		wait_players_ready();
X		wait_game_over();
X		tp2=time((long)0);
X
X		for(i=0;i<max;i++)
X			if (active[i]==1)	play_time[i]+=(tp2 - tp1);
X	};
X}
X
Xint check_points(a,b)
X	int	*a,*b;
X{
X	if (points[*a]<points[*b])	return(1);
X	if (points[*a]>points[*b])	return(-1);
X	return(0);
X}
X
X/************************************************
X * preparation of a text-field with the		*
X * sorted list of players with their scores.	*
X ************************************************/
Xprepare_scores()
X{	int	i;
X
X/* Spieler nach Punkten sortieren */
X	players=0;
X	for (i=0;i<max;i++)
X		if (active[i])		sorted[players++]=i;
X
X	qsort(sorted,players,sizeof(int),check_points);
X
X/* pruefen, ob Spielende erreicht */
X	if (match)
X	{	int	mp=5*players;
X		
X		if ((points[sorted[0]]>=mp) && (points[sorted[0]]>points[sorted[1]]+1))
X		{	match=0;
X			sprintf(tscreen[0],"-- Final Result --");
X		}
X		else
X			sprintf(tscreen[0],"Points:       (%d)",mp);
X	}
X	else
X	{
X		sprintf(tscreen[0],"Points:");
X	};
X
X	sprintf(tscreen[1],"");
X
X	lines=2;
X	for (i=0;i<players;i++)
X		sprintf(tscreen[lines++],"%-13s%2d%3d",disp_name[sorted[i]],place[sorted[i]],points[sorted[i]]);
X}
X
Xshow_keys()
X{
X	sprintf(tscreen[0],"****  TRON  - by Helmut Hoenig ****");
X	sprintf(tscreen[1],"");
X	sprintf(tscreen[2],"             Keyboard         Mouse");
X	sprintf(tscreen[3],"");
X	sprintf(tscreen[4],"left turn:   'z' 'x' 'm' ','  left");
X	sprintf(tscreen[5],"right turn:  'c' 'v' '.' '/'  right");
X	sprintf(tscreen[6],"jump:        SPACE            middle");
X	sprintf(tscreen[7],"speed:       SHIFT");
X	sprintf(tscreen[8],"booster:     SHIFT & CTRL");
X	sprintf(tscreen[9],"");
X	sprintf(tscreen[10]," >> no turns while booster's on. <<");
X	lines=11;
X	send_scores();
X};
X	
Xprepare_message()
X{
X	sprintf(tscreen[0],"- Timeout -");
X	lines=1;
X}
X
X/*********************************************
X * sends the textfield to all active players *
X *********************************************/
Xsend_scores()
X{	int	i,l;
X
X	for (i=0;i<max;i++)
X		if (active[i] & 1)
X		{	writeint(sockets[i],SCORE);
X			writeint(sockets[i],lines);
X	    		for (l=0;l<lines;l++)
X			{		writestring(sockets[i],tscreen[l]);
X			};
X		};
X}
X
X/**************************************************************
X * sends the game_start-message to all players.		      *
X * containing the port-number and host of the next player and *
X * a flag, if the player should create the first datagram.    *
X **************************************************************/		
Xsend_game_start()
X{	int	i,ind=0,starter=0;
X	
X	int	perm[MAXPLAYERS];
X
X	g_count++;
X
X	for (i=0;i<max;i++)
X		if (active[i])	perm[ind++]=i;
X
X	for (i=0;i<ind;i++)
X	{	writeint(sockets[perm[i]],GAMESTART);
X		writeint(sockets[perm[i]],players);
X		writeint(sockets[perm[i]],active[perm[i]]);
X		writeint(sockets[perm[i]],g_count);
X		if (i == 0)
X			writeint(sockets[perm[i]],1);
X		else
X			writeint(sockets[perm[i]],0);
X
X		writestring(sockets[perm[i]],host_name[perm[((i+1) % ind)]]);
X		writeshort(sockets[perm[i]],ports[perm[((i+1) % ind)]]);
X	};
X}
X
Xsend_exit()
X{	int	i;
X
X	for (i=0;i<max;i++)
X		writeint(sockets[i],EXIT);
X}
X
X/***********************************************
X * waits, until all players are ready to start *
X ***********************************************/
Xwait_players_ready()
X{
Xint	readfds,writefds,execptfds;
Xstruct	timeval	timeout;
X
Xint	ready_count=0,i,nfound;
X
X    do
X    {	readfds=0;
X	writefds=0;
X	execptfds=0;
X/*	timeout.tv_sec=0;
X	timeout.tv_usec=0;
X*/
X	for (i=0;i<max;i++)
X		if (active[i])	readfds |= (1<<sockets[i]);
X
X	nfound=select(32,&readfds,&writefds,&execptfds,0);
X	if (nfound<0)
X	{	fprintf(stderr,"#%s: error occured in select.\n",my_host);
X		exit(0);
X	};
X	for (i=0;i<max;i++)
X	    if (readfds & (1<<sockets[i]))
X	    {	int	v;
X	    	if ((v=readint(sockets[i]))!=PLAYER_READY)
X	    	{	fprintf(stderr,"#%s: illegal message (%d) received from %s.\n",my_host,v,disp_name[i]);
X			send_exit();
X	    		exit(0);
X	    	};
X	    	ready_count++;
X	    };
X    }
X    while(ready_count<players);
X}
X
Xint check_count(a,b)
X	int	*a,*b;
X{
X	if (count[*a]<count[*b])	return(1);
X	if (count[*a]>count[*b])	return(-1);
X	return(0);
X}
X
X/***************************************************
X * waits, until the game is over.		   *
X * the server receives a counter from each player, *
X * which says, when it was destroyed.		   *
X ***************************************************/
Xwait_game_over()
X{
Xint	readfds,writefds,execptfds;
Xstruct	timeval	timeout;
X
Xint	ready_count=0,i,nfound;
X
X    data_error=0;
X    while(ready_count<players)
X    {	readfds=0;
X	writefds=0;
X	execptfds=0;
X/*	timeout.tv_sec=0;
X	timeout.tv_usec=0;
X*/
X	for (i=0;i<max;i++)
X		if (active[i])		readfds |= (1<<sockets[i]);
X
X	nfound=select(32,&readfds,&writefds,&execptfds,0);
X	if (nfound<0)
X	{	fprintf(stderr,"#%s: error occured in select.\n",my_host);
X		exit(0);
X	};
X	for (i=0;i<max;i++)
X	    if (readfds & (1<<sockets[i]))
X	    {	int	v;
X	    	if ((v=readint(sockets[i]))!=DESTROYED)
X		{	data_error=1;
X			printf("#%s: error-message by %s.\n",my_host,disp_name[i]);
X			fflush(stdout);
X		}
X	    	else
X	    	{
X/*			printf("#%s: %s destroyed.\n",my_host,disp_name[i]); */
X	    		count[i]=readint(sockets[i]);
X	    	};
X	    	ready_count++;
X	    };
X    };
X
X/*  printf("#%s: all players destroyed.\n",my_host); */
X
X/* Punkte verteilen */
Xif (!data_error)
X{   players=0;
X    for (i=0;i<max;i++)
X    	if (active[i])	sorted[players++]=i;
X
X    qsort(sorted,players,sizeof(int),check_count);
X
X    for (i=0;i<players;i++)
X    {	points[sorted[i]] +=(place[sorted[i]] = players-i-1);
X
X    };
X	packet_count += (long)count[sorted[0]];
X};
X}
X
X
X/*******************************************************
X * XWindow-Functions for redrawing and event-executing *
X *******************************************************/
Xredraw_disps()
X{	int	i;
X
X	XRaiseWindow(display,aw);
X	printat(1,1,"TRON",FID);
X	for (i=0;i<max;i++)
X	{	printat(1,i+3,disp_name[i],FID);
X		if (active[i]==2)
X			printcleared(20,i+3,"AUTO",FID);
X		else if (active[i]==1)
X			printcleared(20,i+3," YES",FID);
X		else
X			printcleared(20,i+3,"  NO",FID);
X	};
X	printat(1,3+max+1,"Start Match",FID);
X	printat(1,3+max+2,"Start Game",FID);
X	printat(1,3+max+3,"Show Keys",FID);
X	printat(1,3+max+4,"Clear Scores",FID);
X	printat(1,3+max+5,"Quit",FID);
X	XFlush(display);
X}
X
Xaw_event(type)
X	unsigned	type;
X{	int		i,y;
X
X	switch(type)
X	{
X	case Expose:
X		redraw_disps();
X		break;
X	case ButtonPress:
X		y=((event.xbutton.y)/CharHeight(FID))-3;
X		if (y<0)	break;
X
X		if (y<max)
X		{
X			active[y]=(active[y]+1)%3;	/* switching:	NO->YES->AUTO->NO */
X			if (auto_only[y])
X			{	if (active[y]==1)	active[y]++;
X			}
X			if (active[y] & 2)	writeint(sockets[y],UNMAP);
X		}
X		else
X		{	y-=max+1;
X			if (y<2)			/* START GAME OR MATCH */
X			{	int	i1,i2,j;
X
X				i1=i2=0;
X				for (j=0;j<max;j++)
X				{	if (active[j])
X					{	i1++;
X						if (active[j]==1)	i2++;
X					}
X				}
X				if ((i1>1)&&(i2>0))
X				{	waiting=0;
X					match=(y==0);
X				}
X				else
X				{	XBell(display,50);
X					XFlush(display);
X				}
X			};
X			if (y==2)			/* SHOW KEYS */
X			{	int	t;
X				for (t=0;t<max;t++)
X					if (active[t]==1)	break;
X				if (t==max)
X					XBell(display,10);
X				else
X					show_keys();
X				return;
X			};
X
X			if ((y==3) || (match))		/* CLEAR SCORES */
X				for (i=0;i<max;i++)
X				{	sorted[i]=i;
X					points[i]=0;
X					place[i]=0;
X				};
X			if (y==4)			/* QUIT */
X			{	send_exit();
X
X				printf("#%s: program ends.\n",my_host);
X				printf("#total number of datagrams: %ld\n",packet_count);
X				fflush(stdout);
X				exit(0);
X			};
X		};
X		if (waiting)
X		{	redraw_disps();
X			prepare_scores();
X			send_scores();
X		};
X	};
X}
END_OF_FILE
if test 19352 -ne `wc -c <'tron_server.c'`; then
    echo shar: \"'tron_server.c'\" unpacked with wrong size!
fi
# end of 'tron_server.c'
fi
echo shar: End of shell archive.
echo '*** Think of changing the TRON_RUN_FILE-Macro in the makefile ! ***'
exit 0



More information about the Comp.sources.x mailing list