OSDN Git Service

added keen 4-6 rebuild code for reference.... i need to stop doing this... xD
[proj16/16.git] / 16 / keen456 / KEEN4-6 / CK_DEMO.C
diff --git a/16/keen456/KEEN4-6/CK_DEMO.C b/16/keen456/KEEN4-6/CK_DEMO.C
deleted file mode 100755 (executable)
index 5004cf3..0000000
+++ /dev/null
@@ -1,2132 +0,0 @@
-/* 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
-boolean scorescreenkludge;\r
-\r
-/*\r
-=============================================================================\r
-\r
-                                                LOCAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-#if GRMODE == EGAGR\r
-\r
-Uint8 starcolors[17] = STARPALETTE;\r
-Uint16 plaquenum[4] = {IDSOFTPIC, PROGTEAMPIC, ARTISTPIC, DIRECTORPIC};\r
-Uint8 termcolors[17] = INTROPALETTE;\r
-Uint8 termcolors2[17] = SHRINKPALETTE;\r
-\r
-Uint8 ortoend[8] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01};\r
-Uint8 andtoend[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE};\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// uninitialized variables:\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-typedef struct {\r
-       Uint16 height;\r
-       Uint16 width;\r
-       Uint16 rowofs[200];\r
-} shapehead;\r
-\r
-typedef shapehead _seg * shapeseg;\r
-\r
-// text crawl variables:\r
-memptr linecode;\r
-void far *linestarts[200];\r
-Uint16 sourceline[200];\r
-Uint16 masterlines;\r
-void far *routine;\r
-memptr sourcepic;\r
-memptr bittables;\r
-\r
-// terminator intro variables:\r
-shapeseg commander;\r
-shapeseg keen;\r
-shapeseg both;\r
-memptr scaletable;\r
-memptr cmdrshifts[8];\r
-Sint16 commanderbwide;\r
-Uint16 lastsource;\r
-Uint16 keenstart;\r
-memptr basepl[5];\r
-Uint16 baseplwidth[5];\r
-Uint16 baseplheight[5];\r
-memptr plaqueseg;\r
-Uint16 plaquewidth;\r
-Uint16 plaquewidthwords;\r
-Uint16 plaqueheight;\r
-Uint16 plaqueplane;\r
-Uint16 plaquedelta;\r
-Uint16 *shiftptr;\r
-Uint16 planeon;\r
-Sint16 drawheight;\r
-Uint16 source2;\r
-static Uint16 t_dest;\r
-static Sint16 plaque;\r
-static Sint16 plaquephase;\r
-static Sint16 plaquey;\r
-static Sint16 lastframe;\r
-static Sint16 pageon;\r
-static Sint16 prevbottom[2];\r
-Uint16 pageofs;\r
-Uint16 byteadjust;\r
-\r
-#endif // if GRMODE == EGAGR\r
-\r
-//===========================================================================\r
-\r
-/*\r
-============================\r
-=\r
-= CheckLastScan\r
-=\r
-============================\r
-*/\r
-\r
-void CheckLastScan(void)\r
-{\r
-       if (LastScan)\r
-       {\r
-               if (storedemo)\r
-               {\r
-                       playstate = ex_resetgame;\r
-                       restartgame = gd_Normal;\r
-                       IN_ClearKeysDown();\r
-                       NewGame();\r
-               }\r
-#ifndef KEEN6\r
-               else if (LastScan == sc_F1)\r
-               {\r
-                       HelpScreens();\r
-               }\r
-#endif\r
-               else\r
-               {\r
-                       US_ControlPanel();\r
-                       if (restartgame)\r
-                       {\r
-                               playstate = ex_resetgame;\r
-                       }\r
-                       else if (loadedgame)\r
-                       {\r
-                               playstate = ex_loadedgame;\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-#if GRMODE == EGAGR\r
-/*\r
-=============================================================================\r
-\r
-                                                       TERMINATOR INTRO\r
-\r
-=============================================================================\r
-*/\r
-\r
-/*\r
-============================\r
-=\r
-= LoadPlaque\r
-=\r
-============================\r
-*/\r
-\r
-void LoadPlaque(Sint16 index)\r
-{\r
-       Sint16 LocatePlaque(Sint16 elapsed);\r
-\r
-       Uint16 chunk, picnum, width, height, planesize, i;\r
-       Uint8 far *source;\r
-       Uint16 far *dest;\r
-\r
-       //\r
-       // cache the pic and get pic size\r
-       //\r
-       chunk = plaquenum[index];\r
-       CA_CacheGrChunk(chunk);\r
-       picnum = chunk - STARTPICS;\r
-       baseplwidth[index] = width = pictable[picnum].width;\r
-       baseplheight[index] = height = pictable[picnum].height;\r
-       planesize = width * height * 2;\r
-\r
-       //\r
-       // allocate buffer and convert pic into to our format\r
-       // (convert bytes to word indices for faster shift-drawing)\r
-       //\r
-       MM_GetPtr(&basepl[index], planesize*2); // 2 planes\r
-       source = grsegs[chunk];\r
-       dest = basepl[index];\r
-       for (i=0; i<planesize; i++)\r
-       {\r
-               *dest++ = *source++ << 1;\r
-       }\r
-\r
-       //\r
-       // pic in original format is no longer needed\r
-       //\r
-       MM_FreePtr(&grsegs[chunk]);\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= DrawPlaque\r
-=\r
-============================\r
-*/\r
-\r
-void DrawPlaque(Sint16 elapsed, Uint16 x)\r
-{\r
-       Uint16 shift, xb;\r
-       Sint16 y, bottom, oldbottom;\r
-       Uint16 eraseheight, skip, screenoff;\r
-\r
-       shift = x & 7;\r
-       xb = (pageofs + (x / 8)) + (20 - (plaquewidth >> 1));\r
-\r
-       EGAMAPMASK(12); // write to "red" and "intensity" plane (for erasing old pic)\r
-\r
-       //\r
-       // update position (and pic number)\r
-       //\r
-       y = LocatePlaque(elapsed);\r
-\r
-       //\r
-       // erase leftovers of the previous frame\r
-       //\r
-       bottom = y + plaqueheight;\r
-       if (bottom < 0)\r
-               bottom = 0;\r
-       oldbottom = prevbottom[pageon];\r
-       if (bottom < 200 && oldbottom > bottom)\r
-       {\r
-               eraseheight = oldbottom - bottom;\r
-               screenoff = xb + ylookup[bottom];\r
-               asm {\r
-                       mov     es, screenseg;\r
-                       mov     bx, linewidth;\r
-                       sub     bx, plaquewidthwords;\r
-                       sub     bx, plaquewidthwords;\r
-                       mov     di, screenoff;\r
-                       mov     dx, eraseheight;\r
-                       mov     si, plaquewidthwords;\r
-                       xor     ax, ax;\r
-               }\r
-eraseloop:\r
-               asm {\r
-                       mov     cx, si;\r
-                       rep stosw;\r
-                       add     di, bx;\r
-                       dec     dx;\r
-                       jnz     eraseloop;\r
-               }\r
-       }\r
-       if (bottom > 200)\r
-               bottom = 200;\r
-       prevbottom[pageon] = bottom;\r
-\r
-       //\r
-       // draw the (new) pic at the new position\r
-       //\r
-       drawheight = plaqueheight;\r
-       skip = 0;\r
-       if (y < 0)\r
-       {\r
-               skip = -y * (plaquewidth << 1);\r
-               drawheight += y;\r
-               y = 0;\r
-       }\r
-       else if (y + plaqueheight > 200)\r
-       {\r
-               drawheight = 200 - y;\r
-       }\r
-       source2 = skip + plaqueplane;\r
-       if (drawheight > 0)\r
-       {\r
-               shiftptr = shifttabletable[shift];\r
-               t_dest = xb + ylookup[y];\r
-               asm {\r
-                       mov     bx, skip;\r
-                       push    bp;\r
-                       mov     bp, shiftptr;\r
-                       mov     es, screenseg;\r
-                       mov     ds, plaqueseg;\r
-                       mov     ah, 4;\r
-                       mov     BYTE PTR ss:planeon, ah;\r
-               }\r
-planeloop:\r
-               asm {\r
-                       mov     dx, SC_INDEX;\r
-                       mov     al, SC_MAPMASK;\r
-                       out     dx, ax;\r
-                       mov     dx, ss:drawheight;\r
-                       mov     di, ss:t_dest;\r
-               }\r
-yloop:\r
-               asm {\r
-                       mov     cx, ss:plaquewidth;\r
-                       xor     al, al;\r
-               }\r
-xloop:\r
-               asm {\r
-                       mov     si, [bx];\r
-                       add     bx, 2;\r
-                       xor     ah, ah;\r
-                       or      ax, [bp+si];\r
-                       stosb;\r
-                       mov     al, ah;\r
-                       loop    xloop;\r
-                       stosb;\r
-                       mov     WORD PTR es:[di], 0;\r
-                       add     di, ss:plaquedelta;\r
-                       dec     dx;\r
-                       jnz     yloop;\r
-                       mov     bx, ss:source2;\r
-                       mov     ah, BYTE PTR ss:planeon;\r
-                       shl     ah, 1;\r
-                       mov     BYTE PTR ss:planeon, ah;\r
-                       cmp     ah, 16;\r
-                       jnz     planeloop;\r
-                       pop     bp;\r
-                       mov     ax, ss;\r
-                       mov     ds, ax;\r
-               }\r
-       }\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= LocatePlaque\r
-=\r
-============================\r
-*/\r
-\r
-Sint16 LocatePlaque(Sint16 elapsed)\r
-{\r
-       switch (plaquephase)\r
-       {\r
-       case -1:\r
-               //\r
-               // pic starts to appear\r
-               //\r
-               plaqueseg = basepl[plaque];\r
-               plaquewidth = baseplwidth[plaque];\r
-               plaquewidthwords = (plaquewidth + 3) >> 1;\r
-               plaqueheight = baseplheight[plaque];\r
-               plaquedelta = linewidth - (plaquewidth + 1);\r
-               plaqueplane = (plaquewidth * plaqueheight) << 1;\r
-               plaquephase++;\r
-               lastframe = elapsed;\r
-               plaquey = 240;\r
-               // no break or return here!\r
-       case 0:\r
-               //\r
-               // pic is moving from the bottom to the center of the screen\r
-               //\r
-               plaquey -= (elapsed - lastframe) << 1;\r
-               if (plaquey < 100)\r
-               {\r
-                       plaquey = 100;\r
-                       plaquephase++;\r
-               }\r
-               lastframe = elapsed;\r
-               return plaquey - (plaqueheight >> 1);\r
-\r
-       case 1:\r
-               //\r
-               // pic is staying at the center position\r
-               //\r
-               if (elapsed - lastframe > 200)\r
-               {\r
-                       plaquephase++;\r
-                       lastframe = elapsed;\r
-               }\r
-               return 100 - (plaqueheight >> 1);\r
-\r
-       case 2:\r
-               //\r
-               // pic is moving up from the center to the top of the screen\r
-               //\r
-               plaquey -= (elapsed - lastframe) << 1;\r
-               if (plaquey < -40)\r
-               {\r
-                       plaquey = -40;\r
-                       if (++plaque < 4)\r
-                       {\r
-                               plaquephase = -1;\r
-                       }\r
-                       else\r
-                       {\r
-                               plaquephase = 3;\r
-                       }\r
-               }\r
-               lastframe = elapsed;\r
-               return plaquey - (plaqueheight >> 1);\r
-       }\r
-\r
-       return -40;\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= SlideLetters\r
-=\r
-============================\r
-*/\r
-\r
-void SlideLetters(void)\r
-{\r
-       Sint16 x, cPosX, screenxb;\r
-       Uint16 elapsed, totaltics, dstofs;\r
-       Sint16 cStart, cEnd, cTotalMove;\r
-       Uint16 shift, srcseg, srcofs;\r
-       Sint16 clearleft, copywidth, clearright;\r
-       Uint16 srcdif, dstdif;\r
-       Sint32 now;\r
-\r
-       //\r
-       // set up characteristics of the animation\r
-       //\r
-       EGAWRITEMODE(0);\r
-       EGAREADMAP(0);  // useless...\r
-\r
-       keenstart = keen->width + 200;\r
-       EGAREADMAP(1);  // also useless ... I think...\r
-\r
-       cEnd = 120 - commander->width;\r
-       cStart = 320;\r
-       cTotalMove = cEnd - cStart;\r
-       totaltics = abs(cTotalMove);\r
-\r
-       pageofs = pageon = 0;\r
-       lasttimecount = TimeCount;\r
-       while (TimeCount == lasttimecount);\r
-       lasttimecount = TimeCount;\r
-\r
-       for (elapsed=0; elapsed <= totaltics; elapsed += tics)\r
-       {\r
-               //\r
-               // draw the credits pic\r
-               //\r
-               x = ((Sint32)keenstart * (Sint32)(totaltics-elapsed)) / (Sint32)totaltics;\r
-               DrawPlaque(elapsed, x);\r
-\r
-               //\r
-               // get ready to draw draw the "COMMANDER" pic\r
-               //\r
-               cPosX = cStart + ((Sint32)cTotalMove * (Sint32)elapsed) / (Sint32)totaltics;\r
-               cPosX += x & 7;\r
-               screenxb = (cPosX + 0x800) / 8 + -0x100;\r
-               shift = (cPosX + 0x800) & 7;\r
-               srcseg = FP_SEG(cmdrshifts[shift]);\r
-               srcofs = 0;\r
-               dstofs = pageofs + x / 8;\r
-               if (screenxb > 0)\r
-               {\r
-                       clearleft = (screenxb + 1) / 2;\r
-                       if (screenxb & 1)\r
-                               dstofs--;\r
-                       copywidth = 21 - clearleft;\r
-                       clearright = 0;\r
-               }\r
-               else if (-commanderbwide + 40 < screenxb)\r
-               {\r
-                       clearleft = 0;\r
-                       copywidth = 21;\r
-                       clearright = 0;\r
-                       srcofs -= screenxb;\r
-               }\r
-               else\r
-               {\r
-                       clearleft = 0;\r
-                       copywidth = (commanderbwide + screenxb) / 2;\r
-                       clearright = 21 - copywidth;\r
-                       srcofs -= screenxb;\r
-               }\r
-               srcdif = commanderbwide - copywidth*2;\r
-               dstdif = 248 - (clearleft + copywidth + clearright)*2;\r
-\r
-               //\r
-               // draw "COMMANDER" pic\r
-               //\r
-               EGAMAPMASK(2);\r
-\r
-               asm {\r
-                       mov     di, dstofs;\r
-                       mov     es, screenseg;\r
-                       mov     si, srcofs;\r
-                       mov     lastsource, si;\r
-                       mov     ds, srcseg;\r
-                       mov     dx, 200;\r
-               }\r
-yloop:\r
-               asm {\r
-                       xor     ax, ax;\r
-                       mov     cx, clearleft;\r
-                       rep stosw;\r
-                       mov     cx, copywidth;\r
-                       rep movsw;\r
-                       xor     ax, ax;\r
-                       mov     cx, clearright;\r
-                       rep stosw;\r
-                       test    dx, 1;\r
-                       jnz     oddline;\r
-                       mov     si, ss:lastsource;\r
-                       jmp     nextline;\r
-               }\r
-oddline:\r
-               asm {\r
-                       add     si, srcdif;\r
-                       mov     ss:lastsource, si;\r
-               }\r
-nextline:\r
-               asm {\r
-                       add     di, dstdif;\r
-                       dec     dx;\r
-                       jnz     yloop;\r
-                       mov     ax, ss;\r
-                       mov     ds, ax;\r
-               }\r
-\r
-               //\r
-               // page flip\r
-               //\r
-               VW_SetScreen(pageofs + x / 8, x & 7);\r
-               pageon ^= 1;\r
-               if (pageon)\r
-               {\r
-                       pageofs = 124;\r
-               }\r
-               else\r
-               {\r
-                       pageofs = 0;\r
-               }\r
-\r
-               //\r
-               // handle timing\r
-               //\r
-               do\r
-               {\r
-                       now = TimeCount;\r
-                       tics = now - lasttimecount;\r
-               } while (tics < 2);\r
-               lasttimecount = now;\r
-\r
-               //\r
-               // handle input\r
-               //\r
-               if (IN_IsUserInput() && LastScan != sc_F1)\r
-               {\r
-                       LastScan = sc_Space;\r
-               }\r
-               if (LastScan)\r
-                       return;\r
-       }\r
-\r
-       byteadjust = x / 8;\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= DrawScan\r
-=\r
-============================\r
-*/\r
-\r
-void DrawScan(Sint16 far *source, Uint8 far *dest)\r
-{\r
-       register Uint16 x;\r
-       register Sint16 w;\r
-       register Uint16 val;\r
-       register Uint16 i;\r
-\r
-       val = x = 0;\r
-       for (;;)\r
-       {\r
-               //\r
-               // first part: puts black pixels (<width> pixels wide)\r
-               //\r
-               w = *source++;\r
-               if (w == -1)\r
-               {\r
-                       *dest++ = val;\r
-                       *dest = 0;\r
-                       return;\r
-               }\r
-\r
-               x += w;\r
-               if (x > 7)\r
-               {\r
-                       *dest++ = val;\r
-                       val = 0;\r
-                       i = (x / 8) - 1;\r
-                       while (i--)\r
-                       {\r
-                               *dest++ = 0;\r
-                       }\r
-                       x &= 7;\r
-               }\r
-\r
-               //\r
-               // second part: puts white pixels (<width> pixels wide)\r
-               //\r
-               w = *source++;\r
-               if (w == -1)\r
-               {\r
-                       *dest++ = val;\r
-                       *dest = 0;\r
-                       return;\r
-               }\r
-\r
-               val |= ortoend[x];\r
-               x += w;\r
-               if (x > 7)\r
-               {\r
-                       *dest++ = val;\r
-                       val = 0xFF;\r
-                       i = (x / 8) - 1;\r
-                       while (i--)\r
-                       {\r
-                               *dest++ = 0xFF;\r
-                       }\r
-                       x &= 7;\r
-               }\r
-               val &= andtoend[x];\r
-       }\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= BuildScaleShape\r
-=\r
-============================\r
-*/\r
-\r
-void BuildScaleShape(void)\r
-{\r
-       Sint16 px, w;\r
-       Sint16 far *source;\r
-       Sint16 far *dest;\r
-       Sint16 y;\r
-\r
-       MM_GetPtr((memptr*)&both, 30000);\r
-       dest = MK_FP(FP_SEG(both), sizeof(shapehead));\r
-\r
-       for (y=0; y<200; y++)\r
-       {\r
-               both->rowofs[y] = FP_OFF(dest);\r
-               px = 0;\r
-\r
-               EGAREADMAP(1);  // this is pretty useless, we're not reading from EGA memory here\r
-\r
-               source = (Sint16 far *)((byte _seg *)commander + commander->rowofs[y]);\r
-               w = *source++;\r
-               do\r
-               {\r
-                       *dest++ = px;\r
-                       px = px + w;\r
-                       w = *source++;\r
-               } while (w != -1);\r
-\r
-               //\r
-               // insert an 80 pixel gap between "COMMANDER" and "KEEN"\r
-               //\r
-               // This assumes that the rightmost column(s) of the "COMMANDER"\r
-               // shape are black. Otherwise the gap would be filled with\r
-               // white pixels and the "KEEN" image would use inverted colors\r
-               // as a result.\r
-               //\r
-               px += 80;\r
-\r
-               EGAREADMAP(0);  // this is pretty useless, we're not reading from EGA memory here\r
-\r
-               source = (Sint16 far *)((byte _seg *)keen + keen->rowofs[y]);\r
-               source++;       // kludgy bit, causes errors when left egde of "KEEN" is no rectangle\r
-               w = *source++;\r
-               do\r
-               {\r
-                       *dest++ = px;\r
-                       px = px + w;\r
-                       w = *source++;\r
-               } while (w != -1);\r
-\r
-               *dest++ = px;   // put last value\r
-               *dest++ = -1;   // put end-of-line\r
-       }\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= ScalePointScan\r
-=\r
-============================\r
-*/\r
-\r
-void ScalePointScan(Sint16 far *rowptr, Sint16 y, Sint16 toleft, Sint16 far *scaletable)\r
-{\r
-       Uint8 far *dest;\r
-       Sint16 left, endx;\r
-       Uint16 w, val, x, right;\r
-       register Sint16 px, sx;\r
-\r
-       val = x = 0;\r
-       endx = 320 - toleft;\r
-       dest = MK_FP(0xA000, pageofs + byteadjust + ylookup[y]);\r
-\r
-       if (toleft < 0)\r
-       {\r
-               left = -toleft;\r
-               val = 0;\r
-               x = 0;\r
-\r
-               for (;;)\r
-               {\r
-                       px = *rowptr++;\r
-                       sx = scaletable[px];\r
-                       if (sx > left)\r
-                               goto drawwhite;\r
-\r
-                       px = *rowptr++;\r
-                       sx = scaletable[px];\r
-                       if (sx > left)\r
-                               goto drawblack;\r
-               }\r
-       }\r
-\r
-       //\r
-       // regular\r
-       //\r
-       val = 0;\r
-       x = toleft & 7;\r
-       dest += (toleft >> 3);\r
-       left = 0;\r
-       rowptr++;       // the first value is always 0, we need the next value\r
-drawloop:\r
-       px = *rowptr++;\r
-       sx = scaletable[px];\r
-\r
-       //\r
-       // draw/add black pixels\r
-       //\r
-drawblack:\r
-       w = sx - left;\r
-       left = sx;\r
-       x += w;\r
-       if (x > 7)\r
-       {\r
-               asm {\r
-                       les     di, dest;\r
-                       mov     al, BYTE PTR val;\r
-                       stosb;\r
-                       mov     cx, x;\r
-                       shr     cx, 1;\r
-                       shr     cx, 1;\r
-                       shr     cx, 1;\r
-                       dec     cx;\r
-                       xor     al, al;\r
-                       mov     BYTE PTR val, al;\r
-                       rep stosb;\r
-                       and     x, 7;\r
-                       mov     WORD PTR dest, di;\r
-               }\r
-       }\r
-\r
-       //\r
-       // stop if the right side of the screen is reached\r
-       //\r
-       if (sx > endx)\r
-               return;\r
-\r
-       //\r
-       // stop if the end of the image row is reached\r
-       // \r
-       // This is only checked after drawing the black part, so the\r
-       // combined shape must not end with white pixels on the right.\r
-       // That means the rightmost column(s) of the "KEEN" shape must\r
-       // always be black.\r
-       //\r
-       px = *rowptr++;\r
-       if (px == -1)\r
-               goto clearright;\r
-\r
-       sx = scaletable[px];\r
-\r
-       //\r
-       // draw/add white pixels\r
-       //\r
-drawwhite:\r
-       w = sx - left;\r
-       left = sx;\r
-       val |= ortoend[x];\r
-       x += w;\r
-       if (x > 7)\r
-       {\r
-               asm {\r
-                       les     di, dest;\r
-                       mov     al, BYTE PTR val;\r
-                       stosb;\r
-                       mov     cx, x;\r
-                       shr     cx, 1;\r
-                       shr     cx, 1;\r
-                       shr     cx, 1;\r
-                       dec     cx;\r
-                       mov     al, 255;\r
-                       mov     BYTE PTR val, al;\r
-                       rep stosb;\r
-                       and     x, 7;\r
-                       mov     WORD PTR dest, di;\r
-               }\r
-       }\r
-\r
-       //\r
-       // stop if the right side of the screen is reached\r
-       //\r
-       if (sx > endx)\r
-               return;\r
-\r
-       val &= andtoend[x];\r
-       goto drawloop;\r
-\r
-       //\r
-       // clear the right side of the screen\r
-       //\r
-clearright:\r
-       w = 320 - left;\r
-       x += w;\r
-       if (x > 7)\r
-       {\r
-               *dest++ = val;\r
-               val = 0;\r
-               right = x / 8 - 1;\r
-               while (right--)\r
-               {\r
-                       *dest++ = 0;\r
-               }\r
-               x &= 7;\r
-               return;\r
-       }\r
-       return;\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= ScaleDown\r
-=\r
-============================\r
-*/\r
-\r
-void ScaleDown(void)\r
-{\r
-       Uint16 i;\r
-       Uint16 toleft, ticselapsed, ticstotal, scale, endscale, rownum, rowinc;\r
-       Sint32 now;\r
-       Sint16 far *rowptr;\r
-       Uint16 scaleheight, top, bottom, lastbottom[2];\r
-       Sint32 leftorigin;\r
-\r
-       //\r
-       // set our new palette\r
-       //\r
-       SetPalette(termcolors2);\r
-\r
-       EGAREADMAP(1);  // this is pretty useless, we're not reading from EGA memory here\r
-\r
-       leftorigin = 120l - commander->width;\r
-       BuildScaleShape();\r
-       MM_GetPtr(&scaletable, 2500*sizeof(Uint16));\r
-\r
-       scale = 0x100;          // 100%\r
-       endscale = 0x21;        // 13% (scale from 200px to 26px)\r
-       endscale = 0x21;        // redundant\r
-       lastbottom[0] = lastbottom[1] = 200;\r
-       ticselapsed = 1;\r
-       ticstotal = 30; // time for the whole shrinking animation\r
-\r
-       while (ticselapsed <= ticstotal)\r
-       {\r
-               //\r
-               // get current scaling\r
-               //\r
-               if (ticselapsed == ticstotal)\r
-               {\r
-                       scale = endscale;\r
-                       toleft = 0;\r
-                       top = 4;\r
-               }\r
-               else\r
-               {\r
-                       scale = 0x100 - ((0x100-endscale) * ticselapsed) / ticstotal;\r
-                       toleft = (leftorigin * (ticstotal - ticselapsed)) / ticstotal;\r
-                       top = (ticselapsed * 4) / ticstotal;\r
-               }\r
-\r
-               //\r
-               // build scale table:           scaletable[i] = (i*scale) / 0x100;\r
-               //\r
-               asm {\r
-                       xor     ax, ax;\r
-                       xor     dx, dx;\r
-                       mov     cx, 2500;\r
-                       mov     bx, scale;\r
-                       mov     es, scaletable;\r
-                       xor     di, di;\r
-               }\r
-l1:\r
-               asm {\r
-                       mov     es:[di], ah;\r
-                       inc     di;\r
-                       mov     es:[di], dl;\r
-                       inc     di;\r
-                       add     ax, bx;\r
-                       adc     dx, 0;\r
-                       loop    l1;\r
-               }\r
-\r
-               //\r
-               // wait... didn't we already do this?\r
-               //\r
-               if (ticselapsed == ticstotal)\r
-               {\r
-                       toleft = 0;\r
-               }\r
-               else\r
-               {\r
-                       toleft = (leftorigin * (ticstotal - ticselapsed)) / ticstotal;\r
-               }\r
-\r
-               //\r
-               // prepare scaled drawing process\r
-               //\r
-               scaleheight = ((Sint16 _seg *)scaletable)[200];\r
-               rownum = 0;\r
-               rowinc = 0x10000l / scale;\r
-               bufferofs = pageofs + byteadjust;\r
-\r
-               //\r
-               // erase stuff at the top\r
-               //\r
-               if (top > 0)\r
-               {\r
-                       VW_Bar(0, 0, 320, top, BLACK);\r
-               }\r
-\r
-               //\r
-               // draw the scaled shape\r
-               //\r
-               EGAWRITEMODE(0);\r
-               EGAMAPMASK(15);\r
-\r
-               for (i=0; i<scaleheight; i++)\r
-               {\r
-                       rowptr = (Sint16 far *)((byte _seg *)both + both->rowofs[rownum >> 8]);\r
-                       ScalePointScan(rowptr, i+top, toleft, scaletable);\r
-\r
-                       rownum += rowinc;\r
-               }\r
-\r
-               //\r
-               // erase leftovers at the bottom of the screen\r
-               //\r
-               bufferofs = pageofs + byteadjust;\r
-               bottom = scaleheight + top;\r
-               if (lastbottom[pageon] > bottom)\r
-               {\r
-                       VW_Bar(0, bottom, 320, lastbottom[pageon] - bottom, BLACK);\r
-                       lastbottom[pageon] = bottom;\r
-               }\r
-\r
-               //\r
-               // page flip\r
-               //\r
-               VW_SetScreen(pageofs+byteadjust, 0);\r
-               pageon ^= 1;\r
-               if (pageon)\r
-               {\r
-                       pageofs = 124;\r
-               }\r
-               else\r
-               {\r
-                       pageofs = 0;\r
-               }\r
-\r
-               //\r
-               // handle timing\r
-               //\r
-               now = TimeCount;\r
-               tics = now - lasttimecount;\r
-               lasttimecount = now;\r
-               if (tics > 8)\r
-                       tics = 8;       // don't skip too many frames on slow systems\r
-\r
-               if (ticselapsed == ticstotal)\r
-                       break;\r
-\r
-               ticselapsed += tics;\r
-               if (ticselapsed > ticstotal)\r
-                       ticselapsed = ticstotal;\r
-\r
-               //\r
-               // handle input\r
-               //\r
-               if (IN_IsUserInput() && LastScan != sc_F1)\r
-               {\r
-                       LastScan = sc_Space;\r
-               }\r
-               if (LastScan)\r
-                       return; // BUG: buffers aren't freed!\r
-       }\r
-\r
-       //\r
-       // free the buffers\r
-       //\r
-       MM_FreePtr(&scaletable);\r
-       MM_FreePtr((memptr*)&both);\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= FinishPage\r
-=\r
-============================\r
-*/\r
-\r
-void FinishPage(void)\r
-{\r
-       Sint16 swap, temp, i, n, x, y;\r
-       Uint16 ofs;\r
-       Sint16 top, bottom, delta;\r
-       Uint8 bitmask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};\r
-       Sint16 xtable[320], ytable[200];\r
-\r
-       //\r
-       // build lookup tables\r
-       //\r
-       for (i=0; i<320; i++)\r
-       {\r
-               xtable[i] = i;\r
-       }\r
-       for (i=0; i<320; i++)\r
-       {\r
-               swap = random(320);\r
-               temp = xtable[swap];\r
-               xtable[swap] = xtable[i];\r
-               xtable[i] = temp;\r
-       }\r
-       for (i=0; i<200; i++)\r
-       {\r
-               ytable[i] = xtable[i];\r
-       }\r
-\r
-       //\r
-       // set up display\r
-       //\r
-       VW_SetDefaultColors();\r
-       if (pageon)\r
-       {\r
-               bufferofs = byteadjust + 124;\r
-               displayofs = byteadjust;\r
-       }\r
-       else\r
-       {\r
-               bufferofs = byteadjust;\r
-               displayofs = byteadjust + 124;\r
-       }\r
-       VW_SetScreen(displayofs, 0);\r
-\r
-       //\r
-       // draw title pic to the non-displayed buffer\r
-       //\r
-       VW_DrawPic(0, 0, TITLEPICPIC);\r
-\r
-       //\r
-       // copy "random" pixels from the non-displayed area\r
-       // into the displayed area to create the "fizzle" effect\r
-       //\r
-       delta = displayofs - bufferofs;\r
-\r
-       //\r
-       // set ES register for the pixel copying code in the loops\r
-       //\r
-       // This is faster than setting the ES register in the loops,\r
-       // but you need to make sure nothing in the loops overwrites\r
-       // the ES register, otherwise the code won't work correctly.\r
-       //\r
-       asm     mov     es, screenseg;\r
-\r
-       for (i = 0; i< 360; i++)\r
-       {\r
-               top = i - 160;\r
-               if (top < 0)\r
-                       top = 0;\r
-\r
-               bottom = i;\r
-               if (bottom >= 200)\r
-                       bottom = 199;\r
-\r
-               for (y = top; y <= bottom; y++)\r
-               {\r
-                       ofs = bufferofs + ylookup[y];\r
-                       for (n=0; n<2; n++)\r
-                       {\r
-                               x = xtable[ytable[y]];\r
-                               if (++ytable[y] == 320)\r
-                               {\r
-                                       ytable[y] = 0;\r
-                               }\r
-\r
-                               //\r
-                               // set bitmask for our x value\r
-                               //\r
-                               asm     mov     cx, x;\r
-                               asm     mov     si, cx;\r
-                               asm     and     si, 7;\r
-                               asm     cli;\r
-                               asm     mov     dx, GC_INDEX;\r
-                               asm     mov     al, GC_BITMASK;\r
-                               asm     mov     ah, BYTE PTR bitmask[si];\r
-                               asm     out     dx, ax;\r
-                               asm     sti;\r
-\r
-                               //\r
-                               // set up source and dest index registers\r
-                               //\r
-                               asm     mov     si, ofs;\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, delta;\r
-\r
-                               //\r
-                               // copy the pixel data (all 4 planes)\r
-                               //\r
-                               // "blue" plane:\r
-                               asm     mov     dx, SC_INDEX;\r
-                               asm     mov     ax, SC_MAPMASK + 1*256;\r
-                               asm     out     dx, ax;\r
-                               asm     mov     dx, GC_INDEX;\r
-                               asm     mov     ax, GC_READMAP + 0*256;\r
-                               asm     out     dx, ax;\r
-                               asm     mov     bl, es:[si];\r
-                               asm     xchg    bl, es:[di];\r
-                               // "green" plane:\r
-                               asm     mov     dx, SC_INDEX;\r
-                               asm     mov     ax, SC_MAPMASK + 2*256;\r
-                               asm     out     dx, ax;\r
-                               asm     mov     dx, GC_INDEX;\r
-                               asm     mov     ax, GC_READMAP + 1*256;\r
-                               asm     out     dx, ax;\r
-                               asm     mov     bl, es:[si];\r
-                               asm     xchg    bl, es:[di];\r
-                               // "red" plane:\r
-                               asm     mov     dx, SC_INDEX;\r
-                               asm     mov     ax, SC_MAPMASK + 4*256;\r
-                               asm     out     dx, ax;\r
-                               asm     mov     dx, GC_INDEX;\r
-                               asm     mov     ax, GC_READMAP + 2*256;\r
-                               asm     out     dx, ax;\r
-                               asm     mov     bl, es:[si];\r
-                               asm     xchg    bl, es:[di];\r
-                               // "intensity" plane:\r
-                               asm     mov     dx, SC_INDEX;\r
-                               asm     mov     ax, SC_MAPMASK + 8*256;\r
-                               asm     out     dx, ax;\r
-                               asm     mov     dx, GC_INDEX;\r
-                               asm     mov     ax, GC_READMAP + 3*256;\r
-                               asm     out     dx, ax;\r
-                               asm     mov     bl, es:[si];\r
-                               asm     xchg    bl, es:[di];\r
-                       }\r
-               }\r
-\r
-               VW_WaitVBL(1);  // so the fizzle animation won't go super fast\r
-\r
-               if (IN_IsUserInput() && LastScan != sc_F1)\r
-               {\r
-                       LastScan = sc_Space;\r
-               }\r
-               if (LastScan)\r
-               {\r
-                       EGABITMASK(0xFF);\r
-                       EGAMAPMASK(15);\r
-                       return;\r
-               }\r
-       }\r
-\r
-       //\r
-       // clean up EGA registers\r
-       //\r
-       EGABITMASK(0xFF);\r
-       EGAMAPMASK(15);\r
-\r
-       //\r
-       // pause for 6 seconds\r
-       //\r
-       IN_UserInput(6 * TickBase, false);\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= Terminator\r
-=\r
-============================\r
-*/\r
-\r
-void Terminator(void)\r
-{\r
-       Uint16 i, shift, bufsize;\r
-       Sint16 far *source;\r
-       Uint8 far *dest;\r
-       Uint16 srcseg, destseg;\r
-       boolean pagefinished;\r
-       Uint16 rowofs[200];\r
-\r
-       pagefinished = false;\r
-       CA_SetAllPurge();\r
-       SetPaletteEx(colors[0]);        // all black\r
-       VW_ClearVideo(BLACK);\r
-       VW_SetLineWidth(248);   // 1984 pixels total, we're using 992 per "page"\r
-\r
-       CA_CacheGrChunk(TITLEPICPIC);\r
-       CA_CacheGrChunk(BIGCOMMANDER);\r
-       CA_CacheGrChunk(BIGKEEN);\r
-       keen = grsegs[BIGKEEN];\r
-       commander = grsegs[BIGCOMMANDER];\r
-\r
-       EGAMAPMASK(1);\r
-\r
-       keenstart = keen->width + 200;\r
-       VW_SetScreen((keenstart/8)+1, 0);\r
-\r
-       //\r
-       // draw the "KEEN" pic (to first "page")\r
-       //\r
-       for (i=0; i<200; i++)\r
-       {\r
-               source = (Sint16 far *)((byte _seg *)keen + keen->rowofs[i]);\r
-               dest = MK_FP(0xA000, ylookup[i]);\r
-               dest += 25;     // 25 bytes -> 200 pixels\r
-               DrawScan(source, dest);\r
-       }\r
-       //\r
-       // copy pic from first "page" to second "page"\r
-       //\r
-       VW_ScreenToScreen(0, 124, 109, 200);\r
-\r
-       //\r
-       // create pre-shifted image buffers for the "COMMANDER" pic\r
-       // (only 100 pixels high instead of 200 pixels to save memory)\r
-       //\r
-       commanderbwide = (commander->width + 7) / 8;\r
-       commanderbwide = (commanderbwide + 3) & ~1;\r
-       bufsize = commanderbwide * 100; // half height\r
-       for (shift = 0; shift < 8; shift++)\r
-       {\r
-               MM_GetPtr(&cmdrshifts[shift], bufsize);\r
-       }\r
-\r
-       //\r
-       // re-assign shape pointers (memory manager might have moved the buffers)\r
-       //\r
-       keen = grsegs[BIGKEEN];\r
-       commander = grsegs[BIGCOMMANDER];\r
-\r
-       //\r
-       // draw the first (unshifted) version of the "COMMANDER" pic to the buffer\r
-       //\r
-       for (i=0; i<100; i++)\r
-       {\r
-               rowofs[i*2] = rowofs[i*2+1] = i * commanderbwide;\r
-               source = (Sint16 far *)((byte _seg *)commander + commander->rowofs[i*2]);\r
-               dest = (Uint8 _seg *)cmdrshifts[0] + rowofs[i*2];\r
-               DrawScan(source, dest);\r
-       }\r
-\r
-       //\r
-       // create the shifted versions of the "COMMANDER" pic\r
-       //\r
-       for (shift = 1; shift < 8; shift++)\r
-       {\r
-               srcseg = FP_SEG(cmdrshifts[shift-1]);\r
-               destseg = FP_SEG(cmdrshifts[shift]);\r
-               asm {\r
-                       mov     ds, srcseg;\r
-                       mov     es, destseg;\r
-                       mov     cx, bufsize;\r
-                       clc;\r
-                       xor     si, si;\r
-                       xor     di, di;\r
-               }\r
-l1:\r
-               asm {\r
-                       lodsb;\r
-                       rcr     al, 1;\r
-                       stosb;\r
-                       loop    l1;\r
-                       mov     ax, ss;\r
-                       mov     ds, ax;\r
-               }\r
-       }\r
-\r
-       //\r
-       // prepare (and set) the palettes\r
-       //\r
-       termcolors[16] = termcolors2[16] = termcolors[16] = bordercolor;\r
-       SetPalette(termcolors);\r
-\r
-       //\r
-       // cache the credits pics (they are converted into a special\r
-       // format to make shifted drawing easier during the animation)\r
-       //\r
-       for (i=0; i<4; i++)\r
-       {\r
-               LoadPlaque(i);\r
-       }\r
-\r
-       //\r
-       // play the animation\r
-       //\r
-       plaque = lastframe = 0;\r
-       plaquephase = -1;\r
-       SlideLetters();\r
-\r
-       //\r
-       // free some of the buffers\r
-       // (shrink animation needs additional memory)\r
-       //\r
-       for (i=0; i<4; i++)\r
-       {\r
-               MM_FreePtr(&basepl[i]);\r
-       }\r
-       for (shift=0; shift<8; shift++)\r
-       {\r
-               MM_FreePtr(&cmdrshifts[shift]);\r
-       }\r
-\r
-       //\r
-       // do the shrinking and fizzle fade animations\r
-       // (if intro wasn't aborted)\r
-       //\r
-       if (!LastScan)\r
-       {\r
-               ScaleDown();\r
-       }\r
-\r
-       if (!LastScan)\r
-       {\r
-               FinishPage();\r
-               pagefinished = true;\r
-       }\r
-\r
-       //\r
-       // free the remaining buffers\r
-       //\r
-       MM_SetPurge(&grsegs[BIGCOMMANDER], 3);\r
-       MM_SetPurge(&grsegs[BIGKEEN], 3);\r
-\r
-       //\r
-       // switch back to default graphics settings\r
-       //\r
-       VW_ClearVideo(BLACK);\r
-       VW_SetLineWidth(SCREENWIDTH);\r
-       VW_SetDefaultColors();\r
-       RF_FixOfs();\r
-       CA_ClearMarks();\r
-\r
-       //\r
-       // handle input and main menu stuff\r
-       //\r
-       if (LastScan == sc_None)\r
-       {\r
-               return;\r
-       }\r
-#ifndef KEEN6\r
-       if (LastScan == sc_F1)\r
-       {\r
-               HelpScreens();\r
-               return;\r
-       }\r
-#endif\r
-       if (!pagefinished)\r
-       {\r
-               RF_FixOfs();    //redundant\r
-               CA_CacheGrChunk(TITLEPICPIC);\r
-               VW_DrawPic(0, 0, TITLEPICPIC);\r
-               VW_SetScreen(bufferofs, 0);\r
-               IN_Ack();\r
-               CA_ClearMarks();\r
-               if (storedemo)\r
-               {\r
-                       playstate = ex_resetgame;\r
-                       restartgame = gd_Normal;\r
-                       IN_ClearKeysDown();\r
-                       NewGame();\r
-                       return;\r
-               }\r
-       }\r
-\r
-       US_ControlPanel();\r
-       if (restartgame)\r
-       {\r
-               playstate = ex_resetgame;\r
-       }\r
-       else if (loadedgame)\r
-       {\r
-               playstate = ex_loadedgame;\r
-       }\r
-}\r
-\r
-/*\r
-=============================================================================\r
-\r
-                                                       STAR WARS TEXT CRAWL\r
-\r
-=============================================================================\r
-*/\r
-\r
-/*\r
-============================\r
-=\r
-= BuildBitTables\r
-=\r
-============================\r
-*/\r
-\r
-void BuildBitTables(void)\r
-{\r
-       Uint16 bit1, bit2, i;\r
-       Uint8 far *buffer;\r
-\r
-       MM_GetPtr(&bittables, 0x4000);\r
-       buffer = bittables;\r
-\r
-       //\r
-       // generate a lookup table that maps the bits of the "texture" (bit1)\r
-       // to the appropriate bit for the screen position (bit2) to make the\r
-       // scaler code faster and smaller\r
-       //\r
-       // table[((7-b1)*8+(7-b2))*256+i] = (i & (1 << (7-b1))) ? (1 << (7-b2)) : 0;\r
-       //\r
-       for (bit1 = 1; bit1 < 0x100; bit1 <<= 1)\r
-       {\r
-               for (bit2 = 1; bit2 < 0x100; bit2 <<= 1)\r
-               {\r
-                       for (i = 0; i < 0x100; i++, buffer++)\r
-                       {\r
-                               if (i & bit1)\r
-                               {\r
-                                       *buffer = bit2;\r
-                               }\r
-                               else\r
-                               {\r
-                                       *buffer = 0;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= CompileSWUpdate\r
-=\r
-============================\r
-*/\r
-\r
-void CompileSWUpdate(void)\r
-{\r
-       Sint16 y;\r
-       Uint16 i, width, scalestep, step;\r
-       Sint32 scale, rowof, xpos, size;\r
-       void far *buffer;\r
-       Uint8 srcoff, srcbit, bitpos;\r
-       Uint16 destoff, srcx, left, orindex, lastoff;\r
-\r
-       BuildBitTables();\r
-       size = 190000;\r
-       MM_GetPtr(&linecode, size);\r
-       buffer = linecode;\r
-       //\r
-       // Note: You should really lock the pointer to prevent the memmory manager\r
-       // from moving the buffer around. This code stores a bunch of pointers to\r
-       // this memory block in the linestarts array. Those pointers will not be\r
-       // updated when the memory manager moves the buffer around and the game\r
-       // might end up crashing (or worse) when trying to run the "code" at the\r
-       // memory location after the data was moved. The game starts playing music\r
-       // after this function is done, which may or may not cause the memory\r
-       // manager to move memory blocks around.\r
-       //\r
-\r
-       //\r
-       // move the buffer address into ES:DI (and keep it there)\r
-       //\r
-       asm     mov     es, WORD PTR buffer+2;\r
-       asm     mov     di, WORD PTR buffer;\r
-       //\r
-       // Since the address is kept in ES:DI, we must save and restore\r
-       // the ES register when calling other functions (push es / pop es).\r
-       // The Borland C compiler always saves and restores the DI register\r
-       // when a function modifies it, so we don't need to worry about\r
-       // that register. This is a bit of an ugly hack, but it makes this\r
-       // code a little faster and smaller.\r
-       //\r
-\r
-       scale = 320l << 11;\r
-       scalestep = (((Uint32)(320-40) << 11) / 200);   // roughly 1.4 pixels per step, going from 320 pixels to 40 pixels in 200 steps\r
-       rowof = 0;\r
-\r
-       for (y=199; y >= 0; y--)\r
-       {\r
-               //\r
-               // draw a blue line for the current row\r
-               //\r
-               asm     push    es;\r
-               VW_Hlin(0, 320, y, BLUE);\r
-               asm     pop     es;\r
-\r
-               //\r
-               // update the buffer variable with the current (normalized) ES:DI address\r
-               //\r
-               asm     mov     WORD PTR buffer, di;\r
-               asm     mov     WORD PTR buffer+2, es;\r
-\r
-               //\r
-               // store the address in the scaler lookup table\r
-               //\r
-               linestarts[y] = buffer;\r
-\r
-               //\r
-               // get current scaling factors\r
-               //\r
-               width = ((Uint16)((scale/2) >> 11)) << 1;       // some trickery to make sure width is even\r
-               sourceline[y] = (rowof >> 11);\r
-               step = (336l << 11) / width;\r
-               xpos = 0;\r
-               rowof += step;\r
-               left = 160 - (width >> 1);\r
-               destoff = ylookup[y] + left / 8;\r
-               bitpos = left & 7;\r
-\r
-               //\r
-               // generate the machine code\r
-               //\r
-               //              MOV     CX, SS\r
-               //              MOV     SS, AX\r
-               //              ADD     DI, <destoff>\r
-               //              XOR     AL, AL\r
-               //\r
-               asm     mov     ax, 0D18Ch;\r
-               asm     stosw;\r
-               asm     mov     ax, 0D08Eh;\r
-               asm     stosw;\r
-               asm     mov     ax, 0C781h;\r
-               asm     stosw;\r
-               asm     mov     ax, destoff;\r
-               asm     stosw;\r
-               asm     mov     ax, 0C030h;\r
-               asm     stosw;\r
-\r
-               lastoff = -1;\r
-               for (i=0; i<width; i++)\r
-               {\r
-                       srcx = (xpos >> 11);\r
-                       srcoff = (srcx / 8);\r
-                       srcbit = srcx & 7;\r
-\r
-                       orindex = ((7-srcbit)*8 + 7-bitpos) << 8;\r
-                       if (srcoff != lastoff)\r
-                       {\r
-                               //\r
-                               //              MOV     BL, [BP + <srcoff>]\r
-                               //\r
-                               asm     mov     ax, 5E8Ah;\r
-                               asm     stosw;\r
-                               asm     mov     al, srcoff;\r
-                               asm     stosb;\r
-\r
-                               lastoff = srcoff;\r
-                       }\r
-\r
-                       //\r
-                       //              OR              AL, [BX + <orindex>]\r
-                       //\r
-                       asm     mov     ax, 870Ah;\r
-                       asm     stosw;\r
-                       asm     mov     ax, orindex;\r
-                       asm     stosw;\r
-\r
-                       bitpos++;\r
-                       if (bitpos == 8)\r
-                       {\r
-                               bitpos = 0;\r
-\r
-                               //\r
-                               //              STOSB\r
-                               //              XOR     AL, AL\r
-                               //\r
-                               asm     mov     ax, 30AAh;\r
-                               asm     stosw;\r
-                               asm     mov     al, 0C0h;\r
-                               asm     stosb;\r
-                       }\r
-\r
-                       xpos += step;\r
-               }\r
-\r
-               if (bitpos)\r
-               {\r
-                       //\r
-                       //              STOSB\r
-                       //\r
-                       asm     mov     al, 0AAh;\r
-                       asm     stosb;\r
-               }\r
-               //\r
-               // generate end of subroutine\r
-               //\r
-               //              MOV     SS, CX\r
-               //              RETF\r
-               //\r
-               asm     mov     ax, 0D18Eh;\r
-               asm     stosw;\r
-               asm     mov     al, 0CBh;\r
-               asm     stosb;\r
-\r
-               //\r
-               // normalize ES:DI\r
-               //\r
-               asm     mov     ax, di;\r
-               asm     shr     ax, 1;\r
-               asm     shr     ax, 1;\r
-               asm     shr     ax, 1;\r
-               asm     shr     ax, 1;\r
-               asm     mov     bx, es;\r
-               asm     add     ax, bx;\r
-               asm     mov     es, ax;\r
-               asm     and     di, 0Fh;\r
-\r
-               //\r
-               // update scale value for next row\r
-               //\r
-               scale -= scalestep;\r
-\r
-               //\r
-               // replace the blue line with the row from the background image\r
-               //\r
-               asm     push    es;\r
-               VW_ScreenToScreen(ylookup[y] + 0x8000, ylookup[y], 40, 1);\r
-               asm     pop     es;\r
-\r
-               if (LastScan)\r
-                       return;\r
-       }\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= TranslateString\r
-=\r
-============================\r
-*/\r
-\r
-void TranslateString(char *text)\r
-{\r
-       char c;\r
-\r
-       while (*text)\r
-       {\r
-               c = *text;\r
-\r
-               if (c >= 'A' && c <= 'Z')\r
-               {\r
-                       c = c + -33;\r
-               }\r
-               else if (c >= 'a' && c <= 'z')\r
-               {\r
-                       c = c + -39;\r
-               }\r
-               else if (c == '.')\r
-               {\r
-                       c = 84;\r
-               }\r
-               else if (c == ',')\r
-               {\r
-                       c = 85;\r
-               }\r
-               else if (c == '-')\r
-               {\r
-                       c = 86;\r
-               }\r
-               else if (c == '"')\r
-               {\r
-                       c = 87;\r
-               }\r
-               else if (c == ' ')\r
-               {\r
-                       c = 88;\r
-               }\r
-               else if (c == '!')\r
-               {\r
-                       c = 89;\r
-               }\r
-               else if (c == '\'')\r
-               {\r
-                       c = 90;\r
-               }\r
-               else if (c != '\n')\r
-               {\r
-                       c = 84; // any unhandled character is drawn as '.'\r
-               }\r
-\r
-               *text++ = c;\r
-       }\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= DrawSWText\r
-=\r
-============================\r
-*/\r
-\r
-void DrawSWText(void)\r
-{\r
-       char far *text;\r
-       char *ptr;\r
-       char c;\r
-       char strbuf[80];\r
-\r
-       WindowX = 0;\r
-       WindowW = 336;\r
-       PrintY = 1;             // always leave the first line blank\r
-       bufferofs = 0;\r
-       panadjust = 0;\r
-       text = swtext;\r
-       masterlines = 0;\r
-\r
-       //\r
-       // draw the entire text to video memory\r
-       //\r
-       while (*text)\r
-       {\r
-               ptr = strbuf;\r
-               do\r
-               {\r
-                       c = *text++;\r
-                       *ptr++ = c;\r
-               } while (c != '\n' && c != '\0');\r
-               *ptr = '\0';\r
-\r
-               TranslateString(strbuf);\r
-\r
-               US_CPrint(strbuf);\r
-\r
-               bufferofs += ylookup[PrintY];\r
-               masterlines += PrintY;\r
-               PrintY = 0;\r
-       }\r
-\r
-       //\r
-       // allocate a buffer large enough to hold the entire text image\r
-       // and move the image data from video memory into that buffer\r
-       //\r
-       MM_GetPtr(&sourcepic, bufferofs);\r
-       EGAREADMAP(1);  // read from "green" plane (doesn't really matter from which plane we read)\r
-       movedata(screenseg, 0, FP_SEG(sourcepic), 0, bufferofs);\r
-\r
-       //\r
-       // erase the (first screen of the) text from video memory.\r
-       // we're going to display this area and copy the backgound pic\r
-       // here line-by-line as the scalers are generated and we don't\r
-       // want to have parts of the text still visible at that point.\r
-       //\r
-       bufferofs = 0;\r
-       VW_Bar(0, 0, 320, 200, BLACK);\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= ScrollSWText\r
-=\r
-============================\r
-*/\r
-\r
-void ScrollSWText(void)\r
-{\r
-       Sint32 now;\r
-       Uint16 pos;\r
-       Sint16 i, rowof;\r
-\r
-       tics = TimeCount = lasttimecount = 0;\r
-\r
-       EGAWRITEMODE(0);\r
-       EGAMAPMASK(8);  // only draw to the "intensity" plane (so we don't erase the backgound pic)\r
-\r
-       pos = 0;\r
-       while (masterlines + 400 >= pos)\r
-       {\r
-               for (i = 199; i >= 0; i--)\r
-               {\r
-                       rowof = pos - sourceline[i];\r
-                       if (rowof < 0 || rowof >= masterlines)\r
-                       {\r
-                               masterofs = 0;  // draw the first (blank) line of the buffer\r
-                       }\r
-                       else\r
-                       {\r
-                               masterofs = rowof * 42;\r
-                       }\r
-                       routine = linestarts[i];\r
-                       asm {\r
-                               mov     es, screenseg;\r
-                               mov     di, pageofs;\r
-                               mov     ds, bittables;\r
-                               push    bp;\r
-                               mov     bp, ss:masterofs;\r
-                               mov     ax, ss:sourcepic;\r
-                               xor     bh, bh;\r
-                               cli;    // disable interrupts (scaler changes register SS, so interrupts would be fatal!)\r
-                               call    ss:routine;\r
-                               sti;    // enable interrupts again\r
-                               pop     bp;\r
-                               mov     ax, ss;\r
-                               mov     ds, ax;\r
-                       }\r
-               }\r
-\r
-               VW_SetScreen(pageofs, 0);\r
-               pageon ^= 1;\r
-               pageofs = pageon << 15;\r
-\r
-               now = TimeCount;\r
-               tics = tics + (now - lasttimecount);\r
-               lasttimecount = now;\r
-               if (tics > 20)\r
-                       tics = 20;\r
-\r
-               pos = pos + tics / 4;\r
-               tics &= 3;\r
-\r
-               if (IN_IsUserInput() && LastScan != sc_F1)\r
-                       LastScan = sc_Space;\r
-\r
-               if (LastScan)\r
-                       break;\r
-       }\r
-}\r
-\r
-/*\r
-============================\r
-=\r
-= StarWars\r
-=\r
-============================\r
-*/\r
-\r
-void StarWars(void)\r
-{\r
-       SetPaletteEx(colors[0]);        // all black\r
-       VW_ClearVideo(BLACK);\r
-       VW_SetLineWidth(42);    // 336 pixels\r
-       VW_SetScreen(0, 0);\r
-       pageon = pageofs = 0;\r
-       CA_SetAllPurge();\r
-       CA_CacheGrChunk(STARTFONT+2);\r
-       fontnumber = 2;\r
-       DrawSWText();\r
-       fontnumber = 0;\r
-\r
-       CA_CacheGrChunk(SW_BACKGROUNDPIC);\r
-       bufferofs = 0x8000;\r
-       VW_DrawPic(0, 0, SW_BACKGROUNDPIC);\r
-       CA_SetAllPurge();\r
-       SetPaletteEx(starcolors);\r
-       bufferofs = 0;\r
-       CompileSWUpdate();\r
-\r
-       if (!LastScan)\r
-       {\r
-               StartMusic(STARWARSMUSIC);\r
-               ScrollSWText();\r
-               StopMusic();\r
-       }\r
-\r
-       MM_FreePtr(&linecode);\r
-       MM_FreePtr(&bittables);\r
-       MM_FreePtr(&sourcepic);\r
-\r
-       VW_ClearVideo(BLACK);\r
-       VW_SetLineWidth(SCREENWIDTH);\r
-       VW_SetDefaultColors();\r
-       RF_FixOfs();\r
-       CA_ClearMarks();\r
-\r
-       CheckLastScan();\r
-}\r
-\r
-#endif // if GRMODE == EGAGR\r
-\r
-//===========================================================================\r
-\r
-/*\r
-============================\r
-=\r
-= ShowTitle\r
-=\r
-============================\r
-*/\r
-\r
-void ShowTitle(void)\r
-{\r
-       panadjust = 0;\r
-       CA_CacheGrChunk(TITLEPICPIC);\r
-       VW_DrawPic(0, 0, TITLEPICPIC);\r
-#if GRMODE == CGAGR\r
-       VW_UpdateScreen();\r
-#else\r
-       VW_SetScreen(displayofs, 0);\r
-       VW_ScreenToScreen(bufferofs, displayofs, 42, 224);\r
-#endif\r
-       IN_UserInput(6*TickBase, false);\r
-       CA_ClearMarks();\r
-       CheckLastScan();\r
-}\r
-\r
-//===========================================================================\r
-\r
-#if GRMODE == CGAGR\r
-/*\r
-============================\r
-=\r
-= ShowCredits\r
-=\r
-============================\r
-*/\r
-\r
-void ShowCredits(void)\r
-{\r
-       panadjust = 0;\r
-       CA_CacheGrChunk(SW_BACKGROUNDPIC);\r
-       VW_DrawPic(0, 0, SW_BACKGROUNDPIC);\r
-       VW_UpdateScreen();\r
-       IN_UserInput(6*TickBase, false);\r
-       CA_ClearMarks();\r
-       CheckLastScan();\r
-}\r
-#endif\r
-\r
-//===========================================================================\r
-\r
-/*\r
-============================\r
-=\r
-= RunDemo\r
-=\r
-============================\r
-*/\r
-\r
-void RunDemo(Sint16 num)\r
-{\r
-       Uint16 far *demodata;\r
-       \r
-       NewGame();\r
-       num += DEMO0;\r
-       CA_CacheGrChunk(num);\r
-       demodata = grsegs[num];\r
-       gamestate.mapon = demodata[0];\r
-       DemoSize = demodata[1];\r
-       MM_GetPtr(&(memptr)DemoBuffer, DemoSize);\r
-       MM_SetLock(&(memptr)DemoBuffer, true);\r
-       _fmemcpy(DemoBuffer, ((char _seg *)grsegs[num])+4, DemoSize);\r
-       MM_FreePtr(&grsegs[num]);\r
-       IN_StartDemoPlayback(DemoBuffer, DemoSize);\r
-       SetupGameLevel(true);\r
-       if (scorescreenkludge)\r
-       {\r
-               DrawHighScores();\r
-       }\r
-       PlayLoop();\r
-       IN_StopDemo();\r
-       MM_FreePtr(&(memptr)DemoBuffer);\r
-       VW_FixRefreshBuffer();\r
-       CA_ClearMarks();\r
-       CheckLastScan();\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-============================\r
-=\r
-= DrawHighScores\r
-=\r
-============================\r
-*/\r
-\r
-void DrawHighScores(void)\r
-{\r
-       Uint16 i, n;\r
-       Uint16 width, height;\r
-       HighScore *entry;\r
-       Uint16 oldbufferofs;\r
-       char buf[16], *bufptr;\r
-       \r
-       RF_NewPosition(0, 0);\r
-       oldbufferofs = bufferofs;\r
-       bufferofs = masterofs;\r
-#ifdef KEEN5\r
-#if GRMODE == CGAGR\r
-       fontcolor = 2;\r
-#else\r
-       fontcolor = BLUE ^ LIGHTMAGENTA;        // blue text on light magenta background (XOR draw mode!)\r
-#endif\r
-#endif\r
-       for (i=0, entry=&Scores[0]; i<MaxScores; i++, entry++)\r
-       {\r
-               PrintY = i*16 + HIGHSCORE_TOP;\r
-               PrintX = HIGHSCORE_LEFT;\r
-               US_Print(entry->name);\r
-#ifdef KEEN4\r
-               PrintX = 152;\r
-               for (n=0; n<entry->completed; n++)\r
-               {\r
-                       VWB_DrawTile8(PrintX, PrintY+1, 71);\r
-                       PrintX += 8;\r
-               }\r
-#endif\r
-               ultoa(entry->score, buf, 10);\r
-               for (bufptr=buf; *bufptr; bufptr++)\r
-               {\r
-                       *bufptr = *bufptr + 81;\r
-               }\r
-               USL_MeasureString(buf, &width, &height);\r
-               PrintX = HIGHSCORE_RIGHT - width;\r
-               US_Print(buf);\r
-       }\r
-       fontcolor = WHITE;      // back to default color\r
-       bufferofs = oldbufferofs;\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-============================\r
-=\r
-= CheckHighScore\r
-=\r
-============================\r
-*/\r
-\r
-void CheckHighScore(Sint32 score, Sint16 completed)\r
-{\r
-       Uint16 i, n;\r
-       Sint16 index;\r
-       HighScore entry;\r
-       \r
-       strcpy(entry.name, ""); //Note: 'entry.name[0] = 0;' would be more efficient\r
-       entry.score = score;\r
-       entry.completed = completed;\r
-       for (i=0, index=-1; i<MaxScores; i++)\r
-       {\r
-               if (Scores[i].score < entry.score ||\r
-                       (Scores[i].score == entry.score && Scores[i].completed < entry.completed))\r
-               {\r
-                       n=MaxScores;\r
-                       while (--n > i)\r
-                       {\r
-                               Scores[n] = Scores[n-1];\r
-                       }\r
-                       Scores[i] = entry;\r
-                       index = i;\r
-                       HighScoresDirty = true;\r
-                       break;\r
-               }\r
-       }\r
-       if (index != -1)\r
-       {\r
-               scorescreenkludge = true;\r
-               gamestate.mapon = HIGHSCORE_MAP;\r
-               SetupGameLevel(true);\r
-               DrawHighScores();\r
-#ifdef KEEN5\r
-#if GRMODE == CGAGR\r
-               fontcolor = 2;\r
-#else\r
-               fontcolor = BLUE ^ LIGHTMAGENTA;        // blue text on light magenta background (XOR draw mode!)\r
-#endif\r
-#endif\r
-               RF_Refresh();\r
-               RF_Refresh();\r
-               PrintY = i*16 + HIGHSCORE_TOP;\r
-               PrintX = HIGHSCORE_LEFT;\r
-               US_LineInput(PrintX, PrintY, Scores[index].name, NULL, true, MaxHighName, 112);\r
-               scorescreenkludge = false;\r
-       }\r
-#ifdef KEEN5\r
-       fontcolor = 15; // back to default color (white)\r
-#endif\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-============================\r
-=\r
-= ShowHighScores\r
-=\r
-============================\r
-*/\r
-\r
-void ShowHighScores(void)\r
-{\r
-       scorescreenkludge = true;\r
-       IN_ClearKeysDown();\r
-       RunDemo(4);\r
-       scorescreenkludge = false;\r
-}\r