]> 4ch.mooo.com Git - 16.git/blobdiff - src/lib/hp/game/c3_game.c
not done making demohp.c. i gotta get the files to the other lappy4
[16.git] / src / lib / hp / game / c3_game.c
diff --git a/src/lib/hp/game/c3_game.c b/src/lib/hp/game/c3_game.c
new file mode 100755 (executable)
index 0000000..a71d254
--- /dev/null
@@ -0,0 +1,1199 @@
+/* Catacomb 3-D Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_GAME.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+#ifdef PROFILE\r
+#include "TIME.H"\r
+#endif\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define NUMLUMPS        25\r
+\r
+#define CONTROLSLUMP    0\r
+#define ORCLUMP         1\r
+#define TROLLLUMP        2\r
+#define WARPLUMP        3\r
+#define BOLTLUMP        4\r
+#define NUKELUMP        5\r
+#define POTIONLUMP      6\r
+#define RKEYLUMP        7\r
+#define YKEYLUMP        8\r
+#define GKEYLUMP        9\r
+#define BKEYLUMP        10\r
+#define SCROLLLUMP      11\r
+#define CHESTLUMP       12\r
+#define PLAYERLUMP      13\r
+#define WALL1LUMP       14\r
+#define WALL2LUMP       15\r
+#define BDOORLUMP       16\r
+#define DEMONLUMP               17\r
+#define MAGELUMP                18\r
+#define BATLUMP                 19\r
+#define GRELLUMP                20\r
+#define GOALLUMP                21\r
+\r
+\r
+int     lumpstart[NUMLUMPS] = {\r
+CONTROLS_LUMP_START,\r
+ORC_LUMP_START,\r
+TROLL_LUMP_START,\r
+WARP_LUMP_START,\r
+BOLT_LUMP_START,\r
+NUKE_LUMP_START,\r
+POTION_LUMP_START,\r
+RKEY_LUMP_START,\r
+YKEY_LUMP_START,\r
+GKEY_LUMP_START,\r
+BKEY_LUMP_START,\r
+SCROLL_LUMP_START,\r
+CHEST_LUMP_START,\r
+PLAYER_LUMP_START,\r
+WALL1_LUMP_START,\r
+WALL2_LUMP_START,\r
+BDOOR_LUMP_START,\r
+DEMON_LUMP_START,\r
+MAGE_LUMP_START,\r
+BAT_LUMP_START,\r
+GREL_LUMP_START,\r
+NEMESISPIC\r
+};\r
+\r
+\r
+int     lumpend[NUMLUMPS] = {\r
+CONTROLS_LUMP_END,\r
+ORC_LUMP_END,\r
+TROLL_LUMP_END,\r
+WARP_LUMP_END,\r
+BOLT_LUMP_END,\r
+NUKE_LUMP_END,\r
+POTION_LUMP_END,\r
+RKEY_LUMP_END,\r
+YKEY_LUMP_END,\r
+GKEY_LUMP_END,\r
+BKEY_LUMP_END,\r
+SCROLL_LUMP_END,\r
+CHEST_LUMP_END,\r
+PLAYER_LUMP_END,\r
+WALL1_LUMP_END,\r
+WALL2_LUMP_END,\r
+BDOOR_LUMP_END,\r
+DEMON_LUMP_END,\r
+MAGE_LUMP_END,\r
+BAT_LUMP_END,\r
+GREL_LUMP_END,\r
+NEMESISPIC\r
+};\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+unsigned        latchpics[NUMLATCHPICS];\r
+unsigned        tileoffsets[NUMTILE16];\r
+unsigned        textstarts[27];\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean lumpneeded[NUMLUMPS];\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= ScanInfoPlane\r
+=\r
+= Spawn all actors and mark down special places\r
+=\r
+==========================\r
+*/\r
+\r
+void ScanInfoPlane (void)\r
+{\r
+       unsigned        x,y,i,j;\r
+       int                     tile;\r
+       unsigned        far     *start;\r
+\r
+       InitObjList();                  // start spawning things with a clean slate\r
+\r
+       memset (lumpneeded,0,sizeof(lumpneeded));\r
+\r
+       start = mapsegs[2];\r
+       for (y=0;y<mapheight;y++)\r
+               for (x=0;x<mapwidth;x++)\r
+               {\r
+                       tile = *start++;\r
+                       if (!tile)\r
+                               continue;\r
+\r
+                       switch (tile)\r
+                       {\r
+                       case 1:\r
+                       case 2:\r
+                       case 3:\r
+                       case 4:\r
+                               lumpneeded[PLAYERLUMP] = true;\r
+                               SpawnPlayer(x,y,NORTH+tile-1);\r
+                               break;\r
+\r
+                       case 5:\r
+                       case 6:\r
+                       case 7:\r
+                       case 8:\r
+                       case 9:\r
+                       case 10:\r
+                       case 11:\r
+                               lumpneeded[tile-5+BOLTLUMP] = true;\r
+                               SpawnBonus(x,y,tile-5);\r
+                               break;\r
+\r
+                       case 12:\r
+                       case 13:\r
+                       case 14:\r
+                       case 15:\r
+                       case 16:\r
+                       case 17:\r
+                       case 18:\r
+                       case 19:\r
+                               lumpneeded[SCROLLLUMP] = true;\r
+                               SpawnBonus(x,y,B_SCROLL1+tile-12);\r
+                               break;\r
+\r
+                       case 20:        // goal\r
+                               lumpneeded[GOALLUMP] = true;\r
+                               SpawnBonus(x,y,B_GOAL);\r
+                               break;\r
+\r
+                       case 21:        // chest\r
+                               lumpneeded[CHESTLUMP] = true;\r
+                               SpawnBonus(x,y,B_CHEST);\r
+                               break;\r
+\r
+                       case 24:\r
+                               lumpneeded[WARPLUMP] = true;\r
+                               SpawnWarp (x,y,0);\r
+                               break;\r
+//------\r
+                       case 41:\r
+                               if (gamestate.difficulty <gd_Hard)\r
+                                       break;\r
+                       case 36:\r
+                               if (gamestate.difficulty <gd_Normal)\r
+                                       break;\r
+                       case 22:\r
+                               lumpneeded[TROLLLUMP] = true;\r
+                               SpawnTroll (x,y);\r
+                               break;\r
+\r
+                       case 42:\r
+                               if (gamestate.difficulty <gd_Hard)\r
+                                       break;\r
+                       case 37:\r
+                               if (gamestate.difficulty <gd_Normal)\r
+                                       break;\r
+                       case 23:\r
+                               lumpneeded[ORCLUMP] = true;\r
+                               SpawnOrc (x,y);\r
+                               break;\r
+\r
+                       case 43:\r
+                               if (gamestate.difficulty <gd_Hard)\r
+                                       break;\r
+                       case 38:\r
+                               if (gamestate.difficulty <gd_Normal)\r
+                                       break;\r
+                       case 25:\r
+                               lumpneeded[BATLUMP] = true;\r
+                               SpawnBat (x,y);\r
+                               break;\r
+\r
+                       case 44:\r
+                               if (gamestate.difficulty <gd_Hard)\r
+                                       break;\r
+                       case 39:\r
+                               if (gamestate.difficulty <gd_Normal)\r
+                                       break;\r
+                       case 26:\r
+                               lumpneeded[DEMONLUMP] = true;\r
+                               SpawnDemon (x,y);\r
+                               break;\r
+\r
+                       case 45:\r
+                               if (gamestate.difficulty <gd_Hard)\r
+                                       break;\r
+                       case 40:\r
+                               if (gamestate.difficulty <gd_Normal)\r
+                                       break;\r
+                       case 27:\r
+                               lumpneeded[MAGELUMP] = true;\r
+                               SpawnMage (x,y);\r
+                               break;\r
+\r
+                       case 28:\r
+                               lumpneeded[GRELLUMP] = true;\r
+                               SpawnNemesis (x,y);\r
+                               break;\r
+\r
+                       case 29:\r
+                               SpawnBounce (x,y,0);\r
+                               break;\r
+\r
+                       case 30:\r
+                               SpawnBounce (x,y,1);\r
+                               break;\r
+\r
+                       case 31:\r
+                       case 32:\r
+                       case 33:\r
+                       case 34:\r
+                               lumpneeded[WARPLUMP] = true;\r
+                               SpawnWarp (x,y,tile-30);\r
+                               break;\r
+                       }\r
+               }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= ScanText\r
+=\r
+==================\r
+*/\r
+\r
+void ScanText (void)\r
+{\r
+       int     i;\r
+       char far *text;\r
+\r
+       text = (char _seg *)grsegs[LEVEL1TEXT+mapon];\r
+\r
+       textstarts[0] = 0;\r
+\r
+       for (i=1;i<=26;i++)\r
+       {\r
+               while (*text != '\n')\r
+               {\r
+                       if (*text == '\r')\r
+                               *text = 0;\r
+                       text++;\r
+               }\r
+               text++;\r
+               textstarts[i] = FP_OFF(text);\r
+       }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= DrawEnterScreen\r
+=\r
+==================\r
+*/\r
+\r
+static  char    *levelnames[] =\r
+                               {\r
+                                       "The Approach",\r
+                                       "Nemesis's Keep",\r
+                                       "Ground Floor",\r
+                                       "Second Floor",\r
+                                       "Third Floor",\r
+                                       "Tower One",\r
+                                       "Tower Two",\r
+                                       "Secret Halls",\r
+                                       "Access Floor",\r
+                                       "The Dungeon",\r
+                                       "Lower Dungeon",\r
+                                       "Catacomb",\r
+                                       "Lower Reaches",\r
+                                       "The Warrens",\r
+                                       "Hidden Caverns",\r
+                                       "The Fens of Insanity",\r
+                                       "Chaos Corridors",\r
+                                       "The Labyrinth",\r
+                                       "Halls of Blood",\r
+                                       "Nemesis's Lair"\r
+                               };\r
+void DrawEnterScreen (void)\r
+{\r
+       int     x,y;\r
+\r
+       VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,9);     // Medium blue\r
+\r
+       x = (VIEWWIDTH - (18 * 8)) / 2 -3;\r
+       y = (VIEWHEIGHT - (5 * 8)) / 2;\r
+       VW_DrawPic(x / 8,y,ENTERPLAQUEPIC);\r
+\r
+       WindowX = x;\r
+       WindowW = 18 * 8;\r
+       PrintY = (VIEWHEIGHT/2) + 3;\r
+       US_CPrint (levelnames[gamestate.mapon]);\r
+}\r
+\r
+//==========================================================================\r
+\r
+boolean tileneeded[NUMFLOORS];\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= CacheScaleds\r
+=\r
+==================\r
+*/\r
+\r
+void CacheScaleds (void)\r
+{\r
+       int     i,j;\r
+       unsigned        source,dest;\r
+\r
+       FreeUpMemory ();\r
+       CA_CacheGrChunk(LEVEL1TEXT+mapon);\r
+       ScanText ();\r
+\r
+//\r
+// make sure we are displaying screenpage 0\r
+//\r
+       if (screenpage)\r
+       {\r
+               source = screenloc[screenpage];\r
+               dest = screenloc[0];\r
+               VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);\r
+               screenpage = 0;\r
+               VW_SetScreen (dest,0);\r
+               displayofs = dest;\r
+       }\r
+\r
+//\r
+// cache wall pictures\r
+//\r
+       for (i=1;i<NUMFLOORS;i++)\r
+               if (tileneeded[i])\r
+               {\r
+                       SetupScaleWall (walllight1[i]);\r
+                       SetupScaleWall (walllight2[i]);\r
+                       SetupScaleWall (walldark1[i]);\r
+                       SetupScaleWall (walldark2[i]);\r
+               }\r
+\r
+//\r
+// cache the actor pictures\r
+//\r
+       for (i=0;i<NUMLUMPS;i++)\r
+               if (lumpneeded[i])\r
+                       for (j=lumpstart[i];j<=lumpend[i];j++)\r
+                               SetupScalePic(j);\r
+\r
+       source = screenloc[0];\r
+       for (i=1;i<=2;i++)\r
+       {\r
+               dest = screenloc[i];\r
+               VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);\r
+       }\r
+\r
+       screenpage = 1;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= SetupGameLevel\r
+=\r
+==================\r
+*/\r
+\r
+void SetupGameLevel (void)\r
+{\r
+       int     x,y,i;\r
+       unsigned        far *map,tile,spot;\r
+\r
+       memset (tileneeded,0,sizeof(tileneeded));\r
+//\r
+// randomize if not a demo\r
+//\r
+       if (DemoMode)\r
+       {\r
+               US_InitRndT(false);\r
+               gamestate.difficulty = gd_Normal;\r
+       }\r
+       else\r
+               US_InitRndT(true);\r
+\r
+//\r
+// load the level\r
+//\r
+       CA_CacheMap (gamestate.mapon);\r
+\r
+       mapwidth = mapheaderseg[mapon]->width;\r
+       mapheight = mapheaderseg[mapon]->height;\r
+\r
+//\r
+// make a lookup table for the maps left edge\r
+//\r
+       spot = 0;\r
+       for (y=0;y<mapheight;y++)\r
+       {\r
+         farmapylookup[y] = spot;\r
+         spot += mapwidth;\r
+       }\r
+\r
+//\r
+// copy the wall data to a data segment array\r
+//\r
+       memset (tilemap,0,sizeof(tilemap));\r
+       memset (actorat,0,sizeof(actorat));\r
+       map = mapsegs[0];\r
+       for (y=0;y<mapheight;y++)\r
+               for (x=0;x<mapwidth;x++)\r
+               {\r
+                       tile = *map++;\r
+                       if (tile<NUMFLOORS)\r
+                       {\r
+                               tileneeded[tile] = true;\r
+                               tilemap[x][y] = tile;\r
+                               if (tile>=EXPWALLSTART && tile<EXPWALLSTART+NUMEXPWALLS)\r
+                               {\r
+                                       tileneeded[WALLEXP] = tileneeded[WALLEXP+1]\r
+                                       = tileneeded[WALLEXP+2] = true;\r
+                               }\r
+\r
+                               if (tile>0)\r
+                                       (unsigned)actorat[x][y] = tile;\r
+                       }\r
+               }\r
+\r
+\r
+//\r
+// decide which graphics are needed and spawn actors\r
+//\r
+       ScanInfoPlane ();\r
+\r
+//\r
+// have the caching manager load and purge stuff to make sure all marks\r
+// are in memory\r
+//\r
+       CA_LoadAllSounds ();\r
+\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= LatchDrawPic\r
+=\r
+=====================\r
+*/\r
+\r
+void LatchDrawPic (unsigned x, unsigned y, unsigned picnum)\r
+{\r
+       unsigned wide, height, source, dest;\r
+\r
+       wide = pictable[picnum-STARTPICS].width;\r
+       height = pictable[picnum-STARTPICS].height;\r
+       dest = bufferofs + ylookup[y]+x;\r
+       source = latchpics[picnum-FIRSTLATCHPIC];\r
+\r
+       EGAWRITEMODE(1);\r
+       EGAMAPMASK(15);\r
+\r
+asm     mov     bx,[linewidth]\r
+asm     sub     bx,[wide]\r
+\r
+asm     mov     ax,[screenseg]\r
+asm     mov     es,ax\r
+asm     mov     ds,ax\r
+\r
+asm     mov     si,[source]\r
+asm     mov     di,[dest]\r
+asm     mov     dx,[height]                             // scan lines to draw\r
+asm     mov     ax,[wide]\r
+\r
+lineloop:\r
+asm     mov     cx,ax\r
+asm     rep     movsb\r
+asm     add     di,bx\r
+\r
+asm     dec     dx\r
+asm     jnz     lineloop\r
+\r
+asm     mov     ax,ss\r
+asm     mov     ds,ax                                   // restore turbo's data segment\r
+\r
+       EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= Victory\r
+=\r
+=====================\r
+*/\r
+\r
+void Victory (void)\r
+{\r
+       FreeUpMemory ();\r
+       NormalScreen ();\r
+       CA_CacheGrChunk (FINALEPIC);\r
+       VWB_DrawPic (0,0,FINALEPIC);\r
+       UNMARKGRCHUNK(FINALEPIC);\r
+       VW_UpdateScreen ();\r
+       SD_PlaySound (GETBOLTSND);\r
+       SD_WaitSoundDone ();\r
+       SD_PlaySound (GETNUKESND);\r
+       SD_WaitSoundDone ();\r
+       SD_PlaySound (GETPOTIONSND);\r
+       SD_WaitSoundDone ();\r
+       SD_PlaySound (GETKEYSND);\r
+       SD_WaitSoundDone ();\r
+       SD_PlaySound (GETSCROLLSND);\r
+       SD_WaitSoundDone ();\r
+       SD_PlaySound (GETPOINTSSND);\r
+       SD_WaitSoundDone ();\r
+       IN_ClearKeysDown ();\r
+       IN_Ack();\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= Died\r
+=\r
+===================\r
+*/\r
+\r
+void Died (void)\r
+{\r
+       unsigned page1,page2;\r
+//\r
+// fizzle fade screen to grey\r
+//\r
+       FreeUpMemory ();\r
+       SD_PlaySound (GAMEOVERSND);\r
+       bufferofs = screenloc[(screenpage+1)%3];\r
+       LatchDrawPic(0,0,DEADPIC);\r
+       FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);\r
+       IN_ClearKeysDown();\r
+       IN_Ack();\r
+       VW_SetScreen (bufferofs,0);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= NormalScreen\r
+=\r
+===================\r
+*/\r
+\r
+void NormalScreen (void)\r
+{\r
+        VW_SetSplitScreen (200);\r
+        bufferofs = displayofs = SCREEN1START;\r
+        VW_Bar(0,0,320,200,0);\r
+        bufferofs = SCREEN2START;\r
+        VW_Bar(0,0,320,200,0);\r
+        VW_SetScreen (displayofs,0);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= DrawPlayScreen\r
+=\r
+===================\r
+*/\r
+\r
+void DrawPlayScreen (void)\r
+{\r
+       int     i,j,p,m;\r
+\r
+       screenpage = 0;\r
+\r
+       bufferofs = 0;\r
+       VW_Bar (0,0,320,STATUSLINES,7);\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               VW_Bar (0,0,320,VIEWHEIGHT,7);\r
+       }\r
+\r
+\r
+       VW_SetSplitScreen(144);\r
+       VW_SetScreen(screenloc[0],0);\r
+       bufferofs = 0;\r
+\r
+       CA_CacheGrChunk (STATUSPIC);\r
+       CA_CacheGrChunk (SIDEBARSPIC);\r
+\r
+       VW_DrawPic (0,0,STATUSPIC);\r
+\r
+       for (i=0;i<3;i++)\r
+       {\r
+               bufferofs = screenloc[i];\r
+               VW_DrawPic (33,0,SIDEBARSPIC);\r
+       }\r
+\r
+       grneeded[STATUSPIC]&= ~ca_levelbit;\r
+       grneeded[SIDEBARSPIC]&= ~ca_levelbit;\r
+       MM_SetPurge(&grsegs[STATUSPIC],3);\r
+       MM_SetPurge(&grsegs[SIDEBARSPIC],3);\r
+\r
+       RedrawStatusWindow ();\r
+       bufferofs = displayofs = screenloc[0];\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= LoadLatchMem\r
+=\r
+===================\r
+*/\r
+\r
+void LoadLatchMem (void)\r
+{\r
+       int     i,j,p,m;\r
+       byte    far *src, far *dest;\r
+       unsigned        destoff;\r
+\r
+       EGAWRITEMODE(0);\r
+\r
+//\r
+// draw some pics into latch memory\r
+//\r
+\r
+//\r
+// tile 8s\r
+//\r
+       latchpics[0] = freelatch;\r
+       src = (byte _seg *)grsegs[STARTTILE8];\r
+       dest = MK_FP(0xa000,freelatch);\r
+\r
+       for (i=0;i<NUMTILE8;i++)\r
+       {\r
+               for (p=0;p<4;p++)\r
+               {\r
+                       m = 1<<p;\r
+                       asm     mov     dx,SC_INDEX\r
+                       asm     mov     al,SC_MAPMASK\r
+                       asm     mov     ah,[BYTE PTR m]\r
+                       asm     out     dx,ax\r
+                       for (j=0;j<8;j++)\r
+                               *(dest+j)=*src++;\r
+               }\r
+               dest+=8;\r
+       }\r
+\r
+//\r
+// tile 16s\r
+//\r
+       src = (byte _seg *)grsegs[STARTTILE16];\r
+\r
+       for (i=0;i<NUMTILE16;i++)\r
+       {\r
+               CA_CacheGrChunk (STARTTILE16+i);\r
+               src = (byte _seg *)grsegs[STARTTILE16+i];\r
+               if (src)\r
+               {\r
+                       tileoffsets[i] = FP_OFF(dest);\r
+                       for (p=0;p<4;p++)\r
+                       {\r
+                               m = 1<<p;\r
+                               asm     mov     dx,SC_INDEX\r
+                               asm     mov     al,SC_MAPMASK\r
+                               asm     mov     ah,[BYTE PTR m]\r
+                               asm     out     dx,ax\r
+                               for (j=0;j<32;j++)\r
+                                       *(dest+j)=*src++;\r
+                       }\r
+                       dest+=32;\r
+                       MM_FreePtr (&grsegs[STARTTILE16+i]);\r
+                       UNMARKGRCHUNK(STARTTILE16+i);\r
+               }\r
+               else\r
+                       tileoffsets[i] = 0;\r
+       }\r
+\r
+\r
+//\r
+// pics\r
+//\r
+       destoff = FP_OFF(dest);\r
+       for (i=FIRSTLATCHPIC+1;i<FIRSTSCALEPIC;i++)\r
+       {\r
+               latchpics[i-FIRSTLATCHPIC] = destoff;\r
+               CA_CacheGrChunk (i);\r
+               j = pictable[i-STARTPICS].width * pictable[i-STARTPICS].height;\r
+               VW_MemToScreen (grsegs[i],destoff,j,1);\r
+               destoff+=j;\r
+               MM_FreePtr (&grsegs[i]);\r
+               UNMARKGRCHUNK(i);\r
+       }\r
+\r
+       EGAMAPMASK(15);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= FizzleFade\r
+=\r
+===================\r
+*/\r
+\r
+#define PIXPERFRAME     1600\r
+\r
+void FizzleFade (unsigned source, unsigned dest,\r
+       unsigned width,unsigned height, boolean abortable)\r
+{\r
+       unsigned        drawofs,pagedelta;\r
+       unsigned        char maskb[8] = {1,2,4,8,16,32,64,128};\r
+       unsigned        x,y,p,frame;\r
+       long            rndval;\r
+\r
+       pagedelta = dest-source;\r
+       VW_SetScreen (dest,0);\r
+       rndval = 1;\r
+       y = 0;\r
+\r
+asm     mov     es,[screenseg]\r
+asm     mov     dx,SC_INDEX\r
+asm     mov     al,SC_MAPMASK\r
+asm     out     dx,al\r
+\r
+       TimeCount=frame=0;\r
+       do      // while (1)\r
+       {\r
+               if (abortable)\r
+               {\r
+                       IN_ReadControl(0,&c);\r
+                       if (c.button0 || c.button1 || Keyboard[sc_Space]\r
+                       || Keyboard[sc_Enter])\r
+                       {\r
+                               VW_ScreenToScreen (source,dest,width/8,height);\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               for (p=0;p<PIXPERFRAME;p++)\r
+               {\r
+                       //\r
+                       // seperate random value into x/y pair\r
+                       //\r
+                       asm     mov     ax,[WORD PTR rndval]\r
+                       asm     mov     dx,[WORD PTR rndval+2]\r
+                       asm     mov     bx,ax\r
+                       asm     dec     bl\r
+                       asm     mov     [BYTE PTR y],bl                 // low 8 bits - 1 = y xoordinate\r
+                       asm     mov     bx,ax\r
+                       asm     mov     cx,dx\r
+                       asm     shr     cx,1\r
+                       asm     rcr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     shr     bx,1\r
+                       asm     mov     [x],bx                                  // next 9 bits = x xoordinate\r
+                       //\r
+                       // advance to next random element\r
+                       //\r
+                       asm     shr     dx,1\r
+                       asm     rcr     ax,1\r
+                       asm     jnc     noxor\r
+                       asm     xor     dx,0x0001\r
+                       asm     xor     ax,0x2000\r
+noxor:\r
+                       asm     mov     [WORD PTR rndval],ax\r
+                       asm     mov     [WORD PTR rndval+2],dx\r
+\r
+                       if (x>width || y>height)\r
+                               continue;\r
+                       drawofs = source+ylookup[y];\r
+\r
+                       asm     mov     cx,[x]\r
+                       asm     mov     si,cx\r
+                       asm     and     si,7\r
+                       asm     mov dx,GC_INDEX\r
+                       asm     mov al,GC_BITMASK\r
+                       asm     mov     ah,BYTE PTR [maskb+si]\r
+                       asm     out dx,ax\r
+\r
+                       asm     mov     si,[drawofs]\r
+                       asm     shr     cx,1\r
+                       asm     shr     cx,1\r
+                       asm     shr     cx,1\r
+                       asm     add     si,cx\r
+                       asm     mov     di,si\r
+                       asm     add     di,[pagedelta]\r
+\r
+                       asm     mov     dx,GC_INDEX\r
+                       asm     mov     al,GC_READMAP                   // leave GC_INDEX set to READMAP\r
+                       asm     out     dx,al\r
+\r
+                       asm     mov     dx,SC_INDEX+1\r
+                       asm     mov     al,1\r
+                       asm     out     dx,al\r
+                       asm     mov     dx,GC_INDEX+1\r
+                       asm     mov     al,0\r
+                       asm     out     dx,al\r
+\r
+                       asm     mov     bl,[es:si]\r
+                       asm     xchg [es:di],bl\r
+\r
+                       asm     mov     dx,SC_INDEX+1\r
+                       asm     mov     al,2\r
+                       asm     out     dx,al\r
+                       asm     mov     dx,GC_INDEX+1\r
+                       asm     mov     al,1\r
+                       asm     out     dx,al\r
+\r
+                       asm     mov     bl,[es:si]\r
+                       asm     xchg [es:di],bl\r
+\r
+                       asm     mov     dx,SC_INDEX+1\r
+                       asm     mov     al,4\r
+                       asm     out     dx,al\r
+                       asm     mov     dx,GC_INDEX+1\r
+                       asm     mov     al,2\r
+                       asm     out     dx,al\r
+\r
+                       asm     mov     bl,[es:si]\r
+                       asm     xchg [es:di],bl\r
+\r
+                       asm     mov     dx,SC_INDEX+1\r
+                       asm     mov     al,8\r
+                       asm     out     dx,al\r
+                       asm     mov     dx,GC_INDEX+1\r
+                       asm     mov     al,3\r
+                       asm     out     dx,al\r
+\r
+                       asm     mov     bl,[es:si]\r
+                       asm     xchg [es:di],bl\r
+\r
+                       if (rndval == 1)                // entire sequence has been completed\r
+                       {\r
+                               EGABITMASK(255);\r
+                               EGAMAPMASK(15);\r
+                               return;\r
+                       };\r
+               }\r
+               frame++;\r
+               while (TimeCount<frame)         // don't go too fast\r
+               ;\r
+       } while (1);\r
+\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= FizzleOut\r
+=\r
+===================\r
+*/\r
+\r
+void FizzleOut (int showlevel)\r
+{\r
+       unsigned page1,page2;\r
+//\r
+// fizzle fade screen to grey\r
+//\r
+       bufferofs = screenloc[(screenpage+1)%3];\r
+       if (showlevel)\r
+               DrawEnterScreen ();\r
+       FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= FreeUpMemory\r
+=\r
+====================\r
+*/\r
+\r
+void FreeUpMemory (void)\r
+{\r
+       int     i;\r
+\r
+       for (i=0;i<NUMSCALEPICS;i++)\r
+               if (shapedirectory[i])\r
+                       MM_SetPurge (&(memptr)shapedirectory[i],3);\r
+\r
+       for (i=0;i<NUMSCALEWALLS;i++)\r
+               if (walldirectory[i])\r
+                       MM_SetPurge (&(memptr)walldirectory[i],3);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= DrawHighScores\r
+=\r
+==================\r
+*/\r
+\r
+void    DrawHighScores(void)\r
+{\r
+       char            buffer[16],*str;\r
+       word            i,j,\r
+                               w,h,\r
+                               x,y;\r
+       HighScore       *s;\r
+\r
+\r
+       CA_CacheGrChunk (HIGHSCORESPIC);\r
+       VWB_DrawPic (0,0,HIGHSCORESPIC);\r
+       MM_SetPurge (&grsegs[HIGHSCORESPIC],3);\r
+       UNMARKGRCHUNK(HIGHSCORESPIC);\r
+\r
+       for (i = 0,s = Scores;i < MaxScores;i++,s++)\r
+       {\r
+               PrintY = 68 + (16 * i);\r
+\r
+               //\r
+               // name\r
+               //\r
+               PrintX = 60;\r
+               US_Print(s->name);\r
+\r
+               //\r
+               // level\r
+               //\r
+               ultoa(s->completed,buffer,10);\r
+               for (str = buffer;*str;str++)\r
+                       *str = *str + (129 - '0');      // Used fixed-width numbers (129...)\r
+               USL_MeasureString(buffer,&w,&h);\r
+               PrintX = (25 * 8) - 8 - w;\r
+               US_Print(buffer);\r
+\r
+               //\r
+               // score\r
+               //\r
+               ultoa(s->score,buffer,10);\r
+               for (str = buffer;*str;str++)\r
+                       *str = *str + (129 - '0');      // Used fixed-width numbers (129...)\r
+               USL_MeasureString(buffer,&w,&h);\r
+               PrintX = (34 * 8) - 8 - w;\r
+               US_Print(buffer);\r
+       }\r
+\r
+       fontcolor = F_BLACK;\r
+}\r
+\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= CheckHighScore\r
+=\r
+=======================\r
+*/\r
+\r
+void    CheckHighScore (long score,word other)\r
+{\r
+       word            i,j;\r
+       int                     n;\r
+       HighScore       myscore;\r
+\r
+       strcpy(myscore.name,"");\r
+       myscore.score = score;\r
+       myscore.completed = other;\r
+\r
+       for (i = 0,n = -1;i < MaxScores;i++)\r
+       {\r
+               if\r
+               (\r
+                       (myscore.score > Scores[i].score)\r
+               ||      (\r
+                               (myscore.score == Scores[i].score)\r
+                       &&      (myscore.completed > Scores[i].completed)\r
+                       )\r
+               )\r
+               {\r
+                       for (j = MaxScores;--j > i;)\r
+                               Scores[j] = Scores[j - 1];\r
+                       Scores[i] = myscore;\r
+                       n = i;\r
+                       HighScoresDirty = true;\r
+                       break;\r
+               }\r
+       }\r
+\r
+       if (n != -1)\r
+       {\r
+       //\r
+       // got a high score\r
+       //\r
+               DrawHighScores ();\r
+               PrintY = 68 + (16 * n);\r
+               PrintX = 60;\r
+               US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100);\r
+       }\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= GameLoop\r
+=\r
+===================\r
+*/\r
+\r
+void GameLoop (void)\r
+{\r
+       int i,xl,yl,xh,yh;\r
+       char num[20];\r
+#ifdef PROFILE\r
+       clock_t start,end;\r
+#endif\r
+\r
+       DrawPlayScreen ();\r
+\r
+restart:\r
+       if (!loadedgame)\r
+       {\r
+               gamestate.difficulty = restartgame;\r
+               restartgame = gd_Continue;\r
+               DrawEnterScreen ();\r
+       }\r
+\r
+       do\r
+       {\r
+               playstate = gd_Continue;\r
+               if (!loadedgame)\r
+                       SetupGameLevel ();\r
+               else\r
+                       loadedgame = false;\r
+\r
+               CacheScaleds ();\r
+\r
+#ifdef PROFILE\r
+start = clock();\r
+while (start == clock());\r
+start++;\r
+#endif\r
+               PlayLoop ();\r
+#ifdef PROFILE\r
+end = clock();\r
+itoa(end-start,str,10);\r
+               Quit (str);\r
+#endif\r
+\r
+\r
+               switch (playstate)\r
+               {\r
+               case ex_died:\r
+                       Died ();\r
+                       NormalScreen ();\r
+                       FreeUpMemory ();\r
+                       CheckHighScore (gamestate.score,gamestate.mapon+1);\r
+                       return;\r
+               case ex_warped:\r
+                       FizzleOut (true);\r
+                       if (gamestate.mapon >= NUMLEVELS)\r
+                       {\r
+                               Victory ();\r
+                               FreeUpMemory ();\r
+                               CheckHighScore(gamestate.score,gamestate.mapon+1);\r
+                               return;\r
+                       }\r
+                       break;\r
+               case ex_abort:\r
+                       FreeUpMemory ();\r
+                       return;\r
+               case ex_resetgame:\r
+               case ex_loadedgame:\r
+                       goto restart;\r
+               case ex_victorious:\r
+                       Victory ();\r
+                       FreeUpMemory();\r
+                       CheckHighScore(gamestate.score,gamestate.mapon+1);\r
+                       return;\r
+               }\r
+\r
+       } while (1);\r
+\r
+}\r