#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>

#include "stdarg.h"
#include "build.h"
#include "names.h"

#include <stdio.h>
#include <string.h>

#define TICSPERFRAME 3
#define MOVEFIFOSIZ 256

#define   TEKWAR
#define   SECT_LOTAG_CLIMB                    5060

#ifdef    GAMEC
#define   WASSTATIC static
#endif

#ifdef    TEKWAR
#define   WASSTATIC        
// must match tekwar.h
#define   KENSPLAYERHEIGHT    34
#define   DOOMGUY             999 
#endif

#ifdef    TEKWAR
extern    void copyrightscreen(void);
extern    void depositsymbol(int snum);
extern    void showmessage(char *fmt,...);
extern    void netstartspot(long *x, long *y, short *sectnum);
extern    int  placerandompic(long);
extern    void domenuinput(void);
extern    void toss(short);
extern    long pickupclock;
extern    spritetype   pickup;
extern    void smkplayseq(char *name);
extern    void startgametime(void);
extern    void endgametime(void);
extern    int  choosemission(void);
extern    int  missionfailed(void);
extern    void cduninit(void);
extern    char debrief;
extern    void jstick(void);
#pragma   aux  jstick modify exact [eax ebx ecx edx esi edi];
extern    void clearpal(void);
extern    int  autocenter[];
extern    char tektempbuf[];
extern    long startx,starty,startz,starta,starts;
extern    char onelev[];
extern    long headbob;
extern    char gameover;
extern    char outofsync;
extern    char dofadein;
extern    char activemenu;
extern    int  ovmode;  
extern    int  mousesensitivity;
extern    int  cyberenabled;
extern    int  iglassenabled;
extern    int  vfx1enabled;
extern    char puckbuttons;
extern    short puckpitch,puckroll,puckbutton[];
extern    int  difficulty;
extern    int  mission;
FILE      *dbgfp;
int       dbgfilen;
char      dbgfname[16];
int       dbgflag;
int       dbgcolumn;
short     mousebias=1;
short     biasthreshhold=72;
char      biasthreshholdon=0;  
short     lastmousy;
char      keyedhorizon;
char      joycenteringon=0;
int       joyxcenter,joyycenter;
//** Les START - 09/26/95
char      jcalibration=0,joycenteringon,
          jstickenabled=0;
int       jctrx=0,joyxcenter,
          jctry=0,joyycenter;
int       jlowx,jlowy,
          jhighx,jhighy;
char      oldjoyb;
//** Les  END  - 09/26/95
short     yaw,pitch,roll,vrangle,vrpitch;
int       joyx,joyy;
char      joyb;
char      spaceballon=0;

//** Les START - 09/26/95
#include "avlib.h"

short     spaceballinitflag;
SPW_InputEvent sbpacket;
//** Les END   - 09/26/95
#endif

typedef struct
{
	long x, y, z;
} point3d;

#ifdef    GAMEC
void (__interrupt __far *oldtimerhandler)();
void __interrupt __far timerhandler(void);
#endif

#define KEYFIFOSIZ 64
void (__interrupt __far *oldkeyhandler)();
void __interrupt __far keyhandler(void);
volatile char keystatus[256], keyfifo[KEYFIFOSIZ], keyfifoplc, keyfifoend;
volatile char readch, oldreadch, extended, keytemp;

WASSTATIC long vel, svel, angvel;
WASSTATIC long vel2, svel2, angvel2;

extern volatile long recsnddone, recsndoffs;
WASSTATIC long recording = -2;

WASSTATIC long chainxres[4] = {256,320,360,400};
WASSTATIC long chainyres[11] = {200,240,256,270,300,350,360,400,480,512,540};
WASSTATIC long vesares[7][2] = {320,200,640,400,640,480,800,600,1024,768,
									  1280,1024,1600,1200};
#ifdef    GAMEC
#define NUMOPTIONS 8
#define NUMKEYS 19
WASSTATIC char option[NUMOPTIONS] = {0,0,0,0,0,0,1,0};
WASSTATIC char keys[NUMKEYS] =
{
	0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39,
	0x1e,0x2c,0xd1,0xc9,0x33,0x34,
	0x9c,0x1c,0xd,0xc,0xf,
};
WASSTATIC long digihz[7] = {6000,8000,11025,16000,22050,32000,44100};
#endif

#ifdef    TEKWAR
#define   NUMOPTIONS          8
#define   NUMKEYS             32
#define   MAXMOREOPTIONS      21
#define   MAXTOGGLES          16
#define   MAXGAMESTUFF        16
char option[NUMOPTIONS] = {
      1,       // 0  VIDEO MODE CHAINED OR NO
      0,       // 1  SOUND CHOICE
      0,       // 2  MUSIC CHOICE
      1,       // 3  MOUSE ON/OFF
      0,       // 4  MULTIPLAYER COUNT
      0,       // 5  MULTIPLYER SETTING
      0,       // 6  VIDEO RES CHOICE
      0        // 7  SOUND FREQ
};
char keys[NUMKEYS] = {
     200,         // 0  FWD
     208,         // 1  BKWD
     203,         // 2  RIGHT  
     205,         // 3  LEFT  
      42,         // 4  RUN / AMPLIFY  
      56,         // 5  STRAFE  
      29,         // 6  SHOOT  
      57,         // 7  USE  
      45,         // 8  JUMP  
      46,         // 9  CROUCH
     201,         // 10 LOOK UP  
     209,         // 11 LOOK DOWN  
      51,         // 12 SLIDE LEFT     
      52,         // 13 SLIDE RIGHT  
      15,         // 14 MAP MODE  
     156,         // 15 SWITCH PLAYER  
      13,         // 16 EXPAND VIEW
      12,         // 17 SHRINK VIEW
      50,         // 18 MESSAGE MODE  
     199,         // 19 AUTOCENTER
      19,         // 20 TOGGLE REARVIEW
      18,         // 21 TOGGLE PREPARED ITEM
      35,         // 22 TOGGLE HEALTH METER
      34,         // 23 TOGGLE CROSSHAIRS
      20,         // 24 TOGGLE ELAPSED TIME
      31,         // 25 TOGGLE SCORE
      23,         // 26 TOGGLE INVENTORY
      53,         // 27 CONCEAL WEAPON
      58,         // 28 MOUSE LOOKUP/DOWN
      26,         // 29 N/U
      26,         // 30 N/U
      26          // 31 N/U
};
char moreoptions[MAXMOREOPTIONS] = {
        1,     // 0  MOUSE ON/OFF         
       29,     // 1  MOUSE BUTTON 1 MAP
      200,     // 2  MOUSE BUTTON 2 MAP
        0,     // 3  JOYSTICK ON/OFF
        4,     // 4  JOYSTICK BUTTON 1 MAP
        6,     // 5  JOYSTICK BUTTON 2 MAP
       10,     // 6  JOYSTICK BUTTON 3 MAP
       11,     // 7  JOYSTICK BUTTON 4 MAP
        1,     // 8  DIFFICULTY LEVEL
       16,     // 9  SOUND VOLUME
       16,     // 10 MUSIC VOLUME
        8,     // 11 MOUSE SENSITIVITY
        1,     // 12 HEAD BOB
        0,     // 13 N/U
        0,     // 14 N/U
        0      // 15 N/U
};
char toggles[MAXTOGGLES] = { 1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0 };
int  gamestuff[MAXGAMESTUFF] = { 
     -1,       // 0  joyxcenter
     -1,       // 1  joyycenter
      0,       // 2  screensize
      0,       // 3  brightness
    100,       // 4  biasthreshhold
      0,       // 5  warpretang
      0,       // 6  warpretsect
      0,       // 7 
      0,       // 8 
      0,       // 9 
      0,       // 10
      0,       // 11
      0,       // 12
      0,       // 13
      0,       // 14
      0        // 15
};
#endif

WASSTATIC char frame2draw[MAXPLAYERS];
WASSTATIC long frameskipcnt[MAXPLAYERS];

WASSTATIC char gundmost[320];

#define LAVASIZ 128
#define LAVALOGSIZ 7
#define LAVAMAXDROPS 32
WASSTATIC char lavabakpic[(LAVASIZ+2)*(LAVASIZ+2)], lavainc[LAVASIZ];
WASSTATIC long lavanumdrops, lavanumframes;
WASSTATIC long lavadropx[LAVAMAXDROPS], lavadropy[LAVAMAXDROPS];
WASSTATIC long lavadropsiz[LAVAMAXDROPS], lavadropsizlookup[LAVAMAXDROPS];
WASSTATIC long lavaradx[32][128], lavarady[32][128], lavaradcnt[32];

	//Shared player variables
WASSTATIC long posx[MAXPLAYERS], posy[MAXPLAYERS], posz[MAXPLAYERS];
WASSTATIC long horiz[MAXPLAYERS], zoom[MAXPLAYERS], hvel[MAXPLAYERS];
WASSTATIC short ang[MAXPLAYERS], cursectnum[MAXPLAYERS], ocursectnum[MAXPLAYERS];
WASSTATIC short playersprite[MAXPLAYERS], deaths[MAXPLAYERS];
WASSTATIC long lastchaingun[MAXPLAYERS];
WASSTATIC long health[MAXPLAYERS], score[MAXPLAYERS], saywatchit[MAXPLAYERS];
WASSTATIC short numbombs[MAXPLAYERS], oflags[MAXPLAYERS];
WASSTATIC char dimensionmode[MAXPLAYERS];
WASSTATIC char revolvedoorstat[MAXPLAYERS];
WASSTATIC short revolvedoorang[MAXPLAYERS], revolvedoorrotang[MAXPLAYERS];
WASSTATIC long revolvedoorx[MAXPLAYERS], revolvedoory[MAXPLAYERS];

	//ENGINE CONTROLLED MULTIPLAYER VARIABLES:
extern short numplayers, myconnectindex;
extern short connecthead, connectpoint2[MAXPLAYERS];   //Player linked list variables (indeces, not connection numbers)

	//Local multiplayer variables
WASSTATIC long locselectedgun;
WASSTATIC signed char locvel, olocvel;
WASSTATIC short locsvel, olocsvel;                          // Les 09/27/95
WASSTATIC short locangvel, olocangvel;                      // Les 09/27/95
WASSTATIC short locbits, olocbits;

	//Local multiplayer variables for second player
WASSTATIC long locselectedgun2;
WASSTATIC signed char locvel2, olocvel2;
WASSTATIC short locsvel2, olocsvel2;                        // Les 09/27/95
WASSTATIC short locangvel2, olocangvel2;                    // Les 09/27/95
WASSTATIC short locbits2, olocbits2;

  //Multiplayer syncing variables
WASSTATIC signed char fsyncvel[MAXPLAYERS], osyncvel[MAXPLAYERS], syncvel[MAXPLAYERS];
WASSTATIC short fsyncsvel[MAXPLAYERS], osyncsvel[MAXPLAYERS], syncsvel[MAXPLAYERS];       // Les 09/27/95
WASSTATIC short fsyncangvel[MAXPLAYERS], osyncangvel[MAXPLAYERS], syncangvel[MAXPLAYERS]; // Les 09/27/95
WASSTATIC unsigned short fsyncbits[MAXPLAYERS], osyncbits[MAXPLAYERS], syncbits[MAXPLAYERS];

WASSTATIC char frameinterpolate = 1, detailmode = 0, ready2send = 0;
WASSTATIC long ototalclock = 0, gotlastpacketclock = 0, smoothratio;
WASSTATIC long oposx[MAXPLAYERS], oposy[MAXPLAYERS], oposz[MAXPLAYERS];
WASSTATIC long ohoriz[MAXPLAYERS], ozoom[MAXPLAYERS];
WASSTATIC short oang[MAXPLAYERS];

WASSTATIC point3d osprite[MAXSPRITESONSCREEN];

WASSTATIC long movefifoplc, movefifoend;
WASSTATIC signed char baksyncvel[MOVEFIFOSIZ][MAXPLAYERS];
WASSTATIC short baksyncsvel[MOVEFIFOSIZ][MAXPLAYERS];       // Les 09/27/95
WASSTATIC short baksyncangvel[MOVEFIFOSIZ][MAXPLAYERS];     // Les 09/27/95
WASSTATIC short baksyncbits[MOVEFIFOSIZ][MAXPLAYERS];

	//MULTI.OBJ sync state variables
extern char syncstate;
	//GAME.C sync state variables
WASSTATIC short syncstat = 0;
WASSTATIC long syncvalplc, othersyncvalplc;
WASSTATIC long syncvalend, othersyncvalend;
WASSTATIC long syncvalcnt, othersyncvalcnt;
WASSTATIC short syncval[MOVEFIFOSIZ], othersyncval[MOVEFIFOSIZ];

