]> 4ch.mooo.com Git - 16.git/blob - 16/keen456/KEEN4-6/CK_DEMO.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / CK_DEMO.C
1 /* Reconstructed Commander Keen 4-6 Source Code\r
2  * Copyright (C) 2021 K1n9_Duk3\r
3  *\r
4  * This file is loosely based on:\r
5  * Keen Dreams Source Code\r
6  * Copyright (C) 2014 Javier M. Chavez\r
7  *\r
8  * This program is free software; you can redistribute it and/or modify\r
9  * it under the terms of the GNU General Public License as published by\r
10  * the Free Software Foundation; either version 2 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU General Public License along\r
19  * with this program; if not, write to the Free Software Foundation, Inc.,\r
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
21  */\r
22 \r
23 #include "CK_DEF.H"\r
24 \r
25 /*\r
26 =============================================================================\r
27 \r
28                                                  GLOBAL VARIABLES\r
29 \r
30 =============================================================================\r
31 */\r
32 \r
33 boolean scorescreenkludge;\r
34 \r
35 /*\r
36 =============================================================================\r
37 \r
38                                                  LOCAL VARIABLES\r
39 \r
40 =============================================================================\r
41 */\r
42 \r
43 #if GRMODE == EGAGR\r
44 \r
45 Uint8 starcolors[17] = STARPALETTE;\r
46 Uint16 plaquenum[4] = {IDSOFTPIC, PROGTEAMPIC, ARTISTPIC, DIRECTORPIC};\r
47 Uint8 termcolors[17] = INTROPALETTE;\r
48 Uint8 termcolors2[17] = SHRINKPALETTE;\r
49 \r
50 Uint8 ortoend[8] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01};\r
51 Uint8 andtoend[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE};\r
52 \r
53 /////////////////////////////////////////////////////////////////////////////\r
54 // uninitialized variables:\r
55 /////////////////////////////////////////////////////////////////////////////\r
56 \r
57 typedef struct {\r
58         Uint16 height;\r
59         Uint16 width;\r
60         Uint16 rowofs[200];\r
61 } shapehead;\r
62 \r
63 typedef shapehead _seg * shapeseg;\r
64 \r
65 // text crawl variables:\r
66 memptr linecode;\r
67 void far *linestarts[200];\r
68 Uint16 sourceline[200];\r
69 Uint16 masterlines;\r
70 void far *routine;\r
71 memptr sourcepic;\r
72 memptr bittables;\r
73 \r
74 // terminator intro variables:\r
75 shapeseg commander;\r
76 shapeseg keen;\r
77 shapeseg both;\r
78 memptr scaletable;\r
79 memptr cmdrshifts[8];\r
80 Sint16 commanderbwide;\r
81 Uint16 lastsource;\r
82 Uint16 keenstart;\r
83 memptr basepl[5];\r
84 Uint16 baseplwidth[5];\r
85 Uint16 baseplheight[5];\r
86 memptr plaqueseg;\r
87 Uint16 plaquewidth;\r
88 Uint16 plaquewidthwords;\r
89 Uint16 plaqueheight;\r
90 Uint16 plaqueplane;\r
91 Uint16 plaquedelta;\r
92 Uint16 *shiftptr;\r
93 Uint16 planeon;\r
94 Sint16 drawheight;\r
95 Uint16 source2;\r
96 static Uint16 t_dest;\r
97 static Sint16 plaque;\r
98 static Sint16 plaquephase;\r
99 static Sint16 plaquey;\r
100 static Sint16 lastframe;\r
101 static Sint16 pageon;\r
102 static Sint16 prevbottom[2];\r
103 Uint16 pageofs;\r
104 Uint16 byteadjust;\r
105 \r
106 #endif  // if GRMODE == EGAGR\r
107 \r
108 //===========================================================================\r
109 \r
110 /*\r
111 ============================\r
112 =\r
113 = CheckLastScan\r
114 =\r
115 ============================\r
116 */\r
117 \r
118 void CheckLastScan(void)\r
119 {\r
120         if (LastScan)\r
121         {\r
122                 if (storedemo)\r
123                 {\r
124                         playstate = ex_resetgame;\r
125                         restartgame = gd_Normal;\r
126                         IN_ClearKeysDown();\r
127                         NewGame();\r
128                 }\r
129 #ifndef KEEN6\r
130                 else if (LastScan == sc_F1)\r
131                 {\r
132                         HelpScreens();\r
133                 }\r
134 #endif\r
135                 else\r
136                 {\r
137                         US_ControlPanel();\r
138                         if (restartgame)\r
139                         {\r
140                                 playstate = ex_resetgame;\r
141                         }\r
142                         else if (loadedgame)\r
143                         {\r
144                                 playstate = ex_loadedgame;\r
145                         }\r
146                 }\r
147         }\r
148 }\r
149 \r
150 #if GRMODE == EGAGR\r
151 /*\r
152 =============================================================================\r
153 \r
154                                                         TERMINATOR INTRO\r
155 \r
156 =============================================================================\r
157 */\r
158 \r
159 /*\r
160 ============================\r
161 =\r
162 = LoadPlaque\r
163 =\r
164 ============================\r
165 */\r
166 \r
167 void LoadPlaque(Sint16 index)\r
168 {\r
169         Sint16 LocatePlaque(Sint16 elapsed);\r
170 \r
171         Uint16 chunk, picnum, width, height, planesize, i;\r
172         Uint8 far *source;\r
173         Uint16 far *dest;\r
174 \r
175         //\r
176         // cache the pic and get pic size\r
177         //\r
178         chunk = plaquenum[index];\r
179         CA_CacheGrChunk(chunk);\r
180         picnum = chunk - STARTPICS;\r
181         baseplwidth[index] = width = pictable[picnum].width;\r
182         baseplheight[index] = height = pictable[picnum].height;\r
183         planesize = width * height * 2;\r
184 \r
185         //\r
186         // allocate buffer and convert pic into to our format\r
187         // (convert bytes to word indices for faster shift-drawing)\r
188         //\r
189         MM_GetPtr(&basepl[index], planesize*2); // 2 planes\r
190         source = grsegs[chunk];\r
191         dest = basepl[index];\r
192         for (i=0; i<planesize; i++)\r
193         {\r
194                 *dest++ = *source++ << 1;\r
195         }\r
196 \r
197         //\r
198         // pic in original format is no longer needed\r
199         //\r
200         MM_FreePtr(&grsegs[chunk]);\r
201 }\r
202 \r
203 /*\r
204 ============================\r
205 =\r
206 = DrawPlaque\r
207 =\r
208 ============================\r
209 */\r
210 \r
211 void DrawPlaque(Sint16 elapsed, Uint16 x)\r
212 {\r
213         Uint16 shift, xb;\r
214         Sint16 y, bottom, oldbottom;\r
215         Uint16 eraseheight, skip, screenoff;\r
216 \r
217         shift = x & 7;\r
218         xb = (pageofs + (x / 8)) + (20 - (plaquewidth >> 1));\r
219 \r
220         EGAMAPMASK(12); // write to "red" and "intensity" plane (for erasing old pic)\r
221 \r
222         //\r
223         // update position (and pic number)\r
224         //\r
225         y = LocatePlaque(elapsed);\r
226 \r
227         //\r
228         // erase leftovers of the previous frame\r
229         //\r
230         bottom = y + plaqueheight;\r
231         if (bottom < 0)\r
232                 bottom = 0;\r
233         oldbottom = prevbottom[pageon];\r
234         if (bottom < 200 && oldbottom > bottom)\r
235         {\r
236                 eraseheight = oldbottom - bottom;\r
237                 screenoff = xb + ylookup[bottom];\r
238                 asm {\r
239                         mov     es, screenseg;\r
240                         mov     bx, linewidth;\r
241                         sub     bx, plaquewidthwords;\r
242                         sub     bx, plaquewidthwords;\r
243                         mov     di, screenoff;\r
244                         mov     dx, eraseheight;\r
245                         mov     si, plaquewidthwords;\r
246                         xor     ax, ax;\r
247                 }\r
248 eraseloop:\r
249                 asm {\r
250                         mov     cx, si;\r
251                         rep stosw;\r
252                         add     di, bx;\r
253                         dec     dx;\r
254                         jnz     eraseloop;\r
255                 }\r
256         }\r
257         if (bottom > 200)\r
258                 bottom = 200;\r
259         prevbottom[pageon] = bottom;\r
260 \r
261         //\r
262         // draw the (new) pic at the new position\r
263         //\r
264         drawheight = plaqueheight;\r
265         skip = 0;\r
266         if (y < 0)\r
267         {\r
268                 skip = -y * (plaquewidth << 1);\r
269                 drawheight += y;\r
270                 y = 0;\r
271         }\r
272         else if (y + plaqueheight > 200)\r
273         {\r
274                 drawheight = 200 - y;\r
275         }\r
276         source2 = skip + plaqueplane;\r
277         if (drawheight > 0)\r
278         {\r
279                 shiftptr = shifttabletable[shift];\r
280                 t_dest = xb + ylookup[y];\r
281                 asm {\r
282                         mov     bx, skip;\r
283                         push    bp;\r
284                         mov     bp, shiftptr;\r
285                         mov     es, screenseg;\r
286                         mov     ds, plaqueseg;\r
287                         mov     ah, 4;\r
288                         mov     BYTE PTR ss:planeon, ah;\r
289                 }\r
290 planeloop:\r
291                 asm {\r
292                         mov     dx, SC_INDEX;\r
293                         mov     al, SC_MAPMASK;\r
294                         out     dx, ax;\r
295                         mov     dx, ss:drawheight;\r
296                         mov     di, ss:t_dest;\r
297                 }\r
298 yloop:\r
299                 asm {\r
300                         mov     cx, ss:plaquewidth;\r
301                         xor     al, al;\r
302                 }\r
303 xloop:\r
304                 asm {\r
305                         mov     si, [bx];\r
306                         add     bx, 2;\r
307                         xor     ah, ah;\r
308                         or      ax, [bp+si];\r
309                         stosb;\r
310                         mov     al, ah;\r
311                         loop    xloop;\r
312                         stosb;\r
313                         mov     WORD PTR es:[di], 0;\r
314                         add     di, ss:plaquedelta;\r
315                         dec     dx;\r
316                         jnz     yloop;\r
317                         mov     bx, ss:source2;\r
318                         mov     ah, BYTE PTR ss:planeon;\r
319                         shl     ah, 1;\r
320                         mov     BYTE PTR ss:planeon, ah;\r
321                         cmp     ah, 16;\r
322                         jnz     planeloop;\r
323                         pop     bp;\r
324                         mov     ax, ss;\r
325                         mov     ds, ax;\r
326                 }\r
327         }\r
328 }\r
329 \r
330 /*\r
331 ============================\r
332 =\r
333 = LocatePlaque\r
334 =\r
335 ============================\r
336 */\r
337 \r
338 Sint16 LocatePlaque(Sint16 elapsed)\r
339 {\r
340         switch (plaquephase)\r
341         {\r
342         case -1:\r
343                 //\r
344                 // pic starts to appear\r
345                 //\r
346                 plaqueseg = basepl[plaque];\r
347                 plaquewidth = baseplwidth[plaque];\r
348                 plaquewidthwords = (plaquewidth + 3) >> 1;\r
349                 plaqueheight = baseplheight[plaque];\r
350                 plaquedelta = linewidth - (plaquewidth + 1);\r
351                 plaqueplane = (plaquewidth * plaqueheight) << 1;\r
352                 plaquephase++;\r
353                 lastframe = elapsed;\r
354                 plaquey = 240;\r
355                 // no break or return here!\r
356         case 0:\r
357                 //\r
358                 // pic is moving from the bottom to the center of the screen\r
359                 //\r
360                 plaquey -= (elapsed - lastframe) << 1;\r
361                 if (plaquey < 100)\r
362                 {\r
363                         plaquey = 100;\r
364                         plaquephase++;\r
365                 }\r
366                 lastframe = elapsed;\r
367                 return plaquey - (plaqueheight >> 1);\r
368 \r
369         case 1:\r
370                 //\r
371                 // pic is staying at the center position\r
372                 //\r
373                 if (elapsed - lastframe > 200)\r
374                 {\r
375                         plaquephase++;\r
376                         lastframe = elapsed;\r
377                 }\r
378                 return 100 - (plaqueheight >> 1);\r
379 \r
380         case 2:\r
381                 //\r
382                 // pic is moving up from the center to the top of the screen\r
383                 //\r
384                 plaquey -= (elapsed - lastframe) << 1;\r
385                 if (plaquey < -40)\r
386                 {\r
387                         plaquey = -40;\r
388                         if (++plaque < 4)\r
389                         {\r
390                                 plaquephase = -1;\r
391                         }\r
392                         else\r
393                         {\r
394                                 plaquephase = 3;\r
395                         }\r
396                 }\r
397                 lastframe = elapsed;\r
398                 return plaquey - (plaqueheight >> 1);\r
399         }\r
400 \r
401         return -40;\r
402 }\r
403 \r
404 /*\r
405 ============================\r
406 =\r
407 = SlideLetters\r
408 =\r
409 ============================\r
410 */\r
411 \r
412 void SlideLetters(void)\r
413 {\r
414         Sint16 x, cPosX, screenxb;\r
415         Uint16 elapsed, totaltics, dstofs;\r
416         Sint16 cStart, cEnd, cTotalMove;\r
417         Uint16 shift, srcseg, srcofs;\r
418         Sint16 clearleft, copywidth, clearright;\r
419         Uint16 srcdif, dstdif;\r
420         Sint32 now;\r
421 \r
422         //\r
423         // set up characteristics of the animation\r
424         //\r
425         EGAWRITEMODE(0);\r
426         EGAREADMAP(0);  // useless...\r
427 \r
428         keenstart = keen->width + 200;\r
429         EGAREADMAP(1);  // also useless ... I think...\r
430 \r
431         cEnd = 120 - commander->width;\r
432         cStart = 320;\r
433         cTotalMove = cEnd - cStart;\r
434         totaltics = abs(cTotalMove);\r
435 \r
436         pageofs = pageon = 0;\r
437         lasttimecount = TimeCount;\r
438         while (TimeCount == lasttimecount);\r
439         lasttimecount = TimeCount;\r
440 \r
441         for (elapsed=0; elapsed <= totaltics; elapsed += tics)\r
442         {\r
443                 //\r
444                 // draw the credits pic\r
445                 //\r
446                 x = ((Sint32)keenstart * (Sint32)(totaltics-elapsed)) / (Sint32)totaltics;\r
447                 DrawPlaque(elapsed, x);\r
448 \r
449                 //\r
450                 // get ready to draw draw the "COMMANDER" pic\r
451                 //\r
452                 cPosX = cStart + ((Sint32)cTotalMove * (Sint32)elapsed) / (Sint32)totaltics;\r
453                 cPosX += x & 7;\r
454                 screenxb = (cPosX + 0x800) / 8 + -0x100;\r
455                 shift = (cPosX + 0x800) & 7;\r
456                 srcseg = FP_SEG(cmdrshifts[shift]);\r
457                 srcofs = 0;\r
458                 dstofs = pageofs + x / 8;\r
459                 if (screenxb > 0)\r
460                 {\r
461                         clearleft = (screenxb + 1) / 2;\r
462                         if (screenxb & 1)\r
463                                 dstofs--;\r
464                         copywidth = 21 - clearleft;\r
465                         clearright = 0;\r
466                 }\r
467                 else if (-commanderbwide + 40 < screenxb)\r
468                 {\r
469                         clearleft = 0;\r
470                         copywidth = 21;\r
471                         clearright = 0;\r
472                         srcofs -= screenxb;\r
473                 }\r
474                 else\r
475                 {\r
476                         clearleft = 0;\r
477                         copywidth = (commanderbwide + screenxb) / 2;\r
478                         clearright = 21 - copywidth;\r
479                         srcofs -= screenxb;\r
480                 }\r
481                 srcdif = commanderbwide - copywidth*2;\r
482                 dstdif = 248 - (clearleft + copywidth + clearright)*2;\r
483 \r
484                 //\r
485                 // draw "COMMANDER" pic\r
486                 //\r
487                 EGAMAPMASK(2);\r
488 \r
489                 asm {\r
490                         mov     di, dstofs;\r
491                         mov     es, screenseg;\r
492                         mov     si, srcofs;\r
493                         mov     lastsource, si;\r
494                         mov     ds, srcseg;\r
495                         mov     dx, 200;\r
496                 }\r
497 yloop:\r
498                 asm {\r
499                         xor     ax, ax;\r
500                         mov     cx, clearleft;\r
501                         rep stosw;\r
502                         mov     cx, copywidth;\r
503                         rep movsw;\r
504                         xor     ax, ax;\r
505                         mov     cx, clearright;\r
506                         rep stosw;\r
507                         test    dx, 1;\r
508                         jnz     oddline;\r
509                         mov     si, ss:lastsource;\r
510                         jmp     nextline;\r
511                 }\r
512 oddline:\r
513                 asm {\r
514                         add     si, srcdif;\r
515                         mov     ss:lastsource, si;\r
516                 }\r
517 nextline:\r
518                 asm {\r
519                         add     di, dstdif;\r
520                         dec     dx;\r
521                         jnz     yloop;\r
522                         mov     ax, ss;\r
523                         mov     ds, ax;\r
524                 }\r
525 \r
526                 //\r
527                 // page flip\r
528                 //\r
529                 VW_SetScreen(pageofs + x / 8, x & 7);\r
530                 pageon ^= 1;\r
531                 if (pageon)\r
532                 {\r
533                         pageofs = 124;\r
534                 }\r
535                 else\r
536                 {\r
537                         pageofs = 0;\r
538                 }\r
539 \r
540                 //\r
541                 // handle timing\r
542                 //\r
543                 do\r
544                 {\r
545                         now = TimeCount;\r
546                         tics = now - lasttimecount;\r
547                 } while (tics < 2);\r
548                 lasttimecount = now;\r
549 \r
550                 //\r
551                 // handle input\r
552                 //\r
553                 if (IN_IsUserInput() && LastScan != sc_F1)\r
554                 {\r
555                         LastScan = sc_Space;\r
556                 }\r
557                 if (LastScan)\r
558                         return;\r
559         }\r
560 \r
561         byteadjust = x / 8;\r
562 }\r
563 \r
564 /*\r
565 ============================\r
566 =\r
567 = DrawScan\r
568 =\r
569 ============================\r
570 */\r
571 \r
572 void DrawScan(Sint16 far *source, Uint8 far *dest)\r
573 {\r
574         register Uint16 x;\r
575         register Sint16 w;\r
576         register Uint16 val;\r
577         register Uint16 i;\r
578 \r
579         val = x = 0;\r
580         for (;;)\r
581         {\r
582                 //\r
583                 // first part: puts black pixels (<width> pixels wide)\r
584                 //\r
585                 w = *source++;\r
586                 if (w == -1)\r
587                 {\r
588                         *dest++ = val;\r
589                         *dest = 0;\r
590                         return;\r
591                 }\r
592 \r
593                 x += w;\r
594                 if (x > 7)\r
595                 {\r
596                         *dest++ = val;\r
597                         val = 0;\r
598                         i = (x / 8) - 1;\r
599                         while (i--)\r
600                         {\r
601                                 *dest++ = 0;\r
602                         }\r
603                         x &= 7;\r
604                 }\r
605 \r
606                 //\r
607                 // second part: puts white pixels (<width> pixels wide)\r
608                 //\r
609                 w = *source++;\r
610                 if (w == -1)\r
611                 {\r
612                         *dest++ = val;\r
613                         *dest = 0;\r
614                         return;\r
615                 }\r
616 \r
617                 val |= ortoend[x];\r
618                 x += w;\r
619                 if (x > 7)\r
620                 {\r
621                         *dest++ = val;\r
622                         val = 0xFF;\r
623                         i = (x / 8) - 1;\r
624                         while (i--)\r
625                         {\r
626                                 *dest++ = 0xFF;\r
627                         }\r
628                         x &= 7;\r
629                 }\r
630                 val &= andtoend[x];\r
631         }\r
632 }\r
633 \r
634 /*\r
635 ============================\r
636 =\r
637 = BuildScaleShape\r
638 =\r
639 ============================\r
640 */\r
641 \r
642 void BuildScaleShape(void)\r
643 {\r
644         Sint16 px, w;\r
645         Sint16 far *source;\r
646         Sint16 far *dest;\r
647         Sint16 y;\r
648 \r
649         MM_GetPtr((memptr*)&both, 30000);\r
650         dest = MK_FP(FP_SEG(both), sizeof(shapehead));\r
651 \r
652         for (y=0; y<200; y++)\r
653         {\r
654                 both->rowofs[y] = FP_OFF(dest);\r
655                 px = 0;\r
656 \r
657                 EGAREADMAP(1);  // this is pretty useless, we're not reading from EGA memory here\r
658 \r
659                 source = (Sint16 far *)((byte _seg *)commander + commander->rowofs[y]);\r
660                 w = *source++;\r
661                 do\r
662                 {\r
663                         *dest++ = px;\r
664                         px = px + w;\r
665                         w = *source++;\r
666                 } while (w != -1);\r
667 \r
668                 //\r
669                 // insert an 80 pixel gap between "COMMANDER" and "KEEN"\r
670                 //\r
671                 // This assumes that the rightmost column(s) of the "COMMANDER"\r
672                 // shape are black. Otherwise the gap would be filled with\r
673                 // white pixels and the "KEEN" image would use inverted colors\r
674                 // as a result.\r
675                 //\r
676                 px += 80;\r
677 \r
678                 EGAREADMAP(0);  // this is pretty useless, we're not reading from EGA memory here\r
679 \r
680                 source = (Sint16 far *)((byte _seg *)keen + keen->rowofs[y]);\r
681                 source++;       // kludgy bit, causes errors when left egde of "KEEN" is no rectangle\r
682                 w = *source++;\r
683                 do\r
684                 {\r
685                         *dest++ = px;\r
686                         px = px + w;\r
687                         w = *source++;\r
688                 } while (w != -1);\r
689 \r
690                 *dest++ = px;   // put last value\r
691                 *dest++ = -1;   // put end-of-line\r
692         }\r
693 }\r
694 \r
695 /*\r
696 ============================\r
697 =\r
698 = ScalePointScan\r
699 =\r
700 ============================\r
701 */\r
702 \r
703 void ScalePointScan(Sint16 far *rowptr, Sint16 y, Sint16 toleft, Sint16 far *scaletable)\r
704 {\r
705         Uint8 far *dest;\r
706         Sint16 left, endx;\r
707         Uint16 w, val, x, right;\r
708         register Sint16 px, sx;\r
709 \r
710         val = x = 0;\r
711         endx = 320 - toleft;\r
712         dest = MK_FP(0xA000, pageofs + byteadjust + ylookup[y]);\r
713 \r
714         if (toleft < 0)\r
715         {\r
716                 left = -toleft;\r
717                 val = 0;\r
718                 x = 0;\r
719 \r
720                 for (;;)\r
721                 {\r
722                         px = *rowptr++;\r
723                         sx = scaletable[px];\r
724                         if (sx > left)\r
725                                 goto drawwhite;\r
726 \r
727                         px = *rowptr++;\r
728                         sx = scaletable[px];\r
729                         if (sx > left)\r
730                                 goto drawblack;\r
731                 }\r
732         }\r
733 \r
734         //\r
735         // regular\r
736         //\r
737         val = 0;\r
738         x = toleft & 7;\r
739         dest += (toleft >> 3);\r
740         left = 0;\r
741         rowptr++;       // the first value is always 0, we need the next value\r
742 drawloop:\r
743         px = *rowptr++;\r
744         sx = scaletable[px];\r
745 \r
746         //\r
747         // draw/add black pixels\r
748         //\r
749 drawblack:\r
750         w = sx - left;\r
751         left = sx;\r
752         x += w;\r
753         if (x > 7)\r
754         {\r
755                 asm {\r
756                         les     di, dest;\r
757                         mov     al, BYTE PTR val;\r
758                         stosb;\r
759                         mov     cx, x;\r
760                         shr     cx, 1;\r
761                         shr     cx, 1;\r
762                         shr     cx, 1;\r
763                         dec     cx;\r
764                         xor     al, al;\r
765                         mov     BYTE PTR val, al;\r
766                         rep stosb;\r
767                         and     x, 7;\r
768                         mov     WORD PTR dest, di;\r
769                 }\r
770         }\r
771 \r
772         //\r
773         // stop if the right side of the screen is reached\r
774         //\r
775         if (sx > endx)\r
776                 return;\r
777 \r
778         //\r
779         // stop if the end of the image row is reached\r
780         // \r
781         // This is only checked after drawing the black part, so the\r
782         // combined shape must not end with white pixels on the right.\r
783         // That means the rightmost column(s) of the "KEEN" shape must\r
784         // always be black.\r
785         //\r
786         px = *rowptr++;\r
787         if (px == -1)\r
788                 goto clearright;\r
789 \r
790         sx = scaletable[px];\r
791 \r
792         //\r
793         // draw/add white pixels\r
794         //\r
795 drawwhite:\r
796         w = sx - left;\r
797         left = sx;\r
798         val |= ortoend[x];\r
799         x += w;\r
800         if (x > 7)\r
801         {\r
802                 asm {\r
803                         les     di, dest;\r
804                         mov     al, BYTE PTR val;\r
805                         stosb;\r
806                         mov     cx, x;\r
807                         shr     cx, 1;\r
808                         shr     cx, 1;\r
809                         shr     cx, 1;\r
810                         dec     cx;\r
811                         mov     al, 255;\r
812                         mov     BYTE PTR val, al;\r
813                         rep stosb;\r
814                         and     x, 7;\r
815                         mov     WORD PTR dest, di;\r
816                 }\r
817         }\r
818 \r
819         //\r
820         // stop if the right side of the screen is reached\r
821         //\r
822         if (sx > endx)\r
823                 return;\r
824 \r
825         val &= andtoend[x];\r
826         goto drawloop;\r
827 \r
828         //\r
829         // clear the right side of the screen\r
830         //\r
831 clearright:\r
832         w = 320 - left;\r
833         x += w;\r
834         if (x > 7)\r
835         {\r
836                 *dest++ = val;\r
837                 val = 0;\r
838                 right = x / 8 - 1;\r
839                 while (right--)\r
840                 {\r
841                         *dest++ = 0;\r
842                 }\r
843                 x &= 7;\r
844                 return;\r
845         }\r
846         return;\r
847 }\r
848 \r
849 /*\r
850 ============================\r
851 =\r
852 = ScaleDown\r
853 =\r
854 ============================\r
855 */\r
856 \r
857 void ScaleDown(void)\r
858 {\r
859         Uint16 i;\r
860         Uint16 toleft, ticselapsed, ticstotal, scale, endscale, rownum, rowinc;\r
861         Sint32 now;\r
862         Sint16 far *rowptr;\r
863         Uint16 scaleheight, top, bottom, lastbottom[2];\r
864         Sint32 leftorigin;\r
865 \r
866         //\r
867         // set our new palette\r
868         //\r
869         SetPalette(termcolors2);\r
870 \r
871         EGAREADMAP(1);  // this is pretty useless, we're not reading from EGA memory here\r
872 \r
873         leftorigin = 120l - commander->width;\r
874         BuildScaleShape();\r
875         MM_GetPtr(&scaletable, 2500*sizeof(Uint16));\r
876 \r
877         scale = 0x100;          // 100%\r
878         endscale = 0x21;        // 13% (scale from 200px to 26px)\r
879         endscale = 0x21;        // redundant\r
880         lastbottom[0] = lastbottom[1] = 200;\r
881         ticselapsed = 1;\r
882         ticstotal = 30; // time for the whole shrinking animation\r
883 \r
884         while (ticselapsed <= ticstotal)\r
885         {\r
886                 //\r
887                 // get current scaling\r
888                 //\r
889                 if (ticselapsed == ticstotal)\r
890                 {\r
891                         scale = endscale;\r
892                         toleft = 0;\r
893                         top = 4;\r
894                 }\r
895                 else\r
896                 {\r
897                         scale = 0x100 - ((0x100-endscale) * ticselapsed) / ticstotal;\r
898                         toleft = (leftorigin * (ticstotal - ticselapsed)) / ticstotal;\r
899                         top = (ticselapsed * 4) / ticstotal;\r
900                 }\r
901 \r
902                 //\r
903                 // build scale table:           scaletable[i] = (i*scale) / 0x100;\r
904                 //\r
905                 asm {\r
906                         xor     ax, ax;\r
907                         xor     dx, dx;\r
908                         mov     cx, 2500;\r
909                         mov     bx, scale;\r
910                         mov     es, scaletable;\r
911                         xor     di, di;\r
912                 }\r
913 l1:\r
914                 asm {\r
915                         mov     es:[di], ah;\r
916                         inc     di;\r
917                         mov     es:[di], dl;\r
918                         inc     di;\r
919                         add     ax, bx;\r
920                         adc     dx, 0;\r
921                         loop    l1;\r
922                 }\r
923 \r
924                 //\r
925                 // wait... didn't we already do this?\r
926                 //\r
927                 if (ticselapsed == ticstotal)\r
928                 {\r
929                         toleft = 0;\r
930                 }\r
931                 else\r
932                 {\r
933                         toleft = (leftorigin * (ticstotal - ticselapsed)) / ticstotal;\r
934                 }\r
935 \r
936                 //\r
937                 // prepare scaled drawing process\r
938                 //\r
939                 scaleheight = ((Sint16 _seg *)scaletable)[200];\r
940                 rownum = 0;\r
941                 rowinc = 0x10000l / scale;\r
942                 bufferofs = pageofs + byteadjust;\r
943 \r
944                 //\r
945                 // erase stuff at the top\r
946                 //\r
947                 if (top > 0)\r
948                 {\r
949                         VW_Bar(0, 0, 320, top, BLACK);\r
950                 }\r
951 \r
952                 //\r
953                 // draw the scaled shape\r
954                 //\r
955                 EGAWRITEMODE(0);\r
956                 EGAMAPMASK(15);\r
957 \r
958                 for (i=0; i<scaleheight; i++)\r
959                 {\r
960                         rowptr = (Sint16 far *)((byte _seg *)both + both->rowofs[rownum >> 8]);\r
961                         ScalePointScan(rowptr, i+top, toleft, scaletable);\r
962 \r
963                         rownum += rowinc;\r
964                 }\r
965 \r
966                 //\r
967                 // erase leftovers at the bottom of the screen\r
968                 //\r
969                 bufferofs = pageofs + byteadjust;\r
970                 bottom = scaleheight + top;\r
971                 if (lastbottom[pageon] > bottom)\r
972                 {\r
973                         VW_Bar(0, bottom, 320, lastbottom[pageon] - bottom, BLACK);\r
974                         lastbottom[pageon] = bottom;\r
975                 }\r
976 \r
977                 //\r
978                 // page flip\r
979                 //\r
980                 VW_SetScreen(pageofs+byteadjust, 0);\r
981                 pageon ^= 1;\r
982                 if (pageon)\r
983                 {\r
984                         pageofs = 124;\r
985                 }\r
986                 else\r
987                 {\r
988                         pageofs = 0;\r
989                 }\r
990 \r
991                 //\r
992                 // handle timing\r
993                 //\r
994                 now = TimeCount;\r
995                 tics = now - lasttimecount;\r
996                 lasttimecount = now;\r
997                 if (tics > 8)\r
998                         tics = 8;       // don't skip too many frames on slow systems\r
999 \r
1000                 if (ticselapsed == ticstotal)\r
1001                         break;\r
1002 \r
1003                 ticselapsed += tics;\r
1004                 if (ticselapsed > ticstotal)\r
1005                         ticselapsed = ticstotal;\r
1006 \r
1007                 //\r
1008                 // handle input\r
1009                 //\r
1010                 if (IN_IsUserInput() && LastScan != sc_F1)\r
1011                 {\r
1012                         LastScan = sc_Space;\r
1013                 }\r
1014                 if (LastScan)\r
1015                         return; // BUG: buffers aren't freed!\r
1016         }\r
1017 \r
1018         //\r
1019         // free the buffers\r
1020         //\r
1021         MM_FreePtr(&scaletable);\r
1022         MM_FreePtr((memptr*)&both);\r
1023 }\r
1024 \r
1025 /*\r
1026 ============================\r
1027 =\r
1028 = FinishPage\r
1029 =\r
1030 ============================\r
1031 */\r
1032 \r
1033 void FinishPage(void)\r
1034 {\r
1035         Sint16 swap, temp, i, n, x, y;\r
1036         Uint16 ofs;\r
1037         Sint16 top, bottom, delta;\r
1038         Uint8 bitmask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};\r
1039         Sint16 xtable[320], ytable[200];\r
1040 \r
1041         //\r
1042         // build lookup tables\r
1043         //\r
1044         for (i=0; i<320; i++)\r
1045         {\r
1046                 xtable[i] = i;\r
1047         }\r
1048         for (i=0; i<320; i++)\r
1049         {\r
1050                 swap = random(320);\r
1051                 temp = xtable[swap];\r
1052                 xtable[swap] = xtable[i];\r
1053                 xtable[i] = temp;\r
1054         }\r
1055         for (i=0; i<200; i++)\r
1056         {\r
1057                 ytable[i] = xtable[i];\r
1058         }\r
1059 \r
1060         //\r
1061         // set up display\r
1062         //\r
1063         VW_SetDefaultColors();\r
1064         if (pageon)\r
1065         {\r
1066                 bufferofs = byteadjust + 124;\r
1067                 displayofs = byteadjust;\r
1068         }\r
1069         else\r
1070         {\r
1071                 bufferofs = byteadjust;\r
1072                 displayofs = byteadjust + 124;\r
1073         }\r
1074         VW_SetScreen(displayofs, 0);\r
1075 \r
1076         //\r
1077         // draw title pic to the non-displayed buffer\r
1078         //\r
1079         VW_DrawPic(0, 0, TITLEPICPIC);\r
1080 \r
1081         //\r
1082         // copy "random" pixels from the non-displayed area\r
1083         // into the displayed area to create the "fizzle" effect\r
1084         //\r
1085         delta = displayofs - bufferofs;\r
1086 \r
1087         //\r
1088         // set ES register for the pixel copying code in the loops\r
1089         //\r
1090         // This is faster than setting the ES register in the loops,\r
1091         // but you need to make sure nothing in the loops overwrites\r
1092         // the ES register, otherwise the code won't work correctly.\r
1093         //\r
1094         asm     mov     es, screenseg;\r
1095 \r
1096         for (i = 0; i< 360; i++)\r
1097         {\r
1098                 top = i - 160;\r
1099                 if (top < 0)\r
1100                         top = 0;\r
1101 \r
1102                 bottom = i;\r
1103                 if (bottom >= 200)\r
1104                         bottom = 199;\r
1105 \r
1106                 for (y = top; y <= bottom; y++)\r
1107                 {\r
1108                         ofs = bufferofs + ylookup[y];\r
1109                         for (n=0; n<2; n++)\r
1110                         {\r
1111                                 x = xtable[ytable[y]];\r
1112                                 if (++ytable[y] == 320)\r
1113                                 {\r
1114                                         ytable[y] = 0;\r
1115                                 }\r
1116 \r
1117                                 //\r
1118                                 // set bitmask for our x value\r
1119                                 //\r
1120                                 asm     mov     cx, x;\r
1121                                 asm     mov     si, cx;\r
1122                                 asm     and     si, 7;\r
1123                                 asm     cli;\r
1124                                 asm     mov     dx, GC_INDEX;\r
1125                                 asm     mov     al, GC_BITMASK;\r
1126                                 asm     mov     ah, BYTE PTR bitmask[si];\r
1127                                 asm     out     dx, ax;\r
1128                                 asm     sti;\r
1129 \r
1130                                 //\r
1131                                 // set up source and dest index registers\r
1132                                 //\r
1133                                 asm     mov     si, ofs;\r
1134                                 asm     shr     cx, 1;\r
1135                                 asm     shr     cx, 1;\r
1136                                 asm     shr     cx, 1;\r
1137                                 asm     add     si, cx;\r
1138                                 asm     mov     di, si;\r
1139                                 asm     add     di, delta;\r
1140 \r
1141                                 //\r
1142                                 // copy the pixel data (all 4 planes)\r
1143                                 //\r
1144                                 // "blue" plane:\r
1145                                 asm     mov     dx, SC_INDEX;\r
1146                                 asm     mov     ax, SC_MAPMASK + 1*256;\r
1147                                 asm     out     dx, ax;\r
1148                                 asm     mov     dx, GC_INDEX;\r
1149                                 asm     mov     ax, GC_READMAP + 0*256;\r
1150                                 asm     out     dx, ax;\r
1151                                 asm     mov     bl, es:[si];\r
1152                                 asm     xchg    bl, es:[di];\r
1153                                 // "green" plane:\r
1154                                 asm     mov     dx, SC_INDEX;\r
1155                                 asm     mov     ax, SC_MAPMASK + 2*256;\r
1156                                 asm     out     dx, ax;\r
1157                                 asm     mov     dx, GC_INDEX;\r
1158                                 asm     mov     ax, GC_READMAP + 1*256;\r
1159                                 asm     out     dx, ax;\r
1160                                 asm     mov     bl, es:[si];\r
1161                                 asm     xchg    bl, es:[di];\r
1162                                 // "red" plane:\r
1163                                 asm     mov     dx, SC_INDEX;\r
1164                                 asm     mov     ax, SC_MAPMASK + 4*256;\r
1165                                 asm     out     dx, ax;\r
1166                                 asm     mov     dx, GC_INDEX;\r
1167                                 asm     mov     ax, GC_READMAP + 2*256;\r
1168                                 asm     out     dx, ax;\r
1169                                 asm     mov     bl, es:[si];\r
1170                                 asm     xchg    bl, es:[di];\r
1171                                 // "intensity" plane:\r
1172                                 asm     mov     dx, SC_INDEX;\r
1173                                 asm     mov     ax, SC_MAPMASK + 8*256;\r
1174                                 asm     out     dx, ax;\r
1175                                 asm     mov     dx, GC_INDEX;\r
1176                                 asm     mov     ax, GC_READMAP + 3*256;\r
1177                                 asm     out     dx, ax;\r
1178                                 asm     mov     bl, es:[si];\r
1179                                 asm     xchg    bl, es:[di];\r
1180                         }\r
1181                 }\r
1182 \r
1183                 VW_WaitVBL(1);  // so the fizzle animation won't go super fast\r
1184 \r
1185                 if (IN_IsUserInput() && LastScan != sc_F1)\r
1186                 {\r
1187                         LastScan = sc_Space;\r
1188                 }\r
1189                 if (LastScan)\r
1190                 {\r
1191                         EGABITMASK(0xFF);\r
1192                         EGAMAPMASK(15);\r
1193                         return;\r
1194                 }\r
1195         }\r
1196 \r
1197         //\r
1198         // clean up EGA registers\r
1199         //\r
1200         EGABITMASK(0xFF);\r
1201         EGAMAPMASK(15);\r
1202 \r
1203         //\r
1204         // pause for 6 seconds\r
1205         //\r
1206         IN_UserInput(6 * TickBase, false);\r
1207 }\r
1208 \r
1209 /*\r
1210 ============================\r
1211 =\r
1212 = Terminator\r
1213 =\r
1214 ============================\r
1215 */\r
1216 \r
1217 void Terminator(void)\r
1218 {\r
1219         Uint16 i, shift, bufsize;\r
1220         Sint16 far *source;\r
1221         Uint8 far *dest;\r
1222         Uint16 srcseg, destseg;\r
1223         boolean pagefinished;\r
1224         Uint16 rowofs[200];\r
1225 \r
1226         pagefinished = false;\r
1227         CA_SetAllPurge();\r
1228         SetPaletteEx(colors[0]);        // all black\r
1229         VW_ClearVideo(BLACK);\r
1230         VW_SetLineWidth(248);   // 1984 pixels total, we're using 992 per "page"\r
1231 \r
1232         CA_CacheGrChunk(TITLEPICPIC);\r
1233         CA_CacheGrChunk(BIGCOMMANDER);\r
1234         CA_CacheGrChunk(BIGKEEN);\r
1235         keen = grsegs[BIGKEEN];\r
1236         commander = grsegs[BIGCOMMANDER];\r
1237 \r
1238         EGAMAPMASK(1);\r
1239 \r
1240         keenstart = keen->width + 200;\r
1241         VW_SetScreen((keenstart/8)+1, 0);\r
1242 \r
1243         //\r
1244         // draw the "KEEN" pic (to first "page")\r
1245         //\r
1246         for (i=0; i<200; i++)\r
1247         {\r
1248                 source = (Sint16 far *)((byte _seg *)keen + keen->rowofs[i]);\r
1249                 dest = MK_FP(0xA000, ylookup[i]);\r
1250                 dest += 25;     // 25 bytes -> 200 pixels\r
1251                 DrawScan(source, dest);\r
1252         }\r
1253         //\r
1254         // copy pic from first "page" to second "page"\r
1255         //\r
1256         VW_ScreenToScreen(0, 124, 109, 200);\r
1257 \r
1258         //\r
1259         // create pre-shifted image buffers for the "COMMANDER" pic\r
1260         // (only 100 pixels high instead of 200 pixels to save memory)\r
1261         //\r
1262         commanderbwide = (commander->width + 7) / 8;\r
1263         commanderbwide = (commanderbwide + 3) & ~1;\r
1264         bufsize = commanderbwide * 100; // half height\r
1265         for (shift = 0; shift < 8; shift++)\r
1266         {\r
1267                 MM_GetPtr(&cmdrshifts[shift], bufsize);\r
1268         }\r
1269 \r
1270         //\r
1271         // re-assign shape pointers (memory manager might have moved the buffers)\r
1272         //\r
1273         keen = grsegs[BIGKEEN];\r
1274         commander = grsegs[BIGCOMMANDER];\r
1275 \r
1276         //\r
1277         // draw the first (unshifted) version of the "COMMANDER" pic to the buffer\r
1278         //\r
1279         for (i=0; i<100; i++)\r
1280         {\r
1281                 rowofs[i*2] = rowofs[i*2+1] = i * commanderbwide;\r
1282                 source = (Sint16 far *)((byte _seg *)commander + commander->rowofs[i*2]);\r
1283                 dest = (Uint8 _seg *)cmdrshifts[0] + rowofs[i*2];\r
1284                 DrawScan(source, dest);\r
1285         }\r
1286 \r
1287         //\r
1288         // create the shifted versions of the "COMMANDER" pic\r
1289         //\r
1290         for (shift = 1; shift < 8; shift++)\r
1291         {\r
1292                 srcseg = FP_SEG(cmdrshifts[shift-1]);\r
1293                 destseg = FP_SEG(cmdrshifts[shift]);\r
1294                 asm {\r
1295                         mov     ds, srcseg;\r
1296                         mov     es, destseg;\r
1297                         mov     cx, bufsize;\r
1298                         clc;\r
1299                         xor     si, si;\r
1300                         xor     di, di;\r
1301                 }\r
1302 l1:\r
1303                 asm {\r
1304                         lodsb;\r
1305                         rcr     al, 1;\r
1306                         stosb;\r
1307                         loop    l1;\r
1308                         mov     ax, ss;\r
1309                         mov     ds, ax;\r
1310                 }\r
1311         }\r
1312 \r
1313         //\r
1314         // prepare (and set) the palettes\r
1315         //\r
1316         termcolors[16] = termcolors2[16] = termcolors[16] = bordercolor;\r
1317         SetPalette(termcolors);\r
1318 \r
1319         //\r
1320         // cache the credits pics (they are converted into a special\r
1321         // format to make shifted drawing easier during the animation)\r
1322         //\r
1323         for (i=0; i<4; i++)\r
1324         {\r
1325                 LoadPlaque(i);\r
1326         }\r
1327 \r
1328         //\r
1329         // play the animation\r
1330         //\r
1331         plaque = lastframe = 0;\r
1332         plaquephase = -1;\r
1333         SlideLetters();\r
1334 \r
1335         //\r
1336         // free some of the buffers\r
1337         // (shrink animation needs additional memory)\r
1338         //\r
1339         for (i=0; i<4; i++)\r
1340         {\r
1341                 MM_FreePtr(&basepl[i]);\r
1342         }\r
1343         for (shift=0; shift<8; shift++)\r
1344         {\r
1345                 MM_FreePtr(&cmdrshifts[shift]);\r
1346         }\r
1347 \r
1348         //\r
1349         // do the shrinking and fizzle fade animations\r
1350         // (if intro wasn't aborted)\r
1351         //\r
1352         if (!LastScan)\r
1353         {\r
1354                 ScaleDown();\r
1355         }\r
1356 \r
1357         if (!LastScan)\r
1358         {\r
1359                 FinishPage();\r
1360                 pagefinished = true;\r
1361         }\r
1362 \r
1363         //\r
1364         // free the remaining buffers\r
1365         //\r
1366         MM_SetPurge(&grsegs[BIGCOMMANDER], 3);\r
1367         MM_SetPurge(&grsegs[BIGKEEN], 3);\r
1368 \r
1369         //\r
1370         // switch back to default graphics settings\r
1371         //\r
1372         VW_ClearVideo(BLACK);\r
1373         VW_SetLineWidth(SCREENWIDTH);\r
1374         VW_SetDefaultColors();\r
1375         RF_FixOfs();\r
1376         CA_ClearMarks();\r
1377 \r
1378         //\r
1379         // handle input and main menu stuff\r
1380         //\r
1381         if (LastScan == sc_None)\r
1382         {\r
1383                 return;\r
1384         }\r
1385 #ifndef KEEN6\r
1386         if (LastScan == sc_F1)\r
1387         {\r
1388                 HelpScreens();\r
1389                 return;\r
1390         }\r
1391 #endif\r
1392         if (!pagefinished)\r
1393         {\r
1394                 RF_FixOfs();    //redundant\r
1395                 CA_CacheGrChunk(TITLEPICPIC);\r
1396                 VW_DrawPic(0, 0, TITLEPICPIC);\r
1397                 VW_SetScreen(bufferofs, 0);\r
1398                 IN_Ack();\r
1399                 CA_ClearMarks();\r
1400                 if (storedemo)\r
1401                 {\r
1402                         playstate = ex_resetgame;\r
1403                         restartgame = gd_Normal;\r
1404                         IN_ClearKeysDown();\r
1405                         NewGame();\r
1406                         return;\r
1407                 }\r
1408         }\r
1409 \r
1410         US_ControlPanel();\r
1411         if (restartgame)\r
1412         {\r
1413                 playstate = ex_resetgame;\r
1414         }\r
1415         else if (loadedgame)\r
1416         {\r
1417                 playstate = ex_loadedgame;\r
1418         }\r
1419 }\r
1420 \r
1421 /*\r
1422 =============================================================================\r
1423 \r
1424                                                         STAR WARS TEXT CRAWL\r
1425 \r
1426 =============================================================================\r
1427 */\r
1428 \r
1429 /*\r
1430 ============================\r
1431 =\r
1432 = BuildBitTables\r
1433 =\r
1434 ============================\r
1435 */\r
1436 \r
1437 void BuildBitTables(void)\r
1438 {\r
1439         Uint16 bit1, bit2, i;\r
1440         Uint8 far *buffer;\r
1441 \r
1442         MM_GetPtr(&bittables, 0x4000);\r
1443         buffer = bittables;\r
1444 \r
1445         //\r
1446         // generate a lookup table that maps the bits of the "texture" (bit1)\r
1447         // to the appropriate bit for the screen position (bit2) to make the\r
1448         // scaler code faster and smaller\r
1449         //\r
1450         // table[((7-b1)*8+(7-b2))*256+i] = (i & (1 << (7-b1))) ? (1 << (7-b2)) : 0;\r
1451         //\r
1452         for (bit1 = 1; bit1 < 0x100; bit1 <<= 1)\r
1453         {\r
1454                 for (bit2 = 1; bit2 < 0x100; bit2 <<= 1)\r
1455                 {\r
1456                         for (i = 0; i < 0x100; i++, buffer++)\r
1457                         {\r
1458                                 if (i & bit1)\r
1459                                 {\r
1460                                         *buffer = bit2;\r
1461                                 }\r
1462                                 else\r
1463                                 {\r
1464                                         *buffer = 0;\r
1465                                 }\r
1466                         }\r
1467                 }\r
1468         }\r
1469 }\r
1470 \r
1471 /*\r
1472 ============================\r
1473 =\r
1474 = CompileSWUpdate\r
1475 =\r
1476 ============================\r
1477 */\r
1478 \r
1479 void CompileSWUpdate(void)\r
1480 {\r
1481         Sint16 y;\r
1482         Uint16 i, width, scalestep, step;\r
1483         Sint32 scale, rowof, xpos, size;\r
1484         void far *buffer;\r
1485         Uint8 srcoff, srcbit, bitpos;\r
1486         Uint16 destoff, srcx, left, orindex, lastoff;\r
1487 \r
1488         BuildBitTables();\r
1489         size = 190000;\r
1490         MM_GetPtr(&linecode, size);\r
1491         buffer = linecode;\r
1492         //\r
1493         // Note: You should really lock the pointer to prevent the memmory manager\r
1494         // from moving the buffer around. This code stores a bunch of pointers to\r
1495         // this memory block in the linestarts array. Those pointers will not be\r
1496         // updated when the memory manager moves the buffer around and the game\r
1497         // might end up crashing (or worse) when trying to run the "code" at the\r
1498         // memory location after the data was moved. The game starts playing music\r
1499         // after this function is done, which may or may not cause the memory\r
1500         // manager to move memory blocks around.\r
1501         //\r
1502 \r
1503         //\r
1504         // move the buffer address into ES:DI (and keep it there)\r
1505         //\r
1506         asm     mov     es, WORD PTR buffer+2;\r
1507         asm     mov     di, WORD PTR buffer;\r
1508         //\r
1509         // Since the address is kept in ES:DI, we must save and restore\r
1510         // the ES register when calling other functions (push es / pop es).\r
1511         // The Borland C compiler always saves and restores the DI register\r
1512         // when a function modifies it, so we don't need to worry about\r
1513         // that register. This is a bit of an ugly hack, but it makes this\r
1514         // code a little faster and smaller.\r
1515         //\r
1516 \r
1517         scale = 320l << 11;\r
1518         scalestep = (((Uint32)(320-40) << 11) / 200);   // roughly 1.4 pixels per step, going from 320 pixels to 40 pixels in 200 steps\r
1519         rowof = 0;\r
1520 \r
1521         for (y=199; y >= 0; y--)\r
1522         {\r
1523                 //\r
1524                 // draw a blue line for the current row\r
1525                 //\r
1526                 asm     push    es;\r
1527                 VW_Hlin(0, 320, y, BLUE);\r
1528                 asm     pop     es;\r
1529 \r
1530                 //\r
1531                 // update the buffer variable with the current (normalized) ES:DI address\r
1532                 //\r
1533                 asm     mov     WORD PTR buffer, di;\r
1534                 asm     mov     WORD PTR buffer+2, es;\r
1535 \r
1536                 //\r
1537                 // store the address in the scaler lookup table\r
1538                 //\r
1539                 linestarts[y] = buffer;\r
1540 \r
1541                 //\r
1542                 // get current scaling factors\r
1543                 //\r
1544                 width = ((Uint16)((scale/2) >> 11)) << 1;       // some trickery to make sure width is even\r
1545                 sourceline[y] = (rowof >> 11);\r
1546                 step = (336l << 11) / width;\r
1547                 xpos = 0;\r
1548                 rowof += step;\r
1549                 left = 160 - (width >> 1);\r
1550                 destoff = ylookup[y] + left / 8;\r
1551                 bitpos = left & 7;\r
1552 \r
1553                 //\r
1554                 // generate the machine code\r
1555                 //\r
1556                 //              MOV     CX, SS\r
1557                 //              MOV     SS, AX\r
1558                 //              ADD     DI, <destoff>\r
1559                 //              XOR     AL, AL\r
1560                 //\r
1561                 asm     mov     ax, 0D18Ch;\r
1562                 asm     stosw;\r
1563                 asm     mov     ax, 0D08Eh;\r
1564                 asm     stosw;\r
1565                 asm     mov     ax, 0C781h;\r
1566                 asm     stosw;\r
1567                 asm     mov     ax, destoff;\r
1568                 asm     stosw;\r
1569                 asm     mov     ax, 0C030h;\r
1570                 asm     stosw;\r
1571 \r
1572                 lastoff = -1;\r
1573                 for (i=0; i<width; i++)\r
1574                 {\r
1575                         srcx = (xpos >> 11);\r
1576                         srcoff = (srcx / 8);\r
1577                         srcbit = srcx & 7;\r
1578 \r
1579                         orindex = ((7-srcbit)*8 + 7-bitpos) << 8;\r
1580                         if (srcoff != lastoff)\r
1581                         {\r
1582                                 //\r
1583                                 //              MOV     BL, [BP + <srcoff>]\r
1584                                 //\r
1585                                 asm     mov     ax, 5E8Ah;\r
1586                                 asm     stosw;\r
1587                                 asm     mov     al, srcoff;\r
1588                                 asm     stosb;\r
1589 \r
1590                                 lastoff = srcoff;\r
1591                         }\r
1592 \r
1593                         //\r
1594                         //              OR              AL, [BX + <orindex>]\r
1595                         //\r
1596                         asm     mov     ax, 870Ah;\r
1597                         asm     stosw;\r
1598                         asm     mov     ax, orindex;\r
1599                         asm     stosw;\r
1600 \r
1601                         bitpos++;\r
1602                         if (bitpos == 8)\r
1603                         {\r
1604                                 bitpos = 0;\r
1605 \r
1606                                 //\r
1607                                 //              STOSB\r
1608                                 //              XOR     AL, AL\r
1609                                 //\r
1610                                 asm     mov     ax, 30AAh;\r
1611                                 asm     stosw;\r
1612                                 asm     mov     al, 0C0h;\r
1613                                 asm     stosb;\r
1614                         }\r
1615 \r
1616                         xpos += step;\r
1617                 }\r
1618 \r
1619                 if (bitpos)\r
1620                 {\r
1621                         //\r
1622                         //              STOSB\r
1623                         //\r
1624                         asm     mov     al, 0AAh;\r
1625                         asm     stosb;\r
1626                 }\r
1627                 //\r
1628                 // generate end of subroutine\r
1629                 //\r
1630                 //              MOV     SS, CX\r
1631                 //              RETF\r
1632                 //\r
1633                 asm     mov     ax, 0D18Eh;\r
1634                 asm     stosw;\r
1635                 asm     mov     al, 0CBh;\r
1636                 asm     stosb;\r
1637 \r
1638                 //\r
1639                 // normalize ES:DI\r
1640                 //\r
1641                 asm     mov     ax, di;\r
1642                 asm     shr     ax, 1;\r
1643                 asm     shr     ax, 1;\r
1644                 asm     shr     ax, 1;\r
1645                 asm     shr     ax, 1;\r
1646                 asm     mov     bx, es;\r
1647                 asm     add     ax, bx;\r
1648                 asm     mov     es, ax;\r
1649                 asm     and     di, 0Fh;\r
1650 \r
1651                 //\r
1652                 // update scale value for next row\r
1653                 //\r
1654                 scale -= scalestep;\r
1655 \r
1656                 //\r
1657                 // replace the blue line with the row from the background image\r
1658                 //\r
1659                 asm     push    es;\r
1660                 VW_ScreenToScreen(ylookup[y] + 0x8000, ylookup[y], 40, 1);\r
1661                 asm     pop     es;\r
1662 \r
1663                 if (LastScan)\r
1664                         return;\r
1665         }\r
1666 }\r
1667 \r
1668 /*\r
1669 ============================\r
1670 =\r
1671 = TranslateString\r
1672 =\r
1673 ============================\r
1674 */\r
1675 \r
1676 void TranslateString(char *text)\r
1677 {\r
1678         char c;\r
1679 \r
1680         while (*text)\r
1681         {\r
1682                 c = *text;\r
1683 \r
1684                 if (c >= 'A' && c <= 'Z')\r
1685                 {\r
1686                         c = c + -33;\r
1687                 }\r
1688                 else if (c >= 'a' && c <= 'z')\r
1689                 {\r
1690                         c = c + -39;\r
1691                 }\r
1692                 else if (c == '.')\r
1693                 {\r
1694                         c = 84;\r
1695                 }\r
1696                 else if (c == ',')\r
1697                 {\r
1698                         c = 85;\r
1699                 }\r
1700                 else if (c == '-')\r
1701                 {\r
1702                         c = 86;\r
1703                 }\r
1704                 else if (c == '"')\r
1705                 {\r
1706                         c = 87;\r
1707                 }\r
1708                 else if (c == ' ')\r
1709                 {\r
1710                         c = 88;\r
1711                 }\r
1712                 else if (c == '!')\r
1713                 {\r
1714                         c = 89;\r
1715                 }\r
1716                 else if (c == '\'')\r
1717                 {\r
1718                         c = 90;\r
1719                 }\r
1720                 else if (c != '\n')\r
1721                 {\r
1722                         c = 84; // any unhandled character is drawn as '.'\r
1723                 }\r
1724 \r
1725                 *text++ = c;\r
1726         }\r
1727 }\r
1728 \r
1729 /*\r
1730 ============================\r
1731 =\r
1732 = DrawSWText\r
1733 =\r
1734 ============================\r
1735 */\r
1736 \r
1737 void DrawSWText(void)\r
1738 {\r
1739         char far *text;\r
1740         char *ptr;\r
1741         char c;\r
1742         char strbuf[80];\r
1743 \r
1744         WindowX = 0;\r
1745         WindowW = 336;\r
1746         PrintY = 1;             // always leave the first line blank\r
1747         bufferofs = 0;\r
1748         panadjust = 0;\r
1749         text = swtext;\r
1750         masterlines = 0;\r
1751 \r
1752         //\r
1753         // draw the entire text to video memory\r
1754         //\r
1755         while (*text)\r
1756         {\r
1757                 ptr = strbuf;\r
1758                 do\r
1759                 {\r
1760                         c = *text++;\r
1761                         *ptr++ = c;\r
1762                 } while (c != '\n' && c != '\0');\r
1763                 *ptr = '\0';\r
1764 \r
1765                 TranslateString(strbuf);\r
1766 \r
1767                 US_CPrint(strbuf);\r
1768 \r
1769                 bufferofs += ylookup[PrintY];\r
1770                 masterlines += PrintY;\r
1771                 PrintY = 0;\r
1772         }\r
1773 \r
1774         //\r
1775         // allocate a buffer large enough to hold the entire text image\r
1776         // and move the image data from video memory into that buffer\r
1777         //\r
1778         MM_GetPtr(&sourcepic, bufferofs);\r
1779         EGAREADMAP(1);  // read from "green" plane (doesn't really matter from which plane we read)\r
1780         movedata(screenseg, 0, FP_SEG(sourcepic), 0, bufferofs);\r
1781 \r
1782         //\r
1783         // erase the (first screen of the) text from video memory.\r
1784         // we're going to display this area and copy the backgound pic\r
1785         // here line-by-line as the scalers are generated and we don't\r
1786         // want to have parts of the text still visible at that point.\r
1787         //\r
1788         bufferofs = 0;\r
1789         VW_Bar(0, 0, 320, 200, BLACK);\r
1790 }\r
1791 \r
1792 /*\r
1793 ============================\r
1794 =\r
1795 = ScrollSWText\r
1796 =\r
1797 ============================\r
1798 */\r
1799 \r
1800 void ScrollSWText(void)\r
1801 {\r
1802         Sint32 now;\r
1803         Uint16 pos;\r
1804         Sint16 i, rowof;\r
1805 \r
1806         tics = TimeCount = lasttimecount = 0;\r
1807 \r
1808         EGAWRITEMODE(0);\r
1809         EGAMAPMASK(8);  // only draw to the "intensity" plane (so we don't erase the backgound pic)\r
1810 \r
1811         pos = 0;\r
1812         while (masterlines + 400 >= pos)\r
1813         {\r
1814                 for (i = 199; i >= 0; i--)\r
1815                 {\r
1816                         rowof = pos - sourceline[i];\r
1817                         if (rowof < 0 || rowof >= masterlines)\r
1818                         {\r
1819                                 masterofs = 0;  // draw the first (blank) line of the buffer\r
1820                         }\r
1821                         else\r
1822                         {\r
1823                                 masterofs = rowof * 42;\r
1824                         }\r
1825                         routine = linestarts[i];\r
1826                         asm {\r
1827                                 mov     es, screenseg;\r
1828                                 mov     di, pageofs;\r
1829                                 mov     ds, bittables;\r
1830                                 push    bp;\r
1831                                 mov     bp, ss:masterofs;\r
1832                                 mov     ax, ss:sourcepic;\r
1833                                 xor     bh, bh;\r
1834                                 cli;    // disable interrupts (scaler changes register SS, so interrupts would be fatal!)\r
1835                                 call    ss:routine;\r
1836                                 sti;    // enable interrupts again\r
1837                                 pop     bp;\r
1838                                 mov     ax, ss;\r
1839                                 mov     ds, ax;\r
1840                         }\r
1841                 }\r
1842 \r
1843                 VW_SetScreen(pageofs, 0);\r
1844                 pageon ^= 1;\r
1845                 pageofs = pageon << 15;\r
1846 \r
1847                 now = TimeCount;\r
1848                 tics = tics + (now - lasttimecount);\r
1849                 lasttimecount = now;\r
1850                 if (tics > 20)\r
1851                         tics = 20;\r
1852 \r
1853                 pos = pos + tics / 4;\r
1854                 tics &= 3;\r
1855 \r
1856                 if (IN_IsUserInput() && LastScan != sc_F1)\r
1857                         LastScan = sc_Space;\r
1858 \r
1859                 if (LastScan)\r
1860                         break;\r
1861         }\r
1862 }\r
1863 \r
1864 /*\r
1865 ============================\r
1866 =\r
1867 = StarWars\r
1868 =\r
1869 ============================\r
1870 */\r
1871 \r
1872 void StarWars(void)\r
1873 {\r
1874         SetPaletteEx(colors[0]);        // all black\r
1875         VW_ClearVideo(BLACK);\r
1876         VW_SetLineWidth(42);    // 336 pixels\r
1877         VW_SetScreen(0, 0);\r
1878         pageon = pageofs = 0;\r
1879         CA_SetAllPurge();\r
1880         CA_CacheGrChunk(STARTFONT+2);\r
1881         fontnumber = 2;\r
1882         DrawSWText();\r
1883         fontnumber = 0;\r
1884 \r
1885         CA_CacheGrChunk(SW_BACKGROUNDPIC);\r
1886         bufferofs = 0x8000;\r
1887         VW_DrawPic(0, 0, SW_BACKGROUNDPIC);\r
1888         CA_SetAllPurge();\r
1889         SetPaletteEx(starcolors);\r
1890         bufferofs = 0;\r
1891         CompileSWUpdate();\r
1892 \r
1893         if (!LastScan)\r
1894         {\r
1895                 StartMusic(STARWARSMUSIC);\r
1896                 ScrollSWText();\r
1897                 StopMusic();\r
1898         }\r
1899 \r
1900         MM_FreePtr(&linecode);\r
1901         MM_FreePtr(&bittables);\r
1902         MM_FreePtr(&sourcepic);\r
1903 \r
1904         VW_ClearVideo(BLACK);\r
1905         VW_SetLineWidth(SCREENWIDTH);\r
1906         VW_SetDefaultColors();\r
1907         RF_FixOfs();\r
1908         CA_ClearMarks();\r
1909 \r
1910         CheckLastScan();\r
1911 }\r
1912 \r
1913 #endif  // if GRMODE == EGAGR\r
1914 \r
1915 //===========================================================================\r
1916 \r
1917 /*\r
1918 ============================\r
1919 =\r
1920 = ShowTitle\r
1921 =\r
1922 ============================\r
1923 */\r
1924 \r
1925 void ShowTitle(void)\r
1926 {\r
1927         panadjust = 0;\r
1928         CA_CacheGrChunk(TITLEPICPIC);\r
1929         VW_DrawPic(0, 0, TITLEPICPIC);\r
1930 #if GRMODE == CGAGR\r
1931         VW_UpdateScreen();\r
1932 #else\r
1933         VW_SetScreen(displayofs, 0);\r
1934         VW_ScreenToScreen(bufferofs, displayofs, 42, 224);\r
1935 #endif\r
1936         IN_UserInput(6*TickBase, false);\r
1937         CA_ClearMarks();\r
1938         CheckLastScan();\r
1939 }\r
1940 \r
1941 //===========================================================================\r
1942 \r
1943 #if GRMODE == CGAGR\r
1944 /*\r
1945 ============================\r
1946 =\r
1947 = ShowCredits\r
1948 =\r
1949 ============================\r
1950 */\r
1951 \r
1952 void ShowCredits(void)\r
1953 {\r
1954         panadjust = 0;\r
1955         CA_CacheGrChunk(SW_BACKGROUNDPIC);\r
1956         VW_DrawPic(0, 0, SW_BACKGROUNDPIC);\r
1957         VW_UpdateScreen();\r
1958         IN_UserInput(6*TickBase, false);\r
1959         CA_ClearMarks();\r
1960         CheckLastScan();\r
1961 }\r
1962 #endif\r
1963 \r
1964 //===========================================================================\r
1965 \r
1966 /*\r
1967 ============================\r
1968 =\r
1969 = RunDemo\r
1970 =\r
1971 ============================\r
1972 */\r
1973 \r
1974 void RunDemo(Sint16 num)\r
1975 {\r
1976         Uint16 far *demodata;\r
1977         \r
1978         NewGame();\r
1979         num += DEMO0;\r
1980         CA_CacheGrChunk(num);\r
1981         demodata = grsegs[num];\r
1982         gamestate.mapon = demodata[0];\r
1983         DemoSize = demodata[1];\r
1984         MM_GetPtr(&(memptr)DemoBuffer, DemoSize);\r
1985         MM_SetLock(&(memptr)DemoBuffer, true);\r
1986         _fmemcpy(DemoBuffer, ((char _seg *)grsegs[num])+4, DemoSize);\r
1987         MM_FreePtr(&grsegs[num]);\r
1988         IN_StartDemoPlayback(DemoBuffer, DemoSize);\r
1989         SetupGameLevel(true);\r
1990         if (scorescreenkludge)\r
1991         {\r
1992                 DrawHighScores();\r
1993         }\r
1994         PlayLoop();\r
1995         IN_StopDemo();\r
1996         MM_FreePtr(&(memptr)DemoBuffer);\r
1997         VW_FixRefreshBuffer();\r
1998         CA_ClearMarks();\r
1999         CheckLastScan();\r
2000 }\r
2001 \r
2002 //===========================================================================\r
2003 \r
2004 /*\r
2005 ============================\r
2006 =\r
2007 = DrawHighScores\r
2008 =\r
2009 ============================\r
2010 */\r
2011 \r
2012 void DrawHighScores(void)\r
2013 {\r
2014         Uint16 i, n;\r
2015         Uint16 width, height;\r
2016         HighScore *entry;\r
2017         Uint16 oldbufferofs;\r
2018         char buf[16], *bufptr;\r
2019         \r
2020         RF_NewPosition(0, 0);\r
2021         oldbufferofs = bufferofs;\r
2022         bufferofs = masterofs;\r
2023 #ifdef KEEN5\r
2024 #if GRMODE == CGAGR\r
2025         fontcolor = 2;\r
2026 #else\r
2027         fontcolor = BLUE ^ LIGHTMAGENTA;        // blue text on light magenta background (XOR draw mode!)\r
2028 #endif\r
2029 #endif\r
2030         for (i=0, entry=&Scores[0]; i<MaxScores; i++, entry++)\r
2031         {\r
2032                 PrintY = i*16 + HIGHSCORE_TOP;\r
2033                 PrintX = HIGHSCORE_LEFT;\r
2034                 US_Print(entry->name);\r
2035 #ifdef KEEN4\r
2036                 PrintX = 152;\r
2037                 for (n=0; n<entry->completed; n++)\r
2038                 {\r
2039                         VWB_DrawTile8(PrintX, PrintY+1, 71);\r
2040                         PrintX += 8;\r
2041                 }\r
2042 #endif\r
2043                 ultoa(entry->score, buf, 10);\r
2044                 for (bufptr=buf; *bufptr; bufptr++)\r
2045                 {\r
2046                         *bufptr = *bufptr + 81;\r
2047                 }\r
2048                 USL_MeasureString(buf, &width, &height);\r
2049                 PrintX = HIGHSCORE_RIGHT - width;\r
2050                 US_Print(buf);\r
2051         }\r
2052         fontcolor = WHITE;      // back to default color\r
2053         bufferofs = oldbufferofs;\r
2054 }\r
2055 \r
2056 //===========================================================================\r
2057 \r
2058 /*\r
2059 ============================\r
2060 =\r
2061 = CheckHighScore\r
2062 =\r
2063 ============================\r
2064 */\r
2065 \r
2066 void CheckHighScore(Sint32 score, Sint16 completed)\r
2067 {\r
2068         Uint16 i, n;\r
2069         Sint16 index;\r
2070         HighScore entry;\r
2071         \r
2072         strcpy(entry.name, ""); //Note: 'entry.name[0] = 0;' would be more efficient\r
2073         entry.score = score;\r
2074         entry.completed = completed;\r
2075         for (i=0, index=-1; i<MaxScores; i++)\r
2076         {\r
2077                 if (Scores[i].score < entry.score ||\r
2078                         (Scores[i].score == entry.score && Scores[i].completed < entry.completed))\r
2079                 {\r
2080                         n=MaxScores;\r
2081                         while (--n > i)\r
2082                         {\r
2083                                 Scores[n] = Scores[n-1];\r
2084                         }\r
2085                         Scores[i] = entry;\r
2086                         index = i;\r
2087                         HighScoresDirty = true;\r
2088                         break;\r
2089                 }\r
2090         }\r
2091         if (index != -1)\r
2092         {\r
2093                 scorescreenkludge = true;\r
2094                 gamestate.mapon = HIGHSCORE_MAP;\r
2095                 SetupGameLevel(true);\r
2096                 DrawHighScores();\r
2097 #ifdef KEEN5\r
2098 #if GRMODE == CGAGR\r
2099                 fontcolor = 2;\r
2100 #else\r
2101                 fontcolor = BLUE ^ LIGHTMAGENTA;        // blue text on light magenta background (XOR draw mode!)\r
2102 #endif\r
2103 #endif\r
2104                 RF_Refresh();\r
2105                 RF_Refresh();\r
2106                 PrintY = i*16 + HIGHSCORE_TOP;\r
2107                 PrintX = HIGHSCORE_LEFT;\r
2108                 US_LineInput(PrintX, PrintY, Scores[index].name, NULL, true, MaxHighName, 112);\r
2109                 scorescreenkludge = false;\r
2110         }\r
2111 #ifdef KEEN5\r
2112         fontcolor = 15; // back to default color (white)\r
2113 #endif\r
2114 }\r
2115 \r
2116 //===========================================================================\r
2117 \r
2118 /*\r
2119 ============================\r
2120 =\r
2121 = ShowHighScores\r
2122 =\r
2123 ============================\r
2124 */\r
2125 \r
2126 void ShowHighScores(void)\r
2127 {\r
2128         scorescreenkludge = true;\r
2129         IN_ClearKeysDown();\r
2130         RunDemo(4);\r
2131         scorescreenkludge = false;\r
2132 }\r