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