1 // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
2 // Ken Silverman's official web site: "http://www.advsys.net/ken"
3 // See the included license file "BUILDLIC.TXT" for license info.
4 // This file has been modified from Ken Silverman's original release
5 
6 #include <fcntl.h>
7 #include <io.h>
8 #include <sys\types.h>
9 #include <sys\stat.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <dos.h>
14 #include "build.h"
15 #include "names.h"
16 #include "pragmas.h"
17 
18 #define TIMERINTSPERSECOND 280
19 #define MOVESPERSECOND 40
20 #define TICSPERFRAME 3
21 #define MOVEFIFOSIZ 256
22 #define EYEHEIGHT (32<<8)   //Normally (32<<8), (51<<8) to make mirrors happy
23 
24 /***************************************************************************
25 	KEN'S TAG DEFINITIONS:      (Please define your own tags for your games)
26 
27  sector[?].lotag = 0   Normal sector
28  sector[?].lotag = 1   If you are on a sector with this tag, then all sectors
29 								  with same hi tag as this are operated.  Once.
30  sector[?].lotag = 2   Same as sector[?].tag = 1 but this is retriggable.
31  sector[?].lotag = 3   A really stupid sector that really does nothing now.
32  sector[?].lotag = 4   A sector where you are put closer to the floor
33 								  (such as the slime in DOOM1.DAT)
34  sector[?].lotag = 5   A really stupid sector that really does nothing now.
35  sector[?].lotag = 6   A normal door - instead of pressing D, you tag the
36 								  sector with a 6.  The reason I make you edit doors
37 								  this way is so that can program the doors
38 								  yourself.
39  sector[?].lotag = 7   A door the goes down to open.
40  sector[?].lotag = 8   A door that opens horizontally in the middle.
41  sector[?].lotag = 9   A sliding door that opens vertically in the middle.
42 								  -Example of the advantages of not using BSP tree.
43  sector[?].lotag = 10  A warping sector with floor and walls that shade.
44  sector[?].lotag = 11  A sector with all walls that do X-panning.
45  sector[?].lotag = 12  A sector with walls using the dragging function.
46  sector[?].lotag = 13  A sector with some swinging doors in it.
47  sector[?].lotag = 14  A revolving door sector.
48  sector[?].lotag = 15  A subway track.
49  sector[?].lotag = 16  A true double-sliding door.
50 
51 	wall[?].lotag = 0   Normal wall
52 	wall[?].lotag = 1   Y-panning wall
53 	wall[?].lotag = 2   Switch - If you flip it, then all sectors with same hi
54 								  tag as this are operated.
55 	wall[?].lotag = 3   Marked wall to detemine starting dir. (sector tag 12)
56 	wall[?].lotag = 4   Mark on the shorter wall closest to the pivot point
57 								  of a swinging door. (sector tag 13)
58 	wall[?].lotag = 5   Mark where a subway should stop. (sector tag 15)
59 	wall[?].lotag = 6   Mark for true double-sliding doors (sector tag 16)
60 	wall[?].lotag = 7   Water fountain
61 	wall[?].lotag = 8   Bouncy wall!
62 
63  sprite[?].lotag = 0   Normal sprite
64  sprite[?].lotag = 1   If you press space bar on an AL, and the AL is tagged
65 								  with a 1, he will turn evil.
66  sprite[?].lotag = 2   When this sprite is operated, a bomb is shot at its
67 								  position.
68  sprite[?].lotag = 3   Rotating sprite.
69  sprite[?].lotag = 4   Sprite switch.
70  sprite[?].lotag = 5   Basketball hoop score.
71 
72 KEN'S STATUS DEFINITIONS:  (Please define your own statuses for your games)
73  status = 0            Inactive sprite
74  status = 1            Active monster sprite
75  status = 2            Monster that becomes active only when it sees you
76  status = 3            Smoke on the wall for chainguns
77  status = 4            Splashing sprites (When you shoot slime)
78  status = 5            Explosion!
79  status = 6            Travelling bullet
80  status = 7            Bomb sprial-out explosion
81  status = 8            Player!
82  status = 9            EVILALGRAVE shrinking list
83  status = 10           EVILAL list
84  status = 11           Sprite respawning list
85  status = 12           Sprite which does not respawn (Andy's addition)
86  status = MAXSTATUS    Non-existent sprite (this will be true for your
87 														  code also)
88 **************************************************************************/
89 
90 typedef struct
91 {
92 	long x, y, z;
93 } point3d;
94 
95 typedef struct
96 {
97 	signed char fvel, svel, avel;
98 	short bits;
99 } input;
100 
101 static long screentilt = 0;
102 
103 void (__interrupt __far *oldtimerhandler)();
104 void __interrupt __far timerhandler(void);
105 
106 #define KEYFIFOSIZ 64
107 void (__interrupt __far *oldkeyhandler)();
108 void __interrupt __far keyhandler(void);
109 volatile char keystatus[256], keyfifo[KEYFIFOSIZ], keyfifoplc, keyfifoend;
110 volatile char readch, oldreadch, extended, keytemp;
111 
112 static long fvel, svel, avel;
113 static long fvel2, svel2, avel2;
114 
115 #define NUMOPTIONS 8
116 #define NUMKEYS 19
117 static long vesares[13][2] = {320,200,360,200,320,240,360,240,320,400,
118 									360,400,640,350,640,400,640,480,800,600,
119 									1024,768,1280,1024,1600,1200};
120 static char option[NUMOPTIONS] = {0,0,0,0,0,0,1,0};
121 static char keys[NUMKEYS] =
122 {
123 	0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39,
124 	0x1e,0x2c,0xd1,0xc9,0x33,0x34,
125 	0x9c,0x1c,0xd,0xc,0xf,
126 };
127 
128 static long digihz[7] = {6000,8000,11025,16000,22050,32000,44100};
129 
130 static char frame2draw[MAXPLAYERS];
131 static long frameskipcnt[MAXPLAYERS];
132 
133 #define LAVASIZ 128
134 #define LAVALOGSIZ 7
135 #define LAVAMAXDROPS 32
136 static char lavabakpic[(LAVASIZ+4)*(LAVASIZ+4)], lavainc[LAVASIZ];
137 static long lavanumdrops, lavanumframes;
138 static long lavadropx[LAVAMAXDROPS], lavadropy[LAVAMAXDROPS];
139 static long lavadropsiz[LAVAMAXDROPS], lavadropsizlookup[LAVAMAXDROPS];
140 static long lavaradx[24][96], lavarady[24][96], lavaradcnt[32];
141 
142 	//Shared player variables
143 static long posx[MAXPLAYERS], posy[MAXPLAYERS], posz[MAXPLAYERS];
144 static long horiz[MAXPLAYERS], zoom[MAXPLAYERS], hvel[MAXPLAYERS];
145 static short ang[MAXPLAYERS], cursectnum[MAXPLAYERS], ocursectnum[MAXPLAYERS];
146 static short playersprite[MAXPLAYERS], deaths[MAXPLAYERS];
147 static long lastchaingun[MAXPLAYERS];
148 static long health[MAXPLAYERS], flytime[MAXPLAYERS];
149 static short oflags[MAXPLAYERS];
150 static short numbombs[MAXPLAYERS];
151 static short numgrabbers[MAXPLAYERS];   // Andy did this
152 static short nummissiles[MAXPLAYERS];   // Andy did this
153 static char dimensionmode[MAXPLAYERS];
154 static char revolvedoorstat[MAXPLAYERS];
155 static short revolvedoorang[MAXPLAYERS], revolvedoorrotang[MAXPLAYERS];
156 static long revolvedoorx[MAXPLAYERS], revolvedoory[MAXPLAYERS];
157 
158 	//ENGINE CONTROLLED MULTIPLAYER VARIABLES:
159 extern short numplayers, myconnectindex;
160 extern short connecthead, connectpoint2[MAXPLAYERS];   //Player linked list variables (indeces, not connection numbers)
161 
162 static long nummoves;
163 // Bug: NUMSTATS used to be equal to the greatest tag number,
164 // so that the last statrate[] entry was random memory junk
165 // because stats 0-NUMSTATS required NUMSTATS+1 bytes.   -Andy
166 #define NUMSTATS 13
167 static signed char statrate[NUMSTATS] = {-1,0,-1,0,0,0,1,3,0,3,15,-1,-1};
168 
169 	//Input structures
170 static char networkmode;     //0 is 2(n-1) mode, 1 is n(n-1) mode
171 static long locselectedgun, locselectedgun2;
172 static input loc, oloc, loc2;
173 static input ffsync[MAXPLAYERS], osync[MAXPLAYERS], sync[MAXPLAYERS];
174 	//Input faketimerhandler -> movethings fifo
175 static long movefifoplc, movefifoend[MAXPLAYERS];
176 static input baksync[MOVEFIFOSIZ][MAXPLAYERS];
177 	//Game recording variables
178 static long reccnt, recstat = 1;
179 static input recsync[16384][2];
180 
181 static signed char otherlag[MAXPLAYERS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
182 static long averagelag[MAXPLAYERS] = {512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512};
183 
184 static long fakemovefifoplc;
185 static long myx, myy, myz, omyx, omyy, omyz, myzvel;
186 static long myhoriz, omyhoriz;
187 static short myang, omyang, mycursectnum;
188 static long myxbak[MOVEFIFOSIZ], myybak[MOVEFIFOSIZ], myzbak[MOVEFIFOSIZ];
189 static long myhorizbak[MOVEFIFOSIZ];
190 static short myangbak[MOVEFIFOSIZ];
191 
192 	//MULTI.OBJ sync state variables
193 extern char syncstate;
194 	//GAME.C sync state variables
195 static char syncstat, syncval[MOVEFIFOSIZ], othersyncval[MOVEFIFOSIZ];
196 static long syncvaltottail, syncvalhead, othersyncvalhead, syncvaltail;
197 
198 static char detailmode = 0, ready2send = 0;
199 static long ototalclock = 0, gotlastpacketclock = 0, smoothratio;
200 static long oposx[MAXPLAYERS], oposy[MAXPLAYERS], oposz[MAXPLAYERS];
201 static long ohoriz[MAXPLAYERS], ozoom[MAXPLAYERS];
202 static short oang[MAXPLAYERS];
203 
204 static point3d osprite[MAXSPRITES];
205 
206 #define MAXINTERPOLATIONS 1024
207 static long numinterpolations = 0, startofdynamicinterpolations = 0;
208 static long oldipos[MAXINTERPOLATIONS];
209 static long bakipos[MAXINTERPOLATIONS];
210 static long *curipos[MAXINTERPOLATIONS];
211 
212 extern long cachecount, transarea;
213 
214 static char playerreadyflag[MAXPLAYERS];
215 
216 	//Miscellaneous variables
217 static char packbuf[MAXXDIM];
218 static char tempbuf[MAXXDIM], boardfilename[80];
219 static short tempshort[MAXSECTORS];
220 static short screenpeek = 0, oldmousebstatus = 0, brightness = 0;
221 static short screensize, screensizeflag = 0;
222 static short neartagsector, neartagwall, neartagsprite;
223 static long lockclock, neartagdist, neartaghitdist;
224 extern long frameplace, pageoffset, ydim16;
225 static long globhiz, globloz, globhihit, globlohit;
226 static long stereomode = 0;
227 extern long stereowidth, stereopixelwidth, activepage;
228 
229 	//Over the shoulder mode variables
230 static long cameradist = -1, cameraang = 0, cameraclock = 0;
231 
232 	//Board animation variables
233 #define MAXMIRRORS 64
234 static short mirrorwall[MAXMIRRORS], mirrorsector[MAXMIRRORS], mirrorcnt;
235 static short floormirrorsector[64], floormirrorcnt;
236 static short turnspritelist[16], turnspritecnt;
237 static short warpsectorlist[64], warpsectorcnt;
238 static short xpanningsectorlist[16], xpanningsectorcnt;
239 static short ypanningwalllist[64], ypanningwallcnt;
240 static short floorpanninglist[64], floorpanningcnt;
241 static short dragsectorlist[16], dragxdir[16], dragydir[16], dragsectorcnt;
242 static long dragx1[16], dragy1[16], dragx2[16], dragy2[16], dragfloorz[16];
243 static short swingcnt, swingwall[32][5], swingsector[32];
244 static short swingangopen[32], swingangclosed[32], swingangopendir[32];
245 static short swingang[32], swinganginc[32];
246 static long swingx[32][8], swingy[32][8];
247 static short revolvesector[4], revolveang[4], revolvecnt;
248 static long revolvex[4][16], revolvey[4][16];
249 static long revolvepivotx[4], revolvepivoty[4];
250 static short subwaytracksector[4][128], subwaynumsectors[4], subwaytrackcnt;
251 static long subwaystop[4][8], subwaystopcnt[4];
252 static long subwaytrackx1[4], subwaytracky1[4];
253 static long subwaytrackx2[4], subwaytracky2[4];
254 static long subwayx[4], subwaygoalstop[4], subwayvel[4], subwaypausetime[4];
255 static short waterfountainwall[MAXPLAYERS], waterfountaincnt[MAXPLAYERS];
256 static short slimesoundcnt[MAXPLAYERS];
257 
258 	//Variables that let you type messages to other player
259 static char getmessage[162], getmessageleng;
260 static long getmessagetimeoff;
261 static char typemessage[162], typemessageleng = 0, typemode = 0;
262 static char scantoasc[128] =
263 {
264 	0,0,'1','2','3','4','5','6','7','8','9','0','-','=',0,0,
265 	'q','w','e','r','t','y','u','i','o','p','[',']',0,0,'a','s',
266 	'd','f','g','h','j','k','l',';',39,'`',0,92,'z','x','c','v',
267 	'b','n','m',',','.','/',0,'*',0,32,0,0,0,0,0,0,
268 	0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
269 	'2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
270 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
271 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
272 };
273 static char scantoascwithshift[128] =
274 {
275 	0,0,'!','@','#','$','%','^','&','*','(',')','_','+',0,0,
276 	'Q','W','E','R','T','Y','U','I','O','P','{','}',0,0,'A','S',
277 	'D','F','G','H','J','K','L',':',34,'~',0,'|','Z','X','C','V',
278 	'B','N','M','<','>','?',0,'*',0,32,0,0,0,0,0,0,
279 	0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
280 	'2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
281 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
282 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
283 };
284 
285 	//These variables are for animating x, y, or z-coordinates of sectors,
286 	//walls, or sprites (They are NOT to be used for changing the [].picnum's)
287 	//See the setanimation(), and getanimategoal() functions for more details.
288 #define MAXANIMATES 512
289 static long *animateptr[MAXANIMATES], animategoal[MAXANIMATES];
290 static long animatevel[MAXANIMATES], animateacc[MAXANIMATES], animatecnt = 0;
291 
292 	//These parameters are in exact order of sprite structure in BUILD.H
293 #define spawnsprite(newspriteindex2,x2,y2,z2,cstat2,shade2,pal2,       \
294 		clipdist2,xrepeat2,yrepeat2,xoffset2,yoffset2,picnum2,ang2,      \
295 		xvel2,yvel2,zvel2,owner2,sectnum2,statnum2,lotag2,hitag2,extra2) \
296 {                                                                      \
297 	spritetype *spr2;                                                   \
298 	newspriteindex2 = insertsprite(sectnum2,statnum2);                  \
299 	spr2 = &sprite[newspriteindex2];                                    \
300 	spr2->x = x2; spr2->y = y2; spr2->z = z2;                           \
301 	spr2->cstat = cstat2; spr2->shade = shade2;                         \
302 	spr2->pal = pal2; spr2->clipdist = clipdist2;                       \
303 	spr2->xrepeat = xrepeat2; spr2->yrepeat = yrepeat2;                 \
304 	spr2->xoffset = xoffset2; spr2->yoffset = yoffset2;                 \
305 	spr2->picnum = picnum2; spr2->ang = ang2;                           \
306 	spr2->xvel = xvel2; spr2->yvel = yvel2; spr2->zvel = zvel2;         \
307 	spr2->owner = owner2;                                               \
308 	spr2->lotag = lotag2; spr2->hitag = hitag2; spr2->extra = extra2;   \
309 	copybuf(&spr2->x,&osprite[newspriteindex2].x,3);                    \
310 	show2dsprite[newspriteindex2>>3] &= ~(1<<(newspriteindex2&7));      \
311 	if (show2dsector[sectnum2>>3]&(1<<(sectnum2&7)))                    \
312 		show2dsprite[newspriteindex2>>3] |= (1<<(newspriteindex2&7));    \
313 }                                                                      \
314 
main(short int argc,char ** argv)315 main(short int argc,char **argv)
316 {
317 	long i, j, k, l, fil, waitplayers, x1, y1, x2, y2;
318 	short other, packleng;
319 	char *ptr;
320 
321 	initgroupfile("stuff.dat");
322 
323 	if ((argc >= 2) && (stricmp("-net",argv[1]) != 0) && (stricmp("/net",argv[1]) != 0))
324 	{
325 		strcpy(&boardfilename,argv[1]);
326 		if(strchr(boardfilename,'.') == 0)
327 			strcat(boardfilename,".map");
328 	}
329 	else
330 		strcpy(&boardfilename,"nukeland.map");
331 
332 	if ((fil = open("setup.dat",O_BINARY|O_RDWR,S_IREAD)) != -1)
333 	{
334 		read(fil,&option[0],NUMOPTIONS);
335 		read(fil,&keys[0],NUMKEYS);
336 		close(fil);
337 	}
338 	if (option[3] != 0) initmouse();
339 
340 	initengine();
341 	initkeys();
342 	inittimer();
343 	initmultiplayers(option[4],option[5],0);
344 
345 	pskyoff[0] = 0; pskyoff[1] = 0; pskybits = 1;
346 
347 	initsb(option[1],option[2],digihz[option[7]>>4],((option[7]&4)>0)+1,((option[7]&2)>0)+1,60,option[7]&1);
348 	if (strcmp(boardfilename,"klab.map") == 0)
349 		loadsong("klabsong.kdm");
350 	else
351 		loadsong("neatsong.kdm");
352 	musicon();
353 
354 	loadpics("tiles000.art");                      //Load artwork
355 	qloadkvx(0L,"voxel000.kvx");
356 	qloadkvx(1L,"voxel001.kvx");
357 
358 		//Here's an example of TRUE ornamented walls
359 		//The allocatepermanenttile should be called right after loadpics
360 		//Since it resets the tile cache for each call.
361 	if (allocatepermanenttile(SLIME,128,128) == 0)    //If enough memory
362 	{
363 		printf("Not enough memory for slime!\n");
364 		exit(0);
365 	}
366 	if (allocatepermanenttile(MAXTILES-1,64,64) != 0)    //If enough memory
367 	{
368 			//My face with an explosion written over it
369 		copytilepiece(KENPICTURE,0,0,64,64,MAXTILES-1,0,0);
370 		copytilepiece(EXPLOSION,0,0,64,64,MAXTILES-1,0,0);
371 	}
372 
373 	initlava();
374 
375 	for(j=0;j<256;j++)
376 		tempbuf[j] = ((j+32)&255);  //remap colors for screwy palette sectors
377 	makepalookup(16,tempbuf,0,0,0,1);
378 
379 	for(j=0;j<256;j++) tempbuf[j] = j;
380 	makepalookup(17,tempbuf,24,24,24,1);
381 
382 	for(j=0;j<256;j++) tempbuf[j] = j; //(j&31)+32;
383 	makepalookup(18,tempbuf,8,8,48,1);
384 
385 	prepareboard(boardfilename);                   //Load board
386 
387 	if (option[4] > 0)
388 	{
389 		x1 = ((xdim-screensize)>>1);
390 		x2 = x1+screensize-1;
391 		y1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1);
392 		y2 = y1 + scale(screensize,ydim-32,xdim)-1;
393 		drawtilebackground(0L,0L,BACKGROUND,8,x1,y1,x2,y2,0);
394 
395 		sendlogon();
396 		if (option[4] < 5) waitplayers = 2; else waitplayers = option[4]-3;
397 		while (numplayers < waitplayers)
398 		{
399 			sprintf(tempbuf,"%ld of %ld players in...",numplayers,waitplayers);
400 			printext256(68L,84L,31,0,tempbuf,0);
401 			nextpage();
402 
403 			if (getpacket(&other,packbuf) > 0)
404 				if (packbuf[0] == 255)
405 					keystatus[1] = 1;
406 
407 			if (keystatus[1])
408 			{
409 				sendlogoff();         //Signing off
410 				musicoff();
411 				uninitmultiplayers();
412 				uninittimer();
413 				uninitkeys();
414 				uninitengine();
415 				uninitsb();
416 				uninitgroupfile();
417 				setvmode(0x3);        //Set back to text mode
418 				exit(0);
419 			}
420 		}
421 		screenpeek = myconnectindex;
422 
423 		if (numplayers <= 3)
424 			networkmode = 1;
425 		else
426 			networkmode = 0;
427 
428 		j = 1;
429 		for(i=connecthead;i>=0;i=connectpoint2[i])
430 		{
431 			if (myconnectindex == i) break;
432 			j++;
433 		}
434 		sprintf(getmessage,"Player %ld",j);
435 		if (networkmode == 0)
436 		{
437 			if (j == 1) strcat(getmessage," (Master)");
438 					 else strcat(getmessage," (Slave)");
439 		}
440 		else
441 			strcat(getmessage," (Even)");
442 		getmessageleng = strlen(getmessage);
443 		getmessagetimeoff = totalclock+120;
444 	}
445 
446 	reccnt = 0;
447 	for(i=connecthead;i>=0;i=connectpoint2[i]) initplayersprite((short)i);
448 
449 	//waitforeverybody();
450 	totalclock = ototalclock = 0; gotlastpacketclock = 0; nummoves = 0;
451 
452 	drawscreen(screenpeek,65536L);
453 
454 	ready2send = 1;
455 	while (!keystatus[1])       //Main loop starts here
456 	{
457 			// backslash (useful only with KDM)
458 		if (keystatus[0x2b]) { keystatus[0x2b] = 0; preparesndbuf(); }
459 
460 		if ((networkmode == 1) || (myconnectindex != connecthead))
461 			while (fakemovefifoplc != movefifoend[myconnectindex]) fakedomovethings();
462 
463 		getpackets();
464 
465 		if (typemode == 0)           //if normal game keys active
466 		{
467 			if ((keystatus[0x2a]&keystatus[0x36]&keystatus[0x13]) > 0)   //Sh.Sh.R (replay)
468 			{
469 				keystatus[0x13] = 0;
470 				playback();
471 			}
472 
473 			if (keystatus[0x26]&(keystatus[0x1d]|keystatus[0x9d])) //Load game
474 			{
475 				keystatus[0x26] = 0;
476 				loadgame();
477 				drawstatusbar(screenpeek);   // Andy did this
478 			}
479 
480 			if (keystatus[0x1f]&(keystatus[0x1d]|keystatus[0x9d])) //Save game
481 			{
482 				keystatus[0x1f] = 0;
483 				savegame();
484 			}
485 		}
486 
487 		if ((networkmode == 0) || (option[4] == 0))
488 		{
489 			while (movefifoplc != movefifoend[0]) domovethings();
490 		}
491 		else
492 		{
493 			j = connecthead;
494 			if (j == myconnectindex) j = connectpoint2[j];
495 			averagelag[j] = ((averagelag[j]*7+(((movefifoend[myconnectindex]-movefifoend[j]+otherlag[j]+2)&255)<<8))>>3);
496 			j = max(averagelag[j]>>9,1);
497 			while (((movefifoend[myconnectindex]-movefifoplc)&(MOVEFIFOSIZ-1)) > j)
498 			{
499 				for(i=connecthead;i>=0;i=connectpoint2[i])
500 					if (movefifoplc == movefifoend[i]) break;
501 				if (i >= 0) break;
502 				if (myconnectindex != connecthead)
503 				{
504 					k = ((movefifoend[myconnectindex]-movefifoend[connecthead]-otherlag[connecthead]+128)&255);
505 					if (k > 128+1) ototalclock++;
506 					if (k < 128-1) ototalclock--;
507 				}
508 				domovethings();
509 			}
510 		}
511 		i = (totalclock-gotlastpacketclock)*(65536/(TIMERINTSPERSECOND/MOVESPERSECOND));
512 		drawscreen(screenpeek,i);
513 		if (((stereomode) || (option[0] == 6)) && ((activepage&1)))
514 			drawscreen(screenpeek,i);
515 	}
516 
517 	sendlogoff();         //Signing off
518 	musicoff();
519 	uninitmultiplayers();
520 	uninittimer();
521 	uninitkeys();
522 	uninitengine();
523 	uninitsb();
524 	uninitgroupfile();
525 	setvmode(0x3);        //Set back to text mode
526 
527 	if (stereomode)
528 	{
529 		printf("stereowidth was: %ld\n",stereowidth);
530 		printf("stereopixelwidth was: %ld\n",stereopixelwidth);
531 	}
532 	return(0);
533 }
534 
operatesector(short dasector)535 operatesector(short dasector)
536 {     //Door code
537 	long i, j, k, s, nexti, good, cnt, datag;
538 	long dax, day, daz, dax2, day2, daz2, centx, centy;
539 	short startwall, endwall, wallfind[2];
540 
541 	datag = sector[dasector].lotag;
542 
543 	startwall = sector[dasector].wallptr;
544 	endwall = startwall + sector[dasector].wallnum;
545 	centx = 0L, centy = 0L;
546 	for(i=startwall;i<endwall;i++)
547 	{
548 		centx += wall[i].x;
549 		centy += wall[i].y;
550 	}
551 	centx /= (endwall-startwall);
552 	centy /= (endwall-startwall);
553 
554 		//Simple door that moves up  (tag 8 is a combination of tags 6 & 7)
555 	if ((datag == 6) || (datag == 8))    //If the sector in front is a door
556 	{
557 		i = getanimationgoal((long)&sector[dasector].ceilingz);
558 		if (i >= 0)      //If door already moving, reverse its direction
559 		{
560 			if (datag == 8)
561 				daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1);
562 			else
563 				daz = sector[dasector].floorz;
564 
565 			if (animategoal[i] == daz)
566 				animategoal[i] = sector[nextsectorneighborz(dasector,sector[dasector].floorz,-1,-1)].ceilingz;
567 			else
568 				animategoal[i] = daz;
569 			animatevel[i] = 0;
570 		}
571 		else      //else insert the door's ceiling on the animation list
572 		{
573 			if (sector[dasector].ceilingz == sector[dasector].floorz)
574 				daz = sector[nextsectorneighborz(dasector,sector[dasector].floorz,-1,-1)].ceilingz;
575 			else
576 			{
577 				if (datag == 8)
578 					daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1);
579 				else
580 					daz = sector[dasector].floorz;
581 			}
582 			if ((j = setanimation(&sector[dasector].ceilingz,daz,6L,6L)) >= 0)
583 				wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,&centx,&centy,0);
584 		}
585 	}
586 		//Simple door that moves down
587 	if ((datag == 7) || (datag == 8)) //If the sector in front's elevator
588 	{
589 		i = getanimationgoal((long)&sector[dasector].floorz);
590 		if (i >= 0)      //If elevator already moving, reverse its direction
591 		{
592 			if (datag == 8)
593 				daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1);
594 			else
595 				daz = sector[dasector].ceilingz;
596 
597 			if (animategoal[i] == daz)
598 				animategoal[i] = sector[nextsectorneighborz(dasector,sector[dasector].ceilingz,1,1)].floorz;
599 			else
600 				animategoal[i] = daz;
601 			animatevel[i] = 0;
602 		}
603 		else      //else insert the elevator's ceiling on the animation list
604 		{
605 			if (sector[dasector].floorz == sector[dasector].ceilingz)
606 				daz = sector[nextsectorneighborz(dasector,sector[dasector].ceilingz,1,1)].floorz;
607 			else
608 			{
609 				if (datag == 8)
610 					daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1);
611 				else
612 					daz = sector[dasector].ceilingz;
613 			}
614 			if ((j = setanimation(&sector[dasector].floorz,daz,6L,6L)) >= 0)
615 				wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,&centx,&centy,0);
616 		}
617 	}
618 
619 	if (datag == 9)   //Smooshy-wall sideways double-door
620 	{
621 		//find any points with either same x or same y coordinate
622 		//  as center (centx, centy) - should be 2 points found.
623 		wallfind[0] = -1;
624 		wallfind[1] = -1;
625 		for(i=startwall;i<endwall;i++)
626 			if ((wall[i].x == centx) || (wall[i].y == centy))
627 			{
628 				if (wallfind[0] == -1)
629 					wallfind[0] = i;
630 				else
631 					wallfind[1] = i;
632 			}
633 
634 		for(j=0;j<2;j++)
635 		{
636 			if ((wall[wallfind[j]].x == centx) && (wall[wallfind[j]].y == centy))
637 			{
638 				//find what direction door should open by averaging the
639 				//  2 neighboring points of wallfind[0] & wallfind[1].
640 				i = wallfind[j]-1; if (i < startwall) i = endwall-1;
641 				dax2 = ((wall[i].x+wall[wall[wallfind[j]].point2].x)>>1)-wall[wallfind[j]].x;
642 				day2 = ((wall[i].y+wall[wall[wallfind[j]].point2].y)>>1)-wall[wallfind[j]].y;
643 				if (dax2 != 0)
644 				{
645 					dax2 = wall[wall[wall[wallfind[j]].point2].point2].x;
646 					dax2 -= wall[wall[wallfind[j]].point2].x;
647 					setanimation(&wall[wallfind[j]].x,wall[wallfind[j]].x+dax2,4L,0L);
648 					setanimation(&wall[i].x,wall[i].x+dax2,4L,0L);
649 					setanimation(&wall[wall[wallfind[j]].point2].x,wall[wall[wallfind[j]].point2].x+dax2,4L,0L);
650 				}
651 				else if (day2 != 0)
652 				{
653 					day2 = wall[wall[wall[wallfind[j]].point2].point2].y;
654 					day2 -= wall[wall[wallfind[j]].point2].y;
655 					setanimation(&wall[wallfind[j]].y,wall[wallfind[j]].y+day2,4L,0L);
656 					setanimation(&wall[i].y,wall[i].y+day2,4L,0L);
657 					setanimation(&wall[wall[wallfind[j]].point2].y,wall[wall[wallfind[j]].point2].y+day2,4L,0L);
658 				}
659 			}
660 			else
661 			{
662 				i = wallfind[j]-1; if (i < startwall) i = endwall-1;
663 				dax2 = ((wall[i].x+wall[wall[wallfind[j]].point2].x)>>1)-wall[wallfind[j]].x;
664 				day2 = ((wall[i].y+wall[wall[wallfind[j]].point2].y)>>1)-wall[wallfind[j]].y;
665 				if (dax2 != 0)
666 				{
667 					setanimation(&wall[wallfind[j]].x,centx,4L,0L);
668 					setanimation(&wall[i].x,centx+dax2,4L,0L);
669 					setanimation(&wall[wall[wallfind[j]].point2].x,centx+dax2,4L,0L);
670 				}
671 				else if (day2 != 0)
672 				{
673 					setanimation(&wall[wallfind[j]].y,centy,4L,0L);
674 					setanimation(&wall[i].y,centy+day2,4L,0L);
675 					setanimation(&wall[wall[wallfind[j]].point2].y,centy+day2,4L,0L);
676 				}
677 			}
678 		}
679 		wsayfollow("updowndr.wav",4096L-256L,256L,&centx,&centy,0);
680 		wsayfollow("updowndr.wav",4096L+256L,256L,&centx,&centy,0);
681 	}
682 
683 	if (datag == 13)  //Swinging door
684 	{
685 		for(i=0;i<swingcnt;i++)
686 		{
687 			if (swingsector[i] == dasector)
688 			{
689 				if (swinganginc[i] == 0)
690 				{
691 					if (swingang[i] == swingangclosed[i])
692 					{
693 						swinganginc[i] = swingangopendir[i];
694 						wsayfollow("opendoor.wav",4096L+(krand()&511)-256,256L,&centx,&centy,0);
695 					}
696 					else
697 						swinganginc[i] = -swingangopendir[i];
698 				}
699 				else
700 					swinganginc[i] = -swinganginc[i];
701 
702 				for(j=1;j<=3;j++)
703 				{
704 					setinterpolation(&wall[swingwall[i][j]].x);
705 					setinterpolation(&wall[swingwall[i][j]].y);
706 				}
707 			}
708 		}
709 	}
710 
711 	if (datag == 16)  //True sideways double-sliding door
712 	{
713 		 //get 2 closest line segments to center (dax, day)
714 		wallfind[0] = -1;
715 		wallfind[1] = -1;
716 		for(i=startwall;i<endwall;i++)
717 			if (wall[i].lotag == 6)
718 			{
719 				if (wallfind[0] == -1)
720 					wallfind[0] = i;
721 				else
722 					wallfind[1] = i;
723 			}
724 
725 		for(j=0;j<2;j++)
726 		{
727 			if ((((wall[wallfind[j]].x+wall[wall[wallfind[j]].point2].x)>>1) == centx) && (((wall[wallfind[j]].y+wall[wall[wallfind[j]].point2].y)>>1) == centy))
728 			{     //door was closed
729 					//find what direction door should open
730 				i = wallfind[j]-1; if (i < startwall) i = endwall-1;
731 				dax2 = wall[i].x-wall[wallfind[j]].x;
732 				day2 = wall[i].y-wall[wallfind[j]].y;
733 				if (dax2 != 0)
734 				{
735 					dax2 = wall[wall[wall[wall[wallfind[j]].point2].point2].point2].x;
736 					dax2 -= wall[wall[wall[wallfind[j]].point2].point2].x;
737 					setanimation(&wall[wallfind[j]].x,wall[wallfind[j]].x+dax2,4L,0L);
738 					setanimation(&wall[i].x,wall[i].x+dax2,4L,0L);
739 					setanimation(&wall[wall[wallfind[j]].point2].x,wall[wall[wallfind[j]].point2].x+dax2,4L,0L);
740 					setanimation(&wall[wall[wall[wallfind[j]].point2].point2].x,wall[wall[wall[wallfind[j]].point2].point2].x+dax2,4L,0L);
741 				}
742 				else if (day2 != 0)
743 				{
744 					day2 = wall[wall[wall[wall[wallfind[j]].point2].point2].point2].y;
745 					day2 -= wall[wall[wall[wallfind[j]].point2].point2].y;
746 					setanimation(&wall[wallfind[j]].y,wall[wallfind[j]].y+day2,4L,0L);
747 					setanimation(&wall[i].y,wall[i].y+day2,4L,0L);
748 					setanimation(&wall[wall[wallfind[j]].point2].y,wall[wall[wallfind[j]].point2].y+day2,4L,0L);
749 					setanimation(&wall[wall[wall[wallfind[j]].point2].point2].y,wall[wall[wall[wallfind[j]].point2].point2].y+day2,4L,0L);
750 				}
751 			}
752 			else
753 			{    //door was not closed
754 				i = wallfind[j]-1; if (i < startwall) i = endwall-1;
755 				dax2 = wall[i].x-wall[wallfind[j]].x;
756 				day2 = wall[i].y-wall[wallfind[j]].y;
757 				if (dax2 != 0)
758 				{
759 					setanimation(&wall[wallfind[j]].x,centx,4L,0L);
760 					setanimation(&wall[i].x,centx+dax2,4L,0L);
761 					setanimation(&wall[wall[wallfind[j]].point2].x,centx,4L,0L);
762 					setanimation(&wall[wall[wall[wallfind[j]].point2].point2].x,centx+dax2,4L,0L);
763 				}
764 				else if (day2 != 0)
765 				{
766 					setanimation(&wall[wallfind[j]].y,centy,4L,0L);
767 					setanimation(&wall[i].y,centy+day2,4L,0L);
768 					setanimation(&wall[wall[wallfind[j]].point2].y,centy,4L,0L);
769 					setanimation(&wall[wall[wall[wallfind[j]].point2].point2].y,centy+day2,4L,0L);
770 				}
771 			}
772 		}
773 		wsayfollow("updowndr.wav",4096L-64L,256L,&centx,&centy,0);
774 		wsayfollow("updowndr.wav",4096L+64L,256L,&centx,&centy,0);
775 	}
776 }
777 
operatesprite(short dasprite)778 operatesprite(short dasprite)
779 {
780 	long datag;
781 
782 	datag = sprite[dasprite].lotag;
783 
784 	if (datag == 2)    //A sprite that shoots a bomb
785 	{
786 		shootgun(dasprite,
787 					sprite[dasprite].x,sprite[dasprite].y,sprite[dasprite].z,
788 					sprite[dasprite].ang,100L,sprite[dasprite].sectnum,2);
789 	}
790 }
791 
changehealth(short snum,short deltahealth)792 changehealth(short snum, short deltahealth)
793 {
794 	long dax, day;
795 	short good, k, startwall, endwall, s;
796 
797 	if (health[snum] > 0)
798 	{
799 		health[snum] += deltahealth;
800 		if (health[snum] > 999) health[snum] = 999;
801 
802 		if (health[snum] <= 0)
803 		{
804 			health[snum] = -1;
805 			wsayfollow("death.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
806 			sprite[playersprite[snum]].picnum = SKELETON;
807 		}
808 
809 		if ((snum == screenpeek) && (screensize <= xdim))
810 		{
811 			if (health[snum] > 0)
812 				sprintf(&tempbuf,"Health:%3d",health[snum]);
813 			else
814 				sprintf(&tempbuf,"YOU STINK!");
815 
816 			printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-24,tempbuf,ALPHABET,80);
817 		}
818 	}
819 	return(health[snum] <= 0);      //You were just injured
820 }
821 
changenumbombs(short snum,short deltanumbombs)822 changenumbombs(short snum, short deltanumbombs) {   // Andy did this
823 	numbombs[snum] += deltanumbombs;
824 	if (numbombs[snum] > 999) numbombs[snum] = 999;
825 	if (numbombs[snum] <= 0) {
826 		wsayfollow("doh.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
827 		numbombs[snum] = 0;
828 	}
829 
830 	if ((snum == screenpeek) && (screensize <= xdim)) {
831 		sprintf(&tempbuf,"B:%3d",numbombs[snum]);
832 		printext(8L,(ydim - 28L),tempbuf,ALPHABET,80);
833 	}
834 }
835 
changenummissiles(short snum,short deltanummissiles)836 changenummissiles(short snum, short deltanummissiles) {   // Andy did this
837 	nummissiles[snum] += deltanummissiles;
838 	if (nummissiles[snum] > 999) nummissiles[snum] = 999;
839 	if (nummissiles[snum] <= 0) {
840 		wsayfollow("doh.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
841 		nummissiles[snum] = 0;
842 	}
843 
844 	if ((snum == screenpeek) && (screensize <= xdim)) {
845 		sprintf(&tempbuf,"M:%3d",nummissiles[snum]);
846 		printext(8L,(ydim - 20L),tempbuf,ALPHABET,80);
847 	}
848 }
849 
changenumgrabbers(short snum,short deltanumgrabbers)850 changenumgrabbers(short snum, short deltanumgrabbers) {   // Andy did this
851 	numgrabbers[snum] += deltanumgrabbers;
852 	if (numgrabbers[snum] > 999) numgrabbers[snum] = 999;
853 	if (numgrabbers[snum] <= 0) {
854 		wsayfollow("doh.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
855 		numgrabbers[snum] = 0;
856 	}
857 
858 	if ((snum == screenpeek) && (screensize <= xdim)) {
859 		sprintf(&tempbuf,"G:%3d",numgrabbers[snum]);
860 		printext(8L,(ydim - 12L),tempbuf,ALPHABET,80);
861 	}
862 }
863 
864 static long ostatusflytime = 0x80000000;
drawstatusflytime(short snum)865 drawstatusflytime(short snum) {   // Andy did this
866 	long nstatusflytime;
867 
868 	if ((snum == screenpeek) && (screensize <= xdim)) {
869 		nstatusflytime = (((flytime[snum] + 119) - lockclock) / 120);
870 		if (nstatusflytime > 1000) nstatusflytime = 1000;
871 		else if (nstatusflytime < 0) nstatusflytime = 0;
872 		if (nstatusflytime != ostatusflytime) {
873 			if (nstatusflytime > 999) sprintf(&tempbuf,"FT:BIG");
874 			else sprintf(&tempbuf,"FT:%3d",nstatusflytime);
875 			printext((xdim - 56L),(ydim - 20L),tempbuf,ALPHABET,80);
876 			ostatusflytime = nstatusflytime;
877 		}
878 	}
879 }
880 
drawstatusbar(short snum)881 drawstatusbar(short snum) {   // Andy did this
882 	long nstatusflytime;
883 
884 	if ((snum == screenpeek) && (screensize <= xdim)) {
885 		sprintf(&tempbuf,"Deaths:%d",deaths[snum]);
886 		printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-16,tempbuf,ALPHABET,80);
887 		sprintf(&tempbuf,"Health:%3d",health[snum]);
888 		printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-24,tempbuf,ALPHABET,80);
889 
890 		sprintf(&tempbuf,"B:%3d",numbombs[snum]);
891 		printext(8L,(ydim - 28L),tempbuf,ALPHABET,80);
892 		sprintf(&tempbuf,"M:%3d",nummissiles[snum]);
893 		printext(8L,(ydim - 20L),tempbuf,ALPHABET,80);
894 		sprintf(&tempbuf,"G:%3d",numgrabbers[snum]);
895 		printext(8L,(ydim - 12L),tempbuf,ALPHABET,80);
896 
897 		nstatusflytime = (((flytime[snum] + 119) - lockclock) / 120);
898 		if (nstatusflytime < 0) {
899 			sprintf(&tempbuf,"FT:  0");
900 			ostatusflytime = 0;
901 		}
902 		else if (nstatusflytime > 999) {
903 			sprintf(&tempbuf,"FT:BIG");
904 			ostatusflytime = 999;
905 		}
906 		else {
907 			sprintf(&tempbuf,"FT:%3d",nstatusflytime);
908 			ostatusflytime = nstatusflytime;
909 		}
910 		printext((xdim - 56L),(ydim - 20L),tempbuf,ALPHABET,80);
911 	}
912 }
913 
prepareboard(char * daboardfilename)914 prepareboard(char *daboardfilename)
915 {
916 	short startwall, endwall, dasector;
917 	long i, j, k, s, dax, day, daz, dax2, day2;
918 
919 	getmessageleng = 0;
920 	typemessageleng = 0;
921 
922 	randomseed = 17L;
923 
924 		//Clear (do)animation's list
925 	animatecnt = 0;
926 	typemode = 0;
927 	locselectedgun = 0;
928 	locselectedgun2 = 0;
929 
930 	if (loadboard(daboardfilename,&posx[0],&posy[0],&posz[0],&ang[0],&cursectnum[0]) == -1)
931 	{
932 		musicoff();
933 		uninitmultiplayers();
934 		uninittimer();
935 		uninitkeys();
936 		uninitengine();
937 		uninitsb();
938 		uninitgroupfile();
939 		setvmode(0x3);        //Set back to text mode
940 		printf("Board not found\n");
941 		exit(0);
942 	}
943 
944 	setup3dscreen();
945 
946 	for(i=0;i<MAXPLAYERS;i++)
947 	{
948 		posx[i] = posx[0];
949 		posy[i] = posy[0];
950 		posz[i] = posz[0];
951 		ang[i] = ang[0];
952 		cursectnum[i] = cursectnum[0];
953 		ocursectnum[i] = cursectnum[0];
954 		horiz[i] = 100;
955 		lastchaingun[i] = 0;
956 		health[i] = 100;
957 		dimensionmode[i] = 3;
958 		numbombs[i] = 0;
959 		numgrabbers[i] = 0;
960 		nummissiles[i] = 0;
961 		flytime[i] = 0L;
962 		zoom[i] = 768L;
963 		deaths[i] = 0L;
964 		playersprite[i] = -1;
965 		screensize = xdim;
966 
967 		oposx[i] = posx[0];
968 		oposy[i] = posy[0];
969 		oposz[i] = posz[0];
970 		ohoriz[i] = horiz[0];
971 		ozoom[i] = zoom[0];
972 		oang[i] = ang[0];
973 	}
974 
975 	myx = omyx = posx[myconnectindex];
976 	myy = omyy = posy[myconnectindex];
977 	myz = omyz = posz[myconnectindex];
978 	myhoriz = omyhoriz = horiz[myconnectindex];
979 	myang = omyang = ang[myconnectindex];
980 	mycursectnum = cursectnum[myconnectindex];
981 	myzvel = 0;
982 
983 	movefifoplc = fakemovefifoplc = 0;
984 	syncvalhead = 0L; othersyncvalhead = 0L;
985 	syncvaltottail = 0L; syncvaltail = 0L;
986 	numinterpolations = 0;
987 
988 	clearbufbyte(&oloc,sizeof(input),0L);
989 	for(i=0;i<MAXPLAYERS;i++)
990 	{
991 		movefifoend[i] = 0;
992 		clearbufbyte(&ffsync[i],sizeof(input),0L);
993 		clearbufbyte(&sync[i],sizeof(input),0L);
994 		clearbufbyte(&osync[i],sizeof(input),0L);
995 	}
996 
997 		//Scan sector tags
998 
999 	for(i=0;i<MAXPLAYERS;i++)
1000 	{
1001 		waterfountainwall[i] = -1;
1002 		waterfountaincnt[i] = 0;
1003 	}
1004 	slimesoundcnt[i] = 0;
1005 	warpsectorcnt = 0;      //Make a list of warping sectors
1006 	xpanningsectorcnt = 0;  //Make a list of wall x-panning sectors
1007 	floorpanningcnt = 0;    //Make a list of slime sectors
1008 	dragsectorcnt = 0;      //Make a list of moving platforms
1009 	swingcnt = 0;           //Make a list of swinging doors
1010 	revolvecnt = 0;         //Make a list of revolving doors
1011 	subwaytrackcnt = 0;     //Make a list of subways
1012 
1013 	floormirrorcnt = 0;
1014 	tilesizx[FLOORMIRROR] = 0;
1015 	tilesizy[FLOORMIRROR] = 0;
1016 
1017 	for(i=0;i<numsectors;i++)
1018 	{
1019 		switch(sector[i].lotag)
1020 		{
1021 			case 4:
1022 				floorpanninglist[floorpanningcnt++] = i;
1023 				break;
1024 			case 10:
1025 				warpsectorlist[warpsectorcnt++] = i;
1026 				break;
1027 			case 11:
1028 				xpanningsectorlist[xpanningsectorcnt++] = i;
1029 				break;
1030 			case 12:
1031 				dasector = i;
1032 				dax = 0x7fffffff;
1033 				day = 0x7fffffff;
1034 				dax2 = 0x80000000;
1035 				day2 = 0x80000000;
1036 				startwall = sector[i].wallptr;
1037 				endwall = startwall+sector[i].wallnum;
1038 				for(j=startwall;j<endwall;j++)
1039 				{
1040 					if (wall[j].x < dax) dax = wall[j].x;
1041 					if (wall[j].y < day) day = wall[j].y;
1042 					if (wall[j].x > dax2) dax2 = wall[j].x;
1043 					if (wall[j].y > day2) day2 = wall[j].y;
1044 					if (wall[j].lotag == 3) k = j;
1045 				}
1046 				if (wall[k].x == dax) dragxdir[dragsectorcnt] = -16;
1047 				if (wall[k].y == day) dragydir[dragsectorcnt] = -16;
1048 				if (wall[k].x == dax2) dragxdir[dragsectorcnt] = 16;
1049 				if (wall[k].y == day2) dragydir[dragsectorcnt] = 16;
1050 
1051 				dasector = wall[startwall].nextsector;
1052 				dragx1[dragsectorcnt] = 0x7fffffff;
1053 				dragy1[dragsectorcnt] = 0x7fffffff;
1054 				dragx2[dragsectorcnt] = 0x80000000;
1055 				dragy2[dragsectorcnt] = 0x80000000;
1056 				startwall = sector[dasector].wallptr;
1057 				endwall = startwall+sector[dasector].wallnum;
1058 				for(j=startwall;j<endwall;j++)
1059 				{
1060 					if (wall[j].x < dragx1[dragsectorcnt]) dragx1[dragsectorcnt] = wall[j].x;
1061 					if (wall[j].y < dragy1[dragsectorcnt]) dragy1[dragsectorcnt] = wall[j].y;
1062 					if (wall[j].x > dragx2[dragsectorcnt]) dragx2[dragsectorcnt] = wall[j].x;
1063 					if (wall[j].y > dragy2[dragsectorcnt]) dragy2[dragsectorcnt] = wall[j].y;
1064 
1065 					setinterpolation(&sector[dasector].floorz);
1066 					setinterpolation(&wall[j].x);
1067 					setinterpolation(&wall[j].y);
1068 					setinterpolation(&wall[wall[j].nextwall].x);
1069 					setinterpolation(&wall[wall[j].nextwall].y);
1070 				}
1071 
1072 				dragx1[dragsectorcnt] += (wall[sector[i].wallptr].x-dax);
1073 				dragy1[dragsectorcnt] += (wall[sector[i].wallptr].y-day);
1074 				dragx2[dragsectorcnt] -= (dax2-wall[sector[i].wallptr].x);
1075 				dragy2[dragsectorcnt] -= (day2-wall[sector[i].wallptr].y);
1076 
1077 				dragfloorz[dragsectorcnt] = sector[i].floorz;
1078 
1079 				dragsectorlist[dragsectorcnt++] = i;
1080 				break;
1081 			case 13:
1082 				startwall = sector[i].wallptr;
1083 				endwall = startwall+sector[i].wallnum;
1084 				for(j=startwall;j<endwall;j++)
1085 				{
1086 					if (wall[j].lotag == 4)
1087 					{
1088 						k = wall[wall[wall[wall[j].point2].point2].point2].point2;
1089 						if ((wall[j].x == wall[k].x) && (wall[j].y == wall[k].y))
1090 						{     //Door opens counterclockwise
1091 							swingwall[swingcnt][0] = j;
1092 							swingwall[swingcnt][1] = wall[j].point2;
1093 							swingwall[swingcnt][2] = wall[wall[j].point2].point2;
1094 							swingwall[swingcnt][3] = wall[wall[wall[j].point2].point2].point2;
1095 							swingangopen[swingcnt] = 1536;
1096 							swingangclosed[swingcnt] = 0;
1097 							swingangopendir[swingcnt] = -1;
1098 						}
1099 						else
1100 						{     //Door opens clockwise
1101 							swingwall[swingcnt][0] = wall[j].point2;
1102 							swingwall[swingcnt][1] = j;
1103 							swingwall[swingcnt][2] = lastwall(j);
1104 							swingwall[swingcnt][3] = lastwall(swingwall[swingcnt][2]);
1105 							swingwall[swingcnt][4] = lastwall(swingwall[swingcnt][3]);
1106 							swingangopen[swingcnt] = 512;
1107 							swingangclosed[swingcnt] = 0;
1108 							swingangopendir[swingcnt] = 1;
1109 						}
1110 						for(k=0;k<4;k++)
1111 						{
1112 							swingx[swingcnt][k] = wall[swingwall[swingcnt][k]].x;
1113 							swingy[swingcnt][k] = wall[swingwall[swingcnt][k]].y;
1114 						}
1115 
1116 						swingsector[swingcnt] = i;
1117 						swingang[swingcnt] = swingangclosed[swingcnt];
1118 						swinganginc[swingcnt] = 0;
1119 						swingcnt++;
1120 					}
1121 				}
1122 				break;
1123 			case 14:
1124 				startwall = sector[i].wallptr;
1125 				endwall = startwall+sector[i].wallnum;
1126 				dax = 0L;
1127 				day = 0L;
1128 				for(j=startwall;j<endwall;j++)
1129 				{
1130 					dax += wall[j].x;
1131 					day += wall[j].y;
1132 				}
1133 				revolvepivotx[revolvecnt] = dax / (endwall-startwall);
1134 				revolvepivoty[revolvecnt] = day / (endwall-startwall);
1135 
1136 				k = 0;
1137 				for(j=startwall;j<endwall;j++)
1138 				{
1139 					revolvex[revolvecnt][k] = wall[j].x;
1140 					revolvey[revolvecnt][k] = wall[j].y;
1141 
1142 					setinterpolation(&wall[j].x);
1143 					setinterpolation(&wall[j].y);
1144 					setinterpolation(&wall[wall[j].nextwall].x);
1145 					setinterpolation(&wall[wall[j].nextwall].y);
1146 
1147 					k++;
1148 				}
1149 				revolvesector[revolvecnt] = i;
1150 				revolveang[revolvecnt] = 0;
1151 
1152 				revolvecnt++;
1153 				break;
1154 			case 15:
1155 				subwaytracksector[subwaytrackcnt][0] = i;
1156 
1157 				subwaystopcnt[subwaytrackcnt] = 0;
1158 				dax = 0x7fffffff;
1159 				day = 0x7fffffff;
1160 				dax2 = 0x80000000;
1161 				day2 = 0x80000000;
1162 				startwall = sector[i].wallptr;
1163 				endwall = startwall+sector[i].wallnum;
1164 				for(j=startwall;j<endwall;j++)
1165 				{
1166 					if (wall[j].x < dax) dax = wall[j].x;
1167 					if (wall[j].y < day) day = wall[j].y;
1168 					if (wall[j].x > dax2) dax2 = wall[j].x;
1169 					if (wall[j].y > day2) day2 = wall[j].y;
1170 				}
1171 				for(j=startwall;j<endwall;j++)
1172 				{
1173 					if (wall[j].lotag == 5)
1174 					{
1175 						if ((wall[j].x > dax) && (wall[j].y > day) && (wall[j].x < dax2) && (wall[j].y < day2))
1176 						{
1177 							subwayx[subwaytrackcnt] = wall[j].x;
1178 						}
1179 						else
1180 						{
1181 							subwaystop[subwaytrackcnt][subwaystopcnt[subwaytrackcnt]] = wall[j].x;
1182 							subwaystopcnt[subwaytrackcnt]++;
1183 						}
1184 					}
1185 				}
1186 
1187 				for(j=1;j<subwaystopcnt[subwaytrackcnt];j++)
1188 					for(k=0;k<j;k++)
1189 						if (subwaystop[subwaytrackcnt][j] < subwaystop[subwaytrackcnt][k])
1190 						{
1191 							s = subwaystop[subwaytrackcnt][j];
1192 							subwaystop[subwaytrackcnt][j] = subwaystop[subwaytrackcnt][k];
1193 							subwaystop[subwaytrackcnt][k] = s;
1194 						}
1195 
1196 				subwaygoalstop[subwaytrackcnt] = 0;
1197 				for(j=0;j<subwaystopcnt[subwaytrackcnt];j++)
1198 					if (klabs(subwaystop[subwaytrackcnt][j]-subwayx[subwaytrackcnt]) < klabs(subwaystop[subwaytrackcnt][subwaygoalstop[subwaytrackcnt]]-subwayx[subwaytrackcnt]))
1199 						subwaygoalstop[subwaytrackcnt] = j;
1200 
1201 				subwaytrackx1[subwaytrackcnt] = dax;
1202 				subwaytracky1[subwaytrackcnt] = day;
1203 				subwaytrackx2[subwaytrackcnt] = dax2;
1204 				subwaytracky2[subwaytrackcnt] = day2;
1205 
1206 				subwaynumsectors[subwaytrackcnt] = 1;
1207 				for(j=0;j<numsectors;j++)
1208 					if (j != i)
1209 					{
1210 						startwall = sector[j].wallptr;
1211 						if (wall[startwall].x > subwaytrackx1[subwaytrackcnt])
1212 							if (wall[startwall].y > subwaytracky1[subwaytrackcnt])
1213 								if (wall[startwall].x < subwaytrackx2[subwaytrackcnt])
1214 									if (wall[startwall].y < subwaytracky2[subwaytrackcnt])
1215 									{
1216 										if (sector[j].floorz != sector[i].floorz)
1217 										{
1218 											sector[j].ceilingstat |= 64;
1219 											sector[j].floorstat |= 64;
1220 										}
1221 										subwaytracksector[subwaytrackcnt][subwaynumsectors[subwaytrackcnt]] = j;
1222 										subwaynumsectors[subwaytrackcnt]++;
1223 									}
1224 					}
1225 
1226 				subwayvel[subwaytrackcnt] = 64;
1227 				subwaypausetime[subwaytrackcnt] = 720;
1228 
1229 				startwall = sector[i].wallptr;
1230 				endwall = startwall+sector[i].wallnum;
1231 				for(k=startwall;k<endwall;k++)
1232 					if (wall[k].x > subwaytrackx1[subwaytrackcnt])
1233 						if (wall[k].y > subwaytracky1[subwaytrackcnt])
1234 							if (wall[k].x < subwaytrackx2[subwaytrackcnt])
1235 								if (wall[k].y < subwaytracky2[subwaytrackcnt])
1236 									setinterpolation(&wall[k].x);
1237 
1238 				for(j=1;j<subwaynumsectors[subwaytrackcnt];j++)
1239 				{
1240 					dasector = subwaytracksector[subwaytrackcnt][j];
1241 
1242 					startwall = sector[dasector].wallptr;
1243 					endwall = startwall+sector[dasector].wallnum;
1244 					for(k=startwall;k<endwall;k++)
1245 						setinterpolation(&wall[k].x);
1246 
1247 					for(k=headspritesect[dasector];k>=0;k=nextspritesect[k])
1248 						if (statrate[sprite[k].statnum] < 0)
1249 							setinterpolation(&sprite[k].x);
1250 				}
1251 
1252 
1253 				subwaytrackcnt++;
1254 				break;
1255 		}
1256 		if (sector[i].floorpicnum == FLOORMIRROR)
1257 			floormirrorsector[mirrorcnt++] = i;
1258 	}
1259 
1260 		//Scan wall tags
1261 
1262 	mirrorcnt = 0;
1263 	tilesizx[MIRROR] = 0;
1264 	tilesizy[MIRROR] = 0;
1265 	for(i=0;i<MAXMIRRORS;i++)
1266 	{
1267 		tilesizx[i+MIRRORLABEL] = 0;
1268 		tilesizy[i+MIRRORLABEL] = 0;
1269 	}
1270 
1271 	ypanningwallcnt = 0;
1272 	for(i=0;i<numwalls;i++)
1273 	{
1274 		if (wall[i].lotag == 1) ypanningwalllist[ypanningwallcnt++] = i;
1275 		s = wall[i].nextsector;
1276 		if ((s >= 0) && (wall[i].overpicnum == MIRROR) && (wall[i].cstat&32))
1277 		{
1278 			if ((sector[s].floorstat&1) == 0)
1279 			{
1280 				wall[i].overpicnum = MIRRORLABEL+mirrorcnt;
1281 				sector[s].ceilingpicnum = MIRRORLABEL+mirrorcnt;
1282 				sector[s].floorpicnum = MIRRORLABEL+mirrorcnt;
1283 				sector[s].floorstat |= 1;
1284 				mirrorwall[mirrorcnt] = i;
1285 				mirrorsector[mirrorcnt] = s;
1286 				mirrorcnt++;
1287 			}
1288 			else
1289 				wall[i].overpicnum = sector[s].ceilingpicnum;
1290 		}
1291 	}
1292 
1293 		//Invalidate textures in sector behind mirror
1294 	for(i=0;i<mirrorcnt;i++)
1295 	{
1296 		k = mirrorsector[i];
1297 		startwall = sector[k].wallptr;
1298 		endwall = startwall + sector[k].wallnum;
1299 		for(j=startwall;j<endwall;j++)
1300 		{
1301 			wall[j].picnum = MIRROR;
1302 			wall[j].overpicnum = MIRROR;
1303 		}
1304 	}
1305 
1306 		//Scan sprite tags&picnum's
1307 
1308 	turnspritecnt = 0;
1309 	for(i=0;i<MAXSPRITES;i++)
1310 	{
1311 		if (sprite[i].lotag == 3) turnspritelist[turnspritecnt++] = i;
1312 
1313 		if (sprite[i].statnum < MAXSTATUS)    //That is, if sprite exists
1314 			switch(sprite[i].picnum)
1315 			{
1316 				case BROWNMONSTER:              //All cases here put the sprite
1317 					if ((sprite[i].cstat&128) == 0)
1318 					{
1319 						sprite[i].z -= ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
1320 						sprite[i].cstat |= 128;
1321 					}
1322 					sprite[i].extra = sprite[i].ang;
1323 					sprite[i].clipdist = mulscale7(sprite[i].xrepeat,tilesizx[sprite[i].picnum]);
1324 					if (sprite[i].statnum != 1) changespritestat(i,2);   //on waiting for you (list 2)
1325 					sprite[i].lotag = mulscale5(sprite[i].xrepeat,sprite[i].yrepeat);
1326 					sprite[i].cstat |= 0x101;    //Set the hitscan sensitivity bit
1327 					break;
1328 				case AL:
1329 					sprite[i].cstat |= 0x101;    //Set the hitscan sensitivity bit
1330 					sprite[i].lotag = 0x60;
1331 					changespritestat(i,0);
1332 					break;
1333 				case EVILAL:
1334 					sprite[i].cstat |= 0x101;    //Set the hitscan sensitivity bit
1335 					sprite[i].lotag = 0x60;
1336 					changespritestat(i,10);
1337 					break;
1338 			}
1339 	}
1340 
1341 	for(i=MAXSPRITES-1;i>=0;i--) copybuf(&sprite[i].x,&osprite[i].x,3);
1342 
1343 	searchmap(cursectnum[connecthead]);
1344 
1345 	lockclock = 0;
1346 	ototalclock = 0;
1347 	gotlastpacketclock = 0;
1348 
1349 	screensize = xdim;
1350 	dax = ((xdim-screensize)>>1);
1351 	dax2 = dax+screensize-1;
1352 	day = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1);
1353 	day2 = day + scale(screensize,ydim-32,xdim)-1;
1354 	setview(dax,day,dax2,day2);
1355 
1356 	startofdynamicinterpolations = numinterpolations;
1357 }
1358 
checktouchsprite(short snum,short sectnum)1359 checktouchsprite(short snum, short sectnum)
1360 {
1361 	long i, nexti;
1362 
1363 	if ((sectnum < 0) || (sectnum >= numsectors)) return;
1364 
1365 	for(i=headspritesect[sectnum];i>=0;i=nexti)
1366 	{
1367 		nexti = nextspritesect[i];
1368 		if (sprite[i].cstat&0x8000) continue;
1369 		if ((klabs(posx[snum]-sprite[i].x)+klabs(posy[snum]-sprite[i].y) < 512) && (klabs((posz[snum]>>8)-((sprite[i].z>>8)-(tilesizy[sprite[i].picnum]>>1))) <= 40))
1370 		{
1371 			switch(sprite[i].picnum)
1372 			{
1373 				case COIN:
1374 					wsayfollow("getstuff.wav",4096L+(krand()&127)-64,192L,&sprite[i].x,&sprite[i].y,0);
1375 					changehealth(snum,5);
1376 					if (sprite[i].statnum == 12) deletesprite((short)i);
1377 					else {
1378 						sprite[i].cstat |= 0x8000;
1379 						sprite[i].extra = 120*60;
1380 						changespritestat((short)i,11);
1381 					}
1382 					break;
1383 				case DIAMONDS:
1384 					wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1385 					changehealth(snum,15);
1386 					if (sprite[i].statnum == 12) deletesprite((short)i);
1387 					else {
1388 						sprite[i].cstat |= 0x8000;
1389 						sprite[i].extra = 120*120;
1390 						changespritestat((short)i,11);
1391 					}
1392 					break;
1393 				case COINSTACK:
1394 					wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1395 					changehealth(snum,25);
1396 					if (sprite[i].statnum == 12) deletesprite((short)i);
1397 					else {
1398 						sprite[i].cstat |= 0x8000;
1399 						sprite[i].extra = 120*180;
1400 						changespritestat((short)i,11);
1401 					}
1402 					break;
1403 				case GIFTBOX:
1404 					wsayfollow("getstuff.wav",4096L+(krand()&127)+256-mulscale4(sprite[i].xrepeat,sprite[i].yrepeat),208L,&sprite[i].x,&sprite[i].y,0);
1405 					changehealth(snum,max(mulscale8(sprite[i].xrepeat,sprite[i].yrepeat),1));
1406 					if (sprite[i].statnum == 12) deletesprite((short)i);
1407 					else {
1408 						sprite[i].cstat |= 0x8000;
1409 						sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat);
1410 						changespritestat((short)i,11);
1411 					}
1412 					break;
1413 				case CANNON:
1414 					wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1415 					if (snum == myconnectindex) keystatus[4] = 1;
1416 					changenumbombs(snum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1));
1417 					if (sprite[i].statnum == 12) deletesprite((short)i);
1418 					else {
1419 						sprite[i].cstat |= 0x8000;
1420 						sprite[i].extra = 60*(sprite[i].xrepeat+sprite[i].yrepeat);
1421 						changespritestat((short)i,11);
1422 					}
1423 					break;
1424 				case LAUNCHER:
1425 					wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1426 					if (snum == myconnectindex) keystatus[5] = 1;
1427 					changenummissiles(snum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1));
1428 					if (sprite[i].statnum == 12) deletesprite((short)i);
1429 					else {
1430 						sprite[i].cstat |= 0x8000;
1431 						sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat);
1432 						changespritestat((short)i,11);
1433 					}
1434 					break;
1435 				case GRABCANNON:
1436 					wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1437 					if (snum == myconnectindex) keystatus[6] = 1;
1438 					changenumgrabbers(snum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1));
1439 					if (sprite[i].statnum == 12) deletesprite((short)i);
1440 					else {
1441 						sprite[i].cstat |= 0x8000;
1442 						sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat);
1443 						changespritestat((short)i,11);
1444 					}
1445 					break;
1446 				case AIRPLANE:
1447 					wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1448 					if (flytime[snum] < lockclock) flytime[snum] = lockclock;
1449 					flytime[snum] += 60*(sprite[i].xrepeat+sprite[i].yrepeat);
1450 					drawstatusflytime(snum);
1451 					if (sprite[i].statnum == 12) deletesprite((short)i);
1452 					else {
1453 						sprite[i].cstat |= 0x8000;
1454 						sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat);
1455 						changespritestat((short)i,11);
1456 					}
1457 					break;
1458 			}
1459 		}
1460 	}
1461 }
1462 
checkgrabbertouchsprite(short snum,short sectnum)1463 checkgrabbertouchsprite(short snum, short sectnum)   // Andy did this
1464 {
1465 	long i, nexti;
1466 	short onum;
1467 
1468 	if ((sectnum < 0) || (sectnum >= numsectors)) return;
1469 	onum = (sprite[snum].owner & (MAXSPRITES - 1));
1470 
1471 	for(i=headspritesect[sectnum];i>=0;i=nexti)
1472 	{
1473 		nexti = nextspritesect[i];
1474 		if (sprite[i].cstat&0x8000) continue;
1475 		if ((klabs(sprite[snum].x-sprite[i].x)+klabs(sprite[snum].y-sprite[i].y) < 512) && (klabs((sprite[snum].z>>8)-((sprite[i].z>>8)-(tilesizy[sprite[i].picnum]>>1))) <= 40))
1476 		{
1477 			switch(sprite[i].picnum)
1478 			{
1479 				case COIN:
1480 					wsayfollow("getstuff.wav",4096L+(krand()&127)-64,192L,&sprite[i].x,&sprite[i].y,0);
1481 					changehealth(onum,5);
1482 					if (sprite[i].statnum == 12) deletesprite((short)i);
1483 					else {
1484 						sprite[i].cstat |= 0x8000;
1485 						sprite[i].extra = 120*60;
1486 						changespritestat((short)i,11);
1487 					}
1488 					break;
1489 				case DIAMONDS:
1490 					wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1491 					changehealth(onum,15);
1492 					if (sprite[i].statnum == 12) deletesprite((short)i);
1493 					else {
1494 						sprite[i].cstat |= 0x8000;
1495 						sprite[i].extra = 120*120;
1496 						changespritestat((short)i,11);
1497 					}
1498 					break;
1499 				case COINSTACK:
1500 					wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1501 					changehealth(onum,25);
1502 					if (sprite[i].statnum == 12) deletesprite((short)i);
1503 					else {
1504 						sprite[i].cstat |= 0x8000;
1505 						sprite[i].extra = 120*180;
1506 						changespritestat((short)i,11);
1507 					}
1508 					break;
1509 				case GIFTBOX:
1510 					wsayfollow("getstuff.wav",4096L+(krand()&127)+256-mulscale4(sprite[i].xrepeat,sprite[i].yrepeat),208L,&sprite[i].x,&sprite[i].y,0);
1511 					changehealth(onum,max(mulscale8(sprite[i].xrepeat,sprite[i].yrepeat),1));
1512 					if (sprite[i].statnum == 12) deletesprite((short)i);
1513 					else {
1514 						sprite[i].cstat |= 0x8000;
1515 						sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat);
1516 						changespritestat((short)i,11);
1517 					}
1518 					break;
1519 				case CANNON:
1520 					wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1521 					if (onum == myconnectindex) keystatus[4] = 1;
1522 					changenumbombs(onum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1));
1523 					if (sprite[i].statnum == 12) deletesprite((short)i);
1524 					else {
1525 						sprite[i].cstat |= 0x8000;
1526 						sprite[i].extra = 60*(sprite[i].xrepeat+sprite[i].yrepeat);
1527 						changespritestat((short)i,11);
1528 					}
1529 					break;
1530 				case LAUNCHER:
1531 					wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1532 					if (onum == myconnectindex) keystatus[5] = 1;
1533 					changenummissiles(onum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1));
1534 					if (sprite[i].statnum == 12) deletesprite((short)i);
1535 					else {
1536 						sprite[i].cstat |= 0x8000;
1537 						sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat);
1538 						changespritestat((short)i,11);
1539 					}
1540 					break;
1541 				case GRABCANNON:
1542 					wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1543 					if (onum == myconnectindex) keystatus[6] = 1;
1544 					changenumgrabbers(onum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1));
1545 					if (sprite[i].statnum == 12) deletesprite((short)i);
1546 					else {
1547 						sprite[i].cstat |= 0x8000;
1548 						sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat);
1549 						changespritestat((short)i,11);
1550 					}
1551 					break;
1552 				case AIRPLANE:
1553 					wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1554 					if (flytime[snum] < lockclock) flytime[snum] = lockclock;
1555 					flytime[onum] += 60*(sprite[i].xrepeat+sprite[i].yrepeat);
1556 					drawstatusflytime(onum);
1557 					if (sprite[i].statnum == 12) deletesprite((short)i);
1558 					else {
1559 						sprite[i].cstat |= 0x8000;
1560 						sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat);
1561 						changespritestat((short)i,11);
1562 					}
1563 					break;
1564 			}
1565 		}
1566 	}
1567 }
1568 
shootgun(short snum,long x,long y,long z,short daang,long dahoriz,short dasectnum,char guntype)1569 shootgun(short snum, long x, long y, long z,
1570 			short daang, long dahoriz, short dasectnum, char guntype)
1571 {
1572 	short hitsect, hitwall, hitsprite, daang2;
1573 	long i, j, daz2, hitx, hity, hitz;
1574 
1575 	switch(guntype)
1576 	{
1577 		case 0:    //Shoot chain gun
1578 			daang2 = ((daang + (krand()&31)-16)&2047);
1579 			daz2 = ((100-dahoriz)*2000) + ((krand()-32768)>>1);
1580 
1581 			hitscan(x,y,z,dasectnum,                   //Start position
1582 				sintable[(daang2+512)&2047],            //X vector of 3D ang
1583 				sintable[daang2&2047],                  //Y vector of 3D ang
1584 				daz2,                                   //Z vector of 3D ang
1585 				&hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1);
1586 
1587 			if (wall[hitwall].picnum == KENPICTURE)
1588 			{
1589 				if (waloff[MAXTILES-1] != 0) wall[hitwall].picnum = MAXTILES-1;
1590 				wsayfollow("hello.wav",4096L+(krand()&127)-64,256L,&wall[hitwall].x,&wall[hitwall].y,0);
1591 			}
1592 			else if (((hitwall < 0) && (hitsprite < 0) && (hitz >= z) && ((sector[hitsect].floorpicnum == SLIME) || (sector[hitsect].floorpicnum == FLOORMIRROR))) || ((hitwall >= 0) && (wall[hitwall].picnum == SLIME)))
1593 			{    //If you shoot slime, make a splash
1594 				wsayfollow("splash.wav",4096L+(krand()&511)-256,256L,&hitx,&hity,0);
1595 				spawnsprite(j,hitx,hity,hitz,2,0,0,32,64,64,0,0,SPLASH,daang,
1596 					0,0,0,snum+4096,hitsect,4,63,0,0); //63=time left for splash
1597 			}
1598 			else
1599 			{
1600 				wsayfollow("shoot.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0);
1601 
1602 				if ((hitsprite >= 0) && (sprite[hitsprite].statnum < MAXSTATUS))
1603 					switch(sprite[hitsprite].picnum)
1604 					{
1605 						case BROWNMONSTER:
1606 							if (sprite[hitsprite].lotag > 0) sprite[hitsprite].lotag -= 10;
1607 							if (sprite[hitsprite].lotag > 0)
1608 							{
1609 								wsayfollow("hurt.wav",4096L+(krand()&511)-256,256L,&hitx,&hity,0);
1610 								if (sprite[hitsprite].lotag <= 25)
1611 									sprite[hitsprite].cstat |= 2;
1612 							}
1613 							else
1614 							{
1615 								wsayfollow("mondie.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0);
1616 								sprite[hitsprite].z += ((tilesizy[sprite[hitsprite].picnum]*sprite[hitsprite].yrepeat)<<1);
1617 								sprite[hitsprite].picnum = GIFTBOX;
1618 								sprite[hitsprite].cstat &= ~0x83;    //Should not clip, foot-z
1619 								changespritestat(hitsprite,12);
1620 
1621 								spawnsprite(j,hitx,hity,hitz+(32<<8),0,-4,0,32,64,64,
1622 									0,0,EXPLOSION,daang,0,0,0,snum+4096,
1623 									hitsect,5,31,0,0);
1624 							}
1625 							break;
1626 						case EVILAL:
1627 							wsayfollow("blowup.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0);
1628 							sprite[hitsprite].picnum = EVILALGRAVE;
1629 							sprite[hitsprite].cstat = 0;
1630 							sprite[hitsprite].xvel = (krand()&255)-128;
1631 							sprite[hitsprite].yvel = (krand()&255)-128;
1632 							sprite[hitsprite].zvel = (krand()&4095)-3072;
1633 							changespritestat(hitsprite,9);
1634 
1635 							spawnsprite(j,hitx,hity,hitz+(32<<8),0,-4,0,32,64,64,0,
1636 								0,EXPLOSION,daang,0,0,0,snum+4096,hitsect,5,31,0,0);
1637 								 //31=time left for explosion
1638 
1639 							break;
1640 						case PLAYER:
1641 							for(j=connecthead;j>=0;j=connectpoint2[j])
1642 								if (playersprite[j] == hitsprite)
1643 								{
1644 									wsayfollow("ouch.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0);
1645 									changehealth(j,-10);
1646 									break;
1647 								}
1648 							break;
1649 					}
1650 
1651 				spawnsprite(j,hitx,hity,hitz+(8<<8),2,-4,0,32,16,16,0,0,
1652 					EXPLOSION,daang,0,0,0,snum+4096,hitsect,3,63,0,0);
1653 
1654 					//Sprite starts out with center exactly on wall.
1655 					//This moves it back enough to see it at all angles.
1656 				movesprite((short)j,-(((long)sintable[(512+daang)&2047]*TICSPERFRAME)<<4),-(((long)sintable[daang]*TICSPERFRAME)<<4),0L,4L<<8,4L<<8,CLIPMASK1);
1657 			}
1658 			break;
1659 		case 1:    //Shoot silver sphere bullet
1660 			spawnsprite(j,x,y,z,1+128,0,0,16,64,64,0,0,BULLET,daang,
1661 						  sintable[(daang+512)&2047]>>5,sintable[daang&2047]>>5,
1662 						  (100-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0);
1663 			wsayfollow("shoot2.wav",4096L+(krand()&127)-64,128L,&sprite[j].x,&sprite[j].y,1);
1664 			break;
1665 		case 2:    //Shoot bomb
1666 		  spawnsprite(j,x,y,z,128,0,0,12,16,16,0,0,BOMB,daang,
1667 			  sintable[(daang+512)&2047]*5>>8,sintable[daang&2047]*5>>8,
1668 			  (80-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0);
1669 			wsayfollow("shoot3.wav",4096L+(krand()&127)-64,192L,&sprite[j].x,&sprite[j].y,1);
1670 			break;
1671 		case 3:    //Shoot missile (Andy did this)
1672 			spawnsprite(j,x,y,z,1+128,0,0,16,32,32,0,0,MISSILE,daang,
1673 						  sintable[(daang+512)&2047]>>4,sintable[daang&2047]>>4,
1674 						  (100-dahoriz)<<7,snum+4096,dasectnum,6,0,0,0);
1675 			wsayfollow("shoot3.wav",4096L+(krand()&127)-64,192L,&sprite[j].x,&sprite[j].y,1);
1676 			break;
1677 		case 4:    //Shoot grabber (Andy did this)
1678 			spawnsprite(j,x,y,z,1+128,0,0,16,64,64,0,0,GRABBER,daang,
1679 						  sintable[(daang+512)&2047]>>5,sintable[daang&2047]>>5,
1680 						  (100-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0);
1681 			wsayfollow("shoot4.wav",4096L+(krand()&127)-64,128L,&sprite[j].x,&sprite[j].y,1);
1682 			break;
1683 	}
1684 }
1685 
1686 #define MAXVOXMIPS 5
1687 extern char *voxoff[][MAXVOXMIPS];
analyzesprites(long dax,long day)1688 analyzesprites(long dax, long day)
1689 {
1690 	long i, j, k, *longptr;
1691 	point3d *ospr;
1692 	spritetype *tspr;
1693 
1694 		//This function is called between drawrooms() and drawmasks()
1695 		//It has a list of possible sprites that may be drawn on this frame
1696 
1697 	for(i=0,tspr=&tsprite[0];i<spritesortcnt;i++,tspr++)
1698 	{
1699 		switch(tspr->picnum)
1700 		{
1701 			case PLAYER:
1702 				//   //Get which of the 8 angles of the sprite to draw (0-7)
1703 				//   //k ranges from 0-7
1704 				//k = getangle(tspr->x-dax,tspr->y-day);
1705 				//k = (((tspr->ang+3072+128-k)&2047)>>8)&7;
1706 				//   //This guy has only 5 pictures for 8 angles (3 are x-flipped)
1707 				//if (k <= 4)
1708 				//{
1709 				//   tspr->picnum += (k<<2);
1710 				//   tspr->cstat &= ~4;   //clear x-flipping bit
1711 				//}
1712 				//else
1713 				//{
1714 				//   tspr->picnum += ((8-k)<<2);
1715 				//   tspr->cstat |= 4;    //set x-flipping bit
1716 				//}
1717 
1718 				if ((tspr->cstat&2) == 0)
1719 				{
1720 					tspr->cstat |= 48;
1721 					longptr = (long *)voxoff[0][0];
1722 					tspr->xrepeat = scale(tspr->xrepeat,56,longptr[2]);
1723 					tspr->yrepeat = scale(tspr->yrepeat,56,longptr[2]);
1724 					tspr->picnum = 0;
1725 					tspr->shade -= 6;
1726 				}
1727 				break;
1728 			case BROWNMONSTER:
1729 				tspr->cstat |= 48;
1730 				tspr->picnum = 1;
1731 				break;
1732 		}
1733 
1734 		k = statrate[tspr->statnum];
1735 		if (k >= 0)  //Interpolate moving sprite
1736 		{
1737 			ospr = &osprite[tspr->owner];
1738 			switch(k)
1739 			{
1740 				case 0: j = smoothratio; break;
1741 				case 1: j = (smoothratio>>1)+(((nummoves-tspr->owner)&1)<<15); break;
1742 				case 3: j = (smoothratio>>2)+(((nummoves-tspr->owner)&3)<<14); break;
1743 				case 7: j = (smoothratio>>3)+(((nummoves-tspr->owner)&7)<<13); break;
1744 				case 15: j = (smoothratio>>4)+(((nummoves-tspr->owner)&15)<<12); break;
1745 			}
1746 			k = tspr->x-ospr->x; tspr->x = ospr->x;
1747 			if (k != 0) tspr->x += mulscale16(k,j);
1748 			k = tspr->y-ospr->y; tspr->y = ospr->y;
1749 			if (k != 0) tspr->y += mulscale16(k,j);
1750 			k = tspr->z-ospr->z; tspr->z = ospr->z;
1751 			if (k != 0) tspr->z += mulscale16(k,j);
1752 		}
1753 
1754 			//Don't allow close explosion sprites to be transluscent
1755 		k = tspr->statnum;
1756 		if ((k == 3) || (k == 4) || (k == 5) || (k == 7))
1757 			if (klabs(dax-tspr->x) < 256)
1758 				if (klabs(day-tspr->y) < 256)
1759 					tspr->cstat &= ~2;
1760 
1761 		tspr->shade += 6;
1762 		if (sector[tspr->sectnum].ceilingstat&1)
1763 			tspr->shade += sector[tspr->sectnum].ceilingshade;
1764 		else
1765 			tspr->shade += sector[tspr->sectnum].floorshade;
1766 	}
1767 }
1768 
tagcode()1769 tagcode()
1770 {
1771 	long i, nexti, j, k, l, s, dax, day, daz, dax2, day2, cnt, good;
1772 	short startwall, endwall, dasector, p, oldang;
1773 
1774 	for(p=connecthead;p>=0;p=connectpoint2[p])
1775 	{
1776 		if (sector[cursectnum[p]].lotag == 1)
1777 		{
1778 			activatehitag(sector[cursectnum[p]].hitag);
1779 			sector[cursectnum[p]].lotag = 0;
1780 			sector[cursectnum[p]].hitag = 0;
1781 		}
1782 		if ((sector[cursectnum[p]].lotag == 2) && (cursectnum[p] != ocursectnum[p]))
1783 			activatehitag(sector[cursectnum[p]].hitag);
1784 	}
1785 
1786 	for(i=0;i<warpsectorcnt;i++)
1787 	{
1788 		dasector = warpsectorlist[i];
1789 		j = ((lockclock&127)>>2);
1790 		if (j >= 16) j = 31-j;
1791 		{
1792 			sector[dasector].ceilingshade = j;
1793 			sector[dasector].floorshade = j;
1794 			startwall = sector[dasector].wallptr;
1795 			endwall = startwall+sector[dasector].wallnum;
1796 			for(s=startwall;s<endwall;s++)
1797 				wall[s].shade = j;
1798 		}
1799 	}
1800 
1801 	for(p=connecthead;p>=0;p=connectpoint2[p])
1802 		if (sector[cursectnum[p]].lotag == 10)  //warp sector
1803 		{
1804 			if (cursectnum[p] != ocursectnum[p])
1805 			{
1806 				warpsprite(playersprite[p]);
1807 				posx[p] = sprite[playersprite[p]].x;
1808 				posy[p] = sprite[playersprite[p]].y;
1809 				posz[p] = sprite[playersprite[p]].z;
1810 				ang[p] = sprite[playersprite[p]].ang;
1811 				cursectnum[p] = sprite[playersprite[p]].sectnum;
1812 
1813 				sprite[playersprite[p]].z += EYEHEIGHT;
1814 
1815 				//warp(&posx[p],&posy[p],&posz[p],&ang[p],&cursectnum[p]);
1816 					//Update sprite representation of player
1817 				//setsprite(playersprite[p],posx[p],posy[p],posz[p]+EYEHEIGHT);
1818 				//sprite[playersprite[p]].ang = ang[p];
1819 			}
1820 		}
1821 
1822 	for(i=0;i<xpanningsectorcnt;i++)   //animate wall x-panning sectors
1823 	{
1824 		dasector = xpanningsectorlist[i];
1825 
1826 		startwall = sector[dasector].wallptr;
1827 		endwall = startwall+sector[dasector].wallnum;
1828 		for(s=startwall;s<endwall;s++)
1829 			wall[s].xpanning = ((lockclock>>2)&255);
1830 	}
1831 
1832 	for(i=0;i<ypanningwallcnt;i++)
1833 		wall[ypanningwalllist[i]].ypanning = ~(lockclock&255);
1834 
1835 	for(i=0;i<turnspritecnt;i++)
1836 	{
1837 		sprite[turnspritelist[i]].ang += (TICSPERFRAME<<2);
1838 		sprite[turnspritelist[i]].ang &= 2047;
1839 	}
1840 
1841 	for(i=0;i<floorpanningcnt;i++)   //animate floor of slime sectors
1842 	{
1843 		sector[floorpanninglist[i]].floorxpanning = ((lockclock>>2)&255);
1844 		sector[floorpanninglist[i]].floorypanning = ((lockclock>>2)&255);
1845 	}
1846 
1847 	for(i=0;i<dragsectorcnt;i++)
1848 	{
1849 		dasector = dragsectorlist[i];
1850 
1851 		startwall = sector[dasector].wallptr;
1852 		endwall = startwall+sector[dasector].wallnum;
1853 
1854 		if (wall[startwall].x+dragxdir[i] < dragx1[i]) dragxdir[i] = 16;
1855 		if (wall[startwall].y+dragydir[i] < dragy1[i]) dragydir[i] = 16;
1856 		if (wall[startwall].x+dragxdir[i] > dragx2[i]) dragxdir[i] = -16;
1857 		if (wall[startwall].y+dragydir[i] > dragy2[i]) dragydir[i] = -16;
1858 
1859 		for(j=startwall;j<endwall;j++)
1860 			dragpoint(j,wall[j].x+dragxdir[i],wall[j].y+dragydir[i]);
1861 		j = sector[dasector].floorz;
1862 		sector[dasector].floorz = dragfloorz[i]+(sintable[(lockclock<<4)&2047]>>3);
1863 
1864 		for(p=connecthead;p>=0;p=connectpoint2[p])
1865 			if (cursectnum[p] == dasector)
1866 			{
1867 				posx[p] += dragxdir[i];
1868 				posy[p] += dragydir[i];
1869 				if (p == myconnectindex)
1870 					{ myx += dragxdir[i]; myy += dragydir[i]; }
1871 				//posz[p] += (sector[dasector].floorz-j);
1872 
1873 					//Update sprite representation of player
1874 				setsprite(playersprite[p],posx[p],posy[p],posz[p]+EYEHEIGHT);
1875 				sprite[playersprite[p]].ang = ang[p];
1876 			}
1877 	}
1878 
1879 	for(i=0;i<swingcnt;i++)
1880 	{
1881 		if (swinganginc[i] != 0)
1882 		{
1883 			oldang = swingang[i];
1884 			for(j=0;j<(TICSPERFRAME<<2);j++)
1885 			{
1886 				swingang[i] = ((swingang[i]+swinganginc[i])&2047);
1887 				if (swingang[i] == swingangclosed[i])
1888 				{
1889 					wsayfollow("closdoor.wav",4096L+(krand()&511)-256,256L,&swingx[i][0],&swingy[i][0],0);
1890 					swinganginc[i] = 0;
1891 				}
1892 				if (swingang[i] == swingangopen[i]) swinganginc[i] = 0;
1893 			}
1894 			for(k=1;k<=3;k++)
1895 				rotatepoint(swingx[i][0],swingy[i][0],swingx[i][k],swingy[i][k],swingang[i],&wall[swingwall[i][k]].x,&wall[swingwall[i][k]].y);
1896 
1897 			if (swinganginc[i] != 0)
1898 			{
1899 				for(p=connecthead;p>=0;p=connectpoint2[p])
1900 					if ((cursectnum[p] == swingsector[i]) || (testneighborsectors(cursectnum[p],swingsector[i]) == 1))
1901 					{
1902 						cnt = 256;
1903 						do
1904 						{
1905 							good = 1;
1906 
1907 								//swingangopendir is -1 if forwards, 1 is backwards
1908 							l = (swingangopendir[i] > 0);
1909 							for(k=l+3;k>=l;k--)
1910 								if (clipinsidebox(posx[p],posy[p],swingwall[i][k],128L) != 0)
1911 								{
1912 									good = 0;
1913 									break;
1914 								}
1915 							if (good == 0)
1916 							{
1917 								if (cnt == 256)
1918 								{
1919 									swinganginc[i] = -swinganginc[i];
1920 									swingang[i] = oldang;
1921 								}
1922 								else
1923 								{
1924 									swingang[i] = ((swingang[i]-swinganginc[i])&2047);
1925 								}
1926 								for(k=1;k<=3;k++)
1927 									rotatepoint(swingx[i][0],swingy[i][0],swingx[i][k],swingy[i][k],swingang[i],&wall[swingwall[i][k]].x,&wall[swingwall[i][k]].y);
1928 								if (swingang[i] == swingangclosed[i])
1929 								{
1930 									wsayfollow("closdoor.wav",4096L+(krand()&511)-256,256L,&swingx[i][0],&swingy[i][0],0);
1931 									swinganginc[i] = 0;
1932 									break;
1933 								}
1934 								if (swingang[i] == swingangopen[i])
1935 								{
1936 									swinganginc[i] = 0;
1937 									break;
1938 								}
1939 								cnt--;
1940 							}
1941 						} while ((good == 0) && (cnt > 0));
1942 					}
1943 			}
1944 		}
1945 		if (swinganginc[i] == 0)
1946 			for(j=1;j<=3;j++)
1947 			{
1948 				stopinterpolation(&wall[swingwall[i][j]].x);
1949 				stopinterpolation(&wall[swingwall[i][j]].y);
1950 			}
1951 	}
1952 
1953 	for(i=0;i<revolvecnt;i++)
1954 	{
1955 		startwall = sector[revolvesector[i]].wallptr;
1956 		endwall = startwall + sector[revolvesector[i]].wallnum;
1957 
1958 		revolveang[i] = ((revolveang[i]-(TICSPERFRAME<<2))&2047);
1959 		for(k=startwall;k<endwall;k++)
1960 		{
1961 			rotatepoint(revolvepivotx[i],revolvepivoty[i],revolvex[i][k-startwall],revolvey[i][k-startwall],revolveang[i],&dax,&day);
1962 			dragpoint(k,dax,day);
1963 		}
1964 	}
1965 
1966 	for(i=0;i<subwaytrackcnt;i++)
1967 	{
1968 		if ((subwayvel[i] < -2) || (subwayvel[i] > 2))
1969 		{
1970 			dasector = subwaytracksector[i][0];
1971 			startwall = sector[dasector].wallptr;
1972 			endwall = startwall+sector[dasector].wallnum;
1973 			for(k=startwall;k<endwall;k++)
1974 				if (wall[k].x > subwaytrackx1[i])
1975 					if (wall[k].y > subwaytracky1[i])
1976 						if (wall[k].x < subwaytrackx2[i])
1977 							if (wall[k].y < subwaytracky2[i])
1978 								wall[k].x += subwayvel[i];
1979 
1980 			for(j=1;j<subwaynumsectors[i];j++)
1981 			{
1982 				dasector = subwaytracksector[i][j];
1983 
1984 				startwall = sector[dasector].wallptr;
1985 				endwall = startwall+sector[dasector].wallnum;
1986 				for(k=startwall;k<endwall;k++)
1987 					wall[k].x += subwayvel[i];
1988 
1989 				for(s=headspritesect[dasector];s>=0;s=nextspritesect[s])
1990 					sprite[s].x += subwayvel[i];
1991 			}
1992 
1993 			for(p=connecthead;p>=0;p=connectpoint2[p])
1994 				if (cursectnum[p] != subwaytracksector[i][0])
1995 					if (sector[cursectnum[p]].floorz != sector[subwaytracksector[i][0]].floorz)
1996 						if (posx[p] > subwaytrackx1[i])
1997 							if (posy[p] > subwaytracky1[i])
1998 								if (posx[p] < subwaytrackx2[i])
1999 									if (posy[p] < subwaytracky2[i])
2000 									{
2001 										posx[p] += subwayvel[i];
2002 										if (p == myconnectindex)
2003 											{ myx += subwayvel[i]; }
2004 
2005 											//Update sprite representation of player
2006 										setsprite(playersprite[p],posx[p],posy[p],posz[p]+EYEHEIGHT);
2007 										sprite[playersprite[p]].ang = ang[p];
2008 									}
2009 
2010 			subwayx[i] += subwayvel[i];
2011 		}
2012 
2013 		j = subwayvel[i];
2014 		k = subwaystop[i][subwaygoalstop[i]] - subwayx[i];
2015 		if (k > 0)
2016 		{
2017 			if (k > 4096)
2018 			{
2019 				if (subwayvel[i] < 256) subwayvel[i]++;
2020 			}
2021 			else
2022 				subwayvel[i] = (k>>4)+1;
2023 		}
2024 		else if (k < 0)
2025 		{
2026 			if (k < -4096)
2027 			{
2028 				if (subwayvel[i] > -256) subwayvel[i]--;
2029 			}
2030 			else
2031 				subwayvel[i] = (k>>4)-1;
2032 		}
2033 		if ((j < 0) && (subwayvel[i] >= 0)) subwayvel[i] = -1;
2034 		if ((j > 0) && (subwayvel[i] <= 0)) subwayvel[i] = 1;
2035 
2036 		if ((subwayvel[i] <= 2) && (subwayvel[i] >= -2) && (klabs(k) < 2048))
2037 		{
2038 			  //Open / close doors
2039 			if ((subwaypausetime[i] == 720) || ((subwaypausetime[i] >= 120) && (subwaypausetime[i]-TICSPERFRAME < 120)))
2040 				activatehitag(sector[subwaytracksector[i][0]].hitag);
2041 
2042 			subwaypausetime[i] -= TICSPERFRAME;
2043 			if (subwaypausetime[i] < 0)
2044 			{
2045 				subwaypausetime[i] = 720;
2046 				if (subwayvel[i] < 0)
2047 				{
2048 					subwaygoalstop[i]--;
2049 					if (subwaygoalstop[i] < 0)
2050 					{
2051 						subwaygoalstop[i] = 1;
2052 						subwayvel[i] = 1;
2053 					}
2054 				}
2055 				else if (subwayvel[i] > 0)
2056 				{
2057 					subwaygoalstop[i]++;
2058 					if (subwaygoalstop[i] >= subwaystopcnt[i])
2059 					{
2060 						subwaygoalstop[i] = subwaystopcnt[i]-2;
2061 						subwayvel[i] = -1;
2062 					}
2063 				}
2064 			}
2065 		}
2066 	}
2067 }
2068 
statuslistcode()2069 statuslistcode()
2070 {
2071 	short p, target, hitobject, daang, osectnum, movestat;
2072 	long i, nexti, j, nextj, k, l, dax, day, daz, dist, ox, oy, mindist;
2073 	long doubvel, xvect, yvect;
2074 
2075 		//Go through active BROWNMONSTER list
2076 	for(i=headspritestat[1];i>=0;i=nexti)
2077 	{
2078 		nexti = nextspritestat[i];
2079 
2080 		k = krand();
2081 
2082 			//Choose a target player
2083 		mindist = 0x7fffffff; target = connecthead;
2084 		for(p=connecthead;p>=0;p=connectpoint2[p])
2085 		{
2086 			dist = klabs(sprite[i].x-posx[p])+klabs(sprite[i].y-posy[p]);
2087 			if (dist < mindist) mindist = dist, target = p;
2088 		}
2089 
2090 			//brown monster decides to shoot bullet
2091 		if ((k&63) == 23)
2092 		{
2093 			if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[target],posy[target],posz[target],cursectnum[target]) == 0)
2094 			{
2095 				if ((k&0xf00) == 0xb00) changespritestat(i,2);
2096 			}
2097 			else
2098 			{
2099 				wsayfollow("monshoot.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1);
2100 
2101 				doubvel = (TICSPERFRAME<<((sync[target].bits&256)>0));
2102 				xvect = 0, yvect = 0;
2103 				if (sync[target].fvel != 0)
2104 				{
2105 					xvect += ((((long)sync[target].fvel)*doubvel*(long)sintable[(ang[target]+512)&2047])>>3);
2106 					yvect += ((((long)sync[target].fvel)*doubvel*(long)sintable[ang[target]&2047])>>3);
2107 				}
2108 				if (sync[target].svel != 0)
2109 				{
2110 					xvect += ((((long)sync[target].svel)*doubvel*(long)sintable[ang[target]&2047])>>3);
2111 					yvect += ((((long)sync[target].svel)*doubvel*(long)sintable[(ang[target]+1536)&2047])>>3);
2112 				}
2113 
2114 				ox = posx[target]; oy = posy[target];
2115 
2116 					//distance is j
2117 				j = ksqrt((ox-sprite[i].x)*(ox-sprite[i].x)+(oy-sprite[i].y)*(oy-sprite[i].y));
2118 
2119 				switch((sprite[i].extra>>11)&3)
2120 				{
2121 					case 1: j = -(j>>1); break;
2122 					case 3: j = 0; break;
2123 					case 0: case 2: break;
2124 				}
2125 				sprite[i].extra += 2048;
2126 
2127 					//rate is (TICSPERFRAME<<19)
2128 				xvect = scale(xvect,j,TICSPERFRAME<<19);
2129 				yvect = scale(yvect,j,TICSPERFRAME<<19);
2130 				clipmove(&ox,&oy,&posz[target],&cursectnum[target],xvect<<14,yvect<<14,128L,4<<8,4<<8,CLIPMASK0);
2131 				ox -= sprite[i].x;
2132 				oy -= sprite[i].y;
2133 
2134 				daang = ((getangle(ox,oy)+(krand()&7)-4)&2047);
2135 
2136 				dax = (sintable[(daang+512)&2047]>>6);
2137 				day = (sintable[daang&2047]>>6);
2138 				daz = 0;
2139 				if (ox != 0)
2140 					daz = scale(dax,posz[target]+(8<<8)-sprite[i].z,ox);
2141 				else if (oy != 0)
2142 					daz = scale(day,posz[target]+(8<<8)-sprite[i].z,oy);
2143 
2144 				spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,128,0,0,
2145 					16,sprite[i].xrepeat,sprite[i].yrepeat,0,0,BULLET,daang,dax,day,daz,i,sprite[i].sectnum,6,0,0,0);
2146 
2147 				sprite[i].extra &= (~2047);
2148 			}
2149 		}
2150 
2151 			//Move brown monster
2152 		dax = sprite[i].x;   //Back up old x&y if stepping off cliff
2153 		day = sprite[i].y;
2154 
2155 		doubvel = max(mulscale7(sprite[i].xrepeat,sprite[i].yrepeat),4);
2156 
2157 		osectnum = sprite[i].sectnum;
2158 		movestat = movesprite((short)i,(long)sintable[(sprite[i].ang+512)&2047]*doubvel,(long)sintable[sprite[i].ang]*doubvel,0L,4L<<8,4L<<8,CLIPMASK0);
2159 		if (globloz > sprite[i].z+(48<<8))
2160 			{ sprite[i].x = dax; sprite[i].y = day; movestat = 1; }
2161 		else
2162 			sprite[i].z = globloz-((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
2163 
2164 		if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10))
2165 			{ warpsprite((short)i); movestat = 0; }
2166 
2167 		if ((movestat != 0) || ((k&63) == 1))
2168 		{
2169 			if (sprite[i].ang == (sprite[i].extra&2047))
2170 			{
2171 				daang = (getangle(posx[target]-sprite[i].x,posy[target]-sprite[i].y)&2047);
2172 				daang = ((daang+(krand()&1023)-512)&2047);
2173 				sprite[i].extra = ((sprite[i].extra&(~2047))|daang);
2174 			}
2175 			if ((sprite[i].extra-sprite[i].ang)&1024)
2176 			{
2177 				sprite[i].ang = ((sprite[i].ang-32)&2047);
2178 				if (!((sprite[i].extra-sprite[i].ang)&1024)) sprite[i].ang = (sprite[i].extra&2047);
2179 			}
2180 			else
2181 			{
2182 				sprite[i].ang = ((sprite[i].ang+32)&2047);
2183 				if (((sprite[i].extra-sprite[i].ang)&1024)) sprite[i].ang = (sprite[i].extra&2047);
2184 			}
2185 		}
2186 	}
2187 
2188 	for(i=headspritestat[10];i>=0;i=nexti)  //EVILAL list
2189 	{
2190 		nexti = nextspritestat[i];
2191 
2192 		if (sprite[i].yrepeat < 38) continue;
2193 		if (sprite[i].yrepeat < 64)
2194 		{
2195 			sprite[i].xrepeat++;
2196 			sprite[i].yrepeat++;
2197 			continue;
2198 		}
2199 
2200 		if ((nummoves-i)&statrate[10]) continue;
2201 
2202 			//Choose a target player
2203 		mindist = 0x7fffffff; target = connecthead;
2204 		for(p=connecthead;p>=0;p=connectpoint2[p])
2205 		{
2206 			dist = klabs(sprite[i].x-posx[p])+klabs(sprite[i].y-posy[p]);
2207 			if (dist < mindist) mindist = dist, target = p;
2208 		}
2209 
2210 		k = (krand()&255);
2211 
2212 		if ((sprite[i].lotag&32) && (k < 48))  //Al decides to reproduce
2213 		{
2214 			l = 0;
2215 			if ((sprite[i].lotag&64) && (k < 2))  //Give him a chance to reproduce without seeing you
2216 				l = 1;
2217 			else if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[target],posy[target],posz[target],cursectnum[target]) == 1)
2218 				l = 1;
2219 			if (l != 0)
2220 			{
2221 				spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].cstat,sprite[i].shade,sprite[i].pal,
2222 					sprite[i].clipdist,38,38,sprite[i].xoffset,sprite[i].yoffset,sprite[i].picnum,krand()&2047,0,0,0,i,
2223 					sprite[i].sectnum,10,sprite[i].lotag,sprite[i].hitag,sprite[i].extra);
2224 				switch(krand()&31)  //Mutations!
2225 				{
2226 					case 0: sprite[i].cstat ^= 2; break;
2227 					case 1: sprite[i].cstat ^= 512; break;
2228 					case 2: sprite[i].shade++; break;
2229 					case 3: sprite[i].shade--; break;
2230 					case 4: sprite[i].pal ^= 16; break;
2231 					case 5: case 6: case 7: sprite[i].lotag ^= (1<<(krand()&7)); break;
2232 					case 8: sprite[i].lotag = (krand()&255); break;
2233 				}
2234 			}
2235 		}
2236 		if (k >= 208+((sprite[i].lotag&128)>>2))    //Al decides to shoot bullet
2237 		{
2238 			if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[target],posy[target],posz[target],cursectnum[target]) == 1)
2239 			{
2240 				wsayfollow("zipguns.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1);
2241 
2242 				spawnsprite(j,sprite[i].x,sprite[i].y,
2243 					sector[sprite[i].sectnum].floorz-(24<<8),
2244 					0,0,0,16,32,32,0,0,BULLET,
2245 					(getangle(posx[target]-sprite[j].x,
2246 						posy[target]-sprite[j].y)+(krand()&15)-8)&2047,
2247 					sintable[(sprite[j].ang+512)&2047]>>6,
2248 					sintable[sprite[j].ang&2047]>>6,
2249 					((posz[target]+(8<<8)-sprite[j].z)<<8) /
2250 					  (ksqrt((posx[target]-sprite[j].x) *
2251 								(posx[target]-sprite[j].x) +
2252 								(posy[target]-sprite[j].y) *
2253 								(posy[target]-sprite[j].y))+1),
2254 								i,sprite[i].sectnum,6,0,0,0);
2255 			}
2256 		}
2257 
2258 			//Move Al
2259 		l = (((sprite[i].lotag&3)+2)<<8);
2260 		if (sprite[i].lotag&4) l = -l;
2261 		dax = sintable[(sprite[i].ang+512)&2047]*l;
2262 		day = sintable[sprite[i].ang]*l;
2263 
2264 		osectnum = sprite[i].sectnum;
2265 		movestat = movesprite((short)i,dax,day,0L,-8L<<8,-8L<<8,CLIPMASK0);
2266 		sprite[i].z = globloz;
2267 		if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10))
2268 		{
2269 			warpsprite((short)i);
2270 			movestat = 0;
2271 		}
2272 
2273 		if (sprite[i].lotag&16)
2274 		{
2275 			if (((k&124) >= 120) && (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[target],posy[target],posz[target],cursectnum[target]) == 1))
2276 				sprite[i].ang = getangle(posx[target]-sprite[i].x,posy[target]-sprite[i].y);
2277 			else
2278 				sprite[i].ang = (krand()&2047);
2279 		}
2280 
2281 		if (movestat != 0)
2282 		{
2283 			if ((k&2) && (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[target],posy[target],posz[target],cursectnum[target]) == 1))
2284 				sprite[i].ang = getangle(posx[target]-sprite[i].x,posy[target]-sprite[i].y);
2285 			else
2286 				sprite[i].ang = (krand()&2047);
2287 
2288 			if ((movestat&49152) == 49152)
2289 				if (sprite[movestat&16383].picnum == EVILAL)
2290 					if ((k&31) >= 30)
2291 					{
2292 						wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2293 						sprite[i].picnum = EVILALGRAVE;
2294 						sprite[i].cstat = 0;
2295 						sprite[i].xvel = (krand()&255)-128;
2296 						sprite[i].yvel = (krand()&255)-128;
2297 						sprite[i].zvel = (krand()&4095)-3072;
2298 						changespritestat(i,9);
2299 					}
2300 
2301 			if (sprite[i].lotag&8)
2302 				if ((k&31) >= 30)
2303 				{
2304 					wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2305 					sprite[i].picnum = EVILALGRAVE;
2306 					sprite[i].cstat = 0;
2307 					sprite[i].xvel = (krand()&255)-128;
2308 					sprite[i].yvel = (krand()&255)-128;
2309 					sprite[i].zvel = (krand()&4095)-3072;
2310 					changespritestat(i,9);
2311 				}
2312 
2313 			if (movestat == -1)
2314 			{
2315 				wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2316 				sprite[i].picnum = EVILALGRAVE;
2317 				sprite[i].cstat = 0;
2318 				sprite[i].xvel = (krand()&255)-128;
2319 				sprite[i].yvel = (krand()&255)-128;
2320 				sprite[i].zvel = (krand()&4095)-3072;
2321 				changespritestat(i,9);
2322 			}
2323 		}
2324 	}
2325 
2326 		//Go through travelling bullet sprites
2327 	for(i=headspritestat[6];i>=0;i=nexti)
2328 	{
2329 		nexti = nextspritestat[i];
2330 
2331 		if ((nummoves-i)&statrate[6]) continue;
2332 
2333 			 //If the sprite is a bullet then...
2334 		if ((sprite[i].picnum == BULLET) || (sprite[i].picnum == GRABBER) || (sprite[i].picnum == MISSILE) || (sprite[i].picnum == BOMB))
2335 		{
2336 			dax = ((((long)sprite[i].xvel)*TICSPERFRAME)<<12);
2337 			day = ((((long)sprite[i].yvel)*TICSPERFRAME)<<12);
2338 			daz = ((((long)sprite[i].zvel)*TICSPERFRAME)>>2);
2339 			if (sprite[i].picnum == BOMB) daz = 0;
2340 
2341 			osectnum = sprite[i].sectnum;
2342 			hitobject = movesprite((short)i,dax,day,daz,4L<<8,4L<<8,CLIPMASK1);
2343 			if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10))
2344 			{
2345 				warpsprite((short)i);
2346 				hitobject = 0;
2347 			}
2348 
2349 			if (sprite[i].picnum == GRABBER) {   // Andy did this (& Ken) !Homing!
2350 				checkgrabbertouchsprite(i,sprite[i].sectnum);
2351 				l = 0x7fffffff;
2352 				for (j = connecthead; j >= 0; j = connectpoint2[j])   // Players
2353 					if (j != (sprite[i].owner & (MAXSPRITES - 1)))
2354 						if (cansee(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,posx[j],posy[j],posz[j],cursectnum[j])) {
2355 							k = ksqrt(sqr(posx[j] - sprite[i].x) + sqr(posy[j] - sprite[i].y) + (sqr(posz[j] - sprite[i].z) >> 8));
2356 							if (k < l) {
2357 								l = k;
2358 								dax = (posx[j] - sprite[i].x);
2359 								day = (posy[j] - sprite[i].y);
2360 								daz = (posz[j] - sprite[i].z);
2361 							}
2362 						}
2363 				for(j = headspritestat[1]; j >= 0; j = nextj) {   // Active monsters
2364 					nextj = nextspritestat[j];
2365 					if (cansee(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z,sprite[j].sectnum)) {
2366 						k = ksqrt(sqr(sprite[j].x - sprite[i].x) + sqr(sprite[j].y - sprite[i].y) + (sqr(sprite[j].z - sprite[i].z) >> 8));
2367 						if (k < l) {
2368 							l = k;
2369 							dax = (sprite[j].x - sprite[i].x);
2370 							day = (sprite[j].y - sprite[i].y);
2371 							daz = (sprite[j].z - sprite[i].z);
2372 						}
2373 					}
2374 				}
2375 				for(j = headspritestat[2]; j >= 0; j = nextj) {   // Inactive monsters
2376 					nextj = nextspritestat[j];
2377 					if (cansee(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z,sprite[j].sectnum)) {
2378 						k = ksqrt(sqr(sprite[j].x - sprite[i].x) + sqr(sprite[j].y - sprite[i].y) + (sqr(sprite[j].z - sprite[i].z) >> 8));
2379 						if (k < l) {
2380 							l = k;
2381 							dax = (sprite[j].x - sprite[i].x);
2382 							day = (sprite[j].y - sprite[i].y);
2383 							daz = (sprite[j].z - sprite[i].z);
2384 						}
2385 					}
2386 				}
2387 				if (l != 0x7fffffff) {
2388 					sprite[i].xvel = (divscale7(dax,l) + sprite[i].xvel);   // 1/5 of velocity is homing, 4/5 is momentum
2389 					sprite[i].yvel = (divscale7(day,l) + sprite[i].yvel);   // 1/5 of velocity is homing, 4/5 is momentum
2390 					sprite[i].zvel = (divscale7(daz,l) + sprite[i].zvel);   // 1/5 of velocity is homing, 4/5 is momentum
2391 					l = ksqrt((sprite[i].xvel * sprite[i].xvel) + (sprite[i].yvel * sprite[i].yvel) + ((sprite[i].zvel * sprite[i].zvel) >> 8));
2392 					sprite[i].xvel = divscale9(sprite[i].xvel,l);
2393 					sprite[i].yvel = divscale9(sprite[i].yvel,l);
2394 					sprite[i].zvel = divscale9(sprite[i].zvel,l);
2395 					sprite[i].ang = getangle(sprite[i].xvel,sprite[i].yvel);
2396 				}
2397 			}
2398 
2399 			if (sprite[i].picnum == BOMB)
2400 			{
2401 				j = sprite[i].sectnum;
2402 				if ((sector[j].floorstat&2) && (sprite[i].z > globloz-(8<<8)))
2403 				{
2404 					k = sector[j].wallptr;
2405 					daang = getangle(wall[wall[k].point2].x-wall[k].x,wall[wall[k].point2].y-wall[k].y);
2406 					sprite[i].xvel += mulscale22(sintable[(daang+1024)&2047],sector[j].floorheinum);
2407 					sprite[i].yvel += mulscale22(sintable[(daang+512)&2047],sector[j].floorheinum);
2408 				}
2409 			}
2410 
2411 			if (sprite[i].picnum == BOMB)
2412 			{
2413 				sprite[i].z += sprite[i].zvel;
2414 				sprite[i].zvel += (TICSPERFRAME<<7);
2415 				if (sprite[i].z < globhiz+(tilesizy[BOMB]<<6))
2416 				{
2417 					sprite[i].z = globhiz+(tilesizy[BOMB]<<6);
2418 					sprite[i].zvel = -(sprite[i].zvel>>1);
2419 				}
2420 				if (sprite[i].z > globloz-(tilesizy[BOMB]<<6))
2421 				{
2422 					sprite[i].z = globloz-(tilesizy[BOMB]<<6);
2423 					sprite[i].zvel = -(sprite[i].zvel>>1);
2424 				}
2425 				dax = sprite[i].xvel; day = sprite[i].yvel;
2426 				dist = dax*dax+day*day;
2427 				if (dist < 512)
2428 				{
2429 					bombexplode(i);
2430 					goto bulletisdeletedskip;
2431 				}
2432 				if (dist < 4096)
2433 				{
2434 					sprite[i].xrepeat = ((4096+2048)*16) / (dist+2048);
2435 					sprite[i].yrepeat = sprite[i].xrepeat;
2436 					sprite[i].xoffset = (krand()&15)-8;
2437 					sprite[i].yoffset = (krand()&15)-8;
2438 				}
2439 				if (mulscale30(krand(),dist) == 0)
2440 				{
2441 					sprite[i].xvel -= ksgn(sprite[i].xvel);
2442 					sprite[i].yvel -= ksgn(sprite[i].yvel);
2443 					sprite[i].zvel -= ksgn(sprite[i].zvel);
2444 				}
2445 			}
2446 
2447 				//Check for bouncy objects before killing bullet
2448 			if ((hitobject&0xc000) == 16384)  //Bullet hit a ceiling/floor
2449 			{
2450 				k = sector[hitobject&(MAXSECTORS-1)].wallptr; l = wall[k].point2;
2451 				daang = getangle(wall[l].x-wall[k].x,wall[l].y-wall[k].y);
2452 
2453 				getzsofslope(hitobject&(MAXSECTORS-1),sprite[i].x,sprite[i].y,&k,&l);
2454 				if (sprite[i].z < ((k+l)>>1)) k = sector[hitobject&(MAXSECTORS-1)].ceilingheinum;
2455 												 else k = sector[hitobject&(MAXSECTORS-1)].floorheinum;
2456 
2457 				dax = mulscale14(k,sintable[(daang)&2047]);
2458 				day = mulscale14(k,sintable[(daang+1536)&2047]);
2459 				daz = 4096;
2460 
2461 				k = sprite[i].xvel*dax+sprite[i].yvel*day+mulscale4(sprite[i].zvel,daz);
2462 				l = dax*dax+day*day+daz*daz;
2463 				if ((klabs(k)>>14) < l)
2464 				{
2465 					k = divscale17(k,l);
2466 					sprite[i].xvel -= mulscale16(dax,k);
2467 					sprite[i].yvel -= mulscale16(day,k);
2468 					sprite[i].zvel -= mulscale12(daz,k);
2469 				}
2470 				wsayfollow("bouncy.wav",4096L+(krand()&127)-64,255,&sprite[i].x,&sprite[i].y,1);
2471 				hitobject = 0;
2472 				sprite[i].owner = -1;   //Bullet turns evil!
2473 			}
2474 			else if ((hitobject&0xc000) == 32768)  //Bullet hit a wall
2475 			{
2476 				if (wall[hitobject&4095].lotag == 8)
2477 				{
2478 					dax = sprite[i].xvel; day = sprite[i].yvel;
2479 					if ((sprite[i].picnum != BOMB) || (dax*dax+day*day >= 512))
2480 					{
2481 						k = (hitobject&4095); l = wall[k].point2;
2482 						j = getangle(wall[l].x-wall[k].x,wall[l].y-wall[k].y)+512;
2483 
2484 							//k = cos(ang) * sin(ang) * 2
2485 						k = mulscale13(sintable[(j+512)&2047],sintable[j&2047]);
2486 							//l = cos(ang * 2)
2487 						l = sintable[((j<<1)+512)&2047];
2488 
2489 						ox = sprite[i].xvel; oy = sprite[i].yvel;
2490 						dax = -ox; day = -oy;
2491 						sprite[i].xvel = dmulscale14(day,k,dax,l);
2492 						sprite[i].yvel = dmulscale14(dax,k,-day,l);
2493 
2494 						if (sprite[i].picnum == BOMB)
2495 						{
2496 							sprite[i].xvel -= (sprite[i].xvel>>3);
2497 							sprite[i].yvel -= (sprite[i].yvel>>3);
2498 							sprite[i].zvel -= (sprite[i].zvel>>3);
2499 						}
2500 						ox -= sprite[i].xvel; oy -= sprite[i].yvel;
2501 						dist = ((ox*ox+oy*oy)>>8);
2502 						wsayfollow("bouncy.wav",4096L+(krand()&127)-64,min(dist,256),&sprite[i].x,&sprite[i].y,1);
2503 						hitobject = 0;
2504 						sprite[i].owner = -1;   //Bullet turns evil!
2505 					}
2506 				}
2507 			}
2508 			else if ((hitobject&0xc000) == 49152)  //Bullet hit a sprite
2509 			{
2510 				if (sprite[hitobject&4095].picnum == BOUNCYMAT)
2511 				{
2512 					if ((sprite[hitobject&4095].cstat&48) == 0)
2513 					{
2514 						sprite[i].xvel = -sprite[i].xvel;
2515 						sprite[i].yvel = -sprite[i].yvel;
2516 						sprite[i].zvel = -sprite[i].zvel;
2517 						dist = 255;
2518 					}
2519 					else if ((sprite[hitobject&4095].cstat&48) == 16)
2520 					{
2521 						j = sprite[hitobject&4095].ang;
2522 
2523 							//k = cos(ang) * sin(ang) * 2
2524 						k = mulscale13(sintable[(j+512)&2047],sintable[j&2047]);
2525 							//l = cos(ang * 2)
2526 						l = sintable[((j<<1)+512)&2047];
2527 
2528 						ox = sprite[i].xvel; oy = sprite[i].yvel;
2529 						dax = -ox; day = -oy;
2530 						sprite[i].xvel = dmulscale14(day,k,dax,l);
2531 						sprite[i].yvel = dmulscale14(dax,k,-day,l);
2532 
2533 						ox -= sprite[i].xvel; oy -= sprite[i].yvel;
2534 						dist = ((ox*ox+oy*oy)>>8);
2535 					}
2536 					sprite[i].owner = -1;   //Bullet turns evil!
2537 					wsayfollow("bouncy.wav",4096L+(krand()&127)-64,min(dist,256),&sprite[i].x,&sprite[i].y,1);
2538 					hitobject = 0;
2539 				}
2540 			}
2541 
2542 			if (hitobject != 0)
2543 			{
2544 				if ((sprite[i].picnum == MISSILE) || (sprite[i].picnum == BOMB))
2545 				{
2546 					if ((hitobject&0xc000) == 49152)
2547 						if (sprite[hitobject&4095].lotag == 5)  //Basketball hoop
2548 						{
2549 							wsayfollow("niceshot.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2550 							deletesprite((short)i);
2551 							goto bulletisdeletedskip;
2552 						}
2553 
2554 					bombexplode(i);
2555 					goto bulletisdeletedskip;
2556 				}
2557 
2558 				if ((hitobject&0xc000) == 16384)  //Hits a ceiling / floor
2559 				{
2560 					wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2561 					deletesprite((short)i);
2562 					goto bulletisdeletedskip;
2563 				}
2564 				else if ((hitobject&0xc000) == 32768)  //Bullet hit a wall
2565 				{
2566 					if (wall[hitobject&4095].picnum == KENPICTURE)
2567 					{
2568 						if (waloff[MAXTILES-1] != 0)
2569 							wall[hitobject&4095].picnum = MAXTILES-1;
2570 						wsayfollow("hello.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);   //Ken says, "Hello... how are you today!"
2571 					}
2572 					else
2573 						wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2574 
2575 					deletesprite((short)i);
2576 					goto bulletisdeletedskip;
2577 				}
2578 				else if ((hitobject&0xc000) == 49152)  //Bullet hit a sprite
2579 				{
2580 					if ((sprite[hitobject&4095].lotag == 5) && (sprite[i].picnum == GRABBER)) {  // Basketball hoop (Andy's addition)
2581 						wsayfollow("niceshot.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2582 						switch (krand() & 63) {
2583 							case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9:
2584 								sprite[i].picnum = COIN; break;
2585 							case 10: case 11: case 12: case 13: case 14: case 15: case 16:
2586 								sprite[i].picnum = DIAMONDS; break;
2587 							case 17: case 18: case 19:
2588 								sprite[i].picnum = COINSTACK; break;
2589 							case 20: case 21: case 22: case 23:
2590 								sprite[i].picnum = GIFTBOX; break;
2591 							case 24: case 25:
2592 								sprite[i].picnum = GRABCANNON; break;
2593 							case 26: case 27:
2594 								sprite[i].picnum = LAUNCHER; break;
2595 							case 28: case 29: case 30:
2596 								sprite[i].picnum = CANNON; break;
2597 							case 31:
2598 								sprite[i].picnum = AIRPLANE; break;
2599 							default:
2600 								deletesprite((short)i);
2601 								goto bulletisdeletedskip;
2602 						}
2603 						sprite[i].xvel = sprite[i].yvel = sprite[i].zvel = 0;
2604 						sprite[i].cstat &= ~0x83;    //Should not clip, foot-z
2605 						changespritestat(i,12);
2606 						goto bulletisdeletedskip;
2607 					}
2608 
2609 						//Check if bullet hit a player & find which player it was...
2610 					if (sprite[hitobject&4095].picnum == PLAYER)
2611 						for(j=connecthead;j>=0;j=connectpoint2[j])
2612 							if (sprite[i].owner != j+4096)
2613 								if (playersprite[j] == (hitobject&4095))
2614 								{
2615 									wsayfollow("ouch.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2616 									if (sprite[i].picnum == GRABBER) {   // Andy did this
2617 										k = ((sprite[i].xrepeat * sprite[i].yrepeat) * 3) >> 9;
2618 										changehealth((sprite[i].owner - 4096),k);
2619 										changehealth(j,-k);
2620 									}
2621 									else changehealth(j,-mulscale8(sprite[i].xrepeat,sprite[i].yrepeat));
2622 									deletesprite((short)i);
2623 									goto bulletisdeletedskip;
2624 								}
2625 
2626 						//Check if bullet hit any monsters...
2627 					j = (hitobject&4095);     //j is the spritenum that the bullet (spritenum i) hit
2628 					if (sprite[i].owner != j)
2629 					{
2630 						switch(sprite[j].picnum)
2631 						{
2632 							case BROWNMONSTER:
2633 								if (sprite[j].lotag > 0) {
2634 									if (sprite[i].picnum == GRABBER) {   // Andy did this
2635 										k = ((sprite[i].xrepeat * sprite[i].yrepeat) * 3) >> 9;
2636 										changehealth((sprite[i].owner - 4096),k);
2637 										sprite[j].lotag -= k;
2638 									}
2639 									sprite[j].lotag -= mulscale8(sprite[i].xrepeat,sprite[i].yrepeat);
2640 								}
2641 								if (sprite[j].lotag > 0)
2642 								{
2643 									if (sprite[j].lotag <= 25) sprite[j].cstat |= 2;
2644 									wsayfollow("hurt.wav",4096L+(krand()&511)-256,256L,&sprite[i].x,&sprite[i].y,1);
2645 								}
2646 								else
2647 								{
2648 									wsayfollow("mondie.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2649 									sprite[j].z += ((tilesizy[sprite[j].picnum]*sprite[j].yrepeat)<<1);
2650 									sprite[j].picnum = GIFTBOX;
2651 									sprite[j].cstat &= ~0x83;    //Should not clip, foot-z
2652 
2653 									spawnsprite(k,sprite[j].x,sprite[j].y,sprite[j].z,
2654 										0,-4,0,32,64,64,0,0,EXPLOSION,sprite[j].ang,
2655 										0,0,0,j,sprite[j].sectnum,5,31,0,0);
2656 											//31=Time left for explosion to stay
2657 
2658 									changespritestat(j,12);
2659 								}
2660 								deletesprite((short)i);
2661 								goto bulletisdeletedskip;
2662 							case EVILAL:
2663 								wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2664 								sprite[j].picnum = EVILALGRAVE;
2665 								sprite[j].cstat = 0;
2666 								sprite[j].xvel = (krand()&255)-128;
2667 								sprite[j].yvel = (krand()&255)-128;
2668 								sprite[j].zvel = (krand()&4095)-3072;
2669 								changespritestat(j,9);
2670 
2671 								deletesprite((short)i);
2672 								goto bulletisdeletedskip;
2673 							case AL:
2674 								wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2675 								sprite[j].xrepeat += 2;
2676 								sprite[j].yrepeat += 2;
2677 								if (sprite[j].yrepeat >= 38)
2678 								{
2679 									sprite[j].picnum = EVILAL;
2680 									//sprite[j].cstat |= 2;      //Make him transluscent
2681 									changespritestat(j,10);
2682 								}
2683 								deletesprite((short)i);
2684 								goto bulletisdeletedskip;
2685 							default:
2686 								wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2687 								deletesprite((short)i);
2688 								goto bulletisdeletedskip;
2689 						}
2690 					}
2691 				}
2692 			}
2693 		}
2694 bulletisdeletedskip: continue;
2695 	}
2696 
2697 		//Go through monster waiting for you list
2698 	for(i=headspritestat[2];i>=0;i=nexti)
2699 	{
2700 		nexti = nextspritestat[i];
2701 
2702 		if ((nummoves-i)&15) continue;
2703 
2704 			//Use dot product to see if monster's angle is towards a player
2705 		for(p=connecthead;p>=0;p=connectpoint2[p])
2706 			if (sintable[(sprite[i].ang+512)&2047]*(posx[p]-sprite[i].x) + sintable[sprite[i].ang&2047]*(posy[p]-sprite[i].y) >= 0)
2707 				if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[p],posy[p],posz[p],cursectnum[p]) == 1)
2708 				{
2709 					changespritestat(i,1);
2710 					//if (sprite[i].lotag == 100)
2711 					//{
2712 						wsayfollow("iseeyou.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1);
2713 					//   sprite[i].lotag = 99;
2714 					//}
2715 				}
2716 	}
2717 
2718 		//Go through smoke sprites
2719 	for(i=headspritestat[3];i>=0;i=nexti)
2720 	{
2721 		nexti = nextspritestat[i];
2722 
2723 		sprite[i].z -= (TICSPERFRAME<<6);
2724 		sprite[i].lotag -= TICSPERFRAME;
2725 		if (sprite[i].lotag < 0) deletesprite(i);
2726 	}
2727 
2728 		//Go through splash sprites
2729 	for(i=headspritestat[4];i>=0;i=nexti)
2730 	{
2731 		nexti = nextspritestat[i];
2732 
2733 		sprite[i].lotag -= TICSPERFRAME;
2734 		sprite[i].picnum = SPLASH + ((63-sprite[i].lotag)>>4);
2735 		if (sprite[i].lotag < 0) deletesprite(i);
2736 	}
2737 
2738 		//Go through explosion sprites
2739 	for(i=headspritestat[5];i>=0;i=nexti)
2740 	{
2741 		nexti = nextspritestat[i];
2742 
2743 		sprite[i].lotag -= TICSPERFRAME;
2744 		if (sprite[i].lotag < 0) deletesprite(i);
2745 	}
2746 
2747 		//Go through bomb spriral-explosion sprites
2748 	for(i=headspritestat[7];i>=0;i=nexti)
2749 	{
2750 		nexti = nextspritestat[i];
2751 
2752 		sprite[i].xrepeat = (sprite[i].lotag>>2);
2753 		sprite[i].yrepeat = (sprite[i].lotag>>2);
2754 		sprite[i].lotag -= (TICSPERFRAME<<2);
2755 		if (sprite[i].lotag < 0) { deletesprite(i); continue; }
2756 
2757 		if ((nummoves-i)&statrate[7]) continue;
2758 
2759 		sprite[i].x += ((sprite[i].xvel*TICSPERFRAME)>>2);
2760 		sprite[i].y += ((sprite[i].yvel*TICSPERFRAME)>>2);
2761 		sprite[i].z += ((sprite[i].zvel*TICSPERFRAME)>>2);
2762 
2763 		sprite[i].zvel += (TICSPERFRAME<<9);
2764 		if (sprite[i].z < sector[sprite[i].sectnum].ceilingz+(4<<8))
2765 		{
2766 			sprite[i].z = sector[sprite[i].sectnum].ceilingz+(4<<8);
2767 			sprite[i].zvel = -(sprite[i].zvel>>1);
2768 		}
2769 		if (sprite[i].z > sector[sprite[i].sectnum].floorz-(4<<8))
2770 		{
2771 			sprite[i].z = sector[sprite[i].sectnum].floorz-(4<<8);
2772 			sprite[i].zvel = -(sprite[i].zvel>>1);
2773 		}
2774 	}
2775 
2776 		//EVILALGRAVE shrinking list
2777 	for(i=headspritestat[9];i>=0;i=nexti)
2778 	{
2779 		nexti = nextspritestat[i];
2780 
2781 		sprite[i].xrepeat = (sprite[i].lotag>>2);
2782 		sprite[i].yrepeat = (sprite[i].lotag>>2);
2783 		sprite[i].lotag -= TICSPERFRAME;
2784 		if (sprite[i].lotag < 0) { deletesprite(i); continue; }
2785 
2786 		if ((nummoves-i)&statrate[9]) continue;
2787 
2788 		sprite[i].x += (sprite[i].xvel*TICSPERFRAME);
2789 		sprite[i].y += (sprite[i].yvel*TICSPERFRAME);
2790 		sprite[i].z += (sprite[i].zvel*TICSPERFRAME);
2791 
2792 		sprite[i].zvel += (TICSPERFRAME<<8);
2793 		if (sprite[i].z < sector[sprite[i].sectnum].ceilingz)
2794 		{
2795 			sprite[i].z = sector[sprite[i].sectnum].ceilingz;
2796 			sprite[i].xvel -= (sprite[i].xvel>>2);
2797 			sprite[i].yvel -= (sprite[i].yvel>>2);
2798 			sprite[i].zvel = -(sprite[i].zvel>>1);
2799 		}
2800 		if (sprite[i].z > sector[sprite[i].sectnum].floorz)
2801 		{
2802 			sprite[i].z = sector[sprite[i].sectnum].floorz;
2803 			sprite[i].xvel -= (sprite[i].xvel>>2);
2804 			sprite[i].yvel -= (sprite[i].yvel>>2);
2805 			sprite[i].zvel = -(sprite[i].zvel>>1);
2806 		}
2807 	}
2808 
2809 		//Re-spawning sprite list
2810 	for(i=headspritestat[11];i>=0;i=nexti)
2811 	{
2812 		nexti = nextspritestat[i];
2813 
2814 		sprite[i].extra -= TICSPERFRAME;
2815 		if (sprite[i].extra < 0)
2816 		{
2817 			wsayfollow("warp.wav",6144L+(krand()&127)-64,128L,&sprite[i].x,&sprite[i].y,0);
2818 			sprite[i].cstat &= ~0x8000;
2819 			sprite[i].extra = -1;
2820 			changespritestat((short)i,0);
2821 		}
2822 	}
2823 }
2824 
activatehitag(short dahitag)2825 activatehitag(short dahitag)
2826 {
2827 	long i, nexti;
2828 
2829 	for(i=0;i<numsectors;i++)
2830 		if (sector[i].hitag == dahitag) operatesector(i);
2831 
2832 	for(i=headspritestat[0];i>=0;i=nexti)
2833 	{
2834 		nexti = nextspritestat[i];
2835 		if (sprite[i].hitag == dahitag) operatesprite(i);
2836 	}
2837 }
2838 
bombexplode(long i)2839 bombexplode(long i)
2840 {
2841 	long j, nextj, k, daang, dax, day, dist;
2842 
2843 	spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,0,-4,0,
2844 		32,64,64,0,0,EXPLOSION,sprite[i].ang,
2845 		0,0,0,sprite[i].owner,sprite[i].sectnum,5,31,0,0);
2846 		  //31=Time left for explosion to stay
2847 
2848 	for(k=0;k<12;k++)
2849 	{
2850 		spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z+(8<<8),2,-4,0,
2851 			32,24,24,0,0,EXPLOSION,sprite[i].ang,
2852 			(krand()>>7)-256,(krand()>>7)-256,(krand()>>2)-8192,
2853 			sprite[i].owner,sprite[i].sectnum,7,96,0,0);
2854 				//96=Time left for smoke to be alive
2855 	}
2856 
2857 	for(j=connecthead;j>=0;j=connectpoint2[j])
2858 	{
2859 		dist = (posx[j]-sprite[i].x)*(posx[j]-sprite[i].x);
2860 		dist += (posy[j]-sprite[i].y)*(posy[j]-sprite[i].y);
2861 		dist += ((posz[j]-sprite[i].z)>>4)*((posz[j]-sprite[i].z)>>4);
2862 		if (dist < 4194304)
2863 			if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[j],posy[j],posz[j],cursectnum[j]) == 1)
2864 			{
2865 				k = ((32768/((dist>>16)+4))>>5);
2866 				if (j == myconnectindex)
2867 				{
2868 					daang = getangle(posx[j]-sprite[i].x,posy[j]-sprite[i].y);
2869 					dax = ((k*sintable[(daang+512)&2047])>>14);
2870 					day = ((k*sintable[daang&2047])>>14);
2871 					fvel += ((dax*sintable[(ang[j]+512)&2047]+day*sintable[ang[j]&2047])>>14);
2872 					svel += ((day*sintable[(ang[j]+512)&2047]-dax*sintable[ang[j]&2047])>>14);
2873 				}
2874 				changehealth(j,-k);    //if changehealth returns 1, you're dead
2875 			}
2876 	}
2877 
2878 	for(k=1;k<=2;k++)         //Check for hurting monsters
2879 	{
2880 		for(j=headspritestat[k];j>=0;j=nextj)
2881 		{
2882 			nextj = nextspritestat[j];
2883 
2884 			dist = (sprite[j].x-sprite[i].x)*(sprite[j].x-sprite[i].x);
2885 			dist += (sprite[j].y-sprite[i].y)*(sprite[j].y-sprite[i].y);
2886 			dist += ((sprite[j].z-sprite[i].z)>>4)*((sprite[j].z-sprite[i].z)>>4);
2887 			if (dist >= 4194304) continue;
2888 			if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z-(tilesizy[sprite[j].picnum]<<7),sprite[j].sectnum) == 0)
2889 				continue;
2890 			if (sprite[j].picnum == BROWNMONSTER)
2891 			{
2892 				sprite[j].z += ((tilesizy[sprite[j].picnum]*sprite[j].yrepeat)<<1);
2893 				sprite[j].picnum = GIFTBOX;
2894 				sprite[j].cstat &= ~0x83;    //Should not clip, foot-z
2895 				changespritestat(j,12);
2896 			}
2897 		}
2898 	}
2899 
2900 	for(j=headspritestat[10];j>=0;j=nextj)   //Check for EVILAL's
2901 	{
2902 		nextj = nextspritestat[j];
2903 
2904 		dist = (sprite[j].x-sprite[i].x)*(sprite[j].x-sprite[i].x);
2905 		dist += (sprite[j].y-sprite[i].y)*(sprite[j].y-sprite[i].y);
2906 		dist += ((sprite[j].z-sprite[i].z)>>4)*((sprite[j].z-sprite[i].z)>>4);
2907 		if (dist >= 4194304) continue;
2908 		if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z-(tilesizy[sprite[j].picnum]<<7),sprite[j].sectnum) == 0)
2909 			continue;
2910 
2911 		sprite[j].picnum = EVILALGRAVE;
2912 		sprite[j].cstat = 0;
2913 		sprite[j].xvel = (krand()&255)-128;
2914 		sprite[j].yvel = (krand()&255)-128;
2915 		sprite[j].zvel = (krand()&4095)-3072;
2916 		changespritestat(j,9);
2917 	}
2918 
2919 	wsayfollow("blowup.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2920 	deletesprite((short)i);
2921 }
2922 
processinput(short snum)2923 processinput(short snum)
2924 {
2925 	long oldposx, oldposy, nexti;
2926 	long i, j, k, doubvel, xvect, yvect, goalz;
2927 	long dax, day, dax2, day2, odax, oday, odax2, oday2;
2928 	short startwall, endwall;
2929 	char *ptr;
2930 
2931 		//SHARED KEYS:
2932 		//Movement code
2933 	if ((sync[snum].fvel|sync[snum].svel) != 0)
2934 	{
2935 		doubvel = (TICSPERFRAME<<((sync[snum].bits&256)>0));
2936 
2937 		xvect = 0, yvect = 0;
2938 		if (sync[snum].fvel != 0)
2939 		{
2940 			xvect += ((((long)sync[snum].fvel)*doubvel*(long)sintable[(ang[snum]+512)&2047])>>3);
2941 			yvect += ((((long)sync[snum].fvel)*doubvel*(long)sintable[ang[snum]&2047])>>3);
2942 		}
2943 		if (sync[snum].svel != 0)
2944 		{
2945 			xvect += ((((long)sync[snum].svel)*doubvel*(long)sintable[ang[snum]&2047])>>3);
2946 			yvect += ((((long)sync[snum].svel)*doubvel*(long)sintable[(ang[snum]+1536)&2047])>>3);
2947 		}
2948 		if (flytime[snum] > lockclock) { xvect += xvect; yvect += yvect; }   // DOuble flying speed
2949 		clipmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],xvect,yvect,128L,4<<8,4<<8,CLIPMASK0);
2950 		revolvedoorstat[snum] = 1;
2951 	}
2952 	else
2953 	{
2954 		revolvedoorstat[snum] = 0;
2955 	}
2956 
2957 	sprite[playersprite[snum]].cstat &= ~1;
2958 		//Push player away from walls if clipmove doesn't work
2959 	if (pushmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],128L,4<<8,4<<8,CLIPMASK0) < 0)
2960 		changehealth(snum,-1000);  //If this screws up, then instant death!!!
2961 
2962 			// Getzrange returns the highest and lowest z's for an entire box,
2963 			// NOT just a point.  This prevents you from falling off cliffs
2964 			// when you step only slightly over the cliff.
2965 	getzrange(posx[snum],posy[snum],posz[snum],cursectnum[snum],&globhiz,&globhihit,&globloz,&globlohit,128L,CLIPMASK0);
2966 	sprite[playersprite[snum]].cstat |= 1;
2967 
2968 	if (sync[snum].avel != 0)          //ang += avel * constant
2969 	{                         //ENGINE calculates avel for you
2970 		doubvel = TICSPERFRAME;
2971 		if ((sync[snum].bits&256) > 0)  //Lt. shift makes turn velocity 50% faster
2972 			doubvel += (TICSPERFRAME>>1);
2973 		ang[snum] += ((((long)sync[snum].avel)*doubvel)>>4);
2974 		ang[snum] &= 2047;
2975 	}
2976 
2977 	if (health[snum] < 0)
2978 	{
2979 		health[snum] -= TICSPERFRAME;
2980 		if (health[snum] <= -160)
2981 		{
2982 			hvel[snum] = 0;
2983 			if (snum == myconnectindex)
2984 				fvel = 0, svel = 0, avel = 0, keystatus[3] = 1;
2985 
2986 			deaths[snum]++;
2987 			health[snum] = 100;
2988 			numbombs[snum] = 0;
2989 			numgrabbers[snum] = 0;
2990 			nummissiles[snum] = 0;
2991 			flytime[snum] = 0;
2992 
2993 			findrandomspot(&posx[snum],&posy[snum],&cursectnum[snum]);
2994 			posz[snum] = getflorzofslope(cursectnum[snum],posx[snum],posy[snum])-(1<<8);
2995 			horiz[snum] = 100;
2996 			ang[snum] = (krand()&2047);
2997 
2998 			sprite[playersprite[snum]].x = posx[snum];
2999 			sprite[playersprite[snum]].y = posy[snum];
3000 			sprite[playersprite[snum]].z = posz[snum]+EYEHEIGHT;
3001 			sprite[playersprite[snum]].picnum = PLAYER;
3002 			sprite[playersprite[snum]].ang = ang[snum];
3003 			sprite[playersprite[snum]].xrepeat = 64;
3004 			sprite[playersprite[snum]].yrepeat = 64;
3005 			changespritesect(playersprite[snum],cursectnum[snum]);
3006 
3007 			drawstatusbar(snum);   // Andy did this
3008 
3009 			i = playersprite[snum];
3010 			wsayfollow("zipguns.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1);
3011 			for(k=0;k<16;k++)
3012 			{
3013 				spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z+(8<<8),2,-4,0,
3014 					32,24,24,0,0,EXPLOSION,sprite[i].ang,
3015 					(krand()&511)-256,(krand()&511)-256,(krand()&16384)-8192,
3016 					sprite[i].owner,sprite[i].sectnum,7,96,0,0);
3017 						//96=Time left for smoke to be alive
3018 			}
3019 		}
3020 		else
3021 		{
3022 			sprite[playersprite[snum]].xrepeat = max(((128+health[snum])>>1),0);
3023 			sprite[playersprite[snum]].yrepeat = max(((128+health[snum])>>1),0);
3024 
3025 			hvel[snum] += (TICSPERFRAME<<2);
3026 			horiz[snum] = max(horiz[snum]-4,0);
3027 			posz[snum] += hvel[snum];
3028 			if (posz[snum] > globloz-(4<<8))
3029 			{
3030 				posz[snum] = globloz-(4<<8);
3031 				horiz[snum] = min(horiz[snum]+5,200);
3032 				hvel[snum] = 0;
3033 			}
3034 		}
3035 	}
3036 
3037 	if (((sync[snum].bits&8) > 0) && (horiz[snum] > 100-(200>>1))) horiz[snum] -= 4;     //-
3038 	if (((sync[snum].bits&4) > 0) && (horiz[snum] < 100+(200>>1))) horiz[snum] += 4;   //+
3039 
3040 	goalz = globloz-EYEHEIGHT;
3041 	if (sector[cursectnum[snum]].lotag == 4)   //slime sector
3042 		if ((globlohit&0xc000) != 49152)            //You're not on a sprite
3043 		{
3044 			goalz = globloz-(8<<8);
3045 			if (posz[snum] >= goalz-(2<<8))
3046 			{
3047 				clipmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],-TICSPERFRAME<<14,-TICSPERFRAME<<14,128L,4<<8,4<<8,CLIPMASK0);
3048 
3049 				if (slimesoundcnt[snum] >= 0)
3050 				{
3051 					slimesoundcnt[snum] -= TICSPERFRAME;
3052 					while (slimesoundcnt[snum] < 0)
3053 					{
3054 						slimesoundcnt[snum] += 120;
3055 						wsayfollow("slime.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
3056 					}
3057 				}
3058 			}
3059 		}
3060 	if (goalz < globhiz+(16<<8))   //ceiling&floor too close
3061 		goalz = ((globloz+globhiz)>>1);
3062 	//goalz += mousz;
3063 	if (health[snum] >= 0)
3064 	{
3065 		if ((sync[snum].bits&1) > 0)                         //A (stand high)
3066 		{
3067 			if (flytime[snum] <= lockclock)
3068 			{
3069 				if (posz[snum] >= globloz-(32<<8))
3070 				{
3071 					goalz -= (16<<8);
3072 					if (sync[snum].bits&256) goalz -= (24<<8);
3073 				}
3074 			}
3075 			else
3076 			{
3077 				hvel[snum] -= 192;
3078 				if (sync[snum].bits&256) hvel[snum] -= 192;
3079 			}
3080 		}
3081 		if ((sync[snum].bits&2) > 0)                         //Z (stand low)
3082 		{
3083 			if (flytime[snum] <= lockclock)
3084 			{
3085 				goalz += (12<<8);
3086 				if (sync[snum].bits&256) goalz += (12<<8);
3087 			}
3088 			else
3089 			{
3090 				hvel[snum] += 192;
3091 				if (sync[snum].bits&256) hvel[snum] += 192;
3092 			}
3093 		}
3094 	}
3095 
3096 	if (flytime[snum] <= lockclock)
3097 	{
3098 		if (posz[snum] < goalz)
3099 			hvel[snum] += (TICSPERFRAME<<4);
3100 		else
3101 			hvel[snum] = (((goalz-posz[snum])*TICSPERFRAME)>>5);
3102 	}
3103 	else
3104 	{
3105 		hvel[snum] -= (hvel[snum]>>2);
3106 		hvel[snum] -= ksgn(hvel[snum]);
3107 	}
3108 
3109 	posz[snum] += hvel[snum];
3110 	if (posz[snum] > globloz-(4<<8)) posz[snum] = globloz-(4<<8), hvel[snum] = 0;
3111 	if (posz[snum] < globhiz+(4<<8)) posz[snum] = globhiz+(4<<8), hvel[snum] = 0;
3112 
3113 	if (dimensionmode[snum] != 3)
3114 	{
3115 		if (((sync[snum].bits&32) > 0) && (zoom[snum] > 48)) zoom[snum] -= (zoom[snum]>>4);
3116 		if (((sync[snum].bits&16) > 0) && (zoom[snum] < 4096)) zoom[snum] += (zoom[snum]>>4);
3117 	}
3118 
3119 		//Update sprite representation of player
3120 		//   -should be after movement, but before shooting code
3121 	setsprite(playersprite[snum],posx[snum],posy[snum],posz[snum]+EYEHEIGHT);
3122 	sprite[playersprite[snum]].ang = ang[snum];
3123 
3124 	if (health[snum] >= 0)
3125 	{
3126 		if ((cursectnum[snum] < 0) || (cursectnum[snum] >= numsectors))
3127 		{       //How did you get in the wrong sector?
3128 			wsayfollow("ouch.wav",4096L+(krand()&127)-64,64L,&posx[snum],&posy[snum],1);
3129 			changehealth(snum,-TICSPERFRAME);
3130 		}
3131 		else if (globhiz+(8<<8) > globloz)
3132 		{       //Ceiling and floor are smooshing you!
3133 			wsayfollow("ouch.wav",4096L+(krand()&127)-64,64L,&posx[snum],&posy[snum],1);
3134 			changehealth(snum,-TICSPERFRAME);
3135 		}
3136 	}
3137 
3138 	if ((waterfountainwall[snum] >= 0) && (health[snum] >= 0))
3139 		if ((wall[neartagwall].lotag != 7) || ((sync[snum].bits&1024) == 0))
3140 		{
3141 			i = waterfountainwall[snum];
3142 			if (wall[i].overpicnum == USEWATERFOUNTAIN)
3143 				wall[i].overpicnum = WATERFOUNTAIN;
3144 			else if (wall[i].picnum == USEWATERFOUNTAIN)
3145 				wall[i].picnum = WATERFOUNTAIN;
3146 
3147 			waterfountainwall[snum] = -1;
3148 		}
3149 
3150 	if ((sync[snum].bits&1024) > 0)  //Space bar
3151 	{
3152 			//Continuous triggers...
3153 
3154 		neartag(posx[snum],posy[snum],posz[snum],cursectnum[snum],ang[snum],&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1024L,3);
3155 		if (neartagsector == -1)
3156 		{
3157 			i = cursectnum[snum];
3158 			if ((sector[i].lotag|sector[i].hitag) != 0)
3159 				neartagsector = i;
3160 		}
3161 
3162 		if (wall[neartagwall].lotag == 7)  //Water fountain
3163 		{
3164 			if (wall[neartagwall].overpicnum == WATERFOUNTAIN)
3165 			{
3166 				wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
3167 				wall[neartagwall].overpicnum = USEWATERFOUNTAIN;
3168 				waterfountainwall[snum] = neartagwall;
3169 			}
3170 			else if (wall[neartagwall].picnum == WATERFOUNTAIN)
3171 			{
3172 				wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
3173 				wall[neartagwall].picnum = USEWATERFOUNTAIN;
3174 				waterfountainwall[snum] = neartagwall;
3175 			}
3176 
3177 			if (waterfountainwall[snum] >= 0)
3178 			{
3179 				waterfountaincnt[snum] -= TICSPERFRAME;
3180 				while (waterfountaincnt[snum] < 0)
3181 				{
3182 					waterfountaincnt[snum] += 120;
3183 					wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
3184 					changehealth(snum,2);
3185 				}
3186 			}
3187 		}
3188 
3189 			//1-time triggers...
3190 		if ((oflags[snum]&1024) == 0)
3191 		{
3192 			if (neartagsector >= 0)
3193 				if (sector[neartagsector].hitag == 0)
3194 					operatesector(neartagsector);
3195 
3196 			if (neartagwall >= 0)
3197 				if (wall[neartagwall].lotag == 2)  //Switch
3198 				{
3199 					activatehitag(wall[neartagwall].hitag);
3200 
3201 					j = wall[neartagwall].overpicnum;
3202 					if (j == SWITCH1ON)                     //1-time switch
3203 					{
3204 						wall[neartagwall].overpicnum = GIFTBOX;
3205 						wall[neartagwall].lotag = 0;
3206 						wall[neartagwall].hitag = 0;
3207 					}
3208 					if (j == GIFTBOX)                       //1-time switch
3209 					{
3210 						wall[neartagwall].overpicnum = SWITCH1ON;
3211 						wall[neartagwall].lotag = 0;
3212 						wall[neartagwall].hitag = 0;
3213 					}
3214 					if (j == SWITCH2ON) wall[neartagwall].overpicnum = SWITCH2OFF;
3215 					if (j == SWITCH2OFF) wall[neartagwall].overpicnum = SWITCH2ON;
3216 					if (j == SWITCH3ON) wall[neartagwall].overpicnum = SWITCH3OFF;
3217 					if (j == SWITCH3OFF) wall[neartagwall].overpicnum = SWITCH3ON;
3218 
3219 					i = wall[neartagwall].point2;
3220 					dax = ((wall[neartagwall].x+wall[i].x)>>1);
3221 					day = ((wall[neartagwall].y+wall[i].y)>>1);
3222 					wsayfollow("switch.wav",4096L+(krand()&255)-128,256L,&dax,&day,0);
3223 				}
3224 
3225 			if (neartagsprite >= 0)
3226 			{
3227 				if (sprite[neartagsprite].lotag == 1)
3228 				{  //if you're shoving innocent little AL around, he gets mad!
3229 					if (sprite[neartagsprite].picnum == AL)
3230 					{
3231 						sprite[neartagsprite].picnum = EVILAL;
3232 						sprite[neartagsprite].cstat |= 2;   //Make him transluscent
3233 						sprite[neartagsprite].xrepeat = 38;
3234 						sprite[neartagsprite].yrepeat = 38;
3235 						changespritestat(neartagsprite,10);
3236 					}
3237 				}
3238 				if (sprite[neartagsprite].lotag == 4)
3239 				{
3240 					activatehitag(sprite[neartagsprite].hitag);
3241 
3242 					j = sprite[neartagsprite].picnum;
3243 					if (j == SWITCH1ON)                     //1-time switch
3244 					{
3245 						sprite[neartagsprite].picnum = GIFTBOX;
3246 						sprite[neartagsprite].lotag = 0;
3247 						sprite[neartagsprite].hitag = 0;
3248 					}
3249 					if (j == GIFTBOX)                       //1-time switch
3250 					{
3251 						sprite[neartagsprite].picnum = SWITCH1ON;
3252 						sprite[neartagsprite].lotag = 0;
3253 						sprite[neartagsprite].hitag = 0;
3254 					}
3255 					if (j == SWITCH2ON) sprite[neartagsprite].picnum = SWITCH2OFF;
3256 					if (j == SWITCH2OFF) sprite[neartagsprite].picnum = SWITCH2ON;
3257 					if (j == SWITCH3ON) sprite[neartagsprite].picnum = SWITCH3OFF;
3258 					if (j == SWITCH3OFF) sprite[neartagsprite].picnum = SWITCH3ON;
3259 
3260 					dax = sprite[neartagsprite].x;
3261 					day = sprite[neartagsprite].y;
3262 					wsayfollow("switch.wav",4096L+(krand()&255)-128,256L,&dax,&day,0);
3263 				}
3264 			}
3265 		}
3266 	}
3267 
3268 	if ((sync[snum].bits & 2048) > 0) {   // Shoot a bullet
3269 		if ((numbombs[snum] == 0) && (((sync[snum].bits >> 13) & 7) == 2) && (myconnectindex == snum))
3270 			locselectedgun = 0;
3271 		if ((nummissiles[snum] == 0) && (((sync[snum].bits >> 13) & 7) == 3) && (myconnectindex == snum))
3272 			locselectedgun = 1;
3273 		if ((numgrabbers[snum] == 0) && (((sync[snum].bits >> 13) & 7) == 4) && (myconnectindex == snum))
3274 			locselectedgun = 1;
3275 
3276 		if ((health[snum] >= 0) || ((krand() & 127) > -health[snum]))
3277 			switch((sync[snum].bits >> 13) & 7) {
3278 				case 0:
3279 					if (lockclock > lastchaingun[snum]+8) {
3280 						lastchaingun[snum] = lockclock;
3281 						shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],0);
3282 					}
3283 					break;
3284 				case 1:
3285 					if ((oflags[snum] & 2048) == 0)
3286 						shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],1);
3287 					break;
3288 				case 2:
3289 					if ((oflags[snum] & 2048) == 0)
3290 						if (numbombs[snum] > 0) {
3291 							shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],2);
3292 							changenumbombs(snum,-1);
3293 						}
3294 					break;
3295 				case 3:
3296 					if ((oflags[snum] & 2048) == 0)
3297 						if (nummissiles[snum] > 0) {
3298 							shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],3);
3299 							changenummissiles(snum,-1);
3300 						}
3301 					break;
3302 				case 4:
3303 					if ((oflags[snum] & 2048) == 0)
3304 						if (numgrabbers[snum] > 0) {
3305 							shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],4);
3306 							changenumgrabbers(snum,-1);
3307 						}
3308 					break;
3309 			}
3310 	}
3311 
3312 	if ((sync[snum].bits&4096) > (oflags[snum]&4096))  //Keypad enter
3313 	{
3314 		dimensionmode[snum]++;
3315 		if (dimensionmode[snum] > 3) dimensionmode[snum] = 1;
3316 	}
3317 
3318 	oflags[snum] = sync[snum].bits;
3319 }
3320 
view(short snum,long * vx,long * vy,long * vz,short * vsectnum,short ang,long horiz)3321 view (short snum, long *vx, long *vy, long *vz,
3322 		short *vsectnum, short ang, long horiz)
3323 {
3324 	spritetype *sp;
3325 	long i, nx, ny, nz, hx, hy, hz, hitx, hity, hitz;
3326 	short bakcstat, hitsect, hitwall, hitsprite, daang;
3327 
3328 	nx = (sintable[(ang+1536)&2047]>>4);
3329 	ny = (sintable[(ang+1024)&2047]>>4);
3330 	nz = (horiz-100)*128;
3331 
3332 	sp = &sprite[snum];
3333 
3334 	bakcstat = sp->cstat;
3335 	sp->cstat &= (short)~0x101;
3336 
3337 	updatesectorz(*vx,*vy,*vz,vsectnum);
3338 	hitscan(*vx,*vy,*vz,*vsectnum,nx,ny,nz,&hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1);
3339 	hx = hitx-(*vx); hy = hity-(*vy);
3340 	if (klabs(nx)+klabs(ny) > klabs(hx)+klabs(hy))
3341 	{
3342 		*vsectnum = hitsect;
3343 		if (hitwall >= 0)
3344 		{
3345 			daang = getangle(wall[wall[hitwall].point2].x-wall[hitwall].x,
3346 								  wall[wall[hitwall].point2].y-wall[hitwall].y);
3347 
3348 			i = nx*sintable[daang]+ny*sintable[(daang+1536)&2047];
3349 			if (klabs(nx) > klabs(ny)) hx -= mulscale28(nx,i);
3350 										 else hy -= mulscale28(ny,i);
3351 		}
3352 		else if (hitsprite < 0)
3353 		{
3354 			if (klabs(nx) > klabs(ny)) hx -= (nx>>5);
3355 										 else hy -= (ny>>5);
3356 		}
3357 		if (klabs(nx) > klabs(ny)) i = divscale16(hx,nx);
3358 									 else i = divscale16(hy,ny);
3359 		if (i < cameradist) cameradist = i;
3360 	}
3361 	*vx = (*vx)+mulscale16(nx,cameradist);
3362 	*vy = (*vy)+mulscale16(ny,cameradist);
3363 	*vz = (*vz)+mulscale16(nz,cameradist);
3364 
3365 	updatesectorz(*vx,*vy,*vz,vsectnum);
3366 
3367 	sp->cstat = bakcstat;
3368 }
3369 
updatesectorz(long x,long y,long z,short * sectnum)3370 void updatesectorz(long x, long y, long z, short *sectnum)
3371 {
3372 	walltype *wal;
3373 	long i, j, cz, fz;
3374 
3375 	getzsofslope(*sectnum,x,y,&cz,&fz);
3376 	if ((z >= cz) && (z <= fz))
3377 		if (inside(x,y,*sectnum) != 0) return;
3378 
3379 	if ((*sectnum >= 0) && (*sectnum < numsectors))
3380 	{
3381 		wal = &wall[sector[*sectnum].wallptr];
3382 		j = sector[*sectnum].wallnum;
3383 		do
3384 		{
3385 			i = wal->nextsector;
3386 			if (i >= 0)
3387 			{
3388 				getzsofslope(i,x,y,&cz,&fz);
3389 				if ((z >= cz) && (z <= fz))
3390 					if (inside(x,y,(short)i) == 1)
3391 						{ *sectnum = i; return; }
3392 			}
3393 			wal++; j--;
3394 		} while (j != 0);
3395 	}
3396 
3397 	for(i=numsectors-1;i>=0;i--)
3398 	{
3399 		getzsofslope(i,x,y,&cz,&fz);
3400 		if ((z >= cz) && (z <= fz))
3401 			if (inside(x,y,(short)i) == 1)
3402 				{ *sectnum = i; return; }
3403 	}
3404 
3405 	*sectnum = -1;
3406 }
3407 
drawscreen(short snum,long dasmoothratio)3408 drawscreen(short snum, long dasmoothratio)
3409 {
3410 	long i, j, k, l, charsperline, templong;
3411 	long x1, y1, x2, y2, ox1, oy1, ox2, oy2, dist, maxdist;
3412 	long cposx, cposy, cposz, choriz, czoom, tposx, tposy;
3413 	long tiltlock, *longptr, ovisibility, oparallaxvisibility;
3414 	short cang, tang, csect;
3415 	char ch, *ptr, *ptr2, *ptr3, *ptr4;
3416 	spritetype *tspr;
3417 
3418 	smoothratio = max(min(dasmoothratio,65536),0);
3419 
3420 	dointerpolations();
3421 
3422 	if ((snum == myconnectindex) && ((networkmode == 1) || (myconnectindex != connecthead)))
3423 	{
3424 		cposx = omyx+mulscale16(myx-omyx,smoothratio);
3425 		cposy = omyy+mulscale16(myy-omyy,smoothratio);
3426 		cposz = omyz+mulscale16(myz-omyz,smoothratio);
3427 		choriz = omyhoriz+mulscale16(myhoriz-omyhoriz,smoothratio);
3428 		cang = omyang+mulscale16((long)(((myang+1024-omyang)&2047)-1024),smoothratio);
3429 	}
3430 	else
3431 	{
3432 		cposx = oposx[snum]+mulscale16(posx[snum]-oposx[snum],smoothratio);
3433 		cposy = oposy[snum]+mulscale16(posy[snum]-oposy[snum],smoothratio);
3434 		cposz = oposz[snum]+mulscale16(posz[snum]-oposz[snum],smoothratio);
3435 		choriz = ohoriz[snum]+mulscale16(horiz[snum]-ohoriz[snum],smoothratio);
3436 		cang = oang[snum]+mulscale16(((ang[snum]+1024-oang[snum])&2047)-1024,smoothratio);
3437 	}
3438 	czoom = ozoom[snum]+mulscale16(zoom[snum]-ozoom[snum],smoothratio);
3439 
3440 	setears(cposx,cposy,(long)sintable[(cang+512)&2047]<<14,(long)sintable[cang&2047]<<14);
3441 
3442 	if (typemode != 0)
3443 	{
3444 		charsperline = 40;
3445 		//if (dimensionmode[snum] == 2) charsperline = 80;
3446 
3447 		for(i=0;i<=typemessageleng;i+=charsperline)
3448 		{
3449 			for(j=0;j<charsperline;j++)
3450 				tempbuf[j] = typemessage[i+j];
3451 			if (typemessageleng < i+charsperline)
3452 			{
3453 				tempbuf[(typemessageleng-i)] = '_';
3454 				tempbuf[(typemessageleng-i)+1] = 0;
3455 			}
3456 			else
3457 				tempbuf[charsperline] = 0;
3458 			//if (dimensionmode[snum] == 3)
3459 				printext256(0L,(i/charsperline)<<3,183,-1,tempbuf,0);
3460 			//else
3461 			//   printext16(0L,((i/charsperline)<<3)+(pageoffset/640),10,-1,tempbuf,0);
3462 		}
3463 	}
3464 	else
3465 	{
3466 		if (dimensionmode[myconnectindex] == 3)
3467 		{
3468 			templong = screensize;
3469 
3470 			if (((loc.bits&32) > (screensizeflag&32)) && (screensize > 64))
3471 			{
3472 				ox1 = ((xdim-screensize)>>1);
3473 				ox2 = ox1+screensize-1;
3474 				oy1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1);
3475 				oy2 = oy1 + scale(screensize,ydim-32,xdim)-1;
3476 				screensize -= (screensize>>3);
3477 
3478 				if (templong > xdim)
3479 				{
3480 					screensize = xdim;
3481 
3482 					flushperms();
3483 
3484 					rotatesprite((xdim-320)<<15,(ydim-32)<<16,65536L,0,STATUSBAR,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L);
3485 					i = ((xdim-320)>>1);
3486 					while (i >= 8) i -= 8, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L);
3487 					if (i >= 4) i -= 4, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L);
3488 					i = ((xdim-320)>>1)+320;
3489 					while (i <= xdim-8) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 8;
3490 					if (i <= xdim-4) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 4;
3491 
3492 					drawstatusbar(screenpeek);   // Andy did this
3493 				}
3494 
3495 				x1 = ((xdim-screensize)>>1);
3496 				x2 = x1+screensize-1;
3497 				y1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1);
3498 				y2 = y1 + scale(screensize,ydim-32,xdim)-1;
3499 				setview(x1,y1,x2,y2);
3500 
3501 				// (ox1,oy1)�����������������Ŀ
3502 				//          �  (x1,y1)        �
3503 				//          �     �����Ŀ     �
3504 				//          �     �     �     �
3505 				//          �     �������     �
3506 				//          �        (x2,y2)  �
3507 				//          �������������������(ox2,oy2)
3508 
3509 				drawtilebackground(0L,0L,BACKGROUND,8,ox1,oy1,x1-1,oy2,0);
3510 				drawtilebackground(0L,0L,BACKGROUND,8,x2+1,oy1,ox2,oy2,0);
3511 				drawtilebackground(0L,0L,BACKGROUND,8,x1,oy1,x2,y1-1,0);
3512 				drawtilebackground(0L,0L,BACKGROUND,8,x1,y2+1,x2,oy2,0);
3513 			}
3514 			if (((loc.bits&16) > (screensizeflag&16)) && (screensize <= xdim))
3515 			{
3516 				screensize += (screensize>>3);
3517 				if ((screensize > xdim) && (templong == xdim))
3518 				{
3519 					screensize = xdim+1;
3520 					x1 = 0; y1 = 0;
3521 					x2 = xdim-1; y2 = ydim-1;
3522 				}
3523 				else
3524 				{
3525 					if (screensize > xdim) screensize = xdim;
3526 					x1 = ((xdim-screensize)>>1);
3527 					x2 = x1+screensize-1;
3528 					y1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1);
3529 					y2 = y1 + scale(screensize,ydim-32,xdim)-1;
3530 				}
3531 				setview(x1,y1,x2,y2);
3532 			}
3533 			screensizeflag = loc.bits;
3534 		}
3535 	}
3536 
3537 	if (dimensionmode[snum] != 2)
3538 	{
3539 		if ((numplayers > 1) && (option[4] == 0))
3540 		{
3541 				//Do not draw other views constantly if they're staying still
3542 				//It's a shame this trick will only work in screen-buffer mode
3543 				//At least screen-buffer mode covers all the HI hi-res modes
3544 			if (vidoption == 2)
3545 			{
3546 				for(i=connecthead;i>=0;i=connectpoint2[i]) frame2draw[i] = 0;
3547 				frame2draw[snum] = 1;
3548 
3549 					//2-1,3-1,4-2
3550 					//5-2,6-2,7-2,8-3,9-3,10-3,11-3,12-4,13-4,14-4,15-4,16-5
3551 				x1 = posx[snum]; y1 = posy[snum];
3552 				for(j=(numplayers>>2)+1;j>0;j--)
3553 				{
3554 					maxdist = 0x80000000;
3555 					for(i=connecthead;i>=0;i=connectpoint2[i])
3556 						if (frame2draw[i] == 0)
3557 						{
3558 							x2 = posx[i]-x1; y2 = posy[i]-y1;
3559 							dist = dmulscale12(x2,x2,y2,y2);
3560 
3561 							if (dist < 64) dist = 16384;
3562 							else if (dist > 16384) dist = 64;
3563 							else dist = 1048576 / dist;
3564 
3565 							dist *= frameskipcnt[i];
3566 
3567 								//Increase frame rate if screen is moving
3568 							if ((posx[i] != oposx[i]) || (posy[i] != oposy[i]) ||
3569 								 (posz[i] != oposz[i]) || (ang[i] != oang[i]) ||
3570 								 (horiz[i] != ohoriz[i])) dist += dist;
3571 
3572 							if (dist > maxdist) maxdist = dist, k = i;
3573 						}
3574 
3575 					for(i=connecthead;i>=0;i=connectpoint2[i])
3576 						frameskipcnt[i] += (frameskipcnt[i]>>3)+1;
3577 					frameskipcnt[k] = 0;
3578 
3579 					frame2draw[k] = 1;
3580 				}
3581 			}
3582 			else
3583 			{
3584 				for(i=connecthead;i>=0;i=connectpoint2[i]) frame2draw[i] = 1;
3585 			}
3586 
3587 			for(i=connecthead,j=0;i>=0;i=connectpoint2[i],j++)
3588 				if (frame2draw[i] != 0)
3589 				{
3590 					if (numplayers <= 4)
3591 					{
3592 						switch(j)
3593 						{
3594 							case 0: setview(0,0,(xdim>>1)-1,(ydim>>1)-1); break;
3595 							case 1: setview((xdim>>1),0,xdim-1,(ydim>>1)-1); break;
3596 							case 2: setview(0,(ydim>>1),(xdim>>1)-1,ydim-1); break;
3597 							case 3: setview((xdim>>1),(ydim>>1),xdim-1,ydim-1); break;
3598 						}
3599 					}
3600 					else
3601 					{
3602 						switch(j)
3603 						{
3604 							case 0: setview(0,0,(xdim>>2)-1,(ydim>>2)-1); break;
3605 							case 1: setview(xdim>>2,0,(xdim>>1)-1,(ydim>>2)-1); break;
3606 							case 2: setview(xdim>>1,0,xdim-(xdim>>2)-1,(ydim>>2)-1); break;
3607 							case 3: setview(xdim-(xdim>>2),0,xdim-1,(ydim>>2)-1); break;
3608 							case 4: setview(0,ydim>>2,(xdim>>2)-1,(ydim>>1)-1); break;
3609 							case 5: setview(xdim>>2,ydim>>2,(xdim>>1)-1,(ydim>>1)-1); break;
3610 							case 6: setview(xdim>>1,ydim>>2,xdim-(xdim>>2)-1,(ydim>>1)-1); break;
3611 							case 7: setview(xdim-(xdim>>2),ydim>>2,xdim-1,(ydim>>1)-1); break;
3612 							case 8: setview(0,ydim>>1,(xdim>>2)-1,ydim-(ydim>>2)-1); break;
3613 							case 9: setview(xdim>>2,ydim>>1,(xdim>>1)-1,ydim-(ydim>>2)-1); break;
3614 							case 10: setview(xdim>>1,ydim>>1,xdim-(xdim>>2)-1,ydim-(ydim>>2)-1); break;
3615 							case 11: setview(xdim-(xdim>>2),ydim>>1,xdim-1,ydim-(ydim>>2)-1); break;
3616 							case 12: setview(0,ydim-(ydim>>2),(xdim>>2)-1,ydim-1); break;
3617 							case 13: setview(xdim>>2,ydim-(ydim>>2),(xdim>>1)-1,ydim-1); break;
3618 							case 14: setview(xdim>>1,ydim-(ydim>>2),xdim-(xdim>>2)-1,ydim-1); break;
3619 							case 15: setview(xdim-(xdim>>2),ydim-(ydim>>2),xdim-1,ydim-1); break;
3620 						}
3621 					}
3622 
3623 					if (i == snum)
3624 					{
3625 						sprite[playersprite[snum]].cstat |= 0x8000;
3626 						drawrooms(cposx,cposy,cposz,cang,choriz,cursectnum[i]);
3627 						sprite[playersprite[snum]].cstat &= ~0x8000;
3628 						analyzesprites(cposx,cposy);
3629 					}
3630 					else
3631 					{
3632 						sprite[playersprite[i]].cstat |= 0x8000;
3633 						drawrooms(posx[i],posy[i],posz[i],ang[i],horiz[i],cursectnum[i]);
3634 						sprite[playersprite[i]].cstat &= ~0x8000;
3635 						analyzesprites(posx[i],posy[i]);
3636 					}
3637 					drawmasks();
3638 					if ((numgrabbers[i] > 0) || (nummissiles[i] > 0) || (numbombs[i] > 0))
3639 						rotatesprite(160<<16,184L<<16,65536,0,GUNONBOTTOM,sector[cursectnum[i]].floorshade,0,2,windowx1,windowy1,windowx2,windowy2);
3640 
3641 					if (lockclock < 384)
3642 					{
3643 						if (lockclock < 128)
3644 							rotatesprite(320<<15,200<<15,lockclock<<9,lockclock<<4,DEMOSIGN,(128-lockclock)>>2,0,1+2,windowx1,windowy1,windowx2,windowy2);
3645 						else if (lockclock < 256)
3646 							rotatesprite(320<<15,200<<15,65536,0,DEMOSIGN,0,0,2,windowx1,windowy1,windowx2,windowy2);
3647 						else
3648 							rotatesprite(320<<15,200<<15,(384-lockclock)<<9,lockclock<<4,DEMOSIGN,(lockclock-256)>>2,0,1+2,windowx1,windowy1,windowx2,windowy2);
3649 					}
3650 
3651 					if (health[i] <= 0)
3652 						rotatesprite(320<<15,200<<15,(-health[i])<<11,(-health[i])<<5,NO,0,0,2,windowx1,windowy1,windowx2,windowy2);
3653 				}
3654 		}
3655 		else
3656 		{
3657 				//Init for screen rotation
3658 			tiltlock = screentilt;
3659 			if ((tiltlock) || (detailmode))
3660 			{
3661 				walock[MAXTILES-2] = 255;
3662 				if (waloff[MAXTILES-2] == 0)
3663 					allocache(&waloff[MAXTILES-2],320L*320L,&walock[MAXTILES-2]);
3664 				if ((tiltlock&1023) == 0)
3665 					setviewtotile(MAXTILES-2,200L>>detailmode,320L>>detailmode);
3666 				else
3667 					setviewtotile(MAXTILES-2,320L>>detailmode,320L>>detailmode);
3668 				if ((tiltlock&1023) == 512)
3669 				{     //Block off unscreen section of 90� tilted screen
3670 					j = ((320-60)>>detailmode);
3671 					for(i=(60>>detailmode)-1;i>=0;i--)
3672 					{
3673 						startumost[i] = 1; startumost[i+j] = 1;
3674 						startdmost[i] = 0; startdmost[i+j] = 0;
3675 					}
3676 				}
3677 
3678 				i = (tiltlock&511); if (i > 256) i = 512-i;
3679 				i = sintable[i+512]*8 + sintable[i]*5L;
3680 				setaspect(i>>1,yxaspect);
3681 			}
3682 
3683 			if ((gotpic[FLOORMIRROR>>3]&(1<<(FLOORMIRROR&7))) > 0)
3684 			{
3685 				dist = 0x7fffffff; i = 0;
3686 				for(k=floormirrorcnt-1;k>=0;k--)
3687 				{
3688 					j = klabs(wall[sector[floormirrorsector[k]].wallptr].x-cposx);
3689 					j += klabs(wall[sector[floormirrorsector[k]].wallptr].y-cposy);
3690 					if (j < dist) dist = j, i = k;
3691 				}
3692 
3693 				j = floormirrorsector[i];
3694 
3695 				if (cameradist < 0) sprite[playersprite[snum]].cstat |= 0x8000;
3696 				drawrooms(cposx,cposy,(sector[j].floorz<<1)-cposz,cang,201-choriz,j);
3697 				sprite[playersprite[snum]].cstat &= ~0x8000;
3698 				analyzesprites(cposx,cposy);
3699 				drawmasks();
3700 
3701 					//Temp horizon
3702 				l = scale(choriz-100,windowx2-windowx1,320)+((windowy1+windowy2)>>1);
3703 				for(y1=windowy1,y2=windowy2;y1<y2;y1++,y2--)
3704 				{
3705 					ptr = (char *)(frameplace+ylookup[y1]);
3706 					ptr2 = (char *)(frameplace+ylookup[y2]);
3707 					ptr3 = palookup[18];
3708 					ptr3 += (min(klabs(y1-l)>>2,31)<<8);
3709 					ptr4 = palookup[18];
3710 					ptr4 += (min(klabs(y2-l)>>2,31)<<8);
3711 
3712 					j = sintable[((y2+totalclock)<<6)&2047];
3713 					j += sintable[((y2-totalclock)<<7)&2047];
3714 					j >>= 14;
3715 
3716 					ptr2 += j;
3717 
3718 					for(x1=windowx1;x1<=windowx2;x1++)
3719 						{ ch = ptr[x1]; ptr[x1] = ptr3[ptr2[x1]]; ptr2[x1] = ptr4[ch]; }
3720 				}
3721 				gotpic[FLOORMIRROR>>3] &= ~(1<<(FLOORMIRROR&7));
3722 			}
3723 
3724 			if (gotpic[DAYSKY>>3]&(1<<(DAYSKY&7)))
3725 			{
3726 				gotpic[DAYSKY>>3] &= ~(1<<(DAYSKY&7));
3727 				pskyoff[0] = 0; pskyoff[1] = 0; pskybits = 1;
3728 			}
3729 			else if (gotpic[NIGHTSKY>>3]&(1<<(NIGHTSKY&7)))
3730 			{
3731 				gotpic[NIGHTSKY>>3] &= ~(1<<(NIGHTSKY&7));
3732 				pskyoff[0] = 0; pskyoff[1] = 0; pskyoff[2] = 0; pskyoff[3] = 0;
3733 				pskyoff[4] = 0; pskyoff[5] = 0; pskyoff[6] = 0; pskyoff[7] = 0;
3734 				pskybits = 3;
3735 			}
3736 
3737 				//Over the shoulder mode
3738 			csect = cursectnum[snum];
3739 			if (cameradist >= 0)
3740 			{
3741 				cang += cameraang;
3742 				view(playersprite[snum],&cposx,&cposy,&cposz,&csect,cang,choriz);
3743 			}
3744 
3745 				//WARNING!  Assuming (MIRRORLABEL&31) = 0 and MAXMIRRORS = 64
3746 			longptr = (long *)FP_OFF(gotpic[MIRRORLABEL>>3]);
3747 			if (longptr[0]|longptr[1])
3748 				for(i=MAXMIRRORS-1;i>=0;i--)
3749 					if (gotpic[(i+MIRRORLABEL)>>3]&(1<<(i&7)))
3750 					{
3751 						gotpic[(i+MIRRORLABEL)>>3] &= ~(1<<(i&7));
3752 
3753 							//Prepare drawrooms for drawing mirror and calculate reflected
3754 							//position into tposx, tposy, and tang (tposz == cposz)
3755 							//Must call preparemirror before drawrooms and
3756 							//          completemirror after drawrooms
3757 						preparemirror(cposx,cposy,cposz,cang,choriz,
3758 									  mirrorwall[i],mirrorsector[i],&tposx,&tposy,&tang);
3759 
3760 						ovisibility = visibility;
3761 						oparallaxvisibility = parallaxvisibility;
3762 						visibility <<= 1;
3763 						parallaxvisibility <<= 1;
3764 						ptr = palookup[0]; palookup[0] = palookup[17]; palookup[17] = ptr;
3765 
3766 						drawrooms(tposx,tposy,cposz,tang,choriz,mirrorsector[i]|MAXSECTORS);
3767 						for(j=0,tspr=&tsprite[0];j<spritesortcnt;j++,tspr++)
3768 							if ((tspr->cstat&48) == 0) tspr->cstat |= 4;
3769 						analyzesprites(tposx,tposy);
3770 						drawmasks();
3771 
3772 						ptr = palookup[0]; palookup[0] = palookup[17]; palookup[17] = ptr;
3773 						visibility = ovisibility;
3774 						parallaxvisibility = oparallaxvisibility;
3775 
3776 						completemirror();   //Reverse screen x-wise in this function
3777 
3778 						break;
3779 					}
3780 
3781 			if (cameradist < 0) sprite[playersprite[snum]].cstat |= 0x8000;
3782 			drawrooms(cposx,cposy,cposz,cang,choriz,csect);
3783 			sprite[playersprite[snum]].cstat &= ~0x8000;
3784 			analyzesprites(cposx,cposy);
3785 			drawmasks();
3786 
3787 			if ((gotpic[FLOORMIRROR>>3]&(1<<(FLOORMIRROR&7))) > 0)
3788 				transarea += (windowx2-windowx1)*(windowy2-windowy1);
3789 
3790 				//Finish for screen rotation
3791 			if ((tiltlock) || (detailmode))
3792 			{
3793 				setviewback();
3794 				i = (tiltlock&511); if (i > 256) i = 512-i;
3795 				i = sintable[i+512]*8 + sintable[i]*5L;
3796 				if (detailmode == 0) i >>= 1;
3797 				rotatesprite(320<<15,200<<15,i,tiltlock+512,MAXTILES-2,0,0,2+4+64,windowx1,windowy1,windowx2,windowy2);
3798 				walock[MAXTILES-2] = 1;
3799 			}
3800 
3801 			if (((numgrabbers[screenpeek] > 0) || (nummissiles[screenpeek] > 0) || (numbombs[screenpeek] > 0)) && (cameradist < 0))
3802 			{
3803 					//Reset startdmost to bottom of screen
3804 				if ((windowx1 == 0) && (windowx2 == 319) && (yxaspect == 65536) && (tiltlock == 0))
3805 				{
3806 					x1 = 160L-(tilesizx[GUNONBOTTOM]>>1); y1 = windowy2+1;
3807 					for(i=0;i<tilesizx[GUNONBOTTOM];i++)
3808 						startdmost[i+x1] = y1;
3809 				}
3810 				rotatesprite(160<<16,184L<<16,65536,0,GUNONBOTTOM,sector[cursectnum[screenpeek]].floorshade,0,2,windowx1,windowy1,windowx2,windowy2);
3811 			}
3812 
3813 			if (cachecount != 0)
3814 			{
3815 				rotatesprite((320-16)<<16,16<<16,32768,0,BUILDDISK,0,0,2+64,windowx1,windowy1,windowx2,windowy2);
3816 				cachecount = 0;
3817 			}
3818 
3819 			if (lockclock < 384)
3820 			{
3821 				if (lockclock < 128)
3822 					rotatesprite(320<<15,200<<15,lockclock<<9,lockclock<<4,DEMOSIGN,(128-lockclock)>>2,0,1+2,windowx1,windowy1,windowx2,windowy2);
3823 				else if (lockclock < 256)
3824 					rotatesprite(320<<15,200<<15,65536,0,DEMOSIGN,0,0,2,windowx1,windowy1,windowx2,windowy2);
3825 				else
3826 					rotatesprite(320<<15,200<<15,(384-lockclock)<<9,lockclock<<4,DEMOSIGN,(lockclock-256)>>2,0,1+2,windowx1,windowy1,windowx2,windowy2);
3827 			}
3828 
3829 			if (health[screenpeek] <= 0)
3830 				rotatesprite(320<<15,200<<15,(-health[screenpeek])<<11,(-health[screenpeek])<<5,NO,0,0,2,windowx1,windowy1,windowx2,windowy2);
3831 		}
3832 	}
3833 
3834 		//Only animate lava if its picnum is on screen
3835 		//gotpic is a bit array where the tile number's bit is set
3836 		//whenever it is drawn (ceilings, walls, sprites, etc.)
3837 	if ((gotpic[SLIME>>3]&(1<<(SLIME&7))) > 0)
3838 	{
3839 		gotpic[SLIME>>3] &= ~(1<<(SLIME&7));
3840 		if (waloff[SLIME] != 0) movelava((char *)waloff[SLIME]);
3841 	}
3842 
3843 	if ((show2dsector[cursectnum[snum]>>3]&(1<<(cursectnum[snum]&7))) == 0)
3844 		searchmap(cursectnum[snum]);
3845 
3846 	if (dimensionmode[snum] != 3)
3847 	{
3848 			//Move back pivot point
3849 		i = scale(czoom,screensize,320);
3850 		if (dimensionmode[snum] == 2)
3851 		{
3852 			clearview(0L);  //Clear screen to specified color
3853 			drawmapview(cposx,cposy,i,cang);
3854 		}
3855 		drawoverheadmap(cposx,cposy,i,cang);
3856 	}
3857 
3858 	if (getmessageleng > 0)
3859 	{
3860 		charsperline = 40;
3861 		//if (dimensionmode[snum] == 2) charsperline = 80;
3862 
3863 		for(i=0;i<=getmessageleng;i+=charsperline)
3864 		{
3865 			for(j=0;j<charsperline;j++)
3866 				tempbuf[j] = getmessage[i+j];
3867 			if (getmessageleng < i+charsperline)
3868 				tempbuf[(getmessageleng-i)] = 0;
3869 			else
3870 				tempbuf[charsperline] = 0;
3871 
3872 			printext256(0L,((i/charsperline)<<3)+(ydim-32-8)-(((getmessageleng-1)/charsperline)<<3),151,-1,tempbuf,0);
3873 		}
3874 		if (totalclock > getmessagetimeoff)
3875 			getmessageleng = 0;
3876 	}
3877 	if ((numplayers >= 2) && (screenpeek != myconnectindex))
3878 	{
3879 		j = 1;
3880 		for(i=connecthead;i>=0;i=connectpoint2[i])
3881 		{
3882 			if (i == screenpeek) break;
3883 			j++;
3884 		}
3885 		sprintf(tempbuf,"(Player %ld's view)",j);
3886 		printext256((xdim>>1)-(strlen(tempbuf)<<2),0,24,-1,tempbuf,0);
3887 	}
3888 
3889 	if (syncstat != 0) printext256(68L,84L,31,0,"OUT OF SYNC!",0);
3890 	if (syncstate != 0) printext256(68L,92L,31,0,"Missed Network packet!",0);
3891 
3892 //   //Uncomment this to test cache locks
3893 //extern long cacnum;
3894 //typedef struct { long *hand, leng; char *lock; } cactype;
3895 //extern cactype cac[];
3896 //
3897 //   j = 0;
3898 //   for(i=0;i<cacnum;i++)
3899 //      if ((*cac[i].lock) >= 200)
3900 //      {
3901 //         sprintf(tempbuf,"Locked- %ld: Leng:%ld, Lock:%ld",i,cac[i].leng,*cac[i].lock);
3902 //         printext256(0L,j,31,-1,tempbuf,1); j += 6;
3903 //      }
3904 
3905 	nextpage();
3906 
3907 	if (keystatus[0x3f])   //F5
3908 	{
3909 		keystatus[0x3f] = 0;
3910 		detailmode ^= 1;
3911 	}
3912 	if (keystatus[0x58])   //F12
3913 	{
3914 		keystatus[0x58] = 0;
3915 		screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]);
3916 	}
3917 	if (keystatus[0x3c])  //F2 (toggle stereo mode)
3918 	{
3919 		keystatus[0x3c] = 0;
3920 		stereomode++; if (stereomode >= 3) stereomode = 0;
3921 		//setstereo(stereomode);
3922 	}
3923 	if (keystatus[0x3e])  //F4 - screen re-size
3924 	{
3925 		keystatus[0x3e] = 0;
3926 
3927 			//cycle through all vesa modes, then screen-buffer mode
3928 		getvalidvesamodes();
3929 		if (vidoption == 1)
3930 		{
3931 			for(i=0;i<validmodecnt;i++)
3932 				if ((validmodexdim[i] == xdim) && (validmodeydim[i] == ydim))
3933 				{
3934 					if (i == validmodecnt-1)
3935 						setgamemode(2,320L,200L);
3936 					else
3937 						setgamemode(1,validmodexdim[i+1],validmodeydim[i+1]);
3938 					screensize = xdim+1;
3939 					break;
3940 				}
3941 		}
3942 		else if (validmodecnt > 0)
3943 		{
3944 			setgamemode(1,validmodexdim[0],validmodeydim[0]);
3945 			screensize = xdim+1;
3946 		}
3947 
3948 		sprintf(getmessage,"Video mode: %ld x %ld",xdim,ydim);
3949 		if (vidoption == 2) strcat(getmessage," (Screen-buffer)");
3950 		getmessageleng = strlen(getmessage);
3951 		getmessagetimeoff = totalclock+120*5;
3952 	}
3953 	if (keystatus[0x57])  //F11 - brightness
3954 	{
3955 		keystatus[0x57] = 0;
3956 		brightness++;
3957 		if (brightness > 8) brightness = 0;
3958 		setbrightness(brightness,(char *)&palette[0]);
3959 	}
3960 	if (stereomode)  //Adjustments for red-blue / crystal eyes modes
3961 	{
3962 		if (keystatus[0x2a]|keystatus[0x36])
3963 		{
3964 			if (keystatus[0xa]) stereopixelwidth = max(stereopixelwidth-1,0);   //Shift (
3965 			if (keystatus[0xb]) stereopixelwidth++;   //Shift )
3966 		}
3967 		else
3968 		{
3969 			if (keystatus[0xa]) stereowidth = max(stereowidth-512,0);   //(
3970 			if (keystatus[0xb]) stereowidth += 512;   //)
3971 		}
3972 	}
3973 
3974 	if (option[4] == 0)           //Single player only keys
3975 	{
3976 		if (keystatus[0xd2])   //Insert - Insert player
3977 		{
3978 			keystatus[0xd2] = 0;
3979 			if (numplayers < MAXPLAYERS)
3980 			{
3981 				connectpoint2[numplayers-1] = numplayers;
3982 				connectpoint2[numplayers] = -1;
3983 
3984 				movefifoend[numplayers] = movefifoend[0];   //HACK 01/05/2000
3985 
3986 				initplayersprite(numplayers);
3987 
3988 				clearallviews(0L);  //Clear screen to specified color
3989 
3990 				numplayers++;
3991 			}
3992 		}
3993 		if (keystatus[0xd3])   //Delete - Delete player
3994 		{
3995 			keystatus[0xd3] = 0;
3996 			if (numplayers > 1)
3997 			{
3998 				numplayers--;
3999 				connectpoint2[numplayers-1] = -1;
4000 
4001 				deletesprite(playersprite[numplayers]);
4002 				playersprite[numplayers] = -1;
4003 
4004 				if (myconnectindex >= numplayers) myconnectindex = 0;
4005 				if (screenpeek >= numplayers) screenpeek = 0;
4006 
4007 				if (numplayers < 2)
4008 					setup3dscreen();
4009 				else
4010 					clearallviews(0L);  //Clear screen to specified color
4011 			}
4012 		}
4013 		if (keystatus[0x46])   //Scroll Lock
4014 		{
4015 			keystatus[0x46] = 0;
4016 
4017 			myconnectindex = connectpoint2[myconnectindex];
4018 			if (myconnectindex < 0) myconnectindex = connecthead;
4019 			screenpeek = myconnectindex;
4020 		}
4021 	}
4022 
4023 	restoreinterpolations();
4024 }
4025 
movethings()4026 movethings()
4027 {
4028 	long i;
4029 
4030 	gotlastpacketclock = totalclock;
4031 	for(i=connecthead;i>=0;i=connectpoint2[i])
4032 	{
4033 		copybufbyte(&ffsync[i],&baksync[movefifoend[i]][i],sizeof(input));
4034 		movefifoend[i] = ((movefifoend[i]+1)&(MOVEFIFOSIZ-1));
4035 	}
4036 }
4037 
fakedomovethings(void)4038 void fakedomovethings(void)
4039 {
4040 	input *syn;
4041 	long i, j, k, doubvel, xvect, yvect, goalz;
4042 	short bakcstat;
4043 
4044 	syn = (input *)&baksync[fakemovefifoplc][myconnectindex];
4045 
4046 	omyx = myx;
4047 	omyy = myy;
4048 	omyz = myz;
4049 	omyang = myang;
4050 	omyhoriz = myhoriz;
4051 
4052 	bakcstat = sprite[playersprite[myconnectindex]].cstat;
4053 	sprite[playersprite[myconnectindex]].cstat &= ~0x101;
4054 
4055 	if ((syn->fvel|syn->svel) != 0)
4056 	{
4057 		doubvel = (TICSPERFRAME<<((syn->bits&256)>0));
4058 
4059 		xvect = 0, yvect = 0;
4060 		if (syn->fvel != 0)
4061 		{
4062 			xvect += ((((long)syn->fvel)*doubvel*(long)sintable[(myang+512)&2047])>>3);
4063 			yvect += ((((long)syn->fvel)*doubvel*(long)sintable[myang&2047])>>3);
4064 		}
4065 		if (syn->svel != 0)
4066 		{
4067 			xvect += ((((long)syn->svel)*doubvel*(long)sintable[myang&2047])>>3);
4068 			yvect += ((((long)syn->svel)*doubvel*(long)sintable[(myang+1536)&2047])>>3);
4069 		}
4070 		if (flytime[myconnectindex] > lockclock) { xvect += xvect; yvect += yvect; }   // DOuble flying speed
4071 		clipmove(&myx,&myy,&myz,&mycursectnum,xvect,yvect,128L,4<<8,4<<8,CLIPMASK0);
4072 	}
4073 
4074 	pushmove(&myx,&myy,&myz,&mycursectnum,128L,4<<8,4<<8,CLIPMASK0);
4075 	getzrange(myx,myy,myz,mycursectnum,&globhiz,&globhihit,&globloz,&globlohit,128L,CLIPMASK0);
4076 
4077 	if (syn->avel != 0)          //ang += avel * constant
4078 	{                         //ENGINE calculates avel for you
4079 		doubvel = TICSPERFRAME;
4080 		if ((syn->bits&256) > 0)  //Lt. shift makes turn velocity 50% faster
4081 			doubvel += (TICSPERFRAME>>1);
4082 		myang += ((((long)syn->avel)*doubvel)>>4);
4083 		myang &= 2047;
4084 	}
4085 
4086 	if (((syn->bits&8) > 0) && (myhoriz > 100-(200>>1))) myhoriz -= 4;   //-
4087 	if (((syn->bits&4) > 0) && (myhoriz < 100+(200>>1))) myhoriz += 4;   //+
4088 
4089 	goalz = globloz-EYEHEIGHT;
4090 	if (sector[mycursectnum].lotag == 4)   //slime sector
4091 		if ((globlohit&0xc000) != 49152)            //You're not on a sprite
4092 		{
4093 			goalz = globloz-(8<<8);
4094 			if (myz >= goalz-(2<<8))
4095 				clipmove(&myx,&myy,&myz,&mycursectnum,-TICSPERFRAME<<14,-TICSPERFRAME<<14,128L,4<<8,4<<8,CLIPMASK0);
4096 		}
4097 	if (goalz < globhiz+(16<<8))   //ceiling&floor too close
4098 		goalz = ((globloz+globhiz)>>1);
4099 
4100 	if (health[myconnectindex] >= 0)
4101 	{
4102 		if ((syn->bits&1) > 0)                         //A (stand high)
4103 		{
4104 			if (flytime[myconnectindex] <= lockclock)
4105 			{
4106 				if (myz >= globloz-(32<<8))
4107 				{
4108 					goalz -= (16<<8);
4109 					if (syn->bits&256) goalz -= (24<<8);
4110 				}
4111 			}
4112 			else
4113 			{
4114 				myzvel -= 192;
4115 				if (syn->bits&256) myzvel -= 192;
4116 			}
4117 		}
4118 		if ((syn->bits&2) > 0)                         //Z (stand low)
4119 		{
4120 			if (flytime[myconnectindex] <= lockclock)
4121 			{
4122 				goalz += (12<<8);
4123 				if (syn->bits&256) goalz += (12<<8);
4124 			}
4125 			else
4126 			{
4127 				myzvel += 192;
4128 				if (syn->bits&256) myzvel += 192;
4129 			}
4130 		}
4131 	}
4132 
4133 	if (flytime[myconnectindex] <= lockclock)
4134 	{
4135 		if (myz < goalz)
4136 			myzvel += (TICSPERFRAME<<4);
4137 		else
4138 			myzvel = (((goalz-myz)*TICSPERFRAME)>>5);
4139 	}
4140 	else
4141 	{
4142 		myzvel -= (myzvel>>2);
4143 		myzvel -= ksgn(myzvel);
4144 	}
4145 
4146 	myz += myzvel;
4147 	if (myz > globloz-(4<<8)) myz = globloz-(4<<8), myzvel = 0;
4148 	if (myz < globhiz+(4<<8)) myz = globhiz+(4<<8), myzvel = 0;
4149 
4150 	sprite[playersprite[myconnectindex]].cstat = bakcstat;
4151 
4152 	myxbak[fakemovefifoplc] = myx;
4153 	myybak[fakemovefifoplc] = myy;
4154 	myzbak[fakemovefifoplc] = myz;
4155 	myangbak[fakemovefifoplc] = myang;
4156 	myhorizbak[fakemovefifoplc] = myhoriz;
4157 	fakemovefifoplc = (fakemovefifoplc+1)&(MOVEFIFOSIZ-1);
4158 }
4159 
4160 	//Prediction correction
fakedomovethingscorrect()4161 fakedomovethingscorrect()
4162 {
4163 	long i;
4164 
4165 	if ((networkmode == 0) && (myconnectindex == connecthead)) return;
4166 
4167 	i = ((movefifoplc-1)&(MOVEFIFOSIZ-1));
4168 
4169 	if ((posx[myconnectindex] == myxbak[i]) &&
4170 		 (posy[myconnectindex] == myybak[i]) &&
4171 		 (posz[myconnectindex] == myzbak[i]) &&
4172 		 (horiz[myconnectindex] == myhorizbak[i]) &&
4173 		 (ang[myconnectindex] == myangbak[i]))
4174 		 return;
4175 
4176 		//Re-start fakedomovethings back to place of error
4177 	myx = omyx = posx[myconnectindex];
4178 	myy = omyy = posy[myconnectindex];
4179 	myz = omyz = posz[myconnectindex]; myzvel = hvel[myconnectindex];
4180 	myang = omyang = ang[myconnectindex];
4181 	mycursectnum = mycursectnum;
4182 	myhoriz = omyhoriz = horiz[myconnectindex];
4183 
4184 	fakemovefifoplc = movefifoplc;
4185 	while (fakemovefifoplc != movefifoend[myconnectindex]) fakedomovethings();
4186 }
4187 
domovethings()4188 domovethings()
4189 {
4190 	short i, j, startwall, endwall;
4191 	spritetype *spr;
4192 	walltype *wal;
4193 	point3d *ospr;
4194 
4195 	nummoves++;
4196 
4197 	for(i=connecthead;i>=0;i=connectpoint2[i])
4198 		copybufbyte(&baksync[movefifoplc][i],&sync[i],sizeof(input));
4199 	movefifoplc = ((movefifoplc+1)&(MOVEFIFOSIZ-1));
4200 
4201 	if (option[4] != 0)
4202 	{
4203 		syncval[syncvalhead] = (char)(randomseed&255);
4204 		syncvalhead = ((syncvalhead+1)&(MOVEFIFOSIZ-1));
4205 	}
4206 
4207 	for(i=connecthead;i>=0;i=connectpoint2[i])
4208 	{
4209 		oposx[i] = posx[i];
4210 		oposy[i] = posy[i];
4211 		oposz[i] = posz[i];
4212 		ohoriz[i] = horiz[i];
4213 		ozoom[i] = zoom[i];
4214 		oang[i] = ang[i];
4215 	}
4216 
4217 	for(i=NUMSTATS-1;i>=0;i--)
4218 		if (statrate[i] >= 0)
4219 			for(j=headspritestat[i];j>=0;j=nextspritestat[j])
4220 				if (((nummoves-j)&statrate[i]) == 0)
4221 					copybuf(&sprite[j].x,&osprite[j].x,3);
4222 
4223 	for(i=connecthead;i>=0;i=connectpoint2[i])
4224 		ocursectnum[i] = cursectnum[i];
4225 
4226 	updateinterpolations();
4227 
4228 	if ((numplayers <= 2) && (recstat == 1))
4229 	{
4230 		j = 0;
4231 		for(i=connecthead;i>=0;i=connectpoint2[i])
4232 		{
4233 			copybufbyte(&sync[i],&recsync[reccnt][j],sizeof(input));
4234 			j++;
4235 		}
4236 		reccnt++; if (reccnt > 16383) reccnt = 16383;
4237 	}
4238 
4239 	lockclock += TICSPERFRAME;
4240 	drawstatusflytime(screenpeek);   // Andy did this
4241 
4242 	if (cameradist >= 0)
4243 	{
4244 		cameradist = min(cameradist+((totalclock-cameraclock)<<10),65536);
4245 		if (keystatus[0x52])       //0
4246 			cameraang -= ((totalclock-cameraclock)<<(2+(keystatus[0x2a]|keystatus[0x36])));
4247 		if (keystatus[0x53])       //.
4248 			cameraang += ((totalclock-cameraclock)<<(2+(keystatus[0x2a]|keystatus[0x36])));
4249 		cameraclock = totalclock;
4250 	}
4251 
4252 	for(i=connecthead;i>=0;i=connectpoint2[i])
4253 	{
4254 		processinput(i);                        //Move player
4255 
4256 		checktouchsprite(i,cursectnum[i]);      //Pick up coins
4257 		startwall = sector[cursectnum[i]].wallptr;
4258 		endwall = startwall + sector[cursectnum[i]].wallnum;
4259 		for(j=startwall,wal=&wall[j];j<endwall;j++,wal++)
4260 			if (wal->nextsector >= 0) checktouchsprite(i,wal->nextsector);
4261 	}
4262 
4263 	doanimations();
4264 	tagcode();            //Door code, moving sector code, other stuff
4265 	statuslistcode();     //Monster / bullet code / explosions
4266 
4267 	fakedomovethingscorrect();
4268 
4269 	checkmasterslaveswitch();
4270 }
4271 
getinput()4272 getinput()
4273 {
4274 	char ch, keystate, *ptr;
4275 	long i, j, k;
4276 	short mousx, mousy, bstatus;
4277 
4278 	if (typemode == 0)           //if normal game keys active
4279 	{
4280 		if (keystatus[keys[15]])
4281 		{
4282 			keystatus[keys[15]] = 0;
4283 
4284 			screenpeek = connectpoint2[screenpeek];
4285 			if (screenpeek < 0) screenpeek = connecthead;
4286 			drawstatusbar(screenpeek);   // Andy did this
4287 		}
4288 
4289 		for(i=7;i>=0;i--)
4290 			if (keystatus[i+2])
4291 				{ keystatus[i+2] = 0; locselectedgun = i; break; }
4292 	}
4293 
4294 
4295 		//KEYTIMERSTUFF
4296 	if (!keystatus[keys[5]])
4297 	{
4298 		if (keystatus[keys[2]]) avel = max(avel-16*TICSPERFRAME,-128);
4299 		if (keystatus[keys[3]]) avel = min(avel+16*TICSPERFRAME,127);
4300 	}
4301 	else
4302 	{
4303 		if (keystatus[keys[2]]) svel = min(svel+8*TICSPERFRAME,127);
4304 		if (keystatus[keys[3]]) svel = max(svel-8*TICSPERFRAME,-128);
4305 	}
4306 	if (keystatus[keys[0]]) fvel = min(fvel+8*TICSPERFRAME,127);
4307 	if (keystatus[keys[1]]) fvel = max(fvel-8*TICSPERFRAME,-128);
4308 	if (keystatus[keys[12]]) svel = min(svel+8*TICSPERFRAME,127);
4309 	if (keystatus[keys[13]]) svel = max(svel-8*TICSPERFRAME,-128);
4310 
4311 	if (avel < 0) avel = min(avel+12*TICSPERFRAME,0);
4312 	if (avel > 0) avel = max(avel-12*TICSPERFRAME,0);
4313 	if (svel < 0) svel = min(svel+2*TICSPERFRAME,0);
4314 	if (svel > 0) svel = max(svel-2*TICSPERFRAME,0);
4315 	if (fvel < 0) fvel = min(fvel+2*TICSPERFRAME,0);
4316 	if (fvel > 0) fvel = max(fvel-2*TICSPERFRAME,0);
4317 
4318 	if ((option[4] == 0) && (numplayers >= 2))
4319 	{
4320 		if (!keystatus[0x4f])
4321 		{
4322 			if (keystatus[0x4b]) avel2 = max(avel2-16*TICSPERFRAME,-128);
4323 			if (keystatus[0x4d]) avel2 = min(avel2+16*TICSPERFRAME,127);
4324 		}
4325 		else
4326 		{
4327 			if (keystatus[0x4b]) svel2 = min(svel2+8*TICSPERFRAME,127);
4328 			if (keystatus[0x4d]) svel2 = max(svel2-8*TICSPERFRAME,-128);
4329 		}
4330 		if (keystatus[0x48]) fvel2 = min(fvel2+8*TICSPERFRAME,127);
4331 		if (keystatus[0x4c]) fvel2 = max(fvel2-8*TICSPERFRAME,-128);
4332 
4333 		if (avel2 < 0) avel2 = min(avel2+12*TICSPERFRAME,0);
4334 		if (avel2 > 0) avel2 = max(avel2-12*TICSPERFRAME,0);
4335 		if (svel2 < 0) svel2 = min(svel2+2*TICSPERFRAME,0);
4336 		if (svel2 > 0) svel2 = max(svel2-2*TICSPERFRAME,0);
4337 		if (fvel2 < 0) fvel2 = min(fvel2+2*TICSPERFRAME,0);
4338 		if (fvel2 > 0) fvel2 = max(fvel2-2*TICSPERFRAME,0);
4339 	}
4340 
4341 	if (keystatus[0x1a]) screentilt += ((4*TICSPERFRAME)<<(keystatus[0x2a]|keystatus[0x36]));
4342 	if (keystatus[0x1b]) screentilt -= ((4*TICSPERFRAME)<<(keystatus[0x2a]|keystatus[0x36]));
4343 
4344 	i = (TICSPERFRAME<<1);
4345 	while ((screentilt != 0) && (i > 0))
4346 		{ screentilt = ((screentilt+ksgn(screentilt-1024))&2047); i--; }
4347 	if (keystatus[0x28]) screentilt = 1536;
4348 
4349 
4350 	loc.fvel = min(max(fvel,-128+8),127-8);
4351 	loc.svel = min(max(svel,-128+8),127-8);
4352 	loc.avel = min(max(avel,-128+16),127-16);
4353 
4354 	getmousevalues(&mousx,&mousy,&bstatus);
4355 	loc.avel = min(max(loc.avel+(mousx<<3),-128),127);
4356 	loc.fvel = min(max(loc.fvel-(mousy<<3),-128),127);
4357 
4358 	loc.bits = (locselectedgun<<13);
4359 	if (typemode == 0)           //if normal game keys active
4360 	{
4361 		loc.bits |= (keystatus[0x32]<<9);                 //M (be master)
4362 		loc.bits |= ((keystatus[keys[14]]==1)<<12);       //Map mode
4363 	}
4364 	loc.bits |= keystatus[keys[8]];                   //Stand high
4365 	loc.bits |= (keystatus[keys[9]]<<1);              //Stand low
4366 	loc.bits |= (keystatus[keys[16]]<<4);             //Zoom in
4367 	loc.bits |= (keystatus[keys[17]]<<5);             //Zoom out
4368 	loc.bits |= (keystatus[keys[4]]<<8);                 //Run
4369 	loc.bits |= (keystatus[keys[10]]<<2);                //Look up
4370 	loc.bits |= (keystatus[keys[11]]<<3);                //Look down
4371 	loc.bits |= ((keystatus[keys[7]]==1)<<10);           //Space
4372 	loc.bits |= ((keystatus[keys[6]]==1)<<11);           //Shoot
4373 	loc.bits |= (((bstatus&6)>(oldmousebstatus&6))<<10); //Space
4374 	loc.bits |= (((bstatus&1)>(oldmousebstatus&1))<<11); //Shoot
4375 
4376 	oldmousebstatus = bstatus;
4377 	if (((loc.bits&2048) > 0) && (locselectedgun == 1))
4378 		oldmousebstatus &= ~1;     //Allow continous fire with mouse for chain gun
4379 
4380 		//PRIVATE KEYS:
4381 	if (keystatus[0xb7])  //Printscreen
4382 	{
4383 		keystatus[0xb7] = 0;
4384 		printscreeninterrupt();
4385 	}
4386 
4387 	if (keystatus[0x2f])       //V
4388 	{
4389 		keystatus[0x2f] = 0;
4390 		if (cameradist < 0) cameradist = 0; else cameradist = -1;
4391 		cameraang = 0;
4392 	}
4393 
4394 	if (typemode == 0)           //if normal game keys active
4395 	{
4396 		if (keystatus[0x19])  //P
4397 		{
4398 			keystatus[0x19] = 0;
4399 			parallaxtype++;
4400 			if (parallaxtype > 2) parallaxtype = 0;
4401 		}
4402 		if (keystatus[0x38]|keystatus[0xb8])  //ALT
4403 		{
4404 			if (keystatus[0x4a])  // Keypad -
4405 				visibility = min(visibility+(visibility>>3),16384);
4406 			if (keystatus[0x4e])  // Keypad +
4407 				visibility = max(visibility-(visibility>>3),128);
4408 		}
4409 
4410 		if (keystatus[keys[18]])   //Typing mode
4411 		{
4412 			keystatus[keys[18]] = 0;
4413 			typemode = 1;
4414 			keyfifoplc = keyfifoend;      //Reset keyboard fifo
4415 		}
4416 	}
4417 	else
4418 	{
4419 		while (keyfifoplc != keyfifoend)
4420 		{
4421 			ch = keyfifo[keyfifoplc];
4422 			keystate = keyfifo[(keyfifoplc+1)&(KEYFIFOSIZ-1)];
4423 			keyfifoplc = ((keyfifoplc+2)&(KEYFIFOSIZ-1));
4424 
4425 			if (keystate != 0)
4426 			{
4427 				if (ch == 0xe)   //Backspace
4428 				{
4429 					if (typemessageleng == 0) { typemode = 0; break; }
4430 					typemessageleng--;
4431 				}
4432 				if (ch == 0xf)
4433 				{
4434 					keystatus[0xf] = 0;
4435 					typemode = 0;
4436 					break;
4437 				}
4438 				if ((ch == 0x1c) || (ch == 0x9c))  //Either ENTER
4439 				{
4440 					keystatus[0x1c] = 0; keystatus[0x9c] = 0;
4441 					if (typemessageleng > 0)
4442 					{
4443 						packbuf[0] = 2;          //Sending text is message type 4
4444 						for(j=typemessageleng-1;j>=0;j--)
4445 							packbuf[j+1] = typemessage[j];
4446 
4447 						for(i=connecthead;i>=0;i=connectpoint2[i])
4448 							if (i != myconnectindex)
4449 								sendpacket(i,packbuf,typemessageleng+1);
4450 
4451 						typemessageleng = 0;
4452 					}
4453 					typemode = 0;
4454 					break;
4455 				}
4456 
4457 				if ((typemessageleng < 159) && (ch < 128))
4458 				{
4459 					if (keystatus[0x2a]|keystatus[0x36])
4460 						ch = scantoascwithshift[ch];
4461 					else
4462 						ch = scantoasc[ch];
4463 
4464 					if (ch != 0) typemessage[typemessageleng++] = ch;
4465 				}
4466 			}
4467 		}
4468 			//Here's a trick of making key repeat after a 1/2 second
4469 		if (keystatus[0xe])
4470 		{
4471 			if (keystatus[0xe] < 30)
4472 				keystatus[0xe] += TICSPERFRAME;
4473 			else
4474 			{
4475 				if (typemessageleng == 0)
4476 					typemode = 0;
4477 				else
4478 					typemessageleng--;
4479 			}
4480 		}
4481 	}
4482 }
4483 
initplayersprite(short snum)4484 initplayersprite(short snum)
4485 {
4486 	long i;
4487 
4488 	if (playersprite[snum] >= 0) return;
4489 
4490 	spawnsprite(playersprite[snum],posx[snum],posy[snum],posz[snum]+EYEHEIGHT,
4491 		1+256,0,snum,32,64,64,0,0,PLAYER,ang[snum],0,0,0,snum+4096,
4492 		cursectnum[snum],8,0,0,0);
4493 
4494 	switch(snum)
4495 	{
4496 		case 1: for(i=0;i<32;i++) tempbuf[i+192] = i+128; break; //green->red
4497 		case 2: for(i=0;i<32;i++) tempbuf[i+192] = i+32; break;  //green->blue
4498 		case 3: for(i=0;i<32;i++) tempbuf[i+192] = i+224; break; //green->pink
4499 		case 4: for(i=0;i<32;i++) tempbuf[i+192] = i+64; break;  //green->brown
4500 		case 5: for(i=0;i<32;i++) tempbuf[i+192] = i+96; break;
4501 		case 6: for(i=0;i<32;i++) tempbuf[i+192] = i+160; break;
4502 		case 7: for(i=0;i<32;i++) tempbuf[i+192] = i+192; break;
4503 		default: for(i=0;i<256;i++) tempbuf[i] = i; break;
4504 	}
4505 	makepalookup(snum,tempbuf,0,0,0,1);
4506 }
4507 
playback()4508 playback()
4509 {
4510 	long i, j, k;
4511 
4512 	ready2send = 0;
4513 	recstat = 0; i = reccnt;
4514 	while (!keystatus[1])
4515 	{
4516 		while (totalclock >= lockclock+TICSPERFRAME)
4517 		{
4518 			if (i >= reccnt)
4519 			{
4520 				prepareboard(boardfilename);
4521 				for(i=connecthead;i>=0;i=connectpoint2[i])
4522 					initplayersprite((short)i);
4523 				totalclock = 0;
4524 				i = 0;
4525 			}
4526 
4527 			k = 0;
4528 			for(j=connecthead;j>=0;j=connectpoint2[j])
4529 			{
4530 				copybufbyte(&recsync[i][k],&ffsync[j],sizeof(input));
4531 				k++;
4532 			}
4533 			movethings(); domovethings();
4534 			i++;
4535 		}
4536 		drawscreen(screenpeek,(totalclock-gotlastpacketclock)*(65536/(TIMERINTSPERSECOND/MOVESPERSECOND)));
4537 
4538 		if (keystatus[keys[15]])
4539 		{
4540 			keystatus[keys[15]] = 0;
4541 			screenpeek = connectpoint2[screenpeek];
4542 			if (screenpeek < 0) screenpeek = connecthead;
4543 			drawstatusbar(screenpeek);   // Andy did this
4544 		}
4545 		if (keystatus[keys[14]])
4546 		{
4547 			keystatus[keys[14]] = 0;
4548 			dimensionmode[screenpeek]++;
4549 			if (dimensionmode[screenpeek] > 3) dimensionmode[screenpeek] = 1;
4550 		}
4551 	}
4552 
4553 	musicoff();
4554 	uninitmultiplayers();
4555 	uninittimer();
4556 	uninitkeys();
4557 	uninitengine();
4558 	uninitsb();
4559 	uninitgroupfile();
4560 	setvmode(0x3);        //Set back to text mode
4561 	exit(0);
4562 }
4563 
setup3dscreen()4564 setup3dscreen()
4565 {
4566 	long i, dax, day, dax2, day2;
4567 
4568 	i = setgamemode(option[0],vesares[option[6]&15][0],vesares[option[6]&15][1]);
4569 	if (i < 0)
4570 	{
4571 		printf("VESA driver for (%ld * %ld) not found/supported.\n",xdim,ydim);
4572 		printf("   Press ENTER to play in NORMAL mode instead\n");
4573 		printf("   Press ESC to quit to DOS\n");
4574 		keystatus[1] = keystatus[0x1c] = keystatus[0x9c] = 0;
4575 		while (!keystatus[1])
4576 			if (keystatus[0x1c]|keystatus[0x9c])
4577 				{ option[0] = vidoption = 2; i = setgamemode(option[0],vesares[option[6]&15][0],vesares[option[6]&15][1]); break; }
4578 	}
4579 	if (i < 0)
4580 	{
4581 		sendlogoff();
4582 		musicoff();
4583 		uninitmultiplayers();
4584 		uninittimer();
4585 		uninitkeys();
4586 		uninitengine();
4587 		uninitsb();
4588 		uninitgroupfile();
4589 		exit(0);
4590 	}
4591 
4592 	  //Make that ugly pink into black in case it ever shows up!
4593 	i = 0L;
4594 	VBE_setPalette(255,1,(char *)&i);
4595 	//outp(0x3c8,255); outp(0x3c9,0); outp(0x3c9,0); outp(0x3c9,0);
4596 
4597 	screensize = xdim;
4598 	if (screensize > xdim)
4599 	{
4600 		dax = 0; day = 0;
4601 		dax2 = xdim-1; day2 = ydim-1;
4602 	}
4603 	else
4604 	{
4605 		dax = ((xdim-screensize)>>1);
4606 		dax2 = dax+screensize-1;
4607 		day = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1);
4608 		day2 = day + scale(screensize,ydim-32,xdim)-1;
4609 		setview(dax,day,dax2,day2);
4610 	}
4611 
4612 	flushperms();
4613 
4614 	if (screensize < xdim)
4615 		drawtilebackground(0L,0L,BACKGROUND,8,0L,0L,xdim-1L,ydim-1L,0);      //Draw background
4616 
4617 	if (screensize <= xdim)
4618 	{
4619 		rotatesprite((xdim-320)<<15,(ydim-32)<<16,65536L,0,STATUSBAR,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L);
4620 		i = ((xdim-320)>>1);
4621 		while (i >= 8) i -= 8, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L);
4622 		if (i >= 4) i -= 4, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L);
4623 		i = ((xdim-320)>>1)+320;
4624 		while (i <= xdim-8) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 8;
4625 		if (i <= xdim-4) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 4;
4626 
4627 		drawstatusbar(screenpeek);   // Andy did this
4628 	}
4629 }
4630 
findrandomspot(long * x,long * y,short * sectnum)4631 findrandomspot(long *x, long *y, short *sectnum)
4632 {
4633 	short startwall, endwall, s, dasector;
4634 	long dax, day, daz, minx, maxx, miny, maxy, cnt;
4635 
4636 	for(cnt=256;cnt>=0;cnt--)
4637 	{
4638 		do
4639 		{
4640 			dasector = mulscale16(krand(),numsectors);
4641 		} while ((sector[dasector].ceilingz+(8<<8) >= sector[dasector].floorz) || ((sector[dasector].lotag|sector[dasector].hitag) != 0) || ((sector[dasector].floorstat&1) != 0));
4642 
4643 		startwall = sector[dasector].wallptr;
4644 		endwall = startwall+sector[dasector].wallnum;
4645 		if (endwall <= startwall) continue;
4646 
4647 		dax = 0L;
4648 		day = 0L;
4649 		minx = 0x7fffffff; maxx = 0x80000000;
4650 		miny = 0x7fffffff; maxy = 0x80000000;
4651 
4652 		for(s=startwall;s<endwall;s++)
4653 		{
4654 			dax += wall[s].x;
4655 			day += wall[s].y;
4656 			if (wall[s].x < minx) minx = wall[s].x;
4657 			if (wall[s].x > maxx) maxx = wall[s].x;
4658 			if (wall[s].y < miny) miny = wall[s].y;
4659 			if (wall[s].y > maxy) maxy = wall[s].y;
4660 		}
4661 
4662 		if ((maxx-minx <= 256) || (maxy-miny <= 256)) continue;
4663 
4664 		dax /= (endwall-startwall);
4665 		day /= (endwall-startwall);
4666 
4667 		if (inside(dax,day,dasector) == 0) continue;
4668 
4669 		daz = sector[dasector].floorz-(32<<8);
4670 		if (pushmove(&dax,&day,&daz,&dasector,128L,4<<8,4<<8,CLIPMASK0) < 0) continue;
4671 
4672 		*x = dax; *y = day; *sectnum = dasector;
4673 		return;
4674 	}
4675 }
4676 
warp(long * x,long * y,long * z,short * daang,short * dasector)4677 warp(long *x, long *y, long *z, short *daang, short *dasector)
4678 {
4679 	short startwall, endwall, s;
4680 	long i, j, dax, day, ox, oy;
4681 
4682 	ox = *x; oy = *y;
4683 
4684 	for(i=0;i<warpsectorcnt;i++)
4685 		if (warpsectorlist[i] == *dasector)
4686 		{
4687 			j = sector[*dasector].hitag;
4688 			do
4689 			{
4690 				i++;
4691 				if (i >= warpsectorcnt) i = 0;
4692 			} while (sector[warpsectorlist[i]].hitag != j);
4693 			*dasector = warpsectorlist[i];
4694 			break;
4695 		}
4696 
4697 		//Find center of sector
4698 	startwall = sector[*dasector].wallptr;
4699 	endwall = startwall+sector[*dasector].wallnum;
4700 	dax = 0L, day = 0L;
4701 	for(s=startwall;s<endwall;s++)
4702 	{
4703 		dax += wall[s].x, day += wall[s].y;
4704 		if (wall[s].nextsector >= 0)
4705 			i = s;
4706 	}
4707 	*x = dax / (endwall-startwall);
4708 	*y = day / (endwall-startwall);
4709 	*z = sector[*dasector].floorz-(32<<8);
4710 	updatesector(*x,*y,dasector);
4711 	dax = ((wall[i].x+wall[wall[i].point2].x)>>1);
4712 	day = ((wall[i].y+wall[wall[i].point2].y)>>1);
4713 	*daang = getangle(dax-*x,day-*y);
4714 
4715 	wsayfollow("warp.wav",3072L+(krand()&127)-64,192L,&ox,&oy,0);
4716 	wsayfollow("warp.wav",4096L+(krand()&127)-64,256L,x,y,0);
4717 }
4718 
warpsprite(short spritenum)4719 warpsprite(short spritenum)
4720 {
4721 	short dasectnum;
4722 
4723 	dasectnum = sprite[spritenum].sectnum;
4724 	warp(&sprite[spritenum].x,&sprite[spritenum].y,&sprite[spritenum].z,
4725 		  &sprite[spritenum].ang,&dasectnum);
4726 
4727 	copybuf(&sprite[spritenum].x,&osprite[spritenum].x,3);
4728 	changespritesect(spritenum,dasectnum);
4729 
4730 	show2dsprite[spritenum>>3] &= ~(1<<(spritenum&7));
4731 	if (show2dsector[dasectnum>>3]&(1<<(dasectnum&7)))
4732 		show2dsprite[spritenum>>3] |= (1<<(spritenum&7));
4733 }
4734 
initlava()4735 initlava()
4736 {
4737 	long x, y, z, r;
4738 
4739 	for(z=0;z<32;z++) lavaradcnt[z] = 0;
4740 	for(x=-16;x<=16;x++)
4741 		for(y=-16;y<=16;y++)
4742 		{
4743 			r = ksqrt(x*x + y*y);
4744 			lavaradx[r][lavaradcnt[r]] = x;
4745 			lavarady[r][lavaradcnt[r]] = y;
4746 			lavaradcnt[r]++;
4747 		}
4748 
4749 	for(z=0;z<16;z++)
4750 		lavadropsizlookup[z] = 8 / (ksqrt(z)+1);
4751 
4752 	for(z=0;z<LAVASIZ;z++)
4753 		lavainc[z] = klabs((((z^17)>>4)&7)-4)+12;
4754 
4755 	lavanumdrops = 0;
4756 	lavanumframes = 0;
4757 }
4758 
4759 #pragma aux addlava =\
4760 	"mov al, byte ptr [ebx-133]",\
4761 	"mov dl, byte ptr [ebx-1]",\
4762 	"add al, byte ptr [ebx-132]",\
4763 	"add dl, byte ptr [ebx+131]",\
4764 	"add al, byte ptr [ebx-131]",\
4765 	"add dl, byte ptr [ebx+132]",\
4766 	"add al, byte ptr [ebx+1]",\
4767 	"add al, dl",\
4768 	parm [ebx]\
4769 	modify exact [eax edx]\
4770 
movelava(char * dapic)4771 movelava(char *dapic)
4772 {
4773 	long i, j, x, y, z, zz, dalavadropsiz, dadropsizlookup;
4774 	long dalavax, dalavay, *ptr, *ptr2;
4775 
4776 	for(z=min(LAVAMAXDROPS-lavanumdrops-1,3);z>=0;z--)
4777 	{
4778 		lavadropx[lavanumdrops] = (rand()&(LAVASIZ-1));
4779 		lavadropy[lavanumdrops] = (rand()&(LAVASIZ-1));
4780 		lavadropsiz[lavanumdrops] = 1;
4781 		lavanumdrops++;
4782 	}
4783 
4784 	for(z=lavanumdrops-1;z>=0;z--)
4785 	{
4786 		dadropsizlookup = lavadropsizlookup[lavadropsiz[z]]*(((z&1)<<1)-1);
4787 		dalavadropsiz = lavadropsiz[z];
4788 		dalavax = lavadropx[z]; dalavay = lavadropy[z];
4789 		for(zz=lavaradcnt[lavadropsiz[z]]-1;zz>=0;zz--)
4790 		{
4791 			i = (((lavaradx[dalavadropsiz][zz]+dalavax)&(LAVASIZ-1))<<LAVALOGSIZ);
4792 			i += ((lavarady[dalavadropsiz][zz]+dalavay)&(LAVASIZ-1));
4793 			dapic[i] += dadropsizlookup;
4794 			if (dapic[i] < 192) dapic[i] = 192;
4795 		}
4796 
4797 		lavadropsiz[z]++;
4798 		if (lavadropsiz[z] > 10)
4799 		{
4800 			lavanumdrops--;
4801 			lavadropx[z] = lavadropx[lavanumdrops];
4802 			lavadropy[z] = lavadropy[lavanumdrops];
4803 			lavadropsiz[z] = lavadropsiz[lavanumdrops];
4804 		}
4805 	}
4806 
4807 		//Back up dapic with 1 pixel extra on each boundary
4808 		//(to prevent anding for wrap-around)
4809 	ptr = (long *)dapic;
4810 	ptr2 = (long *)((LAVASIZ+4)+1+((long)lavabakpic));
4811 	for(x=0;x<LAVASIZ;x++)
4812 	{
4813 		for(y=(LAVASIZ>>2);y>0;y--) *ptr2++ = ((*ptr++)&0x1f1f1f1f);
4814 		ptr2++;
4815 	}
4816 	for(y=0;y<LAVASIZ;y++)
4817 	{
4818 		lavabakpic[y+1] = (dapic[y+((LAVASIZ-1)<<LAVALOGSIZ)]&31);
4819 		lavabakpic[y+1+(LAVASIZ+1)*(LAVASIZ+4)] = (dapic[y]&31);
4820 	}
4821 	for(x=0;x<LAVASIZ;x++)
4822 	{
4823 		lavabakpic[(x+1)*(LAVASIZ+4)] = (dapic[(x<<LAVALOGSIZ)+(LAVASIZ-1)]&31);
4824 		lavabakpic[(x+1)*(LAVASIZ+4)+(LAVASIZ+1)] = (dapic[x<<LAVALOGSIZ]&31);
4825 	}
4826 	lavabakpic[0] = (dapic[LAVASIZ*LAVASIZ-1]&31);
4827 	lavabakpic[LAVASIZ+1] = (dapic[LAVASIZ*(LAVASIZ-1)]&31);
4828 	lavabakpic[(LAVASIZ+4)*(LAVASIZ+1)] = (dapic[LAVASIZ-1]&31);
4829 	lavabakpic[(LAVASIZ+4)*(LAVASIZ+2)-1] = (dapic[0]&31);
4830 
4831 	ptr = (long *)dapic;
4832 	for(x=0;x<LAVASIZ;x++)
4833 	{
4834 		i = (long)&lavabakpic[(x+1)*(LAVASIZ+4)+1];
4835 		j = i+LAVASIZ;
4836 		for(y=i;y<j;y+=4)
4837 		{
4838 			*ptr++ = ((addlava(y+0)&0xf8)>>3)+
4839 						((addlava(y+1)&0xf8)<<5)+
4840 						((addlava(y+2)&0xf8)<<13)+
4841 						((addlava(y+3)&0xf8)<<21)+
4842 						0xc2c2c2c2;
4843 		}
4844 	}
4845 
4846 	lavanumframes++;
4847 }
4848 
doanimations()4849 doanimations()
4850 {
4851 	long i, j;
4852 
4853 	for(i=animatecnt-1;i>=0;i--)
4854 	{
4855 		j = *animateptr[i];
4856 
4857 		if (j < animategoal[i])
4858 			j = min(j+animatevel[i]*TICSPERFRAME,animategoal[i]);
4859 		else
4860 			j = max(j-animatevel[i]*TICSPERFRAME,animategoal[i]);
4861 		animatevel[i] += animateacc[i];
4862 
4863 		*animateptr[i] = j;
4864 
4865 		if (j == animategoal[i])
4866 		{
4867 			animatecnt--;
4868 			if (i != animatecnt)
4869 			{
4870 				stopinterpolation(animateptr[i]);
4871 				animateptr[i] = animateptr[animatecnt];
4872 				animategoal[i] = animategoal[animatecnt];
4873 				animatevel[i] = animatevel[animatecnt];
4874 				animateacc[i] = animateacc[animatecnt];
4875 			}
4876 		}
4877 	}
4878 }
4879 
getanimationgoal(long animptr)4880 getanimationgoal(long animptr)
4881 {
4882 	long i;
4883 
4884 	for(i=animatecnt-1;i>=0;i--)
4885 		if ((long *)animptr == animateptr[i]) return(i);
4886 	return(-1);
4887 }
4888 
setanimation(long * animptr,long thegoal,long thevel,long theacc)4889 setanimation(long *animptr, long thegoal, long thevel, long theacc)
4890 {
4891 	long i, j;
4892 
4893 	if (animatecnt >= MAXANIMATES) return(-1);
4894 
4895 	j = animatecnt;
4896 	for(i=animatecnt-1;i>=0;i--)
4897 		if (animptr == animateptr[i])
4898 			{ j = i; break; }
4899 
4900 	setinterpolation(animptr);
4901 
4902 	animateptr[j] = animptr;
4903 	animategoal[j] = thegoal;
4904 	animatevel[j] = thevel;
4905 	animateacc[j] = theacc;
4906 	if (j == animatecnt) animatecnt++;
4907 	return(j);
4908 }
4909 
checkmasterslaveswitch()4910 checkmasterslaveswitch()
4911 {
4912 	long i, j;
4913 
4914 	if (option[4] == 0) return;
4915 
4916 	j = 0;
4917 	for(i=connecthead;i>=0;i=connectpoint2[i])
4918 		if (sync[i].bits&512) j++;
4919 	if (j != 1) return;
4920 
4921 	i = connecthead;
4922 	for(j=connectpoint2[i];j>=0;j=connectpoint2[j])
4923 	{
4924 		if (sync[j].bits&512)
4925 		{
4926 			connectpoint2[i] = connectpoint2[j];
4927 			connectpoint2[j] = connecthead;
4928 			connecthead = (short)j;
4929 
4930 			oloc.fvel = loc.fvel+1;
4931 			oloc.svel = loc.svel+1;
4932 			oloc.avel = loc.avel+1;
4933 			oloc.bits = loc.bits+1;
4934 			for(i=0;i<MAXPLAYERS;i++)
4935 			{
4936 				osync[i].fvel = ffsync[i].fvel+1;
4937 				osync[i].svel = ffsync[i].svel+1;
4938 				osync[i].avel = ffsync[i].avel+1;
4939 				osync[i].bits = ffsync[i].bits+1;
4940 			}
4941 
4942 			syncvalhead = othersyncvalhead = syncvaltail = 0L;
4943 			totalclock = ototalclock = gotlastpacketclock = lockclock;
4944 
4945 			j = 1;
4946 			for(i=connecthead;i>=0;i=connectpoint2[i])
4947 			{
4948 				if (myconnectindex == i) break;
4949 				j++;
4950 			}
4951 			if (j == 1)
4952 				strcpy(getmessage,"Player 1 (Master)");
4953 			else
4954 				sprintf(getmessage,"Player %ld (Slave)",j);
4955 			getmessageleng = strlen(getmessage);
4956 			getmessagetimeoff = totalclock+120;
4957 
4958 			return;
4959 		}
4960 		i = j;
4961 	}
4962 }
4963 
inittimer()4964 inittimer()
4965 {
4966 	outp(0x43,0x34);
4967 	outp(0x40,(1193181/TIMERINTSPERSECOND)&255);
4968 	outp(0x40,(1193181/TIMERINTSPERSECOND)>>8);
4969 	oldtimerhandler = _dos_getvect(0x8);
4970 	_disable(); _dos_setvect(0x8, timerhandler); _enable();
4971 }
4972 
uninittimer()4973 uninittimer()
4974 {
4975 	outp(0x43,0x34); outp(0x40,0); outp(0x40,0);
4976 	_disable(); _dos_setvect(0x8, oldtimerhandler); _enable();
4977 }
4978 
timerhandler()4979 void __interrupt __far timerhandler()
4980 {
4981 	totalclock++;
4982 	//_chain_intr(oldtimerhandler);
4983 	outp(0x20,0x20);
4984 }
4985 
initkeys()4986 initkeys()
4987 {
4988 	long i;
4989 
4990 	keyfifoplc = 0; keyfifoend = 0;
4991 	for(i=0;i<256;i++) keystatus[i] = 0;
4992 	oldkeyhandler = _dos_getvect(0x9);
4993 	_disable(); _dos_setvect(0x9, keyhandler); _enable();
4994 }
4995 
uninitkeys()4996 uninitkeys()
4997 {
4998 	short *ptr;
4999 
5000 	_dos_setvect(0x9, oldkeyhandler);
5001 		//Turn off shifts to prevent stucks with quitting
5002 	ptr = (short *)0x417; *ptr &= ~0x030f;
5003 }
5004 
keyhandler()5005 void __interrupt __far keyhandler()
5006 {
5007 	oldreadch = readch; readch = kinp(0x60);
5008 	keytemp = kinp(0x61); koutp(0x61,keytemp|128); koutp(0x61,keytemp&127);
5009 	koutp(0x20,0x20);
5010 	if ((readch|1) == 0xe1) { extended = 128; return; }
5011 	if (oldreadch != readch)
5012 	{
5013 		if ((readch&128) == 0)
5014 		{
5015 			keytemp = readch+extended;
5016 			if (!keystatus[keytemp])
5017 			{
5018 				keystatus[keytemp] = 1;
5019 				keyfifo[keyfifoend] = keytemp;
5020 				keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = 1;
5021 				keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1));
5022 			}
5023 		}
5024 		else
5025 		{
5026 			keytemp = (readch&127)+extended;
5027 			keystatus[keytemp] = 0;
5028 			keyfifo[keyfifoend] = keytemp;
5029 			keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = 0;
5030 			keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1));
5031 		}
5032 	}
5033 	extended = 0;
5034 }
5035 
testneighborsectors(short sect1,short sect2)5036 testneighborsectors(short sect1, short sect2)
5037 {
5038 	short i, startwall, num1, num2;
5039 
5040 	num1 = sector[sect1].wallnum;
5041 	num2 = sector[sect2].wallnum;
5042 	if (num1 < num2) //Traverse walls of sector with fewest walls (for speed)
5043 	{
5044 		startwall = sector[sect1].wallptr;
5045 		for(i=num1-1;i>=0;i--)
5046 			if (wall[i+startwall].nextsector == sect2)
5047 				return(1);
5048 	}
5049 	else
5050 	{
5051 		startwall = sector[sect2].wallptr;
5052 		for(i=num2-1;i>=0;i--)
5053 			if (wall[i+startwall].nextsector == sect1)
5054 				return(1);
5055 	}
5056 	return(0);
5057 }
5058 
loadgame()5059 loadgame()
5060 {
5061 	long i;
5062 	long fil;
5063 
5064 	if ((fil = kopen4load("save0000.gam",0)) == -1) return(-1);
5065 
5066 	kdfread(&numplayers,2,1,fil);
5067 	kdfread(&myconnectindex,2,1,fil);
5068 	kdfread(&connecthead,2,1,fil);
5069 	kdfread(connectpoint2,2,MAXPLAYERS,fil);
5070 
5071 		//Make sure palookups get set, sprites will get overwritten later
5072 	for(i=connecthead;i>=0;i=connectpoint2[i]) initplayersprite((short)i);
5073 
5074 	kdfread(posx,4,MAXPLAYERS,fil);
5075 	kdfread(posy,4,MAXPLAYERS,fil);
5076 	kdfread(posz,4,MAXPLAYERS,fil);
5077 	kdfread(horiz,4,MAXPLAYERS,fil);
5078 	kdfread(zoom,4,MAXPLAYERS,fil);
5079 	kdfread(hvel,4,MAXPLAYERS,fil);
5080 	kdfread(ang,2,MAXPLAYERS,fil);
5081 	kdfread(cursectnum,2,MAXPLAYERS,fil);
5082 	kdfread(ocursectnum,2,MAXPLAYERS,fil);
5083 	kdfread(playersprite,2,MAXPLAYERS,fil);
5084 	kdfread(deaths,2,MAXPLAYERS,fil);
5085 	kdfread(lastchaingun,4,MAXPLAYERS,fil);
5086 	kdfread(health,4,MAXPLAYERS,fil);
5087 	kdfread(numgrabbers,2,MAXPLAYERS,fil);
5088 	kdfread(nummissiles,2,MAXPLAYERS,fil);
5089 	kdfread(numbombs,2,MAXPLAYERS,fil);
5090 	kdfread(flytime,4,MAXPLAYERS,fil);
5091 	kdfread(oflags,2,MAXPLAYERS,fil);
5092 	kdfread(dimensionmode,1,MAXPLAYERS,fil);
5093 	kdfread(revolvedoorstat,1,MAXPLAYERS,fil);
5094 	kdfread(revolvedoorang,2,MAXPLAYERS,fil);
5095 	kdfread(revolvedoorrotang,2,MAXPLAYERS,fil);
5096 	kdfread(revolvedoorx,4,MAXPLAYERS,fil);
5097 	kdfread(revolvedoory,4,MAXPLAYERS,fil);
5098 
5099 	kdfread(&numsectors,2,1,fil);
5100 	kdfread(sector,sizeof(sectortype),numsectors,fil);
5101 	kdfread(&numwalls,2,1,fil);
5102 	kdfread(wall,sizeof(walltype),numwalls,fil);
5103 		//Store all sprites (even holes) to preserve indeces
5104 	kdfread(sprite,sizeof(spritetype),MAXSPRITES,fil);
5105 	kdfread(headspritesect,2,MAXSECTORS+1,fil);
5106 	kdfread(prevspritesect,2,MAXSPRITES,fil);
5107 	kdfread(nextspritesect,2,MAXSPRITES,fil);
5108 	kdfread(headspritestat,2,MAXSTATUS+1,fil);
5109 	kdfread(prevspritestat,2,MAXSPRITES,fil);
5110 	kdfread(nextspritestat,2,MAXSPRITES,fil);
5111 
5112 	kdfread(&fvel,4,1,fil);
5113 	kdfread(&svel,4,1,fil);
5114 	kdfread(&avel,4,1,fil);
5115 
5116 	kdfread(&locselectedgun,4,1,fil);
5117 	kdfread(&loc.fvel,1,1,fil);
5118 	kdfread(&oloc.fvel,1,1,fil);
5119 	kdfread(&loc.svel,1,1,fil);
5120 	kdfread(&oloc.svel,1,1,fil);
5121 	kdfread(&loc.avel,1,1,fil);
5122 	kdfread(&oloc.avel,1,1,fil);
5123 	kdfread(&loc.bits,2,1,fil);
5124 	kdfread(&oloc.bits,2,1,fil);
5125 
5126 	kdfread(&locselectedgun2,4,1,fil);
5127 	kdfread(&loc2.fvel,sizeof(input),1,fil);
5128 
5129 	kdfread(sync,sizeof(input),MAXPLAYERS,fil);
5130 	kdfread(osync,sizeof(input),MAXPLAYERS,fil);
5131 
5132 	kdfread(boardfilename,1,80,fil);
5133 	kdfread(&screenpeek,2,1,fil);
5134 	kdfread(&oldmousebstatus,2,1,fil);
5135 	kdfread(&brightness,2,1,fil);
5136 	kdfread(&neartagsector,2,1,fil);
5137 	kdfread(&neartagwall,2,1,fil);
5138 	kdfread(&neartagsprite,2,1,fil);
5139 	kdfread(&lockclock,4,1,fil);
5140 	kdfread(&neartagdist,4,1,fil);
5141 	kdfread(&neartaghitdist,4,1,fil);
5142 
5143 	kdfread(turnspritelist,2,16,fil);
5144 	kdfread(&turnspritecnt,2,1,fil);
5145 	kdfread(warpsectorlist,2,16,fil);
5146 	kdfread(&warpsectorcnt,2,1,fil);
5147 	kdfread(xpanningsectorlist,2,16,fil);
5148 	kdfread(&xpanningsectorcnt,2,1,fil);
5149 	kdfread(ypanningwalllist,2,64,fil);
5150 	kdfread(&ypanningwallcnt,2,1,fil);
5151 	kdfread(floorpanninglist,2,64,fil);
5152 	kdfread(&floorpanningcnt,2,1,fil);
5153 	kdfread(dragsectorlist,2,16,fil);
5154 	kdfread(dragxdir,2,16,fil);
5155 	kdfread(dragydir,2,16,fil);
5156 	kdfread(&dragsectorcnt,2,1,fil);
5157 	kdfread(dragx1,4,16,fil);
5158 	kdfread(dragy1,4,16,fil);
5159 	kdfread(dragx2,4,16,fil);
5160 	kdfread(dragy2,4,16,fil);
5161 	kdfread(dragfloorz,4,16,fil);
5162 	kdfread(&swingcnt,2,1,fil);
5163 	kdfread(swingwall,2,32*5,fil);
5164 	kdfread(swingsector,2,32,fil);
5165 	kdfread(swingangopen,2,32,fil);
5166 	kdfread(swingangclosed,2,32,fil);
5167 	kdfread(swingangopendir,2,32,fil);
5168 	kdfread(swingang,2,32,fil);
5169 	kdfread(swinganginc,2,32,fil);
5170 	kdfread(swingx,4,32*8,fil);
5171 	kdfread(swingy,4,32*8,fil);
5172 	kdfread(revolvesector,2,4,fil);
5173 	kdfread(revolveang,2,4,fil);
5174 	kdfread(&revolvecnt,2,1,fil);
5175 	kdfread(revolvex,4,4*16,fil);
5176 	kdfread(revolvey,4,4*16,fil);
5177 	kdfread(revolvepivotx,4,4,fil);
5178 	kdfread(revolvepivoty,4,4,fil);
5179 	kdfread(subwaytracksector,2,4*128,fil);
5180 	kdfread(subwaynumsectors,2,4,fil);
5181 	kdfread(&subwaytrackcnt,2,1,fil);
5182 	kdfread(subwaystop,4,4*8,fil);
5183 	kdfread(subwaystopcnt,4,4,fil);
5184 	kdfread(subwaytrackx1,4,4,fil);
5185 	kdfread(subwaytracky1,4,4,fil);
5186 	kdfread(subwaytrackx2,4,4,fil);
5187 	kdfread(subwaytracky2,4,4,fil);
5188 	kdfread(subwayx,4,4,fil);
5189 	kdfread(subwaygoalstop,4,4,fil);
5190 	kdfread(subwayvel,4,4,fil);
5191 	kdfread(subwaypausetime,4,4,fil);
5192 	kdfread(waterfountainwall,2,MAXPLAYERS,fil);
5193 	kdfread(waterfountaincnt,2,MAXPLAYERS,fil);
5194 	kdfread(slimesoundcnt,2,MAXPLAYERS,fil);
5195 
5196 		//Warning: only works if all pointers are in sector structures!
5197 	kdfread(animateptr,4,MAXANIMATES,fil);
5198 	for(i=MAXANIMATES-1;i>=0;i--)
5199 		animateptr[i] = (long *)(animateptr[i]+((long)sector));
5200 
5201 	kdfread(animategoal,4,MAXANIMATES,fil);
5202 	kdfread(animatevel,4,MAXANIMATES,fil);
5203 	kdfread(animateacc,4,MAXANIMATES,fil);
5204 	kdfread(&animatecnt,4,1,fil);
5205 
5206 	kdfread(&totalclock,4,1,fil);
5207 	kdfread(&numframes,4,1,fil);
5208 	kdfread(&randomseed,4,1,fil);
5209 	kdfread(&numpalookups,2,1,fil);
5210 
5211 	kdfread(&visibility,4,1,fil);
5212 	kdfread(&parallaxvisibility,4,1,fil);
5213 	kdfread(&parallaxtype,1,1,fil);
5214 	kdfread(&parallaxyoffs,4,1,fil);
5215 	kdfread(pskyoff,2,MAXPSKYTILES,fil);
5216 	kdfread(&pskybits,2,1,fil);
5217 
5218 	kdfread(&mirrorcnt,2,1,fil);
5219 	kdfread(mirrorwall,2,mirrorcnt,fil);
5220 	kdfread(mirrorsector,2,mirrorcnt,fil);
5221 
5222 		//I should save off interpolation list, but they're pointers :(
5223 	numinterpolations = 0;
5224 	startofdynamicinterpolations = 0;
5225 
5226 	kclose(fil);
5227 
5228 	for(i=connecthead;i>=0;i=connectpoint2[i]) initplayersprite((short)i);
5229 
5230 	totalclock = lockclock;
5231 	ototalclock = lockclock;
5232 
5233 	strcpy(getmessage,"Game loaded.");
5234 	getmessageleng = strlen(getmessage);
5235 	getmessagetimeoff = totalclock+360+(getmessageleng<<4);
5236 	return(0);
5237 }
5238 
savegame()5239 savegame()
5240 {
5241 	long i;
5242 	FILE *fil;
5243 
5244 	if ((fil = fopen("save0000.gam","wb")) == 0) return(-1);
5245 
5246 	dfwrite(&numplayers,2,1,fil);
5247 	dfwrite(&myconnectindex,2,1,fil);
5248 	dfwrite(&connecthead,2,1,fil);
5249 	dfwrite(connectpoint2,2,MAXPLAYERS,fil);
5250 
5251 	dfwrite(posx,4,MAXPLAYERS,fil);
5252 	dfwrite(posy,4,MAXPLAYERS,fil);
5253 	dfwrite(posz,4,MAXPLAYERS,fil);
5254 	dfwrite(horiz,4,MAXPLAYERS,fil);
5255 	dfwrite(zoom,4,MAXPLAYERS,fil);
5256 	dfwrite(hvel,4,MAXPLAYERS,fil);
5257 	dfwrite(ang,2,MAXPLAYERS,fil);
5258 	dfwrite(cursectnum,2,MAXPLAYERS,fil);
5259 	dfwrite(ocursectnum,2,MAXPLAYERS,fil);
5260 	dfwrite(playersprite,2,MAXPLAYERS,fil);
5261 	dfwrite(deaths,2,MAXPLAYERS,fil);
5262 	dfwrite(lastchaingun,4,MAXPLAYERS,fil);
5263 	dfwrite(health,4,MAXPLAYERS,fil);
5264 	dfwrite(numgrabbers,2,MAXPLAYERS,fil);
5265 	dfwrite(nummissiles,2,MAXPLAYERS,fil);
5266 	dfwrite(numbombs,2,MAXPLAYERS,fil);
5267 	dfwrite(flytime,4,MAXPLAYERS,fil);
5268 	dfwrite(oflags,2,MAXPLAYERS,fil);
5269 	dfwrite(dimensionmode,1,MAXPLAYERS,fil);
5270 	dfwrite(revolvedoorstat,1,MAXPLAYERS,fil);
5271 	dfwrite(revolvedoorang,2,MAXPLAYERS,fil);
5272 	dfwrite(revolvedoorrotang,2,MAXPLAYERS,fil);
5273 	dfwrite(revolvedoorx,4,MAXPLAYERS,fil);
5274 	dfwrite(revolvedoory,4,MAXPLAYERS,fil);
5275 
5276 	dfwrite(&numsectors,2,1,fil);
5277 	dfwrite(sector,sizeof(sectortype),numsectors,fil);
5278 	dfwrite(&numwalls,2,1,fil);
5279 	dfwrite(wall,sizeof(walltype),numwalls,fil);
5280 		//Store all sprites (even holes) to preserve indeces
5281 	dfwrite(sprite,sizeof(spritetype),MAXSPRITES,fil);
5282 	dfwrite(headspritesect,2,MAXSECTORS+1,fil);
5283 	dfwrite(prevspritesect,2,MAXSPRITES,fil);
5284 	dfwrite(nextspritesect,2,MAXSPRITES,fil);
5285 	dfwrite(headspritestat,2,MAXSTATUS+1,fil);
5286 	dfwrite(prevspritestat,2,MAXSPRITES,fil);
5287 	dfwrite(nextspritestat,2,MAXSPRITES,fil);
5288 
5289 	dfwrite(&fvel,4,1,fil);
5290 	dfwrite(&svel,4,1,fil);
5291 	dfwrite(&avel,4,1,fil);
5292 
5293 	dfwrite(&locselectedgun,4,1,fil);
5294 	dfwrite(&loc.fvel,1,1,fil);
5295 	dfwrite(&oloc.fvel,1,1,fil);
5296 	dfwrite(&loc.svel,1,1,fil);
5297 	dfwrite(&oloc.svel,1,1,fil);
5298 	dfwrite(&loc.avel,1,1,fil);
5299 	dfwrite(&oloc.avel,1,1,fil);
5300 	dfwrite(&loc.bits,2,1,fil);
5301 	dfwrite(&oloc.bits,2,1,fil);
5302 
5303 	dfwrite(&locselectedgun2,4,1,fil);
5304 	dfwrite(&loc2.fvel,sizeof(input),1,fil);
5305 
5306 	dfwrite(sync,sizeof(input),MAXPLAYERS,fil);
5307 	dfwrite(osync,sizeof(input),MAXPLAYERS,fil);
5308 
5309 	dfwrite(boardfilename,1,80,fil);
5310 	dfwrite(&screenpeek,2,1,fil);
5311 	dfwrite(&oldmousebstatus,2,1,fil);
5312 	dfwrite(&brightness,2,1,fil);
5313 	dfwrite(&neartagsector,2,1,fil);
5314 	dfwrite(&neartagwall,2,1,fil);
5315 	dfwrite(&neartagsprite,2,1,fil);
5316 	dfwrite(&lockclock,4,1,fil);
5317 	dfwrite(&neartagdist,4,1,fil);
5318 	dfwrite(&neartaghitdist,4,1,fil);
5319 
5320 	dfwrite(turnspritelist,2,16,fil);
5321 	dfwrite(&turnspritecnt,2,1,fil);
5322 	dfwrite(warpsectorlist,2,16,fil);
5323 	dfwrite(&warpsectorcnt,2,1,fil);
5324 	dfwrite(xpanningsectorlist,2,16,fil);
5325 	dfwrite(&xpanningsectorcnt,2,1,fil);
5326 	dfwrite(ypanningwalllist,2,64,fil);
5327 	dfwrite(&ypanningwallcnt,2,1,fil);
5328 	dfwrite(floorpanninglist,2,64,fil);
5329 	dfwrite(&floorpanningcnt,2,1,fil);
5330 	dfwrite(dragsectorlist,2,16,fil);
5331 	dfwrite(dragxdir,2,16,fil);
5332 	dfwrite(dragydir,2,16,fil);
5333 	dfwrite(&dragsectorcnt,2,1,fil);
5334 	dfwrite(dragx1,4,16,fil);
5335 	dfwrite(dragy1,4,16,fil);
5336 	dfwrite(dragx2,4,16,fil);
5337 	dfwrite(dragy2,4,16,fil);
5338 	dfwrite(dragfloorz,4,16,fil);
5339 	dfwrite(&swingcnt,2,1,fil);
5340 	dfwrite(swingwall,2,32*5,fil);
5341 	dfwrite(swingsector,2,32,fil);
5342 	dfwrite(swingangopen,2,32,fil);
5343 	dfwrite(swingangclosed,2,32,fil);
5344 	dfwrite(swingangopendir,2,32,fil);
5345 	dfwrite(swingang,2,32,fil);
5346 	dfwrite(swinganginc,2,32,fil);
5347 	dfwrite(swingx,4,32*8,fil);
5348 	dfwrite(swingy,4,32*8,fil);
5349 	dfwrite(revolvesector,2,4,fil);
5350 	dfwrite(revolveang,2,4,fil);
5351 	dfwrite(&revolvecnt,2,1,fil);
5352 	dfwrite(revolvex,4,4*16,fil);
5353 	dfwrite(revolvey,4,4*16,fil);
5354 	dfwrite(revolvepivotx,4,4,fil);
5355 	dfwrite(revolvepivoty,4,4,fil);
5356 	dfwrite(subwaytracksector,2,4*128,fil);
5357 	dfwrite(subwaynumsectors,2,4,fil);
5358 	dfwrite(&subwaytrackcnt,2,1,fil);
5359 	dfwrite(subwaystop,4,4*8,fil);
5360 	dfwrite(subwaystopcnt,4,4,fil);
5361 	dfwrite(subwaytrackx1,4,4,fil);
5362 	dfwrite(subwaytracky1,4,4,fil);
5363 	dfwrite(subwaytrackx2,4,4,fil);
5364 	dfwrite(subwaytracky2,4,4,fil);
5365 	dfwrite(subwayx,4,4,fil);
5366 	dfwrite(subwaygoalstop,4,4,fil);
5367 	dfwrite(subwayvel,4,4,fil);
5368 	dfwrite(subwaypausetime,4,4,fil);
5369 	dfwrite(waterfountainwall,2,MAXPLAYERS,fil);
5370 	dfwrite(waterfountaincnt,2,MAXPLAYERS,fil);
5371 	dfwrite(slimesoundcnt,2,MAXPLAYERS,fil);
5372 
5373 		//Warning: only works if all pointers are in sector structures!
5374 	for(i=MAXANIMATES-1;i>=0;i--)
5375 		animateptr[i] = (long *)(animateptr[i]-((long)sector));
5376 	dfwrite(animateptr,4,MAXANIMATES,fil);
5377 	for(i=MAXANIMATES-1;i>=0;i--)
5378 		animateptr[i] = (long *)(animateptr[i]+((long)sector));
5379 
5380 	dfwrite(animategoal,4,MAXANIMATES,fil);
5381 	dfwrite(animatevel,4,MAXANIMATES,fil);
5382 	dfwrite(animateacc,4,MAXANIMATES,fil);
5383 	dfwrite(&animatecnt,4,1,fil);
5384 
5385 	dfwrite(&totalclock,4,1,fil);
5386 	dfwrite(&numframes,4,1,fil);
5387 	dfwrite(&randomseed,4,1,fil);
5388 	dfwrite(&numpalookups,2,1,fil);
5389 
5390 	dfwrite(&visibility,4,1,fil);
5391 	dfwrite(&parallaxvisibility,4,1,fil);
5392 	dfwrite(&parallaxtype,1,1,fil);
5393 	dfwrite(&parallaxyoffs,4,1,fil);
5394 	dfwrite(pskyoff,2,MAXPSKYTILES,fil);
5395 	dfwrite(&pskybits,2,1,fil);
5396 
5397 	dfwrite(&mirrorcnt,2,1,fil);
5398 	dfwrite(mirrorwall,2,mirrorcnt,fil);
5399 	dfwrite(mirrorsector,2,mirrorcnt,fil);
5400 
5401 	fclose(fil);
5402 
5403 	strcpy(getmessage,"Game saved.");
5404 	getmessageleng = strlen(getmessage);
5405 	getmessagetimeoff = totalclock+360+(getmessageleng<<4);
5406 	return(0);
5407 }
5408 
faketimerhandler()5409 faketimerhandler()
5410 {
5411 	short other, packbufleng;
5412 	long i, j, k, l;
5413 
5414 	if ((totalclock < ototalclock+(TIMERINTSPERSECOND/MOVESPERSECOND)) || (ready2send == 0)) return;
5415 	ototalclock += (TIMERINTSPERSECOND/MOVESPERSECOND);
5416 
5417 	getpackets(); if (getoutputcirclesize() >= 16) return;
5418 	getinput();
5419 
5420 	if (networkmode == 1)
5421 	{
5422 		packbuf[2] = 0; j = 3;
5423 		if (loc.fvel != oloc.fvel) packbuf[j++] = loc.fvel, packbuf[2] |= 1;
5424 		if (loc.svel != oloc.svel) packbuf[j++] = loc.svel, packbuf[2] |= 2;
5425 		if (loc.avel != oloc.avel) packbuf[j++] = loc.avel, packbuf[2] |= 4;
5426 		if ((loc.bits^oloc.bits)&0x00ff) packbuf[j++] = (loc.bits&255), packbuf[2] |= 8;
5427 		if ((loc.bits^oloc.bits)&0xff00) packbuf[j++] = ((loc.bits>>8)&255), packbuf[2] |= 16;
5428 		copybufbyte(&loc,&oloc,sizeof(input));
5429 
5430 		copybufbyte(&loc,&baksync[movefifoend[myconnectindex]][myconnectindex],sizeof(input));
5431 		movefifoend[myconnectindex] = ((movefifoend[myconnectindex]+1)&(MOVEFIFOSIZ-1));
5432 
5433 		for(i=connecthead;i>=0;i=connectpoint2[i])
5434 			if (i != myconnectindex)
5435 			{
5436 				packbuf[0] = 17;
5437 				packbuf[1] = (char)((movefifoend[myconnectindex]-movefifoend[i])&(MOVEFIFOSIZ-1));
5438 
5439 				k = j;
5440 				if ((myconnectindex == connecthead) || ((i == connecthead) && (myconnectindex == connectpoint2[connecthead])))
5441 				{
5442 					while (syncvalhead != syncvaltail)
5443 					{
5444 						packbuf[j++] = syncval[syncvaltail];
5445 						syncvaltail = ((syncvaltail+1)&(MOVEFIFOSIZ-1));
5446 					}
5447 				}
5448 				sendpacket(i,packbuf,j);
5449 				j = k;
5450 			}
5451 
5452 		gotlastpacketclock = totalclock;
5453 		return;
5454 	}
5455 
5456 		//MASTER (or 1 player game)
5457 	if ((myconnectindex == connecthead) || (option[4] == 0))
5458 	{
5459 		copybufbyte(&loc,&ffsync[myconnectindex],sizeof(input));
5460 
5461 		if (option[4] != 0)
5462 		{
5463 			packbuf[0] = 0;
5464 			j = ((numplayers+1)>>1)+1;
5465 			for(k=1;k<j;k++) packbuf[k] = 0;
5466 			k = (1<<3);
5467 			for(i=connecthead;i>=0;i=connectpoint2[i])
5468 			{
5469 				l = 0;
5470 				if (ffsync[i].fvel != osync[i].fvel) packbuf[j++] = ffsync[i].fvel, l |= 1;
5471 				if (ffsync[i].svel != osync[i].svel) packbuf[j++] = ffsync[i].svel, l |= 2;
5472 				if (ffsync[i].avel != osync[i].avel) packbuf[j++] = ffsync[i].avel, l |= 4;
5473 				if (ffsync[i].bits != osync[i].bits)
5474 				{
5475 					packbuf[j++] = (ffsync[i].bits&255);
5476 					packbuf[j++] = ((ffsync[i].bits>>8)&255);
5477 					l |= 8;
5478 				}
5479 				packbuf[k>>3] |= (l<<(k&7));
5480 				k += 4;
5481 
5482 				copybufbyte(&ffsync[i],&osync[i],sizeof(input));
5483 			}
5484 
5485 			while (syncvalhead != syncvaltail)
5486 			{
5487 				packbuf[j++] = syncval[syncvaltail];
5488 				syncvaltail = ((syncvaltail+1)&(MOVEFIFOSIZ-1));
5489 			}
5490 
5491 			for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
5492 				sendpacket(i,packbuf,j);
5493 		}
5494 		else if (numplayers >= 2)
5495 		{
5496 			if (keystatus[0xb5])
5497 			{
5498 				keystatus[0xb5] = 0;
5499 				locselectedgun2++; if (locselectedgun2 >= 3) locselectedgun2 = 0;
5500 			}
5501 
5502 				//Second player on 1 computer mode
5503 			loc2.fvel = min(max(fvel2,-128+8),127-8);
5504 			loc2.svel = min(max(svel2,-128+8),127-8);
5505 			loc2.avel = min(max(avel2,-128+16),127-16);
5506 			loc2.bits = (locselectedgun2<<13);
5507 			loc2.bits |= keystatus[0x45];                  //Stand high
5508 			loc2.bits |= (keystatus[0x47]<<1);             //Stand low
5509 			loc2.bits |= (1<<8);                           //Run
5510 			loc2.bits |= (keystatus[0x49]<<2);             //Look up
5511 			loc2.bits |= (keystatus[0x37]<<3);             //Look down
5512 			loc2.bits |= (keystatus[0x50]<<10);            //Space
5513 			loc2.bits |= (keystatus[0x52]<<11);            //Shoot
5514 
5515 			other = connectpoint2[myconnectindex];
5516 			if (other < 0) other = connecthead;
5517 
5518 			copybufbyte(&loc2,&ffsync[other],sizeof(input));
5519 		}
5520 		movethings();  //Move EVERYTHING (you too!)
5521 	}
5522 	else                        //I am a SLAVE
5523 	{
5524 		packbuf[0] = 1; packbuf[1] = 0; j = 2;
5525 		if (loc.fvel != oloc.fvel) packbuf[j++] = loc.fvel, packbuf[1] |= 1;
5526 		if (loc.svel != oloc.svel) packbuf[j++] = loc.svel, packbuf[1] |= 2;
5527 		if (loc.avel != oloc.avel) packbuf[j++] = loc.avel, packbuf[1] |= 4;
5528 		if ((loc.bits^oloc.bits)&0x00ff) packbuf[j++] = (loc.bits&255), packbuf[1] |= 8;
5529 		if ((loc.bits^oloc.bits)&0xff00) packbuf[j++] = ((loc.bits>>8)&255), packbuf[1] |= 16;
5530 		copybufbyte(&loc,&oloc,sizeof(input));
5531 		sendpacket(connecthead,packbuf,j);
5532 	}
5533 }
5534 
getpackets()5535 getpackets()
5536 {
5537 	long i, j, k, l;
5538 	short other, packbufleng, movecnt;
5539 
5540 	if (option[4] == 0) return;
5541 
5542 	movecnt = 0;
5543 	while ((packbufleng = getpacket(&other,packbuf)) > 0)
5544 	{
5545 		switch(packbuf[0])
5546 		{
5547 			case 0:  //[0] (receive master sync buffer)
5548 				j = ((numplayers+1)>>1)+1; k = (1<<3);
5549 				for(i=connecthead;i>=0;i=connectpoint2[i])
5550 				{
5551 					l = (packbuf[k>>3]>>(k&7));
5552 					if (l&1) ffsync[i].fvel = packbuf[j++];
5553 					if (l&2) ffsync[i].svel = packbuf[j++];
5554 					if (l&4) ffsync[i].avel = packbuf[j++];
5555 					if (l&8)
5556 					{
5557 						ffsync[i].bits = ((short)packbuf[j])+(((short)packbuf[j+1])<<8);
5558 						j += 2;
5559 					}
5560 					k += 4;
5561 				}
5562 
5563 				while (j != packbufleng)
5564 				{
5565 					 othersyncval[othersyncvalhead] = packbuf[j++];
5566 					 othersyncvalhead = ((othersyncvalhead+1)&(MOVEFIFOSIZ-1));
5567 				}
5568 				if ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail))
5569 				{
5570 					syncstat = 0;
5571 					do
5572 					{
5573 						syncstat |= (syncval[syncvaltottail]^othersyncval[syncvaltottail]);
5574 						syncvaltottail = ((syncvaltottail+1)&(MOVEFIFOSIZ-1));
5575 					} while ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail));
5576 				}
5577 
5578 				movethings();        //Move all players and sprites
5579 				movecnt++;
5580 				break;
5581 			case 1:  //[1] (receive slave sync buffer)
5582 				j = 2; k = packbuf[1];
5583 				if (k&1) ffsync[other].fvel = packbuf[j++];
5584 				if (k&2) ffsync[other].svel = packbuf[j++];
5585 				if (k&4) ffsync[other].avel = packbuf[j++];
5586 				if (k&8) ffsync[other].bits = ((ffsync[other].bits&0xff00)|((short)packbuf[j++]));
5587 				if (k&16) ffsync[other].bits = ((ffsync[other].bits&0x00ff)|(((short)packbuf[j++])<<8));
5588 				break;
5589 			case 2:
5590 				getmessageleng = packbufleng-1;
5591 				for(j=getmessageleng-1;j>=0;j--) getmessage[j] = packbuf[j+1];
5592 				getmessagetimeoff = totalclock+360+(getmessageleng<<4);
5593 				break;
5594 			case 3:
5595 				wsay("getstuff.wav",4096L,63L,63L);
5596 				break;
5597 			case 5:
5598 				playerreadyflag[other] = packbuf[1];
5599 				if ((other == connecthead) && (packbuf[1] == 2))
5600 					sendpacket(connecthead,packbuf,2);
5601 				break;
5602 			case 17:
5603 				j = 3; k = packbuf[2];
5604 				if (k&1) ffsync[other].fvel = packbuf[j++];
5605 				if (k&2) ffsync[other].svel = packbuf[j++];
5606 				if (k&4) ffsync[other].avel = packbuf[j++];
5607 				if (k&8) ffsync[other].bits = ((ffsync[other].bits&0xff00)|((short)packbuf[j++]));
5608 				if (k&16) ffsync[other].bits = ((ffsync[other].bits&0x00ff)|(((short)packbuf[j++])<<8));
5609 				otherlag[other] = packbuf[1];
5610 
5611 				copybufbyte(&ffsync[other],&baksync[movefifoend[other]][other],sizeof(input));
5612 				movefifoend[other] = ((movefifoend[other]+1)&(MOVEFIFOSIZ-1));
5613 
5614 				while (j != packbufleng)
5615 				{
5616 					 othersyncval[othersyncvalhead] = packbuf[j++];
5617 					 othersyncvalhead = ((othersyncvalhead+1)&(MOVEFIFOSIZ-1));
5618 				}
5619 				if ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail))
5620 				{
5621 					syncstat = 0;
5622 					do
5623 					{
5624 						syncstat |= (syncval[syncvaltottail]^othersyncval[syncvaltottail]);
5625 						syncvaltottail = ((syncvaltottail+1)&(MOVEFIFOSIZ-1));
5626 					} while ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail));
5627 				}
5628 
5629 				break;
5630 			case 255:  //[255] (logout)
5631 				keystatus[1] = 1;
5632 				break;
5633 		}
5634 	}
5635 	if ((networkmode == 0) && (myconnectindex != connecthead) && ((movecnt&1) == 0))
5636 	{
5637 		if (rand()&1) ototalclock += (TICSPERFRAME>>1);
5638 					else ototalclock -= (TICSPERFRAME>>1);
5639 	}
5640 }
5641 
drawoverheadmap(long cposx,long cposy,long czoom,short cang)5642 drawoverheadmap(long cposx, long cposy, long czoom, short cang)
5643 {
5644 	long i, j, k, l, x1, y1, x2, y2, x3, y3, x4, y4, ox, oy, xoff, yoff;
5645 	long dax, day, cosang, sinang, xspan, yspan, sprx, spry;
5646 	long xrepeat, yrepeat, z1, z2, startwall, endwall, tilenum, daang;
5647 	long xvect, yvect, xvect2, yvect2;
5648 	char col;
5649 	walltype *wal, *wal2;
5650 	spritetype *spr;
5651 
5652 	xvect = sintable[(-cang)&2047] * czoom;
5653 	yvect = sintable[(1536-cang)&2047] * czoom;
5654 	xvect2 = mulscale16(xvect,yxaspect);
5655 	yvect2 = mulscale16(yvect,yxaspect);
5656 
5657 		//Draw red lines
5658 	for(i=0;i<numsectors;i++)
5659 	{
5660 		startwall = sector[i].wallptr;
5661 		endwall = sector[i].wallptr + sector[i].wallnum;
5662 
5663 		z1 = sector[i].ceilingz; z2 = sector[i].floorz;
5664 
5665 		for(j=startwall,wal=&wall[startwall];j<endwall;j++,wal++)
5666 		{
5667 			k = wal->nextwall; if (k < 0) continue;
5668 
5669 			if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue;
5670 			if ((k > j) && ((show2dwall[k>>3]&(1<<(k&7))) > 0)) continue;
5671 
5672 			if (sector[wal->nextsector].ceilingz == z1)
5673 				if (sector[wal->nextsector].floorz == z2)
5674 					if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0) continue;
5675 
5676 			col = 152;
5677 
5678 			if (dimensionmode[screenpeek] == 2)
5679 			{
5680 				if (sector[i].floorz != sector[i].ceilingz)
5681 					if (sector[wal->nextsector].floorz != sector[wal->nextsector].ceilingz)
5682 						if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0)
5683 							if (sector[i].floorz == sector[wal->nextsector].floorz) continue;
5684 				if (sector[i].floorpicnum != sector[wal->nextsector].floorpicnum) continue;
5685 				if (sector[i].floorshade != sector[wal->nextsector].floorshade) continue;
5686 				col = 12;
5687 			}
5688 
5689 			ox = wal->x-cposx; oy = wal->y-cposy;
5690 			x1 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11);
5691 			y1 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11);
5692 
5693 			wal2 = &wall[wal->point2];
5694 			ox = wal2->x-cposx; oy = wal2->y-cposy;
5695 			x2 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11);
5696 			y2 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11);
5697 
5698 			drawline256(x1,y1,x2,y2,col);
5699 		}
5700 	}
5701 
5702 		//Draw sprites
5703 	k = playersprite[screenpeek];
5704 	for(i=0;i<numsectors;i++)
5705 		for(j=headspritesect[i];j>=0;j=nextspritesect[j])
5706 			if ((show2dsprite[j>>3]&(1<<(j&7))) > 0)
5707 			{
5708 				spr = &sprite[j]; if (spr->cstat&0x8000) continue;
5709 				col = 56;
5710 				if (spr->cstat&1) col = 248;
5711 				if (j == k) col = 31;
5712 
5713 				k = statrate[spr->statnum];
5714 				sprx = spr->x;
5715 				spry = spr->y;
5716 				if (k >= 0)
5717 				{
5718 					switch(k)
5719 					{
5720 						case 0: l = smoothratio; break;
5721 						case 1: l = (smoothratio>>1)+(((nummoves-j)&1)<<15); break;
5722 						case 3: l = (smoothratio>>2)+(((nummoves-j)&3)<<14); break;
5723 						case 7: l = (smoothratio>>3)+(((nummoves-j)&7)<<13); break;
5724 						case 15: l = (smoothratio>>4)+(((nummoves-j)&15)<<12); break;
5725 					}
5726 					sprx = osprite[j].x+mulscale16(sprx-osprite[j].x,l);
5727 					spry = osprite[j].y+mulscale16(spry-osprite[j].y,l);
5728 				}
5729 
5730 				switch (spr->cstat&48)
5731 				{
5732 					case 0:
5733 						ox = sprx-cposx; oy = spry-cposy;
5734 						x1 = dmulscale16(ox,xvect,-oy,yvect);
5735 						y1 = dmulscale16(oy,xvect2,ox,yvect2);
5736 
5737 						if (dimensionmode[screenpeek] == 1)
5738 						{
5739 							ox = (sintable[(spr->ang+512)&2047]>>7);
5740 							oy = (sintable[(spr->ang)&2047]>>7);
5741 							x2 = dmulscale16(ox,xvect,-oy,yvect);
5742 							y2 = dmulscale16(oy,xvect,ox,yvect);
5743 
5744 							if (j == playersprite[screenpeek])
5745 							{
5746 								x2 = 0L;
5747 								y2 = -(czoom<<5);
5748 							}
5749 
5750 							x3 = mulscale16(x2,yxaspect);
5751 							y3 = mulscale16(y2,yxaspect);
5752 
5753 							drawline256(x1-x2+(xdim<<11),y1-y3+(ydim<<11),
5754 											x1+x2+(xdim<<11),y1+y3+(ydim<<11),col);
5755 							drawline256(x1-y2+(xdim<<11),y1+x3+(ydim<<11),
5756 											x1+x2+(xdim<<11),y1+y3+(ydim<<11),col);
5757 							drawline256(x1+y2+(xdim<<11),y1-x3+(ydim<<11),
5758 											x1+x2+(xdim<<11),y1+y3+(ydim<<11),col);
5759 						}
5760 						else
5761 						{
5762 							if (((gotsector[i>>3]&(1<<(i&7))) > 0) && (czoom > 96))
5763 							{
5764 								daang = (spr->ang-cang)&2047;
5765 								if (j == playersprite[screenpeek]) { x1 = 0; y1 = 0; daang = 0; }
5766 								rotatesprite((x1<<4)+(xdim<<15),(y1<<4)+(ydim<<15),mulscale16(czoom*spr->yrepeat,yxaspect),daang,spr->picnum,spr->shade,spr->pal,(spr->cstat&2)>>1,windowx1,windowy1,windowx2,windowy2);
5767 							}
5768 						}
5769 						break;
5770 					case 16:
5771 						x1 = sprx; y1 = spry;
5772 						tilenum = spr->picnum;
5773 						xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset);
5774 						if ((spr->cstat&4) > 0) xoff = -xoff;
5775 						k = spr->ang; l = spr->xrepeat;
5776 						dax = sintable[k&2047]*l; day = sintable[(k+1536)&2047]*l;
5777 						l = tilesizx[tilenum]; k = (l>>1)+xoff;
5778 						x1 -= mulscale16(dax,k); x2 = x1+mulscale16(dax,l);
5779 						y1 -= mulscale16(day,k); y2 = y1+mulscale16(day,l);
5780 
5781 						ox = x1-cposx; oy = y1-cposy;
5782 						x1 = dmulscale16(ox,xvect,-oy,yvect);
5783 						y1 = dmulscale16(oy,xvect2,ox,yvect2);
5784 
5785 						ox = x2-cposx; oy = y2-cposy;
5786 						x2 = dmulscale16(ox,xvect,-oy,yvect);
5787 						y2 = dmulscale16(oy,xvect2,ox,yvect2);
5788 
5789 						drawline256(x1+(xdim<<11),y1+(ydim<<11),
5790 										x2+(xdim<<11),y2+(ydim<<11),col);
5791 
5792 						break;
5793 					case 32:
5794 						if (dimensionmode[screenpeek] == 1)
5795 						{
5796 							tilenum = spr->picnum;
5797 							xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset);
5798 							yoff = (long)((signed char)((picanm[tilenum]>>16)&255))+((long)spr->yoffset);
5799 							if ((spr->cstat&4) > 0) xoff = -xoff;
5800 							if ((spr->cstat&8) > 0) yoff = -yoff;
5801 
5802 							k = spr->ang;
5803 							cosang = sintable[(k+512)&2047]; sinang = sintable[k];
5804 							xspan = tilesizx[tilenum]; xrepeat = spr->xrepeat;
5805 							yspan = tilesizy[tilenum]; yrepeat = spr->yrepeat;
5806 
5807 							dax = ((xspan>>1)+xoff)*xrepeat; day = ((yspan>>1)+yoff)*yrepeat;
5808 							x1 = sprx + dmulscale16(sinang,dax,cosang,day);
5809 							y1 = spry + dmulscale16(sinang,day,-cosang,dax);
5810 							l = xspan*xrepeat;
5811 							x2 = x1 - mulscale16(sinang,l);
5812 							y2 = y1 + mulscale16(cosang,l);
5813 							l = yspan*yrepeat;
5814 							k = -mulscale16(cosang,l); x3 = x2+k; x4 = x1+k;
5815 							k = -mulscale16(sinang,l); y3 = y2+k; y4 = y1+k;
5816 
5817 							ox = x1-cposx; oy = y1-cposy;
5818 							x1 = dmulscale16(ox,xvect,-oy,yvect);
5819 							y1 = dmulscale16(oy,xvect2,ox,yvect2);
5820 
5821 							ox = x2-cposx; oy = y2-cposy;
5822 							x2 = dmulscale16(ox,xvect,-oy,yvect);
5823 							y2 = dmulscale16(oy,xvect2,ox,yvect2);
5824 
5825 							ox = x3-cposx; oy = y3-cposy;
5826 							x3 = dmulscale16(ox,xvect,-oy,yvect);
5827 							y3 = dmulscale16(oy,xvect2,ox,yvect2);
5828 
5829 							ox = x4-cposx; oy = y4-cposy;
5830 							x4 = dmulscale16(ox,xvect,-oy,yvect);
5831 							y4 = dmulscale16(oy,xvect2,ox,yvect2);
5832 
5833 							drawline256(x1+(xdim<<11),y1+(ydim<<11),
5834 											x2+(xdim<<11),y2+(ydim<<11),col);
5835 
5836 							drawline256(x2+(xdim<<11),y2+(ydim<<11),
5837 											x3+(xdim<<11),y3+(ydim<<11),col);
5838 
5839 							drawline256(x3+(xdim<<11),y3+(ydim<<11),
5840 											x4+(xdim<<11),y4+(ydim<<11),col);
5841 
5842 							drawline256(x4+(xdim<<11),y4+(ydim<<11),
5843 											x1+(xdim<<11),y1+(ydim<<11),col);
5844 
5845 						}
5846 						break;
5847 				}
5848 			}
5849 
5850 		//Draw white lines
5851 	for(i=0;i<numsectors;i++)
5852 	{
5853 		startwall = sector[i].wallptr;
5854 		endwall = sector[i].wallptr + sector[i].wallnum;
5855 
5856 		k = -1;
5857 		for(j=startwall,wal=&wall[startwall];j<endwall;j++,wal++)
5858 		{
5859 			if (wal->nextwall >= 0) continue;
5860 
5861 			if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue;
5862 
5863 			if (tilesizx[wal->picnum] == 0) continue;
5864 			if (tilesizy[wal->picnum] == 0) continue;
5865 
5866 			if (j == k)
5867 				{ x1 = x2; y1 = y2; }
5868 			else
5869 			{
5870 				ox = wal->x-cposx; oy = wal->y-cposy;
5871 				x1 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11);
5872 				y1 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11);
5873 			}
5874 
5875 			k = wal->point2; wal2 = &wall[k];
5876 			ox = wal2->x-cposx; oy = wal2->y-cposy;
5877 			x2 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11);
5878 			y2 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11);
5879 
5880 			drawline256(x1,y1,x2,y2,24);
5881 		}
5882 	}
5883 }
5884 
5885 	//New movesprite using getzrange.  Note that I made the getzrange
5886 	//parameters global (&globhiz,&globhihit,&globloz,&globlohit) so they
5887 	//don't need to be passed everywhere.  Also this should make this
5888 	//movesprite function compatible with the older movesprite functions.
movesprite(short spritenum,long dx,long dy,long dz,long ceildist,long flordist,long clipmask)5889 movesprite(short spritenum, long dx, long dy, long dz, long ceildist, long flordist, long clipmask)
5890 {
5891 	long daz, zoffs, templong;
5892 	short retval, dasectnum, datempshort;
5893 	spritetype *spr;
5894 
5895 	spr = &sprite[spritenum];
5896 
5897 	if ((spr->cstat&128) == 0)
5898 		zoffs = -((tilesizy[spr->picnum]*spr->yrepeat)<<1);
5899 	else
5900 		zoffs = 0;
5901 
5902 	dasectnum = spr->sectnum;  //Can't modify sprite sectors directly becuase of linked lists
5903 	daz = spr->z+zoffs;  //Must do this if not using the new centered centering (of course)
5904 	retval = clipmove(&spr->x,&spr->y,&daz,&dasectnum,dx,dy,
5905 							((long)spr->clipdist)<<2,ceildist,flordist,clipmask);
5906 
5907 	if (dasectnum < 0) retval = -1;
5908 
5909 	if ((dasectnum != spr->sectnum) && (dasectnum >= 0))
5910 		changespritesect(spritenum,dasectnum);
5911 
5912 		//Set the blocking bit to 0 temporarly so getzrange doesn't pick up
5913 		//its own sprite
5914 	datempshort = spr->cstat; spr->cstat &= ~1;
5915 	getzrange(spr->x,spr->y,spr->z-1,spr->sectnum,
5916 				 &globhiz,&globhihit,&globloz,&globlohit,
5917 				 ((long)spr->clipdist)<<2,clipmask);
5918 	spr->cstat = datempshort;
5919 
5920 	daz = spr->z+zoffs + dz;
5921 	if ((daz <= globhiz) || (daz > globloz))
5922 	{
5923 		if (retval != 0) return(retval);
5924 		return(16384+dasectnum);
5925 	}
5926 	spr->z = daz-zoffs;
5927 	return(retval);
5928 }
5929 
waitforeverybody()5930 waitforeverybody()
5931 {
5932 	long i, j, oldtotalclock;
5933 
5934 	if (numplayers < 2) return;
5935 
5936 	if (myconnectindex == connecthead)
5937 	{
5938 		for(j=1;j<=2;j++)
5939 		{
5940 			for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
5941 				playerreadyflag[i] = 0;
5942 			oldtotalclock = totalclock-8;
5943 			do
5944 			{
5945 				getpackets();
5946 				if (totalclock >= oldtotalclock+8)
5947 				{
5948 					oldtotalclock = totalclock;
5949 					packbuf[0] = 5;
5950 					packbuf[1] = j;
5951 					for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
5952 						if (playerreadyflag[i] != j) sendpacket(i,packbuf,2);
5953 				}
5954 				for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
5955 					if (playerreadyflag[i] != j) break;
5956 			} while (i >= 0);
5957 		}
5958 	}
5959 	else
5960 	{
5961 		playerreadyflag[connecthead] = 0;
5962 		while (playerreadyflag[connecthead] != 2)
5963 		{
5964 			getpackets();
5965 			if (playerreadyflag[connecthead] == 1)
5966 			{
5967 				playerreadyflag[connecthead] = 0;
5968 				sendpacket(connecthead,packbuf,2);
5969 			}
5970 		}
5971 	}
5972 }
5973 
searchmap(short startsector)5974 searchmap(short startsector)
5975 {
5976 	long i, j, dasect, splc, send, startwall, endwall;
5977 	short dapic;
5978 	walltype *wal;
5979 
5980 	if ((startsector < 0) || (startsector >= numsectors)) return;
5981 	for(i=0;i<(MAXSECTORS>>3);i++) show2dsector[i] = 0;
5982 	for(i=0;i<(MAXWALLS>>3);i++) show2dwall[i] = 0;
5983 	for(i=0;i<(MAXSPRITES>>3);i++) show2dsprite[i] = 0;
5984 
5985 	automapping = 0;
5986 
5987 		//Search your area recursively & set all show2dsector/show2dwalls
5988 	tempshort[0] = startsector;
5989 	show2dsector[startsector>>3] |= (1<<(startsector&7));
5990 	dapic = sector[startsector].ceilingpicnum;
5991 	if (waloff[dapic] == 0) loadtile(dapic);
5992 	dapic = sector[startsector].floorpicnum;
5993 	if (waloff[dapic] == 0) loadtile(dapic);
5994 	for(splc=0,send=1;splc<send;splc++)
5995 	{
5996 		dasect = tempshort[splc];
5997 		startwall = sector[dasect].wallptr;
5998 		endwall = startwall + sector[dasect].wallnum;
5999 		for(i=startwall,wal=&wall[startwall];i<endwall;i++,wal++)
6000 		{
6001 			show2dwall[i>>3] |= (1<<(i&7));
6002 			dapic = wall[i].picnum;
6003 			if (waloff[dapic] == 0) loadtile(dapic);
6004 			dapic = wall[i].overpicnum;
6005 			if (((dapic&0xfffff000) == 0) && (waloff[dapic] == 0)) loadtile(dapic);
6006 
6007 			j = wal->nextsector;
6008 			if ((j >= 0) && ((show2dsector[j>>3]&(1<<(j&7))) == 0))
6009 			{
6010 				show2dsector[j>>3] |= (1<<(j&7));
6011 
6012 				dapic = sector[j].ceilingpicnum;
6013 				if (waloff[dapic] == 0) loadtile(dapic);
6014 				dapic = sector[j].floorpicnum;
6015 				if (waloff[dapic] == 0) loadtile(dapic);
6016 
6017 				tempshort[send++] = (short)j;
6018 			}
6019 		}
6020 
6021 		for(i=headspritesect[dasect];i>=0;i=nextspritesect[i])
6022 		{
6023 			show2dsprite[i>>3] |= (1<<(i&7));
6024 			dapic = sprite[i].picnum;
6025 			if (waloff[dapic] == 0) loadtile(dapic);
6026 		}
6027 	}
6028 }
6029 
setinterpolation(long * posptr)6030 setinterpolation(long *posptr)
6031 {
6032 	long i;
6033 
6034 	if (numinterpolations >= MAXINTERPOLATIONS) return;
6035 	for(i=numinterpolations-1;i>=0;i--)
6036 		if (curipos[i] == posptr) return;
6037 	curipos[numinterpolations] = posptr;
6038 	oldipos[numinterpolations] = *posptr;
6039 	numinterpolations++;
6040 }
6041 
stopinterpolation(long * posptr)6042 stopinterpolation(long *posptr)
6043 {
6044 	long i;
6045 
6046 	for(i=numinterpolations-1;i>=startofdynamicinterpolations;i--)
6047 		if (curipos[i] == posptr)
6048 		{
6049 			numinterpolations--;
6050 			oldipos[i] = oldipos[numinterpolations];
6051 			bakipos[i] = bakipos[numinterpolations];
6052 			curipos[i] = curipos[numinterpolations];
6053 		}
6054 }
6055 
updateinterpolations()6056 updateinterpolations()  //Stick at beginning of domovethings
6057 {
6058 	long i;
6059 
6060 	for(i=numinterpolations-1;i>=0;i--) oldipos[i] = *curipos[i];
6061 }
6062 
dointerpolations()6063 dointerpolations()       //Stick at beginning of drawscreen
6064 {
6065 	long i, j, odelta, ndelta;
6066 
6067 	ndelta = 0; j = 0;
6068 	for(i=numinterpolations-1;i>=0;i--)
6069 	{
6070 		bakipos[i] = *curipos[i];
6071 		odelta = ndelta; ndelta = (*curipos[i])-oldipos[i];
6072 		if (odelta != ndelta) j = mulscale16(ndelta,smoothratio);
6073 		*curipos[i] = oldipos[i]+j;
6074 	}
6075 }
6076 
restoreinterpolations()6077 restoreinterpolations()  //Stick at end of drawscreen
6078 {
6079 	long i;
6080 
6081 	for(i=numinterpolations-1;i>=0;i--) *curipos[i] = bakipos[i];
6082 }
6083 
printext(long x,long y,char * buffer,short tilenum,char invisiblecol)6084 printext(long x, long y, char *buffer, short tilenum, char invisiblecol)
6085 {
6086 	long i;
6087 	char ch;
6088 
6089 	for(i=0;buffer[i]!=0;i++)
6090 	{
6091 		ch = buffer[i];
6092 		rotatesprite((x-((8&15)<<3))<<16,(y-((8>>4)<<3))<<16,65536L,0,tilenum,0,0,8+16+64+128,x,y,x+7,y+7);
6093 		rotatesprite((x-((ch&15)<<3))<<16,(y-((ch>>4)<<3))<<16,65536L,0,tilenum,0,0,8+16+128,x,y,x+7,y+7);
6094 		x += 8;
6095 	}
6096 }
6097 
drawtilebackground(long thex,long they,short tilenum,signed char shade,long cx1,long cy1,long cx2,long cy2,char dapalnum)6098 drawtilebackground (long thex, long they, short tilenum,
6099 								  signed char shade, long cx1, long cy1,
6100 								  long cx2, long cy2, char dapalnum)
6101 {
6102 	long x, y, xsiz, ysiz, tx1, ty1, tx2, ty2;
6103 
6104 	xsiz = tilesizx[tilenum]; tx1 = cx1/xsiz; tx2 = cx2/xsiz;
6105 	ysiz = tilesizy[tilenum]; ty1 = cy1/ysiz; ty2 = cy2/ysiz;
6106 
6107 	for(x=tx1;x<=tx2;x++)
6108 		for(y=ty1;y<=ty2;y++)
6109 			rotatesprite(x*xsiz<<16,y*ysiz<<16,65536L,0,tilenum,shade,dapalnum,8+16+64+128,cx1,cy1,cx2,cy2);
6110 }
6111