|
|
1.1 root 1: #include <fcntl.h>
2: #include <io.h>
3: #include <sys\types.h>
4: #include <sys\stat.h>
5: #include <string.h>
6: #include <stdlib.h>
7: #include <dos.h>
8: #include "build.h"
9: #include "names.h"
10:
11: #define TICSPERFRAME 3
12: #define MOVEFIFOSIZ 256
13:
14: /***************************************************************************
15: KEN'S TAG DEFINITIONS: (Please define your own tags for your games)
16:
17: sector[?].lotag = 0 Normal sector
18: sector[?].lotag = 1 If you are on a sector with this tag, then all sectors
19: with same hi tag as this are operated. Once.
20: sector[?].lotag = 2 Same as sector[?].tag = 1 but this is retriggable.
21: sector[?].lotag = 3 A really stupid sector that really does nothing now.
22: sector[?].lotag = 4 A sector where you are put closer to the floor
23: (such as the slime in DOOM1.DAT)
24: sector[?].lotag = 5 A really stupid sector that really does nothing now.
25: sector[?].lotag = 6 A normal door - instead of pressing D, you tag the
26: sector with a 6. The reason I make you edit doors
27: this way is so that can program the doors
28: yourself.
29: sector[?].lotag = 7 A door the goes down to open.
30: sector[?].lotag = 8 A door that opens horizontally in the middle.
31: sector[?].lotag = 9 A sliding door that opens vertically in the middle.
32: -Example of the advantages of not using BSP tree.
33: sector[?].lotag = 10 A warping sector with floor and walls that shade.
34: sector[?].lotag = 11 A sector with all walls that do X-panning.
35: sector[?].lotag = 12 A sector with walls using the dragging function.
36: sector[?].lotag = 13 A sector with some swinging doors in it.
37: sector[?].lotag = 14 A revolving door sector.
38: sector[?].lotag = 15 A subway track.
39: sector[?].lotag = 16 A true double-sliding door.
40: sector[?].lotag = 17 A true double-sliding door for subways only.
41:
42: wall[?].lotag = 0 Normal wall
43: wall[?].lotag = 1 Y-panning wall
44: wall[?].lotag = 2 Switch - If you flip it, then all sectors with same hi
45: tag as this are operated.
46: wall[?].lotag = 3 Marked wall to detemine starting dir. (sector tag 12)
47: wall[?].lotag = 4 Mark on the shorter wall closest to the pivot point
48: of a swinging door. (sector tag 13)
49: wall[?].lotag = 5 Mark where a subway should stop. (sector tag 15)
50: wall[?].lotag = 6 Mark for true double-sliding doors (sector tag 16)
51: wall[?].lotag = 7 Water fountain
52: wall[?].lotag = 8 Bouncy wall!
53:
54: sprite[?].lotag = 0 Normal sprite
55: sprite[?].lotag = 1 If you press space bar on an AL, and the AL is tagged
56: with a 1, he will turn evil.
57: sprite[?].lotag = 2 When this sprite is operated, a bomb is shot at its
58: position.
59: sprite[?].lotag = 3 Rotating sprite.
60: sprite[?].lotag = 4 Sprite switch.
61: sprite[?].lotag = 5 Basketball hoop score.
62:
63: KEN'S STATUS DEFINITIONS: (Please define your own statuses for your games)
64: status = 0 Inactive sprite
65: status = 1 Active monster sprite
66: status = 2 Monster that becomes active only when it sees you
67: status = 3 Smoke on the wall for chainguns
68: status = 4 Splashing sprites (When you shoot slime)
69: status = 5 Explosion!
70: status = 6 Travelling bullet
71: status = 7 Bomb sprial-out explosion
72: status = 8 Player!
73: status = MAXSTATUS Non-existent sprite (this will be true for your
74: code also)
75: **************************************************************************/
76:
77: typedef struct
78: {
79: long x, y, z;
80: } point3d;
81:
82: void (__interrupt __far *oldtimerhandler)();
83: void __interrupt __far timerhandler(void);
84:
85: #define KEYFIFOSIZ 64
86: void (__interrupt __far *oldkeyhandler)();
87: void __interrupt __far keyhandler(void);
88: volatile char keystatus[256], keyfifo[KEYFIFOSIZ], keyfifoplc, keyfifoend;
89: volatile char readch, oldreadch, extended, keytemp;
90:
91: static long vel, svel, angvel;
92: static long vel2, svel2, angvel2;
93:
94: extern volatile long recsnddone, recsndoffs;
95: static long recording = -2;
96:
97: #define NUMOPTIONS 8
98: #define NUMKEYS 19
99: static long chainxres[4] = {256,320,360,400};
100: static long chainyres[11] = {200,240,256,270,300,350,360,400,480,512,540};
101: static long vesares[7][2] = {320,200,640,400,640,480,800,600,1024,768,
102: 1280,1024,1600,1200};
103: static char option[NUMOPTIONS] = {0,0,0,0,0,0,1,0};
104: static char keys[NUMKEYS] =
105: {
106: 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39,
107: 0x1e,0x2c,0xd1,0xc9,0x33,0x34,
108: 0x9c,0x1c,0xd,0xc,0xf,
109: };
110:
111: static long digihz[7] = {6000,8000,11025,16000,22050,32000,44100};
112:
113: static char frame2draw[MAXPLAYERS];
114: static long frameskipcnt[MAXPLAYERS];
115:
116: static char gundmost[320];
117:
118: #define LAVASIZ 128
119: #define LAVALOGSIZ 7
120: #define LAVAMAXDROPS 32
121: static char lavabakpic[(LAVASIZ+2)*(LAVASIZ+2)], lavainc[LAVASIZ];
122: static long lavanumdrops, lavanumframes;
123: static long lavadropx[LAVAMAXDROPS], lavadropy[LAVAMAXDROPS];
124: static long lavadropsiz[LAVAMAXDROPS], lavadropsizlookup[LAVAMAXDROPS];
125: static long lavaradx[32][128], lavarady[32][128], lavaradcnt[32];
126:
127: //Shared player variables
128: static long posx[MAXPLAYERS], posy[MAXPLAYERS], posz[MAXPLAYERS];
129: static long horiz[MAXPLAYERS], zoom[MAXPLAYERS], hvel[MAXPLAYERS];
130: static short ang[MAXPLAYERS], cursectnum[MAXPLAYERS], ocursectnum[MAXPLAYERS];
131: static short playersprite[MAXPLAYERS], deaths[MAXPLAYERS];
132: static long lastchaingun[MAXPLAYERS];
133: static long health[MAXPLAYERS], score[MAXPLAYERS], saywatchit[MAXPLAYERS];
134: static short numbombs[MAXPLAYERS], oflags[MAXPLAYERS];
135: static char dimensionmode[MAXPLAYERS];
136: static char revolvedoorstat[MAXPLAYERS];
137: static short revolvedoorang[MAXPLAYERS], revolvedoorrotang[MAXPLAYERS];
138: static long revolvedoorx[MAXPLAYERS], revolvedoory[MAXPLAYERS];
139:
140: //ENGINE CONTROLLED MULTIPLAYER VARIABLES:
141: extern short numplayers, myconnectindex;
142: extern short connecthead, connectpoint2[MAXPLAYERS]; //Player linked list variables (indeces, not connection numbers)
143:
144: //Local multiplayer variables
145: static long locselectedgun;
146: static signed char locvel, olocvel;
147: static signed char locsvel, olocsvel;
148: static signed char locangvel, olocangvel;
149: static short locbits, olocbits;
150:
151: //Local multiplayer variables for second player
152: static long locselectedgun2;
153: static signed char locvel2, olocvel2;
154: static signed char locsvel2, olocsvel2;
155: static signed char locangvel2, olocangvel2;
156: static short locbits2, olocbits2;
157:
158: //Multiplayer syncing variables
159: static signed char fsyncvel[MAXPLAYERS], osyncvel[MAXPLAYERS], syncvel[MAXPLAYERS];
160: static signed char fsyncsvel[MAXPLAYERS], osyncsvel[MAXPLAYERS], syncsvel[MAXPLAYERS];
161: static signed char fsyncangvel[MAXPLAYERS], osyncangvel[MAXPLAYERS], syncangvel[MAXPLAYERS];
162: static short fsyncbits[MAXPLAYERS], osyncbits[MAXPLAYERS], syncbits[MAXPLAYERS];
163:
164: static char frameinterpolate = 1, detailmode = 0, ready2send = 0;
165: static long ototalclock = 0, gotlastpacketclock = 0, smoothratio;
166: static long oposx[MAXPLAYERS], oposy[MAXPLAYERS], oposz[MAXPLAYERS];
167: static long ohoriz[MAXPLAYERS], ozoom[MAXPLAYERS];
168: static short oang[MAXPLAYERS];
169:
170: static point3d osprite[MAXSPRITESONSCREEN];
171:
172: static long movefifoplc, movefifoend;
173: static signed char baksyncvel[MOVEFIFOSIZ][MAXPLAYERS];
174: static signed char baksyncsvel[MOVEFIFOSIZ][MAXPLAYERS];
175: static signed char baksyncangvel[MOVEFIFOSIZ][MAXPLAYERS];
176: static short baksyncbits[MOVEFIFOSIZ][MAXPLAYERS];
177:
178: //MULTI.OBJ sync state variables
179: extern char syncstate;
180: //GAME.C sync state variables
181: static short syncstat = 0;
182: static long syncvalplc, othersyncvalplc;
183: static long syncvalend, othersyncvalend;
184: static long syncvalcnt, othersyncvalcnt;
185: static short syncval[MOVEFIFOSIZ], othersyncval[MOVEFIFOSIZ];
186:
187: extern long crctable[256];
188: #define updatecrc16(dacrc,dadat) dacrc = (((dacrc<<8)&65535)^crctable[((((unsigned short)dacrc)>>8)&65535)^dadat])
189: static char playerreadyflag[MAXPLAYERS];
190:
191: //Game recording variables
192: static long reccnt, recstat = 1;
193: static signed char recsyncvel[16384][2];
194: static signed char recsyncsvel[16384][2];
195: static signed char recsyncangvel[16384][2];
196: static short recsyncbits[16384][2];
197:
198: //Miscellaneous variables
199: static char tempbuf[max(576,MAXXDIM)], boardfilename[80];
200: static short screenpeek = 0, oldmousebstatus = 0, brightness = 0;
201: static short screensize, screensizeflag = 0;
202: static short neartagsector, neartagwall, neartagsprite;
203: static long lockclock, neartagdist, neartaghitdist;
204: static long masterslavetexttime;
205: extern long frameplace, pageoffset, ydim16, chainnumpages;
206: static long globhiz, globloz, globhihit, globlohit;
207: extern long stereofps, stereowidth, stereopixelwidth;
208:
209: //Board animation variables
210: static short rotatespritelist[16], rotatespritecnt;
211: static short warpsectorlist[64], warpsectorcnt;
212: static short xpanningsectorlist[16], xpanningsectorcnt;
213: static short ypanningwalllist[64], ypanningwallcnt;
214: static short floorpanninglist[64], floorpanningcnt;
215: static short dragsectorlist[16], dragxdir[16], dragydir[16], dragsectorcnt;
216: static long dragx1[16], dragy1[16], dragx2[16], dragy2[16], dragfloorz[16];
217: static short swingcnt, swingwall[32][5], swingsector[32];
218: static short swingangopen[32], swingangclosed[32], swingangopendir[32];
219: static short swingang[32], swinganginc[32];
220: static long swingx[32][8], swingy[32][8];
221: static short revolvesector[4], revolveang[4], revolvecnt;
222: static long revolvex[4][16], revolvey[4][16];
223: static long revolvepivotx[4], revolvepivoty[4];
224: static short subwaytracksector[4][128], subwaynumsectors[4], subwaytrackcnt;
225: static long subwaystop[4][8], subwaystopcnt[4];
226: static long subwaytrackx1[4], subwaytracky1[4];
227: static long subwaytrackx2[4], subwaytracky2[4];
228: static long subwayx[4], subwaygoalstop[4], subwayvel[4], subwaypausetime[4];
229: static short waterfountainwall[MAXPLAYERS], waterfountaincnt[MAXPLAYERS];
230: static short slimesoundcnt[MAXPLAYERS];
231:
232: //Variables that let you type messages to other player
233: static char getmessage[162], getmessageleng;
234: static long getmessagetimeoff;
235: static char typemessage[162], typemessageleng = 0, typemode = 0;
236: static char scantoasc[128] =
237: {
238: 0,0,'1','2','3','4','5','6','7','8','9','0','-','=',0,0,
239: 'q','w','e','r','t','y','u','i','o','p','[',']',0,0,'a','s',
240: 'd','f','g','h','j','k','l',';',39,'`',0,92,'z','x','c','v',
241: 'b','n','m',',','.','/',0,'*',0,32,0,0,0,0,0,0,
242: 0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
243: '2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
244: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
245: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
246: };
247: static char scantoascwithshift[128] =
248: {
249: 0,0,'!','@','#','$','%','^','&','*','(',')','_','+',0,0,
250: 'Q','W','E','R','T','Y','U','I','O','P','{','}',0,0,'A','S',
251: 'D','F','G','H','J','K','L',':',34,'~',0,'|','Z','X','C','V',
252: 'B','N','M','<','>','?',0,'*',0,32,0,0,0,0,0,0,
253: 0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
254: '2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
255: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
256: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
257: };
258:
259: //These variables are for animating x, y, or z-coordinates of sectors,
260: //walls, or sprites (They are NOT to be used for changing the [].picnum's)
261: //See the setanimation(), and getanimategoal() functions for more details.
262: #define MAXANIMATES 512
263: static long *animateptr[MAXANIMATES], animategoal[MAXANIMATES];
264: static long animatevel[MAXANIMATES], animateacc[MAXANIMATES], animatecnt = 0;
265:
266: //Here are some nice in-line assembly pragmas that make life easier.
267: //(at least for Ken)
268: #pragma aux setvmode =\
269: "int 0x10",\
270: parm [eax]\
271:
272: #pragma aux clearbuf =\
273: "rep stosd",\
274: parm [edi][ecx][eax]\
275:
276: #pragma aux clearbufbyte =\
277: "shr ecx, 1",\
278: "jnc skip1",\
279: "stosb",\
280: "skip1: shr ecx, 1",\
281: "jnc skip2",\
282: "stosw",\
283: "skip2: test ecx, ecx",\
284: "jz skip3",\
285: "rep stosd",\
286: "skip3:",\
287: parm [edi][ecx][eax]\
288:
289: #pragma aux copybuf =\
290: "rep movsd",\
291: parm [esi][edi][ecx]\
292:
293: #pragma aux copybufbyte =\
294: "shr ecx, 1",\
295: "jnc skip1",\
296: "movsb",\
297: "skip1: shr ecx, 1",\
298: "jnc skip2",\
299: "movsw",\
300: "skip2: test ecx, ecx",\
301: "jz skip3",\
302: "rep movsd",\
303: "skip3:",\
304: parm [esi][edi][ecx]\
305:
306: #pragma aux copybufreverse =\
307: "shr ecx, 1",\
308: "jnc skipit1",\
309: "mov al, byte ptr [esi]",\
310: "dec esi",\
311: "mov byte ptr [edi], al",\
312: "inc edi",\
313: "skipit1: shr ecx, 1",\
314: "jnc skipit2",\
315: "mov ax, word ptr [esi-1]",\
316: "sub esi, 2",\
317: "ror ax, 8",\
318: "mov word ptr [edi], ax",\
319: "add edi, 2",\
320: "skipit2: test ecx, ecx",\
321: "jz endloop",\
322: "begloop: mov eax, dword ptr [esi-3]",\
323: "sub esi, 4",\
324: "bswap eax",\
325: "mov dword ptr [edi], eax",\
326: "add edi, 4",\
327: "dec ecx",\
328: "jnz begloop",\
329: "endloop:",\
330: parm [esi][edi][ecx]\
331:
332: #pragma aux klabs =\
333: "test eax, eax",\
334: "jns skipnegate",\
335: "neg eax",\
336: "skipnegate:",\
337: parm [eax]\
338:
339: #pragma aux ksgn =\
340: "add ebx, ebx",\
341: "sbb eax, eax",\
342: "cmp eax, ebx",\
343: "adc eax, 0",\
344: parm [ebx]\
345:
346: #pragma aux koutp =\
347: "out dx, al",\
348: parm [edx][eax]\
349:
350: #pragma aux koutpw =\
351: "out dx, ax",\
352: parm [edx][eax]\
353:
354: #pragma aux kinp =\
355: "in al, dx",\
356: parm [edx]\
357:
358: #pragma aux mulscale =\
359: "imul ebx",\
360: "shrd eax, edx, cl",\
361: parm [eax][ebx][ecx]\
362: modify [edx]\
363:
364: #pragma aux divscale =\
365: "mov edx, eax",\
366: "sar edx, 31",\
367: "shld edx, eax, cl",\
368: "sal eax, cl",\
369: "idiv ebx",\
370: parm [eax][ebx][ecx]\
371: modify [edx]\
372:
373: #pragma aux scale =\
374: "imul ebx",\
375: "idiv ecx",\
376: parm [eax][ebx][ecx]\
377: modify [eax edx]\
378:
379: //These parameters are in exact order of sprite structure in BUILD.H
380: #define spawnsprite(newspriteindex2,x2,y2,z2,cstat2,shade2,pal2, \
381: clipdist2,xrepeat2,yrepeat2,xoffset2,yoffset2,picnum2,ang2, \
382: xvel2,yvel2,zvel2,owner2,sectnum2,statnum2,lotag2,hitag2,extra2) \
383: { \
384: spritetype *spr2; \
385: newspriteindex2 = insertsprite(sectnum2,statnum2); \
386: spr2 = &sprite[newspriteindex2]; \
387: spr2->x = x2; spr2->y = y2; spr2->z = z2; \
388: spr2->cstat = cstat2; spr2->shade = shade2; \
389: spr2->pal = pal2; spr2->clipdist = clipdist2; \
390: spr2->xrepeat = xrepeat2; spr2->yrepeat = yrepeat2; \
391: spr2->xoffset = xoffset2; spr2->yoffset = yoffset2; \
392: spr2->picnum = picnum2; spr2->ang = ang2; \
393: spr2->xvel = xvel2; spr2->yvel = yvel2; spr2->zvel = zvel2; \
394: spr2->owner = owner2; \
395: spr2->lotag = lotag2; spr2->hitag = hitag2; spr2->extra = extra2; \
396: copybuf(&spr2->x,&osprite[newspriteindex2].x,3); \
397: } \
398:
399: main(short int argc,char **argv)
400: {
401: long i, j, k, l, fil, waitplayers, x1, y1, x2, y2;
402: short other, tempbufleng;
403: char *ptr;
404:
405: initgroupfile("stuff.dat");
406:
407: if ((argc >= 2) && (stricmp("-net",argv[1]) != 0) && (stricmp("/net",argv[1]) != 0))
408: {
409: strcpy(&boardfilename,argv[1]);
410: if(strchr(boardfilename,'.') == 0)
411: strcat(boardfilename,".map");
412: }
413: else
414: strcpy(&boardfilename,"nukeland.map");
415:
416: if ((fil = open("setup.dat",O_BINARY|O_RDWR,S_IREAD)) != -1)
417: {
418: read(fil,&option[0],NUMOPTIONS);
419: read(fil,&keys[0],NUMKEYS);
420: close(fil);
421: }
422: if (option[3] != 0) initmouse();
423:
424: switch(option[0])
425: {
426: case 0: initengine(0,chainxres[option[6]&15],chainyres[option[6]>>4]); break;
427: case 1: initengine(1,vesares[option[6]&15][0],vesares[option[6]&15][1]); break;
428: case 2: initengine(2,320L,200L); break;
429: case 3: initengine(3,320L,200L); break;
430: case 4: initengine(4,320L,200L); break;
431: case 5: initengine(5,320L,200L); break;
432: case 6: initengine(6,320L,200L); break;
433: }
434: initkeys();
435: inittimer();
436: initmultiplayers(option[4],option[5]);
437:
438: pskyoff[0] = 0; pskyoff[1] = 0; pskybits = 1;
439:
440: initsb(option[1],option[2],digihz[option[7]>>4],((option[7]&4)>0)+1,((option[7]&2)>0)+1,60,option[7]&1);
441: if (strcmp(boardfilename,"klab.map") == 0)
442: loadsong("klabsong.kdm");
443: else
444: loadsong("neatsong.kdm");
445: musicon();
446:
447: loadpics("tiles000.art"); //Load artwork
448: initlava();
449:
450: //Get dmost table for canon
451: if (waloff[GUNONBOTTOM] == 0) loadtile(GUNONBOTTOM);
452: x1 = tilesizx[GUNONBOTTOM]; y1 = tilesizy[GUNONBOTTOM];
453: ptr = (char *)(waloff[GUNONBOTTOM]);
454: for(i=0;i<x1;i++)
455: {
456: y2 = y1-1; while ((ptr[y2] != 255) && (y2 >= 0)) y2--;
457: gundmost[i] = y2+1;
458: ptr += y1;
459: }
460:
461: //Try making a title screen & uncommenting this!
462: //setgamemode();
463: //setview(0L,0L,xdim-1,(ydim-1)>>detailmode);
464: //loadtile(TITLESCREEN);
465: //i = 0; j = 1621;
466: //for(k=0;k<256;k++)
467: //{
468: // for(l=0;l<256;l++)
469: // {
470: // ptr = (char *)(waloff[TITLESCREEN]+i);
471: // *ptr = 159;
472: // i = (i+j)&65535; j = (j+4)&65535;
473: // }
474: // overwritesprite(0L,0L,TITLESCREEN,0,0,0);
475: // nextpage();
476: //}
477:
478: //Here's an example of TRUE ornamented walls
479: //The allocatepermanenttile should be called right after loadpics
480: //Since it resets the tile cache for each call.
481: if (allocatepermanenttile(4095,64,64) >= 0) //If enough memory
482: {
483: //My face with an explosion written over it
484: copytilepiece(KENPICTURE,0,0,64,64,4095,0,0);
485: copytilepiece(EXPLOSION,0,0,64,64,4095,0,0);
486: }
487: if (allocatepermanenttile(SLIME,128,128) < 0) //If enough memory
488: {
489: printf("Not enough memory for slime!\n");
490: exit(0);
491: }
492:
493: for(j=0;j<256;j++)
494: tempbuf[j] = ((j+32)&255); //remap colors for screwy palette sectors
495: makepalookup(16,tempbuf,0,0,0,1);
496:
497: for(j=0;j<256;j++) tempbuf[j] = j;
498: makepalookup(17,tempbuf,24,24,24,1);
499:
500: for(j=0;j<256;j++) tempbuf[j] = j; //(j&31)+32;
501: makepalookup(18,tempbuf,8,8,48,1);
502:
503: prepareboard(boardfilename); //Load board
504:
505: if (option[4] > 0)
506: {
507: x1 = (xdim>>1)-(screensize>>1);
508: x2 = x1+screensize-1;
509: y1 = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
510: y2 = y1 + ((screensize*(ydim-32))/xdim)-1;
511: permanentwritespritetile(0L,0L,BACKGROUND,0,x1,y1,x2,y2,0);
512:
513: sendlogon();
514: if (option[4] < 5) waitplayers = 2; else waitplayers = option[4]-3;
515: while (numplayers < waitplayers)
516: {
517: sprintf(tempbuf,"%ld of %ld players in...",numplayers,waitplayers);
518: printext256(68L,84L,31,0,tempbuf,0);
519: nextpage();
520:
521: if (getpacket(&other,tempbuf) > 0)
522: if (tempbuf[0] == 255)
523: keystatus[1] = 1;
524:
525: if (keystatus[1] > 0)
526: {
527: sendlogoff(); //Signing off
528: musicoff();
529: uninitmultiplayers();
530: uninittimer();
531: uninitkeys();
532: uninitengine();
533: uninitsb();
534: uninitgroupfile();
535: setvmode(0x3); //Set back to text mode
536: exit(0);
537: }
538: }
539: screenpeek = myconnectindex;
540: }
541:
542: reccnt = 0;
543: for(i=connecthead;i>=0;i=connectpoint2[i]) initplayersprite((short)i);
544:
545: //waitforeverybody();
546: resettiming(); ototalclock = 0; gotlastpacketclock = 0;
547:
548: ready2send = 1;
549: while (keystatus[1] == 0) //Main loop starts here
550: {
551: // backslash (useful only with KDM)
552: if (keystatus[0x2b] > 0) { keystatus[0x2b] = 0; preparesndbuf(); }
553:
554: while (movefifoplc != movefifoend) domovethings();
555: drawscreen(screenpeek,(totalclock-gotlastpacketclock)*(65536/TICSPERFRAME));
556: }
557: ready2send = 0;
558:
559: sendlogoff(); //Signing off
560: musicoff();
561: uninitmultiplayers();
562: uninittimer();
563: uninitkeys();
564: uninitengine();
565: uninitsb();
566: uninitgroupfile();
567: setvmode(0x3); //Set back to text mode
568: showengineinfo(); //Show speed statistics
569:
570: return(0);
571: }
572:
573: operatesector(short dasector)
574: { //Door code
575: long i, j, k, s, nexti, good, cnt, datag;
576: long dax, day, daz, dax2, day2, daz2, centx, centy;
577: short startwall, endwall, wallfind[2];
578:
579: datag = sector[dasector].lotag;
580:
581: startwall = sector[dasector].wallptr;
582: endwall = startwall + sector[dasector].wallnum - 1;
583: centx = 0L, centy = 0L;
584: for(i=startwall;i<=endwall;i++)
585: {
586: centx += wall[i].x;
587: centy += wall[i].y;
588: }
589: centx /= (endwall-startwall+1);
590: centy /= (endwall-startwall+1);
591:
592: //Simple door that moves up (tag 8 is a combination of tags 6 & 7)
593: if ((datag == 6) || (datag == 8)) //If the sector in front is a door
594: {
595: i = getanimationgoal((long)§or[dasector].ceilingz);
596: if (i >= 0) //If door already moving, reverse its direction
597: {
598: if (datag == 8)
599: daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1);
600: else
601: daz = sector[dasector].floorz;
602:
603: if (animategoal[i] == daz)
604: animategoal[i] = sector[nextsectorneighborz(dasector,sector[dasector].floorz,-1,-1)].ceilingz;
605: else
606: animategoal[i] = daz;
607: animatevel[i] = 0;
608: }
609: else //else insert the door's ceiling on the animation list
610: {
611: if (sector[dasector].ceilingz == sector[dasector].floorz)
612: daz = sector[nextsectorneighborz(dasector,sector[dasector].floorz,-1,-1)].ceilingz;
613: else
614: {
615: if (datag == 8)
616: daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1);
617: else
618: daz = sector[dasector].floorz;
619: }
620: if ((j = setanimation(§or[dasector].ceilingz,daz,6L,6L)) >= 0)
621: wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,¢x,¢y,0);
622: }
623: }
624: //Simple door that moves down
625: if ((datag == 7) || (datag == 8)) //If the sector in front's elevator
626: {
627: i = getanimationgoal((long)§or[dasector].floorz);
628: if (i >= 0) //If elevator already moving, reverse its direction
629: {
630: if (datag == 8)
631: daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1);
632: else
633: daz = sector[dasector].ceilingz;
634:
635: if (animategoal[i] == daz)
636: animategoal[i] = sector[nextsectorneighborz(dasector,sector[dasector].ceilingz,1,1)].floorz;
637: else
638: animategoal[i] = daz;
639: animatevel[i] = 0;
640: }
641: else //else insert the elevator's ceiling on the animation list
642: {
643: if (sector[dasector].floorz == sector[dasector].ceilingz)
644: daz = sector[nextsectorneighborz(dasector,sector[dasector].ceilingz,1,1)].floorz;
645: else
646: {
647: if (datag == 8)
648: daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1);
649: else
650: daz = sector[dasector].ceilingz;
651: }
652: if ((j = setanimation(§or[dasector].floorz,daz,6L,6L)) >= 0)
653: wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,¢x,¢y,0);
654: }
655: }
656:
657: if (datag == 9) //Smooshy-wall sideways double-door
658: {
659: //find any points with either same x or same y coordinate
660: // as center (centx, centy) - should be 2 points found.
661: wallfind[0] = -1;
662: wallfind[1] = -1;
663: for(i=startwall;i<=endwall;i++)
664: if ((wall[i].x == centx) || (wall[i].y == centy))
665: {
666: if (wallfind[0] == -1)
667: wallfind[0] = i;
668: else
669: wallfind[1] = i;
670: }
671:
672: for(j=0;j<2;j++)
673: {
674: if ((wall[wallfind[j]].x == centx) && (wall[wallfind[j]].y == centy))
675: {
676: //find what direction door should open by averaging the
677: // 2 neighboring points of wallfind[0] & wallfind[1].
678: i = wallfind[j]-1; if (i < startwall) i = endwall;
679: dax2 = ((wall[i].x+wall[wall[wallfind[j]].point2].x)>>1)-wall[wallfind[j]].x;
680: day2 = ((wall[i].y+wall[wall[wallfind[j]].point2].y)>>1)-wall[wallfind[j]].y;
681: if (dax2 != 0)
682: {
683: dax2 = wall[wall[wall[wallfind[j]].point2].point2].x;
684: dax2 -= wall[wall[wallfind[j]].point2].x;
685: setanimation(&wall[wallfind[j]].x,wall[wallfind[j]].x+dax2,4L,0L);
686: setanimation(&wall[i].x,wall[i].x+dax2,4L,0L);
687: setanimation(&wall[wall[wallfind[j]].point2].x,wall[wall[wallfind[j]].point2].x+dax2,4L,0L);
688: }
689: else if (day2 != 0)
690: {
691: day2 = wall[wall[wall[wallfind[j]].point2].point2].y;
692: day2 -= wall[wall[wallfind[j]].point2].y;
693: setanimation(&wall[wallfind[j]].y,wall[wallfind[j]].y+day2,4L,0L);
694: setanimation(&wall[i].y,wall[i].y+day2,4L,0L);
695: setanimation(&wall[wall[wallfind[j]].point2].y,wall[wall[wallfind[j]].point2].y+day2,4L,0L);
696: }
697: }
698: else
699: {
700: i = wallfind[j]-1; if (i < startwall) i = endwall;
701: dax2 = ((wall[i].x+wall[wall[wallfind[j]].point2].x)>>1)-wall[wallfind[j]].x;
702: day2 = ((wall[i].y+wall[wall[wallfind[j]].point2].y)>>1)-wall[wallfind[j]].y;
703: if (dax2 != 0)
704: {
705: setanimation(&wall[wallfind[j]].x,centx,4L,0L);
706: setanimation(&wall[i].x,centx+dax2,4L,0L);
707: setanimation(&wall[wall[wallfind[j]].point2].x,centx+dax2,4L,0L);
708: }
709: else if (day2 != 0)
710: {
711: setanimation(&wall[wallfind[j]].y,centy,4L,0L);
712: setanimation(&wall[i].y,centy+day2,4L,0L);
713: setanimation(&wall[wall[wallfind[j]].point2].y,centy+day2,4L,0L);
714: }
715: }
716: }
717: wsayfollow("updowndr.wav",4096L-256L,256L,¢x,¢y,0);
718: wsayfollow("updowndr.wav",4096L+256L,256L,¢x,¢y,0);
719: }
720:
721: if (datag == 13) //Swinging door
722: {
723: for(i=0;i<swingcnt;i++)
724: {
725: if (swingsector[i] == dasector)
726: {
727: if (swinganginc[i] == 0)
728: {
729: if (swingang[i] == swingangclosed[i])
730: {
731: swinganginc[i] = swingangopendir[i];
732: wsayfollow("opendoor.wav",4096L+(krand()&511)-256,256L,¢x,¢y,0);
733: }
734: else
735: swinganginc[i] = -swingangopendir[i];
736: }
737: else
738: swinganginc[i] = -swinganginc[i];
739: }
740: }
741: }
742:
743: if (datag == 16) //True sideways double-sliding door
744: {
745: //get 2 closest line segments to center (dax, day)
746: wallfind[0] = -1;
747: wallfind[1] = -1;
748: for(i=startwall;i<=endwall;i++)
749: if (wall[i].lotag == 6)
750: {
751: if (wallfind[0] == -1)
752: wallfind[0] = i;
753: else
754: wallfind[1] = i;
755: }
756:
757: for(j=0;j<2;j++)
758: {
759: 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))
760: { //door was closed
761: //find what direction door should open
762: i = wallfind[j]-1; if (i < startwall) i = endwall;
763: dax2 = wall[i].x-wall[wallfind[j]].x;
764: day2 = wall[i].y-wall[wallfind[j]].y;
765: if (dax2 != 0)
766: {
767: dax2 = wall[wall[wall[wall[wallfind[j]].point2].point2].point2].x;
768: dax2 -= wall[wall[wall[wallfind[j]].point2].point2].x;
769: setanimation(&wall[wallfind[j]].x,wall[wallfind[j]].x+dax2,4L,0L);
770: setanimation(&wall[i].x,wall[i].x+dax2,4L,0L);
771: setanimation(&wall[wall[wallfind[j]].point2].x,wall[wall[wallfind[j]].point2].x+dax2,4L,0L);
772: setanimation(&wall[wall[wall[wallfind[j]].point2].point2].x,wall[wall[wall[wallfind[j]].point2].point2].x+dax2,4L,0L);
773: }
774: else if (day2 != 0)
775: {
776: day2 = wall[wall[wall[wall[wallfind[j]].point2].point2].point2].y;
777: day2 -= wall[wall[wall[wallfind[j]].point2].point2].y;
778: setanimation(&wall[wallfind[j]].y,wall[wallfind[j]].y+day2,4L,0L);
779: setanimation(&wall[i].y,wall[i].y+day2,4L,0L);
780: setanimation(&wall[wall[wallfind[j]].point2].y,wall[wall[wallfind[j]].point2].y+day2,4L,0L);
781: setanimation(&wall[wall[wall[wallfind[j]].point2].point2].y,wall[wall[wall[wallfind[j]].point2].point2].y+day2,4L,0L);
782: }
783: }
784: else
785: { //door was not closed
786: i = wallfind[j]-1; if (i < startwall) i = endwall;
787: dax2 = wall[i].x-wall[wallfind[j]].x;
788: day2 = wall[i].y-wall[wallfind[j]].y;
789: if (dax2 != 0)
790: {
791: setanimation(&wall[wallfind[j]].x,centx,4L,0L);
792: setanimation(&wall[i].x,centx+dax2,4L,0L);
793: setanimation(&wall[wall[wallfind[j]].point2].x,centx,4L,0L);
794: setanimation(&wall[wall[wall[wallfind[j]].point2].point2].x,centx+dax2,4L,0L);
795: }
796: else if (day2 != 0)
797: {
798: setanimation(&wall[wallfind[j]].y,centy,4L,0L);
799: setanimation(&wall[i].y,centy+day2,4L,0L);
800: setanimation(&wall[wall[wallfind[j]].point2].y,centy,4L,0L);
801: setanimation(&wall[wall[wall[wallfind[j]].point2].point2].y,centy+day2,4L,0L);
802: }
803: }
804: }
805: wsayfollow("updowndr.wav",4096L-64L,256L,¢x,¢y,0);
806: wsayfollow("updowndr.wav",4096L+64L,256L,¢x,¢y,0);
807: }
808: }
809:
810: operatesprite(short dasprite)
811: {
812: long datag;
813:
814: datag = sprite[dasprite].lotag;
815:
816: if (datag == 2) //A sprite that shoots a bomb
817: {
818: shootgun(dasprite,
819: sprite[dasprite].x,sprite[dasprite].y,sprite[dasprite].z,
820: sprite[dasprite].ang,100L,sprite[dasprite].sectnum,2);
821: }
822: }
823:
824: changehealth(short snum, short deltahealth)
825: {
826: long dax, day;
827: short good, k, startwall, endwall, s;
828:
829: if (health[snum] > 0)
830: {
831: health[snum] += deltahealth;
832: if (health[snum] > 999) health[snum] = 999;
833:
834: if (health[snum] <= 0)
835: {
836: health[snum] = -1;
837: wsayfollow("death.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
838: sprite[playersprite[snum]].picnum = SKELETON;
839: }
840:
841: if ((snum == screenpeek) && (screensize <= xdim))
842: {
843: if (health[snum] > 0)
844: sprintf(&tempbuf,"Health: %3d",health[snum]);
845: else
846: sprintf(&tempbuf,"YOU STINK!!");
847:
848: printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-24,tempbuf,ALPHABET,80);
849: }
850: }
851: return(health[snum] <= 0); //You were just injured
852: }
853:
854: changescore(short snum, short deltascore)
855: {
856: score[snum] += deltascore;
857:
858: if ((snum == screenpeek) && (screensize <= xdim))
859: {
860: sprintf(&tempbuf,"Score:%ld",score[snum]);
861: printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-8,tempbuf,ALPHABET,80);
862: }
863: }
864:
865: prepareboard(char *daboardfilename)
866: {
867: short startwall, endwall, dasector;
868: long i, j, k, s, dax, day, daz, dax2, day2;
869:
870: getmessageleng = 0;
871: typemessageleng = 0;
872:
873: randomseed = 17L;
874:
875: //Clear (do)animation's list
876: animatecnt = 0;
877: typemode = 0;
878: locselectedgun = 0;
879: locselectedgun2 = 0;
880:
881: if (loadboard(daboardfilename,&posx[0],&posy[0],&posz[0],&ang[0],&cursectnum[0]) == -1)
882: {
883: musicoff();
884: uninitmultiplayers();
885: uninittimer();
886: uninitkeys();
887: uninitengine();
888: uninitsb();
889: uninitgroupfile();
890: setvmode(0x3); //Set back to text mode
891: printf("Board not found\n");
892: exit(0);
893: }
894: precache();
895:
896: for(i=0;i<MAXPLAYERS;i++)
897: {
898: posx[i] = posx[0];
899: posy[i] = posy[0];
900: posz[i] = posz[0];
901: ang[i] = ang[0];
902: cursectnum[i] = cursectnum[0];
903: ocursectnum[i] = cursectnum[0];
904: horiz[i] = 100;
905: lastchaingun[i] = 0;
906: health[i] = 100;
907: score[i] = 0L;
908: dimensionmode[i] = 3;
909: numbombs[i] = -1;
910: zoom[i] = 768L;
911: deaths[i] = 0L;
912: playersprite[i] = -1;
913: saywatchit[i] = -1;
914: screensize = xdim;
915:
916: oposx[i] = posx[0];
917: oposy[i] = posy[0];
918: oposz[i] = posz[0];
919: ohoriz[i] = horiz[0];
920: ozoom[i] = zoom[0];
921: oang[i] = ang[0];
922: }
923:
924: movefifoplc = 0; movefifoend = 0;
925: syncvalplc = 0L; othersyncvalplc = 0L;
926: syncvalend = 0L; othersyncvalend = 0L;
927: syncvalcnt = 0L; othersyncvalcnt = 0L;
928:
929: setup3dscreen();
930:
931: olocvel = 0; olocvel2 = 0;
932: olocsvel = 0; olocsvel2 = 0;
933: olocangvel = 0; olocangvel2 = 0;
934: olocbits = 0; olocbits2 = 0;
935: for(i=0;i<MAXPLAYERS;i++)
936: {
937: fsyncvel[i] = syncvel[i] = osyncvel[i] = 0;
938: fsyncsvel[i] = syncsvel[i] = osyncsvel[i] = 0;
939: fsyncangvel[i] = syncangvel[i] = osyncangvel[i] = 0;
940: fsyncbits[i] = syncbits[i] = osyncbits[i] = 0;
941: }
942:
943: //Scan sector tags
944:
945: for(i=0;i<MAXPLAYERS;i++)
946: {
947: waterfountainwall[i] = -1;
948: waterfountaincnt[i] = 0;
949: }
950: slimesoundcnt[i] = 0;
951: warpsectorcnt = 0; //Make a list of warping sectors
952: xpanningsectorcnt = 0; //Make a list of wall x-panning sectors
953: floorpanningcnt = 0; //Make a list of slime sectors
954: dragsectorcnt = 0; //Make a list of moving platforms
955: swingcnt = 0; //Make a list of swinging doors
956: revolvecnt = 0; //Make a list of revolving doors
957: subwaytrackcnt = 0; //Make a list of subways
958:
959: for(i=0;i<numsectors;i++)
960: {
961: switch(sector[i].lotag)
962: {
963: case 4:
964: floorpanninglist[floorpanningcnt++] = i;
965: break;
966: case 10:
967: warpsectorlist[warpsectorcnt++] = i;
968: break;
969: case 11:
970: xpanningsectorlist[xpanningsectorcnt++] = i;
971: break;
972: case 12:
973: dasector = i;
974: dax = 0x7fffffff;
975: day = 0x7fffffff;
976: dax2 = 0x80000000;
977: day2 = 0x80000000;
978: startwall = sector[i].wallptr;
979: endwall = startwall+sector[i].wallnum-1;
980: for(j=startwall;j<=endwall;j++)
981: {
982: if (wall[j].x < dax) dax = wall[j].x;
983: if (wall[j].y < day) day = wall[j].y;
984: if (wall[j].x > dax2) dax2 = wall[j].x;
985: if (wall[j].y > day2) day2 = wall[j].y;
986: if (wall[j].lotag == 3) k = j;
987: }
988: if (wall[k].x == dax) dragxdir[dragsectorcnt] = -16;
989: if (wall[k].y == day) dragydir[dragsectorcnt] = -16;
990: if (wall[k].x == dax2) dragxdir[dragsectorcnt] = 16;
991: if (wall[k].y == day2) dragydir[dragsectorcnt] = 16;
992:
993: dasector = wall[startwall].nextsector;
994: dragx1[dragsectorcnt] = 0x7fffffff;
995: dragy1[dragsectorcnt] = 0x7fffffff;
996: dragx2[dragsectorcnt] = 0x80000000;
997: dragy2[dragsectorcnt] = 0x80000000;
998: startwall = sector[dasector].wallptr;
999: endwall = startwall+sector[dasector].wallnum-1;
1000: for(j=startwall;j<=endwall;j++)
1001: {
1002: if (wall[j].x < dragx1[dragsectorcnt]) dragx1[dragsectorcnt] = wall[j].x;
1003: if (wall[j].y < dragy1[dragsectorcnt]) dragy1[dragsectorcnt] = wall[j].y;
1004: if (wall[j].x > dragx2[dragsectorcnt]) dragx2[dragsectorcnt] = wall[j].x;
1005: if (wall[j].y > dragy2[dragsectorcnt]) dragy2[dragsectorcnt] = wall[j].y;
1006: }
1007:
1008: dragx1[dragsectorcnt] += (wall[sector[i].wallptr].x-dax);
1009: dragy1[dragsectorcnt] += (wall[sector[i].wallptr].y-day);
1010: dragx2[dragsectorcnt] -= (dax2-wall[sector[i].wallptr].x);
1011: dragy2[dragsectorcnt] -= (day2-wall[sector[i].wallptr].y);
1012:
1013: dragfloorz[dragsectorcnt] = sector[i].floorz;
1014:
1015: dragsectorlist[dragsectorcnt++] = i;
1016: break;
1017: case 13:
1018: startwall = sector[i].wallptr;
1019: endwall = startwall+sector[i].wallnum-1;
1020: for(j=startwall;j<=endwall;j++)
1021: {
1022: if (wall[j].lotag == 4)
1023: {
1024: k = wall[wall[wall[wall[j].point2].point2].point2].point2;
1025: if ((wall[j].x == wall[k].x) && (wall[j].y == wall[k].y))
1026: { //Door opens counterclockwise
1027: swingwall[swingcnt][0] = j;
1028: swingwall[swingcnt][1] = wall[j].point2;
1029: swingwall[swingcnt][2] = wall[wall[j].point2].point2;
1030: swingwall[swingcnt][3] = wall[wall[wall[j].point2].point2].point2;
1031: swingangopen[swingcnt] = 1536;
1032: swingangclosed[swingcnt] = 0;
1033: swingangopendir[swingcnt] = -1;
1034: }
1035: else
1036: { //Door opens clockwise
1037: swingwall[swingcnt][0] = wall[j].point2;
1038: swingwall[swingcnt][1] = j;
1039: swingwall[swingcnt][2] = lastwall(j);
1040: swingwall[swingcnt][3] = lastwall(swingwall[swingcnt][2]);
1041: swingwall[swingcnt][4] = lastwall(swingwall[swingcnt][3]);
1042: swingangopen[swingcnt] = 512;
1043: swingangclosed[swingcnt] = 0;
1044: swingangopendir[swingcnt] = 1;
1045: }
1046: for(k=0;k<4;k++)
1047: {
1048: swingx[swingcnt][k] = wall[swingwall[swingcnt][k]].x;
1049: swingy[swingcnt][k] = wall[swingwall[swingcnt][k]].y;
1050: }
1051:
1052: swingsector[swingcnt] = i;
1053: swingang[swingcnt] = swingangclosed[swingcnt];
1054: swinganginc[swingcnt] = 0;
1055: swingcnt++;
1056: }
1057: }
1058: break;
1059: case 14:
1060: startwall = sector[i].wallptr;
1061: endwall = startwall+sector[i].wallnum-1;
1062: dax = 0L;
1063: day = 0L;
1064: for(j=startwall;j<=endwall;j++)
1065: {
1066: dax += wall[j].x;
1067: day += wall[j].y;
1068: }
1069: revolvepivotx[revolvecnt] = dax / (endwall-startwall+1);
1070: revolvepivoty[revolvecnt] = day / (endwall-startwall+1);
1071:
1072: k = 0;
1073: for(j=startwall;j<=endwall;j++)
1074: {
1075: revolvex[revolvecnt][k] = wall[j].x;
1076: revolvey[revolvecnt][k] = wall[j].y;
1077: k++;
1078: }
1079: revolvesector[revolvecnt] = i;
1080: revolveang[revolvecnt] = 0;
1081:
1082: revolvecnt++;
1083: break;
1084: case 15:
1085: subwaytracksector[subwaytrackcnt][0] = i;
1086:
1087: subwaystopcnt[subwaytrackcnt] = 0;
1088: dax = 0x7fffffff;
1089: day = 0x7fffffff;
1090: dax2 = 0x80000000;
1091: day2 = 0x80000000;
1092: startwall = sector[i].wallptr;
1093: endwall = startwall+sector[i].wallnum-1;
1094: for(j=startwall;j<=endwall;j++)
1095: {
1096: if (wall[j].x < dax) dax = wall[j].x;
1097: if (wall[j].y < day) day = wall[j].y;
1098: if (wall[j].x > dax2) dax2 = wall[j].x;
1099: if (wall[j].y > day2) day2 = wall[j].y;
1100: }
1101: for(j=startwall;j<=endwall;j++)
1102: {
1103: if (wall[j].lotag == 5)
1104: {
1105: if ((wall[j].x > dax) && (wall[j].y > day) && (wall[j].x < dax2) && (wall[j].y < day2))
1106: {
1107: subwayx[subwaytrackcnt] = wall[j].x;
1108: }
1109: else
1110: {
1111: subwaystop[subwaytrackcnt][subwaystopcnt[subwaytrackcnt]] = wall[j].x;
1112: subwaystopcnt[subwaytrackcnt]++;
1113: }
1114: }
1115: }
1116:
1117: for(j=1;j<subwaystopcnt[subwaytrackcnt];j++)
1118: for(k=0;k<j;k++)
1119: if (subwaystop[subwaytrackcnt][j] < subwaystop[subwaytrackcnt][k])
1120: {
1121: s = subwaystop[subwaytrackcnt][j];
1122: subwaystop[subwaytrackcnt][j] = subwaystop[subwaytrackcnt][k];
1123: subwaystop[subwaytrackcnt][k] = s;
1124: }
1125:
1126: subwaygoalstop[subwaytrackcnt] = 0;
1127: for(j=0;j<subwaystopcnt[subwaytrackcnt];j++)
1128: if (klabs(subwaystop[subwaytrackcnt][j]-subwayx[subwaytrackcnt]) < klabs(subwaystop[subwaytrackcnt][subwaygoalstop[subwaytrackcnt]]-subwayx[subwaytrackcnt]))
1129: subwaygoalstop[subwaytrackcnt] = j;
1130:
1131: subwaytrackx1[subwaytrackcnt] = dax;
1132: subwaytracky1[subwaytrackcnt] = day;
1133: subwaytrackx2[subwaytrackcnt] = dax2;
1134: subwaytracky2[subwaytrackcnt] = day2;
1135:
1136: subwaynumsectors[subwaytrackcnt] = 1;
1137: for(j=0;j<numsectors;j++)
1138: if (j != i)
1139: {
1140: startwall = sector[j].wallptr;
1141: if (wall[startwall].x > subwaytrackx1[subwaytrackcnt])
1142: if (wall[startwall].y > subwaytracky1[subwaytrackcnt])
1143: if (wall[startwall].x < subwaytrackx2[subwaytrackcnt])
1144: if (wall[startwall].y < subwaytracky2[subwaytrackcnt])
1145: {
1146: if (sector[j].lotag == 16)
1147: sector[j].lotag = 17; //Make special subway door
1148:
1149: if (sector[j].floorz != sector[i].floorz)
1150: {
1151: sector[j].ceilingstat |= 64;
1152: sector[j].floorstat |= 64;
1153: }
1154: subwaytracksector[subwaytrackcnt][subwaynumsectors[subwaytrackcnt]] = j;
1155: subwaynumsectors[subwaytrackcnt]++;
1156: }
1157: }
1158:
1159: subwayvel[subwaytrackcnt] = 64;
1160: subwaypausetime[subwaytrackcnt] = 720;
1161: subwaytrackcnt++;
1162: break;
1163: }
1164: }
1165:
1166: //Scan wall tags
1167:
1168: ypanningwallcnt = 0;
1169: for(i=0;i<numwalls;i++)
1170: {
1171: if (wall[i].lotag == 1) ypanningwalllist[ypanningwallcnt++] = i;
1172: }
1173:
1174: //Scan sprite tags&picnum's
1175:
1176: rotatespritecnt = 0;
1177: for(i=0;i<MAXSPRITES;i++)
1178: {
1179: if (sprite[i].lotag == 3) rotatespritelist[rotatespritecnt++] = i;
1180:
1181: if (sprite[i].statnum < MAXSTATUS) //That is, if sprite exists
1182: switch(sprite[i].picnum)
1183: {
1184: case BROWNMONSTER: //All cases here put the sprite
1185: if ((sprite[i].cstat&128) == 0)
1186: {
1187: sprite[i].z -= ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
1188: sprite[i].cstat |= 128;
1189: }
1190: sprite[i].clipdist = mulscale(sprite[i].xrepeat,tilesizx[sprite[i].picnum],7);
1191: case DOOMGUY: //on waiting for you (list 2)
1192: if (sprite[i].statnum != 1) changespritestat(i,2);
1193: sprite[i].lotag = 100;
1194: case AL:
1195: case EVILAL:
1196: sprite[i].cstat |= 0x101; //Set the hitscan sensitivity bit
1197: }
1198: }
1199:
1200: //Map starts out completed
1201: for(i=0;i<(MAXSECTORS>>3);i++) show2dsector[i] = 0xff;
1202: for(i=0;i<(MAXWALLS>>3);i++) show2dwall[i] = 0xff;
1203: for(i=0;i<(MAXSPRITES>>3);i++) show2dsprite[i] = 0xff;
1204:
1205: //Map starts out blank; you map out what you see in 3D mode
1206: //automapping = 1;
1207:
1208: lockclock = 0;
1209: ototalclock = 0;
1210: gotlastpacketclock = 0;
1211: masterslavetexttime = 0;
1212:
1213: screensize = xdim;
1214: dax = (xdim>>1)-(screensize>>1);
1215: dax2 = dax+screensize-1;
1216: day = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
1217: day2 = day + ((screensize*(ydim-32))/xdim)-1;
1218: setview(dax,day>>detailmode,dax2,day2>>detailmode);
1219: }
1220:
1221:
1222: checktouchsprite(short snum, short sectnum)
1223: {
1224: long i, nexti;
1225:
1226: if ((sectnum < 0) || (sectnum >= numsectors)) return;
1227:
1228: for(i=headspritesect[sectnum];i>=0;i=nexti)
1229: {
1230: nexti = nextspritesect[i];
1231: 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))
1232: {
1233: switch(sprite[i].picnum)
1234: {
1235: case COINSTACK:
1236: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1237: changescore(snum,1000);
1238: changehealth(snum,25);
1239: deletesprite((short)i);
1240: break;
1241: case GIFTBOX:
1242: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,208L,&sprite[i].x,&sprite[i].y,0);
1243: changescore(snum,1000);
1244: changehealth(snum,10);
1245: deletesprite((short)i);
1246: break;
1247: case COIN:
1248: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,192L,&sprite[i].x,&sprite[i].y,0);
1249: changescore(snum,100);
1250: changehealth(snum,5);
1251: deletesprite((short)i);
1252: break;
1253: case DIAMONDS:
1254: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1255: changescore(snum,500);
1256: changehealth(snum,15);
1257: deletesprite((short)i);
1258: break;
1259: case CANON:
1260: if (numbombs[snum] == -1)
1261: {
1262: wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
1263: changescore(snum,1000);
1264: if (snum == myconnectindex) keystatus[4] = 1;
1265: numbombs[snum] = 32767;
1266: }
1267: break;
1268: }
1269: }
1270: }
1271: }
1272:
1273: shootgun(short snum, long x, long y, long z,
1274: short daang, long dahoriz, short dasectnum, char guntype)
1275: {
1276: short hitsect, hitwall, hitsprite, daang2;
1277: long i, j, daz2, hitx, hity, hitz;
1278:
1279: switch(guntype)
1280: {
1281: case 0: //Shoot silver sphere bullet
1282: spawnsprite(j,x,y,z,1+128,0,0,16,64,64,0,0,BULLET,daang,
1283: sintable[(daang+512)&2047]>>5,sintable[daang&2047]>>5,
1284: (100-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0);
1285: wsayfollow("shoot2.wav",4096L+(krand()&127)-64,184L,&sprite[j].x,&sprite[j].y,1);
1286: break;
1287: case 1: //Shoot chain gun
1288: daang2 = ((daang + 2048 + (krand()&31)-16)&2047);
1289: daz2 = ((100-dahoriz)*2000) + ((krand()-32768)>>1);
1290:
1291: hitscan(x,y,z,dasectnum, //Start position
1292: sintable[(daang2+2560)&2047], //X vector of 3D ang
1293: sintable[(daang2+2048)&2047], //Y vector of 3D ang
1294: daz2, //Z vector of 3D ang
1295: &hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz);
1296:
1297: if (wall[hitwall].picnum == KENPICTURE)
1298: {
1299: if (waloff[4095] != 0) wall[hitwall].picnum = 4095;
1300: wsayfollow("hello.wav",4096L+(krand()&127)-64,256L,&wall[hitwall].x,&wall[hitwall].y,0);
1301: }
1302: else if (((hitwall < 0) && (hitsprite < 0) && (hitz >= z) && (sector[hitsect].floorpicnum == SLIME)) || ((hitwall >= 0) && (wall[hitwall].picnum == SLIME)))
1303: { //If you shoot slime, make a splash
1304: wsayfollow("splash.wav",4096L+(krand()&511)-256,256L,&hitx,&hity,0);
1305: spawnsprite(j,hitx,hity,hitz,2,0,0,32,64,64,0,0,SPLASH,daang,
1306: 0,0,0,snum+4096,hitsect,4,63,0,0); //63=time left for splash
1307: }
1308: else
1309: {
1310: wsayfollow("shoot.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0);
1311:
1312: if ((hitsprite >= 0) && (sprite[hitsprite].statnum < MAXSTATUS))
1313: switch(sprite[hitsprite].picnum)
1314: {
1315: case BROWNMONSTER:
1316: if (sprite[hitsprite].lotag > 0) sprite[hitsprite].lotag -= 10;
1317: if (sprite[hitsprite].lotag > 0)
1318: {
1319: wsayfollow("hurt.wav",4096L+(krand()&511)-256,256L,&hitx,&hity,0);
1320: if (sprite[hitsprite].lotag <= 25)
1321: sprite[hitsprite].cstat |= 2;
1322: }
1323: else
1324: {
1325: wsayfollow("blowup.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0);
1326: sprite[hitsprite].z += ((tilesizy[sprite[hitsprite].picnum]*sprite[hitsprite].yrepeat)<<1);
1327: sprite[hitsprite].picnum = GIFTBOX;
1328: sprite[hitsprite].cstat &= ~0x83; //Should not clip, foot-z
1329: changespritestat(hitsprite,0);
1330: changescore(snum,200);
1331:
1332: spawnsprite(j,hitx,hity,hitz+(32<<8),0,-4,0,32,64,64,
1333: 0,0,EXPLOSION,daang,0,0,0,snum+4096,
1334: hitsect,5,31,0,0);
1335: }
1336: break;
1337: case EVILAL:
1338: wsayfollow("blowup.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0);
1339: sprite[hitsprite].picnum = EVILALGRAVE;
1340: sprite[hitsprite].cstat = 0;
1341: sprite[hitsprite].xrepeat = (krand()&63)+16;
1342: sprite[hitsprite].yrepeat = sprite[hitsprite].xrepeat;
1343: changespritestat(hitsprite,0);
1344:
1345: spawnsprite(j,hitx,hity,hitz+(32<<8),0,-4,0,32,64,64,0,
1346: 0,EXPLOSION,daang,0,0,0,snum+4096,hitsect,5,31,0,0);
1347: //31=time left for explosion
1348:
1349: break;
1350: case DOOMGUY:
1351: for(j=connecthead;j>=0;j=connectpoint2[j])
1352: if (playersprite[j] == hitsprite)
1353: {
1354: wsayfollow("ouch.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0);
1355: changehealth(j,-10);
1356: break;
1357: }
1358: break;
1359: }
1360:
1361: spawnsprite(j,hitx,hity,hitz+(8<<8),2,-4,0,32,16,16,0,0,
1362: EXPLOSION,daang,0,0,0,snum+4096,hitsect,3,63,0,0);
1363:
1364: //Sprite starts out with center exactly on wall.
1365: //This moves it back enough to see it at all angles.
1366: movesprite((short)j,-(((long)sintable[(512+daang)&2047]*TICSPERFRAME)<<4),-(((long)sintable[daang]*TICSPERFRAME)<<4),0L,4L<<8,4L<<8,1);
1367: }
1368: break;
1369: case 2: //Shoot bomb
1370: spawnsprite(j,x,y,z,128,0,0,12,16,16,0,0,BOMB,daang,
1371: sintable[(daang+2560)&2047]>>6,sintable[(daang+2048)&2047]>>6,
1372: (80-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0);
1373:
1374: wsayfollow("shoot3.wav",4096L+(krand()&127)-64,256L,&sprite[j].x,&sprite[j].y,1);
1375: break;
1376: }
1377: }
1378:
1379: analyzesprites(long dax, long day)
1380: {
1381: long i, j, k;
1382: point3d *ospr;
1383: spritetype *tspr;
1384:
1385: //This function is called between drawrooms() and drawmasks()
1386: //It has a list of possible sprites that may be drawn on this frame
1387:
1388: for(i=0,tspr=&tsprite[0];i<spritesortcnt;i++,tspr++)
1389: {
1390: switch(tspr->picnum)
1391: {
1392: case DOOMGUY:
1393: //Get which of the 8 angles of the sprite to draw (0-7)
1394: //k ranges from 0-7
1395: k = getangle(tspr->x-dax,tspr->y-day);
1396: k = (((tspr->ang+3072+128-k)&2047)>>8)&7;
1397: //This guy has only 5 pictures for 8 angles (3 are x-flipped)
1398: if (k <= 4)
1399: {
1400: tspr->picnum += (k<<2);
1401: tspr->cstat &= ~4; //clear x-flipping bit
1402: }
1403: else
1404: {
1405: tspr->picnum += ((8-k)<<2);
1406: tspr->cstat |= 4; //set x-flipping bit
1407: }
1408: break;
1409: }
1410:
1411: k = tspr->statnum;
1412: if ((k >= 1) && (k <= 8) && (k != 2)) //Interpolate moving sprite
1413: {
1414: ospr = &osprite[tspr->owner];
1415: k = tspr->x-ospr->x; tspr->x = ospr->x;
1416: if (k != 0) tspr->x += mulscale(k,smoothratio,16);
1417: k = tspr->y-ospr->y; tspr->y = ospr->y;
1418: if (k != 0) tspr->y += mulscale(k,smoothratio,16);
1419: k = tspr->z-ospr->z; tspr->z = ospr->z;
1420: if (k != 0) tspr->z += mulscale(k,smoothratio,16);
1421: }
1422: }
1423: }
1424:
1425: tagcode()
1426: {
1427: long i, nexti, j, k, l, s, dax, day, daz, dax2, day2, cnt, good;
1428: short startwall, endwall, dasector, p, oldang;
1429:
1430: for(p=connecthead;p>=0;p=connectpoint2[p])
1431: {
1432: if (sector[cursectnum[p]].lotag == 1)
1433: {
1434: for(i=0;i<numsectors;i++)
1435: if (sector[i].hitag == sector[cursectnum[p]].hitag)
1436: if (sector[i].lotag != 1)
1437: operatesector(i);
1438: i = headspritestat[0];
1439: while (i != -1)
1440: {
1441: nexti = nextspritestat[i];
1442: if (sprite[i].hitag == sector[cursectnum[p]].hitag)
1443: operatesprite(i);
1444: i = nexti;
1445: }
1446:
1447: sector[cursectnum[p]].lotag = 0;
1448: sector[cursectnum[p]].hitag = 0;
1449: }
1450: if ((sector[cursectnum[p]].lotag == 2) && (cursectnum[p] != ocursectnum[p]))
1451: {
1452: for(i=0;i<numsectors;i++)
1453: if (sector[i].hitag == sector[cursectnum[p]].hitag)
1454: if (sector[i].lotag != 1)
1455: operatesector(i);
1456: i = headspritestat[0];
1457: while (i != -1)
1458: {
1459: nexti = nextspritestat[i];
1460: if (sprite[i].hitag == sector[cursectnum[p]].hitag)
1461: operatesprite(i);
1462: i = nexti;
1463: }
1464: }
1465: }
1466:
1467: for(i=0;i<warpsectorcnt;i++)
1468: {
1469: dasector = warpsectorlist[i];
1470: j = ((lockclock&127)>>2);
1471: if (j >= 16) j = 31-j;
1472: {
1473: sector[dasector].ceilingshade = j;
1474: sector[dasector].floorshade = j;
1475: startwall = sector[dasector].wallptr;
1476: endwall = startwall+sector[dasector].wallnum-1;
1477: for(s=startwall;s<=endwall;s++)
1478: wall[s].shade = j;
1479: }
1480: }
1481:
1482: for(p=connecthead;p>=0;p=connectpoint2[p])
1483: if (sector[cursectnum[p]].lotag == 10) //warp sector
1484: {
1485: if (cursectnum[p] != ocursectnum[p])
1486: {
1487: warpsprite(playersprite[p]);
1488: posx[p] = sprite[playersprite[p]].x;
1489: posy[p] = sprite[playersprite[p]].y;
1490: posz[p] = sprite[playersprite[p]].z;
1491: ang[p] = sprite[playersprite[p]].ang;
1492: cursectnum[p] = sprite[playersprite[p]].sectnum;
1493:
1494: sprite[playersprite[p]].z += (32<<8);
1495:
1496: //warp(&posx[p],&posy[p],&posz[p],&ang[p],&cursectnum[p]);
1497: //Update sprite representation of player
1498: //setsprite(playersprite[p],posx[p],posy[p],posz[p]+(32<<8));
1499: //sprite[playersprite[p]].ang = ang[p];
1500: }
1501: }
1502:
1503: for(i=0;i<xpanningsectorcnt;i++) //animate wall x-panning sectors
1504: {
1505: dasector = xpanningsectorlist[i];
1506:
1507: startwall = sector[dasector].wallptr;
1508: endwall = startwall+sector[dasector].wallnum-1;
1509: for(s=startwall;s<=endwall;s++)
1510: wall[s].xpanning = ((lockclock>>2)&255);
1511: }
1512:
1513: for(i=0;i<ypanningwallcnt;i++)
1514: wall[ypanningwalllist[i]].ypanning = ~(lockclock&255);
1515:
1516: for(i=0;i<rotatespritecnt;i++)
1517: {
1518: sprite[rotatespritelist[i]].ang += (TICSPERFRAME<<2);
1519: sprite[rotatespritelist[i]].ang &= 2047;
1520: }
1521:
1522: for(i=0;i<floorpanningcnt;i++) //animate floor of slime sectors
1523: {
1524: sector[floorpanninglist[i]].floorxpanning = ((lockclock>>2)&255);
1525: sector[floorpanninglist[i]].floorypanning = ((lockclock>>2)&255);
1526: }
1527:
1528: for(i=0;i<dragsectorcnt;i++)
1529: {
1530: dasector = dragsectorlist[i];
1531:
1532: startwall = sector[dasector].wallptr;
1533: endwall = startwall+sector[dasector].wallnum-1;
1534:
1535: if (wall[startwall].x+dragxdir[i] < dragx1[i]) dragxdir[i] = 16;
1536: if (wall[startwall].y+dragydir[i] < dragy1[i]) dragydir[i] = 16;
1537: if (wall[startwall].x+dragxdir[i] > dragx2[i]) dragxdir[i] = -16;
1538: if (wall[startwall].y+dragydir[i] > dragy2[i]) dragydir[i] = -16;
1539:
1540: for(j=startwall;j<=endwall;j++)
1541: dragpoint(j,wall[j].x+dragxdir[i],wall[j].y+dragydir[i]);
1542: j = sector[dasector].floorz;
1543: sector[dasector].floorz = dragfloorz[i]+(sintable[(lockclock<<4)&2047]>>3);
1544:
1545: for(p=connecthead;p>=0;p=connectpoint2[p])
1546: if (cursectnum[p] == dasector)
1547: {
1548: posx[p] += dragxdir[i];
1549: posy[p] += dragydir[i];
1550: posz[p] += (sector[dasector].floorz-j);
1551:
1552: //Update sprite representation of player
1553: setsprite(playersprite[p],posx[p],posy[p],posz[p]+(32<<8));
1554: sprite[playersprite[p]].ang = ang[p];
1555: frameinterpolate = 0;
1556: }
1557: }
1558:
1559: for(i=0;i<swingcnt;i++)
1560: {
1561: if (swinganginc[i] != 0)
1562: {
1563: oldang = swingang[i];
1564: for(j=0;j<(TICSPERFRAME<<2);j++)
1565: {
1566: swingang[i] = ((swingang[i]+2048+swinganginc[i])&2047);
1567: if (swingang[i] == swingangclosed[i])
1568: {
1569: wsayfollow("closdoor.wav",4096L+(krand()&511)-256,256L,&swingx[i][0],&swingy[i][0],0);
1570: swinganginc[i] = 0;
1571: }
1572: if (swingang[i] == swingangopen[i]) swinganginc[i] = 0;
1573: }
1574: for(k=1;k<=3;k++)
1575: 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);
1576:
1577: if (swinganginc[i] != 0)
1578: {
1579: for(p=connecthead;p>=0;p=connectpoint2[p])
1580: if ((cursectnum[p] == swingsector[i]) || (testneighborsectors(cursectnum[p],swingsector[i]) == 1))
1581: {
1582: cnt = 256;
1583: do
1584: {
1585: good = 1;
1586:
1587: //swingangopendir is -1 if forwards, 1 is backwards
1588: l = (swingangopendir[i] > 0);
1589: for(k=l+3;k>=l;k--)
1590: if (clipinsidebox(posx[p],posy[p],swingwall[i][k],128L) != 0)
1591: {
1592: good = 0;
1593: break;
1594: }
1595: if (good == 0)
1596: {
1597: if (cnt == 256)
1598: {
1599: swinganginc[i] = -swinganginc[i];
1600: swingang[i] = oldang;
1601: }
1602: else
1603: {
1604: swingang[i] = ((swingang[i]+2048-swinganginc[i])&2047);
1605: }
1606: for(k=1;k<=3;k++)
1607: 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);
1608: if (swingang[i] == swingangclosed[i])
1609: {
1610: wsayfollow("closdoor.wav",4096L+(krand()&511)-256,256L,&swingx[i][0],&swingy[i][0],0);
1611: swinganginc[i] = 0;
1612: break;
1613: }
1614: if (swingang[i] == swingangopen[i])
1615: {
1616: swinganginc[i] = 0;
1617: break;
1618: }
1619: cnt--;
1620: }
1621: } while ((good == 0) && (cnt > 0));
1622: }
1623: }
1624: }
1625: }
1626:
1627: for(i=0;i<revolvecnt;i++)
1628: {
1629: startwall = sector[revolvesector[i]].wallptr;
1630: endwall = startwall + sector[revolvesector[i]].wallnum - 1;
1631:
1632: revolveang[i] = ((revolveang[i]+2048-(TICSPERFRAME<<2))&2047);
1633: for(k=startwall;k<=endwall;k++)
1634: {
1635: rotatepoint(revolvepivotx[i],revolvepivoty[i],revolvex[i][k-startwall],revolvey[i][k-startwall],revolveang[i],&dax,&day);
1636: dragpoint(k,dax,day);
1637: }
1638: }
1639:
1640: for(i=0;i<subwaytrackcnt;i++)
1641: {
1642: dasector = subwaytracksector[i][0];
1643: startwall = sector[dasector].wallptr;
1644: endwall = startwall+sector[dasector].wallnum-1;
1645: for(k=startwall;k<=endwall;k++)
1646: {
1647: if (wall[k].x > subwaytrackx1[i])
1648: if (wall[k].y > subwaytracky1[i])
1649: if (wall[k].x < subwaytrackx2[i])
1650: if (wall[k].y < subwaytracky2[i])
1651: wall[k].x += (subwayvel[i]&0xfffffffc);
1652: }
1653:
1654: for(j=1;j<subwaynumsectors[i];j++)
1655: {
1656: dasector = subwaytracksector[i][j];
1657:
1658: startwall = sector[dasector].wallptr;
1659: endwall = startwall+sector[dasector].wallnum-1;
1660: for(k=startwall;k<=endwall;k++)
1661: wall[k].x += (subwayvel[i]&0xfffffffc);
1662:
1663: s = headspritesect[dasector];
1664: while (s != -1)
1665: {
1666: k = nextspritesect[s];
1667: sprite[s].x += (subwayvel[i]&0xfffffffc);
1668: s = k;
1669: }
1670: }
1671:
1672: for(p=connecthead;p>=0;p=connectpoint2[p])
1673: if (cursectnum[p] != subwaytracksector[i][0])
1674: if (sector[cursectnum[p]].floorz != sector[subwaytracksector[i][0]].floorz)
1675: if (posx[p] > subwaytrackx1[i])
1676: if (posy[p] > subwaytracky1[i])
1677: if (posx[p] < subwaytrackx2[i])
1678: if (posy[p] < subwaytracky2[i])
1679: {
1680: posx[p] += (subwayvel[i]&0xfffffffc);
1681:
1682: //Update sprite representation of player
1683: setsprite(playersprite[p],posx[p],posy[p],posz[p]+(32<<8));
1684: sprite[playersprite[p]].ang = ang[p];
1685: frameinterpolate = 0;
1686: }
1687:
1688: subwayx[i] += (subwayvel[i]&0xfffffffc);
1689:
1690: k = subwaystop[i][subwaygoalstop[i]] - subwayx[i];
1691: if (k > 0)
1692: {
1693: if (k > 2048)
1694: {
1695: if (subwayvel[i] < 128) subwayvel[i]++;
1696: }
1697: else
1698: subwayvel[i] = (k>>4)+1;
1699: }
1700: else if (k < 0)
1701: {
1702: if (k < -2048)
1703: {
1704: if (subwayvel[i] > -128) subwayvel[i]--;
1705: }
1706: else
1707: subwayvel[i] = ((k>>4)-1);
1708: }
1709:
1710: if (((subwayvel[i]>>2) == 0) && (klabs(k) < 2048))
1711: {
1712: if (subwaypausetime[i] == 720)
1713: {
1714: for(j=1;j<subwaynumsectors[i];j++) //Open all subway doors
1715: {
1716: dasector = subwaytracksector[i][j];
1717: if (sector[dasector].lotag == 17)
1718: {
1719: sector[dasector].lotag = 16;
1720: operatesector(dasector);
1721: sector[dasector].lotag = 17;
1722: }
1723: }
1724: }
1725: if ((subwaypausetime[i] >= 120) && (subwaypausetime[i]-TICSPERFRAME < 120))
1726: {
1727: for(j=1;j<subwaynumsectors[i];j++) //Close all subway doors
1728: {
1729: dasector = subwaytracksector[i][j];
1730: if (sector[dasector].lotag == 17)
1731: {
1732: sector[dasector].lotag = 16;
1733: operatesector(dasector);
1734: sector[dasector].lotag = 17;
1735: }
1736: }
1737: }
1738:
1739: subwaypausetime[i] -= TICSPERFRAME;
1740: if (subwaypausetime[i] < 0)
1741: {
1742: subwaypausetime[i] = 720;
1743: if (subwayvel[i] < 0)
1744: {
1745: subwaygoalstop[i]--;
1746: if (subwaygoalstop[i] < 0)
1747: subwaygoalstop[i] = 1;
1748: }
1749: if (subwayvel[i] > 0)
1750: {
1751: subwaygoalstop[i]++;
1752: if (subwaygoalstop[i] >= subwaystopcnt[i])
1753: subwaygoalstop[i] = subwaystopcnt[i]-2;
1754: }
1755: }
1756: }
1757: }
1758: }
1759:
1760: statuslistcode()
1761: {
1762: short p, target, hitobject, daang, osectnum, movestat;
1763: long i, nexti, j, nextj, k, l, dax, day, daz, dist, ox, oy, mindist;
1764:
1765: i = headspritestat[1]; //Go through active monster sprites
1766: while (i != -1)
1767: {
1768: nexti = nextspritestat[i];
1769:
1770: //Choose a target player
1771: mindist = 0x7fffffff; target = connecthead;
1772: for(p=connecthead;p>=0;p=connectpoint2[p])
1773: {
1774: dist = klabs(sprite[i].x-posx[p])+klabs(sprite[i].y-posy[p]);
1775: if (dist < mindist) mindist = dist, target = p;
1776: }
1777:
1778: switch(sprite[i].picnum)
1779: {
1780: case BROWNMONSTER:
1781:
1782: k = (krand()&63); //Only get random number once
1783: //Who cares if the monster won't shoot and
1784: //change direction at the same time
1785:
1786: //brown monster decides to shoot bullet
1787: if ((sprite[i].lotag > 25) && (k == 0))
1788: if (cansee(posx[target],posy[target],posz[target],cursectnum[target],sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum) == 1)
1789: {
1790: wsayfollow("zipguns.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1);
1791:
1792: spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,128,0,0,
1793: 16,64,64,0,0,BULLET,
1794: (getangle(posx[target]-sprite[j].x,
1795: posy[target]-sprite[j].y)+(krand()&15)-8)&2047,
1796: sintable[(sprite[j].ang+512)&2047]>>6,
1797: sintable[sprite[j].ang&2047]>>6,
1798: ((posz[target]+(8<<8)-sprite[j].z)<<8) /
1799: ksqrt((posx[target]-sprite[j].x) *
1800: (posx[target]-sprite[j].x) +
1801: (posy[target]-sprite[j].y) *
1802: (posy[target]-sprite[j].y)),
1803: i,sprite[i].sectnum,6,0,0,0);
1804: }
1805:
1806: //Move brown monster
1807: dax = sprite[i].x; //Back up old x&y if stepping off cliff
1808: day = sprite[i].y;
1809:
1810: osectnum = sprite[i].sectnum;
1811: movestat = movesprite((short)i,(((long)sintable[(sprite[i].ang+512)&2047])*TICSPERFRAME)<<3,(((long)sintable[sprite[i].ang])*TICSPERFRAME)<<3,0L,4L<<8,4L<<8,0);
1812: if (globloz > sprite[i].z+(48<<8))
1813: { sprite[i].x = dax; sprite[i].y = day; movestat = 1; }
1814: else
1815: sprite[i].z = globloz-((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1);
1816:
1817: if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10))
1818: { warpsprite((short)i); movestat = 0; }
1819:
1820: if ((movestat != 0) || (k == 1))
1821: {
1822: daang = (getangle(posx[target]-sprite[i].x,posy[target]-sprite[i].y)&2047);
1823: sprite[i].ang = ((daang+(krand()&1023)-512)&2047);
1824: }
1825:
1826: break;
1827:
1828: case EVILAL:
1829: if (sprite[i].yrepeat >= 38)
1830: {
1831: if (sprite[i].yrepeat < 64)
1832: {
1833: sprite[i].xrepeat++;
1834: sprite[i].yrepeat++;
1835: }
1836: else
1837: {
1838: if ((krand()&63) == 0) //Al decides to reproduce
1839: {
1840: if (cansee(posx[target],posy[target],posz[target],cursectnum[target],sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum) == 1)
1841: {
1842: spawnsprite(j,sprite[i].x,sprite[i].y,0,1+2+256,0,0,
1843: 32,38,38,0,0,EVILAL,krand()&2047,0,0,0,i,
1844: sprite[i].sectnum,1,0,0,0);
1845: }
1846: }
1847: if ((krand()&63) == 0) //Al decides to shoot bullet
1848: {
1849: if (cansee(posx[target],posy[target],posz[target],cursectnum[target],sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum) == 1)
1850: {
1851: wsayfollow("zipguns.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1);
1852:
1853: spawnsprite(j,sprite[i].x,sprite[i].y,
1854: sector[sprite[i].sectnum].floorz-(24<<8),
1855: 0,0,0,16,64,64,0,0,BULLET,
1856: (getangle(posx[target]-sprite[j].x,
1857: posy[target]-sprite[j].y)+(krand()&15)-8)&2047,
1858: sintable[(sprite[j].ang+2560)&2047]>>6,
1859: sintable[(sprite[j].ang+2048)&2047]>>6,
1860: ((posz[target]+(8<<8)-sprite[j].z)<<8) /
1861: ksqrt((posx[target]-sprite[j].x) *
1862: (posx[target]-sprite[j].x) +
1863: (posy[target]-sprite[j].y) *
1864: (posy[target]-sprite[j].y)),
1865: i,sprite[i].sectnum,6,0,0,0);
1866: }
1867: }
1868:
1869: sprite[i].z = sector[sprite[i].sectnum].floorz;
1870:
1871: //Move Al
1872: dax = ((sintable[(sprite[i].ang+512)&2047]*TICSPERFRAME)<<4);
1873: day = ((sintable[sprite[i].ang]*TICSPERFRAME)<<4);
1874:
1875: osectnum = sprite[i].sectnum;
1876: movestat = movesprite((short)i,dax,day,0L,4L<<8,4L<<8,0);
1877: if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10))
1878: {
1879: warpsprite((short)i);
1880: movestat = 0;
1881: }
1882:
1883: if (movestat != 0)
1884: {
1885: if ((krand()&1) == 0)
1886: sprite[i].ang = getangle(posx[target]-sprite[i].x,posy[target]-sprite[i].y);
1887: else
1888: sprite[i].ang = (krand()&2047);
1889: }
1890: }
1891: }
1892: break;
1893: }
1894:
1895: i = nexti;
1896: }
1897:
1898: i = headspritestat[6]; //Go through travelling bullet sprites
1899: while (i != -1)
1900: {
1901: nexti = nextspritestat[i];
1902:
1903: //If the sprite is a bullet then...
1904: if ((sprite[i].picnum == BULLET) || (sprite[i].picnum == BOMB))
1905: {
1906: dax = ((((long)sprite[i].xvel)*TICSPERFRAME)<<11);
1907: day = ((((long)sprite[i].yvel)*TICSPERFRAME)<<11);
1908: daz = ((((long)sprite[i].zvel)*TICSPERFRAME)>>3);
1909: if (sprite[i].picnum == BOMB) daz = 0;
1910:
1911: osectnum = sprite[i].sectnum;
1912: hitobject = movesprite((short)i,dax,day,daz,4L<<8,4L<<8,1);
1913: if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10))
1914: {
1915: warpsprite((short)i);
1916: hitobject = 0;
1917: }
1918:
1919: if (sprite[i].picnum == BOMB)
1920: {
1921: sprite[i].z += sprite[i].zvel;
1922: sprite[i].zvel += (TICSPERFRAME<<5);
1923: if (sprite[i].z < globhiz+(tilesizy[BOMB]<<6))
1924: {
1925: sprite[i].z = globhiz+(tilesizy[BOMB]<<6);
1926: sprite[i].zvel = -(sprite[i].zvel>>1);
1927: }
1928: if (sprite[i].z > globloz-(tilesizy[BOMB]<<6))
1929: {
1930: sprite[i].z = globloz-(tilesizy[BOMB]<<6);
1931: sprite[i].zvel = -(sprite[i].zvel>>1);
1932: }
1933: dax = sprite[i].xvel; day = sprite[i].yvel;
1934: dist = dax*dax+day*day;
1935: if (dist < 512)
1936: {
1937: bombexplode(i);
1938: goto bulletisdeletedskip;
1939: }
1940: if (dist < 4096)
1941: {
1942: sprite[i].xrepeat = ((4096+2048)*16) / (dist+2048);
1943: sprite[i].yrepeat = sprite[i].xrepeat;
1944: sprite[i].xoffset = (krand()&15)-8;
1945: sprite[i].yoffset = (krand()&15)-8;
1946: }
1947: if (mulscale(krand(),dist,30) == 0)
1948: {
1949: sprite[i].xvel -= ksgn(sprite[i].xvel);
1950: sprite[i].yvel -= ksgn(sprite[i].yvel);
1951: sprite[i].zvel -= ksgn(sprite[i].zvel);
1952: }
1953: }
1954:
1955: //Check for bouncy objects before killing bullet
1956: if ((hitobject&0xc000) == 32768) //Bullet hit a wall
1957: {
1958: if (wall[hitobject&4095].lotag == 8)
1959: {
1960: dax = sprite[i].xvel; day = sprite[i].yvel;
1961: if ((sprite[i].picnum != BOMB) || (dax*dax+day*day >= 512))
1962: {
1963: k = (hitobject&4095); l = wall[k].point2;
1964: j = getangle(wall[l].x-wall[k].x,wall[l].y-wall[k].y)+512;
1965:
1966: //k = cos(ang) * sin(ang) * 2
1967: k = mulscale(sintable[(j+512)&2047],sintable[j&2047],13);
1968: //l = cos(ang * 2)
1969: l = sintable[((j<<1)+512)&2047];
1970:
1971: ox = sprite[i].xvel; oy = sprite[i].yvel;
1972: dax = -ox; day = -oy;
1973: sprite[i].xvel = mulscale(day,k,14) + mulscale(dax,l,14);
1974: sprite[i].yvel = mulscale(dax,k,14) - mulscale(day,l,14);
1975:
1976: if (sprite[i].picnum == BOMB)
1977: {
1978: sprite[i].xvel -= (sprite[i].xvel>>3);
1979: sprite[i].yvel -= (sprite[i].yvel>>3);
1980: sprite[i].zvel -= (sprite[i].zvel>>3);
1981: }
1982: ox -= sprite[i].xvel; oy -= sprite[i].yvel;
1983: dist = ((ox*ox+oy*oy)>>8);
1984: wsayfollow("bouncy.wav",4096L+(krand()&127)-64,min(dist,256),&sprite[i].x,&sprite[i].y,1);
1985: hitobject = 0;
1986: sprite[i].owner = -1; //Bullet turns evil!
1987: }
1988: }
1989: }
1990: else if ((hitobject&0xc000) == 49152) //Bullet hit a sprite
1991: {
1992: if (sprite[hitobject&4095].picnum == BOUNCYMAT)
1993: {
1994: if ((sprite[hitobject&4095].cstat&48) == 0)
1995: {
1996: sprite[i].xvel = -sprite[i].xvel;
1997: sprite[i].yvel = -sprite[i].yvel;
1998: sprite[i].zvel = -sprite[i].zvel;
1999: dist = 255;
2000: }
2001: else if ((sprite[hitobject&4095].cstat&48) == 16)
2002: {
2003: j = sprite[hitobject&4095].ang;
2004:
2005: //k = cos(ang) * sin(ang) * 2
2006: k = mulscale(sintable[(j+512)&2047],sintable[j&2047],13);
2007: //l = cos(ang * 2)
2008: l = sintable[((j<<1)+512)&2047];
2009:
2010: ox = sprite[i].xvel; oy = sprite[i].yvel;
2011: dax = -ox; day = -oy;
2012: sprite[i].xvel = mulscale(day,k,14) + mulscale(dax,l,14);
2013: sprite[i].yvel = mulscale(dax,k,14) - mulscale(day,l,14);
2014:
2015: ox -= sprite[i].xvel; oy -= sprite[i].yvel;
2016: dist = ((ox*ox+oy*oy)>>8);
2017: }
2018: sprite[i].owner = -1; //Bullet turns evil!
2019: wsayfollow("bouncy.wav",4096L+(krand()&127)-64,min(dist,256),&sprite[i].x,&sprite[i].y,1);
2020: hitobject = 0;
2021: }
2022: }
2023:
2024: if (hitobject != 0)
2025: {
2026: if (sprite[i].picnum == BOMB)
2027: {
2028: if ((hitobject&0xc000) == 49152)
2029: if (sprite[hitobject&4095].lotag == 5) //Basketball hoop
2030: {
2031: wsayfollow("niceshot.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2032: deletesprite((short)i);
2033: goto bulletisdeletedskip;
2034: }
2035:
2036: bombexplode(i);
2037: goto bulletisdeletedskip;
2038: }
2039:
2040: if ((hitobject&0xc000) == 16384) //Hits a ceiling / floor
2041: {
2042: wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2043: deletesprite((short)i);
2044: goto bulletisdeletedskip;
2045: }
2046: else if ((hitobject&0xc000) == 32768) //Bullet hit a wall
2047: {
2048: if (wall[hitobject&4095].picnum == KENPICTURE)
2049: {
2050: if (waloff[4095] != 0)
2051: wall[hitobject&4095].picnum = 4095;
2052: wsayfollow("hello.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); //Ken says, "Hello... how are you today!"
2053: }
2054: else
2055: wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2056:
2057: deletesprite((short)i);
2058: goto bulletisdeletedskip;
2059: }
2060: else if ((hitobject&0xc000) == 49152) //Bullet hit a sprite
2061: {
2062: //Check if bullet hit a player & find which player it was...
2063: if (sprite[hitobject&4095].picnum == DOOMGUY)
2064: for(j=connecthead;j>=0;j=connectpoint2[j])
2065: if (sprite[i].owner != j+4096)
2066: if (playersprite[j] == (hitobject&4095))
2067: {
2068: wsayfollow("ouch.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2069: changehealth(j,-25);
2070: deletesprite((short)i);
2071: goto bulletisdeletedskip;
2072: }
2073:
2074: //Check if bullet hit any monsters...
2075: j = (hitobject&4095); //j is the spritenum that the bullet (spritenum i) hit
2076: if (sprite[i].owner != j)
2077: {
2078: switch(sprite[j].picnum)
2079: {
2080: case BROWNMONSTER:
2081: if (sprite[j].lotag > 0) sprite[j].lotag -= 25;
2082: if (sprite[j].lotag > 0)
2083: {
2084: if (sprite[j].lotag <= 25) sprite[j].cstat |= 2;
2085: wsayfollow("hurt.wav",4096L+(krand()&511)-256,256L,&sprite[i].x,&sprite[i].y,1);
2086:
2087: for(j=connecthead;j>=0;j=connectpoint2[j])
2088: if (sprite[i].owner == j+4096)
2089: changescore(j,200);
2090: }
2091: else
2092: {
2093: wsayfollow("blowup.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2094: sprite[j].z += ((tilesizy[sprite[j].picnum]*sprite[j].yrepeat)<<1);
2095: sprite[j].picnum = GIFTBOX;
2096: sprite[j].cstat &= ~0x83; //Should not clip, foot-z
2097:
2098: spawnsprite(k,sprite[j].x,sprite[j].y,sprite[j].z,
2099: 0,-4,0,32,64,64,0,0,EXPLOSION,sprite[j].ang,
2100: 0,0,0,j,sprite[j].sectnum,5,31,0,0);
2101: //31=Time left for explosion to stay
2102:
2103: changespritestat(j,0);
2104:
2105: for(j=connecthead;j>=0;j=connectpoint2[j])
2106: if (sprite[i].owner == j+4096)
2107: changescore(j,200);
2108: }
2109: deletesprite((short)i);
2110: goto bulletisdeletedskip;
2111: case EVILAL:
2112: wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2113: sprite[j].picnum = EVILALGRAVE;
2114: sprite[j].cstat = 0;
2115: sprite[j].xrepeat = (krand()&63)+16;
2116: sprite[j].yrepeat = sprite[j].xrepeat;
2117: changespritestat(j,0);
2118:
2119: for(j=connecthead;j>=0;j=connectpoint2[j])
2120: if (sprite[i].owner == j+4096)
2121: changescore(j,200);
2122:
2123: deletesprite((short)i);
2124: goto bulletisdeletedskip;
2125: case AL:
2126: wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2127: sprite[j].xrepeat += 2;
2128: sprite[j].yrepeat += 2;
2129: if (sprite[j].yrepeat >= 38)
2130: {
2131: sprite[j].picnum = EVILAL;
2132: sprite[j].cstat |= 2; //Make him transluscent
2133: }
2134: changespritestat(j,1);
2135: deletesprite((short)i);
2136: goto bulletisdeletedskip;
2137: default:
2138: wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2139: deletesprite((short)i);
2140: goto bulletisdeletedskip;
2141: }
2142: }
2143: }
2144: }
2145: }
2146:
2147: bulletisdeletedskip:
2148: i = nexti;
2149: }
2150:
2151: for(j=connecthead;j>=0;j=connectpoint2[j])
2152: if ((saywatchit[j] >= lockclock-TICSPERFRAME) && (saywatchit[j] < lockclock))
2153: wsayfollow("watchit.wav",4096L+(krand()&127)-64,256L,&posx[j],&posy[j],1);
2154:
2155: i = headspritestat[2]; //Go through monster waiting for you list
2156: while (i != -1)
2157: {
2158: nexti = nextspritestat[i];
2159:
2160: //Use dot product to see if monster's angle is towards a player
2161: for(p=connecthead;p>=0;p=connectpoint2[p])
2162: if (sintable[(sprite[i].ang+2560)&2047]*(posx[p]-sprite[i].x) + sintable[(sprite[i].ang+2048)&2047]*(posy[p]-sprite[i].y) >= 0)
2163: if (cansee(posx[p],posy[p],posz[p],cursectnum[p],sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum) == 1)
2164: {
2165: changespritestat(i,1);
2166: wsayfollow("iseeyou.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1);
2167: }
2168:
2169: i = nexti;
2170: }
2171:
2172: i = headspritestat[3]; //Go through smoke sprites
2173: while (i >= 0)
2174: {
2175: nexti = nextspritestat[i];
2176:
2177: sprite[i].z -= (TICSPERFRAME<<6);
2178: sprite[i].lotag -= TICSPERFRAME;
2179: if (sprite[i].lotag < 0)
2180: deletesprite(i);
2181:
2182: i = nexti;
2183: }
2184:
2185: i = headspritestat[4]; //Go through splash sprites
2186: while (i >= 0)
2187: {
2188: nexti = nextspritestat[i];
2189:
2190: sprite[i].lotag -= TICSPERFRAME;
2191: sprite[i].picnum = SPLASH + ((63-sprite[i].lotag)>>4);
2192: if (sprite[i].lotag < 0)
2193: deletesprite(i);
2194:
2195: i = nexti;
2196: }
2197:
2198: i = headspritestat[5]; //Go through explosion sprites
2199: while (i >= 0)
2200: {
2201: nexti = nextspritestat[i];
2202:
2203: sprite[i].lotag -= TICSPERFRAME;
2204: if (sprite[i].lotag < 0)
2205: deletesprite(i);
2206:
2207: i = nexti;
2208: }
2209:
2210: i = headspritestat[7]; //Go through bomb spriral-explosion sprites
2211: while (i >= 0)
2212: {
2213: nexti = nextspritestat[i];
2214:
2215: sprite[i].x += ((sprite[i].xvel*TICSPERFRAME)>>4);
2216: sprite[i].y += ((sprite[i].yvel*TICSPERFRAME)>>4);
2217: sprite[i].z += ((sprite[i].zvel*TICSPERFRAME)>>4);
2218:
2219: sprite[i].zvel += (TICSPERFRAME<<7);
2220: if (sprite[i].z < sector[sprite[i].sectnum].ceilingz+(4<<8))
2221: {
2222: sprite[i].z = sector[sprite[i].sectnum].ceilingz+(4<<8);
2223: sprite[i].zvel = -(sprite[i].zvel>>1);
2224: }
2225: if (sprite[i].z > sector[sprite[i].sectnum].floorz-(4<<8))
2226: {
2227: sprite[i].z = sector[sprite[i].sectnum].floorz-(4<<8);
2228: sprite[i].zvel = -(sprite[i].zvel>>1);
2229: }
2230:
2231: sprite[i].xrepeat = (sprite[i].lotag>>2);
2232: sprite[i].yrepeat = (sprite[i].lotag>>2);
2233:
2234: sprite[i].lotag -= TICSPERFRAME;
2235: if (sprite[i].lotag < 0)
2236: deletesprite(i);
2237:
2238: i = nexti;
2239: }
2240: }
2241:
2242: bombexplode(long i)
2243: {
2244: long j, nextj, k, daang, dax, day, dist;
2245:
2246: spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,0,-4,0,
2247: 32,64,64,0,0,EXPLOSION,sprite[i].ang,
2248: 0,0,0,sprite[i].owner,sprite[i].sectnum,5,31,0,0);
2249: //31=Time left for explosion to stay
2250:
2251: for(k=0;k<16;k++)
2252: {
2253: spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z+(8<<8),2,-4,0,
2254: 32,24,24,0,0,EXPLOSION,sprite[i].ang,
2255: (krand()&511)-256,(krand()&511)-256,(krand()&16384)-8192,
2256: sprite[i].owner,sprite[i].sectnum,7,96,0,0);
2257: //96=Time left for smoke to be alive
2258: }
2259:
2260: for(j=connecthead;j>=0;j=connectpoint2[j])
2261: {
2262: dist = (posx[j]-sprite[i].x)*(posx[j]-sprite[i].x);
2263: dist += (posy[j]-sprite[i].y)*(posy[j]-sprite[i].y);
2264: dist += ((posz[j]-sprite[i].z)>>4)*((posz[j]-sprite[i].z)>>4);
2265: if (dist < 4194304)
2266: if (cansee(posx[j],posy[j],posz[j],cursectnum[j],sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum) == 1)
2267: {
2268: k = ((32768/((dist>>16)+4))>>5);
2269: if (j == myconnectindex)
2270: {
2271: daang = getangle(posx[j]-sprite[i].x,posy[j]-sprite[i].y);
2272: dax = ((k*sintable[(daang+2560)&2047])>>14);
2273: day = ((k*sintable[(daang+2048)&2047])>>14);
2274: vel += ((dax*sintable[(ang[j]+2560)&2047]+day*sintable[(ang[j]+2048)&2047])>>14);
2275: svel += ((day*sintable[(ang[j]+2560)&2047]-dax*sintable[(ang[j]+2048)&2047])>>14);
2276: }
2277: if (changehealth(j,-k) == 1) //If you're dead
2278: if (sprite[i].owner == j+4096)
2279: saywatchit[j] = lockclock+120;
2280: }
2281: }
2282:
2283: for(k=1;k<=2;k++) //Check for hurting monsters
2284: {
2285: j = headspritestat[k];
2286: while (j != -1)
2287: {
2288: nextj = nextspritestat[j];
2289:
2290: dist = (sprite[j].x-sprite[i].x)*(sprite[j].x-sprite[i].x);
2291: dist += (sprite[j].y-sprite[i].y)*(sprite[j].y-sprite[i].y);
2292: dist += ((sprite[j].z-sprite[i].z)>>4)*((sprite[j].z-sprite[i].z)>>4);
2293: if (dist < 4194304)
2294: if (cansee(sprite[j].x,sprite[j].y,sprite[j].z-(tilesizy[sprite[j].picnum]<<7),sprite[j].sectnum,sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum) == 1)
2295: {
2296: if (sprite[j].picnum == BROWNMONSTER)
2297: {
2298: sprite[j].z += ((tilesizy[sprite[j].picnum]*sprite[j].yrepeat)<<1);
2299: sprite[j].picnum = GIFTBOX;
2300: sprite[j].cstat &= ~0x83; //Should not clip, foot-z
2301: changespritestat(j,0);
2302: }
2303: if (sprite[j].picnum == EVILAL)
2304: {
2305: sprite[j].picnum = EVILALGRAVE;
2306: sprite[j].cstat = 0;
2307: sprite[j].xrepeat = (krand()&63)+16;
2308: sprite[j].yrepeat = sprite[j].xrepeat;
2309: changespritestat(j,0);
2310: }
2311: }
2312:
2313: j = nextj;
2314: }
2315: }
2316: wsayfollow("blowup.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0);
2317: deletesprite((short)i);
2318: }
2319:
2320: processinput(short snum)
2321: {
2322: long oldposx, oldposy, nexti;
2323: long i, j, k, doubvel, xvect, yvect, goalz;
2324: long dax, day, dax2, day2, odax, oday, odax2, oday2;
2325: short startwall, endwall;
2326: char *ptr;
2327:
2328: //SHARED KEYS:
2329: //Movement code
2330: if ((syncvel[snum]|syncsvel[snum]) != 0)
2331: {
2332: doubvel = (TICSPERFRAME<<((syncbits[snum]&256)>0));
2333:
2334: xvect = 0, yvect = 0;
2335: if (syncvel[snum] != 0)
2336: {
2337: xvect += ((((long)syncvel[snum])*doubvel*(long)sintable[(ang[snum]+2560)&2047])>>3);
2338: yvect += ((((long)syncvel[snum])*doubvel*(long)sintable[(ang[snum]+2048)&2047])>>3);
2339: }
2340: if (syncsvel[snum] != 0)
2341: {
2342: xvect += ((((long)syncsvel[snum])*doubvel*(long)sintable[(ang[snum]+2048)&2047])>>3);
2343: yvect += ((((long)syncsvel[snum])*doubvel*(long)sintable[(ang[snum]+1536)&2047])>>3);
2344: }
2345: clipmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],xvect,yvect,128L,4<<8,4<<8,0);
2346: frameinterpolate = 1;
2347: revolvedoorstat[snum] = 1;
2348: }
2349: else
2350: {
2351: revolvedoorstat[snum] = 0;
2352: }
2353:
2354: //Push player away from walls if clipmove doesn't work
2355: if (pushmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],128L,4<<8,4<<8,0) < 0)
2356: changehealth(snum,-1000); //If this screws up, then instant death!!!
2357:
2358: // Getzrange returns the highest and lowest z's for an entire box,
2359: // NOT just a point. This prevents you from falling off cliffs
2360: // when you step only slightly over the cliff.
2361: sprite[playersprite[snum]].cstat ^= 1;
2362: getzrange(posx[snum],posy[snum],posz[snum],cursectnum[snum],&globhiz,&globhihit,&globloz,&globlohit,128L,0);
2363: sprite[playersprite[snum]].cstat ^= 1;
2364:
2365: if (syncangvel[snum] != 0) //ang += angvel * constant
2366: { //ENGINE calculates angvel for you
2367: doubvel = TICSPERFRAME;
2368: if ((syncbits[snum]&256) > 0) //Lt. shift makes turn velocity 50% faster
2369: doubvel += (TICSPERFRAME>>1);
2370: ang[snum] += ((((long)syncangvel[snum])*doubvel)>>4);
2371: ang[snum] = (ang[snum]+2048)&2047;
2372: }
2373:
2374: if (health[snum] < 0)
2375: {
2376: health[snum] -= TICSPERFRAME;
2377: if (health[snum] <= -160)
2378: {
2379: hvel[snum] = 0;
2380: if (snum == myconnectindex)
2381: vel = 0, svel = 0, angvel = 0, keystatus[3] = 1;
2382:
2383: deaths[snum]++;
2384: health[snum] = 100;
2385: numbombs[snum] = -1;
2386:
2387: findrandomspot(&posx[snum],&posy[snum],&cursectnum[snum]);
2388: posz[snum] = sector[cursectnum[snum]].floorz-(1<<8);
2389: horiz[snum] = 100;
2390: ang[snum] = (krand()&2047);
2391:
2392: setsprite(playersprite[snum],posx[snum],posy[snum],posz[snum]+(32<<8));
2393: sprite[playersprite[snum]].picnum = DOOMGUY;
2394: sprite[playersprite[snum]].ang = ang[snum];
2395: sprite[playersprite[snum]].xrepeat = 64;
2396: sprite[playersprite[snum]].yrepeat = 64;
2397:
2398: if ((snum == screenpeek) && (screensize <= xdim))
2399: {
2400: sprintf(&tempbuf,"Deaths: %d",deaths[snum]);
2401: printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-16,tempbuf,ALPHABET,80);
2402: sprintf(&tempbuf,"Health: %3d",health[snum]);
2403: printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-24,tempbuf,ALPHABET,80);
2404: }
2405:
2406: i = playersprite[snum];
2407: wsayfollow("zipguns.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1);
2408: for(k=0;k<16;k++)
2409: {
2410: spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z+(8<<8),2,-4,0,
2411: 32,24,24,0,0,EXPLOSION,sprite[i].ang,
2412: (krand()&511)-256,(krand()&511)-256,(krand()&16384)-8192,
2413: sprite[i].owner,sprite[i].sectnum,7,96,0,0);
2414: //96=Time left for smoke to be alive
2415: }
2416: }
2417: else
2418: {
2419: sprite[playersprite[snum]].xrepeat = max(((128+health[snum])>>1),0);
2420: sprite[playersprite[snum]].yrepeat = max(((128+health[snum])>>1),0);
2421:
2422: hvel[snum] += (TICSPERFRAME<<2);
2423: horiz[snum] = max(horiz[snum]-4,0);
2424: posz[snum] += hvel[snum];
2425: if (posz[snum] > globloz-(4<<8))
2426: {
2427: posz[snum] = globloz-(4<<8);
2428: horiz[snum] = min(horiz[snum]+5,200);
2429: hvel[snum] = 0;
2430: }
2431: }
2432: }
2433:
2434: if (((syncbits[snum]&8) > 0) && (horiz[snum] > 100-(200>>1))) horiz[snum] -= 4; //-
2435: if (((syncbits[snum]&4) > 0) && (horiz[snum] < 100+(200>>1))) horiz[snum] += 4; //+
2436:
2437: goalz = globloz-(32<<8); //32 pixels above floor
2438: if (sector[cursectnum[snum]].lotag == 4) //slime sector
2439: if ((globlohit&0xc000) != 49152) //You're not on a sprite
2440: {
2441: goalz = globloz-(8<<8);
2442: if (posz[snum] >= goalz-(2<<8))
2443: {
2444: clipmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],-TICSPERFRAME<<14,-TICSPERFRAME<<14,128L,4<<8,4<<8,0);
2445: frameinterpolate = 0;
2446:
2447: if (slimesoundcnt[snum] >= 0)
2448: {
2449: slimesoundcnt[snum] -= TICSPERFRAME;
2450: while (slimesoundcnt[snum] < 0)
2451: {
2452: slimesoundcnt[snum] += 120;
2453: wsayfollow("slime.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
2454: }
2455: }
2456: }
2457: }
2458: if (goalz < globhiz+(16<<8)) //ceiling&floor too close
2459: goalz = ((globloz+globhiz)>>1);
2460: //goalz += mousz;
2461: if (health[snum] >= 0)
2462: {
2463: if ((syncbits[snum]&1) > 0) //A (stand high)
2464: {
2465: if (posz[snum] >= globloz-(32<<8))
2466: {
2467: goalz -= (16<<8);
2468: if ((syncbits[snum]&256) > 0) //Either shift key
2469: goalz -= (24<<8);
2470: }
2471: }
2472: if ((syncbits[snum]&2) > 0) //Z (stand low)
2473: {
2474: goalz += (12<<8);
2475: if ((syncbits[snum]&256) > 0) //Either shift key
2476: goalz += (12<<8);
2477: }
2478: }
2479: if ((sector[cursectnum[snum]].floorstat&2) > 0) //Groudraw
2480: {
2481: if (waloff[sector[cursectnum[snum]].floorheinum] == 0) loadtile(sector[cursectnum[snum]].floorheinum);
2482: ptr = (char *)(waloff[sector[cursectnum[snum]].floorheinum]+(((posx[snum]>>4)&63)<<6)+((posy[snum]>>4)&63));
2483: goalz -= ((*ptr)<<8);
2484: }
2485:
2486: if (posz[snum] < goalz)
2487: hvel[snum] += (TICSPERFRAME<<4);
2488: else
2489: hvel[snum] = (((goalz-posz[snum])*TICSPERFRAME)>>5);
2490:
2491: posz[snum] += hvel[snum];
2492: if (posz[snum] > globloz-(4<<8)) posz[snum] = globloz-(4<<8), hvel[snum] = 0;
2493: if (posz[snum] < globhiz+(4<<8)) posz[snum] = globhiz+(4<<8), hvel[snum] = 0;
2494:
2495: if (dimensionmode[snum] != 3)
2496: {
2497: if (((syncbits[snum]&32) > 0) && (zoom[snum] > 48)) zoom[snum] -= (zoom[snum]>>4);
2498: if (((syncbits[snum]&16) > 0) && (zoom[snum] < 4096)) zoom[snum] += (zoom[snum]>>4);
2499: }
2500:
2501: //Update sprite representation of player
2502: // -should be after movement, but before shooting code
2503: setsprite(playersprite[snum],posx[snum],posy[snum],posz[snum]+(32<<8));
2504: sprite[playersprite[snum]].ang = ang[snum];
2505:
2506: if ((cursectnum[snum] < 0) || (cursectnum[snum] >= numsectors))
2507: { //How did you get in the wrong sector?
2508: wsayfollow("ouch.wav",4096L+(krand()&127)-64,64L,&posx[snum],&posy[snum],1);
2509: changehealth(snum,-TICSPERFRAME);
2510: }
2511: else if (globhiz+(8<<8) > globloz)
2512: { //Ceiling and floor are smooshing you!
2513: wsayfollow("ouch.wav",4096L+(krand()&127)-64,64L,&posx[snum],&posy[snum],1);
2514: changehealth(snum,-TICSPERFRAME);
2515: }
2516:
2517: if ((waterfountainwall[snum] >= 0) && (health[snum] >= 0))
2518: if ((wall[neartagwall].lotag != 7) || ((syncbits[snum]&1024) == 0))
2519: {
2520: i = waterfountainwall[snum];
2521: if (wall[i].overpicnum == USEWATERFOUNTAIN)
2522: wall[i].overpicnum = WATERFOUNTAIN;
2523: else if (wall[i].picnum == USEWATERFOUNTAIN)
2524: wall[i].picnum = WATERFOUNTAIN;
2525:
2526: waterfountainwall[snum] = -1;
2527: }
2528:
2529: if ((syncbits[snum]&1024) > 0) //Space bar
2530: {
2531: //Continuous triggers...
2532:
2533: neartag(posx[snum],posy[snum],posz[snum],cursectnum[snum],ang[snum],&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1024L,3);
2534: if (neartagsector == -1)
2535: {
2536: i = cursectnum[snum];
2537: if ((sector[i].lotag|sector[i].hitag) != 0)
2538: neartagsector = i;
2539: }
2540:
2541: if (wall[neartagwall].lotag == 7) //Water fountain
2542: {
2543: if (wall[neartagwall].overpicnum == WATERFOUNTAIN)
2544: {
2545: wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
2546: wall[neartagwall].overpicnum = USEWATERFOUNTAIN;
2547: waterfountainwall[snum] = neartagwall;
2548: }
2549: else if (wall[neartagwall].picnum == WATERFOUNTAIN)
2550: {
2551: wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
2552: wall[neartagwall].picnum = USEWATERFOUNTAIN;
2553: waterfountainwall[snum] = neartagwall;
2554: }
2555:
2556: if (waterfountainwall[snum] >= 0)
2557: {
2558: waterfountaincnt[snum] -= TICSPERFRAME;
2559: while (waterfountaincnt[snum] < 0)
2560: {
2561: waterfountaincnt[snum] += 120;
2562: wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1);
2563: changehealth(snum,2);
2564: }
2565: }
2566: }
2567:
2568: //1-time triggers...
2569: if ((oflags[snum]&1024) == 0)
2570: {
2571: if (neartagsector >= 0)
2572: if (sector[neartagsector].hitag == 0)
2573: operatesector(neartagsector);
2574:
2575: if (neartagwall >= 0)
2576: if (wall[neartagwall].lotag == 2) //Switch
2577: {
2578: for(i=0;i<numsectors;i++)
2579: if (sector[i].hitag == wall[neartagwall].hitag)
2580: if (sector[i].lotag != 1)
2581: operatesector(i);
2582: i = headspritestat[0];
2583: while (i != -1)
2584: {
2585: nexti = nextspritestat[i];
2586: if (sprite[i].hitag == wall[neartagwall].hitag)
2587: operatesprite(i);
2588: i = nexti;
2589: }
2590:
2591: j = wall[neartagwall].overpicnum;
2592: if (j == SWITCH1ON) //1-time switch
2593: {
2594: wall[neartagwall].overpicnum = GIFTBOX;
2595: wall[neartagwall].lotag = 0;
2596: wall[neartagwall].hitag = 0;
2597: }
2598: if (j == GIFTBOX) //1-time switch
2599: {
2600: wall[neartagwall].overpicnum = SWITCH1ON;
2601: wall[neartagwall].lotag = 0;
2602: wall[neartagwall].hitag = 0;
2603: }
2604: if (j == SWITCH2ON) wall[neartagwall].overpicnum = SWITCH2OFF;
2605: if (j == SWITCH2OFF) wall[neartagwall].overpicnum = SWITCH2ON;
2606: if (j == SWITCH3ON) wall[neartagwall].overpicnum = SWITCH3OFF;
2607: if (j == SWITCH3OFF) wall[neartagwall].overpicnum = SWITCH3ON;
2608:
2609: i = wall[neartagwall].point2;
2610: dax = ((wall[neartagwall].x+wall[i].x)>>1);
2611: day = ((wall[neartagwall].y+wall[i].y)>>1);
2612: wsayfollow("switch.wav",4096L+(krand()&255)-128,256L,&dax,&day,0);
2613: }
2614:
2615: if (neartagsprite >= 0)
2616: {
2617: if (sprite[neartagsprite].lotag == 1)
2618: { //if you're shoving innocent little AL around, he gets mad!
2619: if (sprite[neartagsprite].picnum == AL)
2620: {
2621: sprite[neartagsprite].picnum = EVILAL;
2622: sprite[neartagsprite].cstat |= 2; //Make him transluscent
2623: sprite[neartagsprite].xrepeat = 38;
2624: sprite[neartagsprite].yrepeat = 38;
2625: }
2626: changespritestat(neartagsprite,1);
2627: }
2628: if (sprite[neartagsprite].lotag == 4)
2629: {
2630: for(i=0;i<numsectors;i++)
2631: if (sector[i].hitag == sprite[neartagsprite].hitag)
2632: if (sector[i].lotag != 1)
2633: operatesector(i);
2634: i = headspritestat[0];
2635: while (i != -1)
2636: {
2637: nexti = nextspritestat[i];
2638: if (sprite[i].hitag == sprite[neartagsprite].hitag)
2639: operatesprite(i);
2640: i = nexti;
2641: }
2642:
2643: j = sprite[neartagsprite].picnum;
2644: if (j == SWITCH1ON) //1-time switch
2645: {
2646: sprite[neartagsprite].picnum = GIFTBOX;
2647: sprite[neartagsprite].lotag = 0;
2648: sprite[neartagsprite].hitag = 0;
2649: }
2650: if (j == GIFTBOX) //1-time switch
2651: {
2652: sprite[neartagsprite].picnum = SWITCH1ON;
2653: sprite[neartagsprite].lotag = 0;
2654: sprite[neartagsprite].hitag = 0;
2655: }
2656: if (j == SWITCH2ON) sprite[neartagsprite].picnum = SWITCH2OFF;
2657: if (j == SWITCH2OFF) sprite[neartagsprite].picnum = SWITCH2ON;
2658: if (j == SWITCH3ON) sprite[neartagsprite].picnum = SWITCH3OFF;
2659: if (j == SWITCH3OFF) sprite[neartagsprite].picnum = SWITCH3ON;
2660:
2661: dax = sprite[neartagsprite].x;
2662: day = sprite[neartagsprite].y;
2663: wsayfollow("switch.wav",4096L+(krand()&255)-128,256L,&dax,&day,0);
2664: }
2665: }
2666: }
2667: }
2668:
2669: if ((syncbits[snum]&2048) > 0) //Shoot a bullet
2670: {
2671: if ((health[snum] >= 0) || ((krand()&127) > -health[snum]))
2672: switch((syncbits[snum]>>13)&7)
2673: {
2674: case 0:
2675: if ((oflags[snum]&2048) == 0)
2676: shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],0);
2677: break;
2678: case 1:
2679: if (lockclock > lastchaingun[snum]+8)
2680: {
2681: lastchaingun[snum] = lockclock;
2682: shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],1);
2683: }
2684: break;
2685: case 2:
2686: if ((oflags[snum]&2048) == 0)
2687: if (numbombs[snum] > 0)
2688: {
2689: shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],2);
2690: numbombs[snum]--;
2691: }
2692: break;
2693: }
2694: }
2695:
2696: if ((syncbits[snum]&4096) > (oflags[snum]&4096)) //Keypad enter
2697: {
2698: dimensionmode[snum]++;
2699: if (dimensionmode[snum] > 3) dimensionmode[snum] = 1;
2700: if (snum == screenpeek)
2701: {
2702: if (dimensionmode[snum] == 2) setview(0L,0L,xdim-1,(ydim-1)>>detailmode);
2703: if (dimensionmode[snum] == 3) setup3dscreen();
2704: }
2705: }
2706:
2707: oflags[snum] = syncbits[snum];
2708: }
2709:
2710: static char lockbyte4094;
2711: drawscreen(short snum, long dasmoothratio)
2712: {
2713: long i, j, k, charsperline, templong, dx, dy, top, bot;
2714: long x1, y1, x2, y2, ox1, oy1, ox2, oy2, dist, maxdist;
2715: long cposx, cposy, cposz, choriz, czoom, tposx, tposy, thoriz;
2716: short cang, tang;
2717: char ch, *ptr, *ptr2, *ptr3, *ptr4;
2718:
2719: smoothratio = max(min(dasmoothratio,65536),0);
2720:
2721: setears(posx[snum],posy[snum],(long)sintable[(ang[snum]+512)&2047]<<14,(long)sintable[ang[snum]&2047]<<14);
2722:
2723: cposx = oposx[snum]+mulscale(posx[snum]-oposx[snum],smoothratio,16);
2724: cposy = oposy[snum]+mulscale(posy[snum]-oposy[snum],smoothratio,16);
2725: cposz = oposz[snum]+mulscale(posz[snum]-oposz[snum],smoothratio,16);
2726: if (frameinterpolate == 0)
2727: { cposx = posx[snum]; cposy = posy[snum]; cposz = posz[snum]; }
2728: choriz = ohoriz[snum]+mulscale(horiz[snum]-ohoriz[snum],smoothratio,16);
2729: czoom = ozoom[snum]+mulscale(zoom[snum]-ozoom[snum],smoothratio,16);
2730: cang = oang[snum]+mulscale(((ang[snum]+1024-oang[snum])&2047)-1024,smoothratio,16);
2731:
2732: if (dimensionmode[snum] != 2)
2733: {
2734: if ((numplayers > 1) && (option[4] == 0))
2735: {
2736: //Do not draw other views constantly if they're staying still
2737: //It's a shame this trick will only work in screen-buffer mode
2738: //At least screen-buffer mode covers all the HI hi-res modes
2739: if (vidoption == 1)
2740: {
2741: for(i=connecthead;i>=0;i=connectpoint2[i]) frame2draw[i] = 0;
2742: frame2draw[snum] = 1;
2743:
2744: //2-1,3-1,4-2
2745: //5-2,6-2,7-2,8-3,9-3,10-3,11-3,12-4,13-4,14-4,15-4,16-5
2746: x1 = posx[snum]; y1 = posy[snum];
2747: for(j=(numplayers>>2)+1;j>0;j--)
2748: {
2749: maxdist = 0x80000000;
2750: for(i=connecthead;i>=0;i=connectpoint2[i])
2751: if (frame2draw[i] == 0)
2752: {
2753: x2 = posx[i]-x1; y2 = posy[i]-y1;
2754: dist = mulscale(x2,x2,12) + mulscale(y2,y2,12);
2755:
2756: if (dist < 64) dist = 16384;
2757: else if (dist > 16384) dist = 64;
2758: else dist = 1048576 / dist;
2759:
2760: dist *= frameskipcnt[i];
2761:
2762: //Increase frame rate if screen is moving
2763: if ((posx[i] != oposx[i]) || (posy[i] != oposy[i]) ||
2764: (posz[i] != oposz[i]) || (ang[i] != oang[i]) ||
2765: (horiz[i] != ohoriz[i])) dist += dist;
2766:
2767: if (dist > maxdist) maxdist = dist, k = i;
2768: }
2769:
2770: for(i=connecthead;i>=0;i=connectpoint2[i])
2771: frameskipcnt[i] += (frameskipcnt[i]>>3)+1;
2772: frameskipcnt[k] = 0;
2773:
2774: frame2draw[k] = 1;
2775: }
2776: }
2777: else
2778: {
2779: for(i=connecthead;i>=0;i=connectpoint2[i]) frame2draw[i] = 1;
2780: }
2781:
2782: for(i=connecthead,j=0;i>=0;i=connectpoint2[i],j++)
2783: if (frame2draw[i] != 0)
2784: {
2785: if (numplayers <= 4)
2786: {
2787: switch(j)
2788: {
2789: case 0: setview(0,0,(xdim>>1)-1,(ydim>>1)-1); break;
2790: case 1: setview((xdim>>1),0,xdim-1,(ydim>>1)-1); break;
2791: case 2: setview(0,(ydim>>1),(xdim>>1)-1,ydim-1); break;
2792: case 3: setview((xdim>>1),(ydim>>1),xdim-1,ydim-1); break;
2793: }
2794: }
2795: else
2796: {
2797: switch(j)
2798: {
2799: case 0: setview(0,0,(xdim>>2)-1,(ydim>>2)-1); break;
2800: case 1: setview(xdim>>2,0,(xdim>>1)-1,(ydim>>2)-1); break;
2801: case 2: setview(xdim>>1,0,xdim-(xdim>>2)-1,(ydim>>2)-1); break;
2802: case 3: setview(xdim-(xdim>>2),0,xdim-1,(ydim>>2)-1); break;
2803: case 4: setview(0,ydim>>2,(xdim>>2)-1,(ydim>>1)-1); break;
2804: case 5: setview(xdim>>2,ydim>>2,(xdim>>1)-1,(ydim>>1)-1); break;
2805: case 6: setview(xdim>>1,ydim>>2,xdim-(xdim>>2)-1,(ydim>>1)-1); break;
2806: case 7: setview(xdim-(xdim>>2),ydim>>2,xdim-1,(ydim>>1)-1); break;
2807: case 8: setview(0,ydim>>1,(xdim>>2)-1,ydim-(ydim>>2)-1); break;
2808: case 9: setview(xdim>>2,ydim>>1,(xdim>>1)-1,ydim-(ydim>>2)-1); break;
2809: case 10: setview(xdim>>1,ydim>>1,xdim-(xdim>>2)-1,ydim-(ydim>>2)-1); break;
2810: case 11: setview(xdim-(xdim>>2),ydim>>1,xdim-1,ydim-(ydim>>2)-1); break;
2811: case 12: setview(0,ydim-(ydim>>2),(xdim>>2)-1,ydim-1); break;
2812: case 13: setview(xdim>>2,ydim-(ydim>>2),(xdim>>1)-1,ydim-1); break;
2813: case 14: setview(xdim>>1,ydim-(ydim>>2),xdim-(xdim>>2)-1,ydim-1); break;
2814: case 15: setview(xdim-(xdim>>2),ydim-(ydim>>2),xdim-1,ydim-1); break;
2815: }
2816: }
2817:
2818: if (i == snum)
2819: drawrooms(cposx,cposy,cposz,cang,choriz,cursectnum[i]);
2820: else
2821: drawrooms(posx[i],posy[i],posz[i],ang[i],horiz[i],cursectnum[i]);
2822: analyzesprites(posx[i],posy[i]);
2823: drawmasks();
2824: if (numbombs[i] > 0)
2825: overwritesprite(160L,184L,GUNONBOTTOM,sector[cursectnum[i]].floorshade,1|2,0);
2826:
2827: if (lockclock < 384)
2828: {
2829: if (lockclock < 128)
2830: rotatesprite(320<<15,200<<15,lockclock<<9,lockclock<<4,DEMOSIGN,(128-lockclock)>>2,0,1+2);
2831: else if (lockclock < 256)
2832: rotatesprite(320<<15,200<<15,65536,0,DEMOSIGN,0,0,2);
2833: else
2834: rotatesprite(320<<15,200<<15,(384-lockclock)<<9,lockclock<<4,DEMOSIGN,(lockclock-256)>>2,0,1+2);
2835: }
2836:
2837: if (health[i] <= 0)
2838: rotatesprite(320<<15,200<<15,(-health[i])<<11,(-health[i])<<5,NO,0,0,2);
2839: }
2840: }
2841: else
2842: {
2843: //Startdmost optimization for weapons
2844: if ((numbombs[screenpeek] > 0) && (windowx1 == 0) && (windowx2 == 320))
2845: {
2846: x1 = 160L-(tilesizx[GUNONBOTTOM]>>1);
2847: y1 = 184L-(tilesizy[GUNONBOTTOM]>>1);
2848: for(i=0;i<tilesizx[GUNONBOTTOM];i++)
2849: startdmost[i+x1] = min(windowy2+1,gundmost[i]+y1);
2850: }
2851:
2852: drawrooms(cposx,cposy,cposz,cang,choriz,cursectnum[snum]);
2853: analyzesprites(posx[snum],posy[snum]);
2854: drawmasks();
2855: if (numbombs[screenpeek] > 0)
2856: {
2857: //Reset startdmost to bottom of screen
2858: if ((windowx1 == 0) && (windowx2 == 320))
2859: {
2860: x1 = 160L-(tilesizx[GUNONBOTTOM]>>1); y1 = windowy2+1;
2861: for(i=0;i<tilesizx[GUNONBOTTOM];i++)
2862: startdmost[i+x1] = y1;
2863: }
2864: overwritesprite(160L,184L,GUNONBOTTOM,sector[cursectnum[screenpeek]].floorshade,1|2,0);
2865: }
2866:
2867: if (lockclock < 384)
2868: {
2869: if (lockclock < 128)
2870: rotatesprite(320<<15,200<<15,lockclock<<9,lockclock<<4,DEMOSIGN,(128-lockclock)>>2,0,1+2);
2871: else if (lockclock < 256)
2872: rotatesprite(320<<15,200<<15,65536,0,DEMOSIGN,0,0,2);
2873: else
2874: rotatesprite(320<<15,200<<15,(384-lockclock)<<9,lockclock<<4,DEMOSIGN,(lockclock-256)>>2,0,1+2);
2875: }
2876:
2877: if (health[screenpeek] <= 0)
2878: rotatesprite(320<<15,200<<15,(-health[screenpeek])<<11,(-health[screenpeek])<<5,NO,0,0,2);
2879: }
2880: }
2881:
2882: //Only animate lava if its picnum is on screen
2883: //gotpic is a bit array where the tile number's bit is set
2884: //whenever it is drawn (ceilings, walls, sprites, etc.)
2885: if ((gotpic[SLIME>>3]&(1<<(SLIME&7))) > 0)
2886: {
2887: gotpic[SLIME>>3] &= ~(1<<(SLIME&7));
2888: if (waloff[SLIME] != 0) movelava((char *)waloff[SLIME]);
2889: }
2890:
2891: if (dimensionmode[snum] != 3)
2892: {
2893: //Move back pivot point
2894: cposx += (sintable[(cang+512)&2047]<<6) / czoom;
2895: cposy += (sintable[cang&2047]<<6) / czoom;
2896: if (dimensionmode[snum] == 2)
2897: {
2898: clearview(0L); //Clear screen to specified color
2899: drawmapview(cposx,cposy,czoom,cang);
2900: }
2901: drawoverheadmap(cposx,cposy,czoom,cang);
2902: }
2903:
2904: if (numplayers >= 2)
2905: {
2906: //Tell who's master or slave
2907: if (lockclock < masterslavetexttime+120)
2908: {
2909: if (myconnectindex == connecthead)
2910: printext256(152L,0L,31,-1,"Master",0);
2911: else
2912: printext256(152L,0L,31,-1,"Slave",0);
2913: }
2914: }
2915:
2916: if (typemode != 0)
2917: {
2918: charsperline = 40;
2919: //if (dimensionmode[snum] == 2) charsperline = 80;
2920:
2921: for(i=0;i<=typemessageleng;i+=charsperline)
2922: {
2923: for(j=0;j<charsperline;j++)
2924: tempbuf[j] = typemessage[i+j];
2925: if (typemessageleng < i+charsperline)
2926: {
2927: tempbuf[(typemessageleng-i)] = '_';
2928: tempbuf[(typemessageleng-i)+1] = 0;
2929: }
2930: else
2931: tempbuf[charsperline] = 0;
2932: //if (dimensionmode[snum] == 3)
2933: printext256(0L,(i/charsperline)<<3,183,-1,tempbuf,0);
2934: //else
2935: // printext16(0L,((i/charsperline)<<3)+(pageoffset/640),10,-1,tempbuf,0);
2936: }
2937: }
2938: else
2939: {
2940: if (dimensionmode[myconnectindex] == 3)
2941: {
2942: templong = screensize;
2943:
2944: if (((locbits&32) > (screensizeflag&32)) && (screensize > 64))
2945: {
2946: ox1 = (xdim>>1)-(screensize>>1);
2947: ox2 = ox1+screensize-1;
2948: oy1 = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
2949: oy2 = oy1+((screensize*(ydim-32))/xdim)-1;
2950: screensize -= (screensize>>3);
2951:
2952: if (templong > xdim)
2953: {
2954: screensize = xdim;
2955:
2956: permanentwritesprite((xdim-320)>>1,ydim-32,STATUSBAR,0,0,0,xdim-1,ydim-1,0);
2957: i = ((xdim-320)>>1);
2958: while (i >= 8) i -= 8, permanentwritesprite(i,ydim-32,STATUSBARFILL8,0,0,0,xdim-1,ydim-1,0);
2959: if (i >= 4) i -= 4, permanentwritesprite(i,ydim-32,STATUSBARFILL4,0,0,0,xdim-1,ydim-1,0);
2960: i = ((xdim-320)>>1)+320;
2961: while (i <= xdim-8) permanentwritesprite(i,ydim-32,STATUSBARFILL8,0,0,0,xdim-1,ydim-1,0), i += 8;
2962: if (i <= xdim-4) permanentwritesprite(i,ydim-32,STATUSBARFILL4,0,0,0,xdim-1,ydim-1,0), i += 4;
2963:
2964: sprintf(&tempbuf,"Deaths: %d",deaths[screenpeek]);
2965: printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-16,tempbuf,ALPHABET,80);
2966:
2967: sprintf(&tempbuf,"Health: %3d",health[screenpeek]);
2968: printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-24,tempbuf,ALPHABET,80);
2969:
2970: sprintf(&tempbuf,"Score:%ld",score[screenpeek]);
2971: printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-8,tempbuf,ALPHABET,80);
2972: }
2973:
2974: x1 = (xdim>>1)-(screensize>>1);
2975: x2 = x1+screensize-1;
2976: y1 = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
2977: y2 = y1+((screensize*(ydim-32))/xdim)-1;
2978: setview(x1,y1>>detailmode,x2,y2>>detailmode);
2979:
2980: // (ox1,oy1)�����������������Ŀ
2981: // � (x1,y1) �
2982: // � �����Ŀ �
2983: // � � � �
2984: // � ������� �
2985: // � (x2,y2) �
2986: // �������������������(ox2,oy2)
2987:
2988: permanentwritespritetile(0L,0L,BACKGROUND,0,ox1,oy1,x1-1,oy2,0);
2989: permanentwritespritetile(0L,0L,BACKGROUND,0,x2+1,oy1,ox2,oy2,0);
2990: permanentwritespritetile(0L,0L,BACKGROUND,0,x1,oy1,x2,y1-1,0);
2991: permanentwritespritetile(0L,0L,BACKGROUND,0,x1,y2+1,x2,oy2,0);
2992: }
2993: if (((locbits&16) > (screensizeflag&16)) && (screensize <= xdim))
2994: {
2995: screensize += (screensize>>3);
2996: if ((screensize > xdim) && (templong == xdim))
2997: {
2998: screensize = xdim+1;
2999: x1 = 0; y1 = 0;
3000: x2 = xdim-1; y2 = ydim-1;
3001: }
3002: else
3003: {
3004: if (screensize > xdim) screensize = xdim;
3005: x1 = (xdim>>1)-(screensize>>1);
3006: x2 = x1+screensize-1;
3007: y1 = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
3008: y2 = y1+((screensize*(ydim-32))/xdim)-1;
3009: }
3010: setview(x1,y1>>detailmode,x2,y2>>detailmode);
3011: }
3012: screensizeflag = locbits;
3013: }
3014: }
3015:
3016: if (getmessageleng > 0)
3017: {
3018: charsperline = 40;
3019: //if (dimensionmode[snum] == 2) charsperline = 80;
3020:
3021: for(i=0;i<=getmessageleng;i+=charsperline)
3022: {
3023: for(j=0;j<charsperline;j++)
3024: tempbuf[j] = getmessage[i+j];
3025: if (getmessageleng < i+charsperline)
3026: tempbuf[(getmessageleng-i)] = 0;
3027: else
3028: tempbuf[charsperline] = 0;
3029:
3030: printext256(0L,((i/charsperline)<<3)+(200-32-8)-(((getmessageleng-1)/charsperline)<<3),151,-1,tempbuf,0);
3031: }
3032: if (totalclock > getmessagetimeoff)
3033: getmessageleng = 0;
3034: }
3035: if ((numplayers >= 2) && (screenpeek != myconnectindex))
3036: {
3037: strcpy(tempbuf,"Other");
3038:
3039: //if (dimensionmode[snum] == 3)
3040: printext256((xdim>>1)-(strlen(tempbuf)<<2),0,24,-1,tempbuf,0);
3041: //else
3042: // printext16(xdim-(strlen(tempbuf)<<2),(pageoffset/640),7,-1,tempbuf,0);
3043: }
3044:
3045: if (syncstat != 0) printext256(68L,84L,31,0,"OUT OF SYNC!",0);
3046: if (syncstate != 0) printext256(68L,92L,31,0,"Missed Network packet!",0);
3047:
3048: nextpage();
3049:
3050: if (keystatus[0x3f] > 0) //F5
3051: {
3052: keystatus[0x3f] = 0;
3053: detailmode ^= 1;
3054: if (detailmode == 0)
3055: {
3056: setview(windowx1,windowy1<<1,windowx2,(windowy2<<1)+1);
3057: outp(0x3d4,0x9); outp(0x3d5,(inp(0x3d5)&~31)|1);
3058: }
3059: else
3060: {
3061: setview(windowx1,windowy1>>detailmode,windowx2,windowy2>>detailmode);
3062: setaspect(yxaspect>>1);
3063: outp(0x3d4,0x9); outp(0x3d5,(inp(0x3d5)&~31)|3);
3064: }
3065: }
3066: if (keystatus[0x58] > 0) //F12
3067: {
3068: keystatus[0x58] = 0;
3069: screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]);
3070: }
3071: if (stereofps != 0) //Adjustments for red-blue / 120 crystal eyes modes
3072: {
3073: if ((keystatus[0x2a]|keystatus[0x36]) > 0)
3074: {
3075: if (keystatus[0x1a] > 0) stereopixelwidth--; //Shift [
3076: if (keystatus[0x1b] > 0) stereopixelwidth++; //Shift ]
3077: }
3078: else
3079: {
3080: if (keystatus[0x1a] > 0) stereowidth -= 512; //[
3081: if (keystatus[0x1b] > 0) stereowidth += 512; //]
3082: }
3083: }
3084:
3085: if (option[4] == 0) //Single player only keys
3086: {
3087: if (keystatus[0xd2] > 0) //Insert - Insert player
3088: {
3089: keystatus[0xd2] = 0;
3090: if (numplayers < MAXPLAYERS)
3091: {
3092: connectpoint2[numplayers-1] = numplayers;
3093: connectpoint2[numplayers] = -1;
3094:
3095: initplayersprite(numplayers);
3096:
3097: clearallviews(0L); //Clear screen to specified color
3098:
3099: numplayers++;
3100: }
3101: }
3102: if (keystatus[0xd3] > 0) //Delete - Delete player
3103: {
3104: keystatus[0xd3] = 0;
3105: if (numplayers > 1)
3106: {
3107: numplayers--;
3108: connectpoint2[numplayers-1] = -1;
3109:
3110: deletesprite(playersprite[numplayers]);
3111: playersprite[numplayers] = -1;
3112:
3113: if (myconnectindex >= numplayers) myconnectindex = 0;
3114: if (screenpeek >= numplayers) screenpeek = 0;
3115:
3116: if (numplayers < 2)
3117: setup3dscreen();
3118: else
3119: clearallviews(0L); //Clear screen to specified color
3120: }
3121: }
3122: if (keystatus[0x46] > 0) //Scroll Lock
3123: {
3124: keystatus[0x46] = 0;
3125:
3126: myconnectindex = connectpoint2[myconnectindex];
3127: if (myconnectindex < 0) myconnectindex = connecthead;
3128: screenpeek = myconnectindex;
3129: }
3130: }
3131: }
3132:
3133: movethings()
3134: {
3135: long i;
3136:
3137: gotlastpacketclock = totalclock;
3138: for(i=connecthead;i>=0;i=connectpoint2[i])
3139: {
3140: baksyncvel[movefifoend][i] = fsyncvel[i];
3141: baksyncsvel[movefifoend][i] = fsyncsvel[i];
3142: baksyncangvel[movefifoend][i] = fsyncangvel[i];
3143: baksyncbits[movefifoend][i] = fsyncbits[i];
3144: }
3145: movefifoend = ((movefifoend+1)&(MOVEFIFOSIZ-1));
3146:
3147: //Do this for Master/Slave switching
3148: for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
3149: if (syncbits[i]&512) ready2send = 0;
3150: }
3151:
3152: domovethings()
3153: {
3154: short i, j, startwall, endwall;
3155: spritetype *spr;
3156: walltype *wal;
3157: point3d *ospr;
3158:
3159: for(i=connecthead;i>=0;i=connectpoint2[i])
3160: {
3161: syncvel[i] = baksyncvel[movefifoplc][i];
3162: syncsvel[i] = baksyncsvel[movefifoplc][i];
3163: syncangvel[i] = baksyncangvel[movefifoplc][i];
3164: syncbits[i] = baksyncbits[movefifoplc][i];
3165: }
3166: movefifoplc = ((movefifoplc+1)&(MOVEFIFOSIZ-1));
3167:
3168: syncval[syncvalend] = getsyncstat();
3169: syncvalend = ((syncvalend+1)&(MOVEFIFOSIZ-1));
3170:
3171: for(i=connecthead;i>=0;i=connectpoint2[i])
3172: {
3173: oposx[i] = posx[i];
3174: oposy[i] = posy[i];
3175: oposz[i] = posz[i];
3176: ohoriz[i] = horiz[i];
3177: ozoom[i] = zoom[i];
3178: oang[i] = ang[i];
3179: }
3180:
3181: for(i=1;i<=8;i++)
3182: if (i != 2)
3183: for(j=headspritestat[i];j>=0;j=nextspritestat[j])
3184: copybuf(&sprite[j].x,&osprite[j].x,3);
3185:
3186: for(i=connecthead;i>=0;i=connectpoint2[i])
3187: ocursectnum[i] = cursectnum[i];
3188:
3189: if ((numplayers <= 2) && (recstat == 1))
3190: {
3191: j = 0;
3192: for(i=connecthead;i>=0;i=connectpoint2[i])
3193: {
3194: recsyncvel[reccnt][j] = syncvel[i];
3195: recsyncsvel[reccnt][j] = syncsvel[i];
3196: recsyncangvel[reccnt][j] = syncangvel[i];
3197: recsyncbits[reccnt][j] = syncbits[i];
3198: j++;
3199: }
3200: reccnt++; if (reccnt > 16383) reccnt = 16383;
3201: }
3202:
3203: lockclock += TICSPERFRAME;
3204:
3205: for(i=connecthead;i>=0;i=connectpoint2[i])
3206: {
3207: processinput(i); //Move player
3208:
3209: checktouchsprite(i,cursectnum[i]); //Pick up coins
3210: startwall = sector[cursectnum[i]].wallptr;
3211: endwall = startwall + sector[cursectnum[i]].wallnum;
3212: for(j=startwall,wal=&wall[j];j<endwall;j++,wal++)
3213: if (wal->nextsector >= 0) checktouchsprite(i,wal->nextsector);
3214: }
3215:
3216: doanimations();
3217: tagcode(); //Door code, moving sector code, other stuff
3218: statuslistcode(); //Monster / bullet code / explosions
3219:
3220: checkmasterslaveswitch();
3221: }
3222:
3223: getinput()
3224: {
3225: char ch, keystate, *ptr;
3226: long i, j, k;
3227: short mousx, mousy, bstatus;
3228:
3229: if (typemode == 0) //if normal game keys active
3230: {
3231: if ((keystatus[0x2a]&keystatus[0x36]&keystatus[0x13]) > 0) //Sh.Sh.R (replay)
3232: {
3233: keystatus[0x13] = 0;
3234: playback();
3235: }
3236:
3237: if ((keystatus[0x26]&(keystatus[0x1d]|keystatus[0x9d])) > 0) //Load game
3238: {
3239: keystatus[0x26] = 0;
3240: loadgame();
3241: }
3242:
3243: if ((keystatus[0x1f]&(keystatus[0x1d]|keystatus[0x9d])) > 0) //Save game
3244: {
3245: keystatus[0x1f] = 0;
3246: savegame();
3247: }
3248:
3249: if (keystatus[keys[15]] > 0)
3250: {
3251: keystatus[keys[15]] = 0;
3252:
3253: screenpeek = connectpoint2[screenpeek];
3254: if (screenpeek < 0) screenpeek = connecthead;
3255: }
3256:
3257: for(i=7;i>=0;i--)
3258: if (keystatus[i+2] > 0)
3259: { keystatus[i+2] = 0; locselectedgun = i; break; }
3260: }
3261:
3262:
3263: //KEYTIMERSTUFF
3264: if (keystatus[keys[5]] == 0)
3265: {
3266: if (keystatus[keys[2]] > 0) angvel = max(angvel-16*TICSPERFRAME,-128);
3267: if (keystatus[keys[3]] > 0) angvel = min(angvel+16*TICSPERFRAME,127);
3268: }
3269: else
3270: {
3271: if (keystatus[keys[2]] > 0) svel = min(svel+8*TICSPERFRAME,127);
3272: if (keystatus[keys[3]] > 0) svel = max(svel-8*TICSPERFRAME,-128);
3273: }
3274: if (keystatus[keys[0]] > 0) vel = min(vel+8*TICSPERFRAME,127);
3275: if (keystatus[keys[1]] > 0) vel = max(vel-8*TICSPERFRAME,-128);
3276: if (keystatus[keys[12]] > 0) svel = min(svel+8*TICSPERFRAME,127);
3277: if (keystatus[keys[13]] > 0) svel = max(svel-8*TICSPERFRAME,-128);
3278:
3279: if (angvel < 0) angvel = min(angvel+12*TICSPERFRAME,0);
3280: if (angvel > 0) angvel = max(angvel-12*TICSPERFRAME,0);
3281: if (svel < 0) svel = min(svel+2*TICSPERFRAME,0);
3282: if (svel > 0) svel = max(svel-2*TICSPERFRAME,0);
3283: if (vel < 0) vel = min(vel+2*TICSPERFRAME,0);
3284: if (vel > 0) vel = max(vel-2*TICSPERFRAME,0);
3285:
3286: if ((option[4] == 0) && (numplayers == 2))
3287: {
3288: if (keystatus[0x4f] == 0)
3289: {
3290: if (keystatus[0x4b] > 0) angvel2 = max(angvel2-16*TICSPERFRAME,-128);
3291: if (keystatus[0x4d] > 0) angvel2 = min(angvel2+16*TICSPERFRAME,127);
3292: }
3293: else
3294: {
3295: if (keystatus[0x4b] > 0) svel2 = min(svel2+8*TICSPERFRAME,127);
3296: if (keystatus[0x4d] > 0) svel2 = max(svel2-8*TICSPERFRAME,-128);
3297: }
3298: if (keystatus[0x48] > 0) vel2 = min(vel2+8*TICSPERFRAME,127);
3299: if (keystatus[0x4c] > 0) vel2 = max(vel2-8*TICSPERFRAME,-128);
3300:
3301: if (angvel2 < 0) angvel2 = min(angvel2+12*TICSPERFRAME,0);
3302: if (angvel2 > 0) angvel2 = max(angvel2-12*TICSPERFRAME,0);
3303: if (svel2 < 0) svel2 = min(svel2+2*TICSPERFRAME,0);
3304: if (svel2 > 0) svel2 = max(svel2-2*TICSPERFRAME,0);
3305: if (vel2 < 0) vel2 = min(vel2+2*TICSPERFRAME,0);
3306: if (vel2 > 0) vel2 = max(vel2-2*TICSPERFRAME,0);
3307: }
3308:
3309: locvel = min(max(vel,-128+8),127-8);
3310: locsvel = min(max(svel,-128+8),127-8);
3311: locangvel = min(max(angvel,-128+16),127-16);
3312:
3313: getmousevalues(&mousx,&mousy,&bstatus);
3314: locangvel = min(max(locangvel+(mousx<<3),-128),127);
3315: locvel = min(max(locvel-(mousy<<3),-128),127);
3316:
3317: locbits = (locselectedgun<<13);
3318: if (typemode == 0) //if normal game keys active
3319: {
3320: locbits |= (keystatus[0x32]<<9); //M (be master)
3321: locbits |= ((keystatus[keys[14]]==1)<<12); //Map mode
3322: }
3323: locbits |= keystatus[keys[8]]; //Stand high
3324: locbits |= (keystatus[keys[9]]<<1); //Stand low
3325: locbits |= (keystatus[keys[16]]<<4); //Zoom in
3326: locbits |= (keystatus[keys[17]]<<5); //Zoom out
3327: locbits |= (keystatus[keys[4]]<<8); //Run
3328: locbits |= (keystatus[keys[10]]<<2); //Look up
3329: locbits |= (keystatus[keys[11]]<<3); //Look down
3330: locbits |= ((keystatus[keys[7]]==1)<<10); //Space
3331: locbits |= ((keystatus[keys[6]]==1)<<11); //Shoot
3332: locbits |= (((bstatus&6)>(oldmousebstatus&6))<<10); //Space
3333: locbits |= (((bstatus&1)>(oldmousebstatus&1))<<11); //Shoot
3334:
3335: oldmousebstatus = bstatus;
3336: if (((locbits&2048) > 0) && (locselectedgun == 1))
3337: oldmousebstatus &= ~1; //Allow continous fire with mouse for chain gun
3338:
3339: //PRIVATE KEYS:
3340: if (keystatus[0xb7] > 0) //Printscreen
3341: {
3342: keystatus[0xb7] = 0;
3343: printscreeninterrupt();
3344: }
3345: if (keystatus[0x57] > 0) //F11 - brightness
3346: {
3347: keystatus[0x57] = 0;
3348: brightness++;
3349: if (brightness > 8) brightness = 0;
3350: setbrightness(brightness);
3351: }
3352:
3353: if (typemode == 0) //if normal game keys active
3354: {
3355: if (keystatus[0x19] > 0) //P
3356: {
3357: keystatus[0x19] = 0;
3358: parallaxtype++;
3359: if (parallaxtype > 2) parallaxtype = 0;
3360: }
3361: if ((keystatus[0x38]|keystatus[0xb8]) > 0) //ALT
3362: {
3363: if (keystatus[0x4a] > 0) // Keypad -
3364: visibility = min(visibility+(visibility>>3),16384);
3365: if (keystatus[0x4e] > 0) // Keypad +
3366: visibility = max(visibility-(visibility>>3),128);
3367: }
3368:
3369: /*if ((option[1] == 1) && (option[4] >= 5))
3370: {
3371: if ((keystatus[0x13] > 0) && (recsnddone == 1) && (recording == -2)) //R (record)
3372: {
3373: wrec(32768L);
3374: recording = -1;
3375: }
3376: if ((recording == -1) && ((keystatus[0x13] == 0) || (recsnddone == 1)))
3377: {
3378: continueplay();
3379: recsnddone = 1;
3380: recording = 0;
3381: wsay("recordedvoice",2972L,255L,255L);
3382: }
3383: if ((recording >= 0) && (screenpeek != myconnectindex))
3384: {
3385: tempbuf[0] = 3;
3386:
3387: ptr = (char *)(recsndoffs+recording);
3388: for(i=0;i<256;i++)
3389: tempbuf[i+1] = *ptr++;
3390: recording += 256;
3391:
3392: sendpacket(screenpeek,tempbuf,257L);
3393: if (recording >= 32768)
3394: recording = -2;
3395: }
3396: }*/
3397:
3398: if ((keystatus[keys[18]]) > 0) //Typing mode
3399: {
3400: keystatus[keys[18]] = 0;
3401: typemode = 1;
3402: keyfifoplc = keyfifoend; //Reset keyboard fifo
3403: }
3404: }
3405: else
3406: {
3407: while (keyfifoplc != keyfifoend)
3408: {
3409: ch = keyfifo[keyfifoplc];
3410: keystate = keyfifo[(keyfifoplc+1)&(KEYFIFOSIZ-1)];
3411: keyfifoplc = ((keyfifoplc+2)&(KEYFIFOSIZ-1));
3412:
3413: if (keystate != 0)
3414: {
3415: if (ch == 0xe) //Backspace
3416: {
3417: if (typemessageleng == 0) { typemode = 0; break; }
3418: typemessageleng--;
3419: }
3420: if (ch == 0xf)
3421: {
3422: keystatus[0xf] = 0;
3423: typemode = 0;
3424: break;
3425: }
3426: if ((ch == 0x1c) || (ch == 0x9c)) //Either ENTER
3427: {
3428: keystatus[0x1c] = 0; keystatus[0x9c] = 0;
3429: if (typemessageleng > 0)
3430: {
3431: tempbuf[0] = 2; //Sending text is message type 4
3432: for(j=typemessageleng-1;j>=0;j--)
3433: tempbuf[j+1] = typemessage[j];
3434:
3435: for(i=connecthead;i>=0;i=connectpoint2[i])
3436: if (i != myconnectindex)
3437: sendpacket(i,tempbuf,typemessageleng+1);
3438:
3439: typemessageleng = 0;
3440: }
3441: typemode = 0;
3442: break;
3443: }
3444:
3445: if ((typemessageleng < 159) && (ch < 128))
3446: {
3447: if ((keystatus[0x2a]|keystatus[0x36]) != 0)
3448: ch = scantoascwithshift[ch];
3449: else
3450: ch = scantoasc[ch];
3451:
3452: if (ch != 0) typemessage[typemessageleng++] = ch;
3453: }
3454: }
3455: }
3456: //Here's a trick of making key repeat after a 1/2 second
3457: if (keystatus[0xe] > 0)
3458: {
3459: if (keystatus[0xe] < 30)
3460: keystatus[0xe] += TICSPERFRAME;
3461: else
3462: {
3463: if (typemessageleng == 0)
3464: typemode = 0;
3465: else
3466: typemessageleng--;
3467: }
3468: }
3469: }
3470: }
3471:
3472: initplayersprite(short snum)
3473: {
3474: long i;
3475:
3476: if (playersprite[snum] >= 0) return;
3477:
3478: spawnsprite(playersprite[snum],posx[snum],posy[snum],posz[snum]+(32<<8),
3479: 1+256,0,snum,32,64,64,0,0,DOOMGUY,ang[snum],0,0,0,snum+4096,
3480: cursectnum[snum],8,0,0,0);
3481:
3482: switch(snum)
3483: {
3484: case 1: for(i=0;i<32;i++) tempbuf[i+192] = i+128; break; //green->red
3485: case 2: for(i=0;i<32;i++) tempbuf[i+192] = i+32; break; //green->blue
3486: case 3: for(i=0;i<32;i++) tempbuf[i+192] = i+224; break; //green->pink
3487: case 4: for(i=0;i<32;i++) tempbuf[i+192] = i+64; break; //green->brown
3488: case 5: for(i=0;i<32;i++) tempbuf[i+192] = i+96; break;
3489: case 6: for(i=0;i<32;i++) tempbuf[i+192] = i+160; break;
3490: case 7: for(i=0;i<32;i++) tempbuf[i+192] = i+192; break;
3491: default: for(i=0;i<256;i++) tempbuf[i] = i; break;
3492: }
3493: makepalookup(snum,tempbuf,0,0,0,1);
3494: }
3495:
3496: playback()
3497: {
3498: long i, j, k;
3499:
3500: ready2send = 0;
3501: recstat = 0; i = reccnt;
3502: while (keystatus[1] == 0)
3503: {
3504: while (totalclock >= lockclock+TICSPERFRAME)
3505: {
3506: if (i >= reccnt)
3507: {
3508: prepareboard(boardfilename);
3509: for(i=connecthead;i>=0;i=connectpoint2[i])
3510: initplayersprite((short)i);
3511: resettiming(); ototalclock = 0; gotlastpacketclock = 0;
3512: i = 0;
3513: }
3514:
3515: k = 0;
3516: for(j=connecthead;j>=0;j=connectpoint2[j])
3517: {
3518: fsyncvel[j] = recsyncvel[i][k];
3519: fsyncsvel[j] = recsyncsvel[i][k];
3520: fsyncangvel[j] = recsyncangvel[i][k];
3521: fsyncbits[j] = recsyncbits[i][k];
3522: k++;
3523: }
3524: movethings(); domovethings();
3525: i++;
3526: }
3527: drawscreen(screenpeek,(totalclock-lockclock)*(65536/TICSPERFRAME));
3528:
3529: if (keystatus[keys[15]] > 0)
3530: {
3531: keystatus[keys[15]] = 0;
3532:
3533: screenpeek = connectpoint2[screenpeek];
3534: if (screenpeek < 0) screenpeek = connecthead;
3535: }
3536: if (keystatus[keys[14]] > 0)
3537: {
3538: keystatus[keys[14]] = 0;
3539: dimensionmode[screenpeek]++;
3540: if (dimensionmode[screenpeek] > 3) dimensionmode[screenpeek] = 1;
3541: if (dimensionmode[screenpeek] == 2) setview(0L,0L,xdim-1,(ydim-1)>>detailmode);
3542: if (dimensionmode[screenpeek] == 3) setup3dscreen();
3543: }
3544: }
3545:
3546: musicoff();
3547: uninitmultiplayers();
3548: uninittimer();
3549: uninitkeys();
3550: uninitengine();
3551: uninitsb();
3552: uninitgroupfile();
3553: setvmode(0x3); //Set back to text mode
3554: exit(0);
3555: }
3556:
3557: setup3dscreen()
3558: {
3559: long i, dax, day, dax2, day2;
3560:
3561: setgamemode();
3562:
3563: if (screensize > xdim)
3564: {
3565: dax = 0; day = 0;
3566: dax2 = xdim-1; day2 = ydim-1;
3567: }
3568: else
3569: {
3570: dax = (xdim>>1)-(screensize>>1);
3571: dax2 = dax+screensize-1;
3572: day = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
3573: day2 = day + ((screensize*(ydim-32))/xdim)-1;
3574: setview(dax,day>>detailmode,dax2,day2>>detailmode);
3575: }
3576:
3577: if (screensize < xdim)
3578: permanentwritespritetile(0L,0L,BACKGROUND,0,0L,0L,xdim-1,ydim-1,0); //Draw background
3579:
3580: if (screensize <= xdim)
3581: {
3582: permanentwritesprite((xdim-320)>>1,ydim-32,STATUSBAR,0,0,0,xdim-1,ydim-1,0);
3583: i = ((xdim-320)>>1);
3584: while (i >= 8) i -= 8, permanentwritesprite(i,ydim-32,STATUSBARFILL8,0,0,0,xdim-1,ydim-1,0);
3585: if (i >= 4) i -= 4, permanentwritesprite(i,ydim-32,STATUSBARFILL4,0,0,0,xdim-1,ydim-1,0);
3586: i = ((xdim-320)>>1)+320;
3587: while (i <= xdim-8) permanentwritesprite(i,ydim-32,STATUSBARFILL8,0,0,0,xdim-1,ydim-1,0), i += 8;
3588: if (i <= xdim-4) permanentwritesprite(i,ydim-32,STATUSBARFILL4,0,0,0,xdim-1,ydim-1,0), i += 4;
3589:
3590: sprintf(&tempbuf,"Deaths: %d",deaths[screenpeek]);
3591: printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-16,tempbuf,ALPHABET,80);
3592:
3593: sprintf(&tempbuf,"Health: %3d",health[screenpeek]);
3594: printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-24,tempbuf,ALPHABET,80);
3595:
3596: sprintf(&tempbuf,"Score:%ld",score[screenpeek]);
3597: printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-8,tempbuf,ALPHABET,80);
3598: }
3599: }
3600:
3601: findrandomspot(long *x, long *y, short *sectnum)
3602: {
3603: short startwall, endwall, s;
3604: long dax, day, minx, maxx, miny, maxy, cnt, k;
3605:
3606: cnt = 256;
3607: while (cnt > 0)
3608: {
3609: do
3610: {
3611: k = mulscale(krand(),numsectors,16);
3612: } while ((sector[k].ceilingz >= sector[k].floorz) || (sector[k].lotag != 0) || ((sector[k].floorstat&2) != 0));
3613:
3614: startwall = sector[k].wallptr;
3615: endwall = startwall+sector[k].wallnum-1;
3616: if (endwall > startwall)
3617: {
3618: dax = 0L;
3619: day = 0L;
3620: minx = 0x7fffffff; maxx = 0x80000000;
3621: miny = 0x7fffffff; maxy = 0x80000000;
3622:
3623: for(s=startwall;s<=endwall;s++)
3624: {
3625: dax += wall[s].x;
3626: day += wall[s].y;
3627: if (wall[s].x < minx) minx = wall[s].x;
3628: if (wall[s].x > maxx) maxx = wall[s].x;
3629: if (wall[s].y < miny) miny = wall[s].y;
3630: if (wall[s].y > maxy) maxy = wall[s].y;
3631: }
3632: if ((maxx-minx > 256) && (maxy-miny > 256))
3633: {
3634: dax /= (endwall-startwall+1);
3635: day /= (endwall-startwall+1);
3636: if (inside(dax,day,k) == 1)
3637: {
3638: *x = dax;
3639: *y = day;
3640: *sectnum = k;
3641: return;
3642: }
3643: }
3644: }
3645: cnt--;
3646: }
3647: }
3648:
3649: warp(long *x, long *y, long *z, short *daang, short *dasector)
3650: {
3651: short startwall, endwall, s;
3652: long i, j, dax, day, ox, oy;
3653:
3654: ox = *x; oy = *y;
3655:
3656: for(i=0;i<warpsectorcnt;i++)
3657: if (warpsectorlist[i] == *dasector)
3658: {
3659: j = sector[*dasector].hitag;
3660: do
3661: {
3662: i++;
3663: if (i >= warpsectorcnt) i = 0;
3664: } while (sector[warpsectorlist[i]].hitag != j);
3665: *dasector = warpsectorlist[i];
3666: break;
3667: }
3668:
3669: //Find center of sector
3670: startwall = sector[*dasector].wallptr;
3671: endwall = startwall+sector[*dasector].wallnum-1;
3672: dax = 0L, day = 0L;
3673: for(s=startwall;s<=endwall;s++)
3674: {
3675: dax += wall[s].x, day += wall[s].y;
3676: if (wall[s].nextsector >= 0)
3677: i = s;
3678: }
3679: *x = dax / (endwall-startwall+1);
3680: *y = day / (endwall-startwall+1);
3681: *z = sector[*dasector].floorz-(32<<8);
3682: updatesector(*x,*y,dasector);
3683: dax = ((wall[i].x+wall[wall[i].point2].x)>>1);
3684: day = ((wall[i].y+wall[wall[i].point2].y)>>1);
3685: *daang = getangle(dax-*x,day-*y);
3686:
3687: wsayfollow("warp.wav",3072L+(krand()&127)-64,192L,&ox,&oy,0);
3688: wsayfollow("warp.wav",4096L+(krand()&127)-64,256L,x,y,0);
3689: }
3690:
3691: warpsprite(short spritenum)
3692: {
3693: short dasectnum;
3694:
3695: dasectnum = sprite[spritenum].sectnum;
3696: warp(&sprite[spritenum].x,&sprite[spritenum].y,&sprite[spritenum].z,
3697: &sprite[spritenum].ang,&dasectnum);
3698:
3699: copybuf(&sprite[spritenum].x,&osprite[spritenum].x,3);
3700: changespritesect(spritenum,dasectnum);
3701: }
3702:
3703: initlava()
3704: {
3705: long x, y, z, r;
3706:
3707: for(x=-16;x<=16;x++)
3708: for(y=-16;y<=16;y++)
3709: {
3710: r = ksqrt(x*x + y*y);
3711: lavaradx[r][lavaradcnt[r]] = x;
3712: lavarady[r][lavaradcnt[r]] = y;
3713: lavaradcnt[r]++;
3714: }
3715:
3716: for(z=0;z<16;z++)
3717: lavadropsizlookup[z] = 8 / (ksqrt(z)+1);
3718:
3719: for(z=0;z<LAVASIZ;z++)
3720: lavainc[z] = klabs((((z^17)>>4)&7)-4)+12;
3721:
3722: lavanumdrops = 0;
3723: lavanumframes = 0;
3724: }
3725:
3726: movelava(char *dapic)
3727: {
3728: char dat, *ptr;
3729: long x, y, z, zx, dalavadropsiz, dadropsizlookup, offs, offs2;
3730: long dalavax, dalavay;
3731:
3732: z = 3;
3733: if (lavanumdrops+z >= LAVAMAXDROPS)
3734: z = LAVAMAXDROPS-lavanumdrops-1;
3735: while (z >= 0)
3736: {
3737: lavadropx[lavanumdrops] = (rand()&(LAVASIZ-1));
3738: lavadropy[lavanumdrops] = (rand()&(LAVASIZ-1));
3739: lavadropsiz[lavanumdrops] = 1;
3740: lavanumdrops++;
3741: z--;
3742: }
3743:
3744: z = lavanumdrops-1;
3745: while (z >= 0)
3746: {
3747: dadropsizlookup = lavadropsizlookup[lavadropsiz[z]]*(((z&1)<<1)-1);
3748: dalavadropsiz = lavadropsiz[z];
3749: dalavax = lavadropx[z]; dalavay = lavadropy[z];
3750: for(zx=lavaradcnt[lavadropsiz[z]]-1;zx>=0;zx--)
3751: {
3752: offs = (((lavaradx[dalavadropsiz][zx]+dalavax)&(LAVASIZ-1))<<LAVALOGSIZ);
3753: offs += ((lavarady[dalavadropsiz][zx]+dalavay)&(LAVASIZ-1));
3754: dapic[offs] += dadropsizlookup;
3755: if (dapic[offs] < 192) dapic[offs] = 192;
3756: }
3757:
3758: lavadropsiz[z]++;
3759: if (lavadropsiz[z] > 10)
3760: {
3761: lavanumdrops--;
3762: lavadropx[z] = lavadropx[lavanumdrops];
3763: lavadropy[z] = lavadropy[lavanumdrops];
3764: lavadropsiz[z] = lavadropsiz[lavanumdrops];
3765: }
3766: z--;
3767: }
3768:
3769: //Back up dapic with 1 pixel extra on each boundary
3770: //(to prevent anding for wrap-around)
3771: offs = ((long)dapic);
3772: offs2 = (LAVASIZ+2)+1+((long)lavabakpic);
3773: for(x=0;x<LAVASIZ;x++)
3774: {
3775: copybuf(offs,offs2,LAVASIZ>>2);
3776: offs += LAVASIZ;
3777: offs2 += LAVASIZ+2;
3778: }
3779: for(y=0;y<LAVASIZ;y++)
3780: {
3781: lavabakpic[y+1] = dapic[y+((LAVASIZ-1)<<LAVALOGSIZ)];
3782: lavabakpic[y+1+(LAVASIZ+1)*(LAVASIZ+2)] = dapic[y];
3783: }
3784: for(x=0;x<LAVASIZ;x++)
3785: {
3786: lavabakpic[(x+1)*(LAVASIZ+2)] = dapic[(x<<LAVALOGSIZ)+(LAVASIZ-1)];
3787: lavabakpic[(x+1)*(LAVASIZ+2)+(LAVASIZ+1)] = dapic[x<<LAVALOGSIZ];
3788: }
3789: lavabakpic[0] = dapic[LAVASIZ*LAVASIZ-1];
3790: lavabakpic[LAVASIZ+1] = dapic[LAVASIZ*(LAVASIZ-1)];
3791: lavabakpic[(LAVASIZ+2)*(LAVASIZ+1)] = dapic[LAVASIZ-1];
3792: lavabakpic[(LAVASIZ+2)*(LAVASIZ+2)-1] = dapic[0];
3793:
3794: for(z=(LAVASIZ+2)*(LAVASIZ+2)-4;z>=0;z-=4)
3795: {
3796: lavabakpic[z+0] &= 31;
3797: lavabakpic[z+1] &= 31;
3798: lavabakpic[z+2] &= 31;
3799: lavabakpic[z+3] &= 31;
3800: }
3801:
3802: for(x=LAVASIZ-1;x>=0;x--)
3803: {
3804: offs = (x+1)*(LAVASIZ+2)+1;
3805: ptr = (char *)((x<<LAVALOGSIZ) + (long)dapic);
3806:
3807: zx = ((x+lavanumframes)&(LAVASIZ-1));
3808:
3809: offs2 = LAVASIZ-1;
3810: for(y=offs;y<offs+LAVASIZ;y++)
3811: {
3812: dat = lavainc[(offs2--)&zx];
3813: dat += lavabakpic[y-(LAVASIZ+2)-1];
3814: dat += lavabakpic[y-(LAVASIZ+2)];
3815: dat += lavabakpic[y-(LAVASIZ+2)+1];
3816: dat += lavabakpic[y-1];
3817: dat += lavabakpic[y+1];
3818: dat += lavabakpic[y+(LAVASIZ+2)];
3819: dat += lavabakpic[y+(LAVASIZ+2)-1];
3820: *ptr++ = (dat>>3)+192;
3821: }
3822: }
3823:
3824: lavanumframes++;
3825: }
3826:
3827: doanimations()
3828: {
3829: long i, j;
3830:
3831: for(i=animatecnt-1;i>=0;i--)
3832: {
3833: j = *animateptr[i];
3834:
3835: if (j < animategoal[i])
3836: j = min(j+animatevel[i]*TICSPERFRAME,animategoal[i]);
3837: else
3838: j = max(j-animatevel[i]*TICSPERFRAME,animategoal[i]);
3839: animatevel[i] += animateacc[i];
3840:
3841: *animateptr[i] = j;
3842:
3843: if (j == animategoal[i])
3844: {
3845: animatecnt--;
3846: if (i != animatecnt)
3847: {
3848: animateptr[i] = animateptr[animatecnt];
3849: animategoal[i] = animategoal[animatecnt];
3850: animatevel[i] = animatevel[animatecnt];
3851: animateacc[i] = animateacc[animatecnt];
3852: }
3853: }
3854: }
3855: }
3856:
3857: getanimationgoal(long animptr)
3858: {
3859: long i;
3860:
3861: for(i=animatecnt-1;i>=0;i--)
3862: if (animptr == animateptr[i]) return(i);
3863: return(-1);
3864: }
3865:
3866: setanimation(long *animptr, long thegoal, long thevel, long theacc)
3867: {
3868: long i, j;
3869:
3870: if (animatecnt >= MAXANIMATES) return(-1);
3871:
3872: j = animatecnt;
3873: for(i=animatecnt-1;i>=0;i--)
3874: if (animptr == animateptr[i])
3875: { j = i; break; }
3876:
3877: animateptr[j] = animptr;
3878: animategoal[j] = thegoal;
3879: animatevel[j] = thevel;
3880: animateacc[j] = theacc;
3881: if (j == animatecnt) animatecnt++;
3882: return(j);
3883: }
3884:
3885: checkmasterslaveswitch()
3886: {
3887: long i, j;
3888:
3889: if (option[4] == 0) return;
3890:
3891: i = connecthead; j = connectpoint2[i];
3892: while (j >= 0)
3893: {
3894: if ((syncbits[j]&512) > 0)
3895: {
3896: connectpoint2[i] = connectpoint2[j];
3897: connectpoint2[j] = connecthead;
3898: connecthead = (short)j;
3899:
3900: olocvel = locvel+1; olocvel2 = locvel2+1;
3901: olocsvel = locsvel+1; olocsvel2 = locsvel2+1;
3902: olocangvel = locangvel+1; olocangvel2 = locangvel2+1;
3903: olocbits = locbits+1; olocbits2 = locbits2+1;
3904: for(i=0;i<MAXPLAYERS;i++)
3905: {
3906: osyncvel[i] = fsyncvel[i]+1;
3907: osyncsvel[i] = fsyncsvel[i]+1;
3908: osyncangvel[i] = fsyncangvel[i]+1;
3909: osyncbits[i] = fsyncbits[i]+1;
3910: }
3911:
3912: syncvalplc = 0L; othersyncvalplc = 0L;
3913: syncvalend = 0L; othersyncvalend = 0L;
3914: syncvalcnt = 0L; othersyncvalcnt = 0L;
3915:
3916: totalclock = lockclock;
3917: ototalclock = lockclock;
3918: gotlastpacketclock = lockclock;
3919: masterslavetexttime = lockclock;
3920: ready2send = 1;
3921: return;
3922: }
3923: i = j; j = connectpoint2[i];
3924: }
3925: }
3926:
3927: inittimer()
3928: {
3929: outp(0x43,54); outp(0x40,9942&255); outp(0x40,9942>>8); //120 times/sec
3930: oldtimerhandler = _dos_getvect(0x8);
3931: _disable(); _dos_setvect(0x8, timerhandler); _enable();
3932: }
3933:
3934: uninittimer()
3935: {
3936: outp(0x43,54); outp(0x40,255); outp(0x40,255); //18.2 times/sec
3937: _disable(); _dos_setvect(0x8, oldtimerhandler); _enable();
3938: }
3939:
3940: void __interrupt __far timerhandler()
3941: {
3942: totalclock++;
3943: outp(0x20,0x20);
3944: }
3945:
3946: initkeys()
3947: {
3948: long i;
3949:
3950: keyfifoplc = 0; keyfifoend = 0;
3951: for(i=0;i<256;i++) keystatus[i] = 0;
3952: oldkeyhandler = _dos_getvect(0x9);
3953: _disable(); _dos_setvect(0x9, keyhandler); _enable();
3954: }
3955:
3956: uninitkeys()
3957: {
3958: short *ptr;
3959:
3960: _dos_setvect(0x9, oldkeyhandler);
3961: //Turn off shifts to prevent stucks with quitting
3962: ptr = (short *)0x417; *ptr &= ~0x030f;
3963: }
3964:
3965: void __interrupt __far keyhandler()
3966: {
3967: koutp(0x20,0x20);
3968: oldreadch = readch; readch = kinp(0x60);
3969: keytemp = kinp(0x61); koutp(0x61,keytemp|128); koutp(0x61,keytemp&127);
3970: if ((readch|1) == 0xe1) { extended = 128; return; }
3971: if (oldreadch != readch)
3972: {
3973: if ((readch&128) == 0)
3974: {
3975: keytemp = readch+extended;
3976: if (keystatus[keytemp] == 0)
3977: {
3978: keystatus[keytemp] = 1;
3979: keyfifo[keyfifoend] = keytemp;
3980: keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = 1;
3981: keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1));
3982: }
3983: }
3984: else
3985: {
3986: keytemp = (readch&127)+extended;
3987: keystatus[keytemp] = 0;
3988: keyfifo[keyfifoend] = keytemp;
3989: keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = 0;
3990: keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1));
3991: }
3992: }
3993: extended = 0;
3994: }
3995:
3996: testneighborsectors(short sect1, short sect2)
3997: {
3998: short i, startwall, num1, num2;
3999:
4000: num1 = sector[sect1].wallnum;
4001: num2 = sector[sect2].wallnum;
4002: if (num1 < num2) //Traverse walls of sector with fewest walls (for speed)
4003: {
4004: startwall = sector[sect1].wallptr;
4005: for(i=num1-1;i>=0;i--)
4006: if (wall[i+startwall].nextsector == sect2)
4007: return(1);
4008: }
4009: else
4010: {
4011: startwall = sector[sect2].wallptr;
4012: for(i=num2-1;i>=0;i--)
4013: if (wall[i+startwall].nextsector == sect1)
4014: return(1);
4015: }
4016: return(0);
4017: }
4018:
4019: loadgame()
4020: {
4021: long i, fil;
4022:
4023: if ((fil = open("save0000.gam",O_BINARY|O_RDWR,S_IREAD)) == -1)
4024: return(-1);
4025:
4026: read(fil,&numplayers,2);
4027: read(fil,&myconnectindex,2);
4028: read(fil,&connecthead,2);
4029: read(fil,connectpoint2,MAXPLAYERS<<1);
4030:
4031: //Make sure palookups get set, sprites will get overwritten later
4032: for(i=connecthead;i>=0;i=connectpoint2[i]) initplayersprite((short)i);
4033:
4034: read(fil,posx,MAXPLAYERS<<2);
4035: read(fil,posy,MAXPLAYERS<<2);
4036: read(fil,posz,MAXPLAYERS<<2);
4037: read(fil,horiz,MAXPLAYERS<<2);
4038: read(fil,zoom,MAXPLAYERS<<2);
4039: read(fil,hvel,MAXPLAYERS<<2);
4040: read(fil,ang,MAXPLAYERS<<1);
4041: read(fil,cursectnum,MAXPLAYERS<<1);
4042: read(fil,ocursectnum,MAXPLAYERS<<1);
4043: read(fil,playersprite,MAXPLAYERS<<1);
4044: read(fil,deaths,MAXPLAYERS<<1);
4045: read(fil,lastchaingun,MAXPLAYERS<<2);
4046: read(fil,health,MAXPLAYERS<<2);
4047: read(fil,score,MAXPLAYERS<<2);
4048: read(fil,saywatchit,MAXPLAYERS<<2);
4049: read(fil,numbombs,MAXPLAYERS<<1);
4050: read(fil,&screensize,2);
4051: read(fil,oflags,MAXPLAYERS<<1);
4052: read(fil,dimensionmode,MAXPLAYERS);
4053: read(fil,revolvedoorstat,MAXPLAYERS);
4054: read(fil,revolvedoorang,MAXPLAYERS<<1);
4055: read(fil,revolvedoorrotang,MAXPLAYERS<<1);
4056: read(fil,revolvedoorx,MAXPLAYERS<<2);
4057: read(fil,revolvedoory,MAXPLAYERS<<2);
4058:
4059: read(fil,&numsectors,2);
4060: read(fil,sector,sizeof(sectortype)*numsectors);
4061:
4062: read(fil,&numwalls,2);
4063: read(fil,wall,sizeof(walltype)*numwalls);
4064:
4065: //Store all sprites (even holes) to preserve indeces
4066: read(fil,sprite,sizeof(spritetype)*MAXSPRITES);
4067: read(fil,headspritesect,(MAXSECTORS+1)<<1);
4068: read(fil,prevspritesect,MAXSPRITES<<1);
4069: read(fil,nextspritesect,MAXSPRITES<<1);
4070: read(fil,headspritestat,(MAXSTATUS+1)<<1);
4071: read(fil,prevspritestat,MAXSPRITES<<1);
4072: read(fil,nextspritestat,MAXSPRITES<<1);
4073:
4074: read(fil,&vel,4);
4075: read(fil,&svel,4);
4076: read(fil,&angvel,4);
4077:
4078: read(fil,&locselectedgun,4);
4079: read(fil,&locvel,1);
4080: read(fil,&olocvel,1);
4081: read(fil,&locsvel,1);
4082: read(fil,&olocsvel,1);
4083: read(fil,&locangvel,1);
4084: read(fil,&olocangvel,1);
4085: read(fil,&locbits,2);
4086: read(fil,&olocbits,2);
4087:
4088: read(fil,&locselectedgun2,4);
4089: read(fil,&locvel2,1);
4090: read(fil,&olocvel2,1);
4091: read(fil,&locsvel2,1);
4092: read(fil,&olocsvel2,1);
4093: read(fil,&locangvel2,1);
4094: read(fil,&olocangvel2,1);
4095: read(fil,&locbits2,2);
4096: read(fil,&olocbits2,2);
4097:
4098: read(fil,syncvel,MAXPLAYERS);
4099: read(fil,osyncvel,MAXPLAYERS);
4100: read(fil,syncsvel,MAXPLAYERS);
4101: read(fil,osyncsvel,MAXPLAYERS);
4102: read(fil,syncangvel,MAXPLAYERS);
4103: read(fil,osyncangvel,MAXPLAYERS);
4104: read(fil,syncbits,MAXPLAYERS<<1);
4105: read(fil,osyncbits,MAXPLAYERS<<1);
4106:
4107: read(fil,boardfilename,80);
4108: read(fil,&screenpeek,2);
4109: read(fil,&oldmousebstatus,2);
4110: read(fil,&brightness,2);
4111: read(fil,&neartagsector,2);
4112: read(fil,&neartagwall,2);
4113: read(fil,&neartagsprite,2);
4114: read(fil,&lockclock,4);
4115: read(fil,&neartagdist,4);
4116: read(fil,&neartaghitdist,4);
4117: read(fil,&masterslavetexttime,4);
4118:
4119: read(fil,rotatespritelist,16<<1);
4120: read(fil,&rotatespritecnt,2);
4121: read(fil,warpsectorlist,16<<1);
4122: read(fil,&warpsectorcnt,2);
4123: read(fil,xpanningsectorlist,16<<1);
4124: read(fil,&xpanningsectorcnt,2);
4125: read(fil,ypanningwalllist,64<<1);
4126: read(fil,&ypanningwallcnt,2);
4127: read(fil,floorpanninglist,64<<1);
4128: read(fil,&floorpanningcnt,2);
4129: read(fil,dragsectorlist,16<<1);
4130: read(fil,dragxdir,16<<1);
4131: read(fil,dragydir,16<<1);
4132: read(fil,&dragsectorcnt,2);
4133: read(fil,dragx1,16<<2);
4134: read(fil,dragy1,16<<2);
4135: read(fil,dragx2,16<<2);
4136: read(fil,dragy2,16<<2);
4137: read(fil,dragfloorz,16<<2);
4138: read(fil,&swingcnt,2);
4139: read(fil,swingwall,(32*5)<<1);
4140: read(fil,swingsector,32<<1);
4141: read(fil,swingangopen,32<<1);
4142: read(fil,swingangclosed,32<<1);
4143: read(fil,swingangopendir,32<<1);
4144: read(fil,swingang,32<<1);
4145: read(fil,swinganginc,32<<1);
4146: read(fil,swingx,(32*8)<<2);
4147: read(fil,swingy,(32*8)<<2);
4148: read(fil,revolvesector,4<<1);
4149: read(fil,revolveang,4<<1);
4150: read(fil,&revolvecnt,2);
4151: read(fil,revolvex,(4*16)<<2);
4152: read(fil,revolvey,(4*16)<<2);
4153: read(fil,revolvepivotx,4<<2);
4154: read(fil,revolvepivoty,4<<2);
4155: read(fil,subwaytracksector,(4*128)<<1);
4156: read(fil,subwaynumsectors,4<<1);
4157: read(fil,&subwaytrackcnt,2);
4158: read(fil,subwaystop,(4*8)<<2);
4159: read(fil,subwaystopcnt,4<<2);
4160: read(fil,subwaytrackx1,4<<2);
4161: read(fil,subwaytracky1,4<<2);
4162: read(fil,subwaytrackx2,4<<2);
4163: read(fil,subwaytracky2,4<<2);
4164: read(fil,subwayx,4<<2);
4165: read(fil,subwaygoalstop,4<<2);
4166: read(fil,subwayvel,4<<2);
4167: read(fil,subwaypausetime,4<<2);
4168: read(fil,waterfountainwall,MAXPLAYERS<<1);
4169: read(fil,waterfountaincnt,MAXPLAYERS<<1);
4170: read(fil,slimesoundcnt,MAXPLAYERS<<1);
4171:
4172: //Warning: only works if all pointers are in sector structures!
4173: read(fil,animateptr,MAXANIMATES<<2);
4174: for(i=MAXANIMATES-1;i>=0;i--)
4175: animateptr[i] = (long *)(animateptr[i]+((long)sector));
4176: read(fil,animategoal,MAXANIMATES<<2);
4177: read(fil,animatevel,MAXANIMATES<<2);
4178: read(fil,animateacc,MAXANIMATES<<2);
4179: read(fil,&animatecnt,4);
4180:
4181: read(fil,&totalclock,4);
4182: read(fil,&numframes,4);
4183: read(fil,&randomseed,4);
4184: read(fil,startumost,MAXXDIM<<1);
4185: read(fil,startdmost,MAXXDIM<<1);
4186: read(fil,&numpalookups,2);
4187:
4188: read(fil,&visibility,4);
4189: read(fil,¶llaxtype,1);
4190: read(fil,¶llaxyoffs,4);
4191: read(fil,pskyoff,MAXPSKYTILES<<1);
4192: read(fil,&pskybits,2);
4193:
4194: read(fil,show2dsector,MAXSECTORS>>3);
4195: read(fil,show2dwall,MAXWALLS>>3);
4196: read(fil,show2dsprite,MAXSPRITES>>3);
4197: read(fil,&automapping,1);
4198:
4199: close(fil);
4200:
4201: for(i=connecthead;i>=0;i=connectpoint2[i]) initplayersprite((short)i);
4202:
4203: totalclock = lockclock;
4204: ototalclock = lockclock;
4205:
4206: strcpy(getmessage,"Game loaded.");
4207: getmessageleng = strlen(getmessage);
4208: getmessagetimeoff = totalclock+360+(getmessageleng<<4);
4209: return(0);
4210: }
4211:
4212: savegame()
4213: {
4214: long i, fil;
4215:
4216: if ((fil = open("save0000.gam",O_BINARY|O_TRUNC|O_CREAT|O_WRONLY,S_IWRITE)) == -1)
4217: return(-1);
4218:
4219: write(fil,&numplayers,2);
4220: write(fil,&myconnectindex,2);
4221: write(fil,&connecthead,2);
4222: write(fil,connectpoint2,MAXPLAYERS<<1);
4223:
4224: write(fil,posx,MAXPLAYERS<<2);
4225: write(fil,posy,MAXPLAYERS<<2);
4226: write(fil,posz,MAXPLAYERS<<2);
4227: write(fil,horiz,MAXPLAYERS<<2);
4228: write(fil,zoom,MAXPLAYERS<<2);
4229: write(fil,hvel,MAXPLAYERS<<2);
4230: write(fil,ang,MAXPLAYERS<<1);
4231: write(fil,cursectnum,MAXPLAYERS<<1);
4232: write(fil,ocursectnum,MAXPLAYERS<<1);
4233: write(fil,playersprite,MAXPLAYERS<<1);
4234: write(fil,deaths,MAXPLAYERS<<1);
4235: write(fil,lastchaingun,MAXPLAYERS<<2);
4236: write(fil,health,MAXPLAYERS<<2);
4237: write(fil,score,MAXPLAYERS<<2);
4238: write(fil,saywatchit,MAXPLAYERS<<2);
4239: write(fil,numbombs,MAXPLAYERS<<1);
4240: write(fil,&screensize,2);
4241: write(fil,oflags,MAXPLAYERS<<1);
4242: write(fil,dimensionmode,MAXPLAYERS);
4243: write(fil,revolvedoorstat,MAXPLAYERS);
4244: write(fil,revolvedoorang,MAXPLAYERS<<1);
4245: write(fil,revolvedoorrotang,MAXPLAYERS<<1);
4246: write(fil,revolvedoorx,MAXPLAYERS<<2);
4247: write(fil,revolvedoory,MAXPLAYERS<<2);
4248:
4249: write(fil,&numsectors,2);
4250: write(fil,sector,sizeof(sectortype)*numsectors);
4251:
4252: write(fil,&numwalls,2);
4253: write(fil,wall,sizeof(walltype)*numwalls);
4254:
4255: //Store all sprites (even holes) to preserve indeces
4256: write(fil,sprite,sizeof(spritetype)*MAXSPRITES);
4257: write(fil,headspritesect,(MAXSECTORS+1)<<1);
4258: write(fil,prevspritesect,MAXSPRITES<<1);
4259: write(fil,nextspritesect,MAXSPRITES<<1);
4260: write(fil,headspritestat,(MAXSTATUS+1)<<1);
4261: write(fil,prevspritestat,MAXSPRITES<<1);
4262: write(fil,nextspritestat,MAXSPRITES<<1);
4263:
4264: write(fil,&vel,4);
4265: write(fil,&svel,4);
4266: write(fil,&angvel,4);
4267:
4268: write(fil,&locselectedgun,4);
4269: write(fil,&locvel,1);
4270: write(fil,&olocvel,1);
4271: write(fil,&locsvel,1);
4272: write(fil,&olocsvel,1);
4273: write(fil,&locangvel,1);
4274: write(fil,&olocangvel,1);
4275: write(fil,&locbits,2);
4276: write(fil,&olocbits,2);
4277:
4278: write(fil,&locselectedgun2,4);
4279: write(fil,&locvel2,1);
4280: write(fil,&olocvel2,1);
4281: write(fil,&locsvel2,1);
4282: write(fil,&olocsvel2,1);
4283: write(fil,&locangvel2,1);
4284: write(fil,&olocangvel2,1);
4285: write(fil,&locbits2,2);
4286: write(fil,&olocbits2,2);
4287:
4288: write(fil,syncvel,MAXPLAYERS);
4289: write(fil,osyncvel,MAXPLAYERS);
4290: write(fil,syncsvel,MAXPLAYERS);
4291: write(fil,osyncsvel,MAXPLAYERS);
4292: write(fil,syncangvel,MAXPLAYERS);
4293: write(fil,osyncangvel,MAXPLAYERS);
4294: write(fil,syncbits,MAXPLAYERS<<1);
4295: write(fil,osyncbits,MAXPLAYERS<<1);
4296:
4297: write(fil,boardfilename,80);
4298: write(fil,&screenpeek,2);
4299: write(fil,&oldmousebstatus,2);
4300: write(fil,&brightness,2);
4301: write(fil,&neartagsector,2);
4302: write(fil,&neartagwall,2);
4303: write(fil,&neartagsprite,2);
4304: write(fil,&lockclock,4);
4305: write(fil,&neartagdist,4);
4306: write(fil,&neartaghitdist,4);
4307: write(fil,&masterslavetexttime,4);
4308:
4309: write(fil,rotatespritelist,16<<1);
4310: write(fil,&rotatespritecnt,2);
4311: write(fil,warpsectorlist,16<<1);
4312: write(fil,&warpsectorcnt,2);
4313: write(fil,xpanningsectorlist,16<<1);
4314: write(fil,&xpanningsectorcnt,2);
4315: write(fil,ypanningwalllist,64<<1);
4316: write(fil,&ypanningwallcnt,2);
4317: write(fil,floorpanninglist,64<<1);
4318: write(fil,&floorpanningcnt,2);
4319: write(fil,dragsectorlist,16<<1);
4320: write(fil,dragxdir,16<<1);
4321: write(fil,dragydir,16<<1);
4322: write(fil,&dragsectorcnt,2);
4323: write(fil,dragx1,16<<2);
4324: write(fil,dragy1,16<<2);
4325: write(fil,dragx2,16<<2);
4326: write(fil,dragy2,16<<2);
4327: write(fil,dragfloorz,16<<2);
4328: write(fil,&swingcnt,2);
4329: write(fil,swingwall,(32*5)<<1);
4330: write(fil,swingsector,32<<1);
4331: write(fil,swingangopen,32<<1);
4332: write(fil,swingangclosed,32<<1);
4333: write(fil,swingangopendir,32<<1);
4334: write(fil,swingang,32<<1);
4335: write(fil,swinganginc,32<<1);
4336: write(fil,swingx,(32*8)<<2);
4337: write(fil,swingy,(32*8)<<2);
4338: write(fil,revolvesector,4<<1);
4339: write(fil,revolveang,4<<1);
4340: write(fil,&revolvecnt,2);
4341: write(fil,revolvex,(4*16)<<2);
4342: write(fil,revolvey,(4*16)<<2);
4343: write(fil,revolvepivotx,4<<2);
4344: write(fil,revolvepivoty,4<<2);
4345: write(fil,subwaytracksector,(4*128)<<1);
4346: write(fil,subwaynumsectors,4<<1);
4347: write(fil,&subwaytrackcnt,2);
4348: write(fil,subwaystop,(4*8)<<2);
4349: write(fil,subwaystopcnt,4<<2);
4350: write(fil,subwaytrackx1,4<<2);
4351: write(fil,subwaytracky1,4<<2);
4352: write(fil,subwaytrackx2,4<<2);
4353: write(fil,subwaytracky2,4<<2);
4354: write(fil,subwayx,4<<2);
4355: write(fil,subwaygoalstop,4<<2);
4356: write(fil,subwayvel,4<<2);
4357: write(fil,subwaypausetime,4<<2);
4358: write(fil,waterfountainwall,MAXPLAYERS<<1);
4359: write(fil,waterfountaincnt,MAXPLAYERS<<1);
4360: write(fil,slimesoundcnt,MAXPLAYERS<<1);
4361:
4362: //Warning: only works if all pointers are in sector structures!
4363: for(i=MAXANIMATES-1;i>=0;i--)
4364: animateptr[i] = (long *)(animateptr[i]-((long)sector));
4365: write(fil,animateptr,MAXANIMATES<<2);
4366: for(i=MAXANIMATES-1;i>=0;i--)
4367: animateptr[i] = (long *)(animateptr[i]+((long)sector));
4368: write(fil,animategoal,MAXANIMATES<<2);
4369: write(fil,animatevel,MAXANIMATES<<2);
4370: write(fil,animateacc,MAXANIMATES<<2);
4371: write(fil,&animatecnt,4);
4372:
4373: write(fil,&totalclock,4);
4374: write(fil,&numframes,4);
4375: write(fil,&randomseed,4);
4376: write(fil,startumost,MAXXDIM<<1);
4377: write(fil,startdmost,MAXXDIM<<1);
4378: write(fil,&numpalookups,2);
4379:
4380: write(fil,&visibility,4);
4381: write(fil,¶llaxtype,1);
4382: write(fil,¶llaxyoffs,4);
4383: write(fil,pskyoff,MAXPSKYTILES<<1);
4384: write(fil,&pskybits,2);
4385:
4386: write(fil,show2dsector,MAXSECTORS>>3);
4387: write(fil,show2dwall,MAXWALLS>>3);
4388: write(fil,show2dsprite,MAXSPRITES>>3);
4389: write(fil,&automapping,1);
4390:
4391: close(fil);
4392:
4393: strcpy(getmessage,"Game saved.");
4394: getmessageleng = strlen(getmessage);
4395: getmessagetimeoff = totalclock+360+(getmessageleng<<4);
4396: return(0);
4397: }
4398:
4399: faketimerhandler()
4400: {
4401: short other, tempbufleng;
4402: long i, j, k, l;
4403:
4404: if (totalclock < ototalclock+TICSPERFRAME) return;
4405: if (ready2send == 0) return;
4406: ototalclock = totalclock;
4407:
4408: //I am the MASTER (or 1 player game)
4409: if ((myconnectindex == connecthead) || (option[4] == 0))
4410: {
4411: if (option[4] != 0)
4412: getpackets();
4413:
4414: if (getoutputcirclesize() < 16)
4415: {
4416: getinput();
4417: fsyncvel[myconnectindex] = locvel;
4418: fsyncsvel[myconnectindex] = locsvel;
4419: fsyncangvel[myconnectindex] = locangvel;
4420: fsyncbits[myconnectindex] = locbits;
4421:
4422: if (option[4] != 0)
4423: {
4424: tempbuf[0] = 0;
4425: j = ((numplayers+1)>>1)+1;
4426: for(k=1;k<j;k++) tempbuf[k] = 0;
4427: k = (1<<3);
4428: for(i=connecthead;i>=0;i=connectpoint2[i])
4429: {
4430: l = 0;
4431: if (fsyncvel[i] != osyncvel[i]) tempbuf[j++] = fsyncvel[i], l |= 1;
4432: if (fsyncsvel[i] != osyncsvel[i]) tempbuf[j++] = fsyncsvel[i], l |= 2;
4433: if (fsyncangvel[i] != osyncangvel[i]) tempbuf[j++] = fsyncangvel[i], l |= 4;
4434: if (fsyncbits[i] != osyncbits[i])
4435: {
4436: tempbuf[j++] = (fsyncbits[i]&255);
4437: tempbuf[j++] = ((fsyncbits[i]>>8)&255);
4438: l |= 8;
4439: }
4440: tempbuf[k>>3] |= (l<<(k&7));
4441: k += 4;
4442:
4443: osyncvel[i] = fsyncvel[i];
4444: osyncsvel[i] = fsyncsvel[i];
4445: osyncangvel[i] = fsyncangvel[i];
4446: osyncbits[i] = fsyncbits[i];
4447: }
4448:
4449: while (syncvalplc != syncvalend)
4450: {
4451: tempbuf[j] = (char)(syncval[syncvalplc]&255);
4452: tempbuf[j+1] = (char)((syncval[syncvalplc]>>8)&255);
4453: j += 2;
4454: syncvalplc = ((syncvalplc+1)&(MOVEFIFOSIZ-1));
4455: }
4456:
4457: for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
4458: sendpacket(i,tempbuf,j);
4459: }
4460: else if (numplayers == 2)
4461: {
4462: if (keystatus[0xb5] > 0)
4463: {
4464: keystatus[0xb5] = 0;
4465: locselectedgun2++;
4466: if (locselectedgun2 >= 3) locselectedgun2 = 0;
4467: }
4468:
4469: //Second player on 1 computer mode
4470: locvel2 = min(max(vel2,-128+8),127-8);
4471: locsvel2 = min(max(svel2,-128+8),127-8);
4472: locangvel2 = min(max(angvel2,-128+16),127-16);
4473: locbits2 = (locselectedgun2<<13);
4474: locbits2 |= keystatus[0x45]; //Stand high
4475: locbits2 |= (keystatus[0x47]<<1); //Stand low
4476: locbits2 |= (1<<8); //Run
4477: locbits2 |= (keystatus[0x49]<<2); //Look up
4478: locbits2 |= (keystatus[0x37]<<3); //Look down
4479: locbits2 |= (keystatus[0x50]<<10); //Space
4480: locbits2 |= (keystatus[0x52]<<11); //Shoot
4481:
4482: other = connectpoint2[myconnectindex];
4483: if (other < 0) other = connecthead;
4484:
4485: fsyncvel[other] = locvel2;
4486: fsyncsvel[other] = locsvel2;
4487: fsyncangvel[other] = locangvel2;
4488: fsyncbits[other] = locbits2;
4489: }
4490: movethings(); //Move EVERYTHING (you too!)
4491: }
4492: }
4493: else //I am a SLAVE
4494: {
4495: getpackets();
4496:
4497: if (getoutputcirclesize() < 16)
4498: {
4499: getinput();
4500:
4501: tempbuf[0] = 1; k = 0;
4502: j = 2;
4503:
4504: if (locvel != olocvel) tempbuf[j++] = locvel, k |= 1;
4505: if (locsvel != olocsvel) tempbuf[j++] = locsvel, k |= 2;
4506: if (locangvel != olocangvel) tempbuf[j++] = locangvel, k |= 4;
4507: if ((locbits^olocbits)&0x00ff) tempbuf[j++] = (locbits&255), k |= 8;
4508: if ((locbits^olocbits)&0xff00) tempbuf[j++] = ((locbits>>8)&255), k |= 16;
4509:
4510: tempbuf[1] = k;
4511:
4512: olocvel = locvel;
4513: olocsvel = locsvel;
4514: olocangvel = locangvel;
4515: olocbits = locbits;
4516:
4517: sendpacket(connecthead,tempbuf,j);
4518: }
4519: }
4520: }
4521:
4522: getpackets()
4523: {
4524: long i, j, k, l;
4525: short other, tempbufleng;
4526:
4527: if (option[4] == 0) return;
4528:
4529: while ((tempbufleng = getpacket(&other,tempbuf)) > 0)
4530: {
4531: switch(tempbuf[0])
4532: {
4533: case 0: //[0] (receive master sync buffer)
4534: j = ((numplayers+1)>>1)+1; k = (1<<3);
4535: for(i=connecthead;i>=0;i=connectpoint2[i])
4536: {
4537: l = (tempbuf[k>>3]>>(k&7));
4538: if (l&1) fsyncvel[i] = tempbuf[j++];
4539: if (l&2) fsyncsvel[i] = tempbuf[j++];
4540: if (l&4) fsyncangvel[i] = tempbuf[j++];
4541: if (l&8)
4542: {
4543: fsyncbits[i] = ((short)tempbuf[j])+(((short)tempbuf[j+1])<<8);
4544: j += 2;
4545: }
4546: k += 4;
4547: }
4548: while (j != tempbufleng)
4549: {
4550: othersyncval[othersyncvalend] = ((long)tempbuf[j]);
4551: othersyncval[othersyncvalend] += (((long)tempbuf[j+1])<<8);
4552: j += 2;
4553: othersyncvalend = ((othersyncvalend+1)&(MOVEFIFOSIZ-1));
4554: }
4555:
4556: i = 0;
4557: while (syncvalplc != syncvalend)
4558: {
4559: if (othersyncvalcnt > syncvalcnt)
4560: {
4561: if (i == 0) syncstat = 0, i = 1;
4562: syncstat |= (syncval[syncvalplc]^othersyncval[syncvalplc]);
4563: }
4564: syncvalplc = ((syncvalplc+1)&(MOVEFIFOSIZ-1));
4565: syncvalcnt++;
4566: }
4567: while (othersyncvalplc != othersyncvalend)
4568: {
4569: if (syncvalcnt > othersyncvalcnt)
4570: {
4571: if (i == 0) syncstat = 0, i = 1;
4572: syncstat |= (syncval[othersyncvalplc]^othersyncval[othersyncvalplc]);
4573: }
4574: othersyncvalplc = ((othersyncvalplc+1)&(MOVEFIFOSIZ-1));
4575: othersyncvalcnt++;
4576: }
4577:
4578: movethings(); //Move all players and sprites
4579: break;
4580: case 1: //[1] (receive slave sync buffer)
4581: j = 2; k = tempbuf[1];
4582: if (k&1) fsyncvel[other] = tempbuf[j++];
4583: if (k&2) fsyncsvel[other] = tempbuf[j++];
4584: if (k&4) fsyncangvel[other] = tempbuf[j++];
4585: if (k&8) fsyncbits[other] = ((fsyncbits[other]&0xff00)|((short)tempbuf[j++]));
4586: if (k&16) fsyncbits[other] = ((fsyncbits[other]&0x00ff)|(((short)tempbuf[j++])<<8));
4587: break;
4588: case 2:
4589: getmessageleng = tempbufleng-1;
4590: for(j=getmessageleng-1;j>=0;j--) getmessage[j] = tempbuf[j+1];
4591: getmessagetimeoff = totalclock+360+(getmessageleng<<4);
4592: break;
4593: case 3:
4594: wsay("getstuff.wav",4096L,63L,63L);
4595: break;
4596: case 5:
4597: playerreadyflag[other] = tempbuf[1];
4598: if ((other == connecthead) && (tempbuf[1] == 2))
4599: sendpacket(connecthead,tempbuf,2);
4600: break;
4601: case 255: //[255] (logout)
4602: keystatus[1] = 1;
4603: break;
4604: }
4605: }
4606: }
4607:
4608: drawoverheadmap(long cposx, long cposy, long czoom, short cang)
4609: {
4610: long i, j, k, l, x1, y1, x2, y2, x3, y3, x4, y4, ox, oy, xoff, yoff;
4611: long dax, day, cosang, sinang, xspan, yspan, sprx, spry;
4612: long xrepeat, yrepeat, z1, z2, startwall, endwall, tilenum, daang;
4613: long xvect, yvect, xvect2, yvect2;
4614: char col;
4615: walltype *wal, *wal2;
4616: spritetype *spr;
4617:
4618: xvect = sintable[(2048-cang)&2047] * czoom;
4619: yvect = sintable[(1536-cang)&2047] * czoom;
4620: xvect2 = mulscale(xvect,yxaspect,16);
4621: yvect2 = mulscale(yvect,yxaspect,16);
4622:
4623: //Draw red lines
4624: for(i=0;i<numsectors;i++)
4625: {
4626: startwall = sector[i].wallptr;
4627: endwall = sector[i].wallptr + sector[i].wallnum - 1;
4628:
4629: z1 = sector[i].ceilingz; z2 = sector[i].floorz;
4630:
4631: for(j=startwall,wal=&wall[startwall];j<=endwall;j++,wal++)
4632: {
4633: k = wal->nextwall; if (k < 0) continue;
4634:
4635: if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue;
4636: if ((k > j) && ((show2dwall[k>>3]&(1<<(k&7))) > 0)) continue;
4637:
4638: if (sector[wal->nextsector].ceilingz == z1)
4639: if (sector[wal->nextsector].floorz == z2)
4640: if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0) continue;
4641:
4642: col = 152;
4643:
4644: if (dimensionmode[screenpeek] == 2)
4645: {
4646: if (sector[i].floorz != sector[i].ceilingz)
4647: if (sector[wal->nextsector].floorz != sector[wal->nextsector].ceilingz)
4648: if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0)
4649: if (sector[i].floorz == sector[wal->nextsector].floorz) continue;
4650: if (sector[i].floorpicnum != sector[wal->nextsector].floorpicnum) continue;
4651: if (sector[i].floorshade != sector[wal->nextsector].floorshade) continue;
4652: col = 12;
4653: }
4654:
4655: ox = wal->x-cposx; oy = wal->y-cposy;
4656: x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4657: y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4658:
4659: wal2 = &wall[wal->point2];
4660: ox = wal2->x-cposx; oy = wal2->y-cposy;
4661: x2 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4662: y2 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4663:
4664: drawline256(x1+(xdim<<11),y1+(ydim<<11),x2+(xdim<<11),y2+(ydim<<11),col);
4665: }
4666: }
4667:
4668: //Draw sprites
4669: k = playersprite[screenpeek];
4670: for(i=0;i<numsectors;i++)
4671: for(j=headspritesect[i];j>=0;j=nextspritesect[j])
4672: if ((show2dsprite[j>>3]&(1<<(j&7))) > 0)
4673: {
4674: spr = &sprite[j];
4675: col = 56;
4676: if ((spr->cstat&1) > 0) col = 248;
4677: if (j == k) col = 31;
4678:
4679: sprx = spr->x;
4680: spry = spr->y;
4681:
4682: k = spr->statnum;
4683: if ((k >= 1) && (k <= 8) && (k != 2)) //Interpolate moving sprite
4684: {
4685: sprx = osprite[j].x+mulscale(sprx-osprite[j].x,smoothratio,16);
4686: spry = osprite[j].y+mulscale(spry-osprite[j].y,smoothratio,16);
4687: }
4688:
4689: switch (spr->cstat&48)
4690: {
4691: case 0:
4692: ox = sprx-cposx; oy = spry-cposy;
4693: x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4694: y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4695:
4696: if (dimensionmode[screenpeek] == 1)
4697: {
4698: ox = (sintable[(spr->ang+512)&2047]>>7);
4699: oy = (sintable[(spr->ang)&2047]>>7);
4700: x2 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4701: y2 = mulscale(oy,xvect,16) + mulscale(ox,yvect,16);
4702:
4703: if (j == playersprite[screenpeek])
4704: {
4705: x2 = 0L;
4706: y2 = -(czoom<<5);
4707: }
4708:
4709: x3 = mulscale(x2,yxaspect,16);
4710: y3 = mulscale(y2,yxaspect,16);
4711:
4712: drawline256(x1-x2+(xdim<<11),y1-y3+(ydim<<11),
4713: x1+x2+(xdim<<11),y1+y3+(ydim<<11),col);
4714: drawline256(x1-y2+(xdim<<11),y1+x3+(ydim<<11),
4715: x1+x2+(xdim<<11),y1+y3+(ydim<<11),col);
4716: drawline256(x1+y2+(xdim<<11),y1-x3+(ydim<<11),
4717: x1+x2+(xdim<<11),y1+y3+(ydim<<11),col);
4718: }
4719: else
4720: {
4721: if (((gotsector[i>>3]&(1<<(i&7))) > 0) && (czoom > 192))
4722: {
4723: daang = (spr->ang-cang)&2047;
4724: if (j == playersprite[screenpeek])
4725: { x1 = 0; y1 = (yxaspect<<2); daang = 0; }
4726: rotatesprite((x1<<4)+(xdim<<15),(y1<<4)+(ydim<<15),mulscale(czoom*spr->yrepeat,yxaspect,16),daang,spr->picnum,spr->shade,spr->pal,(spr->cstat&2)>>1);
4727: }
4728: }
4729: break;
4730: case 16:
4731: x1 = sprx; y1 = spry;
4732: tilenum = spr->picnum;
4733: xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset);
4734: if ((spr->cstat&4) > 0) xoff = -xoff;
4735: k = spr->ang; l = spr->xrepeat;
4736: dax = sintable[k&2047]*l; day = sintable[(k+1536)&2047]*l;
4737: l = tilesizx[tilenum]; k = (l>>1)+xoff;
4738: x1 -= mulscale(dax,k,16); x2 = x1+mulscale(dax,l,16);
4739: y1 -= mulscale(day,k,16); y2 = y1+mulscale(day,l,16);
4740:
4741: ox = x1-cposx; oy = y1-cposy;
4742: x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4743: y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4744:
4745: ox = x2-cposx; oy = y2-cposy;
4746: x2 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4747: y2 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4748:
4749: drawline256(x1+(xdim<<11),y1+(ydim<<11),
4750: x2+(xdim<<11),y2+(ydim<<11),col);
4751:
4752: break;
4753: case 32:
4754: if (dimensionmode[screenpeek] == 1)
4755: {
4756: tilenum = spr->picnum;
4757: xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset);
4758: yoff = (long)((signed char)((picanm[tilenum]>>16)&255))+((long)spr->yoffset);
4759: if ((spr->cstat&4) > 0) xoff = -xoff;
4760: if ((spr->cstat&8) > 0) yoff = -yoff;
4761:
4762: k = spr->ang;
4763: cosang = sintable[(k+512)&2047]; sinang = sintable[k];
4764: xspan = tilesizx[tilenum]; xrepeat = spr->xrepeat;
4765: yspan = tilesizy[tilenum]; yrepeat = spr->yrepeat;
4766:
4767: dax = ((xspan>>1)+xoff)*xrepeat; day = ((yspan>>1)+yoff)*yrepeat;
4768: x1 = sprx + mulscale(sinang,dax,16) + mulscale(cosang,day,16);
4769: y1 = spry + mulscale(sinang,day,16) - mulscale(cosang,dax,16);
4770: l = xspan*xrepeat;
4771: x2 = x1 - mulscale(sinang,l,16);
4772: y2 = y1 + mulscale(cosang,l,16);
4773: l = yspan*yrepeat;
4774: k = -mulscale(cosang,l,16); x3 = x2+k; x4 = x1+k;
4775: k = -mulscale(sinang,l,16); y3 = y2+k; y4 = y1+k;
4776:
4777: ox = x1-cposx; oy = y1-cposy;
4778: x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4779: y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4780:
4781: ox = x2-cposx; oy = y2-cposy;
4782: x2 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4783: y2 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4784:
4785: ox = x3-cposx; oy = y3-cposy;
4786: x3 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4787: y3 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4788:
4789: ox = x4-cposx; oy = y4-cposy;
4790: x4 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4791: y4 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4792:
4793: drawline256(x1+(xdim<<11),y1+(ydim<<11),
4794: x2+(xdim<<11),y2+(ydim<<11),col);
4795:
4796: drawline256(x2+(xdim<<11),y2+(ydim<<11),
4797: x3+(xdim<<11),y3+(ydim<<11),col);
4798:
4799: drawline256(x3+(xdim<<11),y3+(ydim<<11),
4800: x4+(xdim<<11),y4+(ydim<<11),col);
4801:
4802: drawline256(x4+(xdim<<11),y4+(ydim<<11),
4803: x1+(xdim<<11),y1+(ydim<<11),col);
4804:
4805: }
4806: break;
4807: }
4808: }
4809:
4810: //Draw white lines
4811: for(i=0;i<numsectors;i++)
4812: {
4813: startwall = sector[i].wallptr;
4814: endwall = sector[i].wallptr + sector[i].wallnum - 1;
4815:
4816: for(j=startwall,wal=&wall[startwall];j<=endwall;j++,wal++)
4817: {
4818: if (wal->nextwall >= 0) continue;
4819:
4820: if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue;
4821:
4822: if (tilesizx[wal->picnum] == 0) continue;
4823: if (tilesizy[wal->picnum] == 0) continue;
4824:
4825: ox = wal->x-cposx; oy = wal->y-cposy;
4826: x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4827: y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4828:
4829: wal2 = &wall[wal->point2];
4830: ox = wal2->x-cposx; oy = wal2->y-cposy;
4831: x2 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
4832: y2 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
4833:
4834: drawline256(x1+(xdim<<11),y1+(ydim<<11),x2+(xdim<<11),y2+(ydim<<11),24);
4835: }
4836: }
4837: }
4838:
4839: //New movesprite using getzrange. Note that I made the getzrange
4840: //parameters global (&globhiz,&globhihit,&globloz,&globlohit) so they
4841: //don't need to be passed everywhere. Also this should make this
4842: //movesprite function compatible with the older movesprite functions.
4843: movesprite(short spritenum, long dx, long dy, long dz, long ceildist, long flordist, char cliptype)
4844: {
4845: long daz, zoffs, templong;
4846: short retval, dasectnum, tempshort;
4847: spritetype *spr;
4848:
4849: spr = &sprite[spritenum];
4850:
4851: if ((spr->cstat&128) == 0)
4852: zoffs = -((tilesizy[spr->picnum]*spr->yrepeat)<<1);
4853: else
4854: zoffs = 0;
4855:
4856: dasectnum = spr->sectnum; //Can't modify sprite sectors directly becuase of linked lists
4857: daz = spr->z+zoffs; //Must do this if not using the new centered centering (of course)
4858: retval = clipmove(&spr->x,&spr->y,&daz,&dasectnum,dx,dy,
4859: ((long)spr->clipdist)<<2,ceildist,flordist,cliptype);
4860:
4861: if ((dasectnum != spr->sectnum) && (dasectnum >= 0))
4862: changespritesect(spritenum,dasectnum);
4863:
4864: //Set the blocking bit to 0 temporarly so getzrange doesn't pick up
4865: //its own sprite
4866: tempshort = spr->cstat; spr->cstat &= ~1;
4867: getzrange(spr->x,spr->y,spr->z-1,spr->sectnum,
4868: &globhiz,&globhihit,&globloz,&globlohit,
4869: ((long)spr->clipdist)<<2,cliptype);
4870: spr->cstat = tempshort;
4871:
4872: daz = spr->z+zoffs + dz;
4873: if ((daz <= globhiz) || (daz > globloz))
4874: {
4875: if (retval != 0) return(retval);
4876: return(16384+dasectnum);
4877: }
4878: spr->z = daz-zoffs;
4879: return(retval);
4880: }
4881:
4882: waitforeverybody()
4883: {
4884: long i, j, oldtotalclock;
4885:
4886: if (numplayers < 2) return;
4887:
4888: if (myconnectindex == connecthead)
4889: {
4890: for(j=1;j<=2;j++)
4891: {
4892: for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
4893: playerreadyflag[i] = 0;
4894: oldtotalclock = totalclock-8;
4895: do
4896: {
4897: getpackets();
4898: if (totalclock >= oldtotalclock+8)
4899: {
4900: oldtotalclock = totalclock;
4901: tempbuf[0] = 5;
4902: tempbuf[1] = j;
4903: for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
4904: if (playerreadyflag[i] != j) sendpacket(i,tempbuf,2);
4905: }
4906: for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
4907: if (playerreadyflag[i] != j) break;
4908: } while (i >= 0);
4909: }
4910: }
4911: else
4912: {
4913: playerreadyflag[connecthead] = 0;
4914: while (playerreadyflag[connecthead] != 2)
4915: {
4916: getpackets();
4917: if (playerreadyflag[connecthead] == 1)
4918: {
4919: playerreadyflag[connecthead] = 0;
4920: sendpacket(connecthead,tempbuf,2);
4921: }
4922: }
4923: }
4924: }
4925:
4926: getsyncstat()
4927: {
4928: long i, j;
4929: unsigned short crc;
4930: spritetype *spr;
4931:
4932: crc = 0;
4933: updatecrc16(crc,randomseed); updatecrc16(crc,randomseed>>8);
4934: for(i=connecthead;i>=0;i=connectpoint2[i])
4935: {
4936: updatecrc16(crc,posx[i]); //if (syncstat != 0) printf("%ld ",posx[i]);
4937: updatecrc16(crc,posy[i]); //if (syncstat != 0) printf("%ld ",posy[i]);
4938: updatecrc16(crc,posz[i]); //if (syncstat != 0) printf("%ld ",posz[i]);
4939: updatecrc16(crc,ang[i]); //if (syncstat != 0) printf("%ld ",ang[i]);
4940: updatecrc16(crc,horiz[i]); //if (syncstat != 0) printf("%ld ",horiz[i]);
4941: updatecrc16(crc,health[i]); //if (syncstat != 0) printf("%ld ",health[i]);
4942: }
4943:
4944: for(i=7;i>=0;i--)
4945: for(j=headspritestat[i];j>=0;j=nextspritestat[j])
4946: {
4947: spr = &sprite[j];
4948: updatecrc16(crc,spr->x); //if (syncstat != 0) printf("%ld ",spr->x);
4949: updatecrc16(crc,spr->y); //if (syncstat != 0) printf("%ld ",spr->y);
4950: updatecrc16(crc,spr->z); //if (syncstat != 0) printf("%ld ",spr->z);
4951: updatecrc16(crc,spr->ang); //if (syncstat != 0) printf("%ld ",spr->ang);
4952: }
4953: //if (syncstat != 0) printf("\n");
4954: return(crc);
4955: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.