extern long crctable[256];
#define updatecrc16(dacrc,dadat) dacrc = (((dacrc<<8)&65535)^crctable[((((unsigned short)dacrc)>>8)&65535)^dadat])
WASSTATIC char playerreadyflag[MAXPLAYERS];

	//Game recording variables
WASSTATIC long reccnt, recstat = 1;
WASSTATIC signed char recsyncvel[16384][2];
WASSTATIC short recsyncsvel[16384][2];                      // Les 09/27/95
WASSTATIC short recsyncangvel[16384][2];                    // Les 09/27/95
WASSTATIC short recsyncbits[16384][2];

	//Miscellaneous variables
WASSTATIC char tempbuf[max(576,MAXXDIM)], boardfilename[80];
WASSTATIC short screenpeek = 0, oldmousebstatus = 0, brightness = 0;
WASSTATIC short screensize, screensizeflag = 0;
WASSTATIC short neartagsector, neartagwall, neartagsprite;
WASSTATIC long lockclock, neartagdist, neartaghitdist;
WASSTATIC long masterslavetexttime;
extern long frameplace, pageoffset, ydim16, chainnumpages;
WASSTATIC long globhiz, globloz, globhihit, globlohit;
extern long stereofps, stereowidth, stereopixelwidth;

	//Board animation variables
WASSTATIC short rotatespritelist[16], rotatespritecnt;
WASSTATIC short warpsectorlist[64], warpsectorcnt;
WASSTATIC short xpanningsectorlist[16], xpanningsectorcnt;
WASSTATIC short ypanningwalllist[64], ypanningwallcnt;
WASSTATIC short floorpanninglist[64], floorpanningcnt;
WASSTATIC short dragsectorlist[16], dragxdir[16], dragydir[16], dragsectorcnt;
WASSTATIC long dragx1[16], dragy1[16], dragx2[16], dragy2[16], dragfloorz[16];
WASSTATIC short swingcnt, swingwall[32][5], swingsector[32];
WASSTATIC short swingangopen[32], swingangclosed[32], swingangopendir[32];
WASSTATIC short swingang[32], swinganginc[32];
WASSTATIC long swingx[32][8], swingy[32][8];
WASSTATIC short revolvesector[4], revolveang[4], revolvecnt;
WASSTATIC long revolvex[4][16], revolvey[4][16];
WASSTATIC long revolvepivotx[4], revolvepivoty[4];
WASSTATIC short subwaytracksector[4][128], subwaynumsectors[4], subwaytrackcnt;
WASSTATIC long subwaystop[4][8], subwaystopcnt[4];
WASSTATIC long subwaytrackx1[4], subwaytracky1[4];
WASSTATIC long subwaytrackx2[4], subwaytracky2[4];
WASSTATIC long subwayx[4], subwaygoalstop[4], subwayvel[4], subwaypausetime[4];
WASSTATIC short waterfountainwall[MAXPLAYERS], waterfountaincnt[MAXPLAYERS];
WASSTATIC short slimesoundcnt[MAXPLAYERS];

	//Variables that let you type messages to other player
