1 /***************************************************************************
2  *    WITCHAVEN.C  - main game code for Witchaven game                     *
3  *                                                                         *
4  ***************************************************************************/
5 
6 #define WHAVEN
7 #define GAME
8 #define SVGA
9 
10 #include "witchaven.h"
11 
12 #include "keyboard.h"
13 #include "control.h"
14 #include "config.h"
15 #include "compat.h"
16 #include "baselayer.h"
17 #include "renderlayer.h"
18 #include "build.h"
19 #include "common.h"
20 #include "objects.h"
21 #include "player.h"
22 #include "effects.h"
23 #include "menu.h"
24 #include "input.h"
25 #include "animation.h"
26 #include "tags.h"
27 #include "network.h"
28 #include "sound.h"
29 #include "grpscan.h"
30 #include "osdcmds.h"
31 #include "common_game.h"
32 
33 #ifdef _WIN32
34 # include "winbits.h"
35 #endif /* _WIN32 */
36 
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40     extern const char* s_buildRev;
41     extern const char* s_buildTimestamp;
42 #ifdef __cplusplus
43 }
44 #endif
45 
46 const char* AppProperName = APPNAME;
47 const char* AppTechnicalName = APPBASENAME;
48 
49 static char g_rootDir[BMAX_PATH];
50 
51 int mouseaiming, aimmode, mouseflip;
52 int runkey_mode, auto_run;
53 
54 
55 #if defined GEKKO
56 # define FPS_YOFFSET 16
57 #else
58 # define FPS_YOFFSET 0
59 #endif
60 
61 
M32RunScript(const char * s)62 void M32RunScript(const char* s) { UNREFERENCED_PARAMETER(s); }
app_crashhandler(void)63 void app_crashhandler(void)
64 {
65     shutdown();
66 }
67 
68 void InstallEngine();
69 
70 int32_t synctics;
71 int32_t globhiz, globloz, globhihit, globlohit;
72 
73 char option[NUMOPTIONS] = { 0,0,0,0,0,0,1,0 };
74 
75 // TODO / FIXME / CHECKME - old Build visibility variable. What happened it?
76 int32_t visibility;
77 
78 int svga = 0; // REVERT / CHECKME - was originally 0
79 int delaycnt, engineinitflag, timerinitflag, videoinitflag;
80 int netgame = 0;
81 int gametype;
82 int godmode = 0; // WH2
83 
84 char boardname[BMAX_PATH];
85 char tempboard[BMAX_PATH];
86 char loadgamename[BMAX_PATH];
87 
88 int32_t* animateptr[MAXANIMATES];
89 int32_t animategoal[MAXANIMATES];
90 int32_t animatevel[MAXANIMATES];
91 int32_t animatecnt = 0;
92 
93 // WH2 variables
94 int treasurescnt = 0;
95 int treasuresfound = 0;
96 int killcnt = 0;
97 int kills = 0;
98 int expgained = 0;
99 int bonus = 0;
100 int overtheshoulder;
101 static char detailmode = 0;
102 static char ready2send = 0;
103 int32_t screentilt = 0;
104 extern int32_t cachecount, transarea;
105 extern char chainstat;
106 
107 
108 uint32_t flags32[32]={
109     0x80000000,0x40000000,0x20000000,0x10000000,
110     0x08000000,0x04000000,0x02000000,0x01000000,
111     0x00800000,0x00400000,0x00200000,0x00100000,
112     0x00080000,0x00040000,0x00020000,0x00010000,
113     0x00008000,0x00004000,0x00002000,0x00001000,
114     0x00000800,0x00000400,0x00000200,0x00000100,
115     0x00000080,0x00000040,0x00000020,0x00000010,
116     0x00000008,0x00000004,0x00000002,0x00000001
117 };
118 
119 extern short cddrive;
120 
121 int32_t followx, followy;
122 
123 int ratcnt = 0;
124 int gameactivated = 0;
125 int escapetomenu = 0;
126 
127 int32_t difficulty = 2;
128 int32_t goreon = 1;
129 
130 int32_t totsynctics, frames;
131 
132 extern bool followmode;
133 extern int loadedgame;
134 extern char tempbuf[50];
135 extern int musiclevel;
136 extern int digilevel;
137 
138 struct Delayitem delayitem[MAXSECTORS];
139 
140 int32_t brightness  = 0;
141 int32_t gbrightness = 0;
142 
143 int swingcnt;
144 short spikecnt;
145 short spikesector[64];
146 
147 short goblinspritelist[100];
148 short goblinwarcnt;
149 
150 short lavadrylandsector[32];
151 short lavadrylandcnt;
152 
153 short xpanningsectorlist[64], xpanningsectorcnt;
154 short ypanningwalllist[64], ypanningwallcnt;
155 short floorpanninglist[64], floorpanningcnt;
156 short skypanlist[64], skypancnt;
157 
158 short crushsectorlist[32], crushsectorcnt;
159 short crushsectoranim[32], crushsectordone[32];
160 
161 short revolvesector[16], revolveang[16], revolveclip[16], revolvecnt;
162 int revolvex[16][16], revolvey[16][16];
163 int revolvepivotx[16], revolvepivoty[16];
164 
165 short dragsectorlist[16], dragxdir[16], dragydir[16], dragsectorcnt;
166 int dragx1[16], dragy1[16], dragx2[16], dragy2[16], dragfloorz[16];
167 
168 short warpsectorlist[16], warpsectorcnt;
169 
170 short bobbingsectorlist[16], bobbingsectorcnt;
171 
172 //JSA ends
173 
174 int justteleported = 0;
175 
176 short ironbarsector[16],ironbarscnt;
177 int ironbarsgoal1[16],ironbarsgoal2[16];
178 short ironbarsdone[16], ironbarsanim[16];
179 int ironbarsgoal[16];
180 
181 extern int mapon;
182 int mapflag;
183 
184 extern char option2[];
185 extern short mousekeys[];
186 
187 static int32_t nonsharedtimer;
188 
189 int adjusthp(int hp);
190 void playloop();
191 void readpalettetable();
192 void drawoverheadmap(Player *plr);
193 
194 int32_t g_commandSetup = 0;
195 int32_t g_noSetup = 0;
196 int32_t g_noAutoLoad = 0;
197 
198 //////////
199 
200 enum gametokens
201 {
202     T_INCLUDE = 0,
203     T_INTERFACE = 0,
204     T_LOADGRP = 1,
205     T_MODE = 1,
206     T_CACHESIZE = 2,
207     T_ALLOW = 2,
208     T_NOAUTOLOAD,
209     T_INCLUDEDEFAULT,
210     T_MUSIC,
211     T_SOUND,
212     T_FILE,
213     T_CUTSCENE,
214     T_ANIMSOUNDS,
215     T_NOFLOORPALRANGE,
216     T_ID,
217     T_MINPITCH,
218     T_MAXPITCH,
219     T_PRIORITY,
220     T_TYPE,
221     T_DISTANCE,
222     T_VOLUME,
223     T_DELAY,
224     T_RENAMEFILE,
225     T_GLOBALGAMEFLAGS,
226     T_ASPECT,
227     T_FORCEFILTER,
228     T_FORCENOFILTER,
229     T_TEXTUREFILTER,
230     T_NEWGAMECHOICES,
231     T_CHOICE,
232     T_NAME,
233     T_LOCKED,
234     T_HIDDEN,
235     T_USERCONTENT,
236 };
237 
238 int witchaven_globalflags;
239 
240 static int parsedefinitions_game(scriptfile*, int);
241 
parsedefinitions_game_include(const char * fileName,scriptfile * pScript,const char * cmdtokptr,int const firstPass)242 static void parsedefinitions_game_include(const char* fileName, scriptfile* pScript, const char* cmdtokptr, int const firstPass)
243 {
244     scriptfile* included = scriptfile_fromfile(fileName);
245 
246     if (!included)
247     {
248         if (!Bstrcasecmp(cmdtokptr, "null") || pScript == NULL) // this is a bit overboard to prevent unused parameter warnings
249         {
250             // initprintf("Warning: Failed including %s as module\n", fn);
251         }
252         /*
253                 else
254                     {
255                     initprintf("Warning: Failed including %s on line %s:%d\n",
256                                fn, script->filename,scriptfile_getlinum(script,cmdtokptr));
257                     }
258         */
259     }
260     else
261     {
262         parsedefinitions_game(included, firstPass);
263         scriptfile_close(included);
264     }
265 }
266 
parsedefinitions_game(scriptfile * pScript,int firstPass)267 static int parsedefinitions_game(scriptfile* pScript, int firstPass)
268 {
269     int   token;
270     char* pToken;
271 
272     static const tokenlist tokens[] =
273     {
274         { "include",         T_INCLUDE          },
275         { "#include",        T_INCLUDE          },
276         { "includedefault",  T_INCLUDEDEFAULT   },
277         { "#includedefault", T_INCLUDEDEFAULT   },
278         { "loadgrp",         T_LOADGRP          },
279         { "cachesize",       T_CACHESIZE        },
280         { "noautoload",      T_NOAUTOLOAD       },
281         { "renamefile",      T_RENAMEFILE       },
282         { "globalgameflags", T_GLOBALGAMEFLAGS  },
283     };
284 
285     do
286     {
287         token = getatoken(pScript, tokens, ARRAY_SIZE(tokens));
288         pToken = pScript->ltextptr;
289 
290         switch (token)
291         {
292             case T_LOADGRP:
293             {
294                 char* fileName;
295 
296                 pathsearchmode = 1;
297                 if (!scriptfile_getstring(pScript, &fileName) && firstPass)
298                 {
299                     if (initgroupfile(fileName) == -1)
300                         initprintf("Could not find file \"%s\".\n", fileName);
301                     else
302                     {
303                         initprintf("Using file \"%s\" as game data.\n", fileName);
304                         if (!g_noAutoLoad && !gSetup.noautoload)
305                             G_DoAutoload(fileName);
306                     }
307                 }
308 
309                 pathsearchmode = 0;
310             }
311             break;
312             case T_CACHESIZE:
313             {
314                 int32_t cacheSize;
315 
316                 if (scriptfile_getnumber(pScript, &cacheSize) || !firstPass)
317                     break;
318 
319                 if (cacheSize > 0)
320                     MAXCACHE1DSIZE = cacheSize << 10;
321             }
322             break;
323             case T_INCLUDE:
324             {
325                 char* fileName;
326 
327                 if (!scriptfile_getstring(pScript, &fileName))
328                     parsedefinitions_game_include(fileName, pScript, pToken, firstPass);
329 
330                 break;
331             }
332             case T_INCLUDEDEFAULT:
333             {
334                 parsedefinitions_game_include(G_DefaultDefFile(), pScript, pToken, firstPass);
335                 break;
336             }
337             case T_NOAUTOLOAD:
338             if (firstPass)
339                 g_noAutoLoad = 1;
340             break;
341             case T_GLOBALGAMEFLAGS: scriptfile_getnumber(pScript, &witchaven_globalflags); break;
342             case T_EOF: return 0;
343             default: break;
344         }
345     } while (1);
346 
347     return 0;
348 }
349 
loaddefinitions_game(const char * fileName,int32_t firstPass)350 int loaddefinitions_game(const char* fileName, int32_t firstPass)
351 {
352     scriptfile* pScript = scriptfile_fromfile(fileName);
353 
354     if (pScript)
355         parsedefinitions_game(pScript, firstPass);
356 
357     for (char const* m : g_defModules)
358         parsedefinitions_game_include(m, NULL, "null", firstPass);
359 
360     if (pScript)
361         scriptfile_close(pScript);
362 
363     scriptfile_clearsymbols();
364 
365     return 0;
366 }
367 
368 #define FPS_COLOR(x) ((x) ? COLOR_RED : COLOR_WHITE)
369 
370 #define COLOR_RED redcol
371 #define COLOR_WHITE whitecol
372 
373 #define LOW_FPS ((videoGetRenderMode() == REND_CLASSIC) ? 35 : 50)
374 #define SLOW_FRAME_TIME 20
375 
G_PrintFPS(void)376 static void G_PrintFPS(void)
377 {
378     static char tempbuf[256];
379     static int32_t frameCount;
380     static double cumulativeFrameDelay;
381     static double lastFrameTime;
382     static float lastFPS; // , minFPS = std::numeric_limits<float>::max(), maxFPS;
383     //static double minGameUpdate = std::numeric_limits<double>::max(), maxGameUpdate;
384 
385     double frameTime = timerGetHiTicks();
386     double frameDelay = frameTime - lastFrameTime;
387     cumulativeFrameDelay += frameDelay;
388 
389     if (frameDelay >= 0)
390     {
391         int32_t x = (xdim <= 640);
392 
393         if (r_showfps)
394         {
395             int32_t chars = Bsprintf(tempbuf, "%.1f ms, %5.1f fps", frameDelay, lastFPS);
396 
397             printext256(windowxy2.x - (chars << (3 - x)) + 1, windowxy1.y + 2 + FPS_YOFFSET, blackcol, -1, tempbuf, x);
398             printext256(windowxy2.x - (chars << (3 - x)), windowxy1.y + 1 + FPS_YOFFSET,
399                 FPS_COLOR(lastFPS < LOW_FPS), -1, tempbuf, x);
400         }
401 
402         if (cumulativeFrameDelay >= 1000.0)
403         {
404             lastFPS = 1000.f * frameCount / cumulativeFrameDelay;
405             // g_frameRate = Blrintf(lastFPS);
406             frameCount = 0;
407             cumulativeFrameDelay = 0.0;
408         }
409         frameCount++;
410     }
411     lastFrameTime = frameTime;
412 }
413 
faketimerhandler(void)414 void faketimerhandler(void)
415 {
416     return;
417 }
418 
419 //
420 //   basic text functions
421 //
422 
cls80x25(int top,int mid,int bot)423 void cls80x25(int top,int mid,int bot)
424 {
425 }
426 
tprintf(int x,int y,const char * fmt,...)427 void tprintf(int x, int y, const char *fmt,...)
428 {
429 }
430 
rp_delay(int goal)431 void rp_delay(int goal)
432 {
433     bool bExit = false;
434 
435     int32_t dagoal = (int)totalclock+goal;
436 
437     while (!bExit)
438     {
439         handleevents();
440         if (totalclock == dagoal) {
441             bExit = true;
442         }
443     }
444 }
445 
446 //
447 //   game code
448 //
449 
showadditionalinfo()450 void showadditionalinfo()
451 {
452     printf("average synctics = %ld\n", totsynctics / frames);
453 }
454 
455 int crashflag;
456 
shutdown()457 void shutdown()
458 {
459     CONFIG_WriteSetup(0);
460 
461 #if 0
462     int fil = open("pref.dat", O_BINARY|O_TRUNC|O_CREAT|O_WRONLY, S_IREAD | S_IWRITE);
463     if (fil != NULL)
464     {
465         write(fil, &goreon, 2);
466         write(fil, &brightness, 2);
467         write(fil, &gbrightness, 2);
468         write(fil, &digilevel, 2);
469         write(fil, &musiclevel, 2);
470         write(fil, &difficulty, 2);
471         close(fil);
472     }
473 #endif
474 
475     SND_Shutdown();
476 
477 //TODO   netshutdown();
478 
479 //    if (engineinitflag) {
480         engineUnInit();
481 //    }
482 
483     if (SoundMode) {
484 //TODO        SND_UnDoBuffers();
485     }
486 
487     if (videoinitflag) {
488 // TODO        setvmode(oldvmode);
489     }
490 
491     //CHECKME uninitkeys();
492     uninitgroupfile();
493 
494     if (crashflag) {
495         return;
496     }
497 
498     exit(EXIT_SUCCESS);
499 }
500 
crash(const char * fmt)501 void crash(const char* fmt)
502 {
503     crashflag = 1;
504     shutdown();
505 
506     printf("\n%s\n", fmt);
507     printf("\n\n\n\n\n\n\n\n");
508 }
509 
doanimations(int32_t numtics)510 void doanimations(int32_t numtics)
511 {
512     for (int i = animatecnt - 1; i >= 0; i--)
513     {
514         int animval = *animateptr[i];
515         if (animval < animategoal[i])
516         {
517             animval += (numtics * animatevel[i]);
518             if (animval > animategoal[i]) {
519                 animval = animategoal[i];
520             }
521         }
522         if (animval > animategoal[i])
523         {
524             animval -= (numtics * animatevel[i]);
525             if (animval < animategoal[i]) {
526                 animval = animategoal[i];
527             }
528         }
529         *animateptr[i] = animval;
530         if (animval == animategoal[i])
531         {
532             animatecnt--;
533             animateptr[i] = animateptr[animatecnt];
534             animategoal[i] = animategoal[animatecnt];
535             animatevel[i] = animatevel[animatecnt];
536         }
537     }
538 }
539 
getanimationgoal(int32_t * animptr)540 int32_t getanimationgoal(int32_t *animptr)
541 {
542     int j = -1;
543     for (int i = 0; i < animatecnt; i++)
544     {
545         if (animptr == animateptr[i])
546         {
547             j = i;
548             break;
549         }
550     }
551 
552     return j;
553 }
554 
setanimation(int32_t * animptr,int32_t thegoal,int32_t thevel)555 int32_t setanimation(int32_t*animptr, int32_t thegoal, int32_t thevel)
556 {
557     if (animatecnt >= MAXANIMATES-1) {
558         return(-1);
559     }
560 
561     int j = animatecnt;
562 
563     for (int i = 0; i < animatecnt; i++)
564     {
565         if (animptr == animateptr[i])
566         {
567             j = i;
568             break;
569         }
570     }
571 
572     animateptr[j]  = animptr;
573     animategoal[j] = thegoal;
574     animatevel[j]  = thevel;
575 
576     if (j == animatecnt) {
577         animatecnt++;
578     }
579 
580     return animatecnt - 1;
581 }
582 
setdelayfunc(void (* func)(int),int item,int delay)583 void setdelayfunc(void (*func)(int),int item,int delay)
584 {
585     for (int i = 0; i < delaycnt; i++)
586     {
587         if (delayitem[i].func == func && delayitem[i].item == item)
588         {
589             if (delay == 0) {
590                 delayitem[i].func = NULL;
591             }
592             delayitem[i].timer = delay;
593             return;
594         }
595     }
596 
597     if (delay > 0)
598     {
599         delayitem[delaycnt].func = func;
600         delayitem[delaycnt].item = item;
601         delayitem[delaycnt].timer = delay;
602         delaycnt++;
603     }
604 }
605 
dodelayitems(int tics)606 void dodelayitems(int tics)
607 {
608     int cnt = delaycnt;
609 
610     for (int i = 0; i < cnt; i++)
611     {
612         if (delayitem[i].func == NULL)
613         {
614             int j = delaycnt - 1;
615             memmove(&delayitem[i], &delayitem[j], sizeof(Delayitem));
616             delaycnt = j;
617         }
618 
619         if (delayitem[i].timer > 0)
620         {
621             if ((delayitem[i].timer -= tics) <= 0)
622             {
623                 delayitem[i].timer = 0;
624                 (*delayitem[i].func)(delayitem[i].item);
625                 delayitem[i].func = NULL;
626             }
627         }
628     }
629 }
630 
setup3dscreen()631 void setup3dscreen()
632 {
633     int32_t dax, day, dax2, day2;
634 
635     Player *plr = &player[pyrn];
636 
637     videoSetGameMode(gSetup.fullscreen, gSetup.xdim, gSetup.ydim, gSetup.bpp, 0);
638 
639     videoinitflag = 1;
640 
641 #if 0 // TODO
642     switch (option[0])
643     {
644         case 1:
645         {
646             if (svga == 0)
647             {
648                 dax = 160 - (plr->screensize >> 1);
649                 dax2 = dax + plr->screensize - 1;
650                 day = 84 - (((plr->screensize * 168) / 320) >> 1);
651                 day2 = STATUSSCREEN - 1;
652                 videoSetViewableArea(dax, day, dax2, day2);
653             }
654             else {
655                 videoSetViewableArea(0, 0, vesares[option[6] & 15][0] - 1, vesares[option[6] & 15][1] - 1);
656             }
657             break;
658         }
659         default:
660             videoSetViewableArea(0, 0, 319, 199);
661         break;
662     }
663 
664     if (svga == 0)
665     {
666         if(plr->screensize <= 320)
667             permanentwritesprite(0,0,BACKGROUND,0,0,0,319,199,0);
668         if(plr->screensize <= 320)
669             permanentwritesprite(0,200-46,NEWSTATUSBAR,0,0,0,319,199,0);
670     }
671     else if(svga == 1)
672     {
673         permanentwritesprite(0,0,SVGAMENU,0,0,0,639,239,0);
674         permanentwritesprite(0,240,SVGAMENU2,0,0,240,639,479,0);
675     }
676 #endif
677 }
678 
setupboard(char * fname)679 void setupboard(char* fname)
680 {
681     int endwall, i, j, k, startwall;
682     int32_t dax, day;
683     short treesize;
684     int32_t dasector;
685     int32_t dax2, day2;
686     int16_t daang;
687 
688     Player* plr = &player[pyrn];
689     randomseed = 17;
690 
691     vec3_t startPos;
692     int status = engineLoadBoard(fname, 0, &startPos, &daang, &plr->sector);
693     if (status == -2)
694         status = engineLoadBoardV5V6(fname, 0, &startPos, &daang, &plr->sector);
695 
696     if (status == -1) {
697         crash("Board not found");
698     }
699 
700     plr->x = startPos.x;
701     plr->y = startPos.y;
702     plr->z = startPos.z;
703 
704     plr->ang = daang;
705 
706 #ifdef YAX_ENABLE
707     yax_update(1);
708 #endif
709 
710     psky_t* pSky = tileSetupSky(0);
711 
712     pSky->tileofs[0] = 0;
713     pSky->tileofs[1] = 0;
714     pSky->tileofs[2] = 0;
715     pSky->tileofs[3] = 0;
716     pSky->yoffs = 256;
717     pSky->lognumtiles = 2;
718     pSky->horizfrac = 65536;
719     pSky->yscale = 65536;
720     parallaxtype = 2;
721     g_visibility = 2048;
722 
723     // TODO    precache();
724 
725     ratcnt = 0;
726     swingcnt = 0;
727     xpanningsectorcnt = 0;
728     ypanningwallcnt = 0;
729     floorpanningcnt = 0;
730     crushsectorcnt = 0;
731     revolvecnt = 0;
732     warpsectorcnt = 0;
733     dragsectorcnt = 0;
734     ironbarscnt = 0;
735     spikecnt = 0;
736     bobbingsectorcnt = 0;
737     goblinwarcnt = 0;
738     lavadrylandcnt = 0;
739 
740     for (i = 0; i < MAXSPRITES; i++) // setup sector effect options
741     {
742         if (sprite[i].picnum == FRED && sprite[i].pal == 1) {
743             deletesprite(i);
744         }
745 
746         if (sprite[i].picnum == RAT) {
747             ratcnt++;
748             if (ratcnt > 10) {
749                 deletesprite(i);
750             }
751         }
752 
753         if (sprite[i].picnum == SPAWN) {
754             deletesprite(i);
755         }
756 
757         if (sprite[i].picnum == TORCH) {
758             sprite[i].cstat &= ~3;
759             changespritestat(i, TORCHLIGHT);
760         }
761 
762         if (sprite[i].picnum == STANDINTORCH ||
763             sprite[i].picnum == BOWLOFFIRE) {
764             changespritestat(i, TORCHLIGHT);
765         }
766 
767         if (sprite[i].picnum == GLOW) {
768             changespritestat(i, GLOWLIGHT);
769         }
770 
771         if (sprite[i].picnum == SNDEFFECT) {
772             sector[sprite[i].sectnum].extra = sprite[i].lotag;
773             deletesprite(i);
774         }
775 
776         if (sprite[i].picnum == SNDLOOP) {      //loop on
777             sector[sprite[i].sectnum].extra = (32768 | (sprite[i].lotag << 1) | 1);
778             deletesprite(i);
779         }
780 
781         if (sprite[i].picnum == SNDLOOPOFF) {   //loop off
782             sector[sprite[i].sectnum].extra = (32768 | (sprite[i].lotag << 1));
783             deletesprite(i);
784         }
785 
786         if (sprite[i].lotag == 80)
787         {
788             ironbarsector[ironbarscnt] = sprite[i].sectnum;
789             ironbarsdone[ironbarscnt] = 0;
790             ironbarsanim[ironbarscnt] = i;
791             ironbarsgoal[ironbarscnt] = 0;
792             ironbarscnt++;
793         }
794 
795         if (sprite[i].statnum < MAXSTATUS)
796         {
797             switch (sprite[i].picnum)
798             {
799                 case GRONHAL:
800                 sprite[i].xrepeat = 30;
801                 sprite[i].yrepeat = 30;
802                 sprite[i].clipdist = 64;
803                 changespritestat(i, FACE);
804                 sprite[i].hitag = adjusthp(300);
805                 sprite[i].lotag = 100;
806                 sprite[i].cstat |= 0x101;
807                 sprite[i].extra = 4;
808                 break;
809                 case GRONMU:
810                 sprite[i].xrepeat = 30;
811                 sprite[i].yrepeat = 30;
812                 sprite[i].clipdist = 64;
813                 changespritestat(i, FACE);
814                 sprite[i].hitag = adjusthp(300);
815                 sprite[i].lotag = 100;
816                 sprite[i].cstat |= 0x101;
817                 sprite[i].extra = 2;
818                 break;
819                 case GRONSW:
820                 sprite[i].xrepeat = 30;
821                 sprite[i].yrepeat = 30;
822                 sprite[i].clipdist = 64;
823                 changespritestat(i, FACE);
824                 sprite[i].hitag = adjusthp(300);
825                 sprite[i].lotag = 100;
826                 sprite[i].cstat |= 0x101;
827                 sprite[i].extra = 0;
828                 break;
829                 case RAT:
830                 sprite[i].xrepeat = 32;
831                 sprite[i].yrepeat = 32;
832                 sprite[i].shade = 12;
833                 sprite[i].pal = 5;
834                 changespritestat(i, FACE);
835                 sprite[i].hitag = 10;
836                 sprite[i].lotag = 100;
837                 sprite[i].cstat = 0x101;
838                 break;
839                 case FISH:
840                 sprite[i].clipdist = 32;
841                 changespritestat(i, FACE);
842                 sprite[i].hitag = 10;
843                 sprite[i].lotag = 100;
844                 sprite[i].cstat |= 0x101;
845                 break;
846                 case WILLOW:
847                 sprite[i].xrepeat = 32;
848                 sprite[i].yrepeat = 32;
849                 sprite[i].clipdist = 64;
850                 changespritestat(i, FACE);
851                 sprite[i].hitag = adjusthp(400);
852                 sprite[i].lotag = 100;
853                 sprite[i].cstat |= 0x101;
854                 break;
855                 case DRAGON:
856                 sprite[i].xrepeat = 54;
857                 sprite[i].yrepeat = 54;
858                 sprite[i].clipdist = 128;
859                 changespritestat(i, FACE);
860                 sprite[i].hitag = adjusthp(900);
861                 sprite[i].lotag = 100;
862                 sprite[i].cstat |= 0x101;
863                 break;
864                 case DEVIL:
865                 case DEVILSTAND:
866                 sprite[i].xrepeat = 36;
867                 sprite[i].yrepeat = 36;
868                 sprite[i].clipdist = 64;
869                 changespritestat(i, FACE);
870                 if (sprite[i].pal == 2)
871                     sprite[i].hitag = adjusthp(60);
872                 else
873                     sprite[i].hitag = adjusthp(50);
874                 sprite[i].lotag = 100;
875                 sprite[i].cstat |= 0x101;
876                 break;
877                 case HANGMAN + 1:
878                 sprite[i].xrepeat = 28;
879                 sprite[i].yrepeat = 28;
880                 break;
881                 case HANGMAN:
882                 sprite[i].xrepeat = 28;
883                 sprite[i].yrepeat = 28;
884                 sprite[i].clipdist = 64;
885                 changespritestat(i, STAND);
886                 sprite[i].hitag = adjusthp(30);
887                 sprite[i].lotag = 100;
888                 sprite[i].cstat |= 0x101;
889                 break;
890                 case SKELETON:
891                 sprite[i].xrepeat = 24;
892                 sprite[i].yrepeat = 24;
893                 sprite[i].clipdist = 64;
894                 changespritestat(i, FACE);
895                 sprite[i].hitag = adjusthp(30);
896                 sprite[i].lotag = 100;
897                 sprite[i].cstat |= 0x101;
898                 break;
899                 case GOBLINDEAD:
900                 sprite[i].xrepeat = 36;
901                 sprite[i].yrepeat = 36;
902                 break;
903                 case GOBLIN:
904                 case GOBLINSTAND:
905                 if (sprite[i].hitag >= 90 && sprite[i].hitag <= 99)
906                 {
907                     if (sprite[i].pal == 0) {
908                         sprite[i].xrepeat = 36;
909                         sprite[i].yrepeat = 36;
910                     }
911                     else {
912                         sprite[i].xrepeat = 30;
913                         sprite[i].yrepeat = 36;
914                     }
915                     sprite[i].extra = 0;
916                     sprite[i].owner = 0;
917                     sprite[i].lotag = 100;
918                     sprite[i].cstat |= 0x101;
919                     sprite[i].clipdist = 64;
920                     goblinspritelist[goblinwarcnt] = i;
921                     goblinwarcnt++;
922                 }
923                 else
924                 {
925                     sprite[i].xrepeat = 36;
926                     sprite[i].yrepeat = 36;
927                     changespritestat(i, FACE);
928                     if (sprite[i].pal == 5)
929                         sprite[i].hitag = adjusthp(35);
930                     else if (sprite[i].pal == 4)
931                         sprite[i].hitag = adjusthp(25);
932                     else
933                         sprite[i].hitag = adjusthp(15);
934                     sprite[i].lotag = 100;
935                     sprite[i].cstat |= 0x101;
936                     if (rand() % 100 > 50)
937                         sprite[i].extra = 1;
938                     sprite[i].clipdist = 64;
939                 }
940                 break;
941                 case GOBLINCHILL:
942                 sprite[i].xrepeat = 36;
943                 sprite[i].yrepeat = 36;
944                 changespritestat(i, STAND);
945                 sprite[i].hitag = adjusthp(15);
946                 sprite[i].lotag = 30;
947                 sprite[i].cstat |= 0x101;
948                 if (rand() % 100 > 50)
949                     sprite[i].extra = 1;
950                 sprite[i].clipdist = 64;
951                 break;
952                 case FATWITCH:
953                 sprite[i].clipdist = 64;
954                 sprite[i].xrepeat = 32;
955                 sprite[i].yrepeat = 32;
956                 changespritestat(i, FACE);
957                 if (sprite[i].pal == 7)
958                     sprite[i].hitag = adjusthp(290);
959                 else
960                     sprite[i].hitag = adjusthp(280);
961                 sprite[i].lotag = 100;
962                 sprite[i].cstat |= 0x101;
963                 if (rand() % 100 > 50)
964                     sprite[i].extra = 1;
965                 break;
966                 case SKULLY:
967                 sprite[i].clipdist = 64;
968                 sprite[i].xrepeat = 32;
969                 sprite[i].yrepeat = 32;
970                 changespritestat(i, FACE);
971                 sprite[i].hitag = adjusthp(300);
972                 sprite[i].lotag = 100;
973                 sprite[i].cstat |= 0x101;
974                 if (rand() % 100 > 50)
975                     sprite[i].extra = 1;
976                 break;
977                 case MINOTAUR:
978                 sprite[i].clipdist = 64;
979                 changespritestat(i, FACE);
980                 sprite[i].hitag = adjusthp(100);
981                 sprite[i].lotag = 100;
982                 sprite[i].cstat |= 0x101;
983                 if (rand() % 100 > 50)
984                     sprite[i].extra = 1;
985                 break;
986                 case FRED:
987                 case FREDSTAND:
988                 if (sprite[i].pal == 1)
989                     break;
990                 sprite[i].xrepeat = 48;
991                 sprite[i].yrepeat = 48;
992                 changespritestat(i, FACE);
993                 sprite[i].hitag = adjusthp(40);
994                 sprite[i].lotag = 100;
995                 sprite[i].cstat |= 0x101;
996                 sprite[i].clipdist = 64;
997                 if (rand() % 100 > 50)
998                     sprite[i].extra = 1;
999                 break;
1000                 case KOBOLD:
1001                 // gave kobold x2 hp
1002                 sprite[i].clipdist = 64;
1003                 changespritestat(i, FACE);
1004                 if (sprite[i].pal == 8)
1005                     sprite[i].hitag = adjusthp(40);
1006                 else if (sprite[i].pal == 7)
1007                     sprite[i].hitag = adjusthp(60);
1008                 else
1009                     sprite[i].hitag = adjusthp(20);
1010                 sprite[i].lotag = 100;
1011                 sprite[i].xrepeat = sprite[i].yrepeat = 54;
1012                 sprite[i].cstat |= 0x101;
1013                 break;
1014                 case SPIDER:
1015                 sprite[i].xrepeat = 24;
1016                 sprite[i].yrepeat = 18;
1017                 sprite[i].clipdist = 64;
1018                 changespritestat(i, FACE);
1019                 sprite[i].hitag = adjusthp(5);
1020                 sprite[i].lotag = 100;
1021                 sprite[i].cstat |= 0x101;
1022                 break;
1023                 case GUARDIAN:
1024                 sprite[i].clipdist = 64;
1025                 changespritestat(i, FACE);
1026                 sprite[i].hitag = adjusthp(200);
1027                 sprite[i].lotag = 100;
1028                 sprite[i].xrepeat = sprite[i].yrepeat = 32;
1029                 sprite[i].cstat |= 0x101;
1030                 break;
1031                 case JUDYSIT:
1032                 changespritestat(i, WITCHSIT);
1033                 if (mapon > 24)
1034                     sprite[i].hitag = adjusthp(700);
1035                 else
1036                     sprite[i].hitag = adjusthp(500);
1037                 sprite[i].lotag = 100;
1038                 sprite[i].xrepeat = sprite[i].yrepeat = 32;
1039                 sprite[i].cstat |= 0x101;
1040                 sprite[i].extra = 1200;
1041                 break;
1042                 case JUDY:
1043                 changespritestat(i, FACE);
1044                 if (mapon > 24)
1045                     sprite[i].hitag = adjusthp(700);
1046                 else
1047                     sprite[i].hitag = adjusthp(500);
1048                 sprite[i].lotag = 100;
1049                 sprite[i].xrepeat = sprite[i].yrepeat = 32;
1050                 sprite[i].cstat |= 0x101;
1051                 break;
1052                 case GOBWEAPON:
1053                 case WEAPON1:
1054                 sprite[i].xrepeat = 34;
1055                 sprite[i].yrepeat = 21;
1056                 break;
1057                 case WEAPON2:
1058                 sprite[i].xrepeat = 26;
1059                 sprite[i].yrepeat = 26;
1060                 break;
1061                 case WEAPON3:
1062                 sprite[i].xrepeat = 44;
1063                 sprite[i].yrepeat = 39;
1064                 break;
1065                 case WEAPON4:
1066                 sprite[i].xrepeat = 25;
1067                 sprite[i].yrepeat = 20;
1068                 break;
1069                 case WEAPON6:
1070                 sprite[i].xrepeat = 20;
1071                 sprite[i].yrepeat = 15;
1072                 sprite[i].cstat &= ~3;
1073                 break;
1074                 case WEAPON7:
1075                 sprite[i].xrepeat = 41;
1076                 sprite[i].yrepeat = 36;
1077                 sprite[i].cstat &= ~3;
1078                 break;
1079                 case QUIVER:
1080                 sprite[i].xrepeat = 27;
1081                 sprite[i].yrepeat = 27;
1082                 break;
1083                 case LEATHERARMOR:
1084                 sprite[i].xrepeat = 47;
1085                 sprite[i].yrepeat = 50;
1086                 break;
1087                 case CHAINMAIL:
1088                 case PLATEARMOR:
1089                 case SHIELD:
1090                 sprite[i].xrepeat = sprite[i].yrepeat = 26;
1091                 break;
1092                 case HELMET:
1093                 sprite[i].xrepeat = 27;
1094                 sprite[i].yrepeat = 28;
1095                 break;
1096                 case SCROLLSCARE:
1097                 case SCROLLNUKE:
1098                 case SCROLLFLY:
1099                 case SCROLLFIREBALL:
1100                 case SCROLLFREEZE:
1101                 case SCROLLNIGHT:
1102                 case SCROLLMAGIC:
1103                 sprite[i].xrepeat = 35;
1104                 sprite[i].yrepeat = 36;
1105                 sprite[i].cstat &= ~3;
1106                 break;
1107                 case DIAMONDRING:
1108                 case ADAMANTINERING:
1109                 sprite[i].xrepeat = 14;
1110                 sprite[i].yrepeat = 14;
1111                 break;
1112                 case SHADOWAMULET:
1113                 sprite[i].xrepeat = 30;
1114                 sprite[i].yrepeat = 23;
1115                 break;
1116                 case GLASSSKULL:
1117                 sprite[i].xrepeat = 22;
1118                 sprite[i].yrepeat = 22;
1119                 break;
1120                 case AHNK:
1121                 sprite[i].xrepeat = 51;
1122                 sprite[i].yrepeat = 54;
1123                 break;
1124                 case BLUESCEPTER:
1125                 case YELLOWSCEPTER:
1126                 sprite[i].xrepeat = 32;
1127                 sprite[i].yrepeat = 32;
1128                 break;
1129                 case ONYXRING:
1130                 sprite[i].xrepeat = 42;
1131                 sprite[i].yrepeat = 28;
1132                 break;
1133                 case HORNEDSKULL:
1134                 case CRYSTALSTAFF:
1135                 sprite[i].xrepeat = 64;
1136                 sprite[i].yrepeat = 64;
1137                 break;
1138                 case AMULETOFTHEMIST:
1139                 sprite[i].xrepeat = 26;
1140                 sprite[i].yrepeat = 28;
1141                 break;
1142                 case SAPHIRERING:
1143                 sprite[i].xrepeat = 30;
1144                 sprite[i].yrepeat = 20;
1145                 break;
1146                 case PINE:
1147                 sprite[i].xrepeat = treesize = ((krand() % 5) + 3) << 4;
1148                 sprite[i].yrepeat = treesize;
1149                 break;
1150                 case GIFTBOX:
1151                 sprite[i].xrepeat = 56;
1152                 sprite[i].yrepeat = 49;
1153                 break;
1154                 case GYSER:
1155                 sprite[i].xrepeat = 32;
1156                 sprite[i].yrepeat = 18;
1157                 sprite[i].shade = -17;
1158                 sprite[i].pal = 0;
1159                 //changespritestat(i,DORMANT);
1160                 break;
1161                 case BARREL:
1162                 case VASEA:
1163                 case VASEB:
1164                 case VASEC:
1165                 sprite[i].cstat |= 0x101;
1166                 sprite[i].clipdist = 64;
1167                 break;
1168                 case BRASSKEY:
1169                 sprite[i].xrepeat = sprite[i].yrepeat = 24;
1170                 break;
1171                 case BLACKKEY:
1172                 sprite[i].xrepeat = sprite[i].yrepeat = 24;
1173                 break;
1174                 case GLASSKEY:
1175                 sprite[i].xrepeat = sprite[i].yrepeat = 24;
1176                 break;
1177                 case IVORYKEY:
1178                 sprite[i].xrepeat = sprite[i].yrepeat = 24;
1179                 break;
1180                 case THEHORN:
1181                 sprite[i].xrepeat = sprite[i].yrepeat = 32;
1182                 break;
1183                 case 2233:     // team flags
1184 // TODO                         netmarkflag(i);
1185                 break;
1186             }
1187         }
1188     }
1189 
1190     for (i = 0; i < numsectors; i++)
1191     {
1192         if (sector[i].lotag == 100) {
1193             spikesector[spikecnt++] = i;
1194         }
1195 
1196         if (sector[i].lotag == 70) {
1197             skypanlist[skypancnt++] = i;
1198         }
1199 
1200         if (sector[i].lotag >= 80 && sector[i].lotag <= 89)
1201         {
1202             floorpanninglist[floorpanningcnt++] = i;
1203         }
1204 
1205         if (sector[i].lotag >= 900 && sector[i].lotag <= 999)
1206         {
1207             lavadrylandsector[lavadrylandcnt] = i;
1208             lavadrylandcnt++;
1209         }
1210 
1211         if (sector[i].lotag >= 2100 && sector[i].lotag <= 2199)
1212         {
1213             startwall = sector[i].wallptr;
1214             endwall = startwall + sector[i].wallnum - 1;
1215             dax = 0;
1216             day = 0;
1217             for (j = startwall; j <= endwall; j++) {
1218                 dax += wall[j].x;
1219                 day += wall[j].y;
1220             }
1221             revolvepivotx[revolvecnt] = dax / (endwall - startwall + 1);
1222             revolvepivoty[revolvecnt] = day / (endwall - startwall + 1);
1223 
1224             k = 0;
1225             for (j = startwall; j <= endwall; j++) {
1226                 revolvex[revolvecnt][k] = wall[j].x;
1227                 revolvey[revolvecnt][k] = wall[j].y;
1228                 k++;
1229             }
1230             revolvesector[revolvecnt] = i;
1231             revolveang[revolvecnt] = 0;
1232 
1233             revolveclip[revolvecnt] = 1;
1234             if (sector[i].ceilingz == sector[wall[startwall].nextsector].ceilingz) {
1235                 revolveclip[revolvecnt] = 0;
1236             }
1237             revolvecnt++;
1238         }
1239 
1240         switch (sector[i].lotag)
1241         {
1242             case DOORSWINGTAG:
1243             startwall = sector[i].wallptr;
1244             endwall = startwall + sector[i].wallnum - 1;
1245             for (j = startwall; j <= endwall; j++)
1246             {
1247                 if (wall[j].lotag == 4)
1248                 {
1249                     k = wall[wall[wall[wall[j].point2].point2].point2].point2;
1250                     if ((wall[j].x == wall[k].x) && (wall[j].y == wall[k].y)) {
1251                         swingdoor[swingcnt].wall[0] = j;
1252                         swingdoor[swingcnt].wall[1] = wall[j].point2;
1253                         swingdoor[swingcnt].wall[2] = wall[wall[j].point2].point2;
1254                         swingdoor[swingcnt].wall[3] = wall[wall[wall[j].point2].point2].point2;
1255                         swingdoor[swingcnt].angopen = 1536;
1256                         swingdoor[swingcnt].angclosed = 0;
1257                         swingdoor[swingcnt].angopendir = -1;
1258                     }
1259                     else {
1260                         swingdoor[swingcnt].wall[0] = wall[j].point2;
1261                         swingdoor[swingcnt].wall[1] = j;
1262                         swingdoor[swingcnt].wall[2] = lastwall(j);
1263                         swingdoor[swingcnt].wall[3] = lastwall(swingdoor[swingcnt].wall[2]);
1264                         swingdoor[swingcnt].angopen = 512;
1265                         swingdoor[swingcnt].angclosed = 0;
1266                         swingdoor[swingcnt].angopendir = 1;
1267                     }
1268                     for (k = 0; k < 4; k++) {
1269                         swingdoor[swingcnt].x[k] = wall[swingdoor[swingcnt].wall[k]].x;
1270                         swingdoor[swingcnt].y[k] = wall[swingdoor[swingcnt].wall[k]].y;
1271                     }
1272                     swingdoor[swingcnt].sector = i;
1273                     swingdoor[swingcnt].ang = swingdoor[swingcnt].angclosed;
1274                     swingdoor[swingcnt].anginc = 0;
1275                     swingcnt++;
1276                 }
1277             }
1278             break;
1279             case 11:
1280             xpanningsectorlist[xpanningsectorcnt++] = i;
1281             break;
1282             case 12:
1283             dasector = i;
1284             dax = 0x7fffffff;
1285             day = 0x7fffffff;
1286             dax2 = 0x80000000;
1287             day2 = 0x80000000;
1288             startwall = sector[i].wallptr;
1289             endwall = startwall + sector[i].wallnum - 1;
1290 
1291             for (j = startwall; j <= endwall; j++)
1292             {
1293                 if (wall[j].x < dax)
1294                     dax = wall[j].x;
1295                 if (wall[j].y < day)
1296                     day = wall[j].y;
1297                 if (wall[j].x > dax2)
1298                     dax2 = wall[j].x;
1299                 if (wall[j].y > day2)
1300                     day2 = wall[j].y;
1301                 if (wall[j].lotag == 3)
1302                     k = j;
1303             }
1304             if (wall[k].x == dax)
1305                 dragxdir[dragsectorcnt] = -16;
1306             if (wall[k].y == day)
1307                 dragydir[dragsectorcnt] = -16;
1308             if (wall[k].x == dax2)
1309                 dragxdir[dragsectorcnt] = 16;
1310             if (wall[k].y == day2)
1311                 dragydir[dragsectorcnt] = 16;
1312 
1313             dasector = wall[startwall].nextsector;
1314             dragx1[dragsectorcnt] = 0x7fffffff;
1315             dragy1[dragsectorcnt] = 0x7fffffff;
1316             dragx2[dragsectorcnt] = 0x80000000;
1317             dragy2[dragsectorcnt] = 0x80000000;
1318             startwall = sector[dasector].wallptr;
1319             endwall = startwall + sector[dasector].wallnum - 1;
1320 
1321             for (j = startwall; j <= endwall; j++)
1322             {
1323                 if (wall[j].x < dragx1[dragsectorcnt])
1324                     dragx1[dragsectorcnt] = wall[j].x;
1325                 if (wall[j].y < dragy1[dragsectorcnt])
1326                     dragy1[dragsectorcnt] = wall[j].y;
1327                 if (wall[j].x > dragx2[dragsectorcnt])
1328                     dragx2[dragsectorcnt] = wall[j].x;
1329                 if (wall[j].y > dragy2[dragsectorcnt])
1330                     dragy2[dragsectorcnt] = wall[j].y;
1331             }
1332 
1333             dragx1[dragsectorcnt] += (wall[sector[i].wallptr].x - dax);
1334             dragy1[dragsectorcnt] += (wall[sector[i].wallptr].y - day);
1335             dragx2[dragsectorcnt] -= (dax2 - wall[sector[i].wallptr].x);
1336             dragy2[dragsectorcnt] -= (day2 - wall[sector[i].wallptr].y);
1337 
1338             dragfloorz[dragsectorcnt] = sector[i].floorz;
1339 
1340             dragsectorlist[dragsectorcnt++] = i;
1341             break;
1342             case 10:
1343             case 14:
1344             case 4002:
1345             warpsectorlist[warpsectorcnt++] = i;
1346             break;
1347             case 10000:
1348             bobbingsectorlist[bobbingsectorcnt++] = i;
1349         }
1350         if (sector[i].floorpicnum == TELEPAD && sector[i].lotag == 0) {
1351             warpsectorlist[warpsectorcnt++] = i;
1352         }
1353     }
1354 
1355     ypanningwallcnt = 0;
1356     for (i = 0; i < numwalls; i++)
1357     {
1358         if (wall[i].lotag == 1) {
1359             ypanningwalllist[ypanningwallcnt++] = i;
1360         }
1361     }
1362 
1363     automapping = 1;
1364 
1365     if (justteleported == 1 || loadedgame == 1)
1366     {
1367         plr->hvel = 0;
1368         angvel = 0;
1369         svel = 0;
1370         vel = 0;
1371 
1372         plr->spritenum = insertsprite(plr->sector, 0);
1373         plr->oldsector = plr->sector;
1374 
1375         sprite[plr->spritenum].x = plr->x;
1376         sprite[plr->spritenum].y = plr->y;
1377         sprite[plr->spritenum].z = sector[plr->sector].floorz;
1378         sprite[plr->spritenum].cstat = 1 + 256;
1379         sprite[plr->spritenum].picnum = FRED;
1380         sprite[plr->spritenum].shade = 0;
1381         sprite[plr->spritenum].xrepeat = 36;
1382         sprite[plr->spritenum].yrepeat = 36;
1383         sprite[plr->spritenum].ang = plr->ang;
1384         sprite[plr->spritenum].xvel = 0;
1385         sprite[plr->spritenum].yvel = 0;
1386         sprite[plr->spritenum].zvel = 0;
1387         sprite[plr->spritenum].owner = 4096;
1388         sprite[plr->spritenum].lotag = 0;
1389         sprite[plr->spritenum].hitag = 0;
1390         sprite[plr->spritenum].pal = 1;
1391 
1392         vec3_t pos;
1393         pos.x = plr->x;
1394         pos.y = plr->y;
1395         pos.z = plr->z + (PLAYERHEIGHT << 8);
1396 
1397         setsprite(plr->spritenum, &pos);
1398 
1399         justteleported = 0;
1400         loadedgame = 0;
1401     }
1402 }
1403 
DrawHUD()1404 void DrawHUD()
1405 {
1406     overwritesprite(0, 200 - 46, NEWSTATUSBAR, 0, 0x2, 0);
1407 
1408     healthpic();
1409     drawarmor();
1410     drawpotionpic();
1411     levelpic();
1412     drawscore();
1413     draworbpic();
1414 }
1415 
drawscreen(Player * plr)1416 void drawscreen(Player* plr)
1417 {
1418     if (plr->dimension == 3 || plr->dimension == 2)
1419     {
1420         drawrooms(plr->x, plr->y, plr->z, plr->ang, plr->horiz, plr->sector);
1421         transformactors(plr);
1422 
1423         renderDrawMasks();
1424 
1425         if (!plr->playerdie) {
1426             drawweapons(plr);
1427         }
1428 
1429         if (plr->spiked) {
1430             spikeheart(plr);
1431         }
1432 
1433         dofx();
1434     }
1435 
1436     if (plr->dimension == 2) {
1437         drawoverheadmap(plr);
1438     }
1439 
1440     monitor();
1441     screenfx();
1442 
1443     plr->oldsector = plr->sector;
1444 
1445     if (netgame) {
1446         whnetmon();
1447     }
1448 
1449     DrawHUD();
1450 
1451     //updatepics();
1452 
1453     G_PrintFPS();
1454 
1455     videoNextPage();
1456 }
1457 
timerhandler()1458 void timerhandler()
1459 {
1460     // TODO    totalclock++;
1461 
1462     OSD_DispatchQueued();
1463 }
1464 
InitTimer()1465 void InitTimer()
1466 {
1467     timerInit(kTimerTicks);
1468     timerSetCallback(timerhandler);
1469 }
1470 
app_main(int argc,char const * const * argv)1471 int app_main(int argc, char const* const* argv)
1472 {
1473     char temp1[10] = { "DEMO" };
1474 
1475     Player* plr = &player[pyrn];
1476 
1477     char tempbuf[256];
1478 
1479 #ifdef _WIN32
1480 #ifndef DEBUGGINGAIDS
1481     if (!G_CheckCmdSwitch(argc, argv, "-noinstancechecking") && !windowsCheckAlreadyRunning())
1482     {
1483 #ifdef EDUKE32_STANDALONE
1484         if (!wm_ynbox(APPNAME, "It looks like " APPNAME " is already running.\n\n"
1485 #else
1486         if (!wm_ynbox(APPNAME, "It looks like the game is already running.\n\n"
1487 #endif
1488             "Are you sure you want to start another copy?"))
1489             return 3;
1490     }
1491 #endif
1492 #endif
1493 
1494     G_ExtPreInit(argc, argv);
1495 
1496     OSD_SetLogFile(APPBASENAME ".log");
1497 
1498     OSD_SetFunctions(NULL,
1499         NULL,
1500         NULL,
1501         NULL,
1502         NULL,
1503         GAME_clearbackground,
1504         BGetTime,
1505         GAME_onshowosd);
1506 
1507     wm_setapptitle(APPNAME);
1508 
1509     initprintf("Witchaven %s\n", s_buildRev);
1510     PrintBuildInfo();
1511 
1512     // This needs to happen afterwards, as G_CheckCommandLine() is where we set
1513     // up the command-line-provided search paths (duh).
1514     G_ExtInit();
1515 
1516     if (!g_useCwd)
1517         G_AddSearchPaths();
1518 
1519 #if defined(RENDERTYPEWIN) && defined(USE_OPENGL)
1520     if (forcegl) initprintf("GL driver blacklist disabled.\n");
1521 #endif
1522 
1523     // used with binds for fast function lookup
1524     hash_init(&h_gamefuncs);
1525     for (bssize_t i = kMaxGameFunctions - 1; i >= 0; i--)
1526     {
1527         if (gamefunctions[i][0] == '\0')
1528             continue;
1529 
1530         hash_add(&h_gamefuncs, gamefunctions[i], i, 0);
1531     }
1532 
1533 #ifdef STARTUP_SETUP_WINDOW
1534     int const readSetup =
1535 #endif
1536         CONFIG_ReadSetup();
1537 
1538     if (enginePreInit())
1539     {
1540         wm_msgbox("Build Engine Initialization Error",
1541             "There was a problem initializing the Build engine: %s", engineerrstr);
1542         ERRprintf("app_main: There was a problem initializing the Build engine: %s\n", engineerrstr);
1543         Bexit(2);
1544     }
1545 
1546     if (Bstrcmp(setupfilename, kSetupFilename))
1547         initprintf("Using config file \"%s\".\n", setupfilename);
1548 
1549     G_ScanGroups();
1550 
1551     wm_msgbox("Pre-Release Software Warning", "%s is not ready for public use. Proceed with caution!", AppProperName);
1552 
1553 #ifdef STARTUP_SETUP_WINDOW
1554     if (readSetup < 0 || (!g_noSetup && gSetup.forcesetup) || g_commandSetup)
1555     {
1556         if (quitevent || !startwin_run())
1557         {
1558             engineUnInit();
1559             Bexit(0);
1560         }
1561     }
1562 #endif
1563 
1564     G_LoadGroups(!g_noAutoLoad && !gSetup.noautoload);
1565 
1566     CONFIG_WriteSetup(1);
1567     CONFIG_ReadSetup();
1568 
1569     initprintf("Initializing OSD...\n");
1570 
1571     Bsprintf(tempbuf, "Witchaven %s", s_buildRev);
1572     OSD_SetVersion(tempbuf, 10, 0);
1573     OSD_SetParameters(0, 0, 0, 0, 0, 0, OSD_ERROR, OSDTEXT_RED, gamefunctions[gamefunc_Show_Console][0] == '\0' ? OSD_PROTECTED : 0);
1574     registerosdcommands();
1575 
1576     SetupInput();
1577 
1578 /*
1579     char* const setupFileName = Xstrdup(setupfilename);
1580     char* const p = strtok(setupFileName, ".");
1581 
1582     if (!p || !Bstrcmp(setupfilename, kSetupFilename))
1583         Bsprintf(tempbuf, "settings.cfg");
1584     else
1585         Bsprintf(tempbuf, "%s_settings.cfg", p);
1586 
1587     Xfree(setupFileName);
1588 */
1589     OSD_Exec("ewitchaven_cvars.cfg");
1590     OSD_Exec("ewitchaven_autoexec.cfg");
1591 
1592     CONFIG_SetDefaultKeys(keydefaults, true);
1593 
1594     system_getcvars();
1595 
1596     InstallEngine();
1597 
1598     const char* defsfile = G_DefFile();
1599     uint32_t stime = timerGetTicks();
1600     if (!loaddefinitionsfile(defsfile))
1601     {
1602         uint32_t etime = timerGetTicks();
1603         initprintf("Definitions file \"%s\" loaded in %d ms.\n", defsfile, etime - stime);
1604     }
1605     loaddefinitions_game(defsfile, FALSE);
1606 
1607     if (enginePostInit())
1608         shutdown();
1609 
1610     g_frameDelay = calcFrameDelay(r_maxfps, r_maxfpsoffset);
1611 
1612     KB_Startup();
1613     InitTimer();
1614 
1615     //TODO    netcheckargs(argc,argv);
1616 
1617     tprintf(-1, 0, "WITCHAVEN Copyright (C) 1995 IntraCorp, Inc. ver 1.1", temp1);
1618     tprintf(2, 2, " map name: level%d", mapon);
1619     tprintf(2, 3, " initengine()");
1620 
1621 #if 0
1622     int fil;
1623     if ((fil = open("setup.dat", O_BINARY | O_RDWR, S_IREAD)) != -1) {
1624         read(fil, &option, NUMOPTIONS);
1625         read(fil, keys, WHNUMKEYS);
1626         read(fil, option2, 7);
1627         close(fil);
1628     }
1629 
1630     if (access("pref.dat", F_OK) != 0) {
1631         goreon = 1;
1632         brightness = gbrightness = 0;
1633         digilevel = 11;
1634         musiclevel = 11;
1635         fil = open("pref.dat", O_BINARY | O_TRUNC | O_CREAT | O_WRONLY, S_IREAD | S_IWRITE);
1636         if (fil != NULL) {
1637             write(fil, &goreon, 2);
1638             write(fil, &brightness, 2);
1639             write(fil, &gbrightness, 2);
1640             write(fil, &digilevel, 2);
1641             write(fil, &musiclevel, 2);
1642             write(fil, &difficulty, 2);
1643             close(fil);
1644         }
1645     }
1646     else {
1647         fil = open("pref.dat", O_RDONLY | O_BINARY);
1648         if (fil != NULL) {
1649             read(fil, &goreon, 2);
1650             read(fil, &brightness, 2);
1651             read(fil, &gbrightness, 2);
1652             read(fil, &digilevel, 2);
1653             read(fil, &musiclevel, 2);
1654             read(fil, &difficulty, 2);
1655             close(fil);
1656         }
1657     }
1658 #endif
1659 
1660     if (option[8] == 1 || option[9] == 1)
1661         MusicMode = 1;
1662     else
1663         MusicMode = 0;
1664 
1665     if (option[10] == 1 || option[11] == 1)
1666         SoundMode = 1;
1667     else
1668         SoundMode = 0;
1669 
1670     // TEMP
1671     MusicMode = 1;
1672     SoundMode = 1;
1673     musiclevel = 15;
1674 
1675     //JSA_SPOOGE
1676     if (SoundMode) {
1677         //TODO        SND_DoBuffers();
1678     }
1679 
1680 #if 0 // TODO
1681     if (option[3] != 0) {
1682         initmouse();
1683         mousekeys[0] = option2[0];
1684         mousekeys[1] = option2[1];
1685     }
1686 
1687     if (option2[2] != 0) {
1688         initjstick();
1689     }
1690 #endif
1691 /*
1692     switch (option[0])
1693     {
1694         case 1:
1695         {
1696             initengine(1, vesares[option[6] & 15][0], vesares[option[6] & 15][1]);
1697             if (vesares[option[6] & 15][0] == 640)
1698                 svga = 1;
1699         }
1700         break;
1701         default:
1702             initengine(1,320,200);
1703         break;
1704     }
1705 */
1706 
1707     /* TODO
1708         pskyoff[0] = 0;
1709         pskyoff[1] = 0;
1710         pskybits = 1;
1711     */
1712 
1713     SND_Startup();
1714 
1715 //    tprintf(2, 4, " loadpics()");
1716 //    tprintf(2, 5, " tiles000.art");
1717 
1718     //** Les END   - 09/06/95
1719 #if 0
1720     if (vixen = ismscdex()) {
1721         sprintf(tempbuf, "%c:\\whaven\\intro.smk", vixen);
1722         if (access(tempbuf, F_OK) != 0) {
1723             crash("\nCD-ROM NOT DETECTED  \n");
1724         }
1725     }
1726 #endif
1727 
1728     initlava();
1729     initwater();
1730 
1731     tprintf(2, 6, " setupboard()");
1732 
1733     pyrn = 0;
1734     tprintf(2, 7, " initplayersprite(%d)", pyrn);
1735     tprintf(2, 8, " resettiming()");
1736     totalclock = 0;
1737 
1738     //JSA_DEMO start menu song here use
1739     //flc_init();
1740     //flc_playseq(plr,0,FT_FULLSCREEN);
1741 
1742     SND_MenuMusic(MENUSONG);
1743 
1744     //precache();
1745 
1746     plr->playerdie = false;
1747     plr->oldsector = plr->sector;
1748     plr->horiz = 100;
1749     plr->zoom = 256;
1750     if (svga == 1) {
1751         plr->screensize = 328;
1752     }
1753     else {
1754         plr->screensize = 320;
1755     }
1756 
1757     plr->dimension = 3;
1758     plr->height = PLAYERHEIGHT;
1759     plr->z = sector[plr->sector].floorz - (plr->height << 8);
1760 
1761     //TODO    visibility = 1024;
1762 
1763     parallaxtype = 1;
1764 
1765     setup3dscreen();
1766 
1767     // intro();
1768 
1769     /*
1770         initpaletteshifts();
1771         readpalettetable();
1772 
1773         gameactivated=0;
1774         escapetomenu=0;
1775     */
1776 
1777 
1778     /*
1779          if (option[MULTIOPT] != 0) {
1780               initmultiplayers(MAXPLAYERS);
1781          }
1782     */
1783 
1784     playloop();
1785 
1786     return 0;
1787 }
1788 
intro()1789 void intro()
1790 {
1791     //loadtile(CAPSTONE);
1792 
1793     //for(i=0;i<32;i++) {
1794     //   overwritesprite(80,40,CAPSTONE,0,0,0);
1795     //   videoNextPage();
1796     //}
1797 
1798     tileLoad(TITLEPIC);
1799 
1800     for (int i = 0; i < 32; i++)
1801     {
1802         overwritesprite(0,0,TITLEPIC,32-i,2,0);
1803         videoNextPage();
1804     }
1805 
1806     rp_delay(120);
1807 
1808     for (int i = 0; i < 32; i++)
1809     {
1810         overwritesprite(0,0,TITLEPIC,i,2,0);
1811         videoNextPage();
1812     }
1813 }
1814 
1815 ClockTicks ototalclock;
1816 
playloop()1817 void playloop()
1818 {
1819     Player *plr = &player[pyrn];
1820 
1821     if (netgame) {
1822 // TODO    initmulti(MAXPLAYERS);
1823     }
1824 
1825     int exit = 0;
1826 
1827     CONTROL_BindsEnabled = 1;
1828 
1829     ototalclock = totalclock;
1830 
1831     while (!exit)
1832     {
1833         static bool frameJustDrawn;
1834         bool gameUpdate = false;
1835         double gameUpdateStartTime = timerGetHiTicks();
1836 
1837         if (gameactivated == 0 || escapetomenu == 1)
1838         {
1839             exit = menuscreen();
1840         }
1841 
1842         if (totalclock >= (ototalclock + kTicksPerFrame))
1843         {
1844             do // while(0)
1845             {
1846                 if (!frameJustDrawn)
1847                     break;
1848 
1849                 frameJustDrawn = false;
1850 
1851                 int32_t oldsynctics = synctics;
1852                 synctics = 4;
1853                 processinput(plr);
1854                 synctics = oldsynctics;
1855 
1856                 do
1857                 {
1858                     ototalclock += kTicksPerFrame;
1859                     auto const moveClock = totalclock;
1860     /*
1861                     if (gameactivated == 0 || escapetomenu == 1)
1862                     {
1863                         exit = menuscreen(plr);
1864                     }
1865                     else
1866     */
1867                     {
1868                         int32_t oldsynctics = synctics;
1869                         // temp
1870                         synctics = kTicksPerFrame;
1871                         processobjs(plr);
1872                         animateobjs(plr);
1873                         animatetags(plr);
1874                         doanimations(kTicksPerFrame);
1875                         dodelayitems(kTicksPerFrame);
1876 
1877                         synctics = oldsynctics;
1878                     }
1879 
1880                     if ((int)(totalclock - moveClock) >= (kTicksPerFrame >> 1))
1881                         break;
1882                 }
1883                 while ((totalclock - ototalclock) >= kTicksPerFrame);
1884 
1885                 gameUpdate = true;
1886 
1887             } while (0);
1888         }
1889 
1890 		keytimerstuff();
1891 
1892 		handleevents();
1893 
1894         drawscreen(plr);
1895 
1896         frameJustDrawn = true;
1897 
1898         #if 0
1899 
1900         handleevents();
1901 
1902         if (gameactivated == 0 || escapetomenu == 1)
1903         {
1904             exit = menuscreen(plr);
1905             #if 0
1906             if (svga == 0)
1907             {
1908                 permanentwritesprite(0, 0, BACKGROUND, 0, 0, 0, 319, 199, 0);
1909                 permanentwritesprite(0, 200 - 46, STATUSBAR, 0, 0, 0, 319, 199, 0);
1910                 //updatepics();
1911             }
1912 
1913             if (svga == 1)
1914             {
1915                 if (plr->screensize == 320) {
1916                     overwritesprite(0, 372, SSTATUSBAR, 0, 0, 0);
1917                     //updatepics();
1918                 }
1919             }
1920             #endif
1921 
1922             plr->z = sector[plr->sector].floorz - (PLAYERHEIGHT << 8);
1923         }
1924 
1925         //        drawscreen(plr);
1926         processinput(plr);
1927 
1928         if (netgame)
1929         {
1930             netgetmove();
1931             netsendmove();
1932         }
1933 
1934         processobjs(plr);
1935         animateobjs(plr);
1936         animatetags(plr);
1937         doanimations(synctics);
1938         dodelayitems(synctics);
1939 
1940         //if (engineFPSLimit()) {
1941             drawscreen(plr);
1942         //}
1943             #endif
1944     }
1945 }
1946 
drawoverheadmap(Player * plr)1947 void drawoverheadmap(Player *plr)
1948 {
1949 #if 0 // TODO
1950     int i, j, k, l, x1, y1, x2, y2, x3, y3, x4, y4, ox, oy, xoff, yoff;
1951     int dax, day, cosang, sinang, xspan, yspan, sprx, spry;
1952     int xrepeat, yrepeat, z1, z2, startwall, endwall, tilenum, daang;
1953     int xvect, yvect, xvect2, yvect2;
1954     char col;
1955     walltype *wal, *wal2;
1956     spritetype *spr;
1957     short cang;
1958     int czoom;
1959 
1960     cang=(short)plr->ang;
1961     czoom=plr->zoom;
1962 
1963     xvect = sintable[(2048-cang)& kAngleMask] * czoom;
1964     yvect = sintable[(1536-cang)& kAngleMask] * czoom;
1965     xvect2 = mulscale(xvect,yxaspect,16);
1966     yvect2 = mulscale(yvect,yxaspect,16);
1967 
1968         //Draw red lines
1969     for (i=0;i<numsectors;i++)
1970     {
1971         startwall = sector[i].wallptr;
1972         endwall = sector[i].wallptr + sector[i].wallnum - 1;
1973 
1974         z1 = sector[i].ceilingz;
1975         z2 = sector[i].floorz;
1976 
1977         for(j=startwall,wal=&wall[startwall];j<=endwall;j++,wal++)
1978         {
1979             k = wal->nextwall;
1980             if (k < 0)
1981                  continue;
1982 
1983             if ((show2dwall[j>>3]&(1<<(j&7))) == 0) {
1984                  continue;
1985             }
1986             if ((k > j) && ((show2dwall[k>>3]&(1<<(k&7))) > 0))
1987                  continue;
1988 
1989             if (sector[wal->nextsector].ceilingz == z1)
1990                 if (sector[wal->nextsector].floorz == z2)
1991                     if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0)
1992                           continue;
1993 
1994             col = 152;
1995 
1996             if (plr->dimension == 2)
1997             {
1998                 if (sector[i].floorz != sector[i].ceilingz)
1999                     if (sector[wal->nextsector].floorz != sector[wal->nextsector].ceilingz)
2000                         if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0)
2001                             if (sector[i].floorz == sector[wal->nextsector].floorz)
2002                                  continue;
2003                 if (sector[i].floorpicnum != sector[wal->nextsector].floorpicnum)
2004                      continue;
2005                 if (sector[i].floorshade != sector[wal->nextsector].floorshade)
2006                      continue;
2007                 col = 12;
2008             }
2009 
2010             ox = wal->x-plr->x; oy = wal->y-plr->y;
2011             x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2012             y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2013 
2014             wal2 = &wall[wal->point2];
2015             ox = wal2->x-plr->x; oy = wal2->y-plr->y;
2016             x2 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2017             y2 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2018 
2019             drawline256(x1+(xdim<<11),y1+(ydim<<11),x2+(xdim<<11),y2+(ydim<<11),col);
2020         }
2021     }
2022 
2023         //Draw sprites
2024     k = plr->spritenum;
2025     for(i=0;i<numsectors;i++)
2026         for(j=headspritesect[i];j>=0;j=nextspritesect[j])
2027             if ((show2dsprite[j>>3]&(1<<(j&7))) > 0)
2028             {
2029                 spr = &sprite[j];
2030                 col = 56;
2031                 if ((spr->cstat&1) > 0)
2032                      col = 248;
2033                 if (j == k)
2034                       col = 31;
2035 
2036                 sprx = spr->x;
2037                 spry = spr->y;
2038 
2039                 k = spr->statnum;
2040                 if ((k >= 1) && (k <= 8) && (k != 2))  //Interpolate moving sprite
2041                 {
2042                     sprx = osprite[j].x+mulscale(sprx-osprite[j].x,smoothratio,16);
2043                     spry = osprite[j].y+mulscale(spry-osprite[j].y,smoothratio,16);
2044                 }
2045 
2046                 switch (spr->cstat&48)
2047                 {
2048                     case 0:
2049                         ox = sprx-plr->x; oy = spry-plr->y;
2050                         x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2051                         y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2052 
2053                         if (plr->dimension == 1)
2054                         {
2055                             ox = (sintable[(spr->ang+512)& kAngleMask]>>7);
2056                             oy = (sintable[(spr->ang)& kAngleMask]>>7);
2057                             x2 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2058                             y2 = mulscale(oy,xvect,16) + mulscale(ox,yvect,16);
2059 
2060                             if (j == plr->spritenum)
2061                             {
2062                                 x2 = 0L;
2063                                 y2 = -(czoom<<5);
2064                             }
2065 
2066                             x3 = mulscale(x2,yxaspect,16);
2067                             y3 = mulscale(y2,yxaspect,16);
2068 
2069                             drawline256(x1-x2+(xdim<<11),y1-y3+(ydim<<11),
2070                                             x1+x2+(xdim<<11),y1+y3+(ydim<<11),col);
2071                             drawline256(x1-y2+(xdim<<11),y1+x3+(ydim<<11),
2072                                             x1+x2+(xdim<<11),y1+y3+(ydim<<11),col);
2073                             drawline256(x1+y2+(xdim<<11),y1-x3+(ydim<<11),
2074                                             x1+x2+(xdim<<11),y1+y3+(ydim<<11),col);
2075                         }
2076                         else
2077                         {
2078                             if (((gotsector[i>>3]&(1<<(i&7))) > 0) && (czoom > 192))
2079                             {
2080                                 daang = (spr->ang-cang)& kAngleMask;
2081                                 if (j == plr->spritenum )
2082                                     { x1 = 0; y1 = (yxaspect<<2); daang = 0; }
2083                                 rotatesprite((x1<<4)+(xdim<<15),(y1<<4)+(ydim<<15),mulscale(czoom*spr->yrepeat,yxaspect,16),daang,spr->picnum,spr->shade,spr->pal,(spr->cstat&2)>>1);
2084                             }
2085                         }
2086                         break;
2087                     case 16:
2088                         x1 = sprx;
2089                         y1 = spry;
2090                         tilenum = spr->picnum;
2091                         xoff = (int)((signed char)((picanm[tilenum]>>8)&255))+((int)spr->xoffset);
2092                         if ((spr->cstat&4) > 0)
2093                              xoff = -xoff;
2094                         k = spr->ang;
2095                         l = spr->xrepeat;
2096                         dax = sintable[k& kAngleMask]*l;
2097                         day = sintable[(k+1536)& kAngleMask]*l;
2098                         l = tilesizx[tilenum];
2099                         k = (l>>1)+xoff;
2100                         x1 -= mulscale(dax,k,16);
2101                         x2 = x1+mulscale(dax,l,16);
2102                         y1 -= mulscale(day,k,16);
2103                         y2 = y1+mulscale(day,l,16);
2104 
2105                         ox = x1-plr->x;
2106                         oy = y1-plr->y;
2107                         x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2108                         y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2109 
2110                         ox = x2-plr->x;
2111                         oy = y2-plr->y;
2112                         x2 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2113                         y2 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2114 
2115                         drawline256(x1+(xdim<<11),y1+(ydim<<11),
2116                                         x2+(xdim<<11),y2+(ydim<<11),col);
2117 
2118                         break;
2119                     case 32:
2120                         if (plr->dimension == 1)
2121                         {
2122                             tilenum = spr->picnum;
2123                             xoff = (int)((signed char)((picanm[tilenum]>>8)&255))+((int)spr->xoffset);
2124                             yoff = (int)((signed char)((picanm[tilenum]>>16)&255))+((int)spr->yoffset);
2125                             if ((spr->cstat&4) > 0)
2126                                  xoff = -xoff;
2127                             if ((spr->cstat&8) > 0)
2128                                  yoff = -yoff;
2129 
2130                             k = spr->ang;
2131                             cosang = sintable[(k+512)& kAngleMask];
2132                             sinang = sintable[k];
2133                             xspan = tilesizx[tilenum];
2134                             xrepeat = spr->xrepeat;
2135                             yspan = tilesizy[tilenum];
2136                             yrepeat = spr->yrepeat;
2137 
2138                             dax = ((xspan>>1)+xoff)*xrepeat;
2139                             day = ((yspan>>1)+yoff)*yrepeat;
2140                             x1 = sprx + mulscale(sinang,dax,16) + mulscale(cosang,day,16);
2141                             y1 = spry + mulscale(sinang,day,16) - mulscale(cosang,dax,16);
2142                             l = xspan*xrepeat;
2143                             x2 = x1 - mulscale(sinang,l,16);
2144                             y2 = y1 + mulscale(cosang,l,16);
2145                             l = yspan*yrepeat;
2146                             k = -mulscale(cosang,l,16);
2147                             x3 = x2+k;
2148                             x4 = x1+k;
2149                             k = -mulscale(sinang,l,16);
2150                             y3 = y2+k;
2151                             y4 = y1+k;
2152 
2153                             ox = x1-plr->x;
2154                             oy = y1-plr->y;
2155                             x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2156                             y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2157 
2158                             ox = x2-plr->x;
2159                             oy = y2-plr->y;
2160                             x2 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2161                             y2 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2162 
2163                             ox = x3-plr->x;
2164                             oy = y3-plr->y;
2165                             x3 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2166                             y3 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2167 
2168                             ox = x4-plr->x;
2169                             oy = y4-plr->y;
2170                             x4 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2171                             y4 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2172 
2173                             drawline256(x1+(xdim<<11),y1+(ydim<<11),
2174                                             x2+(xdim<<11),y2+(ydim<<11),col);
2175 
2176                             drawline256(x2+(xdim<<11),y2+(ydim<<11),
2177                                             x3+(xdim<<11),y3+(ydim<<11),col);
2178 
2179                             drawline256(x3+(xdim<<11),y3+(ydim<<11),
2180                                             x4+(xdim<<11),y4+(ydim<<11),col);
2181 
2182                             drawline256(x4+(xdim<<11),y4+(ydim<<11),
2183                                             x1+(xdim<<11),y1+(ydim<<11),col);
2184 
2185                         }
2186                         break;
2187                 }
2188             }
2189 
2190         //Draw white lines
2191     for(i=0;i<numsectors;i++)
2192     {
2193         startwall = sector[i].wallptr;
2194         endwall = sector[i].wallptr + sector[i].wallnum - 1;
2195 
2196         for(j=startwall,wal=&wall[startwall];j<=endwall;j++,wal++)
2197         {
2198             if (wal->nextwall >= 0)
2199                   continue;
2200 
2201             if ((show2dwall[j>>3]&(1<<(j&7))) == 0) {
2202                  continue;
2203             }
2204 
2205             if (tilesizx[wal->picnum] == 0)
2206                  continue;
2207             if (tilesizy[wal->picnum] == 0)
2208                  continue;
2209 
2210             ox = wal->x-plr->x;
2211             oy = wal->y-plr->y;
2212             x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2213             y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2214 
2215             wal2 = &wall[wal->point2];
2216             ox = wal2->x-plr->x;
2217             oy = wal2->y-plr->y;
2218             x2 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16);
2219             y2 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16);
2220 
2221             drawline256(x1+(xdim<<11),y1+(ydim<<11),x2+(xdim<<11),y2+(ydim<<11),24);
2222         }
2223     }
2224 #endif
2225 }
2226 
readpalettetable()2227 void readpalettetable()
2228 {
2229     uint8_t palbuf[256];
2230 
2231     int hFile = kopen4loadfrommod("lookup.dat", 0);
2232     if (hFile == -1)
2233     {
2234         // TODO - error
2235         return;
2236     }
2237 
2238     uint8_t num_tables = 0;
2239     kread(hFile, &num_tables, 1);
2240 
2241     for (int j = 0; j < num_tables; j++)
2242     {
2243         char lookup_num;
2244         kread(hFile, &lookup_num, 1);
2245         kread(hFile, palbuf, 256);
2246 
2247         paletteMakeLookupTable(lookup_num, (const char*)palbuf, 0, 0, 0, 1);
2248     }
2249 
2250     kclose(hFile);
2251 }
2252 
adjusthp(int hp)2253 int adjusthp(int hp)
2254 {
2255     float factor = (krand() % 20) / 100;
2256     int howhard = difficulty;
2257 
2258     if (krand() % 100 > 50) {
2259         return((hp * (factor + 1)) * howhard);
2260     }
2261     else {
2262         return((hp - (hp * (factor))) * howhard);
2263     }
2264 }
2265 
InstallEngine()2266 void InstallEngine()
2267 {
2268     // initgroupfile("stuff.dat");
2269 
2270     char* cwd;
2271 
2272     if (g_modDir[0] != '/' && (cwd = buildvfs_getcwd(NULL, 0)))
2273     {
2274         buildvfs_chdir(g_modDir);
2275         if (artLoadFiles("tiles%03i.art", MAXCACHE1DSIZE) < 0)
2276         {
2277             buildvfs_chdir(cwd);
2278             if (artLoadFiles("tiles%03i.art", MAXCACHE1DSIZE) < 0)
2279                 crash("Failed loading art.");
2280         }
2281         buildvfs_chdir(cwd);
2282 #ifndef __ANDROID__ //This crashes on *some* Android devices. Small onetime memory leak. TODO fix above function
2283         Xfree(cwd);
2284 #endif
2285     }
2286     else if (artLoadFiles("tiles%03i.art", MAXCACHE1DSIZE) < 0)
2287         crash("Failed loading art.");
2288 
2289     if (engineInit())
2290     {
2291         wm_msgbox("Fatal Engine Initialization Error",
2292             "There was a problem initializing the engine: %s\n\nThe application will now close.", engineerrstr);
2293         //TODO:
2294         //G_Cleanup();
2295         ERRprintf("G_Startup: There was a problem initializing the engine: %s\n", engineerrstr);
2296         exit(6);
2297     }
2298     if (videoSetGameMode(gSetup.fullscreen, gSetup.xdim, gSetup.ydim, gSetup.bpp, 0) < 0)
2299     {
2300         initprintf("Failure setting video mode %dx%dx%d %s! Trying next mode...\n", gSetup.xdim, gSetup.ydim,
2301             gSetup.bpp, gSetup.fullscreen ? "fullscreen" : "windowed");
2302 
2303         int resIdx = 0;
2304 
2305         for (int i = 0; i < validmodecnt; i++)
2306         {
2307             if (validmode[i].xdim == gSetup.xdim && validmode[i].ydim == gSetup.ydim)
2308             {
2309                 resIdx = i;
2310                 break;
2311             }
2312         }
2313 
2314         int const savedIdx = resIdx;
2315         int bpp = gSetup.bpp;
2316 
2317         while (videoSetGameMode(0, validmode[resIdx].xdim, validmode[resIdx].ydim, bpp, 0) < 0)
2318         {
2319             initprintf("Failure setting video mode %dx%dx%d windowed! Trying next mode...\n",
2320                 validmode[resIdx].xdim, validmode[resIdx].ydim, bpp);
2321 
2322             if (++resIdx == validmodecnt)
2323             {
2324                 if (bpp == 8)
2325                     crash("Fatal error: unable to set any video mode!");
2326 
2327                 resIdx = savedIdx;
2328                 bpp = 8;
2329             }
2330         }
2331 
2332         gSetup.xdim = validmode[resIdx].xdim;
2333         gSetup.ydim = validmode[resIdx].ydim;
2334         gSetup.bpp = bpp;
2335     }
2336 
2337     initpaletteshifts();
2338     readpalettetable();
2339 
2340     // build.obj is dated 9th July 1995
2341     enginecompatibilitymode = ENGINE_19950829;
2342 
2343     engineinitflag = 1;
2344 }
2345 
RemoveEngine()2346 void RemoveEngine()
2347 {
2348     engineUnInit();
2349     uninitgroupfile();
2350 }
2351