home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume5 / tron / part02 / tron_run.c < prev   
Encoding:
C/C++ Source or Header  |  1989-11-21  |  27.7 KB  |  1,167 lines

  1. /*     This program was written by Helmut Hoenig    */
  2. /*        in May of 1988 at the Unitversity of        */
  3. /*   Kaiserslautern, Germany. It may be copied freely.    */
  4.  
  5. #define    NONE        255
  6. #define    P_TYPE        unsigned char
  7.  
  8. #define    DX    128    /* Groesse des Feldes */
  9. #define    DY    108
  10. #define    DYSHIFT    1
  11.  
  12. #define    times        0
  13. #define    moremess    0
  14. #define    datagramm    1
  15.  
  16. int    messflag;
  17. short    readshort();
  18.  
  19. #define    CHECK(n)    printf("%s: check %d%c",my_host,n,(char)10); fflush(stdout)
  20.  
  21. #include <X11/Xlib.h>
  22. #include <stdio.h>
  23. #include <strings.h>
  24. #include <sys/types.h>
  25. #include <sys/time.h>
  26. #include <netinet/in.h>
  27. #include <netdb.h>
  28.  
  29. #define    XK_MISCELLANY
  30. #define    XK_LATIN1
  31. #include <X11/keysymdef.h>
  32.  
  33. #include "grey_maps.h"
  34.  
  35. #include "header.h"
  36. #include "messages.h"
  37.  
  38. #define    MAXPLAYERS    8
  39. #define    DIMENSION    4
  40.  
  41. char    *my_host,
  42.     *mast_host;    /* host of the server, received at the start */
  43. int    my_count;    /* count to use, when sending messages to the server */
  44. short    mast_port;    /* port-number of the servers master_socket */
  45.  
  46. int    master,        /* my own stream-socket */
  47.     next;        /* datagram socket to send pakets to the next player */
  48.  
  49. struct    sockaddr_in    mast_sin,next_sin,my_sin;
  50. int            lastlen;
  51.  
  52. char    next_host[20];    /* address of the next player, received befor a game starts */
  53. short    next_port;
  54.  
  55. #if (datagramm==0)
  56.     int    last_acc,last;
  57.     struct    sockaddr_in    last_sin;
  58. #endif
  59.  
  60. /* XWindowstrukturen und -Variablen */
  61.  
  62. #define    FID    0
  63. #define    MAPS    8
  64.  
  65. extern    XFontStruct    *(finfo[]);
  66. extern    Window        aw;
  67. extern    GC        gc_set,gc_clear,gc_filler,gc_copy,gc_orInverted,gc_or;
  68.  
  69. Display    *display;
  70. Screen    *screen;
  71. char    *dispname;    /* received by the server */
  72. XEvent    event;
  73. Window    backw,        /* just a black background window, if the display-size doesn't fit */
  74.     mw,        /* main-window, where the action takes place
  75.                **** no eposure-events executed here (too much effort) ***/
  76.     scorew;        /* window in the middle of the screen for text-outputs */
  77.  
  78. XColor    colors[MAPS];
  79. Pixmap    grey[MAPS];
  80. long    pixels[256];
  81. XColor    cols[DY];
  82. long    planes[1];
  83. int    colored;
  84.  
  85. /* Spielstrukturen und -Variablen */
  86.  
  87. #define    x_size    ((DWidth  / DX))
  88. #define    y_size    ((DHeight / DY))
  89. #define    MWWidth        (DX*x_size)
  90. #define    MWHeight    (DY*y_size)
  91.  
  92. int    field[DX][DY];
  93.  
  94. P_TYPE    xmove[DX * DY];
  95. P_TYPE    ymove[DX * DY];
  96. int    lastmove,actmove;
  97.  
  98. typedef    struct    _Pack    {    /* Spielpaket */
  99.     short    mode;        /* mode: SETUP / PLAY */
  100.     short    game_count;    /* laufende Nummer der Paketuebertragung */
  101.     short    game_number;    /* Nummer des Spiels */
  102.     short    players;    /* aktuelle Zahl der Spieler */
  103.     short    ready;
  104.     
  105.     P_TYPE    x[MAXPLAYERS][DIMENSION];
  106.     P_TYPE    y[MAXPLAYERS][DIMENSION];
  107. } Pack;
  108.  
  109. #define    SETUP        1
  110. #define    PLAY        2
  111. #define    GAME_OVER    4
  112. #define    AUTO_START    8
  113.  
  114. Pack    p;        /* Buffer for the datagram-paket */
  115.  
  116. int    start_flag,players;
  117. int    ready,wait,winner;
  118. int    active;
  119. int    game_num;
  120.  
  121. P_TYPE    posx,posy;
  122. int    dx,dy;
  123. int    fast,boost,jmp_count;
  124.  
  125. #if (times==1)
  126.  
  127. #define    MAXMESS    100
  128.  
  129. int    t_count;
  130. struct    timeval        tfield[MAXMESS+1];
  131. struct    timezone    zone;
  132.  
  133. #endif
  134.  
  135. /* Ausgabefenster */
  136. static    int    lines,max_col;
  137. static    char    tscreen[20][80];
  138.  
  139. /* */
  140. char    *getenv();
  141.  
  142. int    max_time;
  143. int    auto_only=0;
  144.  
  145. main(argc,argv)
  146. int    argc;
  147. char    *argv[];
  148. {
  149. struct    hostent    *hp;
  150. struct    servent    *sp;
  151. int    buffer;
  152. int    help;
  153.  
  154. long    timefield;
  155.  
  156.     time(&timefield);
  157.     srandom((int)timefield);
  158.     
  159.     if (argc!=6)
  160.     {    fprintf(stderr,"*** you must not start this directly. ***\n");
  161.         exit(0);
  162.     };
  163.  
  164.     my_host=getenv("HOST");
  165.     mast_host=argv[1];
  166.     sscanf(argv[2],"%d",&help);
  167.     mast_port = htons((short)help);
  168.     dispname = argv[3];
  169.     sscanf(argv[4],"%d",&my_count);
  170.     sscanf(argv[5],"%d",&messflag);
  171.  
  172. #if (moremess==1)
  173.     printf("%s: count: %d\n",my_host,my_count);
  174.     fflush(stdout);
  175. #endif
  176.  
  177. /* Display oeffnen */
  178.     if (index(dispname,'-')==NULL)
  179.     {    if ((display=XOpenDisplay(dispname))==NULL)
  180.         {    fprintf(stderr,"*** %s: Can't open display.\n",my_host);
  181.             auto_only=1;
  182.         }
  183.         else
  184.         {    screen=XScreenOfDisplay(display,DefaultScreen(display));
  185.             auto_only=0;
  186.         };
  187.     }
  188.     else    auto_only=1;
  189.  
  190. /* 2 bis 3 Sockets aufmachen */
  191.     master=streamsocket();
  192.  
  193.     next=dgramsocket();
  194.  
  195. /* Socketnamen fuer eigenen Socket holen */
  196.  
  197.     init_addr(&my_sin,my_host,htons((short)14253));
  198.  
  199.     while (bind(next,&my_sin,sizeof my_sin))    my_sin.sin_port++;
  200.  
  201. #if (moremess==1)
  202.     printf("%s: my port is %d.\n",my_host,(int)ntohs(my_sin.sin_port));
  203.     fflush(stdout);
  204. #endif
  205.     if (messflag)
  206.     {    printf("%s: master: %s@%d, my-port: %s@%d\n",my_host,mast_host,(int)ntohs(mast_port),my_host,(int)ntohs(my_sin.sin_port));
  207.         fflush(stdout);
  208.     }
  209. /* Verbindung zum Master aufbauen */
  210.     connect_to(master,mast_host,mast_port);
  211.     writeint(master,my_count);
  212.     writeshort(master,(short)ntohs(my_sin.sin_port));
  213.     writeint(master,auto_only);
  214.  
  215.     game();
  216.  
  217. /* Sockets schliessen */
  218.     close(master);
  219.     close(next);
  220. }
  221.  
  222. /*****************************************************
  223.  *   Initialisation                     *    
  224.  * + Loop, executing command-messages of the master. *
  225.  *****************************************************/
  226.  
  227. game()
  228. {
  229. XSetWindowAttributes    attrib;
  230. int            i,j,t;
  231. int            mess;
  232.  
  233. if(!auto_only)
  234. {    init_texter();
  235.     XBell(display,40);
  236. /*    XSynchronize(display,1);    */    /* Hilfe fuer Testzwecke */
  237.     
  238.     XFlush(display);
  239.  
  240. /******************************************************
  241.  * tries to allocate a special amount of color cells. *
  242.  * if it fails, it continues in monochrom.          *
  243.  ******************************************************/
  244.     if (XAllocColorCells(display,XDefaultColormapOfScreen(screen),False,planes,0,pixels,10+(DY>>DYSHIFT)))
  245.     {    int    r1,g1,b1,r2,g2,b2;
  246.         colored = True;
  247.  
  248.         XSetFillStyle(display,gc_filler,FillSolid);
  249.  
  250.         XStoreNamedColor(display,XDefaultColormapOfScreen(screen),
  251.             "red",pixels[0],DoRed | DoGreen | DoBlue);        
  252.         XStoreNamedColor(display,XDefaultColormapOfScreen(screen),
  253.             "blue",pixels[1],DoRed | DoGreen | DoBlue);        
  254.         XStoreNamedColor(display,XDefaultColormapOfScreen(screen),
  255.             "violet",pixels[2],DoRed | DoGreen | DoBlue);        
  256.         XStoreNamedColor(display,XDefaultColormapOfScreen(screen),
  257.             "green",pixels[3],DoRed | DoGreen | DoBlue);        
  258.         XStoreNamedColor(display,XDefaultColormapOfScreen(screen),
  259.             "yellow",pixels[4],DoRed | DoGreen | DoBlue);        
  260.         XStoreNamedColor(display,XDefaultColormapOfScreen(screen),
  261.             "cyan",pixels[5],DoRed | DoGreen | DoBlue);        
  262.         XStoreNamedColor(display,XDefaultColormapOfScreen(screen),
  263.             "navy",pixels[6],DoRed | DoGreen | DoBlue);        
  264.         XStoreNamedColor(display,XDefaultColormapOfScreen(screen),
  265.             "orange",pixels[7],DoRed | DoGreen | DoBlue);        
  266.  
  267.         XStoreNamedColor(display,XDefaultColormapOfScreen(screen),
  268.             "wheat",pixels[8],DoRed | DoGreen | DoBlue);        
  269.         XStoreNamedColor(display,XDefaultColormapOfScreen(screen),
  270.             "dark green",pixels[9],DoRed | DoGreen | DoBlue);
  271.         XSetState(display,gc_or,pixels[9],pixels[9],GXcopy,AllPlanes);
  272.  
  273.         r1 = 192 * 256;        g1 = 224 * 256;        b1 = 255 * 256;
  274.         r2 = 255 * 256;        g2 = 192 * 256;        b2 = 192 * 256;
  275.         
  276.         for (i=0;i<(DY>>DYSHIFT);i++)
  277.         {    cols[i].pixel = pixels[10+i];
  278.             cols[i].red   = (unsigned short)(r1+((r2-r1)*i)/(DY>>DYSHIFT));
  279.             cols[i].green = (unsigned short)(g1+((g2-g1)*i)/(DY>>DYSHIFT));
  280.             cols[i].blue  = (unsigned short)(b1+((b2-b1)*i)/(DY>>DYSHIFT));
  281.             cols[i].flags = DoRed | DoGreen | DoBlue;
  282.         }
  283.         XStoreColors(display,XDefaultColormapOfScreen(screen),cols,(DY>>DYSHIFT));        
  284.     }
  285.     else
  286.     {    colored = False;    }
  287.  
  288.  
  289.     grey[0]=XCreatePixmapFromBitmapData(display,ROOT,grey0_bits,grey0_width,grey0_height,
  290.         1,0,DefaultDepthOfScreen(screen));
  291.     grey[1]=XCreatePixmapFromBitmapData(display,ROOT,grey1_bits,grey1_width,grey1_height,
  292.         1,0,DefaultDepthOfScreen(screen));
  293.     grey[2]=XCreatePixmapFromBitmapData(display,ROOT,grey2_bits,grey2_width,grey2_height,
  294.         1,0,DefaultDepthOfScreen(screen));
  295.     grey[3]=XCreatePixmapFromBitmapData(display,ROOT,grey3_bits,grey3_width,grey3_height,
  296.         1,0,DefaultDepthOfScreen(screen));
  297.     grey[4]=XCreatePixmapFromBitmapData(display,ROOT,grey4_bits,grey4_width,grey4_height,
  298.         1,0,DefaultDepthOfScreen(screen));
  299.     grey[5]=XCreatePixmapFromBitmapData(display,ROOT,grey5_bits,grey5_width,grey5_height,
  300.         1,0,DefaultDepthOfScreen(screen));
  301.     grey[6]=XCreatePixmapFromBitmapData(display,ROOT,grey6_bits,grey6_width,grey6_height,
  302.         1,0,DefaultDepthOfScreen(screen));
  303.     grey[7]=XCreatePixmapFromBitmapData(display,ROOT,grey7_bits,grey7_width,grey7_height,
  304.         1,0,DefaultDepthOfScreen(screen));
  305.  
  306.     backw=XCreateSimpleWindow(display,ROOT,0,0,DWidth,DHeight,
  307.         0,WhitePixelOfScreen(screen),BlackPixelOfScreen(screen));
  308.     attrib.override_redirect = 1;
  309.     XChangeWindowAttributes(display,backw,CWOverrideRedirect,&attrib);
  310.  
  311.     if (colored)
  312.     {    mw=XCreateSimpleWindow(display,backw,
  313.             (DWidth-MWWidth)>>1,(DHeight-MWHeight)>>1,MWWidth,MWHeight,
  314.             0,WhitePixelOfScreen(screen),cols[DY>>(DYSHIFT+1)].pixel);
  315.     }
  316.     else
  317.     {    mw=XCreateSimpleWindow(display,backw,
  318.             (DWidth-MWWidth)>>1,(DHeight-MWHeight)>>1,MWWidth,MWHeight,
  319.             0,WhitePixelOfScreen(screen),BlackPixelOfScreen(screen));
  320.     }
  321.  
  322.     XSelectInput(display,mw,ExposureMask | ButtonPressMask | KeyPressMask | KeyReleaseMask );
  323.     attrib.override_redirect = 1;
  324.     XChangeWindowAttributes(display,mw,CWOverrideRedirect,&attrib);
  325.     XMapRaised(display,mw);
  326.  
  327.     if (colored)
  328.     {    scorew=XCreateSimpleWindow(display,ROOT,0,0,DWidth,DHeight,8,pixels[9],cols[DY>>(DYSHIFT+1)].pixel);
  329.     }
  330.     else
  331.     {    scorew=XCreateSimpleWindow(display,ROOT,0,0,DWidth,DHeight,8,BlackPixelOfScreen(screen),WhitePixelOfScreen(screen));
  332.          XSetWindowBorderPixmap(display,scorew,grey[5]);
  333.     }
  334.     XSelectInput(display,scorew,ExposureMask);
  335.     XChangeWindowAttributes(display,scorew,CWOverrideRedirect,&attrib);
  336. }
  337.  
  338. /*************
  339.  * MAIN-LOOP *
  340.  *************/
  341.     for(;;)
  342.     switch(mess=readint(master))
  343.     {    int    len,signs;
  344.  
  345.     case GAMESTART:
  346. /* weitere Informationen zum aktuellen Spiel holen */
  347.         players=readint(master);    /* Anzahl der Spieler */
  348.         active=readint(master);        /* Flag, ob eigener Spieler rechnergesteuert */
  349.         game_num=readint(master);    /* Spielezaehler */
  350.  
  351.         start_flag=readint(master);    /* Flag, ob man fuer das erste Datagramm im Ring sorgen soll */
  352.  
  353. /* Socket-Adresse des naechsten Spielers im Ring empfangen */
  354.         readstring(master,next_host,19);
  355.         next_port=htons(readshort(master));
  356.         init_addr(&next_sin,next_host,next_port);
  357.         if (messflag)
  358.         {    printf("%s: start of game %d with %d players (start_flag=%d)\n",my_host,game_num,players,start_flag);
  359.             printf("%s: next port is %s@%d\n",my_host,next_host,(int)ntohs(next_port));
  360.             fflush(stdout);
  361.         }
  362.         prepare_to_start();
  363.  
  364. #if (moremess==1)
  365.     printf("%s: received players: %d active: %d start: %d.\n",my_host,players,active,start_flag);
  366.     fflush(stdout);
  367. #endif
  368.  
  369. /* ausgewaehlter Spieler initialisiert Packet-Struktur und sendet sie in den Ring */
  370.         p.mode=(short)SETUP;
  371.         if (start_flag)
  372.         {    p.game_count=(short)0;
  373.             p.players=(short)players;
  374.             p.ready=(short)0;
  375.             p.game_number=(short)game_num;
  376.             for (i=0;i<MAXPLAYERS;i++)
  377.                 for (j=0;j<DIMENSION;j++)
  378.                 {    p.x[i][j]=posx= (P_TYPE)NONE;
  379.                     p.y[i][j]=posy= (P_TYPE)NONE;
  380.                 };
  381.             write_p();
  382.          }
  383.  
  384. /* Schleife fuer Ausfuehrung eines Zuges */
  385. #if (times==0)
  386.         while(make_move());
  387. #else
  388.     /*************************************************************************
  389.      * Testprogramm zur Messung der Umlaufzeit des Datagramms durch den Ring *
  390.      *************************************************************************/
  391.      
  392.         for (t_count=0;t_count<=MAXMESS;t_count++)
  393.         {    gettimeofday(&tfield[t_count],&zone);
  394.             while (read_p());
  395.             write_p();
  396.         };
  397.         if (start_flag)
  398.         {    FILE            *fopen(),*fp;
  399.             fp=fopen("sockets/time_file","w");
  400.             for (t_count=1;t_count<=MAXMESS;t_count++)
  401.             {    long    t;
  402.             
  403.                 t=((tfield[t_count].tv_sec & 0xffff)*1000000 + tfield[t_count].tv_usec)
  404.                 -((tfield[t_count-1].tv_sec & 0xffff)*1000000 + tfield[t_count-1].tv_usec);
  405.                 fprintf(fp,"%3d: %8ld usec\n",t_count,t);
  406.             };
  407.             fclose(fp);
  408.             printf("%s: Timefile written.\n",my_host);
  409.             fflush(stdout);
  410.         };
  411. #endif
  412.         if (!auto_only)        XUngrabServer(display);
  413.         break;
  414.     case SCORE:
  415.         read_scores();                /* Stringfeld lesen und ausgeben */
  416.         if (!auto_only)        redraw_scores();
  417.         break;
  418.     case EXIT:
  419.         printf("%s: program ends.\n",my_host);    /* Programm beenden */
  420.         exit(0);
  421.         break;
  422.     case UNMAP:
  423.         if (auto_only)        break;
  424.         XUnmapWindow(display,scorew);        /* Punktefenster vom Bildschirm entfernen */
  425.         XUnmapWindow(display,backw);
  426.         XFlush(display);
  427.         break;
  428.     default:
  429.         fprintf(stderr,"%s: received unknown instruction (%d) from master.\n",my_host,mess);
  430.         break;
  431.     };
  432. }
  433.  
  434. /********************
  435.  * Stringfeld lesen *
  436.  ********************/
  437.  
  438. read_scores()
  439. {    int    l;
  440.  
  441.     max_col=0;
  442.     lines=readint(master);
  443.  
  444.     for (l=0;l<lines;l++)
  445.     {    readstring(master,&tscreen[l][0],80);
  446.         if (strlen(tscreen[l])>max_col)
  447.             max_col=strlen(tscreen[l]);
  448.     };
  449. }
  450.  
  451. /***********************
  452.  * Stringfeld ausgeben *
  453.  ***********************/
  454.  
  455. redraw_scores()
  456. {    int    x_wsize,y_wsize;
  457.     int    l;
  458.     XEvent    event;
  459.  
  460.     if (auto_only)        return;
  461.  
  462.     XUnmapWindow(display,scorew);
  463.     x_wsize=CharWidth(FID)  * (2+max_col);
  464.     y_wsize=CharHeight(FID) * (2+lines);
  465.     XMoveResizeWindow(display,scorew,(DWidth-x_wsize)>>1,(DHeight-y_wsize)>>1,x_wsize,y_wsize);
  466.     XMapRaised(display,scorew);
  467. /*    XWindowEvent(display,scorew,ExposureMask,&event);    */
  468.     if (colored)
  469.     {    int    xw=1,i;
  470.         int    sdx=(x_wsize>>5);
  471.         int    y0,y1;
  472.  
  473.         y0=0;
  474.         for (i=0;i<32;i++)
  475.         {    y1 = y_wsize*(i+1)/32;
  476.             XSetForeground(display,gc_filler,cols[(DY>>DYSHIFT)*(31-i)/32].pixel);
  477.             XFillRectangle(display,scorew,gc_filler,0,y0,xw*sdx,y1-y0);
  478.             y0=y1;
  479.         }
  480.         do
  481.         {    XCopyArea(display,scorew,scorew,gc_filler,
  482.                 0,0,xw*sdx,y_wsize,xw*sdx,0);
  483.             xw<<=1;
  484.         }
  485.         while (xw<=32);
  486.     }
  487.     else
  488.     {    XClearWindow(display,scorew);
  489.     }
  490.     aw=scorew;
  491.  
  492.     for (l=0;l<lines;l++)
  493.     {    printat(1,l+1,tscreen[l],FID);
  494.     };
  495.     XFlush(display);
  496. }
  497.  
  498. /**********************
  499.  * Spielfeld loeschen *
  500.  **********************/
  501.  
  502. empty_all()
  503. {    int    x,y;
  504.  
  505.     for (x=0;x<DX;x++)
  506.         for (y=0;y<DY;y++)
  507.             field[x][y]=0;
  508.     for (x=0;x<DX;x++)
  509.     {    field[x][0]= -1;
  510.         field[x][DY-1]= -1;
  511.     };
  512.     for (y=0;y<DY;y++)
  513.     {    field[0][y]= -1;
  514.         field[DX-1][y]= -1;
  515.     };
  516. }
  517.  
  518. /*****************************************
  519.  * Vorbereitungen zum Spielstart treffen *
  520.  *****************************************/
  521.  
  522. prepare_to_start()
  523. {    int    i;
  524.     XEvent    event;
  525.  
  526.     empty_all();
  527.     if (active==1)
  528.     {    XGrabServer(display);
  529.         XMapRaised(display,backw);
  530. /*        XWindowEvent(display,mw,ExposureMask,&event);    */
  531.         XClearWindow(display,mw);
  532.  
  533.         if (colored)
  534.         {    int    xw = 1;
  535.  
  536.             for (i=0;i<(DY>>DYSHIFT);i++)
  537.             {    XSetForeground(display,gc_filler,cols[i].pixel);
  538.                 XFillRectangle(display,mw,gc_filler,0,y_size+i*(y_size<<DYSHIFT),xw*x_size,(y_size<<DYSHIFT));
  539.             }
  540.             do
  541.             {    XCopyArea(display,mw,mw,gc_filler,
  542.                     0,0,xw*x_size,MWHeight,xw*x_size,0);
  543.                 xw<<=1;
  544.             }
  545.             while (xw<DX);
  546.  
  547.             XSetForeground(display,gc_filler,pixels[9]);
  548.             XFillRectangle(display,mw,gc_filler,0,0,MWWidth,y_size-1);
  549.             XFillRectangle(display,mw,gc_filler,0,MWHeight-y_size,MWWidth,y_size);
  550.             XFillRectangle(display,mw,gc_filler,0,0,x_size-1,MWHeight);
  551.             XFillRectangle(display,mw,gc_filler,MWWidth-x_size,0,x_size,MWHeight);
  552.         }
  553.         else
  554.         {    XFillRectangle(display,mw,gc_clear,0,0,MWWidth-1,y_size-1);
  555.             XFillRectangle(display,mw,gc_clear,0,MWHeight-y_size,MWWidth-1,y_size-1);
  556.             XFillRectangle(display,mw,gc_clear,0,0,x_size-1,MWHeight-1);
  557.             XFillRectangle(display,mw,gc_clear,MWWidth-x_size,0,x_size-1,MWHeight-1);
  558.         }
  559.         XFlush(display);
  560.     };
  561.     
  562.     writeint(master,PLAYER_READY);    
  563.     dx = 0;
  564.     dy = 0;
  565.     fast = 0;
  566.     boost = 0;
  567.     ready = 0;
  568.     wait = 0;
  569.     winner = 0;    
  570.  
  571.     jmp_count = 10;
  572.  
  573.     lastmove=0;
  574.     actmove=0;
  575.  
  576.  
  577.     if (!auto_only)
  578.     {    XSync(display,1);
  579.         while(XPending(display))    XNextEvent(display,&event);
  580.     }
  581.  
  582. }
  583.  
  584. /*** Datagramm schreiben ***/
  585.  
  586. write_p()
  587. {
  588.     p.mode        = htons(p.mode);
  589.     p.game_count  = htons(p.game_count);
  590.     p.game_number = htons(p.game_number);
  591.     p.players     = htons(p.players);
  592.     p.ready       = htons(p.ready);
  593.     sendto(next,&p,sizeof (Pack),0,&next_sin,sizeof next_sin);
  594.     p.mode        = ntohs(p.mode);
  595.     p.game_count  = ntohs(p.game_count);
  596.     p.game_number = ntohs(p.game_number);
  597.     p.players     = ntohs(p.players);
  598.     p.ready       = ntohs(p.ready);
  599. }
  600.  
  601. /*** Datagramm lesen (Fehler bei Wartezeit>5 Sekunden) ***/
  602.  
  603. read_p()
  604. {
  605.     int    nfound,readfds,writefds,execptfds;
  606. struct    timeval    timeout;
  607.     int    fromlen=0;
  608.  
  609.     readfds=(1<<next);
  610.     writefds=execptfds=0;
  611.     /* bei angefangenem Spiel Timeout nach 5 Sekunden */
  612.     timeout.tv_sec=(p.mode!=(short)PLAY)?(long)60:(long)5;
  613.     timeout.tv_usec=(long)0;
  614.  
  615.     nfound=select(32,&readfds,&writefds,&execptfds,&timeout);
  616.  
  617.     if (nfound<=0)        return(1);
  618.     else
  619.     {    recvfrom(next,&p,sizeof (Pack),0,NULL,&fromlen);
  620.         p.mode        = ntohs(p.mode);
  621.         p.game_count  = ntohs(p.game_count);
  622.         p.game_number = ntohs(p.game_number);
  623.         p.players     = ntohs(p.players);
  624.         p.ready       = ntohs(p.ready);
  625.         return(0);
  626.     };
  627. }
  628.  
  629. /*****************************************
  630.  * einen kompletten Spielzug ausfuehren: *
  631.  * - Datagramm empfangen         *
  632.  * - Spielfeld aktualisieren         *
  633.  * - Eingabeevents auswerten         *
  634.  * - eigenen Zug ausfuehren         *
  635.  * - Datagramm senden             *
  636.  * - Bildschirm aktualisieren         *
  637.  *****************************************/
  638.  
  639. make_move()
  640. {
  641. int    i,j;
  642. int    root_x,root_y,mx,my;
  643. Window    root,child;
  644. int    mask;
  645.  
  646. /* Packet holen */
  647.     do
  648.     {
  649.         if (read_p())
  650.         {    missing_datagram();
  651.             return(0);
  652.         };
  653.     }
  654.     while (game_num != (int)p.game_number);
  655.  
  656.     p.game_count++;
  657.  
  658.     if (p.mode & (short)GAME_OVER)
  659.     {    if (!(winner))    write_p();    /* Alle ausser dem Sieger leiten das Packet noch einmal weiter */
  660.         return(0);
  661.     };
  662.  
  663.     if (p.mode & (short)(SETUP | AUTO_START))
  664.     {    if ((p.players==(short)0) && (active==1))
  665.         {    XBell(display,0);
  666.             XFlush(display);
  667.         };
  668.  
  669.         if (start_flag)
  670.         {    if (p.game_count>(short)400)    p.mode=(short)AUTO_START;
  671.         };
  672.  
  673.         if (wait)
  674.         {    sleep(2);
  675.             wait=0;
  676.             p.mode=(short)PLAY;
  677.             p.players=(short)players;
  678.         };
  679.  
  680.     };
  681.  
  682.     if (active==0)
  683.     {    write_p();
  684.         return(1);
  685.     };
  686.  
  687. /* Zug ausfuehren */
  688.  
  689. /* a.) neue Positionen ins Spielfeld eintragen */
  690.     for (i=0;i<MAXPLAYERS;i++)
  691.         if (p.ready & (short)(1<<i))
  692.         {    if (p.x[i][0]!=(P_TYPE)NONE)
  693.         {    field[p.x[i][0]][p.y[i][0]]=i+1;
  694.             if (p.x[i][1]!=(P_TYPE)NONE)
  695.             {    field[p.x[i][1]][p.y[i][1]]=i+1;
  696.                 if (p.x[i][2]!=(P_TYPE)NONE)
  697.                 {    field[p.x[i][2]][p.y[i][2]]=i+1;
  698.                     if (p.x[i][3]!=(P_TYPE)NONE)
  699.                         field[p.x[i][3]][p.y[i][3]]=i+1;
  700.                 };
  701.             };
  702.         };
  703.         }
  704.         else
  705.         {    if (p.x[i][0]!=(P_TYPE)NONE)
  706.         {    field[p.x[i][0]][p.y[i][0]]=0;
  707.             if (p.x[i][1]!=(P_TYPE)NONE)
  708.             {    field[p.x[i][1]][p.y[i][1]]=0;
  709.                 if (p.x[i][2]!=(P_TYPE)NONE)
  710.                 {    field[p.x[i][2]][p.y[i][2]]=0;
  711.                     if (p.x[i][3]!=(P_TYPE)NONE)
  712.                         field[p.x[i][3]][p.y[i][3]]=0;
  713.                 };
  714.             };
  715.         };
  716.         };
  717.         
  718. /* Computerspiel ? */
  719.     if (active==2)
  720.     {    comp_move();
  721.         write_p();
  722.         return(1);
  723.     };
  724.  
  725. /* b.) MausEvent auswerten */
  726.     if (XPending(display)!=0)    execute_event();
  727.  
  728. /* Spieler automatisch setzen, wenn er es nicht selbst tut. */
  729.     if ((p.mode & (short)AUTO_START) && (ready==0))
  730.     {    XQueryPointer(display,mw,&root,&child,&root_x,&root_y,&mx,&my,&mask);
  731.         setplayer((P_TYPE)(mx / x_size),(P_TYPE)(my / y_size),1);
  732.     };
  733.  
  734. /* c.) eigenen Zug ausfuehren */
  735.     if (p.mode & (short)PLAY)
  736.     {    if (ready)
  737.         {    move(0);
  738.  
  739. /* bei gedrueckter mittlerer Taste schnellere Fahrt */
  740.             if (fast)
  741.             {    if (XPending(display)!=0)    execute_event();
  742.                 move(1);
  743.  
  744.                 if (boost)
  745.                 {    if (XPending(display)!=0)    execute_event();
  746.                     move(2);
  747.                     if (XPending(display)!=0)    execute_event();
  748.                     move(3);
  749.                 }
  750.                 else
  751.                 {    p.x[my_count][2]= (P_TYPE)NONE;
  752.                     p.y[my_count][2]= (P_TYPE)NONE;
  753.                     p.x[my_count][3]= (P_TYPE)NONE;
  754.                     p.y[my_count][3]= (P_TYPE)NONE;
  755.                 };
  756.             }
  757.             else
  758.             {    p.x[my_count][1]= (P_TYPE)NONE;
  759.                 p.y[my_count][1]= (P_TYPE)NONE;
  760.             };
  761.         }
  762.         else if (actmove!=lastmove)    deleter();
  763.         else p.x[my_count][0]=(P_TYPE)NONE;
  764.         
  765.  
  766.     };
  767.     
  768. /* Packet senden */
  769.     write_p();
  770.  
  771. /* Bildschirm bearbeiten */
  772.     for (i=0;i<MAXPLAYERS;i++)
  773.         if (p.ready & (short)(1<<i))
  774.         {    if (p.x[i][0]!=(P_TYPE)NONE)
  775.         {    if (colored)    XSetForeground(display,gc_filler,pixels[i]);
  776.             else        XSetTile(display,gc_filler,grey[i]);
  777.             XFillRectangle(display,mw,gc_filler,p.x[i][0]*x_size,p.y[i][0]*y_size,x_size-1,y_size-1);
  778.             if (p.x[i][1]!=(P_TYPE)NONE)
  779.             {    XFillRectangle(display,mw,gc_filler,p.x[i][1]*x_size,p.y[i][1]*y_size,x_size-1,y_size-1);
  780.                 if (p.x[i][2]!=(P_TYPE)NONE)
  781.                 {    XFillRectangle(display,mw,gc_filler,p.x[i][2]*x_size,p.y[i][2]*y_size,x_size-1,y_size-1);
  782.                     if (p.x[i][3]!=(P_TYPE)NONE)
  783.                     {    XFillRectangle(display,mw,gc_filler,p.x[i][3]*x_size,p.y[i][3]*y_size,x_size-1,y_size-1);
  784.                     };
  785.                 };
  786.             };
  787.         };
  788.         }
  789.         else
  790.         {    if (colored)
  791.         {   if (p.x[i][0]!=(P_TYPE)NONE)
  792.             {    XSetForeground(display,gc_filler,cols[p.y[i][0]>>DYSHIFT].pixel);
  793.             XFillRectangle(display,mw,gc_filler,p.x[i][0]*x_size,p.y[i][0]*y_size,x_size-1,y_size-1);
  794.             if (p.x[i][1]!=(P_TYPE)NONE)
  795.             {    XSetForeground(display,gc_filler,cols[p.y[i][1]>>DYSHIFT].pixel);
  796.                 XFillRectangle(display,mw,gc_filler,p.x[i][1]*x_size,p.y[i][1]*y_size,x_size-1,y_size-1);
  797.                 if (p.x[i][2]!=(P_TYPE)NONE)
  798.                 {    XSetForeground(display,gc_filler,cols[p.y[i][2]>>DYSHIFT].pixel);
  799.                     XFillRectangle(display,mw,gc_filler,p.x[i][2]*x_size,p.y[i][2]*y_size,x_size-1,y_size-1);
  800.                     if (p.x[i][3]!=(P_TYPE)NONE)
  801.                     {    XSetForeground(display,gc_filler,cols[p.y[i][3]>>DYSHIFT].pixel);
  802.                         XFillRectangle(display,mw,gc_filler,p.x[i][3]*x_size,p.y[i][3]*y_size,x_size-1,y_size-1);
  803.                     }
  804.                 };
  805.             };
  806.             }
  807.         }
  808.         else
  809.         {   if (p.x[i][0]!=(P_TYPE)NONE)
  810.             {    XFillRectangle(display,mw,gc_set,p.x[i][0]*x_size,p.y[i][0]*y_size,x_size-1,y_size-1);
  811.             if (p.x[i][1]!=(P_TYPE)NONE)
  812.             {    XFillRectangle(display,mw,gc_set,p.x[i][1]*x_size,p.y[i][1]*y_size,x_size-1,y_size-1);
  813.                 if (p.x[i][2]!=(P_TYPE)NONE)
  814.                 {    XFillRectangle(display,mw,gc_set,p.x[i][2]*x_size,p.y[i][2]*y_size,x_size-1,y_size-1);
  815.                     if (p.x[i][3]!=(P_TYPE)NONE)
  816.                         XFillRectangle(display,mw,gc_set,p.x[i][3]*x_size,p.y[i][3]*y_size,x_size-1,y_size-1);
  817.                 };
  818.             };
  819.             }
  820.         }
  821.         };
  822.  
  823.     XSync(display,0);
  824.     return(1);
  825. }
  826.  
  827. /********************************************************************
  828.  * Automatisches Setzen des Spielers, wenn Wartezeit ueberschritten *
  829.  ********************************************************************/
  830.  
  831. setplayer(mx,my,again)
  832.     P_TYPE    mx,my;
  833.     int    again;
  834. {
  835.     do
  836.     {    if ((mx>0) && (mx<DX-1) && (my>0) && (my<DY-1) && (field[mx][my]==0))
  837.         {    xmove[lastmove  ]= posx = p.x[my_count][0] = mx;
  838.             ymove[lastmove++]= posy = p.y[my_count][0] = my;
  839.             field[mx][my]=my_count+1;
  840.             if ((--p.players) == 0)        wait=1;
  841.             else                wait=0;
  842.             ready = 1;
  843.             p.ready |= (short)(1<<my_count);
  844.             again = 0;
  845.         };
  846.         if (again)
  847.         {    if ((mx<(DX>>1)) || (again>10))    mx++;
  848.             else                mx--;
  849.             if (my<(DY>>1))            my++;
  850.             else                my--;
  851.             again++;
  852.         };
  853.     }
  854.     while(again);
  855. }
  856.  
  857. /********************
  858.  * Event bearbeiten *
  859.  ********************/
  860.  
  861. execute_event()
  862. {    int    help;
  863.  
  864. XEvent    event;
  865.  
  866.     int    fct=0;
  867.  
  868. do
  869. {
  870.     XNextEvent(display,&event);
  871.  
  872.     switch (event.type)
  873.     {
  874.     case ButtonPress:
  875.         switch((int)event.xbutton.button)
  876.         {
  877.         case Button3:
  878.             if (!(boost))    fct=2;
  879.             break;
  880.         case Button2:
  881.             if ((ready == 0) && (p.mode & (short)SETUP))
  882.             {    P_TYPE    mx,my;
  883.                 setplayer((P_TYPE)(event.xbutton.x / x_size),(P_TYPE)(event.xbutton.y / y_size),0);
  884.             }
  885.             else
  886.                 fct=3;
  887.             break;
  888.         case Button1:
  889.             if (!(boost))    fct=1;
  890.             break;
  891.         };    /* end switch(button) */
  892.         break;    /* end ButtonPress */
  893.  
  894.     case KeyPress:
  895.     {    char    sign;
  896.         KeySym    keysym;
  897.  
  898. static Time    last_time;
  899.         
  900.         XLookupString(&event,&sign,1,&keysym,NULL);
  901.  
  902.         if ((event.xkey.time==last_time) || (event.xkey.time==last_time + 1))        break;
  903.  
  904.         switch(keysym)
  905.         {
  906. /*** KEYS to turn left ***/
  907.         case XK_Z:
  908.         case XK_z:
  909.         case XK_X:
  910.         case XK_x:
  911.         case XK_M:
  912.         case XK_m:
  913.         case XK_less:
  914.         case XK_comma:
  915.             fct=1;
  916.             last_time=event.xkey.time;
  917.             break;
  918.  
  919. /*** KEYS to turn right ***/
  920.         case XK_C:
  921.         case XK_c:
  922.         case XK_V:
  923.         case XK_v:
  924.         case XK_greater:
  925.         case XK_period:
  926.         case XK_question:
  927.         case XK_slash:
  928.             fct=2;
  929.             last_time=event.xkey.time;
  930.             break;
  931.  
  932. /*** jump ***/
  933.         case XK_space:
  934.             fct=3;
  935.             break;
  936. /*** double speed ***/
  937.         case XK_Shift_L:
  938.             fast=1; boost=0; break;
  939.             break;
  940.  
  941. /*** double double speed ***/
  942.         case XK_Control_L:
  943.             fast=boost=((event.xkey.state & ShiftMask)?1:0);
  944.             break;
  945.         };
  946.     };
  947.     break;
  948.  
  949.     case    KeyRelease:
  950.     {    char    sign;
  951.         KeySym    keysym;
  952.  
  953.         XLookupString(&event,&sign,1,&keysym,NULL);
  954.         switch(keysym)
  955.         {
  956.         case XK_Shift_L:    fast=0; boost=0; break;
  957.         case XK_Control_L:    fast=((event.xkey.state & ShiftMask)?1:0); boost=0; break;
  958.         };
  959.     };
  960.     };
  961. }
  962. while ((XPending(display)) && (event.type==KeyRelease));
  963.  
  964.     switch(fct)
  965.     {
  966.     case 1:    
  967.             help= dx ;
  968.             dx = dy ;
  969.             dy = -help;
  970.             break;
  971.     case 2:
  972.             help=dy ;
  973.             dy =dx ;
  974.             dx = -help;
  975.             break;
  976.     case 3:
  977.             if (jmp_count == 0)
  978.             {    XBell(display,80);
  979.             }
  980.             else
  981.             {
  982.             posx += (P_TYPE)(3*dx) ;
  983.             posy += (P_TYPE)(3*dy) ;
  984.             jmp_count--;
  985.             }
  986.             break;
  987.     };    /* end switch(fct) */
  988. }
  989.  
  990. /********************************
  991.  * bust - Spieler ist zerstoert *
  992.  ********************************/
  993.  
  994. bust()
  995. {    if (active==1)
  996.     {    XBell(display,40);
  997.         XFlush(display);
  998.     };
  999.     ready = 0;
  1000.     p.ready &= (short)~(1<<my_count);
  1001.     p.x[my_count][0]= (P_TYPE)NONE;
  1002.  
  1003.     if (--p.players==0)
  1004.     {    p.mode=(short)GAME_OVER;    /* falls letzter Spieler => Spiel ist aus */
  1005.         winner=1;
  1006.     };
  1007.     writeint(master,DESTROYED);
  1008.     writeint(master,(int)p.game_count);
  1009. }
  1010.  
  1011. missing_datagram()
  1012. {
  1013.     writeint(master,ERROR);
  1014. }
  1015.  
  1016. /*********************************************************************************
  1017.  * Zug ausfuehren (ind = Index bei gleichzeitigen Zuegen (maxmal 4 bei boost=1)) *
  1018.  *********************************************************************************/
  1019.  
  1020. move(ind)
  1021.     int    ind;
  1022. {    int    root_x,root_y,mx,my;
  1023.     Window    root,child;
  1024.     int    mask;
  1025.  
  1026.     if ((dx == 0) && (dy == 0))
  1027.     {    XQueryPointer(display,mw,&root,&child,&root_x,&root_y,&mx,&my,&mask);
  1028.         mx= (mx/x_size-posx );
  1029.         my= -(my/y_size-posy );
  1030.         if (mx>my)
  1031.         {    if (mx> -my)
  1032.             {    dx =1; dy =0; }
  1033.             else
  1034.             {    dx =0; dy =1; }
  1035.         }
  1036.         else
  1037.         {    if (mx> -my)
  1038.             {    dx =0;   dy = -1; }
  1039.             else
  1040.             {    dx = -1; dy =0;   };
  1041.         };
  1042.         fast = (mask & ShiftMask)?1:0;
  1043.         boost = ((mask & ControlMask)&&(fast))?1:0;
  1044.     };
  1045.     posx += (P_TYPE)dx ;
  1046.     posy += (P_TYPE)dy ;
  1047.  
  1048.     if ((posx!=(P_TYPE)0) && (posy!=(P_TYPE)0) && (posx<(P_TYPE)DX-1) && (posy<(P_TYPE)DY-1) && (field[posx][posy]==0) && ((p.players>(short)1) || (players==1)))
  1049.     {    field[posx][posy]=my_count+1;
  1050.         xmove[lastmove]  =p.x[my_count][ind]=posx;
  1051.         ymove[lastmove++]=p.y[my_count][ind]=posy;
  1052.     }
  1053.     else if (ind==0)    bust();
  1054.     else
  1055.     {    posx -= (P_TYPE)dx ;
  1056.         posy -= (P_TYPE)dy ;
  1057.     };
  1058. }
  1059.  
  1060. /************************************
  1061.  * zu loeschende Felder vorbereiten *
  1062.  ************************************/
  1063.  
  1064. deleter()
  1065. {    int    i;
  1066.  
  1067.     for (i=0;i<DIMENSION;i++)
  1068.     {    if (actmove<lastmove)
  1069.         {    p.x[my_count][i]=xmove[actmove];
  1070.             p.y[my_count][i]=ymove[actmove++];
  1071.         }
  1072.         else
  1073.         {    p.x[my_count][i]=(P_TYPE)NONE;
  1074.             p.y[my_count][i]=(P_TYPE)NONE;
  1075.         };
  1076.     }
  1077. }    
  1078.  
  1079. /***************************
  1080.  * Computerzug-Algorithmus *
  1081.  ***************************/
  1082.      
  1083. changedir()
  1084. {    int    dir[4],dir2[4],r1,r2,ok;
  1085.  
  1086.     dir2[0]=(dir[0]=(field[posx+1][posy  ]==0)) & (field[posx+2][posy  ]==0);
  1087.     dir2[1]=(dir[1]=(field[posx  ][posy+1]==0)) & (field[posx  ][posy+2]==0);
  1088.     dir2[2]=(dir[2]=(field[posx-1][posy  ]==0)) & (field[posx-2][posy  ]==0);
  1089.     dir2[3]=(dir[3]=(field[posx  ][posy-1]==0)) & (field[posx  ][posy-2]==0);
  1090.  
  1091.     r1=r2=(random() & 3);
  1092.     ok=0;
  1093.     do
  1094.     {    if (dir2[r1])
  1095.         {    ok=1;
  1096.             break;
  1097.         };
  1098.     }
  1099.     while ((r1= ((r1+1)&3))!=r2);
  1100.  
  1101.     if (ok==0)
  1102.         do
  1103.         {    if (dir[r1]) break;
  1104.         }
  1105.         while ((r1= ((r1+1)&3))!=r2);
  1106.     
  1107.     switch(r1)
  1108.     {
  1109.     case 0:        dx=  1; dy=  0; break;
  1110.     case 1:        dx=  0; dy=  1; break;
  1111.     case 2:        dx= -1; dy=  0; break;
  1112.     case 3:
  1113.     default:    dx=  0; dy= -1; break;
  1114.     };
  1115.  
  1116.     posx+=(P_TYPE)dx;
  1117.     posy+=(P_TYPE)dy;
  1118. }
  1119.  
  1120. comp_move()
  1121. {
  1122.     if (p.mode==(short)PLAY)
  1123.     {    if (ready)
  1124.          {
  1125.         if ((dx==0) && (dy==0))
  1126.         {    switch(random() & 3)
  1127.             {
  1128.             case 0:        dx=  1; dy=  0; break;
  1129.             case 1:        dx=  0; dy=  1; break;
  1130.             case 2:        dx= -1; dy=  0; break;
  1131.             case 3:
  1132.             default:    dx=  0; dy= -1; break;
  1133.             };
  1134.         };
  1135.         if ((random()%30)>0)
  1136.         {    int    helpx,helpy;
  1137.  
  1138.             if (field[helpx=((int)posx+dx)][helpy=((int)posy+dy)]==0)
  1139.             {    if (field[helpx+dx][helpy+dy]==0)
  1140.                 {    posx=(P_TYPE)helpx;
  1141.                     posy=(P_TYPE)helpy;
  1142.                 }
  1143.                 else
  1144.                     changedir();
  1145.             }
  1146.             else
  1147.                 changedir();
  1148.         }
  1149.         else
  1150.                 changedir();
  1151.             
  1152.         if ((field[posx][posy]==0) && ((p.players>(short)1) || (players==1)))
  1153.         {    field[posx][posy]=my_count+1;
  1154.             xmove[lastmove]  =p.x[my_count][0]=posx;
  1155.             ymove[lastmove++]=p.y[my_count][0]=posy;
  1156.         }
  1157.         else    bust();
  1158.          }
  1159.          else if (actmove!=lastmove)    deleter();
  1160.          else p.x[my_count][0]=(P_TYPE)NONE;
  1161.     }
  1162.     else if ((p.mode==(short)SETUP) && (ready==0))
  1163.     {
  1164.         setplayer(1+(random()%(DX-2)),1+(random()%(DY-2)),1);
  1165.     };
  1166. }
  1167.