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(&sector[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(&sector[dasector].ceilingz,daz,6L,6L)) >= 0)
791                 wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,&centx,&centy,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(&sector[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(&sector[dasector].floorz,daz,6L,6L)) >= 0)
823                 wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,&centx,&centy,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,&centx,&centy,0);
888         wsayfollow("updowndr.wav",4096L+256L,256L,&centx,&centy,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,&centx,&centy,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,&centx,&centy,0);
984         wsayfollow("updowndr.wav",4096L+64L,256L,&centx,&centy,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(&sector[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(&parallaxvisibility,4,1,fil);
5467     kdfread(&parallaxtype,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(&parallaxvisibility,4,1,fil);
5650     dfwrite(&parallaxtype,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