]> 4ch.mooo.com Git - 16.git/blobdiff - 16/keen456/KEEN4-6/CK_GAME.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / CK_GAME.C
diff --git a/16/keen456/KEEN4-6/CK_GAME.C b/16/keen456/KEEN4-6/CK_GAME.C
new file mode 100755 (executable)
index 0000000..157bd3f
--- /dev/null
@@ -0,0 +1,1009 @@
+/* Reconstructed Commander Keen 4-6 Source Code\r
+ * Copyright (C) 2021 K1n9_Duk3\r
+ *\r
+ * This file is loosely based on:\r
+ * Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\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
+#include "CK_DEF.H"\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+Uint16 fadecount;\r
+Sint16 levelcompleted;\r
+Sint32 chunkcount, chunkmax, handpic;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+void FadeAndUnhook(void);\r
+\r
+//===========================================================================\r
+\r
+/*\r
+============================\r
+=\r
+= FreeGraphics\r
+=\r
+============================\r
+*/\r
+\r
+void FreeGraphics(void)\r
+{\r
+       Sint16 i;\r
+       for (i=STARTSPRITES; i<STARTSPRITES+NUMSPRITES; i++)\r
+       {\r
+               if (grsegs[i])\r
+               {\r
+                       MM_SetPurge(&grsegs[i], PURGE_LAST);\r
+               }\r
+       }\r
+       for (i=STARTTILE16; i<STARTEXTERNS; i++)\r
+       {\r
+               if (grsegs[i])\r
+               {\r
+                       MM_SetPurge(&grsegs[i], PURGE_LAST);\r
+               }\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= NewGame\r
+=\r
+= Set up new game to start from the beginning\r
+=\r
+=====================\r
+*/\r
+\r
+void NewGame(void)\r
+{\r
+       memset(&gamestate, 0, sizeof(gamestate));\r
+       gamestate.nextextra = 20000;\r
+       gamestate.lives = 3;\r
+       gamestate.ammo = 5;\r
+}\r
+\r
+//===========================================================================\r
+\r
+#ifndef KEEN5\r
+/*\r
+============================\r
+=\r
+= GameOver\r
+=\r
+============================\r
+*/\r
+\r
+void GameOver(void)\r
+{\r
+       VW_FixRefreshBuffer();\r
+       US_CenterWindow(16, 3);\r
+       US_PrintCentered("Game Over!");\r
+       VW_UpdateScreen();\r
+       IN_ClearKeysDown();\r
+       IN_UserInput(4*TickBase, false);\r
+}\r
+#endif\r
+\r
+//===========================================================================\r
+\r
+/*\r
+============================\r
+=\r
+= SaveTheGame\r
+=\r
+============================\r
+*/\r
+\r
+#define RLETAG 0xABCD\r
+\r
+boolean SaveTheGame(Sint16 handle)\r
+{\r
+       Uint16  i,compressed,expanded;\r
+       objtype *ob;\r
+       memptr  bigbuffer;\r
+\r
+       gamestate.riding = NULL;\r
+\r
+       if (!CA_FarWrite(handle, (byte far *)&gamestate, sizeof(gamestate)))\r
+               return false;\r
+\r
+       expanded = mapwidth * mapheight * 2;\r
+       MM_GetPtr(&bigbuffer, expanded);\r
+\r
+       for (i = 0; i < 3; i++)\r
+       {\r
+               compressed = CA_RLEWCompress(mapsegs[i], expanded, (Uint16 huge *)bigbuffer+1, RLETAG);\r
+               *(Uint16 huge *)bigbuffer = compressed;\r
+               if (!CA_FarWrite(handle, bigbuffer, compressed+2))\r
+               {\r
+                       MM_FreePtr(&bigbuffer);\r
+                       return false;\r
+               }\r
+       }\r
+       for (ob = player; ob; ob=ob->next)\r
+       {\r
+               if (!CA_FarWrite(handle, (byte far *)ob, sizeof(objtype)))\r
+               {\r
+                       MM_FreePtr(&bigbuffer);\r
+                       return false;\r
+               }\r
+       }\r
+       MM_FreePtr(&bigbuffer);\r
+       return true;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+============================\r
+=\r
+= LoadTheGame\r
+=\r
+============================\r
+*/\r
+\r
+boolean LoadTheGame(Sint16 handle)\r
+{\r
+       Uint16  i;\r
+       objtype *prev,*next,*followed;\r
+       Uint16  compressed,expanded;\r
+       memptr  bigbuffer;\r
+#ifdef KEEN5\r
+       Sint16  numfuses;\r
+#endif\r
+\r
+       if (!CA_FarRead(handle, (byte far *)&gamestate, sizeof(gamestate)))\r
+               return false;\r
+\r
+#ifdef KEEN5\r
+       //\r
+       // remember the fuses value for later - SetupGameLevel calls\r
+       // ScanInfoPlane, which resets this part of the gamestate\r
+       //\r
+       numfuses = gamestate.numfuses;\r
+#endif\r
+\r
+       ca_levelbit >>= 1;\r
+       ca_levelnum--;\r
+       SetupGameLevel(false);\r
+       if (mmerror)\r
+       {\r
+               mmerror = false;\r
+               US_CenterWindow(20, 8);\r
+               PrintY += 20;\r
+               US_CPrint("Not enough memory\nto load game!");\r
+               VW_UpdateScreen();\r
+               IN_Ack();\r
+               return false;\r
+       }\r
+       ca_levelbit <<= 1;\r
+       ca_levelnum++;\r
+\r
+       expanded = mapwidth * mapheight * 2;\r
+       MM_BombOnError(true);   //BUG: this should use false to avoid an instant crash\r
+       MM_GetPtr(&bigbuffer, expanded);\r
+       MM_BombOnError(false);  //BUG: this should use true to force an instant crash\r
+       if (mmerror)\r
+       {\r
+               mmerror = false;\r
+               US_CenterWindow(20, 8);\r
+               PrintY += 20;\r
+               US_CPrint("Not enough memory\nto load game!");\r
+               VW_UpdateScreen();\r
+               IN_Ack();\r
+               return false;\r
+       }\r
+       for (i = 0; i < 3; i++)\r
+       {\r
+               if (!CA_FarRead(handle, (byte far *)&compressed, sizeof(compressed)))\r
+               {\r
+                       MM_FreePtr(&bigbuffer);\r
+                       return false;\r
+               }\r
+               if (!CA_FarRead(handle, (byte far *)bigbuffer, compressed))\r
+               {\r
+                       MM_FreePtr(&bigbuffer);\r
+                       return false;\r
+               }\r
+               CA_RLEWexpand(bigbuffer, mapsegs[i], expanded, RLETAG);\r
+       }\r
+       MM_FreePtr(&bigbuffer);\r
+\r
+       InitObjArray();\r
+       new = player;\r
+       prev = new->prev;\r
+       next = new->next;\r
+       if (!CA_FarRead(handle, (byte far *)new, sizeof(objtype)))\r
+       {\r
+               return false;\r
+       }\r
+       new->prev = prev;\r
+       new->next = next;\r
+       new->needtoreact = true;\r
+       new->sprite = NULL;\r
+       new = scoreobj;\r
+       while (true)\r
+       {\r
+               prev = new->prev;\r
+               next = new->next;\r
+               if (!CA_FarRead(handle, (byte far *)new, sizeof(objtype)))\r
+               {\r
+                       return false;\r
+               }\r
+               followed = new->next;\r
+               new->prev = prev;\r
+               new->next = next;\r
+               new->needtoreact = true;\r
+               new->sprite = NULL;\r
+               if (new->obclass == stunnedobj)\r
+               {\r
+                       new->temp3 = 0; //clear sprite ptr for the stars\r
+               }\r
+#if defined KEEN4\r
+               else if (new->obclass == platformobj)\r
+               {\r
+                       new->temp2 = new->temp3 = 0;    //clear sprite ptrs\r
+               }\r
+#elif defined KEEN5\r
+               else if (new->obclass == mineobj)\r
+               {\r
+                       new->temp4 = 0; //clear sprite ptr\r
+               }\r
+               else if (new->obclass == spherefulobj)\r
+               {\r
+                       new->temp1 = new->temp2 = new->temp3 = new->temp4 = 0;  //clear sprite ptrs\r
+               }\r
+#elif defined KEEN6\r
+               else if (new->obclass == platformobj)\r
+               {\r
+                       new->temp3 = 0; //clear sprite ptr\r
+               }\r
+#endif\r
+               if (followed)\r
+               {\r
+                       GetNewObj(false);\r
+               }\r
+               else\r
+               {\r
+                       break;\r
+               }\r
+       }\r
+       scoreobj->temp2 = -1;\r
+       scoreobj->temp1 = -1;\r
+       scoreobj->temp3 = -1;\r
+       scoreobj->temp4 = -1;\r
+#ifdef KEEN5\r
+       gamestate.numfuses = numfuses;  // put value from saved game back in place \r
+#endif\r
+       return true;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+============================\r
+=\r
+= ResetGame\r
+=\r
+============================\r
+*/\r
+\r
+void ResetGame(void)\r
+{\r
+       NewGame();\r
+       ca_levelnum--;\r
+       ca_levelbit >>= 1;\r
+       CA_ClearMarks();\r
+       ca_levelbit <<= 1;\r
+       ca_levelnum++;\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= PatchWorldMap\r
+=\r
+= Takes out blocking squares and spawns flags\r
+=\r
+==========================\r
+*/\r
+\r
+void PatchWorldMap(void)\r
+{\r
+       Uint16 x, y, planeoff, info, level, tag;\r
+       Uint16 far *infoptr;\r
+\r
+       planeoff = 0;\r
+       infoptr = mapsegs[2];\r
+       for (y = 0; y < mapheight; y++)\r
+       {\r
+               for (x = 0; x < mapwidth; x++, infoptr++, planeoff++)\r
+               {\r
+                       info = *infoptr;\r
+                       level = info & 0xFF;\r
+                       if (level >= MINDONELEVEL && level <= MAXDONELEVEL && gamestate.leveldone[level])\r
+                       {\r
+                               tag = info >> 8;\r
+                               *infoptr = 0;   // BUG: infoplane value should only be set to 0 if tag == 0xC0\r
+                               if (tag == 0xD0)\r
+                               {\r
+                                       mapsegs[1][planeoff] = 0;\r
+                               }\r
+                               else if (tag == 0xF0)\r
+                               {\r
+#ifdef KEEN5\r
+                                       SpawnFlag(x, y);\r
+#else\r
+                                       if (levelcompleted == level)\r
+                                       {\r
+                                               SpawnThrowFlag(x, y);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               SpawnFlag(x, y);\r
+                                       }\r
+#endif\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= DelayedFade\r
+=\r
+= Fades out and latches FadeAndUnhook onto the refresh\r
+=\r
+==========================\r
+*/\r
+\r
+void DelayedFade(void)\r
+{\r
+       VW_FadeOut();\r
+       fadecount = 0;\r
+       RF_SetRefreshHook(&FadeAndUnhook);\r
+}\r
+\r
+/*\r
+==========================\r
+=\r
+= FadeAndUnhook\r
+=\r
+= Latch this onto the refresh so the screen only gets faded in after two\r
+= refreshes.  This lets all actors draw themselves to both pages before\r
+= fading the screen in.\r
+=\r
+==========================\r
+*/\r
+\r
+void FadeAndUnhook(void)\r
+{\r
+       if (++fadecount == 2)\r
+       {\r
+               VW_FadeIn();\r
+               RF_SetRefreshHook(NULL);\r
+               TimeCount = lasttimecount;      // don't adaptively time the fade\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= SetupGameLevel\r
+=\r
+= Load in map mapon and cache everything needed for it\r
+=\r
+==========================\r
+*/\r
+\r
+void SetupGameLevel(boolean loadnow)\r
+{\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
+       {\r
+               US_InitRndT(true);\r
+       }\r
+\r
+//\r
+// load the level header and three map planes\r
+//\r
+       CA_CacheMap(gamestate.mapon);\r
+\r
+//\r
+// let the refresh manager set up some variables\r
+//\r
+       RF_NewMap();\r
+\r
+//\r
+// decide which graphics are needed and spawn actors\r
+//\r
+       CA_ClearMarks();\r
+       ScanInfoPlane();\r
+       if (mapon == 0)\r
+       {\r
+               PatchWorldMap();\r
+       }\r
+       RF_MarkTileGraphics();\r
+\r
+//\r
+// have the caching manager load and purge stuff to make sure all marks\r
+// are in memory\r
+//\r
+       MM_BombOnError(false);\r
+       CA_LoadAllSounds();\r
+       if (loadnow)\r
+       {\r
+               if (scorescreenkludge)\r
+               {\r
+                       CA_CacheMarks(NULL);\r
+               }\r
+               else if (DemoMode)\r
+               {\r
+                       CA_CacheMarks("DEMO");\r
+               }\r
+#ifdef KEEN5\r
+               else if (mapon == 0 && player->tiletop > 100)\r
+               {\r
+                       CA_CacheMarks("Keen steps out\nonto Korath III");\r
+               }\r
+#endif\r
+               else\r
+               {\r
+                       _fstrcpy(str, levelenter[mapon]);\r
+                       CA_CacheMarks(str);\r
+               }\r
+       }\r
+       MM_BombOnError(true);\r
+\r
+       if (!mmerror && loadnow)\r
+       {\r
+               DelayedFade();\r
+       }\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= DialogDraw\r
+=\r
+==========================\r
+*/\r
+\r
+void DialogDraw(char *title, Uint16 numcache)\r
+{\r
+       Sint16 i;\r
+       Uint16 width, height;\r
+       Sint32 totalfree;\r
+\r
+       totalfree = MM_TotalFree();\r
+       if (totalfree < 2048)\r
+       {\r
+               handpic = 5;\r
+       }\r
+       else\r
+       {\r
+               handpic = 0;\r
+               for (i = 0; i < 6; i++)\r
+               {\r
+                       CA_CacheGrChunk(i+KEENCOUNT1PIC);\r
+                       CA_UnmarkGrChunk(i+KEENCOUNT1PIC);\r
+                       if (grsegs[i+KEENCOUNT1PIC])\r
+                       {\r
+                               MM_SetPurge(&grsegs[i+KEENCOUNT1PIC], PURGE_FIRST);\r
+                       }\r
+                       else\r
+                       {\r
+                               mmerror = false;\r
+                               handpic = 5;\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       US_CenterWindow(26, 8);\r
+       if (grsegs[KEENCOUNT1PIC])\r
+       {\r
+               VWB_DrawPic(WindowX, WindowY, KEENCOUNT1PIC);\r
+       }\r
+       else\r
+       {\r
+               handpic = 5;\r
+       }\r
+       CA_UnmarkGrChunk(KEENCOUNT1PIC);        //redundant\r
+       WindowW -= 48;\r
+       WindowX += 48;\r
+       SizeText(title, &width, &height);\r
+       PrintY += (WindowH-height)/2 - 4;\r
+       US_CPrint(title);\r
+       VW_UpdateScreen();\r
+       chunkmax = chunkcount = numcache / 6;\r
+       if (!chunkmax && !handpic)\r
+       {\r
+               handpic = 5;\r
+               if (grsegs[KEENCOUNT6PIC])\r
+                       VWB_DrawPic(WindowX-24, WindowY+40, KEENCOUNT6PIC);\r
+               VW_UpdateScreen();\r
+       }\r
+}\r
+\r
+/*\r
+==========================\r
+=\r
+= DialogUpdate\r
+=\r
+==========================\r
+*/\r
+\r
+void DialogUpdate(void)\r
+{\r
+       if (--chunkcount || handpic > 4)\r
+               return;\r
+\r
+       chunkcount = chunkmax;\r
+       if (grsegs[handpic+KEENCOUNT2PIC])\r
+       {\r
+               VWB_DrawPic(WindowX-24, WindowY+40, handpic+KEENCOUNT2PIC);\r
+       }\r
+       VW_UpdateScreen();\r
+       handpic++;\r
+}\r
+\r
+/*\r
+==========================\r
+=\r
+= DialogFinish\r
+=\r
+==========================\r
+*/\r
+\r
+void DialogFinish(void)\r
+{\r
+       //this is empty\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= StartDemoRecord\r
+=\r
+==================\r
+*/\r
+\r
+void StartDemoRecord(void)\r
+{\r
+       Sint16 level;\r
+       boolean esc;\r
+\r
+       VW_FixRefreshBuffer();\r
+       US_CenterWindow(30, 3);\r
+       PrintY += 6;\r
+       US_Print("  Record a demo from level(0-21):");\r
+       VW_UpdateScreen();\r
+       esc = !US_LineInput(px, py, str, NULL, true, 2, 0);\r
+       if (!esc)\r
+       {\r
+               level = atoi(str);\r
+               if (level >= 0 && level <= 21)\r
+               {\r
+                       gamestate.mapon = level;\r
+                       playstate = ex_warped;\r
+                       IN_StartDemoRecord(0x1000);\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+==================\r
+=\r
+= EndDemoRecord\r
+=\r
+==================\r
+*/\r
+\r
+void EndDemoRecord(void)\r
+{\r
+       Sint16 handle;\r
+       boolean esc;\r
+       char filename[] = "DEMO?."EXTENSION;\r
+\r
+       IN_StopDemo();\r
+       VW_FixRefreshBuffer();\r
+       US_CenterWindow(22, 3);\r
+       PrintY += 6;\r
+       US_Print("  Save as demo #(0-9):");\r
+       VW_UpdateScreen();\r
+       esc = !US_LineInput(px, py, str, NULL, true, 2, 0);\r
+       if (!esc && str[0] >= '0' && str[0] <= '9')\r
+       {\r
+               filename[4] = str[0];\r
+               handle = open(filename, O_BINARY|O_WRONLY|O_CREAT, S_IFREG|S_IREAD|S_IWRITE);\r
+               if (handle == -1)\r
+               {\r
+                       Quit("EndDemoRecord:  Cannot write demo file!");\r
+               }\r
+               write(handle, &mapon, sizeof(mapon));\r
+               write(handle, &DemoOffset, sizeof(DemoOffset));\r
+               CA_FarWrite(handle, DemoBuffer, DemoOffset);\r
+               close(handle);\r
+       }\r
+       IN_FreeDemoBuffer();\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= HandleDeath\r
+=\r
+==========================\r
+*/\r
+\r
+void HandleDeath(void)\r
+{\r
+       Uint16 y, color, top, bottom, selection, w, h;\r
+\r
+       _fstrcpy(str, levelnames[mapon]);\r
+       SizeText(str, &w, &h);\r
+\r
+       memset(gamestate.keys, 0, sizeof(gamestate.keys));\r
+       gamestate.lives--;\r
+       if (gamestate.lives >= 0)\r
+       {\r
+               VW_FixRefreshBuffer();\r
+               US_CenterWindow(20, 8);\r
+               PrintY += 3;\r
+               US_CPrint("You didn't make it past");\r
+               top = PrintY+22;\r
+               if (h < 15)\r
+                       PrintY += 4;\r
+               US_CPrint(str);\r
+               PrintY = top+2;\r
+               US_CPrint("Try Again");\r
+               PrintY += 4;\r
+               bottom = PrintY-2;\r
+               US_CPrint("Exit to "WORLDMAPNAME);\r
+\r
+               IN_ClearKeysDown();\r
+               selection = 0;\r
+               while (true)\r
+               {\r
+                       if (selection)\r
+                       {\r
+                               y = bottom;\r
+                       }\r
+                       else\r
+                       {\r
+                               y = top;\r
+                       }\r
+\r
+// draw select bar\r
+                       if ((TimeCount / 16) & 1)\r
+                       {\r
+                               color = SECONDCOLOR;\r
+                       }\r
+                       else\r
+                       {\r
+                               color = FIRSTCOLOR;\r
+                       }\r
+                       VWB_Hlin(WindowX+4, WindowX+WindowW-4, y, color);\r
+                       VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+1, color);\r
+                       VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+12, color);\r
+                       VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+13, color);\r
+                       VWB_Vlin(y+1, y+11, WindowX+4, color);\r
+                       VWB_Vlin(y+1, y+11, WindowX+5, color);\r
+                       VWB_Vlin(y+1, y+11, WindowX+WindowW-4, color);\r
+                       VWB_Vlin(y+1, y+11, WindowX+WindowW-5, color);\r
+\r
+                       VW_UpdateScreen();\r
+\r
+// erase select bar\r
+                       VWB_Hlin(WindowX+4, WindowX+WindowW-4, y, WHITE);\r
+                       VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+1, WHITE);\r
+                       VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+12, WHITE);\r
+                       VWB_Hlin(WindowX+4, WindowX+WindowW-4, y+13, WHITE);\r
+                       VWB_Vlin(y+1, y+11, WindowX+4, WHITE);\r
+                       VWB_Vlin(y+1, y+11, WindowX+5, WHITE);\r
+                       VWB_Vlin(y+1, y+11, WindowX+WindowW-4, WHITE);\r
+                       VWB_Vlin(y+1, y+11, WindowX+WindowW-5, WHITE);\r
+\r
+                       if (LastScan == sc_Escape)\r
+                       {\r
+                               gamestate.mapon = 0;            // exit to world map\r
+                               IN_ClearKeysDown();\r
+                               return;\r
+                       }\r
+\r
+                       IN_ReadControl(0, &c);\r
+                       if (c.button0 || c.button1 || LastScan == sc_Return || LastScan == sc_Space)\r
+                       {\r
+                               if (selection)\r
+                                       gamestate.mapon = 0;            // exit to world map\r
+                               return;\r
+                       }\r
+                       if (c.yaxis == -1 || LastScan == sc_UpArrow)\r
+                       {\r
+                               selection = 0;\r
+                       }\r
+                       else if (c.yaxis == 1 || LastScan == sc_DownArrow)\r
+                       {\r
+                               selection = 1;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+============================\r
+=\r
+= GameLoop\r
+=\r
+= A game has just started (after the cinematic or load game)\r
+=\r
+============================\r
+*/\r
+\r
+void GameLoop(void)\r
+{\r
+       Uint16 temp;\r
+#ifdef KEEN6\r
+       Uint16 i;\r
+#endif\r
+\r
+#ifdef KEEN6\r
+       if (!storedemo)\r
+       {\r
+               if (!US_ManualCheck())\r
+               {\r
+                       loadedgame = false;\r
+                       restartgame = gd_Continue;\r
+                       return;\r
+               }\r
+       }\r
+#endif\r
+\r
+       if (playstate == ex_loadedgame)\r
+       {\r
+               goto loaded;\r
+       }\r
+reset:\r
+       gamestate.difficulty = restartgame;\r
+       restartgame = gd_Continue;\r
+       do\r
+       {\r
+startlevel:\r
+               SetupGameLevel(true);\r
+               if (mmerror)\r
+               {\r
+                       if (gamestate.mapon != 0)\r
+                       {\r
+                               mmerror = false;\r
+                               US_CenterWindow(20, 8);\r
+                               PrintY += 20;\r
+                               US_CPrint("Insufficient memory\nto load level!");\r
+                               VW_UpdateScreen();\r
+                               IN_Ack();\r
+                               gamestate.mapon = 0;            // exit to world map\r
+                               SetupGameLevel(true);\r
+                       }\r
+                       if (mmerror)\r
+                       {\r
+                               Quit("GameLoop: Insufficient memory to load world map!");\r
+                       }\r
+               }\r
+loaded:\r
+               keenkilled = false;\r
+               SD_WaitSoundDone();\r
+\r
+               PlayLoop();\r
+\r
+               if (playstate != ex_loadedgame)\r
+               {\r
+                       memset(gamestate.keys, 0, sizeof(gamestate.keys));\r
+#ifdef KEEN5\r
+                       gamestate.keycard = false;\r
+#endif\r
+               }\r
+               VW_FixRefreshBuffer();\r
+\r
+               if (tedlevel)\r
+               {\r
+                       if (playstate == ex_loadedgame)\r
+                       {\r
+                               goto loaded;\r
+                       }\r
+                       else if (playstate == ex_died)\r
+                       {\r
+                               goto startlevel;\r
+                       }\r
+                       else\r
+                       {\r
+                               TEDDeath();\r
+                       }\r
+               }\r
+\r
+               levelcompleted = -1;\r
+               switch (playstate)\r
+               {\r
+               case ex_resetgame:\r
+                       goto reset;\r
+\r
+               case ex_loadedgame:\r
+                       goto loaded;\r
+\r
+               case ex_died:\r
+                       HandleDeath();\r
+                       break;\r
+\r
+#if defined KEEN4\r
+               case ex_rescued:\r
+                       if (mapon != 0)\r
+                       {\r
+                               SD_PlaySound(SND_LEVELDONE);\r
+                       }\r
+                       levelcompleted = mapon;\r
+                       gamestate.leveldone[mapon] = true;\r
+                       RescuedMember();\r
+                       if (gamestate.rescued != 8)\r
+                       {\r
+                               gamestate.mapon = 0;\r
+                       }\r
+                       else\r
+                       {\r
+                               FreeGraphics();\r
+                               RF_FixOfs();\r
+                               VW_FixRefreshBuffer();\r
+                               FinaleLayout();\r
+                               CheckHighScore(gamestate.score, gamestate.rescued);\r
+                               return;\r
+                       }\r
+                       break;\r
+\r
+#elif defined KEEN5\r
+               case ex_fusebroke:\r
+                       SD_PlaySound(SND_LEVELDONE);\r
+                       levelcompleted = mapon;\r
+                       gamestate.leveldone[mapon] = ex_fusebroke;\r
+                       FinishedFuse();\r
+                       gamestate.mapon = 0;\r
+                       break;\r
+\r
+               case ex_qedbroke:\r
+                       FreeGraphics();\r
+                       RF_FixOfs();\r
+                       VW_FixRefreshBuffer();\r
+                       FinaleLayout();\r
+                       CheckHighScore(gamestate.score, 0);\r
+                       return;\r
+\r
+#elif defined KEEN6\r
+               case ex_hook:\r
+                       GotHook();\r
+                       goto completed;\r
+\r
+               case ex_sandwich:\r
+                       GotSandwich();\r
+                       goto completed;\r
+\r
+               case ex_card:\r
+                       GotPasscard();\r
+                       goto completed;\r
+\r
+               case ex_molly:\r
+                       FreeGraphics();\r
+                       RF_FixOfs();\r
+                       VW_FixRefreshBuffer();\r
+                       FinaleLayout();\r
+                       goto check_score;\r
+\r
+#endif\r
+               case ex_completed:\r
+               case ex_foot:\r
+               case ex_portout:\r
+completed:\r
+                       if (mapon != 0)\r
+                       {\r
+                               SD_PlaySound(SND_LEVELDONE);\r
+                               gamestate.mapon = 0;\r
+                               levelcompleted = mapon;\r
+                               gamestate.leveldone[mapon] = true;\r
+                               if (storedemo && mapon == 2)\r
+                               {\r
+                                       IN_ClearKeysDown();\r
+                                       return;\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+#if GRMODE != CGAGR\r
+                               temp = bufferofs;\r
+                               bufferofs = displayofs;\r
+#endif\r
+                               US_CenterWindow(26, 8);\r
+                               PrintY += 25;\r
+                               US_CPrint("One moment");\r
+#if GRMODE == CGAGR\r
+                               VW_UpdateScreen();\r
+#else\r
+                               bufferofs = temp;\r
+#endif\r
+                       }\r
+                       break;\r
+\r
+               case ex_abortgame:\r
+                       IN_ClearKeysDown();\r
+                       return;\r
+               }\r
+       } while (gamestate.lives >= 0);\r
+\r
+       GameOver();\r
+\r
+check_score:\r
+#if defined KEEN4\r
+       CheckHighScore(gamestate.score, gamestate.rescued);\r
+#else\r
+       temp = 0;\r
+#if defined KEEN6\r
+       for (i = 0; i < GAMELEVELS; i++)\r
+       {\r
+               if (gamestate.leveldone[i])\r
+                       temp++;\r
+       }\r
+#endif\r
+       CheckHighScore(gamestate.score, temp);\r
+#endif\r
+}
\ No newline at end of file