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