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(§or[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(§or[dasector].ceilingz,daz,6L,6L)) >= 0)
835 wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,¢x,¢y,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(§or[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(§or[dasector].floorz,daz,6L,6L)) >= 0)
867 wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,¢x,¢y,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,¢x,¢y,0);
932 wsayfollow("updowndr.wav",4096L+256L,256L,¢x,¢y,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,¢x,¢y,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,¢x,¢y,0);
1026 wsayfollow("updowndr.wav",4096L+64L,256L,¢x,¢y,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(§or[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(¶llaxvisibility,4,1,fil);
5437 kdfread(¶llaxtype,1,1,fil);
5438 kdfread(¶llaxyoffs,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(¶llaxvisibility,4,1,fil);
5615 dfwrite(¶llaxtype,1,1,fil);
5616 dfwrite(¶llaxyoffs,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