]> 4ch.mooo.com Git - 16.git/blob - src/lib/hp/game/c3_game.c
pcxtest.exe and pcxtest2.exe compiles but we are unable to test because of compiling...
[16.git] / src / lib / hp / game / c3_game.c
1 /* Catacomb 3-D Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // C3_GAME.C\r
20 \r
21 #include "C3_DEF.H"\r
22 #pragma hdrstop\r
23 \r
24 #ifdef PROFILE\r
25 #include "TIME.H"\r
26 #endif\r
27 \r
28 \r
29 /*\r
30 =============================================================================\r
31 \r
32                                                  LOCAL CONSTANTS\r
33 \r
34 =============================================================================\r
35 */\r
36 \r
37 #define NUMLUMPS        25\r
38 \r
39 #define CONTROLSLUMP    0\r
40 #define ORCLUMP         1\r
41 #define TROLLLUMP        2\r
42 #define WARPLUMP        3\r
43 #define BOLTLUMP        4\r
44 #define NUKELUMP        5\r
45 #define POTIONLUMP      6\r
46 #define RKEYLUMP        7\r
47 #define YKEYLUMP        8\r
48 #define GKEYLUMP        9\r
49 #define BKEYLUMP        10\r
50 #define SCROLLLUMP      11\r
51 #define CHESTLUMP       12\r
52 #define PLAYERLUMP      13\r
53 #define WALL1LUMP       14\r
54 #define WALL2LUMP       15\r
55 #define BDOORLUMP       16\r
56 #define DEMONLUMP               17\r
57 #define MAGELUMP                18\r
58 #define BATLUMP                 19\r
59 #define GRELLUMP                20\r
60 #define GOALLUMP                21\r
61 \r
62 \r
63 int     lumpstart[NUMLUMPS] = {\r
64 CONTROLS_LUMP_START,\r
65 ORC_LUMP_START,\r
66 TROLL_LUMP_START,\r
67 WARP_LUMP_START,\r
68 BOLT_LUMP_START,\r
69 NUKE_LUMP_START,\r
70 POTION_LUMP_START,\r
71 RKEY_LUMP_START,\r
72 YKEY_LUMP_START,\r
73 GKEY_LUMP_START,\r
74 BKEY_LUMP_START,\r
75 SCROLL_LUMP_START,\r
76 CHEST_LUMP_START,\r
77 PLAYER_LUMP_START,\r
78 WALL1_LUMP_START,\r
79 WALL2_LUMP_START,\r
80 BDOOR_LUMP_START,\r
81 DEMON_LUMP_START,\r
82 MAGE_LUMP_START,\r
83 BAT_LUMP_START,\r
84 GREL_LUMP_START,\r
85 NEMESISPIC\r
86 };\r
87 \r
88 \r
89 int     lumpend[NUMLUMPS] = {\r
90 CONTROLS_LUMP_END,\r
91 ORC_LUMP_END,\r
92 TROLL_LUMP_END,\r
93 WARP_LUMP_END,\r
94 BOLT_LUMP_END,\r
95 NUKE_LUMP_END,\r
96 POTION_LUMP_END,\r
97 RKEY_LUMP_END,\r
98 YKEY_LUMP_END,\r
99 GKEY_LUMP_END,\r
100 BKEY_LUMP_END,\r
101 SCROLL_LUMP_END,\r
102 CHEST_LUMP_END,\r
103 PLAYER_LUMP_END,\r
104 WALL1_LUMP_END,\r
105 WALL2_LUMP_END,\r
106 BDOOR_LUMP_END,\r
107 DEMON_LUMP_END,\r
108 MAGE_LUMP_END,\r
109 BAT_LUMP_END,\r
110 GREL_LUMP_END,\r
111 NEMESISPIC\r
112 };\r
113 \r
114 \r
115 \r
116 /*\r
117 =============================================================================\r
118 \r
119                                                  GLOBAL VARIABLES\r
120 \r
121 =============================================================================\r
122 */\r
123 \r
124 unsigned        latchpics[NUMLATCHPICS];\r
125 unsigned        tileoffsets[NUMTILE16];\r
126 unsigned        textstarts[27];\r
127 \r
128 /*\r
129 =============================================================================\r
130 \r
131                                                  LOCAL VARIABLES\r
132 \r
133 =============================================================================\r
134 */\r
135 \r
136 boolean lumpneeded[NUMLUMPS];\r
137 \r
138 \r
139 //===========================================================================\r
140 \r
141 \r
142 /*\r
143 ==========================\r
144 =\r
145 = ScanInfoPlane\r
146 =\r
147 = Spawn all actors and mark down special places\r
148 =\r
149 ==========================\r
150 */\r
151 \r
152 void ScanInfoPlane (void)\r
153 {\r
154         unsigned        x,y,i,j;\r
155         int                     tile;\r
156         unsigned        far     *start;\r
157 \r
158         InitObjList();                  // start spawning things with a clean slate\r
159 \r
160         memset (lumpneeded,0,sizeof(lumpneeded));\r
161 \r
162         start = mapsegs[2];\r
163         for (y=0;y<mapheight;y++)\r
164                 for (x=0;x<mapwidth;x++)\r
165                 {\r
166                         tile = *start++;\r
167                         if (!tile)\r
168                                 continue;\r
169 \r
170                         switch (tile)\r
171                         {\r
172                         case 1:\r
173                         case 2:\r
174                         case 3:\r
175                         case 4:\r
176                                 lumpneeded[PLAYERLUMP] = true;\r
177                                 SpawnPlayer(x,y,NORTH+tile-1);\r
178                                 break;\r
179 \r
180                         case 5:\r
181                         case 6:\r
182                         case 7:\r
183                         case 8:\r
184                         case 9:\r
185                         case 10:\r
186                         case 11:\r
187                                 lumpneeded[tile-5+BOLTLUMP] = true;\r
188                                 SpawnBonus(x,y,tile-5);\r
189                                 break;\r
190 \r
191                         case 12:\r
192                         case 13:\r
193                         case 14:\r
194                         case 15:\r
195                         case 16:\r
196                         case 17:\r
197                         case 18:\r
198                         case 19:\r
199                                 lumpneeded[SCROLLLUMP] = true;\r
200                                 SpawnBonus(x,y,B_SCROLL1+tile-12);\r
201                                 break;\r
202 \r
203                         case 20:        // goal\r
204                                 lumpneeded[GOALLUMP] = true;\r
205                                 SpawnBonus(x,y,B_GOAL);\r
206                                 break;\r
207 \r
208                         case 21:        // chest\r
209                                 lumpneeded[CHESTLUMP] = true;\r
210                                 SpawnBonus(x,y,B_CHEST);\r
211                                 break;\r
212 \r
213                         case 24:\r
214                                 lumpneeded[WARPLUMP] = true;\r
215                                 SpawnWarp (x,y,0);\r
216                                 break;\r
217 //------\r
218                         case 41:\r
219                                 if (gamestate.difficulty <gd_Hard)\r
220                                         break;\r
221                         case 36:\r
222                                 if (gamestate.difficulty <gd_Normal)\r
223                                         break;\r
224                         case 22:\r
225                                 lumpneeded[TROLLLUMP] = true;\r
226                                 SpawnTroll (x,y);\r
227                                 break;\r
228 \r
229                         case 42:\r
230                                 if (gamestate.difficulty <gd_Hard)\r
231                                         break;\r
232                         case 37:\r
233                                 if (gamestate.difficulty <gd_Normal)\r
234                                         break;\r
235                         case 23:\r
236                                 lumpneeded[ORCLUMP] = true;\r
237                                 SpawnOrc (x,y);\r
238                                 break;\r
239 \r
240                         case 43:\r
241                                 if (gamestate.difficulty <gd_Hard)\r
242                                         break;\r
243                         case 38:\r
244                                 if (gamestate.difficulty <gd_Normal)\r
245                                         break;\r
246                         case 25:\r
247                                 lumpneeded[BATLUMP] = true;\r
248                                 SpawnBat (x,y);\r
249                                 break;\r
250 \r
251                         case 44:\r
252                                 if (gamestate.difficulty <gd_Hard)\r
253                                         break;\r
254                         case 39:\r
255                                 if (gamestate.difficulty <gd_Normal)\r
256                                         break;\r
257                         case 26:\r
258                                 lumpneeded[DEMONLUMP] = true;\r
259                                 SpawnDemon (x,y);\r
260                                 break;\r
261 \r
262                         case 45:\r
263                                 if (gamestate.difficulty <gd_Hard)\r
264                                         break;\r
265                         case 40:\r
266                                 if (gamestate.difficulty <gd_Normal)\r
267                                         break;\r
268                         case 27:\r
269                                 lumpneeded[MAGELUMP] = true;\r
270                                 SpawnMage (x,y);\r
271                                 break;\r
272 \r
273                         case 28:\r
274                                 lumpneeded[GRELLUMP] = true;\r
275                                 SpawnNemesis (x,y);\r
276                                 break;\r
277 \r
278                         case 29:\r
279                                 SpawnBounce (x,y,0);\r
280                                 break;\r
281 \r
282                         case 30:\r
283                                 SpawnBounce (x,y,1);\r
284                                 break;\r
285 \r
286                         case 31:\r
287                         case 32:\r
288                         case 33:\r
289                         case 34:\r
290                                 lumpneeded[WARPLUMP] = true;\r
291                                 SpawnWarp (x,y,tile-30);\r
292                                 break;\r
293                         }\r
294                 }\r
295 \r
296 }\r
297 \r
298 //==========================================================================\r
299 \r
300 /*\r
301 ==================\r
302 =\r
303 = ScanText\r
304 =\r
305 ==================\r
306 */\r
307 \r
308 void ScanText (void)\r
309 {\r
310         int     i;\r
311         char far *text;\r
312 \r
313         text = (char _seg *)grsegs[LEVEL1TEXT+mapon];\r
314 \r
315         textstarts[0] = 0;\r
316 \r
317         for (i=1;i<=26;i++)\r
318         {\r
319                 while (*text != '\n')\r
320                 {\r
321                         if (*text == '\r')\r
322                                 *text = 0;\r
323                         text++;\r
324                 }\r
325                 text++;\r
326                 textstarts[i] = FP_OFF(text);\r
327         }\r
328 \r
329 }\r
330 \r
331 //==========================================================================\r
332 \r
333 /*\r
334 ==================\r
335 =\r
336 = DrawEnterScreen\r
337 =\r
338 ==================\r
339 */\r
340 \r
341 static  char    *levelnames[] =\r
342                                 {\r
343                                         "The Approach",\r
344                                         "Nemesis's Keep",\r
345                                         "Ground Floor",\r
346                                         "Second Floor",\r
347                                         "Third Floor",\r
348                                         "Tower One",\r
349                                         "Tower Two",\r
350                                         "Secret Halls",\r
351                                         "Access Floor",\r
352                                         "The Dungeon",\r
353                                         "Lower Dungeon",\r
354                                         "Catacomb",\r
355                                         "Lower Reaches",\r
356                                         "The Warrens",\r
357                                         "Hidden Caverns",\r
358                                         "The Fens of Insanity",\r
359                                         "Chaos Corridors",\r
360                                         "The Labyrinth",\r
361                                         "Halls of Blood",\r
362                                         "Nemesis's Lair"\r
363                                 };\r
364 void DrawEnterScreen (void)\r
365 {\r
366         int     x,y;\r
367 \r
368         VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,9);     // Medium blue\r
369 \r
370         x = (VIEWWIDTH - (18 * 8)) / 2 -3;\r
371         y = (VIEWHEIGHT - (5 * 8)) / 2;\r
372         VW_DrawPic(x / 8,y,ENTERPLAQUEPIC);\r
373 \r
374         WindowX = x;\r
375         WindowW = 18 * 8;\r
376         PrintY = (VIEWHEIGHT/2) + 3;\r
377         US_CPrint (levelnames[gamestate.mapon]);\r
378 }\r
379 \r
380 //==========================================================================\r
381 \r
382 boolean tileneeded[NUMFLOORS];\r
383 \r
384 \r
385 /*\r
386 ==================\r
387 =\r
388 = CacheScaleds\r
389 =\r
390 ==================\r
391 */\r
392 \r
393 void CacheScaleds (void)\r
394 {\r
395         int     i,j;\r
396         unsigned        source,dest;\r
397 \r
398         FreeUpMemory ();\r
399         CA_CacheGrChunk(LEVEL1TEXT+mapon);\r
400         ScanText ();\r
401 \r
402 //\r
403 // make sure we are displaying screenpage 0\r
404 //\r
405         if (screenpage)\r
406         {\r
407                 source = screenloc[screenpage];\r
408                 dest = screenloc[0];\r
409                 VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);\r
410                 screenpage = 0;\r
411                 VW_SetScreen (dest,0);\r
412                 displayofs = dest;\r
413         }\r
414 \r
415 //\r
416 // cache wall pictures\r
417 //\r
418         for (i=1;i<NUMFLOORS;i++)\r
419                 if (tileneeded[i])\r
420                 {\r
421                         SetupScaleWall (walllight1[i]);\r
422                         SetupScaleWall (walllight2[i]);\r
423                         SetupScaleWall (walldark1[i]);\r
424                         SetupScaleWall (walldark2[i]);\r
425                 }\r
426 \r
427 //\r
428 // cache the actor pictures\r
429 //\r
430         for (i=0;i<NUMLUMPS;i++)\r
431                 if (lumpneeded[i])\r
432                         for (j=lumpstart[i];j<=lumpend[i];j++)\r
433                                 SetupScalePic(j);\r
434 \r
435         source = screenloc[0];\r
436         for (i=1;i<=2;i++)\r
437         {\r
438                 dest = screenloc[i];\r
439                 VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);\r
440         }\r
441 \r
442         screenpage = 1;\r
443 }\r
444 \r
445 //==========================================================================\r
446 \r
447 /*\r
448 ==================\r
449 =\r
450 = SetupGameLevel\r
451 =\r
452 ==================\r
453 */\r
454 \r
455 void SetupGameLevel (void)\r
456 {\r
457         int     x,y,i;\r
458         unsigned        far *map,tile,spot;\r
459 \r
460         memset (tileneeded,0,sizeof(tileneeded));\r
461 //\r
462 // randomize if not a demo\r
463 //\r
464         if (DemoMode)\r
465         {\r
466                 US_InitRndT(false);\r
467                 gamestate.difficulty = gd_Normal;\r
468         }\r
469         else\r
470                 US_InitRndT(true);\r
471 \r
472 //\r
473 // load the level\r
474 //\r
475         CA_CacheMap (gamestate.mapon);\r
476 \r
477         mapwidth = mapheaderseg[mapon]->width;\r
478         mapheight = mapheaderseg[mapon]->height;\r
479 \r
480 //\r
481 // make a lookup table for the maps left edge\r
482 //\r
483         spot = 0;\r
484         for (y=0;y<mapheight;y++)\r
485         {\r
486           farmapylookup[y] = spot;\r
487           spot += mapwidth;\r
488         }\r
489 \r
490 //\r
491 // copy the wall data to a data segment array\r
492 //\r
493         memset (tilemap,0,sizeof(tilemap));\r
494         memset (actorat,0,sizeof(actorat));\r
495         map = mapsegs[0];\r
496         for (y=0;y<mapheight;y++)\r
497                 for (x=0;x<mapwidth;x++)\r
498                 {\r
499                         tile = *map++;\r
500                         if (tile<NUMFLOORS)\r
501                         {\r
502                                 tileneeded[tile] = true;\r
503                                 tilemap[x][y] = tile;\r
504                                 if (tile>=EXPWALLSTART && tile<EXPWALLSTART+NUMEXPWALLS)\r
505                                 {\r
506                                         tileneeded[WALLEXP] = tileneeded[WALLEXP+1]\r
507                                         = tileneeded[WALLEXP+2] = true;\r
508                                 }\r
509 \r
510                                 if (tile>0)\r
511                                         (unsigned)actorat[x][y] = tile;\r
512                         }\r
513                 }\r
514 \r
515 \r
516 //\r
517 // decide which graphics are needed and spawn actors\r
518 //\r
519         ScanInfoPlane ();\r
520 \r
521 //\r
522 // have the caching manager load and purge stuff to make sure all marks\r
523 // are in memory\r
524 //\r
525         CA_LoadAllSounds ();\r
526 \r
527 }\r
528 \r
529 \r
530 //==========================================================================\r
531 \r
532 /*\r
533 =====================\r
534 =\r
535 = LatchDrawPic\r
536 =\r
537 =====================\r
538 */\r
539 \r
540 void LatchDrawPic (unsigned x, unsigned y, unsigned picnum)\r
541 {\r
542         unsigned wide, height, source, dest;\r
543 \r
544         wide = pictable[picnum-STARTPICS].width;\r
545         height = pictable[picnum-STARTPICS].height;\r
546         dest = bufferofs + ylookup[y]+x;\r
547         source = latchpics[picnum-FIRSTLATCHPIC];\r
548 \r
549         EGAWRITEMODE(1);\r
550         EGAMAPMASK(15);\r
551 \r
552 asm     mov     bx,[linewidth]\r
553 asm     sub     bx,[wide]\r
554 \r
555 asm     mov     ax,[screenseg]\r
556 asm     mov     es,ax\r
557 asm     mov     ds,ax\r
558 \r
559 asm     mov     si,[source]\r
560 asm     mov     di,[dest]\r
561 asm     mov     dx,[height]                             // scan lines to draw\r
562 asm     mov     ax,[wide]\r
563 \r
564 lineloop:\r
565 asm     mov     cx,ax\r
566 asm     rep     movsb\r
567 asm     add     di,bx\r
568 \r
569 asm     dec     dx\r
570 asm     jnz     lineloop\r
571 \r
572 asm     mov     ax,ss\r
573 asm     mov     ds,ax                                   // restore turbo's data segment\r
574 \r
575         EGAWRITEMODE(0);\r
576 }\r
577 \r
578 \r
579 //==========================================================================\r
580 \r
581 /*\r
582 =====================\r
583 =\r
584 = Victory\r
585 =\r
586 =====================\r
587 */\r
588 \r
589 void Victory (void)\r
590 {\r
591         FreeUpMemory ();\r
592         NormalScreen ();\r
593         CA_CacheGrChunk (FINALEPIC);\r
594         VWB_DrawPic (0,0,FINALEPIC);\r
595         UNMARKGRCHUNK(FINALEPIC);\r
596         VW_UpdateScreen ();\r
597         SD_PlaySound (GETBOLTSND);\r
598         SD_WaitSoundDone ();\r
599         SD_PlaySound (GETNUKESND);\r
600         SD_WaitSoundDone ();\r
601         SD_PlaySound (GETPOTIONSND);\r
602         SD_WaitSoundDone ();\r
603         SD_PlaySound (GETKEYSND);\r
604         SD_WaitSoundDone ();\r
605         SD_PlaySound (GETSCROLLSND);\r
606         SD_WaitSoundDone ();\r
607         SD_PlaySound (GETPOINTSSND);\r
608         SD_WaitSoundDone ();\r
609         IN_ClearKeysDown ();\r
610         IN_Ack();\r
611 }\r
612 \r
613 //==========================================================================\r
614 \r
615 /*\r
616 ===================\r
617 =\r
618 = Died\r
619 =\r
620 ===================\r
621 */\r
622 \r
623 void Died (void)\r
624 {\r
625         unsigned page1,page2;\r
626 //\r
627 // fizzle fade screen to grey\r
628 //\r
629         FreeUpMemory ();\r
630         SD_PlaySound (GAMEOVERSND);\r
631         bufferofs = screenloc[(screenpage+1)%3];\r
632         LatchDrawPic(0,0,DEADPIC);\r
633         FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);\r
634         IN_ClearKeysDown();\r
635         IN_Ack();\r
636         VW_SetScreen (bufferofs,0);\r
637 }\r
638 \r
639 //==========================================================================\r
640 \r
641 /*\r
642 ===================\r
643 =\r
644 = NormalScreen\r
645 =\r
646 ===================\r
647 */\r
648 \r
649 void NormalScreen (void)\r
650 {\r
651          VW_SetSplitScreen (200);\r
652          bufferofs = displayofs = SCREEN1START;\r
653          VW_Bar(0,0,320,200,0);\r
654          bufferofs = SCREEN2START;\r
655          VW_Bar(0,0,320,200,0);\r
656          VW_SetScreen (displayofs,0);\r
657 }\r
658 \r
659 //==========================================================================\r
660 \r
661 /*\r
662 ===================\r
663 =\r
664 = DrawPlayScreen\r
665 =\r
666 ===================\r
667 */\r
668 \r
669 void DrawPlayScreen (void)\r
670 {\r
671         int     i,j,p,m;\r
672 \r
673         screenpage = 0;\r
674 \r
675         bufferofs = 0;\r
676         VW_Bar (0,0,320,STATUSLINES,7);\r
677         for (i=0;i<3;i++)\r
678         {\r
679                 bufferofs = screenloc[i];\r
680                 VW_Bar (0,0,320,VIEWHEIGHT,7);\r
681         }\r
682 \r
683 \r
684         VW_SetSplitScreen(144);\r
685         VW_SetScreen(screenloc[0],0);\r
686         bufferofs = 0;\r
687 \r
688         CA_CacheGrChunk (STATUSPIC);\r
689         CA_CacheGrChunk (SIDEBARSPIC);\r
690 \r
691         VW_DrawPic (0,0,STATUSPIC);\r
692 \r
693         for (i=0;i<3;i++)\r
694         {\r
695                 bufferofs = screenloc[i];\r
696                 VW_DrawPic (33,0,SIDEBARSPIC);\r
697         }\r
698 \r
699         grneeded[STATUSPIC]&= ~ca_levelbit;\r
700         grneeded[SIDEBARSPIC]&= ~ca_levelbit;\r
701         MM_SetPurge(&grsegs[STATUSPIC],3);\r
702         MM_SetPurge(&grsegs[SIDEBARSPIC],3);\r
703 \r
704         RedrawStatusWindow ();\r
705         bufferofs = displayofs = screenloc[0];\r
706 }\r
707 \r
708 \r
709 //==========================================================================\r
710 \r
711 /*\r
712 ===================\r
713 =\r
714 = LoadLatchMem\r
715 =\r
716 ===================\r
717 */\r
718 \r
719 void LoadLatchMem (void)\r
720 {\r
721         int     i,j,p,m;\r
722         byte    far *src, far *dest;\r
723         unsigned        destoff;\r
724 \r
725         EGAWRITEMODE(0);\r
726 \r
727 //\r
728 // draw some pics into latch memory\r
729 //\r
730 \r
731 //\r
732 // tile 8s\r
733 //\r
734         latchpics[0] = freelatch;\r
735         src = (byte _seg *)grsegs[STARTTILE8];\r
736         dest = MK_FP(0xa000,freelatch);\r
737 \r
738         for (i=0;i<NUMTILE8;i++)\r
739         {\r
740                 for (p=0;p<4;p++)\r
741                 {\r
742                         m = 1<<p;\r
743                         asm     mov     dx,SC_INDEX\r
744                         asm     mov     al,SC_MAPMASK\r
745                         asm     mov     ah,[BYTE PTR m]\r
746                         asm     out     dx,ax\r
747                         for (j=0;j<8;j++)\r
748                                 *(dest+j)=*src++;\r
749                 }\r
750                 dest+=8;\r
751         }\r
752 \r
753 //\r
754 // tile 16s\r
755 //\r
756         src = (byte _seg *)grsegs[STARTTILE16];\r
757 \r
758         for (i=0;i<NUMTILE16;i++)\r
759         {\r
760                 CA_CacheGrChunk (STARTTILE16+i);\r
761                 src = (byte _seg *)grsegs[STARTTILE16+i];\r
762                 if (src)\r
763                 {\r
764                         tileoffsets[i] = FP_OFF(dest);\r
765                         for (p=0;p<4;p++)\r
766                         {\r
767                                 m = 1<<p;\r
768                                 asm     mov     dx,SC_INDEX\r
769                                 asm     mov     al,SC_MAPMASK\r
770                                 asm     mov     ah,[BYTE PTR m]\r
771                                 asm     out     dx,ax\r
772                                 for (j=0;j<32;j++)\r
773                                         *(dest+j)=*src++;\r
774                         }\r
775                         dest+=32;\r
776                         MM_FreePtr (&grsegs[STARTTILE16+i]);\r
777                         UNMARKGRCHUNK(STARTTILE16+i);\r
778                 }\r
779                 else\r
780                         tileoffsets[i] = 0;\r
781         }\r
782 \r
783 \r
784 //\r
785 // pics\r
786 //\r
787         destoff = FP_OFF(dest);\r
788         for (i=FIRSTLATCHPIC+1;i<FIRSTSCALEPIC;i++)\r
789         {\r
790                 latchpics[i-FIRSTLATCHPIC] = destoff;\r
791                 CA_CacheGrChunk (i);\r
792                 j = pictable[i-STARTPICS].width * pictable[i-STARTPICS].height;\r
793                 VW_MemToScreen (grsegs[i],destoff,j,1);\r
794                 destoff+=j;\r
795                 MM_FreePtr (&grsegs[i]);\r
796                 UNMARKGRCHUNK(i);\r
797         }\r
798 \r
799         EGAMAPMASK(15);\r
800 }\r
801 \r
802 //==========================================================================\r
803 \r
804 /*\r
805 ===================\r
806 =\r
807 = FizzleFade\r
808 =\r
809 ===================\r
810 */\r
811 \r
812 #define PIXPERFRAME     1600\r
813 \r
814 void FizzleFade (unsigned source, unsigned dest,\r
815         unsigned width,unsigned height, boolean abortable)\r
816 {\r
817         unsigned        drawofs,pagedelta;\r
818         unsigned        char maskb[8] = {1,2,4,8,16,32,64,128};\r
819         unsigned        x,y,p,frame;\r
820         long            rndval;\r
821 \r
822         pagedelta = dest-source;\r
823         VW_SetScreen (dest,0);\r
824         rndval = 1;\r
825         y = 0;\r
826 \r
827 asm     mov     es,[screenseg]\r
828 asm     mov     dx,SC_INDEX\r
829 asm     mov     al,SC_MAPMASK\r
830 asm     out     dx,al\r
831 \r
832         TimeCount=frame=0;\r
833         do      // while (1)\r
834         {\r
835                 if (abortable)\r
836                 {\r
837                         IN_ReadControl(0,&c);\r
838                         if (c.button0 || c.button1 || Keyboard[sc_Space]\r
839                         || Keyboard[sc_Enter])\r
840                         {\r
841                                 VW_ScreenToScreen (source,dest,width/8,height);\r
842                                 return;\r
843                         }\r
844                 }\r
845 \r
846                 for (p=0;p<PIXPERFRAME;p++)\r
847                 {\r
848                         //\r
849                         // seperate random value into x/y pair\r
850                         //\r
851                         asm     mov     ax,[WORD PTR rndval]\r
852                         asm     mov     dx,[WORD PTR rndval+2]\r
853                         asm     mov     bx,ax\r
854                         asm     dec     bl\r
855                         asm     mov     [BYTE PTR y],bl                 // low 8 bits - 1 = y xoordinate\r
856                         asm     mov     bx,ax\r
857                         asm     mov     cx,dx\r
858                         asm     shr     cx,1\r
859                         asm     rcr     bx,1\r
860                         asm     shr     bx,1\r
861                         asm     shr     bx,1\r
862                         asm     shr     bx,1\r
863                         asm     shr     bx,1\r
864                         asm     shr     bx,1\r
865                         asm     shr     bx,1\r
866                         asm     shr     bx,1\r
867                         asm     mov     [x],bx                                  // next 9 bits = x xoordinate\r
868                         //\r
869                         // advance to next random element\r
870                         //\r
871                         asm     shr     dx,1\r
872                         asm     rcr     ax,1\r
873                         asm     jnc     noxor\r
874                         asm     xor     dx,0x0001\r
875                         asm     xor     ax,0x2000\r
876 noxor:\r
877                         asm     mov     [WORD PTR rndval],ax\r
878                         asm     mov     [WORD PTR rndval+2],dx\r
879 \r
880                         if (x>width || y>height)\r
881                                 continue;\r
882                         drawofs = source+ylookup[y];\r
883 \r
884                         asm     mov     cx,[x]\r
885                         asm     mov     si,cx\r
886                         asm     and     si,7\r
887                         asm     mov dx,GC_INDEX\r
888                         asm     mov al,GC_BITMASK\r
889                         asm     mov     ah,BYTE PTR [maskb+si]\r
890                         asm     out dx,ax\r
891 \r
892                         asm     mov     si,[drawofs]\r
893                         asm     shr     cx,1\r
894                         asm     shr     cx,1\r
895                         asm     shr     cx,1\r
896                         asm     add     si,cx\r
897                         asm     mov     di,si\r
898                         asm     add     di,[pagedelta]\r
899 \r
900                         asm     mov     dx,GC_INDEX\r
901                         asm     mov     al,GC_READMAP                   // leave GC_INDEX set to READMAP\r
902                         asm     out     dx,al\r
903 \r
904                         asm     mov     dx,SC_INDEX+1\r
905                         asm     mov     al,1\r
906                         asm     out     dx,al\r
907                         asm     mov     dx,GC_INDEX+1\r
908                         asm     mov     al,0\r
909                         asm     out     dx,al\r
910 \r
911                         asm     mov     bl,[es:si]\r
912                         asm     xchg [es:di],bl\r
913 \r
914                         asm     mov     dx,SC_INDEX+1\r
915                         asm     mov     al,2\r
916                         asm     out     dx,al\r
917                         asm     mov     dx,GC_INDEX+1\r
918                         asm     mov     al,1\r
919                         asm     out     dx,al\r
920 \r
921                         asm     mov     bl,[es:si]\r
922                         asm     xchg [es:di],bl\r
923 \r
924                         asm     mov     dx,SC_INDEX+1\r
925                         asm     mov     al,4\r
926                         asm     out     dx,al\r
927                         asm     mov     dx,GC_INDEX+1\r
928                         asm     mov     al,2\r
929                         asm     out     dx,al\r
930 \r
931                         asm     mov     bl,[es:si]\r
932                         asm     xchg [es:di],bl\r
933 \r
934                         asm     mov     dx,SC_INDEX+1\r
935                         asm     mov     al,8\r
936                         asm     out     dx,al\r
937                         asm     mov     dx,GC_INDEX+1\r
938                         asm     mov     al,3\r
939                         asm     out     dx,al\r
940 \r
941                         asm     mov     bl,[es:si]\r
942                         asm     xchg [es:di],bl\r
943 \r
944                         if (rndval == 1)                // entire sequence has been completed\r
945                         {\r
946                                 EGABITMASK(255);\r
947                                 EGAMAPMASK(15);\r
948                                 return;\r
949                         };\r
950                 }\r
951                 frame++;\r
952                 while (TimeCount<frame)         // don't go too fast\r
953                 ;\r
954         } while (1);\r
955 \r
956 \r
957 }\r
958 \r
959 //==========================================================================\r
960 \r
961 /*\r
962 ===================\r
963 =\r
964 = FizzleOut\r
965 =\r
966 ===================\r
967 */\r
968 \r
969 void FizzleOut (int showlevel)\r
970 {\r
971         unsigned page1,page2;\r
972 //\r
973 // fizzle fade screen to grey\r
974 //\r
975         bufferofs = screenloc[(screenpage+1)%3];\r
976         if (showlevel)\r
977                 DrawEnterScreen ();\r
978         FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);\r
979 }\r
980 \r
981 //==========================================================================\r
982 \r
983 /*\r
984 ====================\r
985 =\r
986 = FreeUpMemory\r
987 =\r
988 ====================\r
989 */\r
990 \r
991 void FreeUpMemory (void)\r
992 {\r
993         int     i;\r
994 \r
995         for (i=0;i<NUMSCALEPICS;i++)\r
996                 if (shapedirectory[i])\r
997                         MM_SetPurge (&(memptr)shapedirectory[i],3);\r
998 \r
999         for (i=0;i<NUMSCALEWALLS;i++)\r
1000                 if (walldirectory[i])\r
1001                         MM_SetPurge (&(memptr)walldirectory[i],3);\r
1002 }\r
1003 \r
1004 //==========================================================================\r
1005 \r
1006 /*\r
1007 ==================\r
1008 =\r
1009 = DrawHighScores\r
1010 =\r
1011 ==================\r
1012 */\r
1013 \r
1014 void    DrawHighScores(void)\r
1015 {\r
1016         char            buffer[16],*str;\r
1017         word            i,j,\r
1018                                 w,h,\r
1019                                 x,y;\r
1020         HighScore       *s;\r
1021 \r
1022 \r
1023         CA_CacheGrChunk (HIGHSCORESPIC);\r
1024         VWB_DrawPic (0,0,HIGHSCORESPIC);\r
1025         MM_SetPurge (&grsegs[HIGHSCORESPIC],3);\r
1026         UNMARKGRCHUNK(HIGHSCORESPIC);\r
1027 \r
1028         for (i = 0,s = Scores;i < MaxScores;i++,s++)\r
1029         {\r
1030                 PrintY = 68 + (16 * i);\r
1031 \r
1032                 //\r
1033                 // name\r
1034                 //\r
1035                 PrintX = 60;\r
1036                 US_Print(s->name);\r
1037 \r
1038                 //\r
1039                 // level\r
1040                 //\r
1041                 ultoa(s->completed,buffer,10);\r
1042                 for (str = buffer;*str;str++)\r
1043                         *str = *str + (129 - '0');      // Used fixed-width numbers (129...)\r
1044                 USL_MeasureString(buffer,&w,&h);\r
1045                 PrintX = (25 * 8) - 8 - w;\r
1046                 US_Print(buffer);\r
1047 \r
1048                 //\r
1049                 // score\r
1050                 //\r
1051                 ultoa(s->score,buffer,10);\r
1052                 for (str = buffer;*str;str++)\r
1053                         *str = *str + (129 - '0');      // Used fixed-width numbers (129...)\r
1054                 USL_MeasureString(buffer,&w,&h);\r
1055                 PrintX = (34 * 8) - 8 - w;\r
1056                 US_Print(buffer);\r
1057         }\r
1058 \r
1059         fontcolor = F_BLACK;\r
1060 }\r
1061 \r
1062 \r
1063 \r
1064 /*\r
1065 =======================\r
1066 =\r
1067 = CheckHighScore\r
1068 =\r
1069 =======================\r
1070 */\r
1071 \r
1072 void    CheckHighScore (long score,word other)\r
1073 {\r
1074         word            i,j;\r
1075         int                     n;\r
1076         HighScore       myscore;\r
1077 \r
1078         strcpy(myscore.name,"");\r
1079         myscore.score = score;\r
1080         myscore.completed = other;\r
1081 \r
1082         for (i = 0,n = -1;i < MaxScores;i++)\r
1083         {\r
1084                 if\r
1085                 (\r
1086                         (myscore.score > Scores[i].score)\r
1087                 ||      (\r
1088                                 (myscore.score == Scores[i].score)\r
1089                         &&      (myscore.completed > Scores[i].completed)\r
1090                         )\r
1091                 )\r
1092                 {\r
1093                         for (j = MaxScores;--j > i;)\r
1094                                 Scores[j] = Scores[j - 1];\r
1095                         Scores[i] = myscore;\r
1096                         n = i;\r
1097                         HighScoresDirty = true;\r
1098                         break;\r
1099                 }\r
1100         }\r
1101 \r
1102         if (n != -1)\r
1103         {\r
1104         //\r
1105         // got a high score\r
1106         //\r
1107                 DrawHighScores ();\r
1108                 PrintY = 68 + (16 * n);\r
1109                 PrintX = 60;\r
1110                 US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100);\r
1111         }\r
1112 }\r
1113 \r
1114 \r
1115 //==========================================================================\r
1116 \r
1117 /*\r
1118 ===================\r
1119 =\r
1120 = GameLoop\r
1121 =\r
1122 ===================\r
1123 */\r
1124 \r
1125 void GameLoop (void)\r
1126 {\r
1127         int i,xl,yl,xh,yh;\r
1128         char num[20];\r
1129 #ifdef PROFILE\r
1130         clock_t start,end;\r
1131 #endif\r
1132 \r
1133         DrawPlayScreen ();\r
1134 \r
1135 restart:\r
1136         if (!loadedgame)\r
1137         {\r
1138                 gamestate.difficulty = restartgame;\r
1139                 restartgame = gd_Continue;\r
1140                 DrawEnterScreen ();\r
1141         }\r
1142 \r
1143         do\r
1144         {\r
1145                 playstate = gd_Continue;\r
1146                 if (!loadedgame)\r
1147                         SetupGameLevel ();\r
1148                 else\r
1149                         loadedgame = false;\r
1150 \r
1151                 CacheScaleds ();\r
1152 \r
1153 #ifdef PROFILE\r
1154 start = clock();\r
1155 while (start == clock());\r
1156 start++;\r
1157 #endif\r
1158                 PlayLoop ();\r
1159 #ifdef PROFILE\r
1160 end = clock();\r
1161 itoa(end-start,str,10);\r
1162                 Quit (str);\r
1163 #endif\r
1164 \r
1165 \r
1166                 switch (playstate)\r
1167                 {\r
1168                 case ex_died:\r
1169                         Died ();\r
1170                         NormalScreen ();\r
1171                         FreeUpMemory ();\r
1172                         CheckHighScore (gamestate.score,gamestate.mapon+1);\r
1173                         return;\r
1174                 case ex_warped:\r
1175                         FizzleOut (true);\r
1176                         if (gamestate.mapon >= NUMLEVELS)\r
1177                         {\r
1178                                 Victory ();\r
1179                                 FreeUpMemory ();\r
1180                                 CheckHighScore(gamestate.score,gamestate.mapon+1);\r
1181                                 return;\r
1182                         }\r
1183                         break;\r
1184                 case ex_abort:\r
1185                         FreeUpMemory ();\r
1186                         return;\r
1187                 case ex_resetgame:\r
1188                 case ex_loadedgame:\r
1189                         goto restart;\r
1190                 case ex_victorious:\r
1191                         Victory ();\r
1192                         FreeUpMemory();\r
1193                         CheckHighScore(gamestate.score,gamestate.mapon+1);\r
1194                         return;\r
1195                 }\r
1196 \r
1197         } while (1);\r
1198 \r
1199 }\r