WASSTATIC char getmessage[162], getmessageleng;
WASSTATIC long getmessagetimeoff;
WASSTATIC char typemessage[162], typemessageleng = 0, typemode = 0;
WASSTATIC char scantoasc[128] =
{
	0,0,'1','2','3','4','5','6','7','8','9','0','-','=',0,0,
	'q','w','e','r','t','y','u','i','o','p','[',']',0,0,'a','s',
	'd','f','g','h','j','k','l',';',39,'`',0,92,'z','x','c','v',
	'b','n','m',',','.','/',0,'*',0,32,0,0,0,0,0,0,
	0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
	'2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};
WASSTATIC char scantoascwithshift[128] =
{
	0,0,'!','@','#','$','%','^','&','*','(',')','_','+',0,0,
	'Q','W','E','R','T','Y','U','I','O','P','{','}',0,0,'A','S',
	'D','F','G','H','J','K','L',':',34,'~',0,'|','Z','X','C','V',
	'B','N','M','<','>','?',0,'*',0,32,0,0,0,0,0,0,
	0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
	'2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};

	//These variables are for animating x, y, or z-coordinates of sectors,
	//walls, or sprites (They are NOT to be used for changing the [].picnum's)
	//See the setanimation(), and getanimategoal() functions for more details.
#define MAXANIMATES 512
WASSTATIC long *animateptr[MAXANIMATES], animategoal[MAXANIMATES];
WASSTATIC long animatevel[MAXANIMATES], animateacc[MAXANIMATES], animatecnt = 0;

	//Here are some nice in-line assembly pragmas that make life easier.
	//(at least for Ken)
#pragma aux setvmode =\
	"int 0x10",\
	parm [eax]\

#pragma aux clearbuf =\
	"rep stosd",\
	parm [edi][ecx][eax]\

#pragma aux clearbufbyte =\
	"shr ecx, 1",\
	"jnc skip1",\
	"stosb",\
	"skip1: shr ecx, 1",\
	"jnc skip2",\
	"stosw",\
	"skip2: test ecx, ecx",\
	"jz skip3",\
	"rep stosd",\
	"skip3:",\
	parm [edi][ecx][eax]\

#pragma aux copybuf =\
	"rep movsd",\
	parm [esi][edi][ecx]\

#pragma aux copybufbyte =\
	"shr ecx, 1",\
	"jnc skip1",\
	"movsb",\
	"skip1: shr ecx, 1",\
	"jnc skip2",\
	"movsw",\
	"skip2: test ecx, ecx",\
	"jz skip3",\
	"rep movsd",\
	"skip3:",\
	parm [esi][edi][ecx]\

#pragma aux copybufreverse =\
	"shr ecx, 1",\
	"jnc skipit1",\
	"mov al, byte ptr [esi]",\
	"dec esi",\
	"mov byte ptr [edi], al",\
	"inc edi",\
	"skipit1: shr ecx, 1",\
	"jnc skipit2",\
	"mov ax, word ptr [esi-1]",\
	"sub esi, 2",\
	"ror ax, 8",\
	"mov word ptr [edi], ax",\
	"add edi, 2",\
	"skipit2: test ecx, ecx",\
	"jz endloop",\
	"begloop: mov eax, dword ptr [esi-3]",\
	"sub esi, 4",\
	"bswap eax",\
	"mov dword ptr [edi], eax",\
	"add edi, 4",\
	"dec ecx",\
	"jnz begloop",\
	"endloop:",\
	parm [esi][edi][ecx]\

#pragma aux klabs =\
	"test eax, eax",\
	"jns skipnegate",\
	"neg eax",\
	"skipnegate:",\
	parm [eax]\

#pragma aux ksgn =\
	"add ebx, ebx",\
	"sbb eax, eax",\
	"cmp eax, ebx",\
	"adc eax, 0",\
	parm [ebx]\

#pragma aux koutp =\
	"out dx, al",\
	parm [edx][eax]\

#pragma aux koutpw =\
	"out dx, ax",\
	parm [edx][eax]\

#pragma aux kinp =\
	"in al, dx",\
	parm [edx]\

#pragma aux mulscale =\
	"imul ebx",\
	"shrd eax, edx, cl",\
	parm [eax][ebx][ecx]\
	modify [edx]\

#pragma aux divscale =\
	"mov edx, eax",\
	"sar edx, 31",\
	"shld edx, eax, cl",\
	"sal eax, cl",\
	"idiv ebx",\
	parm [eax][ebx][ecx]\
	modify [edx]\

#pragma aux scale =\
	"imul ebx",\
	"idiv ecx",\
	parm [eax][ebx][ecx]\
	modify [eax edx]\


void
debugout(short p)
{
     static int dbglines;

     if (dbgcolumn != 0) {
          fprintf(dbgfp,"\n");
     }
     fprintf(dbgfp,"%2d %6ld %3ld %04X %04d %06ld %06ld %06ld %06ld %ld\n",
                    p,lockclock,movefifoplc,syncbits[p],ang[p],posx[p],posy[p],posz[p],
                    health[p],randomseed);
     dbglines++;
     dbgcolumn=0;
     if (dbglines > 2000) {
          dbglines=0;
          fclose(dbgfp);
          sprintf(dbgfname,"DEBUG.%03d",dbgfilen++);
          dbgfp=fopen(dbgfname,"wt");
          fprintf(dbgfp," P  CLOCK PLC BITS  ANG   X     Y     Z   HEALTH RSEED\n");
          fprintf(dbgfp,"== ====== === ==== ==== ===== ===== ===== ====== =========\n");
     }
}


#define   MAXNAMESIZE    11
#define   NETNAMES
#define   lm(_str_) printf(" %s...\n", _str_);
char      localname[MAXNAMESIZE];
char      netnames[MAXPLAYERS][MAXNAMESIZE];

main(short int argc,char **argv)
{
	long      i, j, k, l, fil, waitplayers, x1, y1, x2, y2;
     short     other, tempbufleng;
	char      *ptr;

     startgametime();

     initgroupfile("stuff.dat");
     tekargv(argc, argv);
     lm("tektextmode");
     tektextmode();
     lm("tekloadsetup");
     tekloadsetup();
     lm("initkeys");
	initkeys();
     lm("inittimer");
	inittimer();
     lm("tekinitmultiplayers");
     tekinitmultiplayers();
     lm("initsb");
	initsb(option[1],option[2],0,0,0,0,0);
     lm("loadpics");
	loadpics("tiles000.art");                     
     lm("tekpreinit");
     tekpreinit();
     lm("tekgamestarted");
     tekgamestarted();
     lm("initmouse");
	if( option[3] != 0 ) initmouse();

//** Les START - 09/26/95
     if( spaceballon ) {
          lm("spaceball init");
          spaceballinitflag=SPW_InputCheckForSpaceball(0);
          if (spaceballinitflag) {
               lm("Spaceball initialized");
          }
     }
//** Les END   - 09/26/95

     if (dbgflag) {
          lm("debug mode: ON");
          sprintf(dbgfname,"DEBUG.%03d",dbgfilen++);
          dbgfp=fopen(dbgfname,"wt");
          fprintf(dbgfp," P  CLOCK PLC BITS  ANG   X     Y     Z   HEALTH RSEED\n");
          fprintf(dbgfp,"== ====== === ==== ==== ===== ===== ===== ====== =========\n");
          dbgcolumn=0;
     }

	if( option[4] > 0 ) {
        lm("multiplayer init");
        teknetpickmap();
		sendlogon();
		if( option[4] < 5 ) {
               waitplayers=2; 
          }
          else {
               waitplayers=option[4]-3;
          }
		while( numplayers < waitplayers ) {
               clearview(0);
               overwritesprite((xdim>>1)-160,0,408,0,0,0);
		     sprintf(tempbuf,"  MULTIPLAYER MODE  ");
		     printext((xdim>>1)-80,(ydim>>1)-24,tempbuf,ALPHABET2,0);
		     sprintf(tempbuf,"%2d OF %2d PLAYERS IN",numplayers,waitplayers);
		     printext((xdim>>1)-80,ydim>>1,tempbuf,ALPHABET2,0);
               nextpage();
			if( getpacket(&other,tempbuf) > 0 ) {
			     if( tempbuf[0] == 255 ) {
					keystatus[1] = 1;
                    }
               }
			if( keystatus[1] > 0 ) {
                    goto gameends;
			}
		}
		screenpeek = myconnectindex;
          clearview(0);
	}
     for( i=connecthead ; i >= 0 ; i=connectpoint2[i] ) {
          initplayersprite((short)i);
     }

     if( option[4] == 0 ) {
          smkplayseq("INTRO");
     }

missionselection:
     if( option[4] == 0 ) {
          if( choosemission() == 0 ) {
               goto gameends;
          }
     }

	reccnt=0;
	movefifoplc = 0; movefifoend = 0;
	syncvalplc = 0; othersyncvalplc = 0;
	syncvalend = 0; othersyncvalend = 0;
	syncvalcnt = 0L; othersyncvalcnt = 0L;
	olocvel = 0; olocvel2 = 0;
	olocsvel = 0; olocsvel2 = 0;
	olocangvel = 0; olocangvel2 = 0;
	olocbits = 0; olocbits2 = 0;
	lockclock = 0;
	ototalclock = 0;
	gotlastpacketclock = 0;
	masterslavetexttime = 0;
	for( i=0; i<MAXPLAYERS; i++ ) {
		fsyncvel[i] = syncvel[i] = osyncvel[i] = 0;
		fsyncsvel[i] = syncsvel[i] = osyncsvel[i] = 0;
		fsyncangvel[i] = syncangvel[i] = osyncangvel[i] = 0;
		fsyncbits[i] = syncbits[i] = osyncbits[i] = 0;
	}
     resettiming(); 

     ready2send = 1;
    #ifdef NETNAMES
     if( option[4] != 0 ) {
          tempbuf[0]=8;
          tempbuf[1]=myconnectindex;
          memcpy(&tempbuf[2],localname,10);
          tempbuf[12]=0;
	     for( i=connecthead; i>=0; i=connectpoint2[i] ) {
          	if( i != myconnectindex ) {
	     	     sendpacket(i,tempbuf,12);
               }
          }
          memcpy(netnames[myconnectindex],localname,10);
          netnames[myconnectindex][10]=0;
     }
    #endif           
     screenpeek=myconnectindex;
	while( !gameover ) {
		while( movefifoplc != movefifoend ) {
               domovethings();
          }
		drawscreen(screenpeek,(totalclock-gotlastpacketclock)*(65536/TICSPERFRAME));
	}
	ready2send = 0;

     if( option[4] == 0 ) {
          debrief=1;
          goto missionselection;
     }

gameends:

     copyrightscreen();

	sendlogoff();        
	uninitmultiplayers();
	uninitsb();
     cduninit();
	uninittimer();
	uninitkeys();
	uninitengine();
	uninitgroupfile();

//** Les START - 09/26/95
    if (spaceballinitflag) {
        SPW_InputShutdown(0);
    }
//** Les END   - 09/26/95

     teksavesetup();
	setvmode(ovmode); 
     endgametime();

     if (dbgflag) {
          fclose(dbgfp);
     }
    #ifdef SHOWFRAMERATE
     if( option[4] == 0 ) {
	     showengineinfo();    
     }
    #endif

	exit(0);
}

void crash(char *,...);

processinput(short snum)
{
	long      oldposx, oldposy, nexti;
	long      i,j,k, doubvel, xvect, yvect, goalz;
	long      dax, day, dax2, day2, odax, oday, odax2, oday2;
	short     startwall, endwall;
	char      *ptr;

     // move player snum
    if (snum < 0 || snum >= MAXPLAYERS) {
        crash("game712: Invalid player number (%d)",snum);
    }

     if (cursectnum[snum] < 0 || cursectnum[snum] >= numsectors) {
          crash("game718: Invalid sector for player %d @ %ld,%ld (%d)",snum,
               posx[snum],posy[snum],cursectnum[snum]);
     }

    if( (syncvel[snum]|syncsvel[snum]) != 0 ) {
          // no run while crouching 
          if( ((syncbits[snum]&2) != 0) && (mission != 7) ) {
	          doubvel = 1+((syncbits[snum]&256) == 0);
          }
          else {
	          doubvel = (TICSPERFRAME<<((syncbits[snum]&256)>0));
               doubvel<<=1;  
          }
		xvect = 0, yvect = 0;
		if( syncvel[snum] != 0 ) {
			xvect += ((((long)syncvel[snum])*doubvel*(long)sintable[(ang[snum]+2560)&2047])>>3);
			yvect += ((((long)syncvel[snum])*doubvel*(long)sintable[(ang[snum]+2048)&2047])>>3);
		}
		if( syncsvel[snum] != 0 ) {
			xvect += ((((long)syncsvel[snum])*doubvel*(long)sintable[(ang[snum]+2048)&2047])>>3);
			yvect += ((((long)syncsvel[snum])*doubvel*(long)sintable[(ang[snum]+1536)&2047])>>3);
		}
		clipmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],xvect,yvect,128L,4<<8,4<<8,0);
		frameinterpolate = 1;
		revolvedoorstat[snum] = 1;
          if( option[4] == 0 ) {
               tekheadbob();
          }
	}
	else {
		revolvedoorstat[snum] = 0;
          headbob=0;
	}

	// push player away from walls if clipmove doesn't work
	if( pushmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],128L,4<<8,4<<8,0) < 0 ) {
	     changehealth(snum,-1000);  // if this fails then instant death
          changescore(snum,-5);
     }

     if (cursectnum[snum] < 0 || cursectnum[snum] >= numsectors) {
          crash("game748: Invalid sector for player %d @ %ld,%ld (%d)",snum,
               posx[snum],posy[snum],cursectnum[snum]);
     }
     if (playersprite[snum] < 0 || playersprite[snum] >= MAXSPRITES) {
          crash("game751: Invalid sprite for player %d (%d)",snum,playersprite[snum]);
     }

	// getzrange returns the highest and lowest z's for an entire box,
	// NOT just a point.  This prevents you from falling off cliffs
	// when you step only slightly over the cliff.
	sprite[playersprite[snum]].cstat ^= 1;
	getzrange(posx[snum],posy[snum],posz[snum],cursectnum[snum],&globhiz,&globhihit,&globloz,&globlohit,128L,0);
	sprite[playersprite[snum]].cstat ^= 1;

     if( cursectnum[snum] != ocursectnum[snum] ) {
          teknewsector(snum);
     }

     if (iglassenabled || cyberenabled || vfx1enabled) {
          if (iglassenabled) {
               vio_read(&yaw,&pitch,&roll);
          }
          else if (cyberenabled) {
               ctm_read(&yaw,&pitch,&roll);
          }
          else if (vfx1enabled) {                                     // Les 09/28/95
               vfx1_read(&yaw,&pitch,&roll,                           // Les 09/29/95
                    &puckpitch,&puckroll,&puckbuttons);               // Les 09/29/95
          }                                                           // Les 09/28/95
          vrangle=(1024-(yaw>>4))&2047;
          vrpitch=100+(pitch/82);
          if (vrpitch < 0) {
               vrpitch=0;
          }
          else if (vrpitch > 200) {
               vrpitch=200;
          }
          ang[snum]=vrangle;
          horiz[snum]=vrpitch;
     }

     // ang += angvel*constant, engine calculates angvel
	if( syncangvel[snum] != 0 ) {      
		doubvel = TICSPERFRAME;
          // if run key then turn faster 
		if( (syncbits[snum]&256) > 0 ) {
			doubvel += (TICSPERFRAME>>1);
          }
		ang[snum] += ((((long)syncangvel[snum])*doubvel)>>4);
		ang[snum] = (ang[snum]+2048)&2047;
	}

	if( health[snum] < 0 ) {
		health[snum] -= (TICSPERFRAME<<1);
		if( health[snum] <= -160 ) {
			hvel[snum] = 0;
			if( snum == myconnectindex ) {
				vel = 0, svel = 0, angvel = 0, keystatus[3] = 1;
               }
			deaths[snum]++;
               if( (option[4] == 0) && (numplayers == 1) ) {
                    fadeout(0,255,32,0,0,100);
               }
               if( option[4] != 0 ) {
                    netstartspot(&posx[snum],&posy[snum],&cursectnum[snum]);
                    if (cursectnum[snum] < 0 || cursectnum[snum] >= numsectors) {
                         crash("game818: Invalid sector for player %d (%d)",snum,cursectnum[snum]);
                    }
                    placerandompic(KLIPPIC);
                    placerandompic(MEDICKITPIC);
                    posz[snum] = sector[cursectnum[snum]].floorz-(1<<8);
                    ang[snum] = (krand_intercept("GAME 802")&2047);
               }
               else {
                    posx[snum]=startx;
                    posy[snum]=starty;
                    posz[snum]=startz;
                    ang[snum]=starta;
                    cursectnum[snum]=starts;
               }

               tekrestoreplayer(snum);

               if( (option[4] == 0) && (missionfailed() == 0) ) {
                    newgame(boardfilename);
                    keystatus[2]=1;
                    dofadein=32;
               }
               else {
                    // some sort of die anim here for multiplayer ?
               }
		}
#if 0                                                       // Les 10/01/95
		else {
			sprite[playersprite[snum]].xrepeat = max(((128+health[snum])>>1),0);
			sprite[playersprite[snum]].yrepeat = max(((128+health[snum])>>1),0);

			hvel[snum] += (TICSPERFRAME<<2);
			horiz[snum] = max(horiz[snum]-4,0);
			posz[snum] += hvel[snum];
			if( posz[snum] > globloz-(4<<8) ) {
				posz[snum] = globloz-(4<<8);
				horiz[snum] = min(horiz[snum]+5,200);
				hvel[snum] = 0;
			}
		}
#endif                                                      // Les 10/01/95
	}
     if( (syncbits[snum]&64) != 0 ) {
          autocenter[snum]=1;
     }
     if( autocenter[snum] ) {
          if( horiz[snum] > 100 ) {
               horiz[snum]-=4;
               if( horiz[snum] < 100 ) {
                    horiz[snum]=100;
               }
          }
          else if( horiz[snum] < 100 ) {
               horiz[snum]+=4;
               if( horiz[snum] > 100 ) {
                    horiz[snum]=100;
               }
          }
          if( horiz[snum] == 100 ) {
               autocenter[snum]=0;
          }
     }

	if (((syncbits[snum]&8) > 0) && (horiz[snum] > 100-(200>>1))) horiz[snum] -= 4;     //-
	if (((syncbits[snum]&4) > 0) && (horiz[snum] < 100+(200>>1))) horiz[snum] += 4;   //+

	// 32 pixels above floor is where player should be
     goalz = globloz-(KENSPLAYERHEIGHT<<8);  

     // kens slime sector
	if( sector[cursectnum[snum]].lotag == 4 ) {
          // if not on a sprite
		if( (globlohit&0xc000) != 49152 ) {
			goalz = globloz-(8<<8);
			if( posz[snum] >= goalz-(2<<8) ) {
				clipmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],-TICSPERFRAME<<14,-TICSPERFRAME<<14,128L,4<<8,4<<8,0);
				frameinterpolate = 0;
				if( slimesoundcnt[snum] >= 0 ) {
					slimesoundcnt[snum] -= TICSPERFRAME;
					while( slimesoundcnt[snum] < 0 ) {
						slimesoundcnt[snum] += 120;
					}
				}
			}
		}
     }

     // case where ceiling & floor are too close
	if( goalz < globhiz+(16<<8) ) {   
		goalz = ((globloz+globhiz)>>1);
     }

     // climb ladder or regular z movement
     if( (mission == 7) || sector[cursectnum[snum]].lotag == SECT_LOTAG_CLIMB ) {
		if( (syncbits[snum]&1) > 0 ) {  
               if( posz[snum] > (sector[cursectnum[snum]].ceilingz+2048) ) {
                    posz[snum]-=64;
                    if( (syncbits[snum]&256) > 0 ) {
                         posz[snum]-=128;
                    }
                    if( mission == 7 ) {
                         posz[snum]-=256;
                    }
               }
          }  
          else	if( (syncbits[snum]&2) > 0 ) {
               if( posz[snum] < (sector[cursectnum[snum]].floorz-2048) ) {
                    posz[snum]+=64;
                    if( (syncbits[snum]&256) > 0 ) {
                         posz[snum]+=128;
                    }
                    if( mission == 7 ) {
                         posz[snum]+=256;
                    }
               }
          }
     }
     else {
	     if( health[snum] >= 0 ) {
               // jump key
	     	if( (syncbits[snum]&1) > 0 ) {              
	     		if( posz[snum] >= globloz-(KENSPLAYERHEIGHT<<8) ) {
                    goalz -= (16<<8);
//                    if( (syncbits[snum]&256) > 0 ) {
	     				goalz -= (24<<8);
//                         }
	     		}
	     	}
               // crouch key
	     	if( (syncbits[snum]&2) > 0 ) {
                goalz += (12<<8);
//                if( (syncbits[snum]&256) > 0 ) {
	     			goalz += (12<<8);
//                    }
	     	}
	     }
          // player is on a groudraw area
	     if( (sector[cursectnum[snum]].floorstat&2) > 0 ) {
	     	if( waloff[sector[cursectnum[snum]].floorheinum] == 0 ) {
                    loadtile(sector[cursectnum[snum]].floorheinum);
               }
	     	ptr = (char *)(waloff[sector[cursectnum[snum]].floorheinum]+(((posx[snum]>>4)&63)<<6)+((posy[snum]>>4)&63));
	     	goalz -= ((*ptr)<<8);
	     }
          // gravity, plus check for if on an elevator 
	     if( posz[snum] < goalz ) {
    	     	hvel[snum] += (TICSPERFRAME<<5)+1;
          }
	     else {
               if( (globlohit&0xC000) == 0xC000 ) {     // on a sprite
                    if ((globlohit-49152) < 0 || (globlohit-49152) >= MAXSPRITES) {
                         crash("game961: Invalid sprite index (%d)",globlohit-49152);
                    }
                    if( sprite[globlohit-49152].lotag >= 1500 ) {
                         onelev[snum]=1;
                    }
               }
               else if( sector[cursectnum[snum]].lotag == 1004 ||
                        sector[cursectnum[snum]].lotag == 1005 ) {
                    onelev[snum]=1;
               }
               else {
                    onelev[snum]=0;
               }
               if (onelev[snum] != 0 && (syncbits[snum]&2) == 0) {
                    hvel[snum]=0;
                    posz[snum]=globloz-(KENSPLAYERHEIGHT<<8);
               }
               else {
                    hvel[snum] = (((goalz-posz[snum])*TICSPERFRAME)>>5);
               }
          }
          tekchangefallz(snum,globloz,globhiz);
     }

     // overhead maps zoom in/out
	if( dimensionmode[snum] != 3 ) {
		if (((syncbits[snum]&32) > 0) && (zoom[snum] > 48)) zoom[snum] -= (zoom[snum]>>4);
		if (((syncbits[snum]&16) > 0) && (zoom[snum] < 4096)) zoom[snum] += (zoom[snum]>>4);
	}

	// update sprite representation of player
	// should be after movement, but before shooting code
	setsprite(playersprite[snum],posx[snum],posy[snum],posz[snum]+(KENSPLAYERHEIGHT<<8));
	sprite[playersprite[snum]].ang = ang[snum];

     // in wrong sector or is ceiling/floor smooshing player
	if( (cursectnum[snum] < 0) || (cursectnum[snum] >= numsectors) ) {
		changehealth(snum,-200);
          changescore(snum,-5);
	}
	else if( globhiz+(8<<8) > globloz ) {
		changehealth(snum,-200);
          changescore(snum,-5);
	}

     // kens waterfountain
	if( (waterfountainwall[snum] >= 0) && (health[snum] >= 0) ) {
        if (neartagwall < 0 || neartagwall >= numwalls) {
            crash("game1009: Invalid wall (%d)",neartagwall);
        }
		if( (wall[neartagwall].lotag != 7) || ((syncbits[snum]&1024) == 0) ) {
			i = waterfountainwall[snum];
            if (i < 0 || i >= numwalls) {
                crash("game1014: Invalid wall index (%d)",i);
            }
			if( wall[i].overpicnum == USEWATERFOUNTAIN ) {
				wall[i].overpicnum = WATERFOUNTAIN;
               }
			else if( wall[i].picnum == USEWATERFOUNTAIN ) {
				wall[i].picnum = WATERFOUNTAIN;
               }
			waterfountainwall[snum] = -1;
		}
     }

     // enter throw
	if( (option[4] == 0 ) && (pickup.picnum != 0) && (keystatus[28] != 0) ) {
          toss(snum);
          keystatus[28]=0;
     }

     // space bar (use) code
	if( ((syncbits[snum]&1024) > 0) && (sector[cursectnum[snum]].lotag == 4444) ) {
          depositsymbol(snum);
     }
     else	if( (syncbits[snum]&1024) > 0 ) {
		// continuous triggers
		neartag(posx[snum],posy[snum],(posz[snum]+(8<<8)),cursectnum[snum],ang[snum],&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1024L,3);
		if( neartagsector == -1 ) {
			i = cursectnum[snum];
			if( (sector[i].lotag|sector[i].hitag) != 0 ) {
				neartagsector = i;
               }
		}
          // kens water fountain
        if( neartagwall >= 0 ) {
            if (neartagwall >= numwalls) {
                 crash("game1053: Invalid wall index (%d)",neartagwall);
            }
            if ( wall[neartagwall].lotag == 7 ) {
                 if( wall[neartagwall].overpicnum == WATERFOUNTAIN ) {
                     wall[neartagwall].overpicnum = USEWATERFOUNTAIN;
                     waterfountainwall[snum] = neartagwall;
                 }
                 else if( wall[neartagwall].picnum == WATERFOUNTAIN ) {
                     wall[neartagwall].picnum = USEWATERFOUNTAIN;
                     waterfountainwall[snum] = neartagwall;
                 }
                 if( waterfountainwall[snum] >= 0 ) {
                     waterfountaincnt[snum] -= TICSPERFRAME;
                     while( waterfountaincnt[snum] < 0 ) {
                         waterfountaincnt[snum] += 120;
                         changehealth(snum,2);
                     }
                 }
			}
		}
		// 1-time triggers
		if( (oflags[snum]&1024) == 0 ) {
			if( neartagsector >= 0 ) {
                if (neartagsector >= numsectors) {
                    crash("game1070: Invalid sector index (%d)",neartagsector);
                }
                if( sector[neartagsector].hitag == 0 ) {
					operatesector(neartagsector);
                    }
               }
			if( neartagwall >= 0 ) {
                if (neartagwall >= numwalls) {
                    crash("game1078: Invalid wall index (%d)",neartagwall);
                }
				if( wall[neartagwall].lotag == 2 ) {
					for( i=0; i<numsectors; i++ ) {
						if( sector[i].hitag == wall[neartagwall].hitag ) {
							if( sector[i].lotag != 1 ) {
								operatesector(i);
                                   }
                              }
                         }
					i = headspritestat[0];
					while( i != -1 ) {
						nexti = nextspritestat[i];
						if( sprite[i].hitag == wall[neartagwall].hitag ) {
							operatesprite(i);
                              }
						i = nexti;
					}
					j = wall[neartagwall].overpicnum;
					if( j == SWITCH1ON ) {
						wall[neartagwall].overpicnum = GIFTBOX;
						wall[neartagwall].lotag = 0;
						wall[neartagwall].hitag = 0;
					}
					if( j == GIFTBOX ) {
						wall[neartagwall].overpicnum = SWITCH1ON;
						wall[neartagwall].lotag = 0;
						wall[neartagwall].hitag = 0;
					}
					if (j == SWITCH2ON)  wall[neartagwall].overpicnum = SWITCH2OFF;
					if (j == SWITCH2OFF) wall[neartagwall].overpicnum = SWITCH2ON;
					if (j == SWITCH3ON)  wall[neartagwall].overpicnum = SWITCH3OFF;
					if (j == SWITCH3OFF) wall[neartagwall].overpicnum = SWITCH3ON;
					i = wall[neartagwall].point2;
					dax = ((wall[neartagwall].x+wall[i].x)>>1);
					day = ((wall[neartagwall].y+wall[i].y)>>1);
				}
               }
			if( neartagsprite >= 0 ) {
                if (neartagsprite >= MAXSPRITES) {
                    crash("game1118: Invalid sprite index (%d)",neartagsprite);
                }
				if( sprite[neartagsprite].lotag == 4 ) { 
                    tekswitchtrigger(snum);
				}
                else {
                     operatesprite(neartagsprite);
                }
			}
		}
	}

     // fire weapon 
	if( (syncbits[snum]&2048) > 0 ) {      
          tekfiregun((syncbits[snum]>>13)&15,snum); 
	}

     // map mode 
    if( (syncbits[snum]&4096) > (oflags[snum]&4096) ) {
        if (dimensionmode[snum] == 3) {
             dimensionmode[snum]=1;
        }
        else {
             dimensionmode[snum]=3;
        }
#if 0               // eliminate map mode 2
		dimensionmode[snum]++;
		if( dimensionmode[snum] > 3 ) {
               dimensionmode[snum] = 1;
          }
#endif
		if( snum == screenpeek ) {
			if (dimensionmode[snum] == 2) setview(0L,0L,xdim-1,(ydim-1)>>detailmode);
			if (dimensionmode[snum] == 3) setup3dscreen();
		}
	}

	oflags[snum] = syncbits[snum];
}

