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