1 /* Reconstructed Commander Keen 4-6 Source Code
\r
2 * Copyright (C) 2021 K1n9_Duk3
\r
4 * This file is primarily based on:
\r
5 * Wolfenstein 3-D Source Code
\r
6 * Copyright (C) 1992 id Software
\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
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
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
26 =============================================================================
\r
28 TEXT FORMATTING COMMANDS
\r
29 ------------------------
\r
30 ^C<hex digit> Change text color
\r
31 ^E[enter] End of layout (all pages)
\r
32 ^G<y>,<x>,<pic>[enter] Draw a graphic and push margins
\r
33 ^P[enter] start new page, must be the first chars in a layout
\r
34 ^L<x>,<y>[ENTER] Locate to a specific spot, x in pixels, y in lines
\r
36 =============================================================================
\r
40 =============================================================================
\r
44 =============================================================================
\r
49 #define BACKCOLOR 2 // CGA magenta
\r
51 #define BACKCOLOR WHITE
\r
54 #define BACKCOLOR RED
\r
57 #define WORDLIMIT 80
\r
58 #define FONTHEIGHT 10
\r
59 #define TOPMARGIN 10
\r
60 #define BOTTOMMARGIN 10
\r
61 #define LEFTMARGIN 10
\r
62 #define RIGHTMARGIN 10
\r
64 #define SPACEWIDTH 7
\r
65 #define TEXTROWS ((200-TOPMARGIN-BOTTOMMARGIN)/FONTHEIGHT)
\r
66 #define SCREENPIXWIDTH 320
\r
67 #define SCREENMID (SCREENPIXWIDTH/2)
\r
70 =============================================================================
\r
74 =============================================================================
\r
77 Sint16 pagenum,numpages;
\r
78 Uint16 leftmargin[TEXTROWS],rightmargin[TEXTROWS];
\r
81 Sint16 picx,picy,picnum,picdelay;
\r
86 //===========================================================================
\r
89 =====================
\r
93 =====================
\r
98 while (*text++ != '\n');
\r
103 =====================
\r
107 =====================
\r
110 Sint16 ParseNumber(void)
\r
112 char c, buffer[80];
\r
116 // scan until a number is found
\r
119 while (c < '0' || c > '9')
\r
123 // copy the number out
\r
132 } while (c >= '0' && c <= '9');
\r
135 return atoi(buffer);
\r
140 =====================
\r
144 = Call with text pointing just after a ^P
\r
145 = Upon exit text points to the start of next line
\r
147 =====================
\r
150 void ParsePicCommand(void)
\r
152 picy = ParseNumber();
\r
153 picx = ParseNumber();
\r
154 picnum = ParseNumber();
\r
158 void ParseTimedCommand(void)
\r
160 picy = ParseNumber();
\r
161 picx = ParseNumber();
\r
162 picnum = ParseNumber();
\r
163 picdelay = ParseNumber();
\r
168 =====================
\r
172 = Call with text pointing just after a ^P
\r
173 = Upon exit text points to the start of next line
\r
175 =====================
\r
178 void TimedPicCommand(void)
\r
180 ParseTimedCommand();
\r
183 // update the screen, and wait for time delay
\r
185 #if GRMODE == CGAGR
\r
189 VW_ScreenToScreen(bufferofs, displayofs, 40, 200);
\r
196 while (picdelay > TimeCount)
\r
202 VWB_DrawPic(picx & ~7, picy, picnum);
\r
207 =====================
\r
211 =====================
\r
214 void HandleCommand(void)
\r
216 Sint16 i,margin,top,bottom;
\r
217 Sint16 picwidth,picheight,picmid;
\r
219 switch (toupper(*(++text)))
\r
222 picy = ParseNumber();
\r
223 picx = ParseNumber();
\r
224 picwidth = ParseNumber();
\r
225 picheight = ParseNumber();
\r
226 VWB_Bar(picx, picy, picwidth, picheight, BACKCOLOR);
\r
230 case 'P': // ^P is start of next page, ^E is end of file
\r
236 case 'C': // ^c<hex digit> changes text color
\r
237 i = toupper(*(++text));
\r
238 if (i >= '0' && i <= '9')
\r
240 fontcolor = i + 0 - '0';
\r
242 else if (i >= 'A' && i <= 'F')
\r
244 fontcolor = i + 10 - 'A';
\r
246 #if GRMODE == CGAGR
\r
248 static Sint16 colormap[16] = {2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0};
\r
249 // Note: This mapping is a bit problematic for Keen 5 CGA,
\r
250 // since some colors get mapped to CGA magenta, which is
\r
251 // used as the background color in that version. Luckily
\r
252 // those colors aren't used in the Keen 5 texts anyway.
\r
254 fontcolor = colormap[fontcolor];
\r
257 fontcolor ^= BACKCOLOR;
\r
262 py = ParseNumber();
\r
263 rowon = (py - 10)/10;
\r
264 py = rowon * 10 + 10;
\r
265 px = ParseNumber();
\r
266 while (*(text++) != '\n') // scan to end of line
\r
270 case 'T': // ^Tyyy,xxx,ppp,ttt waits ttt tics, then draws pic
\r
274 case 'G': // ^Gyyy,xxx,ppp draws graphic
\r
276 VWB_DrawPic(picx & ~7, picy, picnum);
\r
277 picwidth = pictable[picnum-STARTPICS].width * BYTEPIXELS;
\r
278 picheight = pictable[picnum-STARTPICS].height;
\r
279 picmid = picx + picwidth/2;
\r
283 if (picmid > SCREENMID)
\r
285 margin = picx-PICMARGIN; // new right margin
\r
289 margin = picx+picwidth+PICMARGIN; // new left margin
\r
291 top = (picy-TOPMARGIN)/FONTHEIGHT;
\r
296 bottom = (picy+picheight-TOPMARGIN)/FONTHEIGHT;
\r
297 if (bottom >= TEXTROWS)
\r
299 bottom = TEXTROWS-1;
\r
302 for (i=top; i<=bottom; i++)
\r
304 if (picmid > SCREENMID)
\r
306 rightmargin[i] = margin;
\r
310 leftmargin[i] = margin;
\r
315 // adjust this line if needed
\r
317 if (leftmargin[rowon] > px)
\r
319 px = leftmargin[rowon];
\r
327 =====================
\r
331 =====================
\r
338 if (++rowon == TEXTROWS)
\r
341 // overflowed the page, so skip until next page break
\r
348 c = toupper(text[1]);
\r
349 if (c == 'E' || c == 'P')
\r
358 px = leftmargin[rowon];
\r
364 =====================
\r
368 =====================
\r
371 void HandleCtrls(void)
\r
375 c = *(text++); // get the character and advance
\r
385 =====================
\r
389 =====================
\r
392 void HandleWord(void)
\r
394 Uint16 wwidth, wheight, newpos, wordindex;
\r
395 char word[WORDLIMIT];
\r
398 // copy the next word into [word]
\r
400 word[0] = *(text++);
\r
402 while (*text > ' ')
\r
404 word[wordindex] = *(text++);
\r
405 if (++wordindex == WORDLIMIT)
\r
407 Quit("PageLayout: Word limit exceeded");
\r
410 word[wordindex] = 0; // stick a null at end for C
\r
413 // see if it fits on this line
\r
415 VW_MeasurePropString(word, &wwidth, &wheight);
\r
417 while (rightmargin[rowon] < px+wwidth)
\r
422 return; // overflowed page
\r
429 newpos = px+wwidth;
\r
430 VWB_DrawPropString(word);
\r
434 // suck up any extra spaces
\r
436 while (*text == ' ')
\r
444 =====================
\r
448 = Clears the screen, draws the pics on the page, and word wraps the text.
\r
449 = Returns a pointer to the terminating command
\r
451 =====================
\r
454 void PageLayout(boolean shownumber)
\r
456 Sint16 oldcolor, i;
\r
459 oldcolor = fontcolor;
\r
461 #if GRMODE == CGAGR
\r
462 fontcolor = BLACK^BACKCOLOR;
\r
464 fontcolor = YELLOW^BACKCOLOR;
\r
468 // clear the screen
\r
470 VWB_Bar(0, 0, 320, 200, BACKCOLOR);
\r
472 VWB_DrawPic( 0, 0, H_TOPWINDOWPIC);
\r
473 VWB_DrawPic( 0, 8, H_LEFTWINDOWPIC);
\r
474 VWB_DrawPic(312, 8, H_RIGHTWINDOWPIC);
\r
477 VWB_DrawPic(8, 176, H_BOTTOMINFOPIC);
\r
481 VWB_DrawPic(8, 192, H_BOTTOMWINDOWPIC);
\r
485 for (i=0; i<TEXTROWS; i++)
\r
487 leftmargin[i] = LEFTMARGIN;
\r
488 rightmargin[i] = SCREENPIXWIDTH-RIGHTMARGIN;
\r
494 layoutdone = false;
\r
497 // make sure we are starting layout text (^P first command)
\r
499 while (*text <= ' ')
\r
503 if (*text != '^' || toupper(*(++text)) != 'P')
\r
505 Quit("PageLayout: Text not headed with ^P");
\r
507 while (*(text++) != '\n')
\r
511 // process text stream
\r
528 } while (!layoutdone);
\r
534 strcpy(str, "pg ");
\r
535 itoa(pagenum, str2, 10);
\r
537 strcat(str, " of ");
\r
538 itoa(numpages, str2, 10);
\r
540 #if GRMODE == CGAGR
\r
541 fontcolor = BLACK^BACKCOLOR;
\r
543 fontcolor = LIGHTRED^BACKCOLOR;
\r
547 VWB_DrawPropString(str);
\r
550 fontcolor = oldcolor;
\r
553 //===========================================================================
\r
556 =====================
\r
560 = Scans for a previous ^P
\r
562 =====================
\r
565 void BackPage(void)
\r
571 if (text[0] == '^' && toupper(text[1]) == 'P')
\r
578 //===========================================================================
\r
582 =====================
\r
584 = CacheLayoutGraphics
\r
586 = Scans an entire layout file (until a ^E) marking all graphics used, and
\r
587 = counting pages, then caches the graphics in
\r
589 =====================
\r
591 void CacheLayoutGraphics(void)
\r
593 char far *bombpoint, far *textstart;
\r
597 bombpoint = text+30000;
\r
598 numpages = pagenum = 0;
\r
601 CA_MarkGrChunk(H_TOPWINDOWPIC);
\r
602 CA_MarkGrChunk(H_LEFTWINDOWPIC);
\r
603 CA_MarkGrChunk(H_RIGHTWINDOWPIC);
\r
604 CA_MarkGrChunk(H_BOTTOMINFOPIC);
\r
605 CA_MarkGrChunk(H_BOTTOMWINDOWPIC);
\r
612 ch = toupper(*(++text));
\r
613 if (ch == 'P') // start of a page
\r
617 if (ch == 'E') // end of file, so load graphics and return
\r
619 CA_CacheMarks(NULL);
\r
623 if (ch == 'G') // draw graphic command, so mark graphics
\r
626 CA_MarkGrChunk(picnum);
\r
628 if (ch == 'T') // timed draw graphic command, so mark graphics
\r
630 ParseTimedCommand();
\r
631 CA_MarkGrChunk(picnum);
\r
639 } while (text < bombpoint);
\r
641 Quit("CacheLayoutGraphics: No ^E to terminate file!");
\r
644 //===========================================================================
\r
654 Sint16 HelpMenu(void)
\r
657 ControlInfo control;
\r
661 VWB_Bar(0, 0, 320, 200, BACKCOLOR);
\r
663 CA_CacheGrChunk(H_HELPPIC);
\r
664 CA_CacheGrChunk(H_HANDPIC);
\r
665 CA_CacheGrChunk(H_TOPWINDOWPIC);
\r
666 CA_CacheGrChunk(H_LEFTWINDOWPIC);
\r
667 CA_CacheGrChunk(H_RIGHTWINDOWPIC);
\r
668 CA_CacheGrChunk(H_BOTTOMWINDOWPIC);
\r
670 VWB_DrawPic( 0, 0, H_TOPWINDOWPIC);
\r
671 VWB_DrawPic( 0, 8, H_LEFTWINDOWPIC);
\r
672 VWB_DrawPic(312, 8, H_RIGHTWINDOWPIC);
\r
673 VWB_DrawPic( 8, 192, H_BOTTOMWINDOWPIC);
\r
674 VWB_DrawPic( 96, 8, H_HELPPIC);
\r
677 IN_ClearKeysDown();
\r
680 if (helpmenupos < 0)
\r
685 else if (helpmenupos > 3)
\r
690 else if (helpmenupos > 4)
\r
695 VWB_DrawPic(48, 24*helpmenupos+48, H_HANDPIC);
\r
697 VWB_Bar(48, 24*helpmenupos+48, 39, 24, BACKCOLOR);
\r
698 IN_ReadControl(0, &control);
\r
699 IN_ReadCursor(&cursor);
\r
703 IN_ClearKeysDown();
\r
713 VW_ClearVideo(BACKCOLOR);
\r
714 return helpmenupos;
\r
716 VW_ClearVideo(BACKCOLOR);
\r
720 ydelta += cursor.y;
\r
721 if (cursor.button0 || cursor.button1 || control.button0 || control.button1)
\r
723 VW_ClearVideo(BACKCOLOR);
\r
724 return helpmenupos;
\r
731 else if (ydelta > 40)
\r
746 void HelpScreens(void)
\r
748 static Uint16 layouttable[5] =
\r
759 Uint16 olddisplayofs, oldbufferofs, oldfontnumber, temp;
\r
763 oldfontnumber = fontnumber;
\r
764 olddisplayofs = displayofs;
\r
765 oldbufferofs = bufferofs;
\r
768 #if GRMODE == EGAGR
\r
774 VW_ClearVideo(BACKCOLOR);
\r
776 #if GRMODE == EGAGR
\r
779 displayofs = 0x8000;
\r
780 VW_SetScreen(displayofs, 0);
\r
791 VW_ClearVideo(BACKCOLOR);
\r
796 IN_ClearKeysDown();
\r
797 bufferofs = oldbufferofs;
\r
798 displayofs = olddisplayofs;
\r
799 fontnumber = oldfontnumber;
\r
800 VW_ClearVideo(BACKCOLOR);
\r
803 StopMusic(); // Note: it's safer to call StopMusic BEFORE CA_DownLevel
\r
808 pos = layouttable[pos];
\r
809 CA_CacheGrChunk(pos);
\r
810 text = grsegs[pos];
\r
811 CacheLayoutGraphics();
\r
820 #if GRMODE == CGAGR
\r
823 VW_SetScreen(bufferofs, 0);
\r
825 displayofs = bufferofs;
\r
846 case sc_RightArrow:
\r
848 if (pagenum < numpages)
\r
854 } while (LastScan != sc_Escape);
\r
856 MM_FreePtr(&grsegs[pos]);
\r
857 IN_ClearKeysDown();
\r
863 //===========================================================================
\r
872 void FinaleLayout(void)
\r
874 char _seg *textseg;
\r
877 VW_ClearVideo(BACKCOLOR);
\r
881 CA_CacheGrChunk(H_FLASHARROW2PIC);
\r
882 CA_CacheGrChunk(H_FLASHARROW1PIC);
\r
885 if (gamestate.leveldone[13] == ex_fusebroke)
\r
887 CA_CacheGrChunk(T_ENDART2);
\r
888 textseg = grsegs[T_ENDART2];
\r
892 CA_CacheGrChunk(T_ENDART);
\r
893 textseg = grsegs[T_ENDART];
\r
896 CA_CacheGrChunk(T_ENDART);
\r
897 textseg = grsegs[T_ENDART];
\r
901 CacheLayoutGraphics();
\r
903 StartMusic(ENDINGMUSIC);
\r
905 while (pagenum < numpages)
\r
908 IN_ClearKeysDown();
\r
909 #if GRMODE == CGAGR
\r
912 VW_SetScreen(bufferofs, 0);
\r
917 VWB_DrawPic(298, 184, H_FLASHARROW1PIC);
\r
918 #if GRMODE == CGAGR
\r
921 for (i=0; i<TickBase; i++)
\r
923 if (IN_IsUserInput())
\r
930 VWB_DrawPic(298, 184, H_FLASHARROW2PIC);
\r
931 #if GRMODE == CGAGR
\r
934 for (i=0; i<TickBase; i++)
\r
936 if (IN_IsUserInput())
\r
945 ; // Borland C++ 2.0 needs a semicolon here...
\r
951 if (gamestate.leveldone[13] == ex_fusebroke)
\r
953 MM_FreePtr(&grsegs[T_ENDART2]);
\r
957 MM_FreePtr(&grsegs[H_FLASHARROW1PIC]); // BUG! this should free T_ENDART, the arrow should be freed after the else branch!
\r
960 MM_FreePtr(&grsegs[T_ENDART]);
\r
961 MM_FreePtr(&grsegs[H_FLASHARROW1PIC]);
\r
963 MM_FreePtr(&grsegs[H_FLASHARROW2PIC]);
\r
965 IN_ClearKeysDown();
\r
966 #if GRMODE != CGAGR
\r
967 VW_ClearVideo(BACKCOLOR);
\r