drawscreen(short snum, long dasmoothratio)
{
	long      i, j, k, charsperline, templong, dx, dy, top, bot;
	long      x1, y1, x2, y2, ox1, oy1, ox2, oy2, dist, maxdist;
	long      cposx, cposy, cposz, choriz, czoom, tposx, tposy, thoriz;
	short     cang, tang;
	char      ch, *ptr, *ptr2, *ptr3, *ptr4;

	smoothratio = max(min(dasmoothratio,65536),0);

	cposx = oposx[snum]+mulscale(posx[snum]-oposx[snum],smoothratio,16);
	cposy = oposy[snum]+mulscale(posy[snum]-oposy[snum],smoothratio,16);
	cposz = oposz[snum]+mulscale(posz[snum]-oposz[snum],smoothratio,16);
	if( frameinterpolate == 0 ) {
	     cposx = posx[snum]; cposy = posy[snum]; cposz = posz[snum]; 
     }
     cposz+=headbob;
	choriz = ohoriz[snum]+mulscale(horiz[snum]-ohoriz[snum],smoothratio,16);
	czoom = ozoom[snum]+mulscale(zoom[snum]-ozoom[snum],smoothratio,16);
	cang = oang[snum]+mulscale(((ang[snum]+1024-oang[snum])&2047)-1024,smoothratio,16);

	if( dimensionmode[snum] != 2 ) {
		if( (numplayers > 1) && (option[4] == 0) ) {
			// do not draw other views constantly if they're staying still
			// it's a shame this trick will only work in screen-buffer mode
			// at least screen-buffer mode covers all the HI hi-res modes
			if( vidoption == 1 ) {
				for( i=connecthead; i>=0; i=connectpoint2[i] ) {
                         frame2draw[i] = 0;
                    }
				frame2draw[snum] = 1;
				// 2-1,3-1,4-2
				// 5-2,6-2,7-2,8-3,9-3,10-3,11-3,12-4,13-4,14-4,15-4,16-5
				x1 = posx[snum]; y1 = posy[snum];
				for( j=(numplayers>>2)+1; j>0; j-- ) {
					maxdist = 0x80000000;
					for( i=connecthead; i>=0; i=connectpoint2[i] ) {
						if( frame2draw[i] == 0 ) {
							x2 = posx[i]-x1; y2 = posy[i]-y1;
							dist = mulscale(x2,x2,12) + mulscale(y2,y2,12);
							if( dist < 64 ) {
                                        dist = 16384;
                                   }
							else if( dist > 16384 ) {
                                        dist = 64;
                                   }
							else {
                                        dist = 1048576 / dist;
                                   }
							dist *= frameskipcnt[i];
							// increase frame rate if screen is moving
							if( (posx[i] != oposx[i]) || (posy[i] != oposy[i]) ||
							    (posz[i] != oposz[i]) || (ang[i] != oang[i])   ||
							    (horiz[i] != ohoriz[i]) ) {
                                       dist += dist;
                                   }
							if( dist > maxdist ) {
                                        maxdist = dist, k = i;
                                   }
						}
                         }
					for( i=connecthead; i>=0; i=connectpoint2[i] ) {
						frameskipcnt[i] += (frameskipcnt[i]>>3)+1;
                         }
					frameskipcnt[k] = 0;
					frame2draw[k] = 1;
				}
			}
			else {
				for( i=connecthead; i>=0; i=connectpoint2[i] ) {
                         frame2draw[i] = 1;
                    }
			}
               redrawbackfx();    
			for( i=connecthead,j=0; i>=0; i=connectpoint2[i],j++ ) {
				if( frame2draw[i] != 0 ) {
					if( numplayers <= 4 ) {
						switch( j ) {
							case 0: setview(0,0,(xdim>>1)-1,(ydim>>1)-1); break;
							case 1: setview((xdim>>1),0,xdim-1,(ydim>>1)-1); break;
							case 2: setview(0,(ydim>>1),(xdim>>1)-1,ydim-1); break;
							case 3: setview((xdim>>1),(ydim>>1),xdim-1,ydim-1); break;
						}
					}
					else {
						switch( j ) {
							case 0: setview(0,0,(xdim>>2)-1,(ydim>>2)-1); break;
							case 1: setview(xdim>>2,0,(xdim>>1)-1,(ydim>>2)-1); break;
							case 2: setview(xdim>>1,0,xdim-(xdim>>2)-1,(ydim>>2)-1); break;
							case 3: setview(xdim-(xdim>>2),0,xdim-1,(ydim>>2)-1); break;
							case 4: setview(0,ydim>>2,(xdim>>2)-1,(ydim>>1)-1); break;
							case 5: setview(xdim>>2,ydim>>2,(xdim>>1)-1,(ydim>>1)-1); break;
							case 6: setview(xdim>>1,ydim>>2,xdim-(xdim>>2)-1,(ydim>>1)-1); break;
							case 7: setview(xdim-(xdim>>2),ydim>>2,xdim-1,(ydim>>1)-1); break;
							case 8: setview(0,ydim>>1,(xdim>>2)-1,ydim-(ydim>>2)-1); break;
							case 9: setview(xdim>>2,ydim>>1,(xdim>>1)-1,ydim-(ydim>>2)-1); break;
							case 10: setview(xdim>>1,ydim>>1,xdim-(xdim>>2)-1,ydim-(ydim>>2)-1); break;
							case 11: setview(xdim-(xdim>>2),ydim>>1,xdim-1,ydim-(ydim>>2)-1); break;
							case 12: setview(0,ydim-(ydim>>2),(xdim>>2)-1,ydim-1); break;
							case 13: setview(xdim>>2,ydim-(ydim>>2),(xdim>>1)-1,ydim-1); break;
							case 14: setview(xdim>>1,ydim-(ydim>>2),xdim-(xdim>>2)-1,ydim-1); break;
							case 15: setview(xdim-(xdim>>2),ydim-(ydim>>2),xdim-1,ydim-1); break;
						}
					}
					if( i == snum ) {
						drawrooms(cposx,cposy,cposz,cang,choriz,cursectnum[i]);
                         }
					else {
						drawrooms(posx[i],posy[i],posz[i],ang[i],horiz[i],cursectnum[i]);
                         }
					analyzesprites(posx[i],posy[i]);
					drawmasks();
                         tekdrawgun((syncbits[i]>>13)&15,i);
				}
               }
		}
		else {
               redrawbackfx(); 
			drawrooms(cposx,cposy,cposz,cang,choriz,cursectnum[snum]);
			analyzesprites(posx[snum],posy[snum]);
			drawmasks();
               tekdrawgun((syncbits[screenpeek]>>13)&15,screenpeek);
		}
	}

	// move back pivot point for map
	if( dimensionmode[snum] != 3 ) {
		cposx += (sintable[(cang+512)&2047]<<6) / czoom;
		cposy += (sintable[cang&2047]<<6) / czoom;
		if( dimensionmode[snum] == 2 ) {
			clearview(0L);  //Clear screen to specified color
			drawmapview(cposx,cposy,czoom,cang);
		}
		drawoverheadmap(cposx,cposy,czoom,cang);
	}

	// tell who's master or slave in multiplayer
    #ifdef MASTERSLAVEGAMEC
	if( numplayers >= 2 ) {
		if( lockclock < masterslavetexttime+120 ) {
			if (myconnectindex == connecthead)
				printext256(152L,0L,31,-1,"Master",0);
			else
				printext256(152L,0L,31,-1,"Slave",0);
		}
	}
    #endif

	if( typemode != 0 ) {
		charsperline = 40;
		for( i=0; i<=typemessageleng; i+=charsperline ) {
			for( j=0; j<charsperline; j++ ) {
				tempbuf[j] = typemessage[i+j];
               }
			if( typemessageleng < i+charsperline ) {
				tempbuf[(typemessageleng-i)] = '_';
				tempbuf[(typemessageleng-i)+1] = 0;
			}
			else {
				tempbuf[charsperline] = 0;
               }
		}
	}
	else {
		if( dimensionmode[myconnectindex] == 3 ) {
			templong = screensize;
			if( ((locbits&32) > (screensizeflag&32)) && (screensize > 64) ) {
				ox1 = (xdim>>1)-(screensize>>1);
				ox2 = ox1+screensize-1;
				oy1 = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
				oy2 = oy1+((screensize*(ydim-32))/xdim)-1;
                    tekview(&ox1,&oy1, &ox2,&oy2);
				screensize -= (screensize>>3);
				if( templong > xdim ) {
					screensize = xdim;
					permanentwritesprite((xdim-320)>>1,ydim-32,STATUSBAR,0,0,0,xdim-1,ydim-1,0);
					i = ((xdim-320)>>1);
					while( i >= 8 ) {
                              i -= 8, permanentwritesprite(i,ydim-32,STATUSBARFILL8,0,0,0,xdim-1,ydim-1,0);
                         }
					if( i >= 4 ) {
                              i -= 4, permanentwritesprite(i,ydim-32,STATUSBARFILL4,0,0,0,xdim-1,ydim-1,0);
                         }
					i = ((xdim-320)>>1)+320;
					while( i <= xdim-8 ) {
                              permanentwritesprite(i,ydim-32,STATUSBARFILL8,0,0,0,xdim-1,ydim-1,0), i += 8;
                         }
					if( i <= xdim-4 ) {
                              permanentwritesprite(i,ydim-32,STATUSBARFILL4,0,0,0,xdim-1,ydim-1,0), i += 4;
                         }
				}
				x1 = (xdim>>1)-(screensize>>1);
				x2 = x1+screensize-1;
				y1 = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
				y2 = y1+((screensize*(ydim-32))/xdim)-1;
				tekview(&x1,&y1,&x2,&y2);
				setview(x1,y1>>detailmode,x2,y2>>detailmode);
				permanentwritespritetile(0L,0L,BACKGROUND,0,ox1,oy1,x1-1,oy2,0);
				permanentwritespritetile(0L,0L,BACKGROUND,0,x2+1,oy1,ox2,oy2,0);
				permanentwritespritetile(0L,0L,BACKGROUND,0,x1,oy1,x2,y1-1,0);
				permanentwritespritetile(0L,0L,BACKGROUND,0,x1,y2+1,x2,oy2,0);
			}
			if( ((locbits&16) > (screensizeflag&16)) && (screensize <= xdim) ) {
				screensize += (screensize>>3);
				if( (screensize > xdim) && (templong == xdim) ) {
					screensize = xdim+1;
					x1 = 0; y1 = 0;
					x2 = xdim-1; y2 = ydim-1;
				}
				else {
					if (screensize > xdim) screensize = xdim;
					x1 = (xdim>>1)-(screensize>>1);
					x2 = x1+screensize-1;
					y1 = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
					y2 = y1+((screensize*(ydim-32))/xdim)-1;
				}
				tekview(&x1,&y1,&x2,&y2);
				setview(x1,y1>>detailmode,x2,y2>>detailmode);
			}
			screensizeflag = locbits;
		}
	}

	if( getmessageleng > 0 ) {
		charsperline = 40;
		for( i=0; i<=getmessageleng; i+=charsperline ) {
			for( j=0; j<charsperline; j++ ) {
				tempbuf[j] = getmessage[i+j];
               }
			if( getmessageleng < i+charsperline ) {
				tempbuf[(getmessageleng-i)] = 0;
               }
			else {
				tempbuf[charsperline] = 0;
               }
			printext256(0L,((i/charsperline)<<3)+(200-32-8)-(((getmessageleng-1)/charsperline)<<3),151,-1,tempbuf,0);
		}
		if( totalclock > getmessagetimeoff ) {
			getmessageleng = 0;
          }
	}

     // you are looking thru an opponent plaeyer's eyes
	if( (numplayers >= 2) && (screenpeek != myconnectindex) ) {
		strcpy(tempbuf,"Other");
	}

    #ifdef OUTOFSYNCMESSAGE
	if( syncstat != 0 ) {
          printext256(68L,84L,31,0,"OUT OF SYNC!",0);
     }
	if( syncstate != 0 ) { 
          printext256(68L,92L,31,0,"Missed Network packet!",0);
     }
    #endif

     tekscreenfx(snum);

    #ifdef  NETWORKDIAGNOSTICS 
     if( (option[4] > 0) ) {
          for( i=connecthead ; i >= 0 ; i=connectpoint2[i] ) {
    	          sprintf(tektempbuf,"%2d %5d %5d %5d %5d %3d %4d", i,posx[i],posy[i],posz[i],ang[i],horiz[i],health[i]);
	          printext(2,i*8+2,tektempbuf,ALPHABET,255);
          }
		if( myconnectindex == connecthead ) {
               sprintf(tektempbuf,"%2d %s",myconnectindex,"M");
          }
          else {
               sprintf(tektempbuf,"%2d %s",myconnectindex,"S");
          }
          printext(windowx2-48,windowy2-64,tektempbuf,ALPHABET2,255);
     }
    #endif

	nextpage();
     if( dofadein != 0 ) {   
          fadein(0,255,dofadein);    
     }           

    #ifdef OOGIE
     // F5 key
	if( keystatus[0x3f] > 0 ) {
		keystatus[0x3f] = 0;
		detailmode ^= 1;
		if( detailmode == 0 ) {
			setview(windowx1,windowy1<<1,windowx2,(windowy2<<1)+1);
			outp(0x3d4,0x9); outp(0x3d5,(inp(0x3d5)&~31)|1);
		}
		else {
			setview(windowx1,windowy1>>detailmode,windowx2,windowy2>>detailmode);
			setaspect(yxaspect>>1);
			outp(0x3d4,0x9); outp(0x3d5,(inp(0x3d5)&~31)|3);
		}
	}
    #endif

     // F12 key
	if( keystatus[0x58] > 0 ) {
		keystatus[0x58] = 0;
		screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]);
	}

    #ifdef STEREOMODE_ADJUSTMENT_ACTIVE
	if( stereofps != 0 ) { 
		if( (keystatus[0x2a]|keystatus[0x36]) > 0 ) {
			if (keystatus[0x1a] > 0) stereopixelwidth--;   //Shift [
			if (keystatus[0x1b] > 0) stereopixelwidth++;   //Shift ]
		}
		else {
			if (keystatus[0x1a] > 0) stereowidth -= 512;   //[
			if (keystatus[0x1b] > 0) stereowidth += 512;   //]
		}
	}
    #endif

    #ifdef FAKEMULTIPLAYER_ACTIVE
	if( option[4] == 0 ) {
		if( keystatus[0xd2] > 0 ) {
			keystatus[0xd2] = 0;
			if( numplayers < MAXPLAYERS ) {
				connectpoint2[numplayers-1] = numplayers;
				connectpoint2[numplayers] = -1;
				initplayersprite(numplayers);
				clearallviews(0L); 
				numplayers++;
			}
		}
		if( keystatus[0xd3] > 0 ) {
			keystatus[0xd3] = 0;
			if( numplayers > 1 ) {
				numplayers--;
				connectpoint2[numplayers-1] = -1;
				deletesprite(playersprite[numplayers]);
				playersprite[numplayers] = -1;
				if( myconnectindex >= numplayers ) {
                         myconnectindex = 0;
                    }
				if( screenpeek >= numplayers ) {
                         screenpeek = 0;
                    }
				if( numplayers < 2 ) {
					setup3dscreen();
                    }
				else {
					clearallviews(0L);
                    }
			}
		}
          // scroll lock
		if( keystatus[0x46] > 0 ) {
			keystatus[0x46] = 0;
			myconnectindex = connectpoint2[myconnectindex];
			if( myconnectindex < 0 ) {
                    myconnectindex = connecthead;
               }
			screenpeek = myconnectindex;
		}
	}
    #endif
}

