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