1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 sirlemonhead, Nuke.YKT
5 
6 This file is part of PCExhumed.
7 
8 PCExhumed is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 */
22 //-------------------------------------------------------------------------
23 
24 #include "compat.h"
25 #include "keyboard.h"
26 #include "control.h"
27 #include "init.h"
28 #include "runlist.h"
29 #include "switch.h"
30 #include "object.h"
31 #include "aistuff.h"
32 #include "ramses.h"
33 #include "player.h"
34 #include "mummy.h"
35 #include "move.h"
36 #include "ra.h"
37 #include "view.h"
38 #include "runlist.h"
39 #include "engine.h"
40 #include "sound.h"
41 #include "exhumed.h"
42 #include "config.h"
43 #include "items.h"
44 #include "light.h"
45 #include "map.h"
46 #include "menu.h"
47 #include "lighting.h"
48 #include "anims.h"
49 #include "input.h"
50 #include "util.h"
51 #include <stdio.h>
52 #include <string.h>
53 
54 enum
55 {
56     kTagRamses = 61,
57 };
58 
59 ClockTicks ototalclock = 0;
60 
61 int initx, inity, initz;
62 short inita, initsect;
63 
64 short nCurChunkNum = 0;
65 
66 short nBodyGunSprite[50];
67 int movefifoend;
68 int movefifopos;
69 
70 short nCurBodyGunNum;
71 
72 short SectSoundSect[kMaxSectors] = { 0 };
73 short SectSound[kMaxSectors]     = { 0 };
74 short SectFlag[kMaxSectors]      = { 0 };
75 int   SectDepth[kMaxSectors]     = { 0 };
76 int   SectAbove[kMaxSectors]     = { 0 };
77 short SectDamage[kMaxSectors]    = { 0 };
78 short SectSpeed[kMaxSectors]     = { 0 };
79 int   SectBelow[kMaxSectors]     = { 0 };
80 
81 
82 uint8_t bIsVersion6 = kTrue;
83 
84 #if 0
85 // definitions for map version 6 structures
86 #pragma pack(1)
87 
88 // 37 bytes
89 struct Sector_6
90 {
91     uint16_t wallptr, wallnum;
92     short ceilingpicnum, floorpicnum;
93     short ceilingheinum, floorheinum;
94     int ceilingz, floorz;
95     int8_t ceilingshade, floorshade;
96     uint8_t ceilingxpanning, floorxpanning;
97     uint8_t ceilingypanning, floorypanning;
98     uint8_t ceilingstat, floorstat;
99     uint8_t ceilingpal, floorpal;
100     uint8_t visibility;
101     short lotag, hitag, extra;
102 };
103 
104 struct Wall_6
105 {
106     int x, y;
107     short point2, nextsector, nextwall;
108     short picnum, overpicnum;
109     int8_t shade;
110     uint8_t pal;
111     short cstat;
112     uint8_t xrepeat, yrepeat, xpanning, ypanning;
113     short lotag, hitag, extra;
114 };
115 
116 // 43 bytes
117 struct Sprite_6
118 {
119     int x, y, z;
120     short cstat;
121     int8_t shade;
122     uint8_t pal, clipdist;
123     uint8_t xrepeat, yrepeat;
124     int8_t xoffset, yoffset;
125     short picnum, ang, xvel, yvel, zvel, owner;
126     short sectnum, statnum;
127     short lotag, hitag, extra;
128 };
129 
130 #pragma pack()
131 
132 static Sector_6 sector_6[1024];
133 static Wall_6   wall_6[8192];
134 static Sprite_6 sprite_6[4096];
135 #endif
136 
137 
LoadLevel(int nMap)138 uint8_t LoadLevel(int nMap)
139 {
140     char fileName_1[80];
141     char fileName_2[32];
142 
143     initspritelists();
144 
145 //	nMap = 1;
146 
147 //	sprintf(fileName_2, "queen");
148     sprintf(fileName_2, "lev%d", nMap);
149 //	sprintf(fileName_2, "sentry");
150 //	sprintf(fileName_2, "bjd");
151 //	sprintf(fileName_2, "door");
152 //	sprintf(fileName_2, "ceil");
153 //	sprintf(fileName_2, "scarab");
154 //	sprintf(fileName_2, "guns");
155 //	sprintf(fileName_2, "wasp");
156 //	sprintf(fileName_2, "items");
157 
158     fileName_1[0] = '\0';
159     strcat(fileName_1, fileName_2);
160     strcat(fileName_1, ".map");
161 
162     // init stuff
163     {
164         StopAllSounds();
165         nCreaturesLeft = 0;
166         nFreeze = 0;
167         nSpiritSprite = -1;
168 
169         InitLion();
170         InitRexs();
171         InitSets();
172         InitQueens();
173         InitRoachs();
174         InitWasps();
175         InitRats();
176         InitBullets();
177         InitWeapons();
178         InitGrenades();
179         InitAnims();
180         InitSnakes();
181         InitFishes();
182         InitLights();
183         InitMap();
184         InitBubbles();
185         InitObjects();
186         InitLava();
187         InitPushBlocks();
188         InitAnubis();
189         InitSpider();
190         InitMummy();
191         InitScorp();
192         InitPlayer();
193         InitItems();
194         InitInput();
195 
196         if (nMap == kMap20) {
197             InitEnergyTile();
198         }
199     }
200 
201     if (nMap > 15)
202     {
203         nSwitchSound = 35;
204         nStoneSound = 23;
205         nElevSound = 51;
206         nStopSound = 35;
207     }
208     else
209     {
210         nSwitchSound = 33;
211         nStoneSound = 23;
212         nElevSound = 23;
213         nStopSound = 66;
214     }
215 
216     if (nMap < 0) {
217         return kFalse;
218     }
219 
220 #if 0
221     {
222         // going to load the map without loadboard() - to take care of version 6 to 7 map conversion
223         //int hFile = kopen4load(fileName_1, 1);
224         int hFile = kopen4load(fileName_1, 0);
225         //	int hFile = open(fileName_1, O_BINARY | O_RDONLY);
226         if (hFile == -1) {
227             return kFalse;
228         }
229 
230         int version;
231 
232         kread(hFile, &version, sizeof(version));
233         if (version != 6) {
234             bIsVersion6 = kFalse;
235         }
236 
237         initspritelists();
238 
239         memset(show2dsector, 0, sizeof(show2dsector));
240         memset(show2dsprite, 0, sizeof(show2dsprite));
241         memset(show2dwall,   0, sizeof(show2dwall));
242 
243         // replacement for build's loadboard()
244         kread(hFile, &initx, 4);
245         kread(hFile, &inity, 4);
246         kread(hFile, &initz, 4);
247         kread(hFile, &inita, 2);
248         kread(hFile, &initsect, 2);
249 
250         // sectors
251         short nSectors;
252         kread(hFile, &nSectors, sizeof(nSectors));
253 
254         if (bIsVersion6) {
255             kread(hFile, sector_6, sizeof(Sector_6) * nSectors);
256         }
257         else {
258             kread(hFile, sector, sizeof(SECTOR) * nSectors);
259         }
260 
261         // walls
262         short nWalls;
263         kread(hFile, &nWalls, sizeof(nWalls));
264 
265         if (bIsVersion6) {
266             kread(hFile, wall_6, sizeof(Wall_6) * nWalls);
267         }
268         else {
269             kread(hFile, wall, sizeof(WALL) * nWalls);
270         }
271 
272         // sprites
273         short nSprites;
274         kread(hFile, &nSprites, sizeof(nSprites));
275 
276         if (bIsVersion6) {
277             kread(hFile, sprite_6, sizeof(Sprite_6) * nSprites);
278         }
279         else {
280             kread(hFile, sprite, sizeof(SPRITE) * nSprites);
281         }
282 
283         // set engine variables
284         numsectors = nSectors;
285         numwalls = nWalls;
286 
287         // load in our version 6 structs to the engines v7 structs if required
288         if (bIsVersion6)
289         {
290             for (int nSector = 0; nSector < nSectors; nSector++)
291             {
292                 sector[nSector].ceilingz = sector_6[nSector].ceilingz;
293                 sector[nSector].floorz = sector_6[nSector].floorz;
294                 sector[nSector].wallptr = sector_6[nSector].wallptr;
295                 sector[nSector].wallnum = sector_6[nSector].wallnum;
296                 sector[nSector].ceilingpicnum = sector_6[nSector].ceilingpicnum;
297                 sector[nSector].ceilingheinum = Max(Min(((int)sector_6[nSector].ceilingheinum) << 5, 32767), -32768);
298 
299                 if ((sector_6[nSector].ceilingstat & 2) == 0) {
300                     sector[nSector].ceilingheinum = 0;
301                 }
302 
303                 sector[nSector].ceilingshade = sector_6[nSector].ceilingshade;
304                 sector[nSector].ceilingpal = sector_6[nSector].ceilingpal;
305                 sector[nSector].ceilingxpanning = sector_6[nSector].ceilingxpanning;
306                 sector[nSector].ceilingypanning = sector_6[nSector].ceilingypanning;
307                 sector[nSector].floorpicnum = sector_6[nSector].floorpicnum;
308                 sector[nSector].floorheinum = Max(Min(((int)sector_6[nSector].floorheinum) << 5, 32767), -32768);
309 
310                 if ((sector_6[nSector].floorstat & 2) == 0) {
311                     sector[nSector].floorheinum = 0;
312                 }
313 
314                 sector[nSector].floorshade = sector_6[nSector].floorshade;
315                 sector[nSector].floorpal = sector_6[nSector].floorpal;
316                 sector[nSector].floorxpanning = sector_6[nSector].floorxpanning;
317                 sector[nSector].floorypanning = sector_6[nSector].floorypanning;
318                 sector[nSector].ceilingstat = sector_6[nSector].ceilingstat;
319                 sector[nSector].floorstat = sector_6[nSector].floorstat;
320                 sector[nSector].visibility = sector_6[nSector].visibility;
321                 sector[nSector].filler = 0;
322                 sector[nSector].lotag = sector_6[nSector].lotag;
323                 sector[nSector].hitag = sector_6[nSector].hitag;
324                 sector[nSector].extra = sector_6[nSector].extra;
325             }
326 
327             for (int nWall = 0; nWall < nWalls; nWall++)
328             {
329                 wall[nWall].x = wall_6[nWall].x;
330                 wall[nWall].y = wall_6[nWall].y;
331                 wall[nWall].point2 = wall_6[nWall].point2;
332                 wall[nWall].nextwall = wall_6[nWall].nextwall;
333                 wall[nWall].nextsector = wall_6[nWall].nextsector;
334                 wall[nWall].cstat = wall_6[nWall].cstat;
335                 wall[nWall].picnum = wall_6[nWall].picnum;
336                 wall[nWall].overpicnum = wall_6[nWall].overpicnum;
337                 wall[nWall].shade = wall_6[nWall].shade;
338                 wall[nWall].pal = wall_6[nWall].pal;
339                 wall[nWall].xrepeat = wall_6[nWall].xrepeat;
340                 wall[nWall].yrepeat = wall_6[nWall].yrepeat;
341                 wall[nWall].xpanning = wall_6[nWall].xpanning;
342                 wall[nWall].ypanning = wall_6[nWall].ypanning;
343                 wall[nWall].lotag = wall_6[nWall].lotag;
344                 wall[nWall].hitag = wall_6[nWall].hitag;
345                 wall[nWall].extra = wall_6[nWall].extra;
346             }
347 
348             for (int nSprite = 0; nSprite < nSprites; nSprite++)
349             {
350                 sprite[nSprite].x = sprite_6[nSprite].x;
351                 sprite[nSprite].y = sprite_6[nSprite].y;
352                 sprite[nSprite].z = sprite_6[nSprite].z;
353                 sprite[nSprite].cstat = sprite_6[nSprite].cstat;
354                 sprite[nSprite].picnum = sprite_6[nSprite].picnum;
355                 sprite[nSprite].shade = sprite_6[nSprite].shade;
356                 sprite[nSprite].pal = sprite_6[nSprite].pal;
357                 sprite[nSprite].clipdist = sprite_6[nSprite].clipdist;
358                 sprite[nSprite].filler = 0;
359                 sprite[nSprite].xrepeat = sprite_6[nSprite].xrepeat;
360                 sprite[nSprite].yrepeat = sprite_6[nSprite].yrepeat;
361                 sprite[nSprite].xoffset = sprite_6[nSprite].xoffset;
362                 sprite[nSprite].yoffset = sprite_6[nSprite].yoffset;
363                 sprite[nSprite].sectnum = sprite_6[nSprite].sectnum;
364                 sprite[nSprite].statnum = sprite_6[nSprite].statnum;
365                 sprite[nSprite].ang = sprite_6[nSprite].ang;
366                 sprite[nSprite].owner = sprite_6[nSprite].owner;
367                 sprite[nSprite].xvel = sprite_6[nSprite].xvel;
368                 sprite[nSprite].yvel = sprite_6[nSprite].yvel;
369                 sprite[nSprite].zvel = sprite_6[nSprite].zvel;
370                 sprite[nSprite].lotag = sprite_6[nSprite].lotag;
371                 sprite[nSprite].hitag = sprite_6[nSprite].hitag;
372                 sprite[nSprite].extra = sprite_6[nSprite].extra;
373             }
374         }
375 
376         for (int nSprite = 0; nSprite < nSprites; nSprite++) {
377             insertsprite(sprite[nSprite].sectnum, sprite[nSprite].statnum);
378         }
379 
380         updatesector(initx, inity, &initsect);
381 
382         kclose(hFile);
383         hFile = -1;
384     }
385     // loadboard has finished
386 #endif
387     vec3_t startPos;
388     int status = engineLoadBoard(fileName_1, 0, &startPos, &inita, &initsect);
389     if (status == -2)
390         status = engineLoadBoardV5V6(fileName_1, 0, &startPos, &inita, &initsect);
391     initx = startPos.x;
392     inity = startPos.y;
393     initz = startPos.z;
394 
395 #ifdef YAX_ENABLE
396     yax_update(1);
397 #endif
398 
399     int i;
400 
401     for (i = 0; i < kMaxPlayers; i++)
402     {
403         PlayerList[i].nSprite = -1;
404     }
405 
406     psky_t* pSky = tileSetupSky(0);
407 
408     pSky->tileofs[0] = 0;
409     pSky->tileofs[1] = 0;
410     pSky->tileofs[2] = 0;
411     pSky->tileofs[3] = 0;
412     pSky->yoffs = 256;
413     pSky->lognumtiles = 2;
414     pSky->horizfrac = 65536;
415     pSky->yscale = 65536;
416     parallaxtype = 2;
417     g_visibility = 2048;
418     flash = 0;
419     precache();
420 
421     LoadObjects();
422 
423     levelnum = nMap;
424 
425     return kTrue;
426 }
427 
ResetEngine()428 void ResetEngine()
429 {
430     SetOverscan(BASEPAL);
431 
432     EraseScreen(-1);
433 
434     resettiming();
435 
436     totalclock  = 0;
437     ototalclock = totalclock;
438     localclock  = (int)totalclock;
439 
440     numframes = 0;
441 }
442 
InstallEngine()443 void InstallEngine()
444 {
445     // initgroupfile("stuff.dat");
446 
447     char *cwd;
448 
449     if (g_modDir[0] != '/' && (cwd = buildvfs_getcwd(NULL, 0)))
450     {
451         buildvfs_chdir(g_modDir);
452         if (artLoadFiles("tiles%03i.art", MAXCACHE1DSIZE) < 0)
453         {
454             buildvfs_chdir(cwd);
455             if (artLoadFiles("tiles%03i.art", MAXCACHE1DSIZE) < 0)
456                 bail2dos("Failed loading art.");
457         }
458         buildvfs_chdir(cwd);
459 #ifndef __ANDROID__ //This crashes on *some* Android devices. Small onetime memory leak. TODO fix above function
460         Xfree(cwd);
461 #endif
462     }
463     else if (artLoadFiles("tiles%03i.art",MAXCACHE1DSIZE) < 0)
464         bail2dos("Failed loading art.");
465 
466     // TEMP
467 
468     //nScreenWidth *= 2;
469     //nScreenHeight *= 2;
470     bHiRes = kTrue;
471     // TEMP
472 
473     if (engineInit())
474     {
475         wm_msgbox("Fatal Engine Initialization Error",
476                   "There was a problem initializing the engine: %s\n\nThe application will now close.", engineerrstr);
477         //TODO:
478         //G_Cleanup();
479         ERRprintf("G_Startup: There was a problem initializing the engine: %s\n", engineerrstr);
480         exit(6);
481     }
482     if (videoSetGameMode(gSetup.fullscreen, gSetup.xdim, gSetup.ydim, gSetup.bpp, 0) < 0)
483     {
484         initprintf("Failure setting video mode %dx%dx%d %s! Trying next mode...\n", gSetup.xdim, gSetup.ydim,
485                     gSetup.bpp, gSetup.fullscreen ? "fullscreen" : "windowed");
486 
487         int resIdx = 0;
488 
489         for (int i=0; i < validmodecnt; i++)
490         {
491             if (validmode[i].xdim == gSetup.xdim && validmode[i].ydim == gSetup.ydim)
492             {
493                 resIdx = i;
494                 break;
495             }
496         }
497 
498         int const savedIdx = resIdx;
499         int bpp = gSetup.bpp;
500 
501         while (videoSetGameMode(0, validmode[resIdx].xdim, validmode[resIdx].ydim, bpp, 0) < 0)
502         {
503             initprintf("Failure setting video mode %dx%dx%d windowed! Trying next mode...\n",
504                         validmode[resIdx].xdim, validmode[resIdx].ydim, bpp);
505 
506             if (++resIdx == validmodecnt)
507             {
508                 if (bpp == 8)
509                     bail2dos("Fatal error: unable to set any video mode!");
510 
511                 resIdx = savedIdx;
512                 bpp = 8;
513             }
514         }
515 
516         gSetup.xdim = validmode[resIdx].xdim;
517         gSetup.ydim = validmode[resIdx].ydim;
518         gSetup.bpp  = bpp;
519     }
520 
521     LoadPaletteLookups();
522 
523     enginecompatibilitymode = ENGINE_19950829;
524 }
525 
RemoveEngine()526 void RemoveEngine()
527 {
528     engineUnInit();
529     uninitgroupfile();
530 }
531 
SetBelow(short nCurSector,short nBelowSector)532 void SetBelow(short nCurSector, short nBelowSector)
533 {
534     SectBelow[nCurSector] = nBelowSector;
535 }
536 
SetAbove(short nCurSector,short nAboveSector)537 void SetAbove(short nCurSector, short nAboveSector)
538 {
539     SectAbove[nCurSector] = nAboveSector;
540 }
541 
SnapSectors(short nSectorA,short nSectorB,short b)542 void SnapSectors(short nSectorA, short nSectorB, short b)
543 {
544     // edx - nSectorA
545     // eax - nSectorB
546 
547     short nWallA = sector[nSectorA].wallptr;
548     short nWallB = sector[nSectorB].wallptr;
549 
550     short num1 = sector[nSectorA].wallnum;
551     short num2 = sector[nSectorB].wallnum;
552 
553     int nCount = 0;
554 
555     while (num1 > nCount)
556     {
557         short dx = nWallB;
558 
559         int esi = 0x7FFFFFF;
560         int edi = esi;
561 
562         int x = wall[nWallA].x;
563         int y = wall[nWallA].y;
564 
565         int var_14 = 0;
566 
567         int nCount2 = 0;
568 
569         while (nCount2 < num2)
570         {
571             int eax = x - wall[dx].x;
572             int ebx = y - wall[dx].y;
573 
574             if (eax < 0) {
575                 eax = -eax;
576             }
577 
578             int var_38 = eax;
579 
580             if (ebx < 0) {
581                 ebx = -ebx;
582             }
583 
584             int var_3C = ebx;
585 
586             var_38 += var_3C;
587 
588             eax = esi;
589             if (eax < 0) {
590                 eax = -eax;
591             }
592 
593             var_3C = eax;
594 
595             eax = edi;
596 //			int var_34 = edi;
597             if (eax < 0) {
598                 eax = -eax;
599             }
600 
601             int var_34 = eax;
602 
603             var_34 += var_3C;
604 
605             if (var_38 < var_34)
606             {
607                 esi = x - wall[dx].x;
608                 edi = y - wall[dx].y;
609                 var_14 = dx;
610             }
611 
612             dx++;
613             nCount2++;
614         }
615 
616         dragpoint(var_14, wall[var_14].x + esi, wall[var_14].y + edi, 0);
617 
618         nCount++;
619         nWallA++;
620     }
621 
622     if (b) {
623         sector[nSectorB].ceilingz = sector[nSectorA].floorz;
624     }
625 
626     if (SectFlag[nSectorA] & 0x1000) {
627         SnapBobs(nSectorA, nSectorB);
628     }
629 }
630 
InitSectFlag()631 void InitSectFlag()
632 {
633     for (int i = 0; i < kMaxSectors; i++)
634     {
635         SectSoundSect[i] = -1;
636         SectSound[i] = -1;
637         SectAbove[i] = -1;
638         SectBelow[i] = -1;
639         SectDepth[i] = 0;
640         SectFlag[i]  = 0;
641         SectSpeed[i] = 0;
642         SectDamage[i] = 0;
643     }
644 }
645 
ProcessSpriteTag(short nSprite,short nLotag,short nHitag)646 void ProcessSpriteTag(short nSprite, short nLotag, short nHitag)
647 {
648     int nChannel = runlist_AllocChannel(nHitag % 1000);
649 
650     int nSpeed = nLotag / 1000;
651     if (!nSpeed) {
652         nSpeed = 1;
653     }
654 
655     int nVal = nHitag;
656 
657     if (nLotag >= 900 && nLotag <= 949)
658     {
659         ProcessTrailSprite(nSprite, nLotag, nHitag);
660         return;
661     }
662 
663     // handle tags 6 to 60
664     switch (nLotag)
665     {
666         case 8: // M-60 ammo belt
667         {
668             nVal = 3 * (nHitag / 3);
669             // fall through to 6,7 etc
670             fallthrough__;
671         }
672         case 6:
673         case 7:
674         case 9:
675         case 10:
676         case 11:
677         case 15:
678         case 17:
679         case 18:
680         case 19:
681         case 20:
682         case 21:
683         case 22:
684         case 23:
685         case 24:
686         case 26:
687         case 28:
688         case 29:
689         case 30:
690         case 31:
691         case 32:
692         case 33:
693         case 34:
694         case 35:
695         case 36:
696         case 37:
697         case 39:
698         case 40:
699         case 41:
700         case 42:
701         case 43:
702         case 44:
703         case 45:
704         case 46:
705         case 47:
706         case 48:
707         case 49:
708         case 50:
709         case 51:
710         case 52:
711         case 53:
712         case 54:
713         case 55:
714         case 56:
715         case 57:
716         case 58:
717         case 60:
718         {
719             sprite[nSprite].hitag = nVal;
720             changespritestat(nSprite, nLotag + 900);
721             sprite[nSprite].cstat &= 0xFEFE;
722             BuildItemAnim(nSprite);
723             return;
724         }
725         case 12: // berry twig
726         {
727             sprite[nSprite].hitag = 40;
728             changespritestat(nSprite, nLotag + 900);
729             sprite[nSprite].cstat &= 0xFEFE;
730             BuildItemAnim(nSprite);
731             return;
732         }
733         case 13: // blood bowl
734         {
735             sprite[nSprite].hitag = 160;
736             changespritestat(nSprite, nLotag + 900);
737             sprite[nSprite].cstat &= 0xFEFE;
738             BuildItemAnim(nSprite);
739             return;
740         }
741         case 14: // venom bowl
742         {
743             sprite[nSprite].hitag = -200;
744             changespritestat(nSprite, nLotag + 900);
745             sprite[nSprite].cstat &= 0xFEFE;
746             BuildItemAnim(nSprite);
747             return;
748         }
749 
750         case 16:
751             // reserved
752             mydeletesprite(nSprite);
753             return;
754 
755         case 25:
756         case 59:
757         {
758             // extra life or checkpoint scarab. Delete for multiplayer
759             if (nNetPlayerCount != 0)
760             {
761                 mydeletesprite(nSprite);
762                 return;
763             }
764             else
765             {
766                 sprite[nSprite].hitag = nVal;
767                 changespritestat(nSprite, nLotag + 900);
768                 sprite[nSprite].cstat &= 0xFEFE;
769                 BuildItemAnim(nSprite);
770                 return;
771             }
772         }
773         case 27:
774         {
775             sprite[nSprite].hitag = 1;
776             changespritestat(nSprite, 9 + 900);
777             sprite[nSprite].cstat &= 0xFEFE;
778             BuildItemAnim(nSprite);
779             return;
780         }
781 
782         case 38: // raw energy
783         {
784             nVal++;
785             nVal--; // CHECKME ??
786             sprite[nSprite].hitag = nVal;
787             changespritestat(nSprite, nLotag + 900);
788             sprite[nSprite].cstat &= 0xFEFE;
789             BuildItemAnim(nSprite);
790             return;
791         }
792     }
793 
794     int v6 = nLotag % 1000;
795 
796     if (!bNoCreatures || v6 < 100 || v6 > 118)
797     {
798         if (v6 > 999) {
799             mydeletesprite(nSprite);
800             return;
801         }
802 
803         switch (v6)
804         {
805             case 999:
806             {
807                 AddFlicker(sprite[nSprite].sectnum, nSpeed);
808                 break;
809             }
810             case 998:
811             {
812                 AddGlow(sprite[nSprite].sectnum, nSpeed);
813                 break;
814             }
815             case 118: // Anubis with drum
816             {
817                 if (bNoCreatures) {
818                     mydeletesprite(nSprite);
819                     return;
820                 }
821 
822                 BuildAnubis(nSprite, 0, 0, 0, 0, 0, 1);
823                 return;
824             }
825             case 117:
826             {
827                 if (bNoCreatures) {
828                     mydeletesprite(nSprite);
829                     return;
830                 }
831 
832                 BuildWasp(nSprite, 0, 0, 0, 0, 0);
833                 return;
834             }
835             case 116:
836             {
837                 BuildRat(nSprite, 0, 0, 0, 0, -1);
838                 return;
839             }
840             case 115: // Rat (eating)
841             {
842                 BuildRat(nSprite, 0, 0, 0, 0, 0);
843                 return;
844             }
845             case 113:
846             {
847                 BuildQueen(nSprite, 0, 0, 0, 0, 0, nChannel);
848                 return;
849             }
850             case 112:
851             {
852                 BuildScorp(nSprite, 0, 0, 0, 0, 0, nChannel);
853                 return;
854             }
855             case 111:
856             {
857                 if (bNoCreatures) {
858                     mydeletesprite(nSprite);
859                     return;
860                 }
861 
862                 BuildSet(nSprite, 0, 0, 0, 0, 0, nChannel);
863                 return;
864             }
865             case 108:
866             {
867                 if (bNoCreatures) {
868                     mydeletesprite(nSprite);
869                     return;
870                 }
871 
872                 BuildLava(nSprite, 0, 0, 0, 0, 0, nChannel);
873                 return;
874             }
875             case 107:
876             {
877                 if (bNoCreatures) {
878                     mydeletesprite(nSprite);
879                     return;
880                 }
881 
882                 BuildRex(nSprite, 0, 0, 0, 0, 0, nChannel);
883                 return;
884             }
885             case 106:
886             {
887                 if (bNoCreatures) {
888                     mydeletesprite(nSprite);
889                     return;
890                 }
891 
892                 BuildFish(nSprite, 0, 0, 0, 0, 0);
893                 return;
894             }
895             case 105:
896             {
897                 if (bNoCreatures) {
898                     mydeletesprite(nSprite);
899                     return;
900                 }
901 
902                 BuildSpider(nSprite, 0, 0, 0, 0, 0);
903                 return;
904             }
905             case 104:
906             {
907                 if (bNoCreatures) {
908                     mydeletesprite(nSprite);
909                     return;
910                 }
911 
912                 BuildRoach(1, nSprite, 0, 0, 0, 0, 0);
913                 return;
914             }
915             case 103:
916             {
917                 if (bNoCreatures) {
918                     mydeletesprite(nSprite);
919                     return;
920                 }
921 
922                 BuildRoach(0, nSprite, 0, 0, 0, 0, 0);
923                 return;
924             }
925             case 102:
926             {
927                 if (bNoCreatures) {
928                     mydeletesprite(nSprite);
929                     return;
930                 }
931 
932                 BuildLion(nSprite, 0, 0, 0, 0, 0);
933                 return;
934             }
935             case 101:
936             {
937                 if (bNoCreatures) {
938                     mydeletesprite(nSprite);
939                     return;
940                 }
941 
942                 BuildMummy(nSprite, 0, 0, 0, 0, 0);
943                 return;
944             }
945             case 100:
946             {
947                 if (bNoCreatures) {
948                     mydeletesprite(nSprite);
949                     return;
950                 }
951 
952                 BuildAnubis(nSprite, 0, 0, 0, 0, 0, 0);
953                 return;
954             }
955             case 99: // underwater type 2
956             {
957                 short nSector = sprite[nSprite].sectnum;
958                 SetAbove(nSector, nHitag);
959                 SectFlag[nSector] |= kSectUnderwater;
960 
961                 mydeletesprite(nSprite);
962                 return;
963             }
964             case 98:
965             {
966                 short nSector = sprite[nSprite].sectnum;
967                 SetBelow(nSector, nHitag);
968                 SnapSectors(nSector, nHitag, 1);
969 
970                 mydeletesprite(nSprite);
971                 return;
972             }
973             case 97:
974             {
975                 AddSectorBob(sprite[nSprite].sectnum, nHitag, 1);
976 
977                 mydeletesprite(nSprite);
978                 return;
979             }
980             case 96: // Lava sector
981             {
982                 int nDamage = nHitag / 4;
983                 if (!nDamage) {
984                     nDamage = 1;
985                 }
986 
987                 short nSector = sprite[nSprite].sectnum;
988 
989                 SectDamage[nSector] = nDamage;
990                 SectFlag[nSector] |= kSectLava;
991 
992                 mydeletesprite(nSprite);
993                 return;
994             }
995             case 95:
996             {
997                 AddSectorBob(sprite[nSprite].sectnum, nHitag, 0);
998 
999                 mydeletesprite(nSprite);
1000                 return;
1001             }
1002             case 94: // water
1003             {
1004                 short nSector = sprite[nSprite].sectnum;
1005                 SectDepth[nSector] = nHitag << 8;
1006 
1007                 mydeletesprite(nSprite);
1008                 return;
1009             }
1010             case 93:
1011             {
1012                 BuildBubbleMachine(nSprite);
1013                 return;
1014             }
1015             case 90:
1016             {
1017                 BuildObject(nSprite, 3, nHitag);
1018                 return;
1019             }
1020             case 79:
1021             case 89:
1022             {
1023                 short nSector = sprite[nSprite].sectnum;
1024 
1025                 SectSpeed[nSector] = nSpeed;
1026                 SectFlag[nSector] |= sprite[nSprite].ang;
1027 
1028                 mydeletesprite(nSprite);
1029                 return;
1030             }
1031             case 88:
1032             {
1033                 AddFlow(nSprite, nSpeed, 0);
1034 
1035                 mydeletesprite(nSprite);
1036                 return;
1037             }
1038             case 80: // underwater
1039             {
1040                 short nSector = sprite[nSprite].sectnum;
1041                 SectFlag[nSector] |= kSectUnderwater;
1042 
1043                 mydeletesprite(nSprite);
1044                 return;
1045             }
1046             case 78:
1047             {
1048                 AddFlow(nSprite, nSpeed, 1);
1049 
1050                 short nSector = sprite[nSprite].sectnum;
1051                 SectFlag[nSector] |= 0x8000;
1052 
1053                 mydeletesprite(nSprite);
1054                 return;
1055             }
1056             case 77:
1057             {
1058                 int nArrow = BuildArrow(nSprite, nSpeed);
1059 
1060                 runlist_AddRunRec(sRunChannels[nChannel].a, nArrow);
1061                 return;
1062             }
1063             case 76: // Explosion Trigger (Exploding Fire Cauldron)
1064             {
1065                 BuildObject(nSprite, 0, nHitag);
1066                 return;
1067             }
1068             case 75: // Explosion Target (Cauldrons, fireballs and grenades will destroy nearby 75 sprites)
1069             {
1070                 BuildObject(nSprite, 1, nHitag);
1071                 return;
1072             }
1073             case 71:
1074             {
1075                 int nFireball = BuildFireBall(nSprite, nHitag, nSpeed);
1076 
1077                 runlist_AddRunRec(sRunChannels[nChannel].a, nFireball);
1078                 return;
1079             }
1080             case 70:
1081             {
1082                 BuildDrip(nSprite);
1083                 return;
1084             }
1085             case 63:
1086             {
1087                 changespritestat(nSprite, 405);
1088                 sprite[nSprite].cstat = 0x8000;
1089                 return;
1090             }
1091             case 62:
1092             {
1093                 nNetStartSprite[nNetStartSprites] = nSprite;
1094                 sprite[nSprite].cstat = 0x8000;
1095 
1096                 nNetStartSprites++;
1097                 return;
1098             }
1099             case kTagRamses: // Ramses head
1100             {
1101                 nSpiritSprite = nSprite;
1102                 sprite[nSprite].cstat |= 0x8000;
1103                 return;
1104             }
1105             default: // TODO - checkme!
1106             {
1107                 mydeletesprite(nSprite);
1108                 return;
1109             }
1110         }
1111     }
1112 
1113     mydeletesprite(nSprite);
1114 }
1115 
ExamineSprites()1116 void ExamineSprites()
1117 {
1118     nNetStartSprites = 0;
1119     nCurStartSprite = 0;
1120 
1121     for (int nSprite = 0; nSprite < kMaxSprites; nSprite++)
1122     {
1123         int nStatus = sprite[nSprite].statnum;
1124         if (!nStatus)
1125         {
1126             short lotag = sprite[nSprite].lotag;
1127             short hitag = sprite[nSprite].hitag;
1128 
1129             if ((nStatus < kMaxStatus) && lotag)
1130             {
1131                 sprite[nSprite].lotag = 0;
1132                 sprite[nSprite].hitag = 0;
1133 
1134                 ProcessSpriteTag(nSprite, lotag, hitag);
1135             }
1136             else
1137             {
1138                 changespritestat(nSprite, 0);
1139             }
1140         }
1141     }
1142 
1143     if (nNetPlayerCount)
1144     {
1145         int nSprite = insertsprite(initsect, 0);
1146         sprite[nSprite].x = initx;
1147         sprite[nSprite].y = inity;
1148         sprite[nSprite].z = initz;
1149         sprite[nSprite].cstat = 0x8000;
1150         nNetStartSprite[nNetStartSprites] = nSprite;
1151         nNetStartSprites++;
1152     }
1153 }
1154 
LoadObjects()1155 void LoadObjects()
1156 {
1157     runlist_InitRun();
1158     runlist_InitChan();
1159     InitLink();
1160     InitPoint();
1161     InitSlide();
1162     InitSwitch();
1163     InitElev();
1164     InitWallFace();
1165     InitTimeSlot();
1166     InitSectFlag();
1167 
1168     for (int nSector = 0; nSector < numsectors; nSector++)
1169     {
1170         short hitag = sector[nSector].hitag;
1171         short lotag = sector[nSector].lotag;
1172 
1173         sector[nSector].hitag = 0;
1174         sector[nSector].lotag = 0;
1175         sector[nSector].extra = -1;
1176 
1177         if (hitag || lotag)
1178         {
1179             sector[nSector].lotag = runlist_HeadRun() + 1;
1180             sector[nSector].hitag = lotag;
1181 
1182             runlist_ProcessSectorTag(nSector, lotag, hitag);
1183         }
1184     }
1185 
1186     for (int nWall = 0; nWall < numwalls; nWall++)
1187     {
1188         wall[nWall].extra = -1;
1189 
1190         short lotag = wall[nWall].lotag;
1191         short hitag = wall[nWall].hitag;
1192 
1193         wall[nWall].lotag = 0;
1194 
1195         if (hitag || lotag)
1196         {
1197             wall[nWall].lotag = runlist_HeadRun() + 1;
1198             runlist_ProcessWallTag(nWall, lotag, hitag);
1199         }
1200     }
1201 
1202     ExamineSprites();
1203     PostProcess();
1204     InitRa();
1205     InitChunks();
1206 
1207     for (int nChannel = 0; nChannel < kMaxChannels; nChannel++)
1208     {
1209         runlist_ChangeChannel(nChannel, 0);
1210         runlist_ReadyChannel(nChannel);
1211     }
1212 
1213     nCamerax = initx;
1214     nCameray = inity;
1215     nCameraz = initz;
1216 }
1217 
1218