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