home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume15
/
xtb
/
part01
/
xtb.c
< prev
Wrap
C/C++ Source or Header
|
1993-01-27
|
31KB
|
1,425 lines
/*
* X Client
*
* $Header: /morpork/home/bmh/xtest2/RCS/xtb.c,v 1.41 92/10/19 15:34:32 bmh Exp Locker: bmh $
*
* Bernard Hatt
* Camtec Electronics (Ericsson), Leicester, England, LE1 4SA
* bmh@terminus.ericsson.se
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <ctype.h>
#include <math.h>
#include <pwd.h>
#include <errno.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include "defs.h"
#include "comms.h"
#define xtb_width 64 /* bitmap for iconised window */
#define xtb_height 64
static char xtb_bits[] = {
0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
0xf0, 0xff, 0x3f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x3f, 0x00,
0xc0, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x3f, 0x00, 0xc0, 0xff, 0xff, 0xff,
0xf0, 0xff, 0x3f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x00, 0x00,
0xc0, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
0x00, 0xfc, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x00, 0x00,
0xc0, 0xff, 0xff, 0xff, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, 0xff,
0x00, 0xf0, 0xff, 0x0f, 0xc0, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xff, 0x0f,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0xfc, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0xfc, 0x00, 0x00,
0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03,
0x00, 0xfc, 0x00, 0x00, 0x80, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x3f, 0x00,
0xe0, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0x3f, 0x00, 0xf0, 0xff, 0xe0, 0x7f,
0xf0, 0xff, 0x3f, 0x00, 0xf8, 0x0f, 0x00, 0xfe, 0xf0, 0xff, 0x3f, 0x00,
0xfc, 0x07, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0xf0,
0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
0x7e, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x80,
0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x82, 0x0f, 0x00, 0x00, 0x00,
0x50, 0x00, 0x00, 0x81, 0x0f, 0x00, 0x00, 0x00, 0x88, 0x00, 0x80, 0x80,
0x0f, 0x00, 0x00, 0x00, 0x04, 0x01, 0x40, 0xc0, 0x0f, 0x00, 0x00, 0x00,
0x02, 0x02, 0x20, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x01, 0x04, 0x10, 0xc0,
0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0xc0, 0x07, 0x00, 0x00, 0x00,
0x00, 0x10, 0x04, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x80,
0x07, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x80, 0x0f, 0x00, 0x00, 0x00,
0x00, 0x80, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x80,
0x0f, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x0f, 0x00, 0x00, 0x00,
0x00, 0x10, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00,
0x3e, 0x00, 0x00, 0x80, 0x00, 0x04, 0x10, 0x00, 0x3e, 0x00, 0x00, 0x80,
0x01, 0x02, 0x20, 0x00, 0x7c, 0x00, 0x00, 0xc0, 0x02, 0x01, 0x40, 0x00,
0xfc, 0x00, 0x00, 0xe0, 0x84, 0x00, 0x80, 0x00, 0xf8, 0x01, 0x00, 0xf0,
0x48, 0x00, 0x00, 0x01, 0xf0, 0x07, 0x00, 0x7c};
#define KeyMask (KeyPressMask|KeyReleaseMask)
#define ButtonMask (ButtonPressMask|ButtonReleaseMask)
#define MotionMask (PointerMotionMask)
#define MainEventMask (KeyMask|ButtonMask|ExposureMask|ButtonPressMask|ButtonReleaseMask)
#define FieldEventMask (PointerMotionMask|MainEventMask|ButtonPressMask|ButtonReleaseMask)
Display *Disp;
int Scr; /* screen no. */
Window Win,Root;
Window RWin,FWin,SWin,QWin,AWin,MWin; /* should have used an */
Window VSb,HSb; /* array/structure for these */
Window RVSb,RHSb;
GC GcF,GcB,GcTF,GcTB;
#define BOARDER 8 /* boarder between windows */
#define TANKPOINTS 20 /* number of points defining a tank */
typedef struct tank_struct
{
XPoint coord[TANKPOINTS];
} TANK;
TANK Tank[TANKROT]=
{{
{0,0},{T/2,-T},{T,0},{0,-T},{T,0},{0,4*T},{-T,0},{0,-T},{-T,0},{0,3*T},
{-T,0},{0,-3*T},{-T,0},{0,T},{-T,0},{0,-4*T},{T,0},{0,T},{T,0},{T/2,T}
}};
PLAYER player[MAXUSERS]; /* players tanks */
char field[OBJECTSIZE][OBJECTSIZE];
char radar[OBJECTSIZE][OBJECTSIZE];
/* PIMAPS */
#define PIXSIZE 48
Pixmap TankPix[TANKROT];
int fire=0; /* fire button pressed */
int motion=0; /* tank linear motion */
int mrot=0; /* mouse pointer rotation */
int damage=0; /* damage sustained */
char message[BUFLEN]=""; /* message for message window */
char *server=NULL;
POSITION cur={0,300,100,0,0};
POSITION garbage;
int pd[2]; /* pipe for passing current position */
int warpflag=0; /* warp pointer on scrolling main screen */
int invert=1; /* invert motion buttons */
int polyflag=0; /* use polygons to draw tanks */
int pixflag=0; /* use pixmaps to draw tanks */
int myid; /* my id */
int rsd,ssd; /* receive and send socket descripters */
DATA rdata,sdata; /* receive and send data */
Time movetime=0;
int savedx=(-1),savedy=(-1);
int sfx=(-1),sfy=(-1);
int msx,msy; /* mouse x,y */
int ex[MAXUSERS],ey[MAXUSERS],exptime[MAXUSERS]; /* explosions */
int debug=0;
int ppid,cpid;
char *progname;
void
signoff(t,reason) /* send signoff to server and exit */
int t,reason;
{
sdata.id=OUTSWAP(myid);
sdata.type=OUTSWAP(T_SIGNOFF);
sdata.extra.signoff.reason=OUTSWAP(reason);
senddata(ssd,&sdata);
if(t!=0)
sleep(t);
if(getpid()==cpid)
kill(ppid,SIGKILL);
else
kill(cpid,SIGKILL);
exit(1);
}
void
dointr() /* action on interrupt */
{
signoff(0,DESTROYED);
}
void
doXio()
{
signoff(0,QUIT);
}
void
timeout() /* timeout on connect */
{
fprintf(stderr,"%s: No response from server \"%s\" (not running/busy?)\n",progname,server);
exit(1);
}
void
doexplosions() /* deal with on screen explosions */
{
int i,j,k,tx,ty,td,rad;
for(i=0;i<MAXUSERS;i++)
{
if(exptime[i]!=(-1))
{
td=gettime()-exptime[i];
if(td>EXPTIME)
{
exptime[i]=(-1);
tx=ex[i]/OBJECTSCALE;
ty=ey[i]/OBJECTSCALE;
for(k=(-2);k<3;k++)
for(j=(-2);j<3;j++)
DrawFieldSq(tx+k,ty+j,1);
if(damage>=MAXDAMAGE)
{
signoff(5,KILLED);
}
XFlush(Disp);
}
else
{
if(td<=(EXPTIME/2))
{
rad=(td*EXPSIZE*2)/EXPTIME;
XFillArc(Disp,FWin,GcF,ex[i]-(rad/2),ey[i]-(rad/2),rad,rad,0,360*64);
XFlush(Disp);
}
else
{
rad=((td-(EXPTIME/2))*2*EXPSIZE)/EXPTIME;
if(rad>0)
{
XFillArc(Disp,FWin,GcB,ex[i]-(rad/2),ey[i]-(rad/2),rad,rad,0,360*64);
XFlush(Disp);
}
}
}
}
}
}
void
InitTables() /* initialise data tables (generate 128 different tank polygons) */
{
short i,j,x,y;
double xc,yc,angle,incr,theta,len;
x=0;
y=0;
incr=(2*PI)/((double)TANKROT);
for(i=1;i<TANKPOINTS;i++)
{
x+=Tank[0].coord[i].x;
y+=Tank[0].coord[i].y;
Tank[0].coord[i].x=x;
Tank[0].coord[i].y=y;
}
for(j=1;j<TANKROT;j++)
for(i=1;i<TANKPOINTS;i++)
{
angle=((double)j)*incr;
xc=(double)Tank[0].coord[i].x;
yc=(double)Tank[0].coord[i].y;
if(xc==0.0)
{
if(yc>0)
theta=(PI/2.0);
else
theta=(-PI/2.0);
}
else
{
theta=atan2(yc,xc);
}
len=hypot(xc,yc);
theta+=angle;
xc=len*cos(theta);
yc=len*sin(theta);
Tank[j].coord[i].x=(short)(xc+0.5);
Tank[j].coord[i].y=(short)(yc+0.5);
}
for(j=0;j<TANKROT;j++)
{
for(i=TANKPOINTS;i>0;i--)
{
x=Tank[j].coord[i-1].x;
y=Tank[j].coord[i-1].y;
Tank[j].coord[i].x-=x;
Tank[j].coord[i].y-=y;
}
}
}
void
sendstatus() /* send our status to the server */
{
sdata.type=OUTSWAP(T_MOVE);
sdata.id=OUTSWAP(myid);
sdata.extra.move.rot=OUTSWAP(mrot);
sdata.extra.move.linear=OUTSWAP(motion);
sdata.extra.move.fire=OUTSWAP(fire);
/* printf("motion=%d invert=%d\n",motion,invert);*/
senddata(ssd,&sdata);
}
void
WipeTank(x,y,rot,id) /* wipe a tank from the screen */
int x,y,rot,id;
{
int objx,objy;
objx=x/OBJECTSCALE;
objy=y/OBJECTSCALE;
radar[objx][objy]=0;
savedx=objx;
savedy=objy;
x-=(cur.scx*OBJECTSCALE);
y-=(cur.scy*OBJECTSCALE);
sfx=x/OBJECTSCALE;
sfy=y/OBJECTSCALE;
if((sfx<(-1))||(sfy<(-1))||(sfx>(OBJX+1))||(sfy>(OBJY+1)))
return;
if(polyflag)
{
rot=(rot+TANKROT+(TANKROT/4))%TANKROT;
Tank[rot].coord[0].x=x;
Tank[rot].coord[0].y=y;
XFillPolygon(Disp,FWin,GcB,&Tank[rot],TANKPOINTS,Nonconvex,CoordModePrevious);
}
else
{
XCopyPlane(Disp,TankPix[rot],FWin,GcTB,0,0,PIXSIZE,PIXSIZE,x-(PIXSIZE/2),y-(PIXSIZE/2),0x1);
}
if(id!=myid)
XFillRectangle(Disp,FWin,GcB,x-5,y-5,10,10);
}
void
DrawTank(x,y,rot,id) /* draw a tank on the screen */
int x,y,rot,id;
{
int objx,objy,flag;
char str[2];
objx=x/OBJECTSCALE;
objy=y/OBJECTSCALE;
x-=(cur.scx*OBJECTSCALE);
y-=(cur.scy*OBJECTSCALE);
flag=(!radar[savedx][savedy]);
radar[objx][objy]=1;
if((savedx!=objx)||(savedy!=objy)||flag)
{
DrawRadarSq(savedx,savedy,1);
DrawRadarSq(objx,objy,1);
}
objx=x/OBJECTSCALE;
objy=y/OBJECTSCALE;
if((objx<(-1))||(objy<(-1))||(objx>(OBJX+1))||(objy>(OBJY+1)))
return;
if((savedx!=objx)||(savedy!=objy))
{
DrawFieldSq(sfx,sfy,0);
}
if(polyflag)
{
rot=(rot+TANKROT+(TANKROT/4))%TANKROT;
Tank[rot].coord[0].x=x;
Tank[rot].coord[0].y=y;
XFillPolygon(Disp,FWin,GcF,&Tank[rot],TANKPOINTS,Nonconvex,CoordModePrevious);
}
else
{
XCopyPlane(Disp,TankPix[rot],FWin,GcTF,0,0,PIXSIZE,PIXSIZE,x-(PIXSIZE/2),y-(PIXSIZE/2),0x1);
}
if(id!=myid)
{
XFillRectangle(Disp,FWin,GcB,x-5,y-6,10,11);
str[1]='\0';
str[0]=id+BASECHAR;
XDrawString(Disp,FWin,GcF,x-2,y+3,str,1);
}
}
DrawFieldSq(i,j,clear) /* draw a square on the battlefield */
int i,j;
int clear;
{
int x1,x2,y1,y2,mx,my;
switch(field[i+cur.scx][j+cur.scy])
{
case CLEAR:
if(clear)
{
x1=(i*OBJECTSCALE);
y1=(j*OBJECTSCALE);
XFillRectangle(Disp,FWin,GcB,x1,y1,OBJECTSCALE,OBJECTSCALE);
}
break;
case ROUGH:
x1=(i*OBJECTSCALE);
y1=(j*OBJECTSCALE);
x2=x1+OBJECTSCALE-1;
y2=y1+OBJECTSCALE-1;
mx=(x1+x2)/2;
my=(y1+y2)/2;
if(clear)
XFillRectangle(Disp,FWin,GcB,x1,y1,OBJECTSCALE,OBJECTSCALE);
XDrawLine(Disp,FWin,GcF,x1,y1,x2,y2);
XDrawLine(Disp,FWin,GcF,x1,y2,x2,y1);
XDrawLine(Disp,FWin,GcF,mx,y1,x1,my);
XDrawLine(Disp,FWin,GcF,mx,y1,x2,my);
XDrawLine(Disp,FWin,GcF,mx,y2,x1,my);
XDrawLine(Disp,FWin,GcF,mx,y2,x2,my);
break;
case BLOCKED:
x1=(i*OBJECTSCALE);
y1=(j*OBJECTSCALE);
XFillRectangle(Disp,FWin,GcF,x1,y1,OBJECTSCALE,OBJECTSCALE);
break;
default:
break;
}
}
DrawRadarSq(i,j,clear) /* draw a square on the radar window */
int i,j,clear;
{
int x1,x2,y1,y2;
switch(field[i][j])
{
case CLEAR:
if(clear)
{
x1=(i*ROSCALE);
y1=(j*ROSCALE);
XFillRectangle(Disp,RWin,GcB,x1,y1,ROSCALE,ROSCALE);
}
break;
case ROUGH:
x1=(i*ROSCALE);
y1=(j*ROSCALE);
x2=x1+ROSCALE-1;
y2=y1+ROSCALE-1;
if(clear)
XFillRectangle(Disp,RWin,GcB,x1,y1,ROSCALE,ROSCALE);
XDrawLine(Disp,RWin,GcF,x1,y1,x2,y2);
XDrawLine(Disp,RWin,GcF,x1,y2,x2,y1);
break;
case BLOCKED:
x1=(i*ROSCALE);
y1=(j*ROSCALE);
XDrawRectangle(Disp,RWin,GcF,x1,y1,ROSCALE-1,ROSCALE-1);
break;
default:
break;
}
if(radar[i][j])
{
x1=(i*ROSCALE);
y1=(j*ROSCALE);
XFillRectangle(Disp,RWin,GcF,x1,y1,ROSCALE,ROSCALE);
}
}
void
RefreshVSb(clear) /* Refresh vertical scroll bar */
int clear;
{
if(clear)
XClearWindow(Disp,VSb);
XFillRectangle(Disp,VSb,GcF,0,cur.scy*SBY,SCROLLBAR,SBY*OBJY);
}
void
RefreshHSb(clear) /* Refresh horizontal scroll bar */
int clear;
{
if(clear)
XClearWindow(Disp,HSb);
XFillRectangle(Disp,HSb,GcF,cur.scx*SBX,0,SBX*OBJX,SCROLLBAR);
}
void
RefreshRVSb(clear) /* Refresh radar vertical scroll bar */
int clear;
{
if(clear)
XClearWindow(Disp,RVSb);
XFillRectangle(Disp,RVSb,GcF,0,cur.scy*ROSCALE,BOARDER,OBJY*ROSCALE);
}
void
RefreshRHSb(clear) /* refresh radar horizontal scroll bar */
int clear;
{
if(clear)
XClearWindow(Disp,RHSb);
XFillRectangle(Disp,RHSb,GcF,cur.scx*ROSCALE,0,OBJX*ROSCALE,BOARDER);
}
void
RefreshSWin(clear) /* refresh status (list of player names/scores) window */
int clear;
{
int i;
char str[80];
if(clear)
XFillRectangle(Disp,SWin,GcB,0,0,RADARSIZE,15*(MAXUSERS+1));
for(i=0;i<MAXUSERS;i++)
{
if(*(player[i].user.username)=='\0')
continue;
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);
XDrawString(Disp,SWin,GcF,10,(15*(i+1)),str,strlen(str));
}
XFlush(Disp);
}
RefreshFWin(clear) /* refresh battlefield window */
int clear;
{
int i,j;
for(i=0;i<OBJX;i++)
for(j=0;j<OBJY;j++)
DrawFieldSq(i,j,clear);
}
static void
RefreshRWin(clear) /* refresh radar window */
int clear;
{ /* refresh code */
int i,j;
for(i=0;i<OBJECTSIZE;i++)
for(j=0;j<OBJECTSIZE;j++)
DrawRadarSq(i,j,clear);
XFlush(Disp);
}
void
RefreshQWin(clear) /* refresh QUIT window (button */
int clear;
{
char *str="QUIT";
if(clear)
XClearWindow(Disp,QWin);
XDrawString(Disp,QWin,GcF,10,15,str,strlen(str));
XFlush(Disp);
}
void
RefreshAWin(clear) /* refresh armour (damage) window */
int clear;
{
char *str;
if(damage>=MAXDAMAGE)
{
XFillRectangle(Disp,AWin,GcB,0,0,RADARSIZE,(DAMAGEBAR/2)-1);
str="DESTROYED";
}
else
{
str="DAMAGE";
}
if(clear)
XClearWindow(Disp,AWin);
XDrawLine(Disp,AWin,GcF,0,DAMAGEBAR/2,RADARSIZE,DAMAGEBAR/2);
XDrawString(Disp,AWin,GcF,10,15,str,strlen(str));
XFillRectangle(Disp,AWin,GcF,0,DAMAGEBAR/2,damage*DAMAGESCALE,DAMAGEBAR/2);
XFlush(Disp);
}
void
RefreshMWin(clear) /* refresh message window */
int clear;
{
int i;
if(clear)
XClearWindow(Disp,MWin);
for(i=0;i<MAXUSERS;i++)
{
XDrawString(Disp,MWin,GcF,10,15,message,strlen(message));
}
XFlush(Disp);
}
void
RefreshWin(clear)
int clear;
{
}
int
checkscroll(dx,dy) /* check how far we can scroll */
int *dx,*dy;
{
int sx,sy,osx,osy;
osx=SIZE(*dx);
osy=SIZE(*dy);
if((cur.scy+(*dy))<0)
(*dy)=(-1*cur.scy);
if((cur.scy+(*dy))>(OBJECTSIZE-MAINY/OBJECTSCALE))
(*dy)=(OBJECTSIZE-MAINY/OBJECTSCALE)-cur.scy;
if((cur.scx+(*dx))<0)
(*dx)=(-1*cur.scx);
if((cur.scx+(*dx))>(OBJECTSIZE-MAINX/OBJECTSCALE))
(*dx)=(OBJECTSIZE-MAINX/OBJECTSCALE)-cur.scx;
sx=SIZE(*dx);
sy=SIZE(*dy);
if((osx!=0)&&(sx==0)&&(osy!=0)&&(sy!=0)&&(sy!=osy))
return(5);
if((osx!=0)&&(sx!=0)&&(osy!=0)&&(sy==0)&&(sx!=osx))
return(5);
if((osx!=0)&&(sx!=0)&&(osy!=0)&&(sy!=0)&&(sx!=osx)&&(sy!=osy))
return(5);
if(sx>sy)
return(sx);
else
return(sy);
}
void
scroll(dx,dy) /* do the scroll */
int dx,dy;
{
cur.scx+=dx;
cur.scy+=dy;
if(warpflag)
XWarpPointer(Disp,None,None,0,0,MAINX,MAINY,dx*(-1*OBJECTSCALE),dy*(-1*OBJECTSCALE));
if(dx!=0)
{
RefreshHSb(1);
RefreshRHSb(1);
}
if(dy!=0)
{
RefreshVSb(1);
RefreshRVSb(1);
}
if((dx!=0)||(dy!=0))
RefreshFWin(1);
}
void
DoRefresh(refwin) /* send a refresh */
Window refwin;
{
if(refwin==Win)
{
RefreshWin(0);
return;
}
if(refwin==FWin)
{
RefreshFWin(0);
return;
}
if(refwin==RWin)
{
RefreshRWin(0);
return;
}
if(refwin==SWin)
{
RefreshSWin(0);
return;
}
if(refwin==QWin)
{
RefreshQWin(0);
return;
}
if(refwin==VSb)
{
RefreshVSb(0);
return;
}
if(refwin==HSb)
{
RefreshHSb(0);
return;
}
if(refwin==RVSb)
{
RefreshRVSb(0);
return;
}
if(refwin==RHSb)
{
RefreshRHSb(0);
return;
}
if(refwin==AWin)
{
RefreshAWin(0);
return;
}
if(refwin==MWin)
{
RefreshMWin(0);
return;
}
}
int
SocketHandle() /* handle data from the server incomming on the socket */
{
int i,j;
int gx,gy,dx,dy;
if(readdata(rsd,&rdata)!=sizeof(DATA))
{
fprintf(stderr,"%s: Recieved bad data\n");
exit(1);
}
switch(INSWAP(rdata.type))
{
case T_REPLY:
gx=(player[myid].pos.x/OBJECTSCALE)-cur.scx;
gy=(player[myid].pos.y/OBJECTSCALE)-cur.scy;
dy=gy-(MAINX/(2*OBJECTSCALE));
dx=gx-(MAINX/(2*OBJECTSCALE));
doexplosions();
if(checkscroll(&dx,&dy)>1)
scroll(dx,dy);
for(i=0;i<MAXUSERS;i++)
{
if(INSWAP(rdata.extra.reply.pos[i].x)==-1)
continue;
WipeTank(player[i].pos.x,player[i].pos.y,player[i].pos.rot,i);
player[i].pos.x=INSWAP(rdata.extra.reply.pos[i].x);
player[i].pos.y=INSWAP(rdata.extra.reply.pos[i].y);
player[i].pos.rot=INSWAP(rdata.extra.reply.pos[i].rot);
DrawTank(player[i].pos.x,player[i].pos.y,player[i].pos.rot,i);
XFlush(Disp);
}
/* update current position */
cur.x=player[myid].pos.x;
cur.y=player[myid].pos.y;
cur.rot=player[myid].pos.rot;
/* remove any 'spare' data from the pipe */
if(read(pd[0],&garbage,sizeof(POSITION))==-1)
{
if((errno!=EWOULDBLOCK)&&(errno!=EAGAIN))
perror("read pd[0]");
}
/* tell our 'other half' about our new position */
if(write(pd[1],&cur,sizeof(POSITION))==-1)
perror("write pd[0]");
break;
case T_ACCEPT:
for(i=0;i<MAXUSERS;i++)
{
if((*(player[i].user.username)!='\0')&&(*(rdata.extra.accept.players[i].username)=='\0'))
{
WipeTank(player[i].pos.x,player[i].pos.y,player[i].pos.rot,i);
/*DrawRadarSq(player[i].pos.x/OBJECTSCALE,player[i].pos.x/OBJECTSCALE,1);*/
}
strcpy(player[i].user.username,rdata.extra.accept.players[i].username);
strcpy(player[i].user.hostname,rdata.extra.accept.players[i].hostname);
player[i].kills=INSWAP(rdata.extra.accept.kills[i]);
player[i].killed=INSWAP(rdata.extra.accept.killed[i]);
}
RefreshRWin(1);
RefreshSWin(1);
break;
case T_EXPLOSION:
damage=INSWAP(rdata.extra.explosion.damage[myid]);
RefreshAWin(1);
for(i=0;i<MAXUSERS;i++)
{
if(exptime[i]==(-1))
{
ex[i]=INSWAP(rdata.extra.explosion.x)-(cur.scx*OBJECTSCALE);
ey[i]=INSWAP(rdata.extra.explosion.y)-(cur.scy*OBJECTSCALE);
if((ex[i]<(-1*EXPSIZE))||(ey[i]<(-1*EXPSIZE))||(ex[i]>(MAINX+EXPSIZE))||(ey[i]>(EXPSIZE+MAINY)))
break;
exptime[i]=gettime();
break;
}
}
break;
case T_MESSAGE:
strcpy(message,rdata.extra.message.text);
RefreshMWin(1);
break;
case T_ALIVE:
sdata.type=OUTSWAP(T_ALIVE);
senddata(ssd,&sdata);
break;
default:
printf("Unexpected datagram type %d (0x%x)\n",INSWAP(rdata.type),INSWAP(rdata.type));
}
}
int
EventHandle() /* handle X events */
{
XEvent Evnt;
XNextEvent(Disp,&Evnt);
if(read(pd[0],&cur,sizeof(POSITION))==-1)
{
if((errno!=EWOULDBLOCK)&&(errno!=EAGAIN))
perror("read pd[0]");
}
switch(Evnt.type)
{
case ButtonPress:
{
int bno;
XButtonEvent *BEvent;
BEvent=(XButtonEvent*)(&Evnt);
bno=BEvent->button;
if(BEvent->window==FWin)
{
mrot=GetAngle(cur.x,cur.y,msx,msy);
switch(bno)
{
case 1:
if(damage<MAXDAMAGE)
fire=1;
break;
case 2:
motion=invert;
break;
case 3:
motion=0-invert;
break;
}
sendstatus();
}
else
{
if(BEvent->window==QWin)
switch(bno)
{
case 1:
signoff(0,QUIT);
break;
case 2:
/* DEBUG */
printf("cur.scx,cur.scy=%d,%d msx,msy=%d,%d\n",cur.scx,cur.scy,msx,msy);
printf("tankx,tanky=%d,%d\n",cur.x,cur.y);
break;
}
}
}
break;
case ButtonRelease:
{
int bno;
XButtonEvent *BEvent;
BEvent=(XButtonEvent*)(&Evnt);
bno=BEvent->button;
if(BEvent->window==FWin)
{
mrot=GetAngle(cur.x,cur.y,msx,msy);
switch(bno)
{
case 1:
fire=0;
sendstatus();
break;
case 2:
if(motion==invert)
{
motion=0;
sendstatus();
}
break;
case 3:
if(motion==(0-invert))
{
motion=0;
sendstatus();
}
break;
}
}
else
{
printf("Button release outside battlefield\n");
}
}
break;
case MotionNotify:
{
XMotionEvent *MEvent;
MEvent=(XMotionEvent*)(&Evnt);
msx=(MEvent->x)+(cur.scx*OBJECTSCALE);
msy=(MEvent->y)+(cur.scy*OBJECTSCALE);
mrot=GetAngle(cur.x,cur.y,msx,msy);
if(MEvent->window==FWin)
{
if((MEvent->time-movetime)>100)
{
sendstatus();
movetime=MEvent->time;
}
}
else
{
printf("Mouse movement outside battlefield\n");
}
}
break;
case GraphicsExpose:
case Expose:
{
XExposeEvent *EEvent;
EEvent=(XExposeEvent*)(&Evnt);
if(EEvent->count==0)
{
DoRefresh(EEvent->window);
}
}
break;
case DestroyNotify:
{
XDestroyWindowEvent *XDEvent;
XDEvent=(XDestroyWindowEvent*)(&Evnt);
signoff(0,DESTROYED);
}
break;
case KeyPress:
case KeyRelease:
{
char buf[2];
int oldinvert;
XKeyEvent *KEvent;
buf[1]='\0';
KEvent=(XKeyEvent*)(&Evnt);
XLookupString(KEvent,buf,1,NULL,NULL);
if(*buf==0x03)
signoff(0,QUIT);
oldinvert=invert;
if(Evnt.type==KeyPress)
invert=(-1);
else
invert=1;
if(oldinvert!=invert)
{
motion=0-motion;
sendstatus();
}
}
break;
default:
/* fprintf(stderr,"Unknown Event\n");*/
break;
}
}
void
CreatePixmaps()
{
int i,j;
int rot;
XGCValues gcv;
GC GcPF,GcPB;
Pixmap Dummy;
if(pixflag)
{
Dummy=XCreatePixmap(Disp,Win,PIXSIZE,PIXSIZE,1);
gcv.function = GXcopy;
gcv.plane_mask =AllPlanes;
gcv.fill_style = FillSolid;
GcPF=XCreateGC(Disp,Dummy,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
XSetForeground(Disp,GcPF,1);
XSetBackground(Disp,GcPF,0);
GcPB=XCreateGC(Disp,Dummy,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
XSetForeground(Disp,GcPB,0);
XSetBackground(Disp,GcPB,1);
for(i=0;i<TANKROT;i++)
{
TankPix[i]=XCreatePixmap(Disp,Win,PIXSIZE,PIXSIZE,1);
if(TankPix[i]==BadAlloc)
{
/* no memory for pixmaps on server */
fprintf(stderr,"Failed to allocate pixmaps(%d)(%d*%d*%d), using polygons instead\n",i,PIXSIZE,PIXSIZE,1);
/* free currently allocated pixmaps */
for(j=0;j<i;j++)
XFreePixmap(Disp,TankPix[j]);
pixflag=0;
polyflag=1;
break;
}
rot=(i+TANKROT+(TANKROT/4))%TANKROT;
Tank[rot].coord[0].x=PIXSIZE/2;
Tank[rot].coord[0].y=PIXSIZE/2;
XFillRectangle(Disp,TankPix[i],GcPB,0,0,PIXSIZE,PIXSIZE);
XFillPolygon(Disp,TankPix[i],GcPF,&Tank[rot],TANKPOINTS,Nonconvex,CoordModePrevious);
}
/* no longer needed */
XFreeGC(Disp,GcPF);
XFreeGC(Disp,GcPB);
XFreePixmap(Disp,Dummy);
}
}
Xinit(Name,xs,ys) /* initialise X */
char *Name;
int xs,ys;
{
unsigned long bg,fg;
Cursor Curs;
XGCValues gcv;
char *DisplayName;
Pixmap iconised;
XWMHints hint;
int i;
DisplayName=getenv("DISPLAY");
if(DisplayName==NULL)
{
fprintf(stderr,"%s: $DISPLAY not set\n",progname);
exit(1);
}
Disp=XOpenDisplay(DisplayName);
if(Disp==NULL)
{
fprintf(stderr,"%s: Unable to open $DISPLAY (%s)\n",progname,DisplayName);
exit(1);
}
Root=XDefaultRootWindow(Disp);
Scr=DefaultScreen(Disp);
/* if user has specified no defaults */
if((!polyflag)&&(!pixflag))
{
pixflag=1;
polyflag=0;
}
fg=BlackPixel(Disp,Scr);
bg=WhitePixel(Disp,Scr);
/* Main (parent window */
Win=XCreateSimpleWindow(Disp,Root,0,0,xs,ys,2,fg,bg);
/* Radar window */
RWin=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER,RADARSIZE,RADARSIZE,1,fg,bg);
/* Field window */
FWin=XCreateSimpleWindow(Disp,Win,BOARDER*4+RADARSIZE,BOARDER,MAINX,MAINY,1,fg,bg);
/* Armour status window */
AWin=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER*4+RADARSIZE,RADARSIZE-2,DAMAGEBAR,2,fg,bg);
/* Quit window */
QWin=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER*5+RADARSIZE+DAMAGEBAR,RADARSIZE-2,MESSAGESIZE,2,fg,bg);
/* Message window */
MWin=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER*6+MESSAGESIZE+RADARSIZE+DAMAGEBAR,RADARSIZE,MESSAGESIZE,1,fg,bg);
/* Status window */
SWin=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER*7+MESSAGESIZE*2+RADARSIZE+DAMAGEBAR,RADARSIZE,15*(MAXUSERS+1),1,fg,bg);
/* Main vertical and horizontal scroll bars */
VSb=XCreateSimpleWindow(Disp,Win,BOARDER*5+RADARSIZE+MAINX,BOARDER,SCROLLBAR,MAINY-2,2,fg,bg);
HSb=XCreateSimpleWindow(Disp,Win,BOARDER*4+RADARSIZE,BOARDER*2+MAINY,MAINX-2,SCROLLBAR,2,fg,bg);
/* Radar vertical and horizontal scroll bars */
RVSb=XCreateSimpleWindow(Disp,Win,BOARDER*2+RADARSIZE,BOARDER,BOARDER,RADARSIZE,1,fg,bg);
RHSb=XCreateSimpleWindow(Disp,Win,BOARDER,BOARDER*2+RADARSIZE,RADARSIZE,BOARDER,1,fg,bg);
XStoreName(Disp,Win,Name);
gcv.function = GXcopy;
gcv.plane_mask = AllPlanes;
gcv.fill_style = FillSolid;
GcF=XCreateGC(Disp,Win,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
GcB=XCreateGC(Disp,Win,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
XSetForeground(Disp,GcF,fg);
XSetBackground(Disp,GcF,bg);
XSetForeground(Disp,GcB,bg);
XSetBackground(Disp,GcB,fg);
gcv.function = GXor;
GcTF=XCreateGC(Disp,Win,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
gcv.function = GXandInverted;
GcTB=XCreateGC(Disp,Win,(GCFunction | GCPlaneMask | GCFillStyle),&gcv);
XSetForeground(Disp,GcTF,fg);
XSetBackground(Disp,GcTF,bg);
XSetForeground(Disp,GcTB,fg);
XSetBackground(Disp,GcTB,bg);
Curs=XCreateFontCursor(Disp,XC_crosshair);
XDefineCursor(Disp,Win,Curs);
iconised=XCreateBitmapFromData(Disp,Win,xtb_bits,xtb_width,xtb_height);
hint.flags=(InputHint|IconPixmapHint);
hint.input=True;
hint.icon_pixmap=iconised;
XSetWMHints(Disp,Win,&hint);
CreatePixmaps();
XSetIOErrorHandler(doXio);
}
void
SelectAllInputs()
{
XSelectInput(Disp,Win,ExposureMask|StructureNotifyMask);
XSelectInput(Disp,RWin,ExposureMask);
XSelectInput(Disp,FWin,FieldEventMask);
XSelectInput(Disp,QWin,ButtonMask|ExposureMask|StructureNotifyMask);
XSelectInput(Disp,SWin,ExposureMask);
XSelectInput(Disp,VSb,ExposureMask);
XSelectInput(Disp,HSb,ExposureMask);
XSelectInput(Disp,RVSb,ExposureMask);
XSelectInput(Disp,RHSb,ExposureMask);
XSelectInput(Disp,AWin,ExposureMask);
XSelectInput(Disp,MWin,ExposureMask);
}
void
MapAllWindows() /* obvious */
{
XMapWindow(Disp,Win);
XMapWindow(Disp,FWin);
XMapWindow(Disp,RWin);
XMapWindow(Disp,SWin);
XMapWindow(Disp,QWin);
XMapWindow(Disp,VSb);
XMapWindow(Disp,HSb);
XMapWindow(Disp,RVSb);
XMapWindow(Disp,RHSb);
XMapWindow(Disp,AWin);
XMapWindow(Disp,MWin);
XFlush(Disp);
}
main(argc,argv)
int argc;
char *argv[];
{
int i,j;
char *p;
int inport,outport;
int fieldok;
progname=argv[0];
server=getenv("XTB_SERVER");
p=getenv("XTB_INPORT");
if(p!=NULL)
inport=atoi(p);
else
inport=DEFCPORT;
p=getenv("XTB_OUTPORT");
if(p!=NULL)
outport=atoi(p);
else
outport=DEFSPORT;
for(i=1;i<argc;i++)
{
p=argv[i];
if(*p++=='-')
{
switch(*p++)
{
case 'i': /* input/client port */
case 'c':
if(*p=='\0')
inport=atoi(argv[++i]);
else
inport=atoi(p);
break;
case 'o': /* output/server port */
case 's':
if(*p=='\0')
outport=atoi(argv[++i]);
else
outport=atoi(p);
break;
case 'h':
if(*p=='\0')
server=argv[++i];
else
server=p;
break;
case 'w':
warpflag++;
break;
case 'd':
debug++;
break;
case 'b': /* use pixmaps for drawing tanks */
pixflag++;
break;
case 'p': /* use polygons for drawing tanks */
polyflag++;
break;
default:
fprintf(stderr,"Usage: %s [-h server_host] [-w] [-c client_portno] [-s server_portno] \n",argv[0]);
}
}
}
if(server==NULL)
{
fprintf(stderr,"%s: No server host (-h or $XTB_SERVER) defined\n",argv[0]);
exit(1);
}
rsd=openread(inport);
if(rsd==(-1))
{
fprintf(stderr,"%s: Opening port %d failed\n",argv[0],inport);
exit(1);
}
ssd=opensend(server,outport);
if(ssd==(-1))
{
fprintf(stderr,"%s: Connecting to %s/%d failed\n",argv[0],server,outport);
exit(1);
}
for(i=0;i<MAXUSERS;i++)
exptime[i]=(-1);
InitTables();
Xinit("XTankBattle",MAINX+RADARSIZE+6*BOARDER+SCROLLBAR,MAINY+3*BOARDER+SCROLLBAR);
/* signon */
sdata.type=OUTSWAP(T_SIGNON);
sdata.extra.signon.version=OUTSWAP(VERSION);
sdata.extra.signon.port=OUTSWAP(inport); /* could be different to server port */
gethostname(sdata.extra.signon.hostname,HOSTLEN);
strncpy(sdata.extra.signon.username,((struct passwd*)getpwuid(getuid()))->pw_name,NAMELEN-1);
sdata.extra.signon.username[NAMELEN]='\0';
signal(SIGALRM,timeout);
alarm(3);
senddata(ssd,&sdata);
if(readdata(rsd,&rdata)!=sizeof(DATA))
{
fprintf(stderr,"%s: Recieved bad data\n");
exit(1);
}
alarm(0);
switch(INSWAP(rdata.type))
{
case T_ACCEPT:
if(debug)
{
printf("accept\n");
printf("My id is %d\n",INSWAP(rdata.extra.accept.id));
}
myid=INSWAP(rdata.extra.accept.id);
for(i=0;i<MAXUSERS;i++)
{
strcpy(player[i].user.username,rdata.extra.accept.players[i].username);
strcpy(player[i].user.hostname,rdata.extra.accept.players[i].hostname);
player[i].kills=INSWAP(rdata.extra.accept.kills[i]);
player[i].killed=INSWAP(rdata.extra.accept.killed[i]);
}
break;
case T_REJECT:
fprintf(stderr,"reject\n");
fprintf(stderr,"reason: %s\n",rdata.extra.reject.text);
exit(1);
break;
default:
if(debug)
printf("Unknown datagram type %d (0x%x)\n",INSWAP(rdata.type),INSWAP(rdata.type));
}
for(i=0;i<OBJECTSIZE;i++)
for(j=0;j<OBJECTSIZE;j++)
radar[i][j]=0;
for(i=0;i<OBJECTSIZE;i++)
field[i][0]=UNSET;
MapAllWindows();
if(debug)
printf("Getting field data\n");
sdata.id=OUTSWAP(myid);
sdata.type=OUTSWAP(T_DATAREQ);
do
{
fieldok=1;
for(i=0;i<OBJECTSIZE;i++)
{
if(field[i][0]==UNSET)
{
fflush(stdout);
fieldok=0;
sdata.extra.datareq.lineno=OUTSWAP(i);
senddata(ssd,&sdata);
if(readdata(rsd,&rdata)!=sizeof(DATA))
{
fprintf(stderr,"%s: Recieved bad data\n",argv[0]);
exit(1);
}
if(INSWAP(rdata.type)!=T_FIELDDATA)
{
if(INSWAP(rdata.type)==T_MESSAGE)
strcpy(message,rdata.extra.message.text);
else
fprintf(stderr,"%s: Expected field data got 0x%x\n",argv[0],INSWAP(rdata.type));
}
else
{
if(debug)
{
if(INSWAP(rdata.extra.field.lineno)!=i)
printf("%%%d",INSWAP(rdata.extra.field.lineno));
else
printf(".%d",i);
}
memcpy(field[INSWAP(rdata.extra.field.lineno)],rdata.extra.field.object,OBJECTSIZE);
}
}
}
}
while(!fieldok);
putchar('\n');
if(pipe(pd)==(-1))
{
fprintf(stderr,"%s: pipe(pd) failed\n",argv[0]);
exit(1);
}
/* make read pipe descripter non-blocking */
i=1;
if(ioctl(pd[0],FIONBIO,&i)==-1)
{
fcntl(pd[0],F_SETFL,O_NDELAY);
}
ppid=getpid();
signal(SIGHUP,dointr);
signal(SIGINT,dointr);
signal(SIGTERM,dointr);
RefreshRWin(0);
RefreshSWin(0);
RefreshQWin(0);
RefreshVSb(0);
RefreshHSb(0);
RefreshRVSb(0);
RefreshRHSb(0);
RefreshAWin(0);
RefreshMWin(0);
switch(cpid=fork())
{
case 0: /* child */
/* server -> socket -> X display */
cpid=getpid();
Disp=XOpenDisplay(getenv("DISPLAY"));
while(1)
{
SocketHandle();
}
break;
case -1: /* error */
fprintf(stderr,"%s: Couldn't fork()\n",argv[0]);
exit(1);
break;
default:/* parent */
/* X events -> socket -> server */
SelectAllInputs();
while(1)
EventHandle();
break;
}
}