]> 4ch.mooo.com Git - 16.git/blobdiff - 16/keen456/KEEN4-6/CK_TEXT.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / CK_TEXT.C
diff --git a/16/keen456/KEEN4-6/CK_TEXT.C b/16/keen456/KEEN4-6/CK_TEXT.C
new file mode 100755 (executable)
index 0000000..d4fdf65
--- /dev/null
@@ -0,0 +1,971 @@
+/* Reconstructed Commander Keen 4-6 Source Code\r
+ * Copyright (C) 2021 K1n9_Duk3\r
+ *\r
+ * This file is primarily based on:\r
+ * Wolfenstein 3-D Source Code\r
+ * Copyright (C) 1992 id 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
+#include "CK_DEF.H"\r
+\r
+/*\r
+=============================================================================\r
+\r
+TEXT FORMATTING COMMANDS\r
+------------------------\r
+^C<hex digit>                          Change text color\r
+^E[enter]                              End of layout (all pages)\r
+^G<y>,<x>,<pic>[enter] Draw a graphic and push margins\r
+^P[enter]                              start new page, must be the first chars in a layout\r
+^L<x>,<y>[ENTER]               Locate to a specific spot, x in pixels, y in lines\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#if GRMODE == CGAGR\r
+#ifdef KEEN5\r
+#define BACKCOLOR 2    // CGA magenta\r
+#else\r
+#define BACKCOLOR WHITE\r
+#endif\r
+#else\r
+#define BACKCOLOR RED\r
+#endif\r
+\r
+#define WORDLIMIT 80\r
+#define FONTHEIGHT 10\r
+#define TOPMARGIN 10\r
+#define BOTTOMMARGIN 10\r
+#define LEFTMARGIN 10\r
+#define RIGHTMARGIN 10\r
+#define PICMARGIN 8\r
+#define SPACEWIDTH 7\r
+#define TEXTROWS ((200-TOPMARGIN-BOTTOMMARGIN)/FONTHEIGHT)\r
+#define SCREENPIXWIDTH 320\r
+#define SCREENMID (SCREENPIXWIDTH/2)\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+Sint16 pagenum,numpages;\r
+Uint16 leftmargin[TEXTROWS],rightmargin[TEXTROWS];\r
+char far *text;\r
+Uint16 rowon;\r
+Sint16 picx,picy,picnum,picdelay;\r
+boolean layoutdone;\r
+\r
+Sint16 helpmenupos;\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= RipToEOL\r
+=\r
+=====================\r
+*/\r
+\r
+void RipToEOL(void)\r
+{\r
+       while (*text++ != '\n');\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= ParseNumber\r
+=\r
+=====================\r
+*/\r
+\r
+Sint16 ParseNumber(void)\r
+{\r
+       char c, buffer[80];\r
+       char *bufptr;\r
+\r
+//\r
+// scan until a number is found\r
+//\r
+       c = *text;\r
+       while (c < '0' || c > '9')\r
+               c = *++text;\r
+\r
+//\r
+// copy the number out\r
+//\r
+       bufptr = buffer;\r
+       do\r
+       {\r
+               *bufptr = c;\r
+               bufptr++;\r
+               text++;\r
+               c = *text;\r
+       } while (c >= '0' && c <= '9');\r
+       *bufptr = 0;\r
+\r
+       return atoi(buffer);\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= ParsePicCommand\r
+=\r
+= Call with text pointing just after a ^P\r
+= Upon exit text points to the start of next line\r
+=\r
+=====================\r
+*/\r
+\r
+void ParsePicCommand(void)\r
+{\r
+       picy = ParseNumber();\r
+       picx = ParseNumber();\r
+       picnum = ParseNumber();\r
+       RipToEOL();\r
+}\r
+\r
+void ParseTimedCommand(void)\r
+{\r
+       picy = ParseNumber();\r
+       picx = ParseNumber();\r
+       picnum = ParseNumber();\r
+       picdelay = ParseNumber();\r
+       RipToEOL();\r
+}\r
+\r
+/*\r
+=====================\r
+=\r
+= TimedPicCommand\r
+=\r
+= Call with text pointing just after a ^P\r
+= Upon exit text points to the start of next line\r
+=\r
+=====================\r
+*/\r
+\r
+void TimedPicCommand(void)\r
+{\r
+       ParseTimedCommand();\r
+\r
+//\r
+// update the screen, and wait for time delay\r
+//\r
+#if GRMODE == CGAGR\r
+       VW_UpdateScreen();\r
+#else\r
+       VW_WaitVBL(1);\r
+       VW_ScreenToScreen(bufferofs, displayofs, 40, 200);\r
+#endif\r
+\r
+//\r
+// wait for time\r
+//\r
+       TimeCount = 0;\r
+       while (picdelay > TimeCount)\r
+       ;\r
+\r
+//\r
+// draw pic\r
+//\r
+       VWB_DrawPic(picx & ~7, picy, picnum);\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= HandleCommand\r
+=\r
+=====================\r
+*/\r
+\r
+void HandleCommand(void)\r
+{\r
+       Sint16 i,margin,top,bottom;\r
+       Sint16 picwidth,picheight,picmid;\r
+\r
+       switch (toupper(*(++text)))\r
+       {\r
+       case 'B':\r
+               picy = ParseNumber();\r
+               picx = ParseNumber();\r
+               picwidth = ParseNumber();\r
+               picheight = ParseNumber();\r
+               VWB_Bar(picx, picy, picwidth, picheight, BACKCOLOR);\r
+               RipToEOL();\r
+               break;\r
+\r
+       case 'P':               // ^P is start of next page, ^E is end of file\r
+       case 'E':\r
+               layoutdone = true;\r
+               text--;\r
+               break;\r
+\r
+       case 'C':               // ^c<hex digit> changes text color\r
+               i = toupper(*(++text));\r
+               if (i >= '0' && i <= '9')\r
+               {\r
+                       fontcolor = i + 0 - '0';\r
+               }\r
+               else if (i >= 'A' && i <= 'F')\r
+               {\r
+                       fontcolor = i + 10 - 'A';\r
+               }\r
+#if GRMODE == CGAGR\r
+               {\r
+                       static Sint16 colormap[16] = {2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0};\r
+                       // Note: This mapping is a bit problematic for Keen 5 CGA,\r
+                       // since some colors get mapped to CGA magenta, which is\r
+                       // used as the background color in that version. Luckily\r
+                       // those colors aren't used in the Keen 5 texts anyway.\r
+\r
+                       fontcolor = colormap[fontcolor];\r
+               }\r
+#endif\r
+               fontcolor ^= BACKCOLOR;\r
+               text++;\r
+               break;\r
+\r
+       case 'L':\r
+               py = ParseNumber();\r
+               rowon = (py - 10)/10;\r
+               py = rowon * 10 + 10;\r
+               px = ParseNumber();\r
+               while (*(text++) != '\n')       // scan to end of line\r
+               ;\r
+               break;\r
+\r
+       case 'T':               // ^Tyyy,xxx,ppp,ttt waits ttt tics, then draws pic\r
+               TimedPicCommand();\r
+               break;\r
+\r
+       case 'G':               // ^Gyyy,xxx,ppp draws graphic\r
+               ParsePicCommand();\r
+               VWB_DrawPic(picx & ~7, picy, picnum);\r
+               picwidth = pictable[picnum-STARTPICS].width * BYTEPIXELS;\r
+               picheight = pictable[picnum-STARTPICS].height;\r
+               picmid = picx + picwidth/2;\r
+               //\r
+               // adjust margins\r
+               //\r
+               if (picmid > SCREENMID)\r
+               {\r
+                       margin = picx-PICMARGIN;                        // new right margin\r
+               }\r
+               else\r
+               {\r
+                       margin = picx+picwidth+PICMARGIN;       // new left margin\r
+               }\r
+               top = (picy-TOPMARGIN)/FONTHEIGHT;\r
+               if (top < 0)\r
+               {\r
+                       top = 0;\r
+               }\r
+               bottom = (picy+picheight-TOPMARGIN)/FONTHEIGHT;\r
+               if (bottom >= TEXTROWS)\r
+               {\r
+                       bottom = TEXTROWS-1;\r
+               }\r
+\r
+               for (i=top; i<=bottom; i++)\r
+               {\r
+                       if (picmid > SCREENMID)\r
+                       {\r
+                               rightmargin[i] = margin;\r
+                       }\r
+                       else\r
+                       {\r
+                               leftmargin[i] = margin;\r
+                       }\r
+               }\r
+\r
+               //\r
+               // adjust this line if needed\r
+               //\r
+               if (leftmargin[rowon] > px)\r
+               {\r
+                       px = leftmargin[rowon];\r
+               }\r
+               break;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= NewLine\r
+=\r
+=====================\r
+*/\r
+\r
+void NewLine(void)\r
+{\r
+       char c;\r
+\r
+       if (++rowon == TEXTROWS)\r
+       {\r
+       //\r
+       // overflowed the page, so skip until next page break\r
+       //\r
+               layoutdone = true;\r
+               do\r
+               {\r
+                       if (*text == '^')\r
+                       {\r
+                               c = toupper(text[1]);\r
+                               if (c == 'E' || c == 'P')\r
+                               {\r
+                                       layoutdone = true;\r
+                                       return;\r
+                               }\r
+                       }\r
+                       text++;\r
+               } while (1);\r
+       }\r
+       px = leftmargin[rowon];\r
+       py += FONTHEIGHT;\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= HandleCtrls\r
+=\r
+=====================\r
+*/\r
+\r
+void HandleCtrls(void)\r
+{\r
+       char c;\r
+\r
+       c = *(text++);                  // get the character and advance\r
+\r
+       if (c == '\n')\r
+       {\r
+               NewLine();\r
+               return;\r
+       }\r
+}\r
+\r
+/*\r
+=====================\r
+=\r
+= HandleWord\r
+=\r
+=====================\r
+*/\r
+\r
+void HandleWord(void)\r
+{\r
+       Uint16 wwidth, wheight, newpos, wordindex;\r
+       char word[WORDLIMIT];\r
+\r
+       //\r
+       // copy the next word into [word]\r
+       //\r
+       word[0] = *(text++);\r
+       wordindex = 1;\r
+       while (*text > ' ')\r
+       {\r
+               word[wordindex] = *(text++);\r
+               if (++wordindex == WORDLIMIT)\r
+               {\r
+                       Quit("PageLayout: Word limit exceeded");\r
+               }\r
+       }\r
+       word[wordindex] = 0;            // stick a null at end for C\r
+\r
+       //\r
+       // see if it fits on this line\r
+       //\r
+       VW_MeasurePropString(word, &wwidth, &wheight);\r
+       \r
+       while (rightmargin[rowon] < px+wwidth)\r
+       {\r
+               NewLine();\r
+               if (layoutdone)\r
+               {\r
+                       return;         // overflowed page\r
+               }\r
+       }\r
+\r
+       //\r
+       // print it\r
+       //\r
+       newpos = px+wwidth;\r
+       VWB_DrawPropString(word);\r
+       px = newpos;\r
+\r
+       //\r
+       // suck up any extra spaces\r
+       //\r
+       while (*text == ' ')\r
+       {\r
+               px += SPACEWIDTH;\r
+               text++;\r
+       }\r
+}\r
+\r
+/*\r
+=====================\r
+=\r
+= PageLayout\r
+=\r
+= Clears the screen, draws the pics on the page, and word wraps the text.\r
+= Returns a pointer to the terminating command\r
+=\r
+=====================\r
+*/\r
+\r
+void PageLayout(boolean shownumber)\r
+{\r
+       Sint16 oldcolor, i;\r
+       char c;\r
+\r
+       oldcolor = fontcolor;\r
+\r
+#if GRMODE == CGAGR\r
+       fontcolor = BLACK^BACKCOLOR;\r
+#else\r
+       fontcolor = YELLOW^BACKCOLOR;\r
+#endif\r
+\r
+//\r
+// clear the screen\r
+//\r
+       VWB_Bar(0, 0, 320, 200, BACKCOLOR);\r
+#ifndef KEEN6\r
+       VWB_DrawPic(  0, 0, H_TOPWINDOWPIC);\r
+       VWB_DrawPic(  0, 8, H_LEFTWINDOWPIC);\r
+       VWB_DrawPic(312, 8, H_RIGHTWINDOWPIC);\r
+       if (shownumber)\r
+       {\r
+               VWB_DrawPic(8, 176, H_BOTTOMINFOPIC);\r
+       }\r
+       else\r
+       {\r
+               VWB_DrawPic(8, 192, H_BOTTOMWINDOWPIC);\r
+       }\r
+#endif\r
+\r
+       for (i=0; i<TEXTROWS; i++)\r
+       {\r
+               leftmargin[i] = LEFTMARGIN;\r
+               rightmargin[i] = SCREENPIXWIDTH-RIGHTMARGIN;\r
+       }\r
+\r
+       px = LEFTMARGIN;\r
+       py = TOPMARGIN;\r
+       rowon = 0;\r
+       layoutdone = false;\r
+\r
+//\r
+// make sure we are starting layout text (^P first command)\r
+//\r
+       while (*text <= ' ')\r
+       {\r
+               text++;\r
+       }\r
+       if (*text != '^' || toupper(*(++text)) != 'P')\r
+       {\r
+               Quit("PageLayout: Text not headed with ^P");\r
+       }\r
+       while (*(text++) != '\n')\r
+       ;\r
+\r
+//\r
+// process text stream\r
+//\r
+       do\r
+       {\r
+               c = *text;\r
+               if (c == '^')\r
+               {\r
+                       HandleCommand();\r
+               }\r
+               else if (c <= ' ')\r
+               {\r
+                       HandleCtrls();\r
+               }\r
+               else\r
+               {\r
+                       HandleWord();\r
+               }\r
+       } while (!layoutdone);\r
+\r
+       pagenum++;\r
+\r
+       if (shownumber)\r
+       {\r
+               strcpy(str, "pg ");\r
+               itoa(pagenum, str2, 10);\r
+               strcat(str, str2);\r
+               strcat(str, " of ");\r
+               itoa(numpages, str2, 10);\r
+               strcat(str, str2);\r
+#if GRMODE == CGAGR\r
+               fontcolor = BLACK^BACKCOLOR;\r
+#else\r
+               fontcolor = LIGHTRED^BACKCOLOR;\r
+#endif\r
+               py = 186;\r
+               px = 218;\r
+               VWB_DrawPropString(str);\r
+       }\r
+\r
+       fontcolor = oldcolor;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= BackPage\r
+=\r
+= Scans for a previous ^P\r
+=\r
+=====================\r
+*/\r
+\r
+void BackPage(void)\r
+{\r
+       pagenum--;\r
+       do\r
+       {\r
+               text--;\r
+               if (text[0] == '^' && toupper(text[1]) == 'P')\r
+               {\r
+                       return;\r
+               }\r
+       } while (1);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= CacheLayoutGraphics\r
+=\r
+= Scans an entire layout file (until a ^E) marking all graphics used, and\r
+= counting pages, then caches the graphics in\r
+=\r
+=====================\r
+*/\r
+void CacheLayoutGraphics(void)\r
+{\r
+       char    far *bombpoint, far *textstart;\r
+       char    ch;\r
+\r
+       textstart = text;\r
+       bombpoint = text+30000;\r
+       numpages = pagenum = 0;\r
+\r
+#ifndef KEEN6\r
+       CA_MarkGrChunk(H_TOPWINDOWPIC);\r
+       CA_MarkGrChunk(H_LEFTWINDOWPIC);\r
+       CA_MarkGrChunk(H_RIGHTWINDOWPIC);\r
+       CA_MarkGrChunk(H_BOTTOMINFOPIC);\r
+       CA_MarkGrChunk(H_BOTTOMWINDOWPIC);\r
+#endif\r
+\r
+       do\r
+       {\r
+               if (*text == '^')\r
+               {\r
+                       ch = toupper(*(++text));\r
+                       if (ch == 'P')          // start of a page\r
+                       {\r
+                               numpages++;\r
+                       }\r
+                       if (ch == 'E')          // end of file, so load graphics and return\r
+                       {\r
+                               CA_CacheMarks(NULL);\r
+                               text = textstart;\r
+                               return;\r
+                       }\r
+                       if (ch == 'G')          // draw graphic command, so mark graphics\r
+                       {\r
+                               ParsePicCommand();\r
+                               CA_MarkGrChunk(picnum);\r
+                       }\r
+                       if (ch == 'T')          // timed draw graphic command, so mark graphics\r
+                       {\r
+                               ParseTimedCommand();\r
+                               CA_MarkGrChunk(picnum);\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       text++;\r
+               }\r
+\r
+       } while (text < bombpoint);\r
+\r
+       Quit("CacheLayoutGraphics: No ^E to terminate file!");\r
+}\r
+\r
+//===========================================================================\r
+\r
+#ifndef KEEN6\r
+/*\r
+=================\r
+=\r
+= HelpMenu\r
+=\r
+=================\r
+*/\r
+Sint16 HelpMenu(void)\r
+{\r
+       CursorInfo cursor;\r
+       ControlInfo control;\r
+       Sint16 ydelta;\r
+       Uint16 key;\r
+\r
+       VWB_Bar(0, 0, 320, 200, BACKCOLOR);\r
+\r
+       CA_CacheGrChunk(H_HELPPIC);\r
+       CA_CacheGrChunk(H_HANDPIC);\r
+       CA_CacheGrChunk(H_TOPWINDOWPIC);\r
+       CA_CacheGrChunk(H_LEFTWINDOWPIC);\r
+       CA_CacheGrChunk(H_RIGHTWINDOWPIC);\r
+       CA_CacheGrChunk(H_BOTTOMWINDOWPIC);\r
+\r
+       VWB_DrawPic(  0,   0, H_TOPWINDOWPIC);\r
+       VWB_DrawPic(  0,   8, H_LEFTWINDOWPIC);\r
+       VWB_DrawPic(312,   8, H_RIGHTWINDOWPIC);\r
+       VWB_DrawPic(  8, 192, H_BOTTOMWINDOWPIC);\r
+       VWB_DrawPic( 96,   8, H_HELPPIC);\r
+\r
+       ydelta = 0;\r
+       IN_ClearKeysDown();\r
+       do\r
+       {\r
+               if (helpmenupos < 0)\r
+               {\r
+                       helpmenupos = 0;\r
+               }\r
+#ifdef GOODTIMES\r
+               else if (helpmenupos > 3)\r
+               {\r
+                       helpmenupos = 3;\r
+               }\r
+#else\r
+               else if (helpmenupos > 4)\r
+               {\r
+                       helpmenupos = 4;\r
+               }\r
+#endif\r
+               VWB_DrawPic(48, 24*helpmenupos+48, H_HANDPIC);\r
+               VW_UpdateScreen();\r
+               VWB_Bar(48, 24*helpmenupos+48, 39, 24, BACKCOLOR);\r
+               IN_ReadControl(0, &control);\r
+               IN_ReadCursor(&cursor);\r
+               if (LastScan)\r
+               {\r
+                       key = LastScan;\r
+                       IN_ClearKeysDown();\r
+                       switch (key)\r
+                       {\r
+                       case sc_UpArrow:\r
+                               helpmenupos--;\r
+                               break;\r
+                       case sc_DownArrow:\r
+                               helpmenupos++;\r
+                               break;\r
+                       case sc_Enter:\r
+                               VW_ClearVideo(BACKCOLOR);\r
+                               return helpmenupos;\r
+                       case sc_Escape:\r
+                               VW_ClearVideo(BACKCOLOR);\r
+                               return -1;\r
+                       }\r
+               }\r
+               ydelta += cursor.y;\r
+               if (cursor.button0 || cursor.button1 || control.button0 || control.button1)\r
+               {\r
+                       VW_ClearVideo(BACKCOLOR);\r
+                       return helpmenupos;\r
+               }\r
+               if (ydelta < -40)\r
+               {\r
+                       ydelta += 40;\r
+                       helpmenupos--;\r
+               }\r
+               else if (ydelta > 40)\r
+               {\r
+                       ydelta -= 40;\r
+                       helpmenupos++;\r
+               }\r
+       } while (1);\r
+}\r
+\r
+/*\r
+=================\r
+=\r
+= HelpScreens\r
+=\r
+=================\r
+*/\r
+void HelpScreens(void)\r
+{\r
+       static Uint16 layouttable[5] =\r
+       {\r
+               T_HELPART,\r
+               T_CONTRART,\r
+               T_STORYART,\r
+#ifndef GOODTIMES\r
+               T_ORDERART,\r
+#endif\r
+               T_IDART\r
+       };\r
+\r
+       Uint16 olddisplayofs, oldbufferofs, oldfontnumber, temp;\r
+       Sint16 pos;\r
+       boolean newpage;\r
+\r
+       oldfontnumber = fontnumber;\r
+       olddisplayofs = displayofs;\r
+       oldbufferofs = bufferofs;\r
+       fontnumber = 0;\r
+\r
+#if GRMODE == EGAGR\r
+       EGAMAPMASK(15);\r
+#endif\r
+\r
+       CA_UpLevel();\r
+       CA_SetGrPurge();\r
+       VW_ClearVideo(BACKCOLOR);\r
+\r
+#if GRMODE == EGAGR\r
+       RF_FixOfs();\r
+       bufferofs = 0;\r
+       displayofs = 0x8000;\r
+       VW_SetScreen(displayofs, 0);\r
+#endif\r
+\r
+#ifdef KEEN5\r
+       StartMusic(19);\r
+#endif\r
+\r
+       do\r
+       {\r
+               pos = HelpMenu();\r
+\r
+               VW_ClearVideo(BACKCOLOR);\r
+\r
+               if (pos == -1)\r
+               {\r
+                       CA_DownLevel();\r
+                       IN_ClearKeysDown();\r
+                       bufferofs = oldbufferofs;\r
+                       displayofs = olddisplayofs;\r
+                       fontnumber = oldfontnumber;\r
+                       VW_ClearVideo(BACKCOLOR);\r
+                       RF_FixOfs();\r
+#ifdef KEEN5\r
+                       StopMusic();    // Note: it's safer to call StopMusic BEFORE CA_DownLevel\r
+#endif\r
+                       return;\r
+               }\r
+\r
+               pos = layouttable[pos];\r
+               CA_CacheGrChunk(pos);\r
+               text = grsegs[pos];\r
+               CacheLayoutGraphics();\r
+\r
+               newpage = true;\r
+               do\r
+               {\r
+                       if (newpage)\r
+                       {\r
+                               newpage = false;\r
+                               PageLayout(true);\r
+#if GRMODE == CGAGR\r
+                               VW_UpdateScreen();\r
+#else\r
+                               VW_SetScreen(bufferofs, 0);\r
+                               temp = displayofs;\r
+                               displayofs = bufferofs;\r
+                               bufferofs = temp;\r
+#endif\r
+                       }\r
+\r
+                       LastScan = 0;\r
+                       while (!LastScan);\r
+\r
+                       switch (LastScan)\r
+                       {\r
+                       case sc_UpArrow:\r
+                       case sc_LeftArrow:\r
+                       case sc_PgUp:\r
+                               if (pagenum > 1)\r
+                               {\r
+                                       BackPage();\r
+                                       BackPage();\r
+                                       newpage = true;\r
+                               }\r
+                               break;\r
+                       case sc_DownArrow:\r
+                       case sc_RightArrow:\r
+                       case sc_PgDn:\r
+                               if (pagenum < numpages)\r
+                               {\r
+                                       newpage = true;\r
+                               }\r
+                               break;\r
+                       }\r
+               } while (LastScan != sc_Escape);\r
+\r
+               MM_FreePtr(&grsegs[pos]);\r
+               IN_ClearKeysDown();\r
+       } while (true);\r
+}\r
+\r
+#endif\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=================\r
+=\r
+= FinaleLayout\r
+=\r
+=================\r
+*/\r
+void FinaleLayout(void)\r
+{\r
+       char _seg *textseg;\r
+       Sint16 i;\r
+\r
+       VW_ClearVideo(BACKCOLOR);\r
+       RF_FixOfs();\r
+       CA_UpLevel();\r
+       CA_SetGrPurge();\r
+       CA_CacheGrChunk(H_FLASHARROW2PIC);\r
+       CA_CacheGrChunk(H_FLASHARROW1PIC);\r
+\r
+#ifdef KEEN5\r
+       if (gamestate.leveldone[13] == ex_fusebroke)\r
+       {\r
+               CA_CacheGrChunk(T_ENDART2);\r
+               textseg = grsegs[T_ENDART2];\r
+       }\r
+       else\r
+       {\r
+               CA_CacheGrChunk(T_ENDART);\r
+               textseg = grsegs[T_ENDART];\r
+       }\r
+#else\r
+       CA_CacheGrChunk(T_ENDART);\r
+       textseg = grsegs[T_ENDART];\r
+#endif\r
+\r
+       text = textseg;\r
+       CacheLayoutGraphics();\r
+\r
+       StartMusic(ENDINGMUSIC);\r
+\r
+       while (pagenum < numpages)\r
+       {\r
+               PageLayout(false);\r
+               IN_ClearKeysDown();\r
+#if GRMODE == CGAGR\r
+               VW_UpdateScreen();\r
+#else\r
+               VW_SetScreen(bufferofs, 0);\r
+#endif\r
+\r
+               do\r
+               {\r
+                       VWB_DrawPic(298, 184, H_FLASHARROW1PIC);\r
+#if GRMODE == CGAGR\r
+                       VW_UpdateScreen();\r
+#endif\r
+                       for (i=0; i<TickBase; i++)\r
+                       {\r
+                               if (IN_IsUserInput())\r
+                               {\r
+                                       goto nextpage;\r
+                               }\r
+                               VW_WaitVBL(1);\r
+                       }\r
+\r
+                       VWB_DrawPic(298, 184, H_FLASHARROW2PIC);\r
+#if GRMODE == CGAGR\r
+                       VW_UpdateScreen();\r
+#endif\r
+                       for (i=0; i<TickBase; i++)\r
+                       {\r
+                               if (IN_IsUserInput())\r
+                               {\r
+                                       goto nextpage;\r
+                               }\r
+                               VW_WaitVBL(1);\r
+                       }\r
+               } while (1);\r
+\r
+nextpage:\r
+               ;       // Borland C++ 2.0 needs a semicolon here...\r
+       }\r
+\r
+       StopMusic();\r
+\r
+#ifdef KEEN5\r
+       if (gamestate.leveldone[13] == ex_fusebroke)\r
+       {\r
+               MM_FreePtr(&grsegs[T_ENDART2]);\r
+       }\r
+       else\r
+       {\r
+               MM_FreePtr(&grsegs[H_FLASHARROW1PIC]);  // BUG! this should free T_ENDART, the arrow should be freed after the else branch!\r
+       }\r
+#else\r
+       MM_FreePtr(&grsegs[T_ENDART]);\r
+       MM_FreePtr(&grsegs[H_FLASHARROW1PIC]);\r
+#endif\r
+       MM_FreePtr(&grsegs[H_FLASHARROW2PIC]);\r
+       CA_DownLevel();\r
+       IN_ClearKeysDown();\r
+#if GRMODE != CGAGR\r
+       VW_ClearVideo(BACKCOLOR);\r
+       RF_FixOfs();\r
+#endif\r
+       CA_FreeGraphics();\r
+}
\ No newline at end of file