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