home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume15 / xtb / part01 / xtb.c < prev   
C/C++ Source or Header  |  1993-01-27  |  31KB  |  1,425 lines

  1. /*
  2.  * X Client 
  3.  *
  4.  * $Header: /morpork/home/bmh/xtest2/RCS/xtb.c,v 1.41 92/10/19 15:34:32 bmh Exp Locker: bmh $
  5.  *
  6.  * Bernard Hatt
  7.  * Camtec Electronics (Ericsson), Leicester, England, LE1 4SA
  8.  * bmh@terminus.ericsson.se
  9.  *
  10.  */
  11. #include <stdio.h>
  12. #include <sys/types.h>
  13. #include <sys/wait.h>
  14. #include <sys/ioctl.h>
  15. #include <sys/time.h>
  16. #include <netinet/in.h>
  17. #include <unistd.h>
  18. #include <fcntl.h>
  19. #include <signal.h>
  20. #include <ctype.h>
  21. #include <math.h>
  22. #include <pwd.h>
  23. #include <errno.h>
  24.  
  25. #include <X11/X.h>
  26. #include <X11/Xlib.h>
  27. #include <X11/Xutil.h>
  28. #include <X11/cursorfont.h>
  29.  
  30. #include "defs.h"
  31. #include "comms.h"
  32.  
  33. #define xtb_width 64    /* bitmap for iconised window */
  34. #define xtb_height 64
  35. static char xtb_bits[] = {
  36.    0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  37.    0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
  38.    0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  39.    0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
  40.    0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  41.    0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
  42.    0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  43.    0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
  44.    0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  45.    0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
  46.    0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  47.    0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
  48.    0xf0, 0xff, 0x3f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x3f, 0x00,
  49.    0xc0, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x3f, 0x00, 0xc0, 0xff, 0xff, 0xff,
  50.    0xf0, 0xff, 0x3f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x00, 0x00,
  51.    0xc0, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
  52.    0x00, 0xfc, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x00, 0x00,
  53.    0xc0, 0xff, 0xff, 0xff, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, 0xff,
  54.    0x00, 0xf0, 0xff, 0x0f, 0xc0, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xff, 0x0f,
  55.    0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
  56.    0x00, 0xfc, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0xfc, 0x00, 0x00,
  57.    0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03,
  58.    0x00, 0xfc, 0x00, 0x00, 0x80, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x3f, 0x00,
  59.    0xe0, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0x3f, 0x00, 0xf0, 0xff, 0xe0, 0x7f,
  60.    0xf0, 0xff, 0x3f, 0x00, 0xf8, 0x0f, 0x00, 0xfe, 0xf0, 0xff, 0x3f, 0x00,
  61.    0xfc, 0x07, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0xf0,
  62.    0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
  63.    0x7e, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x80,
  64.    0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
  65.    0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x82, 0x0f, 0x00, 0x00, 0x00,
  66.    0x50, 0x00, 0x00, 0x81, 0x0f, 0x00, 0x00, 0x00, 0x88, 0x00, 0x80, 0x80,
  67.    0x0f, 0x00, 0x00, 0x00, 0x04, 0x01, 0x40, 0xc0, 0x0f, 0x00, 0x00, 0x00,
  68.    0x02, 0x02, 0x20, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x01, 0x04, 0x10, 0xc0,
  69.    0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0xc0, 0x07, 0x00, 0x00, 0x00,
  70.    0x00, 0x10, 0x04, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x80,
  71.    0x07, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x80, 0x0f, 0x00, 0x00, 0x00,
  72.    0x00, 0x80, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x80,
  73.    0x0f, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x0f, 0x00, 0x00, 0x00,
  74.    0x00, 0x10, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00,
  75.    0x3e, 0x00, 0x00, 0x80, 0x00, 0x04, 0x10, 0x00, 0x3e, 0x00, 0x00, 0x80,
  76.    0x01, 0x02, 0x20, 0x00, 0x7c, 0x00, 0x00, 0xc0, 0x02, 0x01, 0x40, 0x00,
  77.    0xfc, 0x00, 0x00, 0xe0, 0x84, 0x00, 0x80, 0x00, 0xf8, 0x01, 0x00, 0xf0,
  78.    0x48, 0x00, 0x00, 0x01, 0xf0, 0x07, 0x00, 0x7c};
  79.  
  80.  
  81. #define KeyMask (KeyPressMask|KeyReleaseMask)
  82. #define ButtonMask (ButtonPressMask|ButtonReleaseMask)
  83. #define MotionMask (PointerMotionMask)
  84.  
  85. #define MainEventMask (KeyMask|ButtonMask|ExposureMask|ButtonPressMask|ButtonReleaseMask)
  86. #define FieldEventMask (PointerMotionMask|MainEventMask|ButtonPressMask|ButtonReleaseMask)
  87.  
  88. Display *Disp;
  89. int Scr;    /* screen no. */
  90. Window    Win,Root;
  91. Window    RWin,FWin,SWin,QWin,AWin,MWin;    /* should have used an */
  92. Window    VSb,HSb;            /* array/structure for these */
  93. Window    RVSb,RHSb;
  94.  
  95. GC    GcF,GcB,GcTF,GcTB;
  96.  
  97.  
  98. #define BOARDER    8    /* boarder between windows */
  99. #define TANKPOINTS    20    /* number of points defining a tank */
  100.  
  101. typedef struct tank_struct
  102. {
  103.     XPoint    coord[TANKPOINTS];
  104. } TANK;
  105.  
  106. TANK Tank[TANKROT]=
  107. {{
  108.     {0,0},{T/2,-T},{T,0},{0,-T},{T,0},{0,4*T},{-T,0},{0,-T},{-T,0},{0,3*T},
  109.     {-T,0},{0,-3*T},{-T,0},{0,T},{-T,0},{0,-4*T},{T,0},{0,T},{T,0},{T/2,T}
  110. }};
  111.  
  112. PLAYER player[MAXUSERS];    /* players tanks */
  113. char    field[OBJECTSIZE][OBJECTSIZE];
  114. char    radar[OBJECTSIZE][OBJECTSIZE];
  115.  
  116. /* PIMAPS */
  117. #define PIXSIZE    48
  118. Pixmap TankPix[TANKROT];
  119.  
  120.  
  121. int fire=0;    /* fire button pressed */
  122. int motion=0;    /* tank linear motion */
  123. int mrot=0;    /* mouse pointer rotation */
  124. int damage=0;    /* damage sustained */
  125. char message[BUFLEN]="";    /* message for message window */
  126. char *server=NULL;
  127.  
  128. POSITION cur={0,300,100,0,0};
  129. POSITION garbage;
  130.  
  131. int pd[2];    /* pipe for passing current position */
  132.  
  133. int warpflag=0;    /* warp pointer on scrolling main screen */
  134. int invert=1;    /* invert motion buttons */
  135.  
  136. int polyflag=0;    /* use polygons to draw tanks */
  137. int pixflag=0;    /* use pixmaps to draw tanks */
  138.  
  139.  
  140. int myid;    /* my id */
  141.  
  142. int rsd,ssd;    /* receive and send socket descripters */
  143. DATA rdata,sdata;    /* receive and send data */
  144.  
  145. Time movetime=0;
  146. int savedx=(-1),savedy=(-1);
  147. int sfx=(-1),sfy=(-1);
  148. int msx,msy;    /* mouse x,y */
  149. int ex[MAXUSERS],ey[MAXUSERS],exptime[MAXUSERS];    /* explosions */
  150. int debug=0;
  151.  
  152. int ppid,cpid;
  153.  
  154.  
  155. char *progname;
  156.  
  157.  
  158. void
  159. signoff(t,reason)    /* send signoff to server and exit */
  160. int t,reason;
  161. {
  162.     sdata.id=OUTSWAP(myid);
  163.     sdata.type=OUTSWAP(T_SIGNOFF);
  164.     sdata.extra.signoff.reason=OUTSWAP(reason);
  165.     senddata(ssd,&sdata);
  166.     if(t!=0)
  167.         sleep(t);
  168.     if(getpid()==cpid)
  169.         kill(ppid,SIGKILL);
  170.     else
  171.         kill(cpid,SIGKILL);
  172.     exit(1);
  173. }
  174.  
  175. void
  176. dointr()    /* action on interrupt */
  177. {
  178.     signoff(0,DESTROYED);
  179. }
  180.  
  181. void
  182. doXio()
  183. {
  184.     signoff(0,QUIT);
  185. }
  186.  
  187. void
  188. timeout()    /* timeout on connect */
  189. {
  190.     fprintf(stderr,"%s: No response from server \"%s\" (not running/busy?)\n",progname,server);
  191.     exit(1);
  192. }
  193.  
  194. void
  195. doexplosions()    /* deal with on screen explosions */
  196. {
  197.     int i,j,k,tx,ty,td,rad;
  198.     for(i=0;i<MAXUSERS;i++)
  199.     {
  200.         if(exptime[i]!=(-1))
  201.         {
  202.             td=gettime()-exptime[i];
  203.             if(td>EXPTIME)
  204.             {
  205.                 exptime[i]=(-1);
  206.                 tx=ex[i]/OBJECTSCALE;
  207.                 ty=ey[i]/OBJECTSCALE;
  208.                 for(k=(-2);k<3;k++)
  209.                     for(j=(-2);j<3;j++)
  210.                         DrawFieldSq(tx+k,ty+j,1);
  211.                 if(damage>=MAXDAMAGE)
  212.                 {
  213.                     signoff(5,KILLED);
  214.                 }
  215.                 XFlush(Disp);
  216.             }
  217.             else
  218.             {
  219.                 if(td<=(EXPTIME/2))
  220.                 {
  221.                     rad=(td*EXPSIZE*2)/EXPTIME;
  222.                     XFillArc(Disp,FWin,GcF,ex[i]-(rad/2),ey[i]-(rad/2),rad,rad,0,360*64);
  223.                     XFlush(Disp);
  224.                 }
  225.                 else
  226.                 {
  227.                     rad=((td-(EXPTIME/2))*2*EXPSIZE)/EXPTIME;
  228.                     if(rad>0)
  229.                     {
  230.                         XFillArc(Disp,FWin,GcB,ex[i]-(rad/2),ey[i]-(rad/2),rad,rad,0,360*64);
  231.                         XFlush(Disp);
  232.                     }
  233.                 }
  234.             }
  235.         }
  236.     }
  237. }
  238.  
  239. void
  240. InitTables()    /* initialise data tables (generate 128 different tank polygons) */
  241. {
  242.     short i,j,x,y;
  243.     double xc,yc,angle,incr,theta,len;
  244.  
  245.     x=0;
  246.     y=0;
  247.     incr=(2*PI)/((double)TANKROT);
  248.  
  249.  
  250.     for(i=1;i<TANKPOINTS;i++)
  251.     {
  252.         x+=Tank[0].coord[i].x;
  253.         y+=Tank[0].coord[i].y;
  254.         Tank[0].coord[i].x=x;
  255.         Tank[0].coord[i].y=y;
  256.     }
  257.  
  258.     for(j=1;j<TANKROT;j++)
  259.         for(i=1;i<TANKPOINTS;i++)
  260.         {
  261.             angle=((double)j)*incr;
  262.             xc=(double)Tank[0].coord[i].x;
  263.             yc=(double)Tank[0].coord[i].y;
  264.             if(xc==0.0)
  265.             {
  266.                 if(yc>0)
  267.                     theta=(PI/2.0);
  268.                 else
  269.                     theta=(-PI/2.0);
  270.             }
  271.             else
  272.             {
  273.                 theta=atan2(yc,xc);
  274.             }
  275.  
  276.             len=hypot(xc,yc);
  277.             theta+=angle;
  278.             xc=len*cos(theta);
  279.             yc=len*sin(theta);
  280.             Tank[j].coord[i].x=(short)(xc+0.5);
  281.             Tank[j].coord[i].y=(short)(yc+0.5);
  282.         }
  283.     for(j=0;j<TANKROT;j++)
  284.     {
  285.         for(i=TANKPOINTS;i>0;i--)
  286.         {
  287.             x=Tank[j].coord[i-1].x;
  288.             y=Tank[j].coord[i-1].y;
  289.             Tank[j].coord[i].x-=x;
  290.             Tank[j].coord[i].y-=y;
  291.         }
  292.     }
  293. }
  294.  
  295.  
  296. void
  297. sendstatus()    /* send our status to the server */
  298. {
  299.     sdata.type=OUTSWAP(T_MOVE);
  300.     sdata.id=OUTSWAP(myid);
  301.     sdata.extra.move.rot=OUTSWAP(mrot);
  302.     sdata.extra.move.linear=OUTSWAP(motion);
  303.     sdata.extra.move.fire=OUTSWAP(fire);
  304. /*    printf("motion=%d invert=%d\n",motion,invert);*/
  305.     senddata(ssd,&sdata);
  306. }
  307.  
  308. void
  309. WipeTank(x,y,rot,id)    /* wipe a tank from the screen */
  310. int x,y,rot,id;
  311. {
  312.     int objx,objy;
  313.  
  314.     objx=x/OBJECTSCALE;
  315.     objy=y/OBJECTSCALE;
  316.     radar[objx][objy]=0;
  317.  
  318.     savedx=objx;
  319.     savedy=objy;
  320.     
  321.     x-=(cur.scx*OBJECTSCALE);
  322.     y-=(cur.scy*OBJECTSCALE);
  323.  
  324.     sfx=x/OBJECTSCALE;
  325.     sfy=y/OBJECTSCALE;
  326.  
  327.     if((sfx<(-1))||(sfy<(-1))||(sfx>(OBJX+1))||(sfy>(OBJY+1)))
  328.         return;
  329.     if(polyflag)
  330.     {
  331.         rot=(rot+TANKROT+(TANKROT/4))%TANKROT;
  332.         Tank[rot].coord[0].x=x;
  333.         Tank[rot].coord[0].y=y;
  334.         XFillPolygon(Disp,FWin,GcB,&Tank[rot],TANKPOINTS,Nonconvex,CoordModePrevious);
  335.     }
  336.     else
  337.     {
  338.         XCopyPlane(Disp,TankPix[rot],FWin,GcTB,0,0,PIXSIZE,PIXSIZE,x-(PIXSIZE/2),y-(PIXSIZE/2),0x1);
  339.     }
  340.  
  341.     if(id!=myid)
  342.         XFillRectangle(Disp,FWin,GcB,x-5,y-5,10,10);
  343. }
  344.  
  345. void
  346. DrawTank(x,y,rot,id)    /* draw a tank on the screen */
  347. int x,y,rot,id;
  348. {
  349.     int objx,objy,flag;
  350.     char str[2];
  351.  
  352.     objx=x/OBJECTSCALE;
  353.     objy=y/OBJECTSCALE;
  354.  
  355.     x-=(cur.scx*OBJECTSCALE);
  356.     y-=(cur.scy*OBJECTSCALE);
  357.  
  358.     flag=(!radar[savedx][savedy]);
  359.     radar[objx][objy]=1;
  360.  
  361.     if((savedx!=objx)||(savedy!=objy)||flag)
  362.     {
  363.         DrawRadarSq(savedx,savedy,1);
  364.         DrawRadarSq(objx,objy,1);
  365.     }
  366.  
  367.     objx=x/OBJECTSCALE;
  368.     objy=y/OBJECTSCALE;
  369.     if((objx<(-1))||(objy<(-1))||(objx>(OBJX+1))||(objy>(OBJY+1)))
  370.         return;
  371.  
  372.     if((savedx!=objx)||(savedy!=objy))
  373.     {
  374.         DrawFieldSq(sfx,sfy,0);
  375.     }
  376.     if(polyflag)
  377.     {
  378.         rot=(rot+TANKROT+(TANKROT/4))%TANKROT;
  379.         Tank[rot].coord[0].x=x;
  380.         Tank[rot].coord[0].y=y;
  381.         XFillPolygon(Disp,FWin,GcF,&Tank[rot],TANKPOINTS,Nonconvex,CoordModePrevious);
  382.     }
  383.     else
  384.     {
  385.         XCopyPlane(Disp,TankPix[rot],FWin,GcTF,0,0,PIXSIZE,PIXSIZE,x-(PIXSIZE/2),y-(PIXSIZE/2),0x1);
  386.     }
  387.     if(id!=myid)
  388.     {
  389.         XFillRectangle(Disp,FWin,GcB,x-5,y-6,10,11);
  390.         str[1]='\0';
  391.         str[0]=id+BASECHAR;
  392.         XDrawString(Disp,FWin,GcF,x-2,y+3,str,1);
  393.     }
  394. }
  395.  
  396. DrawFieldSq(i,j,clear)    /* draw a square on the battlefield */
  397. int i,j;
  398. int clear;
  399. {
  400.     int x1,x2,y1,y2,mx,my;
  401.     switch(field[i+cur.scx][j+cur.scy])
  402.     {
  403.     case CLEAR:
  404.         if(clear)
  405.         {
  406.             x1=(i*OBJECTSCALE);
  407.             y1=(j*OBJECTSCALE);
  408.             XFillRectangle(Disp,FWin,GcB,x1,y1,OBJECTSCALE,OBJECTSCALE);
  409.         }
  410.         break;
  411.     case ROUGH:
  412.         x1=(i*OBJECTSCALE);
  413.         y1=(j*OBJECTSCALE);
  414.         x2=x1+OBJECTSCALE-1;
  415.         y2=y1+OBJECTSCALE-1;
  416.         mx=(x1+x2)/2;
  417.         my=(y1+y2)/2;
  418.         if(clear)
  419.             XFillRectangle(Disp,FWin,GcB,x1,y1,OBJECTSCALE,OBJECTSCALE);
  420.         XDrawLine(Disp,FWin,GcF,x1,y1,x2,y2);
  421.         XDrawLine(Disp,FWin,GcF,x1,y2,x2,y1);
  422.         XDrawLine(Disp,FWin,GcF,mx,y1,x1,my);
  423.         XDrawLine(Disp,FWin,GcF,mx,y1,x2,my);
  424.         XDrawLine(Disp,FWin,GcF,mx,y2,x1,my);
  425.         XDrawLine(Disp,FWin,GcF,mx,y2,x2,my);
  426.         break;
  427.     case BLOCKED:
  428.         x1=(i*OBJECTSCALE);
  429.         y1=(j*OBJECTSCALE);
  430.         XFillRectangle(Disp,FWin,GcF,x1,y1,OBJECTSCALE,OBJECTSCALE);
  431.         break;
  432.     default:
  433.         break;
  434.     }
  435. }
  436.  
  437. DrawRadarSq(i,j,clear)    /* draw a square on the radar window */
  438. int i,j,clear;
  439. {
  440.     int x1,x2,y1,y2;
  441.     switch(field[i][j])
  442.     {
  443.     case CLEAR:
  444.         if(clear)
  445.         {
  446.             x1=(i*ROSCALE);
  447.             y1=(j*ROSCALE);
  448.             XFillRectangle(Disp,RWin,GcB,x1,y1,ROSCALE,ROSCALE);
  449.         }
  450.         break;
  451.     case ROUGH:
  452.         x1=(i*ROSCALE);
  453.         y1=(j*ROSCALE);
  454.         x2=x1+ROSCALE-1;
  455.         y2=y1+ROSCALE-1;
  456.         if(clear)
  457.             XFillRectangle(Disp,RWin,GcB,x1,y1,ROSCALE,ROSCALE);
  458.         XDrawLine(Disp,RWin,GcF,x1,y1,x2,y2);
  459.         XDrawLine(Disp,RWin,GcF,x1,y2,x2,y1);
  460.         break;
  461.     case BLOCKED:
  462.         x1=(i*ROSCALE);
  463.         y1=(j*ROSCALE);
  464.         XDrawRectangle(Disp,RWin,GcF,x1,y1,ROSCALE-1,ROSCALE-1);
  465.         break;
  466.     default:
  467.         break;
  468.     }
  469.     if(radar[i][j])
  470.     {
  471.         x1=(i*ROSCALE);
  472.         y1=(j*ROSCALE);
  473.         XFillRectangle(Disp,RWin,GcF,x1,y1,ROSCALE,ROSCALE);
  474.     }
  475. }
  476.  
  477. void
  478. RefreshVSb(clear)    /* Refresh vertical scroll bar */
  479. int clear;
  480. {
  481.     if(clear)
  482.         XClearWindow(Disp,VSb);
  483.     XFillRectangle(Disp,VSb,GcF,0,cur.scy*SBY,SCROLLBAR,SBY*OBJY);
  484. }
  485.  
  486. void
  487. RefreshHSb(clear)    /* Refresh horizontal scroll bar */
  488. int clear;
  489. {
  490.     if(clear)
  491.         XClearWindow(Disp,HSb);
  492.     XFillRectangle(Disp,HSb,GcF,cur.scx*SBX,0,SBX*OBJX,SCROLLBAR);
  493. }
  494.  
  495. void
  496. RefreshRVSb(clear)    /* Refresh radar vertical scroll bar */
  497. int clear;
  498. {
  499.     if(clear)
  500.         XClearWindow(Disp,RVSb);
  501.     XFillRectangle(Disp,RVSb,GcF,0,cur.scy*ROSCALE,BOARDER,OBJY*ROSCALE);
  502. }
  503.  
  504. void
  505. RefreshRHSb(clear)    /* refresh radar horizontal scroll bar */
  506. int clear;
  507. {
  508.     if(clear)
  509.         XClearWindow(Disp,RHSb);
  510.     XFillRectangle(Disp,RHSb,GcF,cur.scx*ROSCALE,0,OBJX*ROSCALE,BOARDER);
  511. }
  512.  
  513. void
  514. RefreshSWin(clear)    /* refresh status (list of player names/scores) window */
  515. int clear;
  516. {
  517.     int i;
  518.     char str[80];
  519.  
  520.     if(clear)
  521.         XFillRectangle(Disp,SWin,GcB,0,0,RADARSIZE,15*(MAXUSERS+1));
  522.     for(i=0;i<MAXUSERS;i++)
  523.     {
  524.         if(*(player[i].user.username)=='\0')
  525.             continue;
  526.         sprintf(str,"%c %c [%2d/%2d]  %s@%s",i+BASECHAR,(i==myid)?'*':':',player[i].kills,player[i].killed,player[i].user.username,player[i].user.hostname);
  527.         XDrawString(Disp,SWin,GcF,10,(15*(i+1)),str,strlen(str));
  528.     }
  529.     XFlush(Disp);
  530. }
  531.  
  532. RefreshFWin(clear)    /* refresh battlefield window */
  533. int clear;
  534. {
  535.     int i,j;
  536.     for(i=0;i<OBJX;i++)
  537.         for(j=0;j<OBJY;j++)
  538.             DrawFieldSq(i,j,clear);
  539. }
  540.  
  541. static void
  542. RefreshRWin(clear)    /* refresh radar window */
  543. int clear;
  544. {    /* refresh code */
  545.  
  546.     int i,j;
  547.  
  548.     for(i=0;i<OBJECTSIZE;i++)
  549.         for(j=0;j<OBJECTSIZE;j++)
  550.             DrawRadarSq(i,j,clear);
  551.     XFlush(Disp);
  552. }
  553.  
  554. void
  555. RefreshQWin(clear)    /* refresh QUIT window (button */
  556. int clear;
  557. {
  558.     char *str="QUIT";
  559.     if(clear)
  560.         XClearWindow(Disp,QWin);
  561.     XDrawString(Disp,QWin,GcF,10,15,str,strlen(str));
  562.     XFlush(Disp);
  563. }
  564.  
  565. void
  566. RefreshAWin(clear)    /* refresh armour (damage) window */
  567. int clear;
  568. {
  569.     char *str;
  570.     if(damage>=MAXDAMAGE)
  571.     {
  572.         XFillRectangle(Disp,AWin,GcB,0,0,RADARSIZE,(DAMAGEBAR/2)-1);
  573.         str="DESTROYED";
  574.     }
  575.     else
  576.     {
  577.         str="DAMAGE";
  578.     }
  579.     if(clear)
  580.         XClearWindow(Disp,AWin);
  581.     XDrawLine(Disp,AWin,GcF,0,DAMAGEBAR/2,RADARSIZE,DAMAGEBAR/2);
  582.     XDrawString(Disp,AWin,GcF,10,15,str,strlen(str));
  583.     XFillRectangle(Disp,AWin,GcF,0,DAMAGEBAR/2,damage*DAMAGESCALE,DAMAGEBAR/2);
  584.     XFlush(Disp);
  585. }
  586.  
  587. void
  588. RefreshMWin(clear)    /* refresh message window */
  589. int clear;
  590. {
  591.     int i;
  592.  
  593.     if(clear)
  594.         XClearWindow(Disp,MWin);
  595.     for(i=0;i<MAXUSERS;i++)
  596.     {
  597.         XDrawString(Disp,MWin,GcF,10,15,message,strlen(message));
  598.     }
  599.     XFlush(Disp);
  600. }
  601.  
  602. void
  603. RefreshWin(clear)
  604. int clear;
  605. {
  606. }
  607.  
  608. int
  609. checkscroll(dx,dy)    /* check how far we can scroll */
  610. int *dx,*dy;
  611. {
  612.     int sx,sy,osx,osy;
  613.     osx=SIZE(*dx);
  614.     osy=SIZE(*dy);
  615.  
  616.     if((cur.scy+(*dy))<0)
  617.         (*dy)=(-1*cur.scy);
  618.     if((cur.scy+(*dy))>(OBJECTSIZE-MAINY/OBJECTSCALE))
  619.         (*dy)=(OBJECTSIZE-MAINY/OBJECTSCALE)-cur.scy;
  620.     if((cur.scx+(*dx))<0)
  621.         (*dx)=(-1*cur.scx);
  622.     if((cur.scx+(*dx))>(OBJECTSIZE-MAINX/OBJECTSCALE))
  623.         (*dx)=(OBJECTSIZE-MAINX/OBJECTSCALE)-cur.scx;
  624.     sx=SIZE(*dx);
  625.     sy=SIZE(*dy);
  626.  
  627.     if((osx!=0)&&(sx==0)&&(osy!=0)&&(sy!=0)&&(sy!=osy))
  628.         return(5);
  629.  
  630.     if((osx!=0)&&(sx!=0)&&(osy!=0)&&(sy==0)&&(sx!=osx))
  631.         return(5);
  632.  
  633.     if((osx!=0)&&(sx!=0)&&(osy!=0)&&(sy!=0)&&(sx!=osx)&&(sy!=osy))
  634.         return(5);
  635.  
  636.     if(sx>sy)
  637.         return(sx);
  638.     else
  639.         return(sy);
  640. }
  641.  
  642. void
  643. scroll(dx,dy)    /* do the scroll */
  644. int dx,dy;
  645. {
  646.     cur.scx+=dx;
  647.     cur.scy+=dy;
  648.  
  649.     if(warpflag)
  650.         XWarpPointer(Disp,None,None,0,0,MAINX,MAINY,dx*(-1*OBJECTSCALE),dy*(-1*OBJECTSCALE));
  651.  
  652.     if(dx!=0)
  653.     {
  654.         RefreshHSb(1);
  655.         RefreshRHSb(1);
  656.     }
  657.     if(dy!=0)
  658.     {
  659.         RefreshVSb(1);
  660.         RefreshRVSb(1);
  661.     }
  662.         
  663.     if((dx!=0)||(dy!=0))
  664.          RefreshFWin(1);
  665. }
  666.  
  667.  
  668. void
  669. DoRefresh(refwin)    /* send a refresh */
  670. Window refwin;
  671. {
  672.     if(refwin==Win)
  673.     {
  674.         RefreshWin(0);
  675.         return;
  676.     }
  677.     if(refwin==FWin)
  678.     {
  679.         RefreshFWin(0);
  680.         return;
  681.     }
  682.     if(refwin==RWin)
  683.     {
  684.         RefreshRWin(0);
  685.         return;
  686.     }
  687.     if(refwin==SWin)
  688.     {
  689.         RefreshSWin(0);
  690.         return;
  691.     }
  692.     if(refwin==QWin)
  693.     {
  694.         RefreshQWin(0);
  695.         return;
  696.     }
  697.     if(refwin==VSb)
  698.     {
  699.         RefreshVSb(0);
  700.         return;
  701.     }
  702.     if(refwin==HSb)
  703.     {
  704.         RefreshHSb(0);
  705.         return;
  706.     }
  707.     if(refwin==RVSb)
  708.     {
  709.         RefreshRVSb(0);
  710.         return;
  711.     }
  712.     if(refwin==RHSb)
  713.     {
  714.         RefreshRHSb(0);
  715.         return;
  716.     }
  717.     if(refwin==AWin)
  718.     {
  719.         RefreshAWin(0);
  720.         return;
  721.     }
  722.     if(refwin==MWin)
  723.     {
  724.         RefreshMWin(0);
  725.         return;
  726.     }
  727. }
  728.  
  729. int
  730. SocketHandle()    /* handle data from the server incomming on the socket */
  731. {
  732.     int i,j;
  733.     int gx,gy,dx,dy;
  734.     if(readdata(rsd,&rdata)!=sizeof(DATA))
  735.     {
  736.         fprintf(stderr,"%s: Recieved bad data\n");
  737.         exit(1);
  738.     }
  739.     switch(INSWAP(rdata.type))
  740.     {
  741.     case T_REPLY:
  742.         gx=(player[myid].pos.x/OBJECTSCALE)-cur.scx;
  743.         gy=(player[myid].pos.y/OBJECTSCALE)-cur.scy;
  744.  
  745.         dy=gy-(MAINX/(2*OBJECTSCALE));
  746.         dx=gx-(MAINX/(2*OBJECTSCALE));
  747.  
  748.         doexplosions();
  749.  
  750.         if(checkscroll(&dx,&dy)>1)
  751.             scroll(dx,dy);
  752.  
  753.         for(i=0;i<MAXUSERS;i++)
  754.         {
  755.             if(INSWAP(rdata.extra.reply.pos[i].x)==-1)
  756.                 continue;
  757.             WipeTank(player[i].pos.x,player[i].pos.y,player[i].pos.rot,i);
  758.             player[i].pos.x=INSWAP(rdata.extra.reply.pos[i].x);
  759.             player[i].pos.y=INSWAP(rdata.extra.reply.pos[i].y);
  760.             player[i].pos.rot=INSWAP(rdata.extra.reply.pos[i].rot);
  761.             DrawTank(player[i].pos.x,player[i].pos.y,player[i].pos.rot,i);
  762.             XFlush(Disp);
  763.         }
  764.         /* update current position */
  765.         cur.x=player[myid].pos.x;
  766.         cur.y=player[myid].pos.y;
  767.         cur.rot=player[myid].pos.rot;
  768.  
  769.             /* remove any 'spare' data from the pipe */
  770.         if(read(pd[0],&garbage,sizeof(POSITION))==-1)
  771.         {
  772.             if((errno!=EWOULDBLOCK)&&(errno!=EAGAIN))
  773.                 perror("read pd[0]");
  774.         }
  775.         
  776.             /* tell our 'other half' about our new position */
  777.         if(write(pd[1],&cur,sizeof(POSITION))==-1)
  778.             perror("write pd[0]");
  779.         break;
  780.     case T_ACCEPT:
  781.         for(i=0;i<MAXUSERS;i++)
  782.         {
  783.             if((*(player[i].user.username)!='\0')&&(*(rdata.extra.accept.players[i].username)=='\0'))
  784.             {
  785.                 WipeTank(player[i].pos.x,player[i].pos.y,player[i].pos.rot,i);
  786.                 /*DrawRadarSq(player[i].pos.x/OBJECTSCALE,player[i].pos.x/OBJECTSCALE,1);*/
  787.             }
  788.             strcpy(player[i].user.username,rdata.extra.accept.players[i].username);
  789.             strcpy(player[i].user.hostname,rdata.extra.accept.players[i].hostname);
  790.             player[i].kills=INSWAP(rdata.extra.accept.kills[i]);
  791.             player[i].killed=INSWAP(rdata.extra.accept.killed[i]);
  792.         }
  793.         RefreshRWin(1);
  794.         RefreshSWin(1);
  795.         break;
  796.     case T_EXPLOSION:
  797.         damage=INSWAP(rdata.extra.explosion.damage[myid]);
  798.         RefreshAWin(1);
  799.         for(i=0;i<MAXUSERS;i++)
  800.         {
  801.             if(exptime[i]==(-1))
  802.             {
  803.                 ex[i]=INSWAP(rdata.extra.explosion.x)-(cur.scx*OBJECTSCALE);
  804.                 ey[i]=INSWAP(rdata.extra.explosion.y)-(cur.scy*OBJECTSCALE);
  805.  
  806.                 if((ex[i]<(-1*EXPSIZE))||(ey[i]<(-1*EXPSIZE))||(ex[i]>(MAINX+EXPSIZE))||(ey[i]>(EXPSIZE+MAINY)))
  807.                     break;
  808.                 exptime[i]=gettime();
  809.                 break;
  810.             }
  811.         }
  812.         break;
  813.     case T_MESSAGE:
  814.         strcpy(message,rdata.extra.message.text);
  815.         RefreshMWin(1);
  816.         break;
  817.     case T_ALIVE:
  818.         sdata.type=OUTSWAP(T_ALIVE);
  819.         senddata(ssd,&sdata);
  820.         break;
  821.     default:
  822.         printf("Unexpected datagram type %d (0x%x)\n",INSWAP(rdata.type),INSWAP(rdata.type));
  823.     }
  824. }
  825.  
  826.  
  827. int
  828. EventHandle()    /* handle X events */
  829. {
  830.     XEvent Evnt;
  831.  
  832.     XNextEvent(Disp,&Evnt);
  833.  
  834.     if(read(pd[0],&cur,sizeof(POSITION))==-1)
  835.     {
  836.         if((errno!=EWOULDBLOCK)&&(errno!=EAGAIN))
  837.             perror("read pd[0]");
  838.     }
  839.  
  840.     switch(Evnt.type)
  841.     {
  842.     case ButtonPress:
  843.         {
  844.             int bno;
  845.             XButtonEvent *BEvent;
  846.             BEvent=(XButtonEvent*)(&Evnt);
  847.             bno=BEvent->button;
  848.             if(BEvent->window==FWin)
  849.             {
  850.                 mrot=GetAngle(cur.x,cur.y,msx,msy);
  851.                 switch(bno)
  852.                 {
  853.                 case 1:
  854.                     if(damage<MAXDAMAGE)
  855.                         fire=1;
  856.                     break;
  857.                 case 2:
  858.                     motion=invert;
  859.                     break;
  860.                 case 3:
  861.                     motion=0-invert;
  862.                     break;
  863.                 }
  864.                 sendstatus();
  865.             }
  866.             else
  867.             {
  868.                 if(BEvent->window==QWin)
  869.                 switch(bno)
  870.                 {
  871.                 case 1:
  872.                     signoff(0,QUIT);
  873.                     break;
  874.                 case 2:
  875.                     /* DEBUG */
  876.                     printf("cur.scx,cur.scy=%d,%d msx,msy=%d,%d\n",cur.scx,cur.scy,msx,msy);
  877.                     printf("tankx,tanky=%d,%d\n",cur.x,cur.y);
  878.                     break;
  879.                 }
  880.             }
  881.         }
  882.         break;
  883.     case ButtonRelease:
  884.         {
  885.             int bno;
  886.             XButtonEvent *BEvent;
  887.             BEvent=(XButtonEvent*)(&Evnt);
  888.             bno=BEvent->button;
  889.  
  890.             if(BEvent->window==FWin)
  891.             {
  892.                 mrot=GetAngle(cur.x,cur.y,msx,msy);
  893.                 switch(bno)
  894.                 {
  895.                 case 1:
  896.                     fire=0;
  897.                     sendstatus();
  898.                     break;
  899.                 case 2:
  900.                     if(motion==invert)
  901.                     {
  902.                         motion=0;
  903.                         sendstatus();
  904.                     }
  905.                     break;
  906.                 case 3:
  907.                     if(motion==(0-invert))
  908.                     {
  909.                         motion=0;
  910.                         sendstatus();
  911.                     }
  912.                     break;
  913.                 }
  914.             }
  915.             else
  916.             {
  917.                 printf("Button release outside battlefield\n");
  918.             }
  919.         }
  920.         break;
  921.     case MotionNotify:
  922.         {
  923.             XMotionEvent *MEvent;
  924.             MEvent=(XMotionEvent*)(&Evnt);
  925.             msx=(MEvent->x)+(cur.scx*OBJECTSCALE);
  926.             msy=(MEvent->y)+(cur.scy*OBJECTSCALE);
  927.             mrot=GetAngle(cur.x,cur.y,msx,msy);
  928.             if(MEvent->window==FWin)
  929.             {
  930.                 if((MEvent->time-movetime)>100)
  931.                 {
  932.                     sendstatus();
  933.                     movetime=MEvent->time;
  934.                 }
  935.             }
  936.             else
  937.             {
  938.                 printf("Mouse movement outside battlefield\n");
  939.             }
  940.         }
  941.         break;
  942.     case GraphicsExpose:
  943.     case Expose:
  944.         {
  945.             XExposeEvent *EEvent;
  946.             EEvent=(XExposeEvent*)(&Evnt);
  947.             if(EEvent->count==0)
  948.             {
  949.                 DoRefresh(EEvent->window);
  950.             }
  951.         }
  952.         break;
  953.     case DestroyNotify:
  954.         {
  955.             XDestroyWindowEvent *XDEvent;
  956.             XDEvent=(XDestroyWindowEvent*)(&Evnt);
  957.             signoff(0,DESTROYED);
  958.         }
  959.         break;
  960.     case KeyPress:
  961.     case KeyRelease:
  962.         {
  963.             char buf[2];
  964.             int oldinvert;
  965.             XKeyEvent *KEvent; 
  966.  
  967.             buf[1]='\0';
  968.             KEvent=(XKeyEvent*)(&Evnt);
  969.             XLookupString(KEvent,buf,1,NULL,NULL);
  970.             if(*buf==0x03)
  971.                 signoff(0,QUIT);
  972.             oldinvert=invert;
  973.             if(Evnt.type==KeyPress)
  974.                 invert=(-1);
  975.             else
  976.                 invert=1;
  977.             if(oldinvert!=invert)
  978.             {
  979.                 motion=0-motion;
  980.                 sendstatus();
  981.             }
  982.         }
  983.         break;
  984.     default:
  985. /*        fprintf(stderr,"Unknown Event\n");*/
  986.         break;
  987.     }
  988. }
  989.  
  990. void
  991. CreatePixmaps()
  992. {
  993.     int i,j;
  994.     int rot;
  995.     XGCValues gcv;
  996.     GC GcPF,GcPB;
  997.     Pixmap Dummy;
  998.  
  999.     if(pixflag)
  1000.     {
  1001.         Dummy=XCreatePixmap(Disp,Win,PIXSIZE,PIXSIZE,1);
  1002.         gcv.function = GXcopy;
  1003.         gcv.plane_mask =AllPlanes;
  1004.         gcv.fill_style = FillSolid;
  1005.         GcPF=XCreateGC(Disp,Dummy,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
  1006.         XSetForeground(Disp,GcPF,1);
  1007.         XSetBackground(Disp,GcPF,0);
  1008.     
  1009.         GcPB=XCreateGC(Disp,Dummy,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
  1010.         XSetForeground(Disp,GcPB,0);
  1011.         XSetBackground(Disp,GcPB,1);
  1012.     
  1013.         for(i=0;i<TANKROT;i++)
  1014.         {
  1015.             TankPix[i]=XCreatePixmap(Disp,Win,PIXSIZE,PIXSIZE,1);
  1016.             if(TankPix[i]==BadAlloc)
  1017.             {
  1018.                 /* no memory for pixmaps on server */
  1019.                 fprintf(stderr,"Failed to allocate pixmaps(%d)(%d*%d*%d), using polygons instead\n",i,PIXSIZE,PIXSIZE,1);
  1020.                 /* free currently allocated pixmaps */
  1021.                 for(j=0;j<i;j++)
  1022.                     XFreePixmap(Disp,TankPix[j]);
  1023.                 pixflag=0;
  1024.                 polyflag=1;
  1025.                 break;
  1026.             }
  1027.             rot=(i+TANKROT+(TANKROT/4))%TANKROT;
  1028.             Tank[rot].coord[0].x=PIXSIZE/2;
  1029.             Tank[rot].coord[0].y=PIXSIZE/2;
  1030.             XFillRectangle(Disp,TankPix[i],GcPB,0,0,PIXSIZE,PIXSIZE);
  1031.             XFillPolygon(Disp,TankPix[i],GcPF,&Tank[rot],TANKPOINTS,Nonconvex,CoordModePrevious);
  1032.         }
  1033.             /* no longer needed */
  1034.         XFreeGC(Disp,GcPF);
  1035.         XFreeGC(Disp,GcPB);
  1036.         XFreePixmap(Disp,Dummy);
  1037.     }
  1038. }
  1039.  
  1040.  
  1041. Xinit(Name,xs,ys)    /* initialise X */
  1042. char *Name;
  1043. int xs,ys;
  1044. {
  1045.     unsigned long bg,fg;
  1046.     Cursor Curs;
  1047.     XGCValues gcv;
  1048.     char *DisplayName;
  1049.     Pixmap iconised;
  1050.     XWMHints hint;
  1051.     int i;
  1052.  
  1053.     DisplayName=getenv("DISPLAY");
  1054.     if(DisplayName==NULL)
  1055.     {
  1056.         fprintf(stderr,"%s: $DISPLAY not set\n",progname);
  1057.         exit(1);
  1058.     }
  1059.  
  1060.     Disp=XOpenDisplay(DisplayName);
  1061.  
  1062.     if(Disp==NULL)
  1063.     {
  1064.         fprintf(stderr,"%s: Unable to open $DISPLAY (%s)\n",progname,DisplayName);
  1065.         exit(1);
  1066.     }
  1067.  
  1068.     Root=XDefaultRootWindow(Disp);
  1069.     Scr=DefaultScreen(Disp);
  1070.  
  1071.         /* if user has specified no defaults */
  1072.     if((!polyflag)&&(!pixflag))
  1073.     {
  1074.         pixflag=1;
  1075.         polyflag=0;
  1076.     }
  1077.  
  1078.     fg=BlackPixel(Disp,Scr);
  1079.     bg=WhitePixel(Disp,Scr);
  1080.  
  1081.         /* Main (parent window */
  1082.     Win=XCreateSimpleWindow(Disp,Root,0,0,xs,ys,2,fg,bg);
  1083.         /* Radar window */
  1084.     RWin=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER,RADARSIZE,RADARSIZE,1,fg,bg);
  1085.         /* Field window */
  1086.     FWin=XCreateSimpleWindow(Disp,Win,BOARDER*4+RADARSIZE,BOARDER,MAINX,MAINY,1,fg,bg);
  1087.         /* Armour status window */
  1088.     AWin=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER*4+RADARSIZE,RADARSIZE-2,DAMAGEBAR,2,fg,bg);
  1089.         /* Quit window */
  1090.     QWin=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER*5+RADARSIZE+DAMAGEBAR,RADARSIZE-2,MESSAGESIZE,2,fg,bg);
  1091.         /* Message window */
  1092.     MWin=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER*6+MESSAGESIZE+RADARSIZE+DAMAGEBAR,RADARSIZE,MESSAGESIZE,1,fg,bg);
  1093.         /* Status window */
  1094.     SWin=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER*7+MESSAGESIZE*2+RADARSIZE+DAMAGEBAR,RADARSIZE,15*(MAXUSERS+1),1,fg,bg);
  1095.  
  1096.         /* Main vertical and horizontal scroll bars */
  1097.     VSb=XCreateSimpleWindow(Disp,Win,BOARDER*5+RADARSIZE+MAINX,BOARDER,SCROLLBAR,MAINY-2,2,fg,bg);
  1098.     HSb=XCreateSimpleWindow(Disp,Win,BOARDER*4+RADARSIZE,BOARDER*2+MAINY,MAINX-2,SCROLLBAR,2,fg,bg);
  1099.         /* Radar vertical and horizontal scroll bars */
  1100.     RVSb=XCreateSimpleWindow(Disp,Win,BOARDER*2+RADARSIZE,BOARDER,BOARDER,RADARSIZE,1,fg,bg);
  1101.     RHSb=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER*2+RADARSIZE,RADARSIZE,BOARDER,1,fg,bg);
  1102.  
  1103.  
  1104.     XStoreName(Disp,Win,Name);
  1105.  
  1106.     gcv.function = GXcopy;
  1107.     gcv.plane_mask = AllPlanes;
  1108.     gcv.fill_style = FillSolid;
  1109.  
  1110.     GcF=XCreateGC(Disp,Win,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
  1111.     GcB=XCreateGC(Disp,Win,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
  1112.  
  1113.     XSetForeground(Disp,GcF,fg);
  1114.     XSetBackground(Disp,GcF,bg);
  1115.     XSetForeground(Disp,GcB,bg);
  1116.     XSetBackground(Disp,GcB,fg);
  1117.  
  1118.     gcv.function = GXor;
  1119.     GcTF=XCreateGC(Disp,Win,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
  1120.  
  1121.     gcv.function = GXandInverted;
  1122.     GcTB=XCreateGC(Disp,Win,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
  1123.  
  1124.     XSetForeground(Disp,GcTF,fg);
  1125.     XSetBackground(Disp,GcTF,bg);
  1126.     XSetForeground(Disp,GcTB,fg);
  1127.     XSetBackground(Disp,GcTB,bg);
  1128.  
  1129.     Curs=XCreateFontCursor(Disp,XC_crosshair);
  1130.     XDefineCursor(Disp,Win,Curs);
  1131.     iconised=XCreateBitmapFromData(Disp,Win,xtb_bits,xtb_width,xtb_height);
  1132.     hint.flags=(InputHint|IconPixmapHint);
  1133.     hint.input=True;
  1134.     hint.icon_pixmap=iconised;
  1135.     XSetWMHints(Disp,Win,&hint);
  1136.     CreatePixmaps();
  1137.  
  1138.     XSetIOErrorHandler(doXio);
  1139. }
  1140.  
  1141. void
  1142. SelectAllInputs()
  1143. {
  1144.     XSelectInput(Disp,Win,ExposureMask|StructureNotifyMask);
  1145.     XSelectInput(Disp,RWin,ExposureMask);
  1146.     XSelectInput(Disp,FWin,FieldEventMask);
  1147.     XSelectInput(Disp,QWin,ButtonMask|ExposureMask|StructureNotifyMask);
  1148.     XSelectInput(Disp,SWin,ExposureMask);
  1149.  
  1150.     XSelectInput(Disp,VSb,ExposureMask);
  1151.     XSelectInput(Disp,HSb,ExposureMask);
  1152.     XSelectInput(Disp,RVSb,ExposureMask);
  1153.     XSelectInput(Disp,RHSb,ExposureMask);
  1154.     XSelectInput(Disp,AWin,ExposureMask);
  1155.     XSelectInput(Disp,MWin,ExposureMask);
  1156. }
  1157.  
  1158. void
  1159. MapAllWindows()        /* obvious */
  1160. {
  1161.     XMapWindow(Disp,Win);
  1162.     XMapWindow(Disp,FWin);
  1163.     XMapWindow(Disp,RWin);
  1164.     XMapWindow(Disp,SWin);
  1165.     XMapWindow(Disp,QWin);
  1166.  
  1167.     XMapWindow(Disp,VSb);
  1168.     XMapWindow(Disp,HSb);
  1169.     XMapWindow(Disp,RVSb);
  1170.     XMapWindow(Disp,RHSb);
  1171.     XMapWindow(Disp,AWin);
  1172.     XMapWindow(Disp,MWin);
  1173.  
  1174.     XFlush(Disp);
  1175. }
  1176.  
  1177.  
  1178. main(argc,argv)
  1179. int argc;
  1180. char *argv[];
  1181. {
  1182.     int i,j;
  1183.     char *p;
  1184.  
  1185.     int inport,outport;
  1186.     int fieldok;
  1187.     progname=argv[0];
  1188.  
  1189.     server=getenv("XTB_SERVER");
  1190.  
  1191.     p=getenv("XTB_INPORT");
  1192.     if(p!=NULL)
  1193.         inport=atoi(p);
  1194.     else
  1195.         inport=DEFCPORT;
  1196.  
  1197.     p=getenv("XTB_OUTPORT");
  1198.     if(p!=NULL)
  1199.         outport=atoi(p);
  1200.     else
  1201.         outport=DEFSPORT;
  1202.  
  1203.     for(i=1;i<argc;i++)
  1204.     {
  1205.         p=argv[i];
  1206.         if(*p++=='-')
  1207.         {
  1208.             switch(*p++)
  1209.             {
  1210.             case 'i':    /* input/client port */
  1211.             case 'c':
  1212.                 if(*p=='\0')
  1213.                     inport=atoi(argv[++i]);
  1214.                 else
  1215.                     inport=atoi(p);
  1216.                 break;
  1217.             case 'o':    /* output/server port */
  1218.             case 's':
  1219.                 if(*p=='\0')
  1220.                     outport=atoi(argv[++i]);
  1221.                 else
  1222.                     outport=atoi(p);
  1223.                 break;
  1224.             case 'h':
  1225.                 if(*p=='\0')
  1226.                     server=argv[++i];
  1227.                 else
  1228.                     server=p;
  1229.                 break;
  1230.             case 'w':
  1231.                 warpflag++;
  1232.                 break;
  1233.             case 'd':
  1234.                 debug++;
  1235.                 break;
  1236.             case 'b':    /* use pixmaps for drawing tanks */
  1237.                 pixflag++;
  1238.                 break;
  1239.             case 'p':    /* use polygons  for drawing tanks */
  1240.                 polyflag++;
  1241.                 break;
  1242.             default:
  1243.                 fprintf(stderr,"Usage: %s [-h server_host] [-w] [-c client_portno] [-s server_portno] \n",argv[0]);
  1244.             }
  1245.         }
  1246.     }
  1247.  
  1248.     if(server==NULL)
  1249.     {
  1250.         fprintf(stderr,"%s: No server host (-h or $XTB_SERVER) defined\n",argv[0]);
  1251.         exit(1);
  1252.     }
  1253.  
  1254.     rsd=openread(inport);
  1255.     if(rsd==(-1))
  1256.     {
  1257.         fprintf(stderr,"%s: Opening port %d failed\n",argv[0],inport);
  1258.         exit(1);
  1259.     }
  1260.     
  1261.     ssd=opensend(server,outport);
  1262.     if(ssd==(-1))
  1263.     {
  1264.         fprintf(stderr,"%s: Connecting to %s/%d failed\n",argv[0],server,outport);
  1265.         exit(1);
  1266.     }
  1267.  
  1268.     for(i=0;i<MAXUSERS;i++)
  1269.         exptime[i]=(-1);
  1270.     InitTables();
  1271.     Xinit("XTankBattle",MAINX+RADARSIZE+6*BOARDER+SCROLLBAR,MAINY+3*BOARDER+SCROLLBAR);
  1272.  
  1273.         /* signon */
  1274.     sdata.type=OUTSWAP(T_SIGNON);
  1275.     sdata.extra.signon.version=OUTSWAP(VERSION);
  1276.     sdata.extra.signon.port=OUTSWAP(inport);    /* could be different to server port */
  1277.     gethostname(sdata.extra.signon.hostname,HOSTLEN);
  1278.     strncpy(sdata.extra.signon.username,((struct passwd*)getpwuid(getuid()))->pw_name,NAMELEN-1);
  1279.     sdata.extra.signon.username[NAMELEN]='\0';
  1280.  
  1281.     signal(SIGALRM,timeout);
  1282.     alarm(3);
  1283.     senddata(ssd,&sdata);
  1284.  
  1285.     if(readdata(rsd,&rdata)!=sizeof(DATA))
  1286.     {
  1287.         fprintf(stderr,"%s: Recieved bad data\n");
  1288.         exit(1);
  1289.     }
  1290.     alarm(0);
  1291.     switch(INSWAP(rdata.type))
  1292.     {
  1293.     case T_ACCEPT:
  1294.         if(debug)
  1295.         {
  1296.             printf("accept\n");
  1297.             printf("My id is %d\n",INSWAP(rdata.extra.accept.id));
  1298.         }
  1299.         myid=INSWAP(rdata.extra.accept.id);
  1300.         for(i=0;i<MAXUSERS;i++)
  1301.         {
  1302.             strcpy(player[i].user.username,rdata.extra.accept.players[i].username);
  1303.             strcpy(player[i].user.hostname,rdata.extra.accept.players[i].hostname);
  1304.             player[i].kills=INSWAP(rdata.extra.accept.kills[i]);
  1305.             player[i].killed=INSWAP(rdata.extra.accept.killed[i]);
  1306.         }
  1307.         break;
  1308.     case T_REJECT:
  1309.         fprintf(stderr,"reject\n");
  1310.         fprintf(stderr,"reason: %s\n",rdata.extra.reject.text);
  1311.         exit(1);
  1312.         break;
  1313.     default:
  1314.         if(debug)
  1315.             printf("Unknown datagram type %d (0x%x)\n",INSWAP(rdata.type),INSWAP(rdata.type));
  1316.     }
  1317.  
  1318.     for(i=0;i<OBJECTSIZE;i++)
  1319.         for(j=0;j<OBJECTSIZE;j++)
  1320.             radar[i][j]=0;
  1321.     for(i=0;i<OBJECTSIZE;i++)
  1322.         field[i][0]=UNSET;
  1323.  
  1324.     MapAllWindows();
  1325.  
  1326.     if(debug)
  1327.         printf("Getting field data\n");
  1328.     sdata.id=OUTSWAP(myid);
  1329.     sdata.type=OUTSWAP(T_DATAREQ);
  1330.  
  1331.     do
  1332.     {
  1333.         fieldok=1;
  1334.         for(i=0;i<OBJECTSIZE;i++)
  1335.         {
  1336.             if(field[i][0]==UNSET)
  1337.             {
  1338.                 fflush(stdout);
  1339.                 fieldok=0;
  1340.                 sdata.extra.datareq.lineno=OUTSWAP(i);
  1341.                 senddata(ssd,&sdata);
  1342.                 if(readdata(rsd,&rdata)!=sizeof(DATA))
  1343.                 {
  1344.                     fprintf(stderr,"%s: Recieved bad data\n",argv[0]);
  1345.                     exit(1);
  1346.                 }
  1347.                 if(INSWAP(rdata.type)!=T_FIELDDATA)
  1348.                 {
  1349.                     if(INSWAP(rdata.type)==T_MESSAGE)
  1350.                         strcpy(message,rdata.extra.message.text);
  1351.                     else
  1352.                         fprintf(stderr,"%s: Expected field data got 0x%x\n",argv[0],INSWAP(rdata.type));
  1353.                 }
  1354.                 else
  1355.                 {
  1356.                     if(debug)
  1357.                     {
  1358.                         if(INSWAP(rdata.extra.field.lineno)!=i)
  1359.                             printf("%%%d",INSWAP(rdata.extra.field.lineno));
  1360.                         else
  1361.                             printf(".%d",i);
  1362.                     }
  1363.                     memcpy(field[INSWAP(rdata.extra.field.lineno)],rdata.extra.field.object,OBJECTSIZE);
  1364.                 }
  1365.             }
  1366.         }
  1367.     }
  1368.     while(!fieldok);
  1369.     putchar('\n');
  1370.  
  1371.     if(pipe(pd)==(-1))
  1372.     {
  1373.         fprintf(stderr,"%s: pipe(pd) failed\n",argv[0]);
  1374.         exit(1);
  1375.     }
  1376.  
  1377.     /* make read pipe descripter non-blocking */
  1378.     i=1;
  1379.     if(ioctl(pd[0],FIONBIO,&i)==-1)
  1380.     {
  1381.         fcntl(pd[0],F_SETFL,O_NDELAY);
  1382.     }
  1383.  
  1384.     ppid=getpid();
  1385.  
  1386.     signal(SIGHUP,dointr);
  1387.     signal(SIGINT,dointr);
  1388.     signal(SIGTERM,dointr);
  1389.     RefreshRWin(0);
  1390.     RefreshSWin(0);
  1391.     RefreshQWin(0);
  1392.     RefreshVSb(0);
  1393.     RefreshHSb(0);
  1394.     RefreshRVSb(0);
  1395.     RefreshRHSb(0);
  1396.     RefreshAWin(0);
  1397.     RefreshMWin(0);
  1398.  
  1399.     switch(cpid=fork())
  1400.     {
  1401.     case 0:    /* child */
  1402.         /* server -> socket -> X display */
  1403.         cpid=getpid();
  1404.         Disp=XOpenDisplay(getenv("DISPLAY"));
  1405.  
  1406.         while(1)
  1407.         {
  1408.             SocketHandle();
  1409.         }
  1410.         break;
  1411.  
  1412.     case -1: /* error */
  1413.         fprintf(stderr,"%s: Couldn't fork()\n",argv[0]);
  1414.         exit(1);
  1415.         break;
  1416.  
  1417.     default:/* parent */
  1418.         /* X events -> socket -> server */
  1419.         SelectAllInputs();
  1420.         while(1)
  1421.             EventHandle();
  1422.         break;
  1423.     }
  1424. }
  1425.