+++ /dev/null
-/* 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