1 #include "build.h"
2 #include "names.h"
3 #include "pragmas.h"
4 #include "cache1d.h"
5 #include "baselayer.h"
6 #include "renderlayer.h"
7 #include "common.h"
8 #include "mmulti.h"
9 #include "keyboard.h"
10 #include "control.h"
11 #include "config.h"
12 #include "tekwar.h"
13 #include "tekver.cpp"
14 #include "grpscan.h"
15 #include "osdcmds.h"
16 #include "common_game.h"
17 
18 #ifdef _WIN32
19 # include "winbits.h"
20 #endif /* _WIN32 */
21 
22 #ifdef __cplusplus
23 extern "C" {
24     #endif
25     extern const char* s_buildRev;
26     extern const char* s_buildTimestamp;
27     #ifdef __cplusplus
28 }
29 #endif
30 
31 const char* AppProperName = APPNAME;
32 const char* AppTechnicalName = APPBASENAME;
33 
34 static char g_rootDir[BMAX_PATH];
35 
36 int mouseaiming, aimmode, mouseflip;
37 int runkey_mode, auto_run;
38 
39 
40 #if defined GEKKO
41 # define FPS_YOFFSET 16
42 #else
43 # define FPS_YOFFSET 0
44 #endif
45 
46 void shutdown();
47 
M32RunScript(const char * s)48 void M32RunScript(const char* s) { UNREFERENCED_PARAMETER(s); }
app_crashhandler(void)49 void app_crashhandler(void)
50 {
51     shutdown();
52 }
53 
54 
55 #define   SECT_LOTAG_CLIMB                    5060
56 
57 #ifdef    TEKWAR
58 FILE      *dbgfp;
59 int       dbgfilen;
60 char      dbgfname[16];
61 int       dbgflag;
62 int       dbgcolumn;
63 short     mousebias=1;
64 short     biasthreshhold=72;
65 char      biasthreshholdon=0;
66 short     lastmousy;
67 char      keyedhorizon;
68 //** Les START - 09/26/95
69 char      jstickenabled=0;
70 int       jlowx,jlowy,
71           jhighx,jhighy;
72 char      oldjoyb;
73 //** Les  END  - 09/26/95
74 short     yaw,pitch,roll,vrangle,vrpitch;
75 
76 #endif
77 
78 int vel, svel, angvel;
79 int vel2, svel2, angvel2;
80 
81 int recording = -2;
82 
83 #ifdef    TEKWAR
84 int xdimgame = 640, ydimgame = 480, bppgame = 8;
85 int forcesetup = 1;
86 
87 #define   MAXMOREOPTIONS      21
88 #define   MAXTOGGLES          16
89 #define   MAXGAMESTUFF        16
90 unsigned char option[NUMOPTIONS] = {
91       1,       // 0  VIDEO MODE CHAINED OR NO
92       0,       // 1  SOUND CHOICE
93       0,       // 2  MUSIC CHOICE
94       1,       // 3  MOUSE ON/OFF
95       0,       // 4  MULTIPLAYER COUNT
96       0,       // 5  MULTIPLYER SETTING
97       2,       // 6  VIDEO RES CHOICE
98       0        // 7  SOUND FREQ
99 };
100 unsigned char keys[NUMGAMEKEYS] = {
101      200,         // 0  FWD
102      208,         // 1  BKWD
103      203,         // 2  RIGHT
104      205,         // 3  LEFT
105       42,         // 4  RUN / AMPLIFY
106       56,         // 5  STRAFE
107       29,         // 6  SHOOT
108       57,         // 7  USE
109       45,         // 8  JUMP
110       46,         // 9  CROUCH
111      201,         // 10 LOOK UP
112      209,         // 11 LOOK DOWN
113       51,         // 12 SLIDE LEFT
114       52,         // 13 SLIDE RIGHT
115       15,         // 14 MAP MODE
116      156,         // 15 SWITCH PLAYER
117       13,         // 16 EXPAND VIEW
118       12,         // 17 SHRINK VIEW
119       50,         // 18 MESSAGE MODE
120      199,         // 19 AUTOCENTER
121       19,         // 20 TOGGLE REARVIEW
122       18,         // 21 TOGGLE PREPARED ITEM
123       35,         // 22 TOGGLE HEALTH METER
124       34,         // 23 TOGGLE CROSSHAIRS
125       20,         // 24 TOGGLE ELAPSED TIME
126       31,         // 25 TOGGLE SCORE
127       23,         // 26 TOGGLE INVENTORY
128       53,         // 27 CONCEAL WEAPON
129       58,         // 28 MOUSE LOOKUP/DOWN
130       26,         // 29 N/U
131       26,         // 30 N/U
132       26          // 31 N/U
133 };
134 unsigned char moreoptions[MAXMOREOPTIONS] = {
135         1,     // 0  MOUSE ON/OFF
136        29,     // 1  MOUSE BUTTON 1 MAP
137       200,     // 2  MOUSE BUTTON 2 MAP
138         0,     // 3  JOYSTICK ON/OFF
139         4,     // 4  JOYSTICK BUTTON 1 MAP
140         6,     // 5  JOYSTICK BUTTON 2 MAP
141        10,     // 6  JOYSTICK BUTTON 3 MAP
142        11,     // 7  JOYSTICK BUTTON 4 MAP
143         1,     // 8  DIFFICULTY LEVEL
144        16,     // 9  SOUND VOLUME
145        16,     // 10 MUSIC VOLUME
146         8,     // 11 MOUSE SENSITIVITY
147         1,     // 12 HEAD BOB
148         0,     // 13 N/U
149         0,     // 14 N/U
150         0      // 15 N/U
151 };
152 char toggles[MAXTOGGLES] = { 1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0 };
153 int  gamestuff[MAXGAMESTUFF] = {
154      -1,       // 0  joyxcenter
155      -1,       // 1  joyycenter
156       0,       // 2  screensize
157       0,       // 3  brightness
158     100,       // 4  biasthreshhold
159       0,       // 5  warpretang
160       0,       // 6  warpretsect
161       0,       // 7
162       0,       // 8
163       0,       // 9
164       0,       // 10
165       0,       // 11
166       0,       // 12
167       0,       // 13
168       0,       // 14
169       0        // 15
170 };
171 #endif
172 
173 char frame2draw[MAXPLAYERS];
174 int frameskipcnt[MAXPLAYERS];
175 
176 char gundmost[320];
177 
178      //Shared player variables
179 int posx[MAXPLAYERS], posy[MAXPLAYERS], posz[MAXPLAYERS];
180 int horiz[MAXPLAYERS], zoom[MAXPLAYERS], hvel[MAXPLAYERS];
181 short ang[MAXPLAYERS], cursectnum[MAXPLAYERS], ocursectnum[MAXPLAYERS];
182 short playersprite[MAXPLAYERS], deaths[MAXPLAYERS];
183 int lastchaingun[MAXPLAYERS];
184 int health[MAXPLAYERS], score[MAXPLAYERS], saywatchit[MAXPLAYERS];
185 short numbombs[MAXPLAYERS], oflags[MAXPLAYERS];
186 char dimensionmode[MAXPLAYERS];
187 char revolvedoorstat[MAXPLAYERS];
188 short revolvedoorang[MAXPLAYERS], revolvedoorrotang[MAXPLAYERS];
189 int revolvedoorx[MAXPLAYERS], revolvedoory[MAXPLAYERS];
190 
191      //Local multiplayer variables
192 int locselectedgun;
193 signed char locvel, olocvel;
194 short locsvel, olocsvel;                          // Les 09/27/95
195 short locangvel, olocangvel;                      // Les 09/27/95
196 short locbits, olocbits;
197 
198      //Local multiplayer variables for second player
199 int locselectedgun2;
200 signed char locvel2, olocvel2;
201 short locsvel2, olocsvel2;                        // Les 09/27/95
202 short locangvel2, olocangvel2;                    // Les 09/27/95
203 short locbits2, olocbits2;
204 
205   //Multiplayer syncing variables
206 signed char fsyncvel[MAXPLAYERS], osyncvel[MAXPLAYERS], syncvel[MAXPLAYERS];
207 short fsyncsvel[MAXPLAYERS], osyncsvel[MAXPLAYERS], syncsvel[MAXPLAYERS];       // Les 09/27/95
208 short fsyncangvel[MAXPLAYERS], osyncangvel[MAXPLAYERS], syncangvel[MAXPLAYERS]; // Les 09/27/95
209 unsigned short fsyncbits[MAXPLAYERS], osyncbits[MAXPLAYERS], syncbits[MAXPLAYERS];
210 
211 char frameinterpolate = 1, detailmode = 0, ready2send = 0;
212 int ototalclock = 0, gotlastpacketclock = 0, smoothratio;
213 int oposx[MAXPLAYERS], oposy[MAXPLAYERS], oposz[MAXPLAYERS];
214 int ohoriz[MAXPLAYERS], ozoom[MAXPLAYERS];
215 short oang[MAXPLAYERS];
216 
217 point3d osprite[MAXSPRITESONSCREEN];
218 
219 int movefifoplc, movefifoend;
220 signed char baksyncvel[MOVEFIFOSIZ][MAXPLAYERS];
221 short baksyncsvel[MOVEFIFOSIZ][MAXPLAYERS];       // Les 09/27/95
222 short baksyncangvel[MOVEFIFOSIZ][MAXPLAYERS];     // Les 09/27/95
223 short baksyncbits[MOVEFIFOSIZ][MAXPLAYERS];
224 
225      //GAME.C sync state variables
226 short syncstat = 0;
227 int syncvalplc, othersyncvalplc;
228 int syncvalend, othersyncvalend;
229 int syncvalcnt, othersyncvalcnt;
230 short syncval[MOVEFIFOSIZ], othersyncval[MOVEFIFOSIZ];
231 
232 extern int crctable[256];
233 char playerreadyflag[MAXPLAYERS];
234 
235      //Game recording variables
236 int reccnt, recstat = 1;
237 signed char recsyncvel[16384][2];
238 short recsyncsvel[16384][2];                      // Les 09/27/95
239 short recsyncangvel[16384][2];                    // Les 09/27/95
240 short recsyncbits[16384][2];
241 
242      //Miscellaneous variables
243 char tempbuf[256];
244 uint8_t packetbuf[MAXXDIM];
245 char boardfilename[80];
246 short screenpeek = 0, oldmousebstatus = 0, brightness = 0;
247 short screensize, screensizeflag = 0;
248 short neartagsector, neartagwall, neartagsprite;
249 int lockclock, neartagdist, neartaghitdist;
250 int masterslavetexttime;
251 int globhiz, globloz, globhihit, globlohit;
252 
253      //Board animation variables
254 short rotatespritelist[16], rotatespritecnt;
255 short warpsectorlist[64], warpsectorcnt;
256 short xpanningsectorlist[16], xpanningsectorcnt;
257 short ypanningwalllist[64], ypanningwallcnt;
258 short floorpanninglist[64], floorpanningcnt;
259 short dragsectorlist[16], dragxdir[16], dragydir[16], dragsectorcnt;
260 int dragx1[16], dragy1[16], dragx2[16], dragy2[16], dragfloorz[16];
261 short swingcnt, swingwall[32][5], swingsector[32];
262 short swingangopen[32], swingangclosed[32], swingangopendir[32];
263 short swingang[32], swinganginc[32];
264 int swingx[32][8], swingy[32][8];
265 short revolvesector[4], revolveang[4], revolvecnt;
266 int revolvex[4][16], revolvey[4][16];
267 int revolvepivotx[4], revolvepivoty[4];
268 short subwaytracksector[4][128], subwaynumsectors[4], subwaytrackcnt;
269 int subwaystop[4][8], subwaystopcnt[4];
270 int subwaytrackx1[4], subwaytracky1[4];
271 int subwaytrackx2[4], subwaytracky2[4];
272 int subwayx[4], subwaygoalstop[4], subwayvel[4], subwaypausetime[4];
273 short waterfountainwall[MAXPLAYERS], waterfountaincnt[MAXPLAYERS];
274 short slimesoundcnt[MAXPLAYERS];
275 
276      //Variables that let you type messages to other player
277 char getmessage[162], getmessageleng;
278 int getmessagetimeoff;
279 char typemessage[162];
280 int typemessageleng = 0, typemode = 0;
281 char scantoasc[128] =
282 {
283      0,0,'1','2','3','4','5','6','7','8','9','0','-','=',0,0,
284      'q','w','e','r','t','y','u','i','o','p','[',']',0,0,'a','s',
285      'd','f','g','h','j','k','l',';',39,'`',0,92,'z','x','c','v',
286      'b','n','m',',','.','/',0,'*',0,32,0,0,0,0,0,0,
287      0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
288      '2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
289      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
290      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
291 };
292 char scantoascwithshift[128] =
293 {
294      0,0,'!','@','#','$','%','^','&','*','(',')','_','+',0,0,
295      'Q','W','E','R','T','Y','U','I','O','P','{','}',0,0,'A','S',
296      'D','F','G','H','J','K','L',':',34,'~',0,'|','Z','X','C','V',
297      'B','N','M','<','>','?',0,'*',0,32,0,0,0,0,0,0,
298      0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
299      '2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
300      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
301      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
302 };
303 
304      //These variables are for animating x, y, or z-coordinates of sectors,
305      //walls, or sprites (They are NOT to be used for changing the [].picnum's)
306      //See the setanimation(), and getanimategoal() functions for more details.
307 int *animateptr[MAXANIMATES], animategoal[MAXANIMATES];
308 int animatevel[MAXANIMATES], animateacc[MAXANIMATES], animatecnt = 0;
309 
310 int32_t g_commandSetup = 0;
311 int32_t g_noSetup = 0;
312 int32_t g_noAutoLoad = 0;
313 
314 //////////
315 
316 enum gametokens
317 {
318     T_INCLUDE = 0,
319     T_INTERFACE = 0,
320     T_LOADGRP = 1,
321     T_MODE = 1,
322     T_CACHESIZE = 2,
323     T_ALLOW = 2,
324     T_NOAUTOLOAD,
325     T_INCLUDEDEFAULT,
326     T_MUSIC,
327     T_SOUND,
328     T_FILE,
329     T_CUTSCENE,
330     T_ANIMSOUNDS,
331     T_NOFLOORPALRANGE,
332     T_ID,
333     T_MINPITCH,
334     T_MAXPITCH,
335     T_PRIORITY,
336     T_TYPE,
337     T_DISTANCE,
338     T_VOLUME,
339     T_DELAY,
340     T_RENAMEFILE,
341     T_GLOBALGAMEFLAGS,
342     T_ASPECT,
343     T_FORCEFILTER,
344     T_FORCENOFILTER,
345     T_TEXTUREFILTER,
346     T_NEWGAMECHOICES,
347     T_CHOICE,
348     T_NAME,
349     T_LOCKED,
350     T_HIDDEN,
351     T_USERCONTENT,
352 };
353 
354 int tekwar_globalflags;
355 
356 static int parsedefinitions_game(scriptfile*, int);
357 
parsedefinitions_game_include(const char * fileName,scriptfile * pScript,const char * cmdtokptr,int const firstPass)358 static void parsedefinitions_game_include(const char* fileName, scriptfile* pScript, const char* cmdtokptr, int const firstPass)
359 {
360     scriptfile* included = scriptfile_fromfile(fileName);
361 
362     if (!included)
363     {
364         if (!Bstrcasecmp(cmdtokptr, "null") || pScript == NULL) // this is a bit overboard to prevent unused parameter warnings
365         {
366             // initprintf("Warning: Failed including %s as module\n", fn);
367         }
368         /*
369                 else
370                     {
371                     initprintf("Warning: Failed including %s on line %s:%d\n",
372                                fn, script->filename,scriptfile_getlinum(script,cmdtokptr));
373                     }
374         */
375     }
376     else
377     {
378         parsedefinitions_game(included, firstPass);
379         scriptfile_close(included);
380     }
381 }
382 
parsedefinitions_game(scriptfile * pScript,int firstPass)383 static int parsedefinitions_game(scriptfile* pScript, int firstPass)
384 {
385     int   token;
386     char* pToken;
387 
388     static const tokenlist tokens[] =
389     {
390         { "include",         T_INCLUDE          },
391         { "#include",        T_INCLUDE          },
392         { "includedefault",  T_INCLUDEDEFAULT   },
393         { "#includedefault", T_INCLUDEDEFAULT   },
394         { "loadgrp",         T_LOADGRP          },
395         { "cachesize",       T_CACHESIZE        },
396         { "noautoload",      T_NOAUTOLOAD       },
397         { "renamefile",      T_RENAMEFILE       },
398         { "globalgameflags", T_GLOBALGAMEFLAGS  },
399     };
400 
401     do
402     {
403         token = getatoken(pScript, tokens, ARRAY_SIZE(tokens));
404         pToken = pScript->ltextptr;
405 
406         switch (token)
407         {
408             case T_LOADGRP:
409             {
410                 char* fileName;
411 
412                 pathsearchmode = 1;
413                 if (!scriptfile_getstring(pScript, &fileName) && firstPass)
414                 {
415                     if (initgroupfile(fileName) == -1)
416                         initprintf("Could not find file \"%s\".\n", fileName);
417                     else
418                     {
419                         initprintf("Using file \"%s\" as game data.\n", fileName);
420                         if (!g_noAutoLoad && !gSetup.noautoload)
421                             G_DoAutoload(fileName);
422                     }
423                 }
424 
425                 pathsearchmode = 0;
426             }
427             break;
428             case T_CACHESIZE:
429             {
430                 int32_t cacheSize;
431 
432                 if (scriptfile_getnumber(pScript, &cacheSize) || !firstPass)
433                     break;
434 
435                 if (cacheSize > 0)
436                     MAXCACHE1DSIZE = cacheSize << 10;
437             }
438             break;
439             case T_INCLUDE:
440             {
441                 char* fileName;
442 
443                 if (!scriptfile_getstring(pScript, &fileName))
444                     parsedefinitions_game_include(fileName, pScript, pToken, firstPass);
445 
446                 break;
447             }
448             case T_INCLUDEDEFAULT:
449             {
450                 parsedefinitions_game_include(G_DefaultDefFile(), pScript, pToken, firstPass);
451                 break;
452             }
453             case T_NOAUTOLOAD:
454             if (firstPass)
455                 g_noAutoLoad = 1;
456             break;
457             case T_GLOBALGAMEFLAGS: scriptfile_getnumber(pScript, &tekwar_globalflags); break;
458             case T_EOF: return 0;
459             default: break;
460         }
461     } while (1);
462 
463     return 0;
464 }
465 
loaddefinitions_game(const char * fileName,int32_t firstPass)466 int loaddefinitions_game(const char* fileName, int32_t firstPass)
467 {
468     scriptfile* pScript = scriptfile_fromfile(fileName);
469 
470     if (pScript)
471         parsedefinitions_game(pScript, firstPass);
472 
473     for (char const* m : g_defModules)
474         parsedefinitions_game_include(m, NULL, "null", firstPass);
475 
476     if (pScript)
477         scriptfile_close(pScript);
478 
479     scriptfile_clearsymbols();
480 
481     return 0;
482 }
483 
484 #define FPS_COLOR(x) ((x) ? COLOR_RED : COLOR_WHITE)
485 
486 #define COLOR_RED redcol
487 #define COLOR_WHITE whitecol
488 
489 #define LOW_FPS ((videoGetRenderMode() == REND_CLASSIC) ? 35 : 50)
490 #define SLOW_FRAME_TIME 20
491 
G_PrintFPS(void)492 static void G_PrintFPS(void)
493 {
494     static char tempbuf[256];
495     static int32_t frameCount;
496     static double cumulativeFrameDelay;
497     static double lastFrameTime;
498     static float lastFPS; // , minFPS = std::numeric_limits<float>::max(), maxFPS;
499     //static double minGameUpdate = std::numeric_limits<double>::max(), maxGameUpdate;
500 
501     double frameTime = timerGetHiTicks();
502     double frameDelay = frameTime - lastFrameTime;
503     cumulativeFrameDelay += frameDelay;
504 
505     if (frameDelay >= 0)
506     {
507         int32_t x = (xdim <= 640);
508 
509         if (r_showfps)
510         {
511             int32_t chars = Bsprintf(tempbuf, "%.1f ms, %5.1f fps", frameDelay, lastFPS);
512 
513             printext256(windowxy2.x - (chars << (3 - x)) + 1, windowxy1.y + 2 + FPS_YOFFSET, blackcol, -1, tempbuf, x);
514             printext256(windowxy2.x - (chars << (3 - x)), windowxy1.y + 1 + FPS_YOFFSET,
515                 FPS_COLOR(lastFPS < LOW_FPS), -1, tempbuf, x);
516         }
517 
518         if (cumulativeFrameDelay >= 1000.0)
519         {
520             lastFPS = 1000.f * frameCount / cumulativeFrameDelay;
521             // g_frameRate = Blrintf(lastFPS);
522             frameCount = 0;
523             cumulativeFrameDelay = 0.0;
524         }
525         frameCount++;
526     }
527     lastFrameTime = frameTime;
528 }
529 
530 void shutdown();
531 
debugout(short p)532 void debugout(short p)
533 {
534      static int dbglines;
535 
536      if (dbgcolumn != 0) {
537           fprintf(dbgfp,"\n");
538      }
539      fprintf(dbgfp,"%2d %6d %3d %04X %04d %06d %06d %06d %06d %d\n",
540                     p,lockclock,movefifoplc,syncbits[p],ang[p],posx[p],posy[p],posz[p],
541                     health[p],randomseed);
542      dbglines++;
543      dbgcolumn=0;
544      if (dbglines > 2000) {
545           dbglines=0;
546           fclose(dbgfp);
547           sprintf(dbgfname,"DEBUG.%03d",dbgfilen++);
548           dbgfp=fopen(dbgfname,"wt");
549           fprintf(dbgfp," P  CLOCK PLC BITS  ANG   X     Y     Z   HEALTH RSEED\n");
550           fprintf(dbgfp,"== ====== === ==== ==== ===== ===== ===== ====== =========\n");
551      }
552 }
553 
554 
555 char localname[MAXNAMESIZE];
556 char netnames[MAXPLAYERS][MAXNAMESIZE];
557 
558 extern int startwin_run(void);
559 
InstallEngine()560 void InstallEngine()
561 {
562     lm("initgroupfile");
563     // initgroupfile("stuff.dat");
564 
565     char* cwd;
566 
567     if (g_modDir[0] != '/' && (cwd = buildvfs_getcwd(NULL, 0)))
568     {
569         buildvfs_chdir(g_modDir);
570         if (artLoadFiles("tiles%03i.art", MAXCACHE1DSIZE) < 0)
571         {
572             buildvfs_chdir(cwd);
573             if (artLoadFiles("tiles%03i.art", MAXCACHE1DSIZE) < 0)
574                 crash("Failed loading art.");
575         }
576         buildvfs_chdir(cwd);
577         #ifndef __ANDROID__ //This crashes on *some* Android devices. Small onetime memory leak. TODO fix above function
578         Xfree(cwd);
579         #endif
580     }
581     else if (artLoadFiles("tiles%03i.art", MAXCACHE1DSIZE) < 0)
582         crash("Failed loading art.");
583 
584     if (engineInit())
585     {
586         wm_msgbox("Fatal Engine Initialization Error",
587             "There was a problem initializing the engine: %s\n\nThe application will now close.", engineerrstr);
588         //TODO:
589         //G_Cleanup();
590         ERRprintf("G_Startup: There was a problem initializing the engine: %s\n", engineerrstr);
591         exit(6);
592     }
593     if (videoSetGameMode(gSetup.fullscreen, gSetup.xdim, gSetup.ydim, gSetup.bpp, 0) < 0)
594     {
595         initprintf("Failure setting video mode %dx%dx%d %s! Trying next mode...\n", gSetup.xdim, gSetup.ydim,
596             gSetup.bpp, gSetup.fullscreen?"fullscreen":"windowed");
597 
598         int resIdx = 0;
599 
600         for (int i = 0; i < validmodecnt; i++)
601         {
602             if (validmode[i].xdim == gSetup.xdim && validmode[i].ydim == gSetup.ydim)
603             {
604                 resIdx = i;
605                 break;
606             }
607         }
608 
609         int const savedIdx = resIdx;
610         int bpp = gSetup.bpp;
611 
612         while (videoSetGameMode(0, validmode[resIdx].xdim, validmode[resIdx].ydim, bpp, 0) < 0)
613         {
614             initprintf("Failure setting video mode %dx%dx%d windowed! Trying next mode...\n",
615                 validmode[resIdx].xdim, validmode[resIdx].ydim, bpp);
616 
617             if (++resIdx == validmodecnt)
618             {
619                 if (bpp == 8)
620                     crash("Fatal error: unable to set any video mode!");
621 
622                 resIdx = savedIdx;
623                 bpp = 8;
624             }
625         }
626 
627         gSetup.xdim = validmode[resIdx].xdim;
628         gSetup.ydim = validmode[resIdx].ydim;
629         gSetup.bpp = bpp;
630     }
631 
632     // build.obj is dated 9th July 1995
633     enginecompatibilitymode = ENGINE_19950829;
634 }
635 
shutdown()636 void shutdown()
637 {
638     CONFIG_WriteSetup(0);
639 
640 // TODO    SND_Shutdown();
641 
642     engineUnInit();
643 
644     uninitgroupfile();
645 
646     exit(EXIT_SUCCESS);
647 }
648 
app_main(int argc,char const * const argv[])649 int app_main(int argc, char const * const argv[])
650 {
651      int      i, waitplayers;
652      int     other;
653 
654      sprintf(tektempbuf, TITLE, VERS);
655      initputs(tektempbuf);
656      initputs("\n\n");
657 //     wm_setapptitle(tektempbuf);
658 
659 #ifdef _WIN32
660 #ifndef DEBUGGINGAIDS
661      if (!G_CheckCmdSwitch(argc, argv, "-noinstancechecking") && !windowsCheckAlreadyRunning())
662      {
663 #ifdef EDUKE32_STANDALONE
664          if (!wm_ynbox(APPNAME, "It looks like " APPNAME " is already running.\n\n"
665 #else
666          if (!wm_ynbox(APPNAME, "It looks like the game is already running.\n\n"
667 #endif
668              "Are you sure you want to start another copy?"))
669              return 3;
670      }
671 #endif
672 #endif
673 
674      tekargv(argc, argv);
675 
676      G_ExtPreInit(argc, argv);
677 
678      OSD_SetLogFile(APPBASENAME ".log");
679 
680      OSD_SetFunctions(NULL,
681          NULL,
682          NULL,
683          NULL,
684          NULL,
685          GAME_clearbackground,
686          BGetTime,
687          GAME_onshowosd);
688 
689      wm_setapptitle(APPNAME);
690 
691      initprintf("TekWar %s\n", s_buildRev);
692      PrintBuildInfo();
693 
694      // This needs to happen afterwards, as G_CheckCommandLine() is where we set
695      // up the command-line-provided search paths (duh).
696      G_ExtInit();
697 
698 #if defined(RENDERTYPEWIN) && defined(USE_OPENGL)
699      if (forcegl) initprintf("GL driver blacklist disabled.\n");
700 #endif
701 
702      // used with binds for fast function lookup
703      hash_init(&h_gamefuncs);
704      for (bssize_t i = kMaxGameFunctions - 1; i >= 0; i--)
705      {
706          if (gamefunctions[i][0] == '\0')
707              continue;
708 
709          hash_add(&h_gamefuncs, gamefunctions[i], i, 0);
710      }
711 
712 #ifdef STARTUP_SETUP_WINDOW
713      int const readSetup =
714 #endif
715      CONFIG_ReadSetup();
716 
717      if (enginePreInit()) {
718           wm_msgbox("Build Engine Initialisation Error",
719                "There was a problem initialising the Build engine: %s", engineerrstr);
720           exit(1);
721      }
722 
723      if (Bstrcmp(setupfilename, kSetupFilename))
724          initprintf("Using config file \"%s\".\n", setupfilename);
725 
726      G_ScanGroups();
727 
728 // REVERT     wm_msgbox("Pre-Release Software Warning", "%s is not ready for public use. Proceed with caution!", AppProperName);
729 
730 #ifdef STARTUP_SETUP_WINDOW
731      if (readSetup < 0 || (!g_noSetup && gSetup.forcesetup) || g_commandSetup)
732      {
733          if (quitevent || !startwin_run())
734          {
735              engineUnInit();
736              Bexit(0);
737          }
738      }
739 #endif
740 
741      G_LoadGroups(!g_noAutoLoad && !gSetup.noautoload);
742 
743      CONFIG_WriteSetup(1);
744      CONFIG_ReadSetup();
745 
746      Bsprintf(tempbuf, "TekWar %s", s_buildRev);
747      OSD_SetVersion(tempbuf, 10, 0);
748      OSD_SetParameters(0, 0, 0, 0, 0, 0, OSD_ERROR, OSDTEXT_RED, gamefunctions[gamefunc_Show_Console][0] == '\0'?OSD_PROTECTED:0);
749      registerosdcommands();
750 
751      lm("tekloadsetup");
752      tekloadsetup();
753 
754      SetupInput();
755 
756 /*
757      char* const setupFileName = Xstrdup(setupfilename);
758      char* const p = strtok(setupFileName, ".");
759 
760      if (!p || !Bstrcmp(setupfilename, kSetupFilename))
761          Bsprintf(tempbuf, "settings.cfg");
762      else
763          Bsprintf(tempbuf, "%s_settings.cfg", p);
764 
765      Xfree(setupFileName);
766 */
767      OSD_Exec("etekwar_cvars.cfg");
768      OSD_Exec("etekwar_autoexec.cfg");
769 
770      CONFIG_SetDefaultKeys(keydefaults, true);
771 
772      system_getcvars();
773 
774      InstallEngine();
775 
776      lm("inittimer");
777      timerInit(CLKIPS);
778 // TODO     timerSetCallback(timerhandler);
779      lm("tekinitmultiplayers");
780      tekinitmultiplayers(0, NULL);
781      lm("initsb");
782      initsb(option[1],option[2],0,0,0,0,0);
783      lm("tekpreinit");
784      tekpreinit();
785      lm("tekgamestarted");
786      tekgamestarted();
787      lm("initinput");
788      initinput();
789      lm("initmouse");
790 // TODO     if( option[3] != 0 ) initmouse();
791 
792      if (dbgflag) {
793           lm("debug mode: ON");
794           sprintf(dbgfname,"DEBUG.%03d",dbgfilen++);
795           dbgfp=fopen(dbgfname,"wt");
796           fprintf(dbgfp," P  CLOCK PLC BITS  ANG   X     Y     Z   HEALTH RSEED\n");
797           fprintf(dbgfp,"== ====== === ==== ==== ===== ===== ===== ====== =========\n");
798           dbgcolumn=0;
799      }
800 
801      const char* defsfile = G_DefFile();
802      uint32_t stime = timerGetTicks();
803      if (!loaddefinitionsfile(defsfile))
804      {
805          uint32_t etime = timerGetTicks();
806          initprintf("Definitions file \"%s\" loaded in %d ms.\n", defsfile, etime - stime);
807      }
808      loaddefinitions_game(defsfile, FALSE);
809 
810     if (enginePostInit())
811         shutdown();
812 
813     KB_Startup();
814     // TODO SND_Startup();
815 
816      if (option[4] > 0)
817      {
818          lm("multiplayer init");
819          teknetpickmap();
820          sendlogon();
821 
822          if (option[4] < 5) {
823              waitplayers = 2;
824          }
825          else {
826              waitplayers = option[4] - 3;
827          }
828 
829          while (numplayers < waitplayers)
830          {
831              videoClearViewableArea(0);
832              overwritesprite((xdim >> 1) - 160, 0, 408, 0, 0, 0);
833              sprintf(tempbuf, "  MULTIPLAYER MODE  ");
834              printext((xdim >> 1) - 80, (ydim >> 1) - 24, tempbuf, ALPHABET2, 0);
835              sprintf(tempbuf, "%2d OF %2d PLAYERS IN", numplayers, waitplayers);
836              printext((xdim >> 1) - 80, ydim >> 1, tempbuf, ALPHABET2, 0);
837              videoNextPage();
838              if (getpacket(&other, packetbuf) > 0)
839              {
840                  if (packetbuf[0] == 255) {
841                      keystatus[1] = 1;
842                  }
843              }
844              if (keystatus[1] > 0) {
845                  goto gameends;
846              }
847          }
848          screenpeek = myconnectindex;
849          videoClearViewableArea(0);
850      }
851      for (i = connecthead; i >= 0; i = connectpoint2[i]) {
852          initplayersprite((short)i);
853      }
854 
855      if (option[4] == 0) {
856          smkplayseq("INTRO");
857      }
858 
859 missionselection:
860      if (option[4] == 0)
861      {
862          if (choosemission() == 0) {
863              goto gameends;
864          }
865      }
866 
867      reccnt=0;
868      movefifoplc = 0; movefifoend = 0;
869      syncvalplc = 0; othersyncvalplc = 0;
870      syncvalend = 0; othersyncvalend = 0;
871      syncvalcnt = 0L; othersyncvalcnt = 0L;
872      olocvel = 0; olocvel2 = 0;
873      olocsvel = 0; olocsvel2 = 0;
874      olocangvel = 0; olocangvel2 = 0;
875      olocbits = 0; olocbits2 = 0;
876      lockclock = 0;
877      ototalclock = 0;
878      gotlastpacketclock = 0;
879      masterslavetexttime = 0;
880      for (i = 0; i < MAXPLAYERS; i++)
881      {
882          fsyncvel[i] = syncvel[i] = osyncvel[i] = 0;
883          fsyncsvel[i] = syncsvel[i] = osyncsvel[i] = 0;
884          fsyncangvel[i] = syncangvel[i] = osyncangvel[i] = 0;
885          fsyncbits[i] = syncbits[i] = osyncbits[i] = 0;
886      }
887      resettiming();
888 
889      ready2send = 1;
890 #ifdef NETNAMES
891      if (option[4] != 0)
892      {
893          packetbuf[0] = 8;
894          packetbuf[1] = myconnectindex;
895          memcpy(&packetbuf[2], localname, 10);
896          packetbuf[12] = 0;
897          for (i = connecthead; i >= 0; i = connectpoint2[i])
898          {
899              if (i != myconnectindex)
900              {
901                  sendpacket(i, packetbuf, 12);
902              }
903          }
904          memcpy(netnames[myconnectindex], localname, 10);
905          netnames[myconnectindex][10] = 0;
906      }
907 #endif
908      screenpeek=myconnectindex;
909      while (!gameover)
910      {
911          handleevents();
912          while (movefifoplc != movefifoend) {
913              domovethings();
914          }
915          drawscreen(screenpeek, (((int)totalclock) - gotlastpacketclock) * (65536 / TICSPERFRAME));
916      }
917      ready2send = 0;
918 
919      if (option[4] == 0)
920      {
921          debrief = 1;
922          goto missionselection;
923      }
924 
925 gameends:
926 
927      CONFIG_WriteSetup(0);
928 
929      copyrightscreen();
930 
931      sendlogoff();
932      uninitmultiplayers();
933      uninitsb();
934      cduninit();
935      //uninittimer();
936      uninitinput();
937      engineUnInit();
938      uninitgroupfile();
939 
940      teksavesetup();
941 
942      if (dbgflag) {
943          fclose(dbgfp);
944      }
945 
946      exit(0);
947 }
948 
949 void
processinput(short snum)950 processinput(short snum)
951 {
952      int      nexti;
953      int      i,j, doubvel, xvect, yvect, goalz;
954      int      dax, day;
955      char      *ptr;
956      vec3_t   pos;
957 
958      // move player snum
959      if (snum < 0 || snum >= MAXPLAYERS) {
960           crash("game712: Invalid player number (%d)",snum);
961      }
962 
963      if (cursectnum[snum] < 0 || cursectnum[snum] >= numsectors) {
964           crash("game718: Invalid sector for player %d @ %ld,%ld (%d)",snum,
965                posx[snum],posy[snum],cursectnum[snum]);
966      }
967 
968      if( (syncvel[snum]|syncsvel[snum]) != 0 ) {
969           // no run while crouching
970           if( ((syncbits[snum]&2) != 0) && (mission != 7) ) {
971                doubvel = 1+((syncbits[snum]&256) == 0);
972           }
973           else {
974                doubvel = (TICSPERFRAME<<((syncbits[snum]&256)>0));
975                doubvel<<=1;
976           }
977           xvect = 0, yvect = 0;
978           if( syncvel[snum] != 0 ) {
979                xvect += ((((int)syncvel[snum])*doubvel*(int)sintable[(ang[snum]+2560)&2047])>>3);
980                yvect += ((((int)syncvel[snum])*doubvel*(int)sintable[(ang[snum]+2048)&2047])>>3);
981           }
982           if( syncsvel[snum] != 0 ) {
983                xvect += ((((int)syncsvel[snum])*doubvel*(int)sintable[(ang[snum]+2048)&2047])>>3);
984                yvect += ((((int)syncsvel[snum])*doubvel*(int)sintable[(ang[snum]+1536)&2047])>>3);
985           }
986 
987           pos.x = posx[snum]; pos.y = posy[snum]; pos.z = posz[snum];
988           clipmove(&pos,&cursectnum[snum],xvect,yvect,128L,4<<8,4<<8,CLIPMASK0);
989 
990           posx[snum] = pos.x; posy[snum] = pos.y; posz[snum] = pos.z;
991 
992           frameinterpolate = 1;
993           revolvedoorstat[snum] = 1;
994           if( option[4] == 0 ) {
995                tekheadbob();
996           }
997      }
998      else {
999           revolvedoorstat[snum] = 0;
1000           headbob=0;
1001      }
1002 
1003      // push player away from walls if clipmove doesn't work
1004      pos.x = posx[snum]; pos.y = posy[snum]; pos.z = posz[snum];
1005 
1006      if( pushmove(&pos,&cursectnum[snum],128L,4<<8,4<<8,CLIPMASK0) < 0 ) {
1007           changehealth(snum,-1000);  // if this fails then instant death
1008           changescore(snum,-5);
1009      }
1010 
1011      posx[snum] = pos.x; posy[snum] = pos.y; posz[snum] = pos.z;
1012 
1013      if (cursectnum[snum] < 0 || cursectnum[snum] >= numsectors) {
1014           crash("game748: Invalid sector for player %d @ %ld,%ld (%d)",snum,
1015                posx[snum],posy[snum],cursectnum[snum]);
1016      }
1017      if (playersprite[snum] < 0 || playersprite[snum] >= MAXSPRITES) {
1018           crash("game751: Invalid sprite for player %d (%d)",snum,playersprite[snum]);
1019      }
1020 
1021      // getzrange returns the highest and lowest z's for an entire box,
1022      // NOT just a point.  This prevents you from falling off cliffs
1023      // when you step only slightly over the cliff.
1024      sprite[playersprite[snum]].cstat ^= 1;
1025 
1026      pos.x = posx[snum]; pos.y = posy[snum]; pos.z = posz[snum];
1027      getzrange(&pos,cursectnum[snum],&globhiz,&globhihit,&globloz,&globlohit,128L,CLIPMASK0);
1028      sprite[playersprite[snum]].cstat ^= 1;
1029 
1030      if( cursectnum[snum] != ocursectnum[snum] ) {
1031           teknewsector(snum);
1032      }
1033 
1034      // ang += angvel*constant, engine calculates angvel
1035      if( syncangvel[snum] != 0 ) {
1036           doubvel = TICSPERFRAME;
1037           // if run key then turn faster
1038           if( (syncbits[snum]&256) > 0 ) {
1039                doubvel += (TICSPERFRAME>>1);
1040           }
1041           ang[snum] += ((((int)syncangvel[snum])*doubvel)>>4);
1042           ang[snum] = (ang[snum]+2048)&2047;
1043      }
1044 
1045      if( health[snum] < 0 ) {
1046           health[snum] -= (TICSPERFRAME<<1);
1047           if( health[snum] <= -160 ) {
1048                hvel[snum] = 0;
1049                if( snum == myconnectindex ) {
1050                     vel = 0, svel = 0, angvel = 0, keystatus[3] = 1;
1051                }
1052                deaths[snum]++;
1053                if( (option[4] == 0) && (numplayers == 1) ) {
1054                     fadeout(0,255,32,0,0,100);
1055                }
1056                if( option[4] != 0 ) {
1057                     netstartspot(&posx[snum],&posy[snum],&cursectnum[snum]);
1058                     if (cursectnum[snum] < 0 || cursectnum[snum] >= numsectors) {
1059                          crash("game818: Invalid sector for player %d (%d)",snum,cursectnum[snum]);
1060                     }
1061                     placerandompic(KLIPPIC);
1062                     placerandompic(MEDICKITPIC);
1063                     posz[snum] = sector[cursectnum[snum]].floorz-(1<<8);
1064                     ang[snum] = (krand_intercept("GAME 802")&2047);
1065                }
1066                else {
1067                     posx[snum]=startx;
1068                     posy[snum]=starty;
1069                     posz[snum]=startz;
1070                     ang[snum]=starta;
1071                     cursectnum[snum]=starts;
1072                }
1073 
1074                tekrestoreplayer(snum);
1075 
1076                if( (option[4] == 0) && (missionfailed() == 0) ) {
1077                     newgame(boardfilename);
1078                     keystatus[2]=1;
1079                     dofadein=32;
1080                }
1081                else {
1082                     // some sort of die anim here for multiplayer ?
1083                }
1084           }
1085 #if 0                                                       // Les 10/01/95
1086           else {
1087                sprite[playersprite[snum]].xrepeat = max(((128+health[snum])>>1),0);
1088                sprite[playersprite[snum]].yrepeat = max(((128+health[snum])>>1),0);
1089 
1090                hvel[snum] += (TICSPERFRAME<<2);
1091                horiz[snum] = max(horiz[snum]-4,0);
1092                posz[snum] += hvel[snum];
1093                if( posz[snum] > globloz-(4<<8) ) {
1094                     posz[snum] = globloz-(4<<8);
1095                     horiz[snum] = min(horiz[snum]+5,200);
1096                     hvel[snum] = 0;
1097                }
1098           }
1099 #endif                                                      // Les 10/01/95
1100      }
1101      if( (syncbits[snum]&64) != 0 ) {
1102           autocenter[snum]=1;
1103      }
1104      if( autocenter[snum] ) {
1105           if( horiz[snum] > 100 ) {
1106                horiz[snum]-=4;
1107                if( horiz[snum] < 100 ) {
1108                     horiz[snum]=100;
1109                }
1110           }
1111           else if( horiz[snum] < 100 ) {
1112                horiz[snum]+=4;
1113                if( horiz[snum] > 100 ) {
1114                     horiz[snum]=100;
1115                }
1116           }
1117           if( horiz[snum] == 100 ) {
1118                autocenter[snum]=0;
1119           }
1120      }
1121 
1122      if (((syncbits[snum]&8) > 0) && (horiz[snum] > 100-(200>>1))) horiz[snum] -= 4;     //-
1123      if (((syncbits[snum]&4) > 0) && (horiz[snum] < 100+(200>>1))) horiz[snum] += 4;   //+
1124 
1125      // 32 pixels above floor is where player should be
1126      goalz = globloz-(KENSPLAYERHEIGHT<<8);
1127 
1128      // kens slime sector
1129      if( sector[cursectnum[snum]].lotag == 4 ) {
1130           // if not on a sprite
1131           if( (globlohit&0xc000) != 49152 ) {
1132                goalz = globloz-(8<<8);
1133                if( posz[snum] >= goalz-(2<<8) )
1134                {
1135                    pos.x = posx[snum]; pos.y = posy[snum]; pos.z = posz[snum];
1136                    clipmove(&pos,&cursectnum[snum],-TICSPERFRAME<<14,-TICSPERFRAME<<14,128L,4<<8,4<<8,CLIPMASK0);
1137                    posx[snum] = pos.x; posy[snum] = pos.y; posz[snum] = pos.z;
1138 
1139                     frameinterpolate = 0;
1140                     if( slimesoundcnt[snum] >= 0 ) {
1141                          slimesoundcnt[snum] -= TICSPERFRAME;
1142                          while( slimesoundcnt[snum] < 0 ) {
1143                               slimesoundcnt[snum] += 120;
1144                          }
1145                     }
1146                }
1147           }
1148      }
1149 
1150      // case where ceiling & floor are too close
1151      if( goalz < globhiz+(16<<8) ) {
1152           goalz = ((globloz+globhiz)>>1);
1153      }
1154 
1155      // climb ladder or regular z movement
1156      if( (mission == 7) || sector[cursectnum[snum]].lotag == SECT_LOTAG_CLIMB ) {
1157           if( (syncbits[snum]&1) > 0 ) {
1158                if( posz[snum] > (sector[cursectnum[snum]].ceilingz+2048) ) {
1159                     posz[snum]-=64;
1160                     if( (syncbits[snum]&256) > 0 ) {
1161                          posz[snum]-=128;
1162                     }
1163                     if( mission == 7 ) {
1164                          posz[snum]-=256;
1165                     }
1166                }
1167           }
1168           else if( (syncbits[snum]&2) > 0 ) {
1169                if( posz[snum] < (sector[cursectnum[snum]].floorz-2048) ) {
1170                     posz[snum]+=64;
1171                     if( (syncbits[snum]&256) > 0 ) {
1172                          posz[snum]+=128;
1173                     }
1174                     if( mission == 7 ) {
1175                          posz[snum]+=256;
1176                     }
1177                }
1178           }
1179      }
1180      else {
1181           if( health[snum] >= 0 ) {
1182                // jump key
1183                if( (syncbits[snum]&1) > 0 ) {
1184                     if( posz[snum] >= globloz-(KENSPLAYERHEIGHT<<8) ) {
1185                     goalz -= (16<<8);
1186 //                    if( (syncbits[snum]&256) > 0 ) {
1187                               goalz -= (24<<8);
1188 //                         }
1189                     }
1190                }
1191                // crouch key
1192                if( (syncbits[snum]&2) > 0 ) {
1193                 goalz += (12<<8);
1194 //                if( (syncbits[snum]&256) > 0 ) {
1195                          goalz += (12<<8);
1196 //                    }
1197                }
1198           }
1199           // player is on a groudraw area
1200          /*jonof: groudraw became slopes
1201           if( (sector[cursectnum[snum]].floorstat&2) > 0 ) {
1202                if( waloff[sector[cursectnum[snum]].floorheinum] == 0 ) {
1203                     loadtile(sector[cursectnum[snum]].floorheinum);
1204                }
1205                ptr = (char *)(waloff[sector[cursectnum[snum]].floorheinum]+(((posx[snum]>>4)&63)<<6)+((posy[snum]>>4)&63));
1206                goalz -= ((*ptr)<<8);
1207           }
1208          */
1209           // gravity, plus check for if on an elevator
1210           if( posz[snum] < goalz ) {
1211                hvel[snum] += (TICSPERFRAME<<5)+1;
1212           }
1213           else {
1214                if( (globlohit&0xC000) == 0xC000 ) {     // on a sprite
1215                     if ((globlohit-49152) < 0 || (globlohit-49152) >= MAXSPRITES) {
1216                          crash("game961: Invalid sprite index (%d)",globlohit-49152);
1217                     }
1218                     if( sprite[globlohit-49152].lotag >= 1500 ) {
1219                          onelev[snum]=1;
1220                     }
1221                }
1222                else if( sector[cursectnum[snum]].lotag == 1004 ||
1223                         sector[cursectnum[snum]].lotag == 1005 ) {
1224                     onelev[snum]=1;
1225                }
1226                else {
1227                     onelev[snum]=0;
1228                }
1229                if (onelev[snum] != 0 && (syncbits[snum]&2) == 0) {
1230                     hvel[snum]=0;
1231                     posz[snum]=globloz-(KENSPLAYERHEIGHT<<8);
1232                }
1233                else {
1234                     hvel[snum] = (((goalz-posz[snum])*TICSPERFRAME)>>5);
1235                }
1236           }
1237           tekchangefallz(snum,globloz,globhiz);
1238      }
1239 
1240      // overhead maps zoom in/out
1241      if( dimensionmode[snum] != 3 ) {
1242           if (((syncbits[snum]&32) > 0) && (zoom[snum] > 48)) zoom[snum] -= (zoom[snum]>>4);
1243           if (((syncbits[snum]&16) > 0) && (zoom[snum] < 4096)) zoom[snum] += (zoom[snum]>>4);
1244      }
1245 
1246      // update sprite representation of player
1247      // should be after movement, but before shooting code
1248      pos.x = posx[snum]; pos.y = posy[snum]; pos.z = posz[snum] + (KENSPLAYERHEIGHT << 8);
1249      setsprite(playersprite[snum],&pos);
1250      sprite[playersprite[snum]].ang = ang[snum];
1251 
1252      // in wrong sector or is ceiling/floor smooshing player
1253      if( (cursectnum[snum] < 0) || (cursectnum[snum] >= numsectors) ) {
1254           changehealth(snum,-200);
1255           changescore(snum,-5);
1256      }
1257      else if( globhiz+(8<<8) > globloz ) {
1258           changehealth(snum,-200);
1259           changescore(snum,-5);
1260      }
1261 
1262      // kens waterfountain
1263      if( (waterfountainwall[snum] >= 0) && (health[snum] >= 0) ) {
1264           if (neartagwall < 0 || neartagwall >= numwalls) {
1265                crash("game1009: Invalid wall (%d)",neartagwall);
1266           }
1267           if( (wall[neartagwall].lotag != 7) || ((syncbits[snum]&1024) == 0) ) {
1268                i = waterfountainwall[snum];
1269                if (i < 0 || i >= numwalls) {
1270                     crash("game1014: Invalid wall index (%d)",i);
1271                }
1272                if( wall[i].overpicnum == USEWATERFOUNTAIN ) {
1273                     wall[i].overpicnum = WATERFOUNTAIN;
1274                }
1275                else if( wall[i].picnum == USEWATERFOUNTAIN ) {
1276                     wall[i].picnum = WATERFOUNTAIN;
1277                }
1278                waterfountainwall[snum] = -1;
1279           }
1280      }
1281 
1282      // enter throw
1283      if( (option[4] == 0 ) && (pickup.picnum != 0) && (keystatus[28] != 0) ) {
1284           toss(snum);
1285           keystatus[28]=0;
1286      }
1287 
1288      // space bar (use) code
1289      if( ((syncbits[snum]&1024) > 0) && (sector[cursectnum[snum]].lotag == 4444) ) {
1290           depositsymbol(snum);
1291      }
1292      else if( (syncbits[snum]&1024) > 0 ) {
1293           // continuous triggers
1294           neartag(posx[snum],posy[snum],(posz[snum]+(8<<8)),cursectnum[snum],ang[snum],&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1024L,3,nullptr);
1295           if( neartagsector == -1 ) {
1296                i = cursectnum[snum];
1297                if( (sector[i].lotag|sector[i].hitag) != 0 ) {
1298                     neartagsector = i;
1299                }
1300           }
1301           // kens water fountain
1302           if( neartagwall >= 0 ) {
1303               if (neartagwall >= numwalls) {
1304                     crash("game1053: Invalid wall index (%d)",neartagwall);
1305                }
1306                if ( wall[neartagwall].lotag == 7 ) {
1307                     if( wall[neartagwall].overpicnum == WATERFOUNTAIN ) {
1308                          wall[neartagwall].overpicnum = USEWATERFOUNTAIN;
1309                          waterfountainwall[snum] = neartagwall;
1310                     }
1311                     else if( wall[neartagwall].picnum == WATERFOUNTAIN ) {
1312                          wall[neartagwall].picnum = USEWATERFOUNTAIN;
1313                          waterfountainwall[snum] = neartagwall;
1314                     }
1315                     if( waterfountainwall[snum] >= 0 ) {
1316                          waterfountaincnt[snum] -= TICSPERFRAME;
1317                          while( waterfountaincnt[snum] < 0 ) {
1318                               waterfountaincnt[snum] += 120;
1319                               changehealth(snum,2);
1320                          }
1321                     }
1322                }
1323           }
1324           // 1-time triggers
1325           if( (oflags[snum]&1024) == 0 ) {
1326                if( neartagsector >= 0 ) {
1327                     if (neartagsector >= numsectors) {
1328                          crash("game1070: Invalid sector index (%d)",neartagsector);
1329                     }
1330                     if( sector[neartagsector].hitag == 0 ) {
1331                          operatesector(neartagsector);
1332                     }
1333                }
1334                if( neartagwall >= 0 ) {
1335                     if (neartagwall >= numwalls) {
1336                          crash("game1078: Invalid wall index (%d)",neartagwall);
1337                     }
1338                     if( wall[neartagwall].lotag == 2 ) {
1339                          for( i=0; i<numsectors; i++ ) {
1340                               if( sector[i].hitag == wall[neartagwall].hitag ) {
1341                                    if( sector[i].lotag != 1 ) {
1342                                         operatesector(i);
1343                                    }
1344                               }
1345                          }
1346                          i = headspritestat[0];
1347                          while( i != -1 ) {
1348                               nexti = nextspritestat[i];
1349                               if( sprite[i].hitag == wall[neartagwall].hitag ) {
1350                                    operatesprite(i);
1351                               }
1352                               i = nexti;
1353                          }
1354                          j = wall[neartagwall].overpicnum;
1355                          if( j == SWITCH1ON ) {
1356                               wall[neartagwall].overpicnum = GIFTBOX;
1357                               wall[neartagwall].lotag = 0;
1358                               wall[neartagwall].hitag = 0;
1359                          }
1360                          if( j == GIFTBOX ) {
1361                               wall[neartagwall].overpicnum = SWITCH1ON;
1362                               wall[neartagwall].lotag = 0;
1363                               wall[neartagwall].hitag = 0;
1364                          }
1365                          if (j == SWITCH2ON)  wall[neartagwall].overpicnum = SWITCH2OFF;
1366                          if (j == SWITCH2OFF) wall[neartagwall].overpicnum = SWITCH2ON;
1367                          if (j == SWITCH3ON)  wall[neartagwall].overpicnum = SWITCH3OFF;
1368                          if (j == SWITCH3OFF) wall[neartagwall].overpicnum = SWITCH3ON;
1369                          i = wall[neartagwall].point2;
1370                          dax = ((wall[neartagwall].x+wall[i].x)>>1);
1371                          day = ((wall[neartagwall].y+wall[i].y)>>1);
1372                     }
1373                }
1374                if( neartagsprite >= 0 ) {
1375                     if (neartagsprite >= MAXSPRITES) {
1376                          crash("game1118: Invalid sprite index (%d)",neartagsprite);
1377                     }
1378                     if( sprite[neartagsprite].lotag == 4 ) {
1379                          tekswitchtrigger(snum);
1380                     }
1381                     else {
1382                          operatesprite(neartagsprite);
1383                     }
1384                }
1385           }
1386      }
1387 
1388      // fire weapon
1389      if( (syncbits[snum]&2048) > 0 ) {
1390           tekfiregun((syncbits[snum]>>13)&15,snum);
1391      }
1392 
1393      // map mode
1394      if( (syncbits[snum]&4096) > (oflags[snum]&4096) ) {
1395           if (dimensionmode[snum] == 3) {
1396                dimensionmode[snum]=1;
1397           }
1398           else {
1399                dimensionmode[snum]=3;
1400           }
1401 #if 0               // eliminate map mode 2
1402           dimensionmode[snum]++;
1403           if( dimensionmode[snum] > 3 ) {
1404                dimensionmode[snum] = 1;
1405           }
1406 #endif
1407           if( snum == screenpeek ) {
1408                if (dimensionmode[snum] == 2) videoSetViewableArea(0L,0L,xdim-1,(ydim-1)>>detailmode);
1409                if (dimensionmode[snum] == 3) setup3dscreen();
1410           }
1411      }
1412 
1413      oflags[snum] = syncbits[snum];
1414 }
1415 
1416 void
drawscreen(short snum,int dasmoothratio)1417 drawscreen(short snum, int dasmoothratio)
1418 {
1419      int      i, j, charsperline, tempint;
1420      int      x1, y1, x2, y2, ox1, oy1, ox2, oy2;
1421      int      cposx, cposy, cposz, choriz, czoom;
1422      short     cang;
1423 
1424      smoothratio = max(min(dasmoothratio,65536),0);
1425 
1426      cposx = oposx[snum]+mulscale(posx[snum]-oposx[snum],smoothratio,16);
1427      cposy = oposy[snum]+mulscale(posy[snum]-oposy[snum],smoothratio,16);
1428      cposz = oposz[snum]+mulscale(posz[snum]-oposz[snum],smoothratio,16);
1429      if( frameinterpolate == 0 ) {
1430           cposx = posx[snum]; cposy = posy[snum]; cposz = posz[snum];
1431      }
1432      cposz+=headbob;
1433      choriz = ohoriz[snum]+mulscale(horiz[snum]-ohoriz[snum],smoothratio,16);
1434      czoom = ozoom[snum]+mulscale(zoom[snum]-ozoom[snum],smoothratio,16);
1435      cang = oang[snum]+mulscale(((ang[snum]+1024-oang[snum])&2047)-1024,smoothratio,16);
1436 
1437      if( dimensionmode[snum] != 2 ) {
1438           if( (numplayers > 1) && (option[4] == 0) ) {
1439                for( i=connecthead; i>=0; i=connectpoint2[i] ) {
1440                     frame2draw[i] = 1;
1441                }
1442                redrawbackfx();
1443                for( i=connecthead,j=0; i>=0; i=connectpoint2[i],j++ ) {
1444                     if( frame2draw[i] != 0 ) {
1445                          if( numplayers <= 4 ) {
1446                               switch( j ) {
1447                                    case 0: videoSetViewableArea(0,0,(xdim>>1)-1,(ydim>>1)-1); break;
1448                                    case 1: videoSetViewableArea((xdim>>1),0,xdim-1,(ydim>>1)-1); break;
1449                                    case 2: videoSetViewableArea(0,(ydim>>1),(xdim>>1)-1,ydim-1); break;
1450                                    case 3: videoSetViewableArea((xdim>>1),(ydim>>1),xdim-1,ydim-1); break;
1451                               }
1452                          }
1453                          else {
1454                               switch( j ) {
1455                                    case 0: videoSetViewableArea(0,0,(xdim>>2)-1,(ydim>>2)-1); break;
1456                                    case 1: videoSetViewableArea(xdim>>2,0,(xdim>>1)-1,(ydim>>2)-1); break;
1457                                    case 2: videoSetViewableArea(xdim>>1,0,xdim-(xdim>>2)-1,(ydim>>2)-1); break;
1458                                    case 3: videoSetViewableArea(xdim-(xdim>>2),0,xdim-1,(ydim>>2)-1); break;
1459                                    case 4: videoSetViewableArea(0,ydim>>2,(xdim>>2)-1,(ydim>>1)-1); break;
1460                                    case 5: videoSetViewableArea(xdim>>2,ydim>>2,(xdim>>1)-1,(ydim>>1)-1); break;
1461                                    case 6: videoSetViewableArea(xdim>>1,ydim>>2,xdim-(xdim>>2)-1,(ydim>>1)-1); break;
1462                                    case 7: videoSetViewableArea(xdim-(xdim>>2),ydim>>2,xdim-1,(ydim>>1)-1); break;
1463                                    case 8: videoSetViewableArea(0,ydim>>1,(xdim>>2)-1,ydim-(ydim>>2)-1); break;
1464                                    case 9: videoSetViewableArea(xdim>>2,ydim>>1,(xdim>>1)-1,ydim-(ydim>>2)-1); break;
1465                                    case 10: videoSetViewableArea(xdim>>1,ydim>>1,xdim-(xdim>>2)-1,ydim-(ydim>>2)-1); break;
1466                                    case 11: videoSetViewableArea(xdim-(xdim>>2),ydim>>1,xdim-1,ydim-(ydim>>2)-1); break;
1467                                    case 12: videoSetViewableArea(0,ydim-(ydim>>2),(xdim>>2)-1,ydim-1); break;
1468                                    case 13: videoSetViewableArea(xdim>>2,ydim-(ydim>>2),(xdim>>1)-1,ydim-1); break;
1469                                    case 14: videoSetViewableArea(xdim>>1,ydim-(ydim>>2),xdim-(xdim>>2)-1,ydim-1); break;
1470                                    case 15: videoSetViewableArea(xdim-(xdim>>2),ydim-(ydim>>2),xdim-1,ydim-1); break;
1471                               }
1472                          }
1473                          if( i == snum ) {
1474                               drawrooms(cposx,cposy,cposz,cang,choriz,cursectnum[i]);
1475                          }
1476                          else {
1477                               drawrooms(posx[i],posy[i],posz[i],ang[i],horiz[i],cursectnum[i]);
1478                          }
1479                          analyzesprites(posx[i],posy[i]);
1480                          renderDrawMasks();
1481                          tekdrawgun((syncbits[i]>>13)&15,i);
1482                     }
1483                }
1484           }
1485           else {
1486                redrawbackfx();
1487                drawrooms(cposx,cposy,cposz,cang,choriz,cursectnum[snum]);
1488                analyzesprites(posx[snum],posy[snum]);
1489                renderDrawMasks();
1490                tekdrawgun((syncbits[screenpeek]>>13)&15,screenpeek);
1491           }
1492      }
1493 
1494      // move back pivot point for map
1495      if( dimensionmode[snum] != 3 ) {
1496           cposx += (sintable[(cang+512)&2047]<<6) / czoom;
1497           cposy += (sintable[cang&2047]<<6) / czoom;
1498           if( dimensionmode[snum] == 2 ) {
1499               videoClearViewableArea(0L);  //Clear screen to specified color
1500 // TODO               drawmapview(cposx,cposy,czoom,cang);
1501           }
1502           drawoverheadmap(cposx,cposy,czoom,cang);
1503      }
1504 
1505      if( typemode != 0 ) {
1506           charsperline = 40;
1507           for( i=0; i<=typemessageleng; i+=charsperline ) {
1508                for( j=0; j<charsperline; j++ ) {
1509                     tempbuf[j] = typemessage[i+j];
1510                }
1511                if( typemessageleng < i+charsperline ) {
1512                     tempbuf[(typemessageleng-i)] = '_';
1513                     tempbuf[(typemessageleng-i)+1] = 0;
1514                }
1515                else {
1516                     tempbuf[charsperline] = 0;
1517                }
1518           }
1519      }
1520      else {
1521           if( dimensionmode[myconnectindex] == 3 ) {
1522                tempint = screensize;
1523                if( ((locbits&32) > (screensizeflag&32)) && (screensize > 64) ) {
1524                     ox1 = (xdim>>1)-(screensize>>1);
1525                     ox2 = ox1+screensize-1;
1526                     oy1 = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
1527                     oy2 = oy1+((screensize*(ydim-32))/xdim)-1;
1528                     tekview(&ox1,&oy1, &ox2,&oy2);
1529                     screensize -= (screensize>>3);
1530                     if( tempint > xdim ) {
1531                          screensize = xdim;
1532                          permanentwritesprite((xdim-320)>>1,ydim-32,STATUSBAR,0,0,0,xdim-1,ydim-1,0);
1533                          i = ((xdim-320)>>1);
1534                          while( i >= 8 ) {
1535                               i -= 8, permanentwritesprite(i,ydim-32,STATUSBARFILL8,0,0,0,xdim-1,ydim-1,0);
1536                          }
1537                          if( i >= 4 ) {
1538                               i -= 4, permanentwritesprite(i,ydim-32,STATUSBARFILL4,0,0,0,xdim-1,ydim-1,0);
1539                          }
1540                          i = ((xdim-320)>>1)+320;
1541                          while( i <= xdim-8 ) {
1542                               permanentwritesprite(i,ydim-32,STATUSBARFILL8,0,0,0,xdim-1,ydim-1,0), i += 8;
1543                          }
1544                          if( i <= xdim-4 ) {
1545                               permanentwritesprite(i,ydim-32,STATUSBARFILL4,0,0,0,xdim-1,ydim-1,0), i += 4;
1546                          }
1547                     }
1548                     x1 = (xdim>>1)-(screensize>>1);
1549                     x2 = x1+screensize-1;
1550                     y1 = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
1551                     y2 = y1+((screensize*(ydim-32))/xdim)-1;
1552                     tekview(&x1,&y1,&x2,&y2);
1553                     videoSetViewableArea(x1,y1>>detailmode,x2,y2>>detailmode);
1554                     permanentwritespritetile(0L,0L,BACKGROUND,0,ox1,oy1,x1-1,oy2,0);
1555                     permanentwritespritetile(0L,0L,BACKGROUND,0,x2+1,oy1,ox2,oy2,0);
1556                     permanentwritespritetile(0L,0L,BACKGROUND,0,x1,oy1,x2,y1-1,0);
1557                     permanentwritespritetile(0L,0L,BACKGROUND,0,x1,y2+1,x2,oy2,0);
1558                }
1559                if( ((locbits&16) > (screensizeflag&16)) && (screensize <= xdim) ) {
1560                     screensize += (screensize>>3);
1561                     if( (screensize > xdim) && (tempint == xdim) ) {
1562                          screensize = xdim+1;
1563                          x1 = 0; y1 = 0;
1564                          x2 = xdim-1; y2 = ydim-1;
1565                     }
1566                     else {
1567                          if (screensize > xdim) screensize = xdim;
1568                          x1 = (xdim>>1)-(screensize>>1);
1569                          x2 = x1+screensize-1;
1570                          y1 = ((ydim-32)>>1)-(((screensize*(ydim-32))/xdim)>>1);
1571                          y2 = y1+((screensize*(ydim-32))/xdim)-1;
1572                     }
1573                     tekview(&x1,&y1,&x2,&y2);
1574                     videoSetViewableArea(x1,y1>>detailmode,x2,y2>>detailmode);
1575                }
1576                screensizeflag = locbits;
1577           }
1578      }
1579 
1580      if( getmessageleng > 0 ) {
1581           charsperline = 40;
1582           for( i=0; i<=getmessageleng; i+=charsperline ) {
1583                for( j=0; j<charsperline; j++ ) {
1584                     tempbuf[j] = getmessage[i+j];
1585                }
1586                if( getmessageleng < i+charsperline ) {
1587                     tempbuf[(getmessageleng-i)] = 0;
1588                }
1589                else {
1590                     tempbuf[charsperline] = 0;
1591                }
1592                printext256(0L,((i/charsperline)<<3)+(200-32-8)-(((getmessageleng-1)/charsperline)<<3),151,-1,tempbuf,0);
1593           }
1594           if( ((int)totalclock) > getmessagetimeoff ) {
1595                getmessageleng = 0;
1596           }
1597      }
1598 
1599      // you are looking thru an opponent plaeyer's eyes
1600      if( (numplayers >= 2) && (screenpeek != myconnectindex) ) {
1601           strcpy(tempbuf,"Other");
1602      }
1603 
1604     #ifdef OUTOFSYNCMESSAGE
1605      if( syncstat != 0 ) {
1606           printext256(68L,84L,31,0,"OUT OF SYNC!",0);
1607      }
1608      if( syncstate != 0 ) {
1609           printext256(68L,92L,31,0,"Missed Network packet!",0);
1610      }
1611     #endif
1612 
1613      tekscreenfx();
1614 
1615     #ifdef  NETWORKDIAGNOSTICS
1616      if( (option[4] > 0) ) {
1617           for( i=connecthead ; i >= 0 ; i=connectpoint2[i] ) {
1618                sprintf(tektempbuf,"%2d %5d %5d %5d %5d %3d %4d", i,posx[i],posy[i],posz[i],ang[i],horiz[i],health[i]);
1619                printext(2,i*8+2,tektempbuf,ALPHABET,255);
1620           }
1621           if( myconnectindex == connecthead ) {
1622                sprintf(tektempbuf,"%2d %s",myconnectindex,"M");
1623           }
1624           else {
1625                sprintf(tektempbuf,"%2d %s",myconnectindex,"S");
1626           }
1627           printext(windowx2-48,windowy2-64,tektempbuf,ALPHABET2,255);
1628      }
1629     #endif
1630 
1631      videoNextPage();
1632      if( dofadein != 0 ) {
1633           fadein(0,255,dofadein);
1634      }
1635 
1636     #ifdef OOGIE
1637      // F5 key
1638      if( keystatus[0x3f] > 0 ) {
1639           keystatus[0x3f] = 0;
1640           detailmode ^= 1;
1641           if( detailmode == 0 ) {
1642                setview(windowx1,windowy1<<1,windowx2,(windowy2<<1)+1);
1643                outp(0x3d4,0x9); outp(0x3d5,(inp(0x3d5)&~31)|1);
1644           }
1645           else {
1646                setview(windowx1,windowy1>>detailmode,windowx2,windowy2>>detailmode);
1647                setaspect(yxaspect>>1);
1648                outp(0x3d4,0x9); outp(0x3d5,(inp(0x3d5)&~31)|3);
1649           }
1650      }
1651     #endif
1652 
1653      // F12 key
1654      if( keystatus[0x58] > 0 ) {
1655           keystatus[0x58] = 0;
1656 // TODO          screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]);
1657      }
1658 
1659     #ifdef STEREOMODE_ADJUSTMENT_ACTIVE
1660      if( stereofps != 0 ) {
1661           if( (keystatus[0x2a]|keystatus[0x36]) > 0 ) {
1662                if (keystatus[0x1a] > 0) stereopixelwidth--;   //Shift [
1663                if (keystatus[0x1b] > 0) stereopixelwidth++;   //Shift ]
1664           }
1665           else {
1666                if (keystatus[0x1a] > 0) stereowidth -= 512;   //[
1667                if (keystatus[0x1b] > 0) stereowidth += 512;   //]
1668           }
1669      }
1670     #endif
1671 
1672     #ifdef FAKEMULTIPLAYER_ACTIVE
1673      if( option[4] == 0 ) {
1674           if( keystatus[0xd2] > 0 ) {
1675                keystatus[0xd2] = 0;
1676                if( numplayers < MAXPLAYERS ) {
1677                     connectpoint2[numplayers-1] = numplayers;
1678                     connectpoint2[numplayers] = -1;
1679                     initplayersprite(numplayers);
1680                     clearallviews(0L);
1681                     numplayers++;
1682                }
1683           }
1684           if( keystatus[0xd3] > 0 ) {
1685                keystatus[0xd3] = 0;
1686                if( numplayers > 1 ) {
1687                     numplayers--;
1688                     connectpoint2[numplayers-1] = -1;
1689                     deletesprite(playersprite[numplayers]);
1690                     playersprite[numplayers] = -1;
1691                     if( myconnectindex >= numplayers ) {
1692                          myconnectindex = 0;
1693                     }
1694                     if( screenpeek >= numplayers ) {
1695                          screenpeek = 0;
1696                     }
1697                     if( numplayers < 2 ) {
1698                          setup3dscreen();
1699                     }
1700                     else {
1701                          clearallviews(0L);
1702                     }
1703                }
1704           }
1705           // scroll lock
1706           if( keystatus[0x46] > 0 ) {
1707                keystatus[0x46] = 0;
1708                myconnectindex = connectpoint2[myconnectindex];
1709                if( myconnectindex < 0 ) {
1710                     myconnectindex = connecthead;
1711                }
1712                screenpeek = myconnectindex;
1713           }
1714      }
1715     #endif
1716 }
1717 
1718 void
movethings()1719 movethings()
1720 {
1721      int      i;
1722 
1723      gotlastpacketclock = (int)totalclock;
1724      for( i=connecthead; i>=0; i=connectpoint2[i] ) {
1725           baksyncvel[movefifoend][i] = fsyncvel[i];
1726           baksyncsvel[movefifoend][i] = fsyncsvel[i];
1727           baksyncangvel[movefifoend][i] = fsyncangvel[i];
1728           baksyncbits[movefifoend][i] = fsyncbits[i];
1729      }
1730      movefifoend = ((movefifoend+1)&(MOVEFIFOSIZ-1));
1731 
1732      // do this for Master/Slave switching
1733      for( i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i] ) {
1734           if( syncbits[i]&512 ) {
1735                ready2send = 0;
1736           }
1737      }
1738 
1739      tektime();
1740 }
1741 
1742 void
domovethings()1743 domovethings()
1744 {
1745      short          i, j, startwall, endwall;
1746      walltype       *wal;
1747 
1748      for( i=connecthead; i>=0; i=connectpoint2[i] ) {
1749         if (dbgflag) {
1750             debugout(i);
1751         }
1752           syncvel[i] = baksyncvel[movefifoplc][i];
1753           syncsvel[i] = baksyncsvel[movefifoplc][i];
1754           syncangvel[i] = baksyncangvel[movefifoplc][i];
1755           syncbits[i] = baksyncbits[movefifoplc][i];
1756      }
1757      movefifoplc = ((movefifoplc+1)&(MOVEFIFOSIZ-1));
1758 #if 0
1759      syncval[syncvalend] = getsyncstat();
1760      syncvalend = ((syncvalend+1)&(MOVEFIFOSIZ-1));
1761 #endif
1762      for( i=connecthead; i>=0; i=connectpoint2[i] ) {
1763           oposx[i] = posx[i];
1764           oposy[i] = posy[i];
1765           oposz[i] = posz[i];
1766           ohoriz[i] = horiz[i];
1767           ozoom[i] = zoom[i];
1768           oang[i] = ang[i];
1769      }
1770 
1771      for( i=1; i<=8; i++ ) {
1772           if( i != 2 ) {
1773                for( j=headspritestat[i]; j>=0; j=nextspritestat[j] ) {
1774                     copybuf(&sprite[j].x,&osprite[j].x,3);
1775                }
1776           }
1777      }
1778 
1779      for( i=connecthead; i>=0; i=connectpoint2[i] ) {
1780           ocursectnum[i] = cursectnum[i];
1781      }
1782 
1783      if( (numplayers <= 2) && (recstat == 1) ) {
1784           j = 0;
1785           for( i=connecthead; i>=0; i=connectpoint2[i] ) {
1786                recsyncvel[reccnt][j] = syncvel[i];
1787                recsyncsvel[reccnt][j] = syncsvel[i];
1788                recsyncangvel[reccnt][j] = syncangvel[i];
1789                recsyncbits[reccnt][j] = syncbits[i];
1790                j++;
1791           }
1792           reccnt++;
1793           if( reccnt > 16383 ) {
1794                reccnt = 16383;
1795           }
1796      }
1797 
1798      lockclock += TICSPERFRAME;
1799 
1800      for( i=connecthead; i>=0; i=connectpoint2[i] ) {
1801           processinput(i);
1802           checktouchsprite(i,cursectnum[i]);
1803           startwall = sector[cursectnum[i]].wallptr;
1804           endwall = startwall + sector[cursectnum[i]].wallnum;
1805           for( j=startwall,wal=&wall[j]; j<endwall; j++,wal++ ) {
1806                if( wal->nextsector >= 0 ) {
1807                     checktouchsprite(i,wal->nextsector);
1808                }
1809           }
1810      }
1811 
1812      doanimations();
1813 
1814      tagcode();
1815      statuslistcode();
1816 
1817      checkmasterslaveswitch();
1818 }
1819 
1820 void
adjustbiasthreshhold(short mousy)1821 adjustbiasthreshhold(short mousy)
1822 {
1823      biasthreshhold-=mousy;
1824      if( biasthreshhold < 8 )
1825           biasthreshhold=8;
1826      if( biasthreshhold > 512 )
1827           biasthreshhold=512;
1828 }
1829 
1830 //** Les START - 09/27/95
1831 short moreoptionbits[]={
1832      -1,                           //  0 move forward
1833      -1,                           //  1 move backward
1834      -1,                           //  2 turn right
1835      -1,                           //  3 turn left
1836       8,                           //  4 run
1837      -1,                           //  5 strafe
1838      11,                           //  6 shoot
1839      10,                           //  7 use
1840       0,                           //  8 jump
1841       1,                           //  9 crouch
1842       2,                           // 10 look up
1843       3,                           // 11 look down
1844      -1,                           // 12 slide left
1845      -1,                           // 13 slide right
1846      12,                           // 14 map
1847      -1,                           // 15 switch player
1848       4,                           // 16 zoom in
1849       5,                           // 17 zoom out
1850      -1,                           // 18 message
1851       6,                           // 19 autocenter
1852      -1,                           // 20 rearview
1853      -1,                           // 21 current item
1854      -1,                           // 22 health
1855      -1,                           // 23 crosshairs
1856      -1,                           // 24 elapsed time
1857      -1,                           // 25 score
1858      -1,                           // 26 inventory
1859       7,                           // 27 conceal weapon
1860      -1                            // 28 mouse look mode
1861 };
1862 //** Les END   - 09/27/95
1863 
getinput()1864 void getinput()
1865 {
1866      int      ch, keystate;
1867      int      i, j;
1868      int     mousx, mousy, bstatus;
1869      short     moving,strafing,turning;
1870 
1871      if( activemenu != 0 ) {
1872           domenuinput();
1873      }
1874 
1875      // normal game keys active
1876      if( typemode == 0 ) {
1877           // shift+shift+R
1878           if( (keystatus[0x2a]&keystatus[0x36]&keystatus[0x13]) > 0 ) {
1879                keystatus[0x13] = 0;
1880                playback();
1881           }
1882          #ifdef SWITCHINGACTIVE
1883           if( keystatus[keys[15]] > 0 ) {
1884                keystatus[keys[15]] = 0;
1885                screenpeek = connectpoint2[screenpeek];
1886                if( screenpeek < 0 ) {
1887                     screenpeek = connecthead;
1888                }
1889           }
1890          #endif
1891           for( i=7; i>=0; i-- ) {
1892                if( (keystatus[i+2] > 0) && tekhasweapon(i,screenpeek) ) {
1893                     keystatus[i+2] = 0;
1894                     locselectedgun = i;
1895                     break;
1896                }
1897           }
1898      }
1899 
1900 //** Les  - moved from below to apply button movements to vel, svel and angvel
1901 //**        if needed
1902 
1903      mousx=mousy=bstatus=0;
1904      #if 0 // TODO
1905      if( moreoptions[0] != 0 ) {
1906           getmousevalues(&mousx,&mousy,&bstatus);
1907           if( biasthreshholdon && (bstatus&6) ) {
1908                adjustbiasthreshhold(mousy);
1909                bstatus=0;
1910           }
1911           // if horizon key down
1912           if( keystatus[58] == 0 ) {
1913                if( mousy > (biasthreshhold) ) {
1914                     mousebias=-1;
1915                }
1916                else if( mousy < -(biasthreshhold) ) {
1917                     mousebias=+1;
1918                }
1919           }
1920      }
1921      #endif
1922 
1923 //** Les START - 09/26/95
1924      locbits=(locselectedgun<<13);                          // Les 09/28/95 moved from below
1925 
1926      #if 0 // TODO
1927      if (jstickenabled) {
1928 //          showmessage("X: %05d Y: %05d B:%04X",joyx,joyy,joyb);
1929           if (joyaxis[0] < jlowx) {
1930                angvel=max(min(angvel-joyaxis[0],127),-128);
1931           }
1932           else if (joyaxis[0] > jhighx) {
1933                angvel=min(max(angvel+joyaxis[0],-128),127);
1934           }
1935           if (joyaxis[1] < jlowy) {
1936                vel=min(max(vel+joyaxis[1],-128),127);
1937           }
1938           else if (joyaxis[1] > jhighy) {
1939                vel=max(min(vel-joyaxis[1],127),-128);
1940           }
1941           for (i=0 ; i < 4 ; i++) {
1942                if ((joyb&(0x10<<i)) == 0) {
1943                     if (moreoptions[i+4] == 0) {
1944                          moving=1;
1945                     }
1946                     else if (moreoptions[i+4] == 1) {
1947                          moving=-1;
1948                     }
1949                     else if (moreoptions[i+4] == 2) {
1950                          turning=1;
1951                     }
1952                     else if (moreoptions[i+4] == 3) {
1953                          turning=-1;
1954                     }
1955                     else if (moreoptions[i+4] == 5) {
1956                          strafing=2;
1957                     }
1958                     else if (moreoptions[i+4] == 12) {
1959                          strafing=-1;
1960                     }
1961                     else if (moreoptions[i+4] == 13) {
1962                          strafing=1;
1963                     }
1964                     else if (moreoptionbits[moreoptions[i+4]] >= 0) {
1965                          locbits|=(1<<moreoptionbits[moreoptions[i+4]]);
1966                     }
1967                }
1968           }
1969           oldjoyb=joyb;
1970      }
1971      #endif
1972 
1973 //** Les END   - 09/26/95
1974 
1975 //** Les START - 09/28/95
1976      moving=strafing=turning=0;
1977      if (moreoptions[0] != 0) {
1978           for (i=0 ; i < 3 ; i++) {
1979                if (bstatus&(1<<i)) {
1980                     switch (i) {
1981                     case 0:
1982                          j=1;
1983                          break;
1984                     case 1:
1985                          j=20;
1986                          break;
1987                     case 2:
1988                          j=2;
1989                          break;
1990                     }
1991                     if (moreoptions[j] == 0) {
1992                          moving=1;
1993                     }
1994                     else if (moreoptions[j] == 1) {
1995                          moving=-1;
1996                     }
1997                     else if (moreoptions[j] == 2) {
1998                          turning=1;
1999                     }
2000                     else if (moreoptions[j] == 3) {
2001                          turning=-1;
2002                     }
2003                     else if (moreoptions[j] == 5) {
2004                          strafing=2;
2005                     }
2006                     else if (moreoptions[j] == 12) {
2007                          strafing=-1;
2008                     }
2009                     else if (moreoptions[j] == 13) {
2010                          strafing=1;
2011                     }
2012                     else {
2013                          locbits|=(1<<moreoptionbits[moreoptions[j]]);
2014                     }
2015                }
2016           }
2017      }
2018 //** Les END   - 09/28/95
2019 
2020      // keyboard survey - use to be keytimerstuff() called from keyhandler
2021      if( keystatus[keys[5]] == 0 && strafing == 0 ) {    // Les 09/28/95
2022           if( keystatus[keys[2]] > 0 || turning == 1) angvel = max(angvel-16*TICSPERFRAME,-128); // Les 09/28/95
2023           if( keystatus[keys[3]] > 0 || turning == -1) angvel = min(angvel+16*TICSPERFRAME,127); // Les 09/28/95
2024      }
2025      else {
2026           if (strafing == 0) {                                                                   // Les 09/28/95
2027                strafing=2;                                                                       // Les 09/28/95
2028           }                                                                                      // Les 09/28/95
2029           if( keystatus[keys[2]] > 0 || turning == 1 ) svel = min(svel+8*TICSPERFRAME,127);      // Les 09/28/95
2030           if( keystatus[keys[3]] > 0 || turning == -1 ) svel = max(svel-8*TICSPERFRAME,-128);    // Les 09/28/95
2031      }
2032      if( keystatus[keys[0]]  > 0 || moving == 1 ) vel  = min(vel+8*TICSPERFRAME,127);           // Les 09/28/95
2033      if( keystatus[keys[1]]  > 0 || moving == -1 ) vel  = max(vel-8*TICSPERFRAME,-128);         // Les 09/28/95
2034      if( keystatus[keys[12]] > 0 || strafing == 1 ) svel = min(svel+8*TICSPERFRAME,127);        // Les 09/28/95
2035      if( keystatus[keys[13]] > 0 || strafing == -1 ) svel = max(svel-8*TICSPERFRAME,-128);      // Les 09/28/95
2036      if( angvel < 0 ) angvel = min(angvel+12*TICSPERFRAME,0);
2037      if( angvel > 0 ) angvel = max(angvel-12*TICSPERFRAME,0);
2038      if( svel < 0 )   svel   = min(svel+2*TICSPERFRAME,0);
2039      if( svel > 0 )   svel   = max(svel-2*TICSPERFRAME,0);
2040      if( vel  < 0 )   vel    = min(vel+2*TICSPERFRAME,0);
2041      if( vel  > 0 )   vel    = max(vel-2*TICSPERFRAME,0);
2042 
2043      if( (option[4] == 0) && (numplayers == 2) ) {
2044           if( keystatus[0x4f] == 0 ) {
2045                if( keystatus[0x4b] > 0 ) angvel2 = max(angvel2-16*TICSPERFRAME,-128);
2046                if( keystatus[0x4d] > 0 ) angvel2 = min(angvel2+16*TICSPERFRAME,127);
2047           }
2048           else {
2049                if( keystatus[0x4b] > 0 ) svel2 = min(svel2+8*TICSPERFRAME,127);
2050                if( keystatus[0x4d] > 0 ) svel2 = max(svel2-8*TICSPERFRAME,-128);
2051           }
2052           if( keystatus[0x48] > 0 ) vel2 = min(vel2+8*TICSPERFRAME,127);
2053           if( keystatus[0x4c] > 0 ) vel2 = max(vel2-8*TICSPERFRAME,-128);
2054           if( angvel2 < 0 ) angvel2 = min(angvel2+12*TICSPERFRAME,0);
2055           if( angvel2 > 0 ) angvel2 = max(angvel2-12*TICSPERFRAME,0);
2056           if( svel2 < 0 )   svel2   = min(svel2+2*TICSPERFRAME,0);
2057           if( svel2 > 0 )   svel2   = max(svel2-2*TICSPERFRAME,0);
2058           if( vel2  < 0 )   vel2    = min(vel2+2*TICSPERFRAME,0);
2059           if( vel2  > 0 )   vel2    = max(vel2-2*TICSPERFRAME,0);
2060      }
2061      if( keystatus[keys[28]] ) {
2062           i=horiz[myconnectindex]+((( int)mousy)>>3);
2063           if( i > 200 ) i=200;
2064           if( i < 0   ) i=0;
2065           horiz[myconnectindex]=i;
2066           keyedhorizon=1;
2067           mousy=0;
2068      }
2069      else {
2070           if( (keyedhorizon) && (horiz[myconnectindex] != 100) )
2071                autocenter[myconnectindex]=1;
2072           keyedhorizon=0;
2073           mousx*=mousesensitivity;
2074      }
2075 //     if( (bstatus&6) != 0 ) {
2076 //          vel=min(vel+(1<<(8+mousesensitivity)),127);
2077 //          vel*=mousebias;
2078 //     }
2079      locvel = min(max(vel,-128+8),127-8);
2080      locsvel = min(max(svel,-128+8),127-8);
2081      locangvel = min(max(angvel,-512+16),511-16);            // Les 09/27/95
2082 
2083      if (strafing == 2) {                                   // Les 09/28/95
2084           locsvel=max(min(svel-mousx,511-16),-512+16);      // Les 09/28/95
2085      }                                                      // Les 09/28/95
2086      else {                                                 // Les 09/28/95
2087           locangvel=min(max(locangvel+mousx,-512),511);     // Les 09/27/95
2088      }                                                      // Les 09/28/95
2089 //** Les START - 09/28/95
2090      if (mousy < 0) {
2091           mousy-=(1<<mousesensitivity);
2092      }
2093      else if (mousy > 0) {
2094           mousy+=(1<<mousesensitivity);
2095      }
2096 //** Les END   - 09/28/95
2097 
2098      locvel=min(max(locvel-mousy,-128),127);
2099 //    locbits = (locselectedgun<<13); moved up to joystick section
2100 
2101 
2102      if( typemode == 0 ) {
2103          #ifdef MASTERSWITCHING
2104           locbits |= (keystatus[0x32]<<9);                  //M (be master)
2105          #endif
2106           locbits |= ((keystatus[keys[14]]==1)<<12);        //Map mode
2107      }
2108      locbits |= keystatus[keys[8]];                         //Stand high
2109      locbits |= (keystatus[keys[9]] <<1);                   //Stand low
2110      locbits |= (keystatus[keys[10]]<<2);                   //Look up
2111      locbits |= (keystatus[keys[11]]<<3);                   //Look down
2112      locbits |= (keystatus[keys[16]]<<4);                   //Zoom in
2113      locbits |= (keystatus[keys[17]]<<5);                   //Zoom out
2114      locbits |= (keystatus[keys[19]]<<6);                   //AutoCenter     TekWar
2115      locbits |= (keystatus[keys[27]]<<7);                   //Conceal Weapin TekWar
2116      locbits |= (keystatus[keys[4]]<<8);                    //Run
2117      locbits |= ((keystatus[keys[7]]==1)<<10);              //Space
2118      locbits |= ((keystatus[keys[6]]==1)<<11);              //Shoot Kbd
2119 //    locbits |= (((bstatus&6)>(oldmousebstatus&6))<<10);    //Space
2120 //    locbits |= (((bstatus&1)>(oldmousebstatus&1))<<11);    //Shoot Mse
2121 
2122      if( typemode != 0 ) {
2123          #ifdef MASTERSWITCHING
2124           locbits &= ~(keystatus[0x32]<<9);
2125          #endif
2126           locbits &= ~((keystatus[keys[14]]==1)<<12);
2127      }
2128 
2129      #if 0 // TODO
2130      if( (joyb == 236) || (joyb == 220) || (joyb == 124) || (joyb == 188) ) {
2131           keystatus[keys[moreoptions[4]]]=0;
2132           keystatus[keys[moreoptions[5]]]=0;
2133           keystatus[keys[moreoptions[6]]]=0;
2134           keystatus[keys[moreoptions[7]]]=0;
2135      }
2136      #endif
2137 
2138      oldmousebstatus = bstatus;
2139      if( (locbits&2048) > 0 ) {
2140           oldmousebstatus &= ~1;
2141      }
2142 
2143      // trap print scrn key
2144      if( keystatus[0xb7] > 0 ) {
2145           keystatus[0xb7] = 0;
2146           //printscreeninterrupt();
2147      }
2148 
2149      // F9 brightness
2150      if( keystatus[67] > 0 ) {
2151           keystatus[67] = 0;
2152           brightness++;
2153           if( brightness > 8 ) brightness = 0;
2154           setbrightness(brightness);
2155      }
2156 
2157     #ifdef OOGIE
2158      // F10 adjust bias threshhold
2159      if (keystatus[68] != 0) {
2160           keystatus[68]=0;
2161           if (dimensionmode[screenpeek] != 3) {
2162                setup3dscreen();
2163           }
2164           else {
2165                dimensionmode[screenpeek]=2;
2166                setview(0L,0L,xdim-1,(ydim-1)>>detailmode);
2167           }
2168      }
2169     #endif
2170 
2171      if( typemode == 0 ) {
2172          #ifdef PARALLAX_SETTING_ACTIVE
2173           if( keystatus[0x19] > 0 ) {
2174                keystatus[0x19] = 0;
2175                parallaxtype++;
2176                if (parallaxtype > 2) parallaxtype = 0;
2177           }
2178          #endif
2179          #ifdef VISIBILITY_SETTING_ACTIVE
2180           if( (keystatus[0x38]|keystatus[0xb8]) > 0 ) {
2181                if (keystatus[0x4a] > 0)  // Keypad -
2182                     visibility = min(visibility+(visibility>>3),16384);
2183                if (keystatus[0x4e] > 0)  // Keypad +
2184                     visibility = max(visibility-(visibility>>3),128);
2185           }
2186          #endif
2187           // if typing mode reset kbrd fifo
2188           if( (keystatus[keys[18]]) > 0 ) {
2189                keystatus[keys[18]] = 0;
2190                typemode = 1;
2191 // TODO               keyfifoplc = keyfifoend;
2192           }
2193      }
2194      else {
2195 
2196          #if 0 // TODO
2197           while( keyfifoplc != keyfifoend )
2198           {
2199                ch = keyfifo[keyfifoplc];
2200                keystate = keyfifo[(keyfifoplc+1)&(KEYFIFOSIZ-1)];
2201                keyfifoplc = ((keyfifoplc+2)&(KEYFIFOSIZ-1));
2202                if( keystate != 0 ) {
2203                     // backspace key
2204                     if( ch == 0xe ) {
2205                          if( typemessageleng == 0 ) {
2206                               typemode = 0;
2207                               break;
2208                          }
2209                          typemessageleng--;
2210                     }
2211                     if( ch == 0xf ) {
2212                          keystatus[0xf] = 0;
2213                          typemode = 0;
2214                          break;
2215                     }
2216                     // either enter key
2217                     if( (ch == 0x1c) || (ch == 0x9c) ) {
2218                          keystatus[0x1c] = 0; keystatus[0x9c] = 0;
2219                          if( typemessageleng > 0 ) {
2220                               tempbuf[0] = 2;
2221                               // sending text is message type 4
2222                               for( j=typemessageleng-1; j>=0; j-- ) {
2223                                    tempbuf[j+1] = typemessage[j];
2224                               }
2225                               for( i=connecthead; i>=0; i=connectpoint2[i] ) {
2226                                    if( i != myconnectindex ) {
2227                                         sendpacket(i,packetbuf,typemessageleng+1);
2228                                    }
2229                               }
2230                               typemessageleng = 0;
2231                          }
2232                          typemode = 0;
2233                          break;
2234                     }
2235                     if( (typemessageleng < 159) && (ch < 128) ) {
2236                          if( (keystatus[0x2a]|keystatus[0x36]) != 0 ) {
2237                               ch = scantoascwithshift[ch];
2238                          }
2239                          else {
2240                               ch = scantoasc[ch];
2241                          }
2242                          if( ch != 0 ) {
2243                               typemessage[typemessageleng++] = ch;
2244                          }
2245                     }
2246                }
2247           }
2248           #endif
2249 
2250           // here's a trick of making key repeat after a 1/2 second
2251           if( keystatus[0xe] > 0 ) {
2252                if( keystatus[0xe] < 30 ) {
2253                     keystatus[0xe] += TICSPERFRAME;
2254                }
2255                else {
2256                     if( typemessageleng == 0 ) {
2257                          typemode = 0;
2258                     }
2259                     else {
2260                          typemessageleng--;
2261                     }
2262                }
2263           }
2264      }
2265 
2266      tekprivatekeys();
2267 }
2268 
2269 void
playback()2270 playback()
2271 {
2272      int i, j, k;
2273 
2274      ready2send = 0;
2275      recstat = 0; i = reccnt;
2276      while (keystatus[1] == 0)
2277      {
2278           while (((int)totalclock) >= lockclock+TICSPERFRAME)
2279           {
2280                if (i >= reccnt)
2281                {
2282                     prepareboard(boardfilename);
2283                     for(i=connecthead;i>=0;i=connectpoint2[i])
2284                          initplayersprite((short)i);
2285                     resettiming(); ototalclock = 0; gotlastpacketclock = 0;
2286                     i = 0;
2287                }
2288 
2289                k = 0;
2290                for(j=connecthead;j>=0;j=connectpoint2[j])
2291                {
2292                     fsyncvel[j] = recsyncvel[i][k];
2293                     fsyncsvel[j] = recsyncsvel[i][k];
2294                     fsyncangvel[j] = recsyncangvel[i][k];
2295                     fsyncbits[j] = recsyncbits[i][k];
2296                     k++;
2297                }
2298                movethings(); domovethings();
2299                i++;
2300           }
2301           drawscreen(screenpeek,(((int)totalclock)-lockclock)*(65536/TICSPERFRAME));
2302 
2303           if (keystatus[keys[15]] > 0)
2304           {
2305                keystatus[keys[15]] = 0;
2306 
2307                screenpeek = connectpoint2[screenpeek];
2308                if (screenpeek < 0) screenpeek = connecthead;
2309           }
2310           if (keystatus[keys[14]] > 0)
2311           {
2312                keystatus[keys[14]] = 0;
2313                dimensionmode[screenpeek]++;
2314                if (dimensionmode[screenpeek] > 3) dimensionmode[screenpeek] = 1;
2315                if (dimensionmode[screenpeek] == 2) videoSetViewableArea(0L,0L,xdim-1,(ydim-1)>>detailmode);
2316                if (dimensionmode[screenpeek] == 3) setup3dscreen();
2317           }
2318      }
2319 
2320      musicoff();
2321 
2322      uninitmultiplayers();
2323      //uninittimer();
2324      uninitinput();
2325      engineUnInit();
2326      uninitsb();
2327      uninitgroupfile();
2328      cduninit();
2329      exit(0);
2330 }
2331 
2332 void
doanimations()2333 doanimations()
2334 {
2335      int i, j;
2336 
2337      for(i=animatecnt-1;i>=0;i--)
2338      {
2339           j = *animateptr[i];
2340 
2341           if (j < animategoal[i])
2342                j = min(j+animatevel[i]*TICSPERFRAME,animategoal[i]);
2343           else
2344                j = max(j-animatevel[i]*TICSPERFRAME,animategoal[i]);
2345           animatevel[i] += animateacc[i];
2346 
2347           *animateptr[i] = j;
2348 
2349           if (j == animategoal[i])
2350           {
2351                animatecnt--;
2352                if (i != animatecnt)
2353                {
2354                     animateptr[i] = animateptr[animatecnt];
2355                     animategoal[i] = animategoal[animatecnt];
2356                     animatevel[i] = animatevel[animatecnt];
2357                     animateacc[i] = animateacc[animatecnt];
2358                }
2359           }
2360      }
2361 }
2362 
2363 int
getanimationgoal(int * animptr)2364 getanimationgoal(int *animptr)
2365 {
2366      int i;
2367 
2368      for(i=animatecnt-1;i>=0;i--)
2369           if (animptr == animateptr[i]) return(i);
2370      return(-1);
2371 }
2372 
2373 int
setanimation(int * animptr,int thegoal,int thevel,int theacc)2374 setanimation(int *animptr, int thegoal, int thevel, int theacc)
2375 {
2376      int i, j;
2377 
2378      if (animatecnt >= MAXANIMATES) return(-1);
2379 
2380      j = animatecnt;
2381      for(i=animatecnt-1;i>=0;i--)
2382           if (animptr == animateptr[i])
2383                { j = i; break; }
2384 
2385      animateptr[j] = animptr;
2386      animategoal[j] = thegoal;
2387      animatevel[j] = thevel;
2388      animateacc[j] = theacc;
2389      if (j == animatecnt) animatecnt++;
2390      return(j);
2391 }
2392 
2393 void
checkmasterslaveswitch()2394 checkmasterslaveswitch()
2395 {
2396      int i, j;
2397 
2398      if (option[4] == 0) return;
2399 
2400      i = connecthead; j = connectpoint2[i];
2401      while (j >= 0)
2402      {
2403           if ((syncbits[j]&512) > 0)
2404           {
2405                connectpoint2[i] = connectpoint2[j];
2406                connectpoint2[j] = connecthead;
2407                connecthead = (short)j;
2408 
2409                olocvel = locvel+1; olocvel2 = locvel2+1;
2410                olocsvel = locsvel+1; olocsvel2 = locsvel2+1;
2411                olocangvel = locangvel+1; olocangvel2 = locangvel2+1;
2412                olocbits = locbits+1; olocbits2 = locbits2+1;
2413                for(i=0;i<MAXPLAYERS;i++)
2414                {
2415                     osyncvel[i] = fsyncvel[i]+1;
2416                     osyncsvel[i] = fsyncsvel[i]+1;
2417                     osyncangvel[i] = fsyncangvel[i]+1;
2418                     osyncbits[i] = fsyncbits[i]+1;
2419                }
2420 
2421                syncvalplc = 0L; othersyncvalplc = 0L;
2422                syncvalend = 0L; othersyncvalend = 0L;
2423                syncvalcnt = 0L; othersyncvalcnt = 0L;
2424 
2425                totalclock = lockclock;
2426                ototalclock = lockclock;
2427                gotlastpacketclock = lockclock;
2428                masterslavetexttime = lockclock;
2429                ready2send = 1;
2430                return;
2431           }
2432           i = j; j = connectpoint2[i];
2433      }
2434 }
2435 
2436 void
faketimerhandler()2437 faketimerhandler()
2438 {
2439      short other;
2440      int i, j, k, l;
2441 
2442      if (((int)totalclock) < ototalclock+TICSPERFRAME) return;
2443      if (ready2send == 0) return;
2444      ototalclock = (int)totalclock;
2445 
2446      // I am the MASTER (or 1 player game)
2447      if ((myconnectindex == connecthead) || (option[4] == 0))
2448      {
2449           if (option[4] != 0)
2450                getpackets();
2451 
2452           if (getoutputcirclesize() < 16)
2453           {
2454                getinput();
2455                fsyncvel[myconnectindex] = locvel;
2456                fsyncsvel[myconnectindex] = locsvel;
2457                fsyncangvel[myconnectindex] = locangvel;
2458                fsyncbits[myconnectindex] = locbits;
2459 
2460                if (option[4] != 0)
2461                {
2462                     packetbuf[0] = 0;
2463                     j = ((numplayers+1)>>1)+1;
2464                     for(k=1;k<j;k++) packetbuf[k] = 0;
2465                     k = (1<<3);
2466                     for(i=connecthead;i>=0;i=connectpoint2[i])
2467                     {
2468                          l = 0;
2469                          if (fsyncvel[i] != osyncvel[i]) packetbuf[j++] = fsyncvel[i], l |= 1;
2470 //** Les START - 09/27/95
2471                          if (fsyncsvel[i] != osyncsvel[i]) {
2472                              packetbuf[j++]=(fsyncsvel[i]&0xFF);
2473                              packetbuf[j++]=(fsyncsvel[i]>>8);
2474                               l|=2;
2475                          }
2476                          if (fsyncangvel[i] != osyncangvel[i]) {
2477                              packetbuf[j++]=(fsyncangvel[i]&0xFF);
2478                              packetbuf[j++]=(fsyncangvel[i]>>8);
2479                               l|=4;
2480                          }
2481 //** Les END   - 09/27/95
2482                          if (fsyncbits[i] != osyncbits[i])
2483                          {
2484                               tempbuf[j++] = (fsyncbits[i]&255);
2485                               tempbuf[j++] = ((fsyncbits[i]>>8)&255);
2486                               l |= 8;
2487                          }
2488                          tempbuf[k>>3] |= (l<<(k&7));
2489                          k += 4;
2490 
2491                          osyncvel[i] = fsyncvel[i];
2492                          osyncsvel[i] = fsyncsvel[i];
2493                          osyncangvel[i] = fsyncangvel[i];
2494                          osyncbits[i] = fsyncbits[i];
2495                     }
2496 #if 0
2497                     while (syncvalplc != syncvalend)
2498                     {
2499                          tempbuf[j] = (unsigned char)(syncval[syncvalplc]&255);
2500                          tempbuf[j+1] = (unsigned char)((syncval[syncvalplc]>>8)&255);
2501                          j += 2;
2502                          syncvalplc = ((syncvalplc+1)&(MOVEFIFOSIZ-1));
2503                     }
2504 #endif
2505                     for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
2506                          sendpacket(i, packetbuf,j);
2507                }
2508                else if (numplayers == 2)
2509                {
2510                     if (keystatus[0xb5] > 0)
2511                     {
2512                          keystatus[0xb5] = 0;
2513                          locselectedgun2++;
2514                          if (locselectedgun2 >= 3) locselectedgun2 = 0;
2515                     }
2516 
2517                     // second player on 1 computer mode
2518                     locvel2 = min(max(vel2,-128+8),127-8);
2519                     locsvel2 = min(max(svel2,-128+8),127-8);
2520                     locangvel2 = min(max(angvel2,-128+16),127-16);
2521                     locbits2 = (locselectedgun2<<13);
2522                     locbits2 |= keystatus[0x45];                  //Stand high
2523                     locbits2 |= (keystatus[0x47]<<1);             //Stand low
2524                     locbits2 |= (1<<8);                           //Run
2525                     locbits2 |= (keystatus[0x49]<<2);             //Look up
2526                     locbits2 |= (keystatus[0x37]<<3);             //Look down
2527                     locbits2 |= (keystatus[0x50]<<10);            //Space
2528                     locbits2 |= (keystatus[0x52]<<11);            //Shoot
2529 
2530                     other = connectpoint2[myconnectindex];
2531                     if (other < 0) other = connecthead;
2532 
2533                     fsyncvel[other] = locvel2;
2534                     fsyncsvel[other] = locsvel2;
2535                     fsyncangvel[other] = locangvel2;
2536                     fsyncbits[other] = locbits2;
2537                }
2538                movethings();  //Move EVERYTHING (you too!)
2539           }
2540      }
2541      else                        //I am a SLAVE
2542      {
2543           getpackets();
2544 
2545           if (getoutputcirclesize() < 16)
2546           {
2547                getinput();
2548 
2549                packetbuf[0] = 1; k = 0;
2550                j = 2;
2551 
2552                if (locvel != olocvel) packetbuf[j++] = locvel, k |= 1;
2553 //** Les START - 09/27/95
2554                if (locsvel != olocsvel) {
2555                    packetbuf[j++]=locsvel&0xFF;
2556                    packetbuf[j++]=(locsvel>>8);
2557                     k|=2;
2558                }
2559                if (locangvel != olocangvel) {
2560                    packetbuf[j++]=locangvel&0xFF;
2561                    packetbuf[j++]=(locangvel>>8);
2562                     k|=4;
2563                }
2564 //** Les END   - 09/27/95
2565                if ((locbits^olocbits)&0x00ff) packetbuf[j++] = (locbits&255), k |= 8;
2566                if ((locbits^olocbits)&0xff00) packetbuf[j++] = ((locbits>>8)&255), k |= 16;
2567 
2568                packetbuf[1] = k;
2569 
2570                olocvel = locvel;
2571                olocsvel = locsvel;
2572                olocangvel = locangvel;
2573                olocbits = locbits;
2574 
2575                sendpacket(connecthead, packetbuf,j);
2576           }
2577      }
2578 }
2579 
2580 void
getpackets()2581 getpackets()
2582 {
2583      int i, j, k, l;
2584      int other, tempbufleng;
2585 
2586      if (option[4] == 0) return;
2587 
2588      while ((tempbufleng = getpacket(&other, packetbuf)) > 0)
2589      {
2590           switch(packetbuf[0])
2591           {
2592                case 0:  //[0] (receive master sync buffer)
2593                     j = ((numplayers+1)>>1)+1; k = (1<<3);
2594                     for(i=connecthead;i>=0;i=connectpoint2[i])
2595                     {
2596                          l = (packetbuf[k>>3]>>(k&7));
2597                          if (l&1) fsyncvel[i] = packetbuf[j++];
2598 //** Les START - 09/27/95
2599                          if (l&2) {
2600                               fsyncsvel[i]= packetbuf[j++];
2601                               fsyncsvel[i]|=(packetbuf[j++]<<8);
2602                          }
2603                          if (l&4) {
2604                               fsyncangvel[i]= packetbuf[j++];
2605                               fsyncangvel[i]|=(packetbuf[j++]<<8);
2606                          }
2607 //** Les END   - 09/27/95
2608                          if (l&8)
2609                          {
2610                               fsyncbits[i] = ((short)packetbuf[j])+(((short)packetbuf[j+1])<<8);
2611                               j += 2;
2612                          }
2613                          k += 4;
2614                     }
2615 #if 0
2616                     while (j != tempbufleng)
2617                     {
2618                          othersyncval[othersyncvalend] = ((int)tempbuf[j]);
2619                          othersyncval[othersyncvalend] += (((int)tempbuf[j+1])<<8);
2620                          j += 2;
2621                          othersyncvalend = ((othersyncvalend+1)&(MOVEFIFOSIZ-1));
2622                     }
2623 
2624                     i = 0;
2625                     while (syncvalplc != syncvalend)
2626                     {
2627                          if (othersyncvalcnt > syncvalcnt)
2628                          {
2629                               if (i == 0) syncstat = 0, i = 1;
2630                               syncstat |= (syncval[syncvalplc]^othersyncval[syncvalplc]);
2631                          }
2632                          syncvalplc = ((syncvalplc+1)&(MOVEFIFOSIZ-1));
2633                          syncvalcnt++;
2634                     }
2635                     while (othersyncvalplc != othersyncvalend)
2636                     {
2637                          if (syncvalcnt > othersyncvalcnt)
2638                          {
2639                               if (i == 0) syncstat = 0, i = 1;
2640                               syncstat |= (syncval[othersyncvalplc]^othersyncval[othersyncvalplc]);
2641                          }
2642                          othersyncvalplc = ((othersyncvalplc+1)&(MOVEFIFOSIZ-1));
2643                          othersyncvalcnt++;
2644                     }
2645 #endif
2646 
2647                 movethings();        //Move all players and sprites
2648                     break;
2649                case 1:  //[1] (receive slave sync buffer)
2650                     j = 2; k = packetbuf[1];
2651                     if (k&1) fsyncvel[other] = packetbuf[j++];
2652 //** Les START - 09/27/95
2653                      if (k&2) {
2654                          fsyncsvel[other]= packetbuf[j++];
2655                          fsyncsvel[other]|=(packetbuf[j++]<<8);
2656                      }
2657                      if (k&4) {
2658                          fsyncangvel[other]= packetbuf[j++];
2659                          fsyncangvel[other]|=(packetbuf[j++]<<8);
2660                      }
2661 //** Les END   - 09/27/95
2662                     if (k&8) fsyncbits[other] = ((fsyncbits[other]&0xff00)|((short)packetbuf[j++]));
2663                     if (k&16) fsyncbits[other] = ((fsyncbits[other]&0x00ff)|(((short)packetbuf[j++])<<8));
2664                     break;
2665                case 2:
2666                     getmessageleng = tempbufleng-1;
2667                     for(j=getmessageleng-1;j>=0;j--) getmessage[j] = packetbuf[j+1];
2668                     getmessagetimeoff = ((int)totalclock)+360+(getmessageleng<<4);
2669                     break;
2670                case 3:
2671                     break;
2672               #ifdef NETNAMES
2673                case 8:
2674                     memcpy(netnames[packetbuf[1]],&packetbuf[2],10);
2675                     netnames[packetbuf[1]][10]=0;
2676                     break;
2677               #endif
2678                case 5:
2679                     playerreadyflag[other] = packetbuf[1];
2680                     if ((other == connecthead) && (packetbuf[1] == 2))
2681                          sendpacket(connecthead, packetbuf,2);
2682                     break;
2683                case 255:  //[255] (logout)
2684                     deletesprite(playersprite[other]);
2685                     sprintf(tektempbuf,"%2d %8s HAS QUIT", other,netnames[other]);
2686                     showmessage(tektempbuf);
2687                     break;
2688           }
2689      }
2690 }
2691 
2692 void
waitforeverybody()2693 waitforeverybody()
2694 {
2695      int i, j, oldtotalclock;
2696 
2697      if (numplayers < 2) return;
2698 
2699      if (myconnectindex == connecthead)
2700      {
2701           for(j=1;j<=2;j++)
2702           {
2703                for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
2704                     playerreadyflag[i] = 0;
2705                oldtotalclock = ((int)totalclock)-8;
2706                do
2707                {
2708                     getpackets();
2709                     if (((int)totalclock) >= oldtotalclock+8)
2710                     {
2711                          oldtotalclock = (int)totalclock;
2712                          packetbuf[0] = 5;
2713                          packetbuf[1] = j;
2714                          for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
2715                               if (playerreadyflag[i] != j) sendpacket(i, packetbuf,2);
2716                     }
2717                     for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
2718                          if (playerreadyflag[i] != j) break;
2719                } while (i >= 0);
2720           }
2721      }
2722      else
2723      {
2724           playerreadyflag[connecthead] = 0;
2725           while (playerreadyflag[connecthead] != 2)
2726           {
2727                getpackets();
2728                if (playerreadyflag[connecthead] == 1)
2729                {
2730                     playerreadyflag[connecthead] = 0;
2731                     sendpacket(connecthead, packetbuf,2);
2732                }
2733           }
2734      }
2735 }
2736 
2737 #if 0
2738 unsigned short
2739 getsyncstat()
2740 {
2741      int i, j;
2742      unsigned short crc;
2743      spritetype *spr;
2744 
2745      crc = 0;
2746      updatecrc16(crc,randomseed); updatecrc16(crc,randomseed>>8);
2747      for(i=connecthead;i>=0;i=connectpoint2[i])
2748      {
2749           updatecrc16(crc,posx[i]);
2750           updatecrc16(crc,posy[i]);
2751           updatecrc16(crc,posz[i]);
2752           updatecrc16(crc,ang[i]);
2753           updatecrc16(crc,horiz[i]);
2754           updatecrc16(crc,health[i]);
2755      }
2756 
2757     #if SPRITES_CRC_CHECK
2758      for( i=1000; i>=0; i-- ) {
2759           for( j=headspritestat[i]; j>=0; j=nextspritestat[j] ) {
2760                spr = &sprite[j];
2761                updatecrc16(crc,spr->x); //if (syncstat != 0) printf("%ld ",spr->x);
2762                updatecrc16(crc,spr->y); //if (syncstat != 0) printf("%ld ",spr->y);
2763                updatecrc16(crc,spr->z); //if (syncstat != 0) printf("%ld ",spr->z);
2764                updatecrc16(crc,spr->ang); //if (syncstat != 0) printf("%ld ",spr->ang);
2765           }
2766      }
2767     #endif
2768 
2769      return(crc);
2770 }
2771 #endif
2772 
2773