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