movethings()
{
	long      i;

	gotlastpacketclock = totalclock;
	for( i=connecthead; i>=0; i=connectpoint2[i] ) {
		baksyncvel[movefifoend][i] = fsyncvel[i];
		baksyncsvel[movefifoend][i] = fsyncsvel[i];
		baksyncangvel[movefifoend][i] = fsyncangvel[i];
		baksyncbits[movefifoend][i] = fsyncbits[i];
	}
	movefifoend = ((movefifoend+1)&(MOVEFIFOSIZ-1));

	// do this for Master/Slave switching
	for( i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i] ) {
		if( syncbits[i]&512 ) {
               ready2send = 0;
          }
     }

     tektime();
}

domovethings()
{
	short          i, j, startwall, endwall;
	spritetype     *spr;
	walltype       *wal;
	point3d        *ospr;

	for( i=connecthead; i>=0; i=connectpoint2[i] ) {
        if (dbgflag) {
            debugout(i);
        }
		syncvel[i] = baksyncvel[movefifoplc][i];
		syncsvel[i] = baksyncsvel[movefifoplc][i];
		syncangvel[i] = baksyncangvel[movefifoplc][i];
		syncbits[i] = baksyncbits[movefifoplc][i];
	}
	movefifoplc = ((movefifoplc+1)&(MOVEFIFOSIZ-1));
#if 0
	syncval[syncvalend] = getsyncstat();
	syncvalend = ((syncvalend+1)&(MOVEFIFOSIZ-1));
#endif
	for( i=connecthead; i>=0; i=connectpoint2[i] ) {
		oposx[i] = posx[i];
		oposy[i] = posy[i];
		oposz[i] = posz[i];
		ohoriz[i] = horiz[i];
		ozoom[i] = zoom[i];
          oang[i] = ang[i];
	}

	for( i=1; i<=8; i++ ) {
		if( i != 2 ) {
			for( j=headspritestat[i]; j>=0; j=nextspritestat[j] ) {
				copybuf(&sprite[j].x,&osprite[j].x,3);
               }
          }
     }

	for( i=connecthead; i>=0; i=connectpoint2[i] ) {
		ocursectnum[i] = cursectnum[i];
     }

	if( (numplayers <= 2) && (recstat == 1) ) {
		j = 0;
		for( i=connecthead; i>=0; i=connectpoint2[i] ) {
			recsyncvel[reccnt][j] = syncvel[i];
			recsyncsvel[reccnt][j] = syncsvel[i];
			recsyncangvel[reccnt][j] = syncangvel[i];
			recsyncbits[reccnt][j] = syncbits[i];
			j++;
		}
		reccnt++; 
          if( reccnt > 16383 ) {
               reccnt = 16383;
          }
	}

	lockclock += TICSPERFRAME;

	for( i=connecthead; i>=0; i=connectpoint2[i] ) {
		processinput(i);                       
		checktouchsprite(i,cursectnum[i]);     
		startwall = sector[cursectnum[i]].wallptr;
		endwall = startwall + sector[cursectnum[i]].wallnum;
		for( j=startwall,wal=&wall[j]; j<endwall; j++,wal++ ) {
			if( wal->nextsector >= 0 ) {
                    checktouchsprite(i,wal->nextsector);
               }
          }
	}

	doanimations();

	tagcode();         
	statuslistcode();  

	checkmasterslaveswitch();
}

void
adjustbiasthreshhold(short mousy)
{
     biasthreshhold-=mousy;
     if( biasthreshhold < 8 )
          biasthreshhold=8;
     if( biasthreshhold > 512 )
          biasthreshhold=512;
}

//** Les START - 09/27/95
#define   NUMSPACEBALLBUTTONS      6

short moreoptionbits[]={
     -1,                           //  0 move forward
     -1,                           //  1 move backward
     -1,                           //  2 turn right
     -1,                           //  3 turn left
      8,                           //  4 run
     -1,                           //  5 strafe
     11,                           //  6 shoot
     10,                           //  7 use
      0,                           //  8 jump
      1,                           //  9 crouch
      2,                           // 10 look up
      3,                           // 11 look down
     -1,                           // 12 slide left
     -1,                           // 13 slide right
     12,                           // 14 map
     -1,                           // 15 switch player
      4,                           // 16 zoom in
      5,                           // 17 zoom out
     -1,                           // 18 message
      6,                           // 19 autocenter
     -1,                           // 20 rearview
     -1,                           // 21 current item
     -1,                           // 22 health
     -1,                           // 23 crosshairs
     -1,                           // 24 elapsed time
     -1,                           // 25 score
     -1,                           // 26 inventory
      7,                           // 27 conceal weapon
     -1                            // 28 mouse look mode
};
//** Les END   - 09/27/95

getinput()
{
	char      ch, keystate, *ptr;
	long      i, j, k;
	short     mousx, mousy, bstatus;
     short     jx,jy;    
     long      angdelta,cybangle,pitdelta;
     short     moving,strafing,turning;

     if( activemenu != 0 ) {              
          domenuinput();
     }   

     // normal game keys active
	if( typemode == 0 ) {
          // shift+shift+R 
		if( (keystatus[0x2a]&keystatus[0x36]&keystatus[0x13]) > 0 ) {
			keystatus[0x13] = 0;
			playback();
		}
         #ifdef SWITCHINGACTIVE
		if( keystatus[keys[15]] > 0 ) {
			keystatus[keys[15]] = 0;
			screenpeek = connectpoint2[screenpeek];
			if( screenpeek < 0 ) {
                    screenpeek = connecthead;
               }
		}
         #endif
		for( i=7; i>=0; i-- ) {
               if( (keystatus[i+2] > 0) && tekhasweapon(i,screenpeek) ) { 
			     keystatus[i+2] = 0; 
                    locselectedgun = i; 
                    break;
               }
          }
	}

//** Les  - moved from below to apply button movements to vel, svel and angvel
//**        if needed

     mousx=mousy=bstatus=0;
     if( moreoptions[0] != 0 ) {
          getmousevalues(&mousx,&mousy,&bstatus);
          if( biasthreshholdon && (bstatus&6) ) {
               adjustbiasthreshhold(mousy);
               bstatus=0;
          }
          // if horizon key down
          if( keystatus[58] == 0 ) { 
               if( mousy > (biasthreshhold) ) {
                    mousebias=-1;
               }
               else if( mousy < -(biasthreshhold) ) {
                    mousebias=+1;
               }
          }
     }
//** Les START - 09/26/95
     if (moreoptions[3] != 0 && jstickenabled == 0 && jcalibration == 0) {
          jcalibration=1;
     }
     locbits=(locselectedgun<<13);                          // Les 09/28/95 moved from below
     if (jstickenabled) {
          jstick();
//          showmessage("X: %05d Y: %05d B:%04X",joyx,joyy,joyb);
          if (keystatus[0x57] != 0) {   // recalibrate joystick (F11)
               jstickenabled=0;
               jcalibration=1;
          }
          if (joyx < jlowx) {
               angvel=max(min(angvel-(jctrx-joyx),127),-128);
          }
          else if (joyx > jhighx) {
               angvel=min(max(angvel+(joyx-jctrx),-128),127);
          }
          if (joyy < jlowy) {
               vel=min(max(vel+(jctry-joyy),-128),127);
          }
          else if (joyy > jhighy) {
               vel=max(min(vel-(joyy-jctry),127),-128);
          }
          for (i=0 ; i < 4 ; i++) {
               if ((joyb&(0x10<<i)) == 0) {
                    if (moreoptions[i+4] == 0) {
                         moving=1;
                    }
                    else if (moreoptions[i+4] == 1) {
                         moving=-1;
                    }
                    else if (moreoptions[i+4] == 2) {
                         turning=1;
                    }
                    else if (moreoptions[i+4] == 3) {
                         turning=-1;
                    }
                    else if (moreoptions[i+4] == 5) {
                         strafing=2;
                    }
                    else if (moreoptions[i+4] == 12) {
                         strafing=-1;
                    }
                    else if (moreoptions[i+4] == 13) {
                         strafing=1;
                    }
                    else if (moreoptionbits[moreoptions[i+4]] >= 0) {
                         locbits|=(1<<moreoptionbits[moreoptions[i+4]]);
                    }
               }
          }
          oldjoyb=joyb;
     }
     else if (jcalibration) {
          jstick();
          switch (jcalibration) {
          case 1:
               showmessage("center stick press button");
               if (((joyb&0xF0) != 0xF0) && ((oldjoyb&0xF0) == 0xF0)) {
                    jctrx=joyx;
                    jctry=joyy;
                    jcalibration++;
               }
               break;
          case 2:
               showmessage("top left press button");
               if (((joyb&0xF0) != 0xF0) && ((oldjoyb&0xF0) == 0xF0)) {
                    jlowx=jctrx-((jctrx-joyx)/4);
                    jlowy=jctry-((jctry-joyy)/4);
                    jcalibration++;
               }
               break;
          case 3:
               showmessage("lower right press button");
               if (((joyb&0xF0) != 0xF0) && ((oldjoyb&0xF0) == 0xF0)) {
                    jhighx=jctrx+((joyx-jctrx)/4);
                    jhighy=jctry+((joyy-jctry)/4);
                    jcalibration=0;
                    jstickenabled=1;
               }
               break;
          }
          oldjoyb=joyb;
     }
     if (spaceballinitflag) {
          if (SPW_IsInputEvent(0,&sbpacket)) {
               angvel=min(max(angvel+(sbpacket.sData[5]>>3),-128),127);
               angvel=max(min(angvel-(sbpacket.sData[4]>>3),127),-128);
               svel=max(min(svel-(sbpacket.sData[0]>>3),127),-128);
               vel=max(min(vel-(sbpacket.sData[2]>>3),127),-128);
          }
     }
//** Les END   - 09/26/95

//** Les START - 09/28/95
     moving=strafing=turning=0;
     if (spaceballinitflag) {
          for (i=0 ; i < NUMSPACEBALLBUTTONS ; i++) {
               if (sbpacket.buttonState.current&(1<<i)) {
                    if (moreoptions[i+14] == 0) {
                         moving=1;
                    }
                    else if (moreoptions[i+14] == 1) {
                         moving=-1;
                    }
                    else if (moreoptions[i+14] == 2) {
                         turning=1;
                    }
                    else if (moreoptions[i+14] == 3) {
                         turning=-1;
                    }
                    else if (moreoptions[i+14] == 5) {
                         strafing=2;
                    }
                    else if (moreoptions[i+14] == 12) {
                         strafing=-1;
                    }
                    else if (moreoptions[i+14] == 13) {
                         strafing=1;
                    }
                    else if (moreoptionbits[moreoptions[i+14]] >= 0) {
                         locbits|=(1<<moreoptionbits[moreoptions[i+14]]);
                    }
               }
          }
     }
     if (moreoptions[0] != 0) {
          for (i=0 ; i < 3 ; i++) {
               if (bstatus&(1<<i)) {
                    switch (i) {
                    case 0:
                         j=1;
                         break;
                    case 1:
                         j=20;
                         break;
                    case 2:
                         j=2;
                         break;
                    }
                    if (moreoptions[j] == 0) {
                         moving=1;
                    }
                    else if (moreoptions[j] == 1) {
                         moving=-1;
                    }
                    else if (moreoptions[j] == 2) {
                         turning=1;
                    }
                    else if (moreoptions[j] == 3) {
                         turning=-1;
                    }
                    else if (moreoptions[j] == 5) {
                         strafing=2;
                    }
                    else if (moreoptions[j] == 12) {
                         strafing=-1;
                    }
                    else if (moreoptions[j] == 13) {
                         strafing=1;
                    }
                    else {
                         locbits|=(1<<moreoptionbits[moreoptions[j]]);
                    }
               }
          }
     }
//** Les END   - 09/28/95

//** Les START - 09/29/95
     if (vfx1enabled) {
          for (i=0 ; i < 3 ; i++) {
               if ((puckbuttons&(1<<i)) != 0) {
                    locbits|=(1<<puckbutton[i]);
               }
          }
          if (puckpitch < -1024) {
               vel=-max(puckpitch>>6,-128);
          }
          else if (puckpitch > 1024) {
               vel=-min(puckpitch>>6,127);
          }
          if (puckroll < -1024) {
               svel=-max(puckroll>>5,-128);
          }
          else if (puckroll > 1024) {
               svel=-min(puckroll>>5,127);
          }
     }
//** Les END   - 09/29/95

	// keyboard survey - use to be keytimerstuff() called from keyhandler
    if( keystatus[keys[5]] == 0 && strafing == 0 ) {    // Les 09/28/95
        if( keystatus[keys[2]] > 0 || turning == 1) angvel = max(angvel-16*TICSPERFRAME,-128); // Les 09/28/95
        if( keystatus[keys[3]] > 0 || turning == -1) angvel = min(angvel+16*TICSPERFRAME,127); // Les 09/28/95
	}
	else {
        if (strafing == 0) {                                                                   // Les 09/28/95
             strafing=2;                                                                       // Les 09/28/95
        }                                                                                      // Les 09/28/95
        if( keystatus[keys[2]] > 0 || turning == 1 ) svel = min(svel+8*TICSPERFRAME,127);      // Les 09/28/95
        if( keystatus[keys[3]] > 0 || turning == -1 ) svel = max(svel-8*TICSPERFRAME,-128);    // Les 09/28/95
	}
    if( keystatus[keys[0]]  > 0 || moving == 1 ) vel  = min(vel+8*TICSPERFRAME,127);           // Les 09/28/95
    if( keystatus[keys[1]]  > 0 || moving == -1 ) vel  = max(vel-8*TICSPERFRAME,-128);         // Les 09/28/95
    if( keystatus[keys[12]] > 0 || strafing == 1 ) svel = min(svel+8*TICSPERFRAME,127);        // Les 09/28/95
    if( keystatus[keys[13]] > 0 || strafing == -1 ) svel = max(svel-8*TICSPERFRAME,-128);      // Les 09/28/95
	if( angvel < 0 ) angvel = min(angvel+12*TICSPERFRAME,0);
	if( angvel > 0 ) angvel = max(angvel-12*TICSPERFRAME,0);
	if( svel < 0 )   svel   = min(svel+2*TICSPERFRAME,0);
	if( svel > 0 )   svel   = max(svel-2*TICSPERFRAME,0);
	if( vel  < 0 )   vel    = min(vel+2*TICSPERFRAME,0);
	if( vel  > 0 )   vel    = max(vel-2*TICSPERFRAME,0);

	if( (option[4] == 0) && (numplayers == 2) ) {
		if( keystatus[0x4f] == 0 ) {
			if( keystatus[0x4b] > 0 ) angvel2 = max(angvel2-16*TICSPERFRAME,-128);
			if( keystatus[0x4d] > 0 ) angvel2 = min(angvel2+16*TICSPERFRAME,127);
		}
		else {
			if( keystatus[0x4b] > 0 ) svel2 = min(svel2+8*TICSPERFRAME,127);
			if( keystatus[0x4d] > 0 ) svel2 = max(svel2-8*TICSPERFRAME,-128);
		}
		if( keystatus[0x48] > 0 ) vel2 = min(vel2+8*TICSPERFRAME,127);
		if( keystatus[0x4c] > 0 ) vel2 = max(vel2-8*TICSPERFRAME,-128);
		if( angvel2 < 0 ) angvel2 = min(angvel2+12*TICSPERFRAME,0);
		if( angvel2 > 0 ) angvel2 = max(angvel2-12*TICSPERFRAME,0);
		if( svel2 < 0 )   svel2   = min(svel2+2*TICSPERFRAME,0);
		if( svel2 > 0 )   svel2   = max(svel2-2*TICSPERFRAME,0);
		if( vel2  < 0 )   vel2    = min(vel2+2*TICSPERFRAME,0);
		if( vel2  > 0 )   vel2    = max(vel2-2*TICSPERFRAME,0);
	}
     if( keystatus[keys[28]] ) {
          i=horiz[myconnectindex]+((( long)mousy)>>3);
          if( i > 200 ) i=200;
          if( i < 0   ) i=0;
          horiz[myconnectindex]=i;               
          keyedhorizon=1;
          mousy=0;
     }
     else {
          if( (keyedhorizon) && (horiz[myconnectindex] != 100) )
               autocenter[myconnectindex]=1;
          keyedhorizon=0;
          mousx*=mousesensitivity;
     }
//     if( (bstatus&6) != 0 ) {
//          vel=min(vel+(1<<(8+mousesensitivity)),127);
//          vel*=mousebias;
//     }
	locvel = min(max(vel,-128+8),127-8);
	locsvel = min(max(svel,-128+8),127-8);
    locangvel = min(max(angvel,-512+16),511-16);            // Les 09/27/95

     if (strafing == 2) {                                   // Les 09/28/95
          locsvel=max(min(svel-mousx,511-16),-512+16);      // Les 09/28/95
     }                                                      // Les 09/28/95
     else {                                                 // Les 09/28/95
          locangvel=min(max(locangvel+mousx,-512),511);     // Les 09/27/95
     }                                                      // Les 09/28/95
//** Les START - 09/28/95
     if (mousy < 0) {
          mousy-=(1<<mousesensitivity);
     }
     else if (mousy > 0) {
          mousy+=(1<<mousesensitivity);
     }
//** Les END   - 09/28/95

    locvel=min(max(locvel-mousy,-128),127);
//    locbits = (locselectedgun<<13); moved up to joystick section

//** Les START - 09/26/95
     if (spaceballinitflag) {
          if (sbpacket.sData[3] > 400) {
               locbits|=(1<<2);                             // Look up
          }
          else if (sbpacket.sData[3] < -400) {
               locbits|=(1<<3);                             // Look down
          }
          if (sbpacket.sData[1] > 400) {
               locbits|=1;                                  // Jump
          }
          else if (sbpacket.sData[1] < -200) {
               locbits|=(1<<1);                             // Crouch
               if (sbpacket.sData[1] < -300) {
                    locbits|=(1<<8);                        // Crouch lower
               }
          }
    }
//** Les END   - 09/26/95

    if( typemode == 0 ) {
         #ifdef MASTERSWITCHING 
		locbits |= (keystatus[0x32]<<9);                  //M (be master)
         #endif
		locbits |= ((keystatus[keys[14]]==1)<<12);        //Map mode
	}
	locbits |= keystatus[keys[8]];                         //Stand high
	locbits |= (keystatus[keys[9]] <<1);                   //Stand low
	locbits |= (keystatus[keys[10]]<<2);                   //Look up
	locbits |= (keystatus[keys[11]]<<3);                   //Look down
	locbits |= (keystatus[keys[16]]<<4);                   //Zoom in
	locbits |= (keystatus[keys[17]]<<5);                   //Zoom out
	locbits |= (keystatus[keys[19]]<<6);                   //AutoCenter     TekWar
	locbits |= (keystatus[keys[27]]<<7);                   //Conceal Weapin TekWar
	locbits |= (keystatus[keys[4]]<<8);                    //Run
	locbits |= ((keystatus[keys[7]]==1)<<10);              //Space
	locbits |= ((keystatus[keys[6]]==1)<<11);              //Shoot Kbd
//    locbits |= (((bstatus&6)>(oldmousebstatus&6))<<10);    //Space
//    locbits |= (((bstatus&1)>(oldmousebstatus&1))<<11);    //Shoot Mse

	if( typemode != 0 ) {
         #ifdef MASTERSWITCHING 
		locbits &= ~(keystatus[0x32]<<9);               
         #endif
		locbits &= ~((keystatus[keys[14]]==1)<<12);     
	}

     if( (joyb == 236) || (joyb == 220) || (joyb == 124) || (joyb == 188) ) {
          keystatus[keys[moreoptions[4]]]=0;
          keystatus[keys[moreoptions[5]]]=0;
          keystatus[keys[moreoptions[6]]]=0;
          keystatus[keys[moreoptions[7]]]=0;
     }

	oldmousebstatus = bstatus;
	if( (locbits&2048) > 0 ) {
		oldmousebstatus &= ~1;  
     }

     // trap print scrn key
	if( keystatus[0xb7] > 0 ) {
		keystatus[0xb7] = 0;
		printscreeninterrupt();
	}

     // F9 brightness
	if( keystatus[67] > 0 ) {
		keystatus[67] = 0;
		brightness++;
		if( brightness > 8 ) brightness = 0;
		setbrightness(brightness);
	}

    #ifdef OOGIE
     // F10 adjust bias threshhold
     if (keystatus[68] != 0) {
          keystatus[68]=0;
          if (dimensionmode[screenpeek] != 3) {
               setup3dscreen();
          }
          else {
               dimensionmode[screenpeek]=2;
               setview(0L,0L,xdim-1,(ydim-1)>>detailmode);
          }
     }
    #endif
/*                                                          // Les 09/26/95
     // F11 joystick centering on
	if( keystatus[0x57] > 0 ) {
		keystatus[0x57] = 0;
          if( biasthreshholdon == 0 ) {
               if( joycenteringon )
                    joycenteringon=0;
               else
                    joycenteringon=1;
          }
	}
*/                                                          // Les 09/26/95

	if( typemode == 0 ) {
         #ifdef PARALLAX_SETTING_ACTIVE
		if( keystatus[0x19] > 0 ) {
			keystatus[0x19] = 0;
			parallaxtype++;
			if (parallaxtype > 2) parallaxtype = 0;
		}
         #endif
         #ifdef VISIBILITY_SETTING_ACTIVE
		if( (keystatus[0x38]|keystatus[0xb8]) > 0 ) {
			if (keystatus[0x4a] > 0)  // Keypad -
				visibility = min(visibility+(visibility>>3),16384);
			if (keystatus[0x4e] > 0)  // Keypad +
				visibility = max(visibility-(visibility>>3),128);
		}
         #endif
          // if typing mode reset kbrd fifo
		if( (keystatus[keys[18]]) > 0 ) {   
			keystatus[keys[18]] = 0;
			typemode = 1;
			keyfifoplc = keyfifoend;
		}
	}
	else {
		while( keyfifoplc != keyfifoend ) {
			ch = keyfifo[keyfifoplc];
			keystate = keyfifo[(keyfifoplc+1)&(KEYFIFOSIZ-1)];
			keyfifoplc = ((keyfifoplc+2)&(KEYFIFOSIZ-1));
			if( keystate != 0 ) {
                    // backspace key
				if( ch == 0xe ) {
					if( typemessageleng == 0 ) { 
                              typemode = 0; 
                              break; 
                         }
					typemessageleng--;
				}
				if( ch == 0xf ) {
					keystatus[0xf] = 0;
					typemode = 0;
					break;
				}
                    // either enter key
				if( (ch == 0x1c) || (ch == 0x9c) ) {
					keystatus[0x1c] = 0; keystatus[0x9c] = 0;
					if( typemessageleng > 0 ) {
						tempbuf[0] = 2;          
                              // sending text is message type 4
						for( j=typemessageleng-1; j>=0; j-- ) {
							tempbuf[j+1] = typemessage[j];
                              }
						for( i=connecthead; i>=0; i=connectpoint2[i] ) {
							if( i != myconnectindex ) {
								sendpacket(i,tempbuf,typemessageleng+1);
                                   }
                              }
						typemessageleng = 0;
					}
					typemode = 0;
					break;
				}
				if( (typemessageleng < 159) && (ch < 128) ) {
					if( (keystatus[0x2a]|keystatus[0x36]) != 0 ) {
						ch = scantoascwithshift[ch];
                         }
					else {
						ch = scantoasc[ch];
                         }
					if( ch != 0 ) {
                              typemessage[typemessageleng++] = ch;
                         }
				}
			}
		}
		// here's a trick of making key repeat after a 1/2 second
		if( keystatus[0xe] > 0 ) {
			if( keystatus[0xe] < 30 ) {
				keystatus[0xe] += TICSPERFRAME;
               }
			else {
				if( typemessageleng == 0 ) {
					typemode = 0;
                    }
				else {
					typemessageleng--;
                    }
			}
		}
	}

     tekprivatekeys();
}

playback()
{
	long i, j, k;

	ready2send = 0;
	recstat = 0; i = reccnt;
	while (keystatus[1] == 0)
	{
		while (totalclock >= lockclock+TICSPERFRAME)
		{
			if (i >= reccnt)
			{
				prepareboard(boardfilename);
				for(i=connecthead;i>=0;i=connectpoint2[i])
					initplayersprite((short)i);
				resettiming(); ototalclock = 0; gotlastpacketclock = 0;
				i = 0;
			}

			k = 0;
			for(j=connecthead;j>=0;j=connectpoint2[j])
			{
				fsyncvel[j] = recsyncvel[i][k];
				fsyncsvel[j] = recsyncsvel[i][k];
				fsyncangvel[j] = recsyncangvel[i][k];
				fsyncbits[j] = recsyncbits[i][k];
				k++;
			}
			movethings(); domovethings();
			i++;
		}
		drawscreen(screenpeek,(totalclock-lockclock)*(65536/TICSPERFRAME));

		if (keystatus[keys[15]] > 0)
		{
			keystatus[keys[15]] = 0;

			screenpeek = connectpoint2[screenpeek];
			if (screenpeek < 0) screenpeek = connecthead;
		}
		if (keystatus[keys[14]] > 0)
		{
			keystatus[keys[14]] = 0;
			dimensionmode[screenpeek]++;
			if (dimensionmode[screenpeek] > 3) dimensionmode[screenpeek] = 1;
			if (dimensionmode[screenpeek] == 2) setview(0L,0L,xdim-1,(ydim-1)>>detailmode);
			if (dimensionmode[screenpeek] == 3) setup3dscreen();
		}
	}

	musicoff();

//** Les START - 09/26/95
    if (spaceballinitflag) {
        SPW_InputShutdown(0);
    }
//** Les END   - 09/26/95

    uninitmultiplayers();
	uninittimer();
	uninitkeys();
	uninitengine();
	uninitsb();
	uninitgroupfile();
     cduninit();
	setvmode(ovmode);
	exit(0);
}

doanimations()
{
	long i, j;

	for(i=animatecnt-1;i>=0;i--)
	{
		j = *animateptr[i];

		if (j < animategoal[i])
			j = min(j+animatevel[i]*TICSPERFRAME,animategoal[i]);
		else
			j = max(j-animatevel[i]*TICSPERFRAME,animategoal[i]);
		animatevel[i] += animateacc[i];

		*animateptr[i] = j;

		if (j == animategoal[i])
		{
			animatecnt--;
			if (i != animatecnt)
			{
				animateptr[i] = animateptr[animatecnt];
				animategoal[i] = animategoal[animatecnt];
				animatevel[i] = animatevel[animatecnt];
				animateacc[i] = animateacc[animatecnt];
			}
		}
	}
}

getanimationgoal(long animptr)
{
	long i;

	for(i=animatecnt-1;i>=0;i--)
		if (animptr == animateptr[i]) return(i);
	return(-1);
}

setanimation(long *animptr, long thegoal, long thevel, long theacc)
{
	long i, j;

	if (animatecnt >= MAXANIMATES) return(-1);

	j = animatecnt;
	for(i=animatecnt-1;i>=0;i--)
		if (animptr == animateptr[i])
			{ j = i; break; }

	animateptr[j] = animptr;
	animategoal[j] = thegoal;
	animatevel[j] = thevel;
	animateacc[j] = theacc;
	if (j == animatecnt) animatecnt++;
	return(j);
}

checkmasterslaveswitch()
{
	long i, j;

	if (option[4] == 0) return;

	i = connecthead; j = connectpoint2[i];
	while (j >= 0)
	{
		if ((syncbits[j]&512) > 0)
		{
			connectpoint2[i] = connectpoint2[j];
			connectpoint2[j] = connecthead;
			connecthead = (short)j;

			olocvel = locvel+1; olocvel2 = locvel2+1;
			olocsvel = locsvel+1; olocsvel2 = locsvel2+1;
			olocangvel = locangvel+1; olocangvel2 = locangvel2+1;
			olocbits = locbits+1; olocbits2 = locbits2+1;
			for(i=0;i<MAXPLAYERS;i++)
			{
				osyncvel[i] = fsyncvel[i]+1;
				osyncsvel[i] = fsyncsvel[i]+1;
				osyncangvel[i] = fsyncangvel[i]+1;
				osyncbits[i] = fsyncbits[i]+1;
			}

			syncvalplc = 0L; othersyncvalplc = 0L;
			syncvalend = 0L; othersyncvalend = 0L;
			syncvalcnt = 0L; othersyncvalcnt = 0L;

			totalclock = lockclock;
			ototalclock = lockclock;
			gotlastpacketclock = lockclock;
			masterslavetexttime = lockclock;
			ready2send = 1;
			return;
		}
		i = j; j = connectpoint2[i];
	}
}

initkeys()
{
	long i;

	keyfifoplc = 0; keyfifoend = 0;
	for(i=0;i<256;i++) keystatus[i] = 0;
	oldkeyhandler = _dos_getvect(0x9);
	_disable(); _dos_setvect(0x9, keyhandler); _enable();
}

uninitkeys()
{
	short *ptr;

	_dos_setvect(0x9, oldkeyhandler);
	// turn off shifts to prevent stucks with quitting
	ptr = (short *)0x417; *ptr &= ~0x030f;
}

void __interrupt __far keyhandler()
{
	koutp(0x20,0x20);
	oldreadch = readch; readch = kinp(0x60);
	keytemp = kinp(0x61); koutp(0x61,keytemp|128); koutp(0x61,keytemp&127);
	if ((readch|1) == 0xe1) { extended = 128; return; }
	if (oldreadch != readch)
	{
		if ((readch&128) == 0)
		{
			keytemp = readch+extended;
			if (keystatus[keytemp] == 0)
			{
				keystatus[keytemp] = 1;
				keyfifo[keyfifoend] = keytemp;
				keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = 1;
				keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1));
			}
		}
		else
		{
			keytemp = (readch&127)+extended;
			keystatus[keytemp] = 0;
			keyfifo[keyfifoend] = keytemp;
			keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = 0;
			keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1));
		}
	}
	extended = 0;
}

faketimerhandler()
{
	short other, tempbufleng;
	long i, j, k, l;

	if (totalclock < ototalclock+TICSPERFRAME) return;
	if (ready2send == 0) return;
	ototalclock = totalclock;

	// I am the MASTER (or 1 player game)
	if ((myconnectindex == connecthead) || (option[4] == 0))
	{
		if (option[4] != 0)
			getpackets();

		if (getoutputcirclesize() < 16)
		{
			getinput();
			fsyncvel[myconnectindex] = locvel;
			fsyncsvel[myconnectindex] = locsvel;
			fsyncangvel[myconnectindex] = locangvel;
			fsyncbits[myconnectindex] = locbits;

			if (option[4] != 0)
			{
				tempbuf[0] = 0;
				j = ((numplayers+1)>>1)+1;
				for(k=1;k<j;k++) tempbuf[k] = 0;
				k = (1<<3);
				for(i=connecthead;i>=0;i=connectpoint2[i])
				{
					l = 0;
					if (fsyncvel[i] != osyncvel[i]) tempbuf[j++] = fsyncvel[i], l |= 1;
//** Les START - 09/27/95
                    if (fsyncsvel[i] != osyncsvel[i]) {
                         tempbuf[j++]=(fsyncsvel[i]&0xFF);
                         tempbuf[j++]=(fsyncsvel[i]>>8);
                         l|=2;
                    }
                    if (fsyncangvel[i] != osyncangvel[i]) {
                         tempbuf[j++]=(fsyncangvel[i]&0xFF);
                         tempbuf[j++]=(fsyncangvel[i]>>8);
                         l|=4;
                    }
//** Les END   - 09/27/95
					if (fsyncbits[i] != osyncbits[i])
					{
						tempbuf[j++] = (fsyncbits[i]&255);
						tempbuf[j++] = ((fsyncbits[i]>>8)&255);
						l |= 8;
					}
					tempbuf[k>>3] |= (l<<(k&7));
					k += 4;

					osyncvel[i] = fsyncvel[i];
					osyncsvel[i] = fsyncsvel[i];
					osyncangvel[i] = fsyncangvel[i];
					osyncbits[i] = fsyncbits[i];
				}
#if 0
				while (syncvalplc != syncvalend)
				{
					tempbuf[j] = (char)(syncval[syncvalplc]&255);
					tempbuf[j+1] = (char)((syncval[syncvalplc]>>8)&255);
					j += 2;
					syncvalplc = ((syncvalplc+1)&(MOVEFIFOSIZ-1));
				}
#endif
				for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
					sendpacket(i,tempbuf,j);
			}
			else if (numplayers == 2)
			{
				if (keystatus[0xb5] > 0)
				{
					keystatus[0xb5] = 0;
					locselectedgun2++;
					if (locselectedgun2 >= 3) locselectedgun2 = 0;
				}

				// second player on 1 computer mode
				locvel2 = min(max(vel2,-128+8),127-8);
				locsvel2 = min(max(svel2,-128+8),127-8);
				locangvel2 = min(max(angvel2,-128+16),127-16);
				locbits2 = (locselectedgun2<<13);
				locbits2 |= keystatus[0x45];                  //Stand high
				locbits2 |= (keystatus[0x47]<<1);             //Stand low
				locbits2 |= (1<<8);                           //Run
				locbits2 |= (keystatus[0x49]<<2);             //Look up
				locbits2 |= (keystatus[0x37]<<3);             //Look down
				locbits2 |= (keystatus[0x50]<<10);            //Space
				locbits2 |= (keystatus[0x52]<<11);            //Shoot

				other = connectpoint2[myconnectindex];
				if (other < 0) other = connecthead;

				fsyncvel[other] = locvel2;
				fsyncsvel[other] = locsvel2;
				fsyncangvel[other] = locangvel2;
				fsyncbits[other] = locbits2;
			}
			movethings();  //Move EVERYTHING (you too!)
		}
	}
	else                        //I am a SLAVE
	{
		getpackets();

		if (getoutputcirclesize() < 16)
		{
			getinput();

			tempbuf[0] = 1; k = 0;
			j = 2;

			if (locvel != olocvel) tempbuf[j++] = locvel, k |= 1;
//** Les START - 09/27/95
               if (locsvel != olocsvel) {
                    tempbuf[j++]=locsvel&0xFF;
                    tempbuf[j++]=(locsvel>>8);
                    k|=2;
               }
               if (locangvel != olocangvel) {
                    tempbuf[j++]=locangvel&0xFF;
                    tempbuf[j++]=(locangvel>>8);
                    k|=4;
               }
//** Les END   - 09/27/95
			if ((locbits^olocbits)&0x00ff) tempbuf[j++] = (locbits&255), k |= 8;
			if ((locbits^olocbits)&0xff00) tempbuf[j++] = ((locbits>>8)&255), k |= 16;

			tempbuf[1] = k;

			olocvel = locvel;
			olocsvel = locsvel;
			olocangvel = locangvel;
			olocbits = locbits;

			sendpacket(connecthead,tempbuf,j);
		}
	}
}

getpackets()
{
	long i, j, k, l;
	short other, tempbufleng;

	if (option[4] == 0) return;

	while ((tempbufleng = getpacket(&other,tempbuf)) > 0)
	{
		switch(tempbuf[0])
		{
			case 0:  //[0] (receive master sync buffer)
				j = ((numplayers+1)>>1)+1; k = (1<<3);
				for(i=connecthead;i>=0;i=connectpoint2[i])
				{
					l = (tempbuf[k>>3]>>(k&7));
					if (l&1) fsyncvel[i] = tempbuf[j++];
//** Les START - 09/27/95
                    if (l&2) {
                         fsyncsvel[i]=tempbuf[j++];
                         fsyncsvel[i]|=(tempbuf[j++]<<8);
                    }
                    if (l&4) {
                         fsyncangvel[i]=tempbuf[j++];
                         fsyncangvel[i]|=(tempbuf[j++]<<8);
                    }
//** Les END   - 09/27/95
					if (l&8)
					{
						fsyncbits[i] = ((short)tempbuf[j])+(((short)tempbuf[j+1])<<8);
						j += 2;
					}
					k += 4;
				}
#if 0
				while (j != tempbufleng)
				{
					othersyncval[othersyncvalend] = ((long)tempbuf[j]);
					othersyncval[othersyncvalend] += (((long)tempbuf[j+1])<<8);
					j += 2;
					othersyncvalend = ((othersyncvalend+1)&(MOVEFIFOSIZ-1));
				}

				i = 0;
				while (syncvalplc != syncvalend)
				{
					if (othersyncvalcnt > syncvalcnt)
					{
						if (i == 0) syncstat = 0, i = 1;
						syncstat |= (syncval[syncvalplc]^othersyncval[syncvalplc]);
					}
					syncvalplc = ((syncvalplc+1)&(MOVEFIFOSIZ-1));
					syncvalcnt++;
				}
				while (othersyncvalplc != othersyncvalend)
				{
					if (syncvalcnt > othersyncvalcnt)
					{
						if (i == 0) syncstat = 0, i = 1;
						syncstat |= (syncval[othersyncvalplc]^othersyncval[othersyncvalplc]);
					}
					othersyncvalplc = ((othersyncvalplc+1)&(MOVEFIFOSIZ-1));
					othersyncvalcnt++;
				}
#endif

                movethings();        //Move all players and sprites
				break;
			case 1:  //[1] (receive slave sync buffer)
				j = 2; k = tempbuf[1];
				if (k&1) fsyncvel[other] = tempbuf[j++];
//** Les START - 09/27/95
                if (k&2) {
                    fsyncsvel[other]=tempbuf[j++];
                    fsyncsvel[other]|=(tempbuf[j++]<<8);
                }
                if (k&4) {
                    fsyncangvel[other]=tempbuf[j++];
                    fsyncangvel[other]|=(tempbuf[j++]<<8);
                }
//** Les END   - 09/27/95
				if (k&8) fsyncbits[other] = ((fsyncbits[other]&0xff00)|((short)tempbuf[j++]));
				if (k&16) fsyncbits[other] = ((fsyncbits[other]&0x00ff)|(((short)tempbuf[j++])<<8));
				break;
			case 2:
				getmessageleng = tempbufleng-1;
				for(j=getmessageleng-1;j>=0;j--) getmessage[j] = tempbuf[j+1];
				getmessagetimeoff = totalclock+360+(getmessageleng<<4);
				break;
			case 3:
				break;
              #ifdef NETNAMES
               case 8:
                    memcpy(netnames[tempbuf[1]],&tempbuf[2],10);
                    netnames[tempbuf[1]][10]=0;
                    break;
              #endif
			case 5:
				playerreadyflag[other] = tempbuf[1];
				if ((other == connecthead) && (tempbuf[1] == 2))
					sendpacket(connecthead,tempbuf,2);
				break;
			case 255:  //[255] (logout)
				deletesprite(playersprite[other]); 
                    sprintf(tektempbuf,"%2d %8s HAS QUIT", other,netnames[other]); 
                    showmessage(tektempbuf);
				break;
		}
	}
}

waitforeverybody()
{
	long i, j, oldtotalclock;

	if (numplayers < 2) return;

	if (myconnectindex == connecthead)
	{
		for(j=1;j<=2;j++)
		{
			for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
				playerreadyflag[i] = 0;
			oldtotalclock = totalclock-8;
			do
			{
				getpackets();
				if (totalclock >= oldtotalclock+8)
				{
					oldtotalclock = totalclock;
					tempbuf[0] = 5;
					tempbuf[1] = j;
					for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
						if (playerreadyflag[i] != j) sendpacket(i,tempbuf,2);
				}
				for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
					if (playerreadyflag[i] != j) break;
			} while (i >= 0);
		}
	}
	else
	{
		playerreadyflag[connecthead] = 0;
		while (playerreadyflag[connecthead] != 2)
		{
			getpackets();
			if (playerreadyflag[connecthead] == 1)
			{
				playerreadyflag[connecthead] = 0;
				sendpacket(connecthead,tempbuf,2);
			}
		}
	}
}

#if 0
getsyncstat()
{
	long i, j;
	unsigned short crc;
	spritetype *spr;

	crc = 0;
	updatecrc16(crc,randomseed); updatecrc16(crc,randomseed>>8);
	for(i=connecthead;i>=0;i=connectpoint2[i])
	{
		updatecrc16(crc,posx[i]);     
		updatecrc16(crc,posy[i]);     
		updatecrc16(crc,posz[i]);     
		updatecrc16(crc,ang[i]);      
		updatecrc16(crc,horiz[i]);    
		updatecrc16(crc,health[i]);   
	}

    #if SPRITES_CRC_CHECK
	for( i=1000; i>=0; i-- ) {
		for( j=headspritestat[i]; j>=0; j=nextspritestat[j] ) {
			spr = &sprite[j];
			updatecrc16(crc,spr->x); //if (syncstat != 0) printf("%ld ",spr->x);
			updatecrc16(crc,spr->y); //if (syncstat != 0) printf("%ld ",spr->y);
			updatecrc16(crc,spr->z); //if (syncstat != 0) printf("%ld ",spr->z);
			updatecrc16(crc,spr->ang); //if (syncstat != 0) printf("%ld ",spr->ang);
		}
     }
    #endif
 
	return(crc);
}
#endif

