1 /*
2  * bctext.c - DOS interface, text functions
3  *
4  * This file is part of Frotz.
5  *
6  * Frotz is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Frotz is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  * Or visit http://www.fsf.org/
20  */
21 
22 #include <alloc.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <conio.h>
26 #include <dos.h>
27 #include "frotz.h"
28 #include "BCfrotz.h"
29 #include "fontdata.h"
30 
31 extern byte far *get_scrnptr(int);
32 
33 int current_bg = 0;
34 int current_fg = 0;
35 int current_style = 0;
36 int current_font = 0;
37 
38 byte text_bg = 0;
39 byte text_fg = 0;
40 byte bg = 0;
41 byte fg = 0;
42 byte scrn_attr = 0;
43 
44 int cursor_x = 0;
45 int cursor_y = 0;
46 
47 char latin1_to_ascii[] =
48 	"   !  c  L  >o<Y  |  S  '' C  a  << not-  R  _  "
49 	"^0 +/-^2 ^3 '  my P  .  ,  ^1 o  >> 1/41/23/4?  "
50 	"A  A  A  A  Ae A  AE C  E  E  E  E  I  I  I  I  "
51 	"Th N  O  O  O  O  Oe *  O  U  U  U  Ue Y  Th ss "
52 	"a  a  a  a  ae a  ae c  e  e  e  e  i  i  i  i  "
53 	"th n  o  o  o  o  oe :  o  u  u  u  ue y  th y  ";
54 
55 char latin1_to_ibm[] = {
56 	0x20, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5,
57 	0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee,
58 	0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa,
59 	0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8,
60 	0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80,
61 	0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8,
62 	0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e,
63 	0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1,
64 	0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87,
65 	0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
66 	0xd0, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6,
67 	0x9b, 0x97, 0xa3, 0x96, 0x81, 0xec, 0xe7, 0x98
68 };
69 
70 static byte far *graphics_font = NULL;
71 static byte far *mcga_font = NULL;
72 static byte far *mcga_width = NULL;
73 static word far *serif_font = NULL;
74 static byte far *serif_width = NULL;
75 
76 
77 /*
78  * load_fonts
79  *
80  * Load the proportional and graphics fonts. In the release version all
81  * font data is appended to the end of the executable.
82  *
83  */
load_fonts(void)84 void load_fonts(void)
85 {
86 	static chunk_offset[] = {
87 		0x6660,
88 		0x6300,
89 		0x4A40,
90 		0x3180,
91 		0x18C0,
92 		0x00
93 	};
94 
95 	if (display == _MCGA_) {
96 		mcga_font = font_data + chunk_offset[1];
97 		mcga_width = (byte *) mcga_font + 0x300;
98 	} else
99 		graphics_font = font_data + chunk_offset[0];
100 
101 	if (display == _AMIGA_ && user_font != 0) {
102 		serif_font = (word *) (font_data + chunk_offset[1 + user_font]);
103 		serif_width = (byte *) serif_font + 0x1800;
104 	}
105 } /* load_fonts */
106 
107 
108 /*
109  * os_font_data
110  *
111  * Return true if the given font is available. The font can be
112  *
113  *    TEXT_FONT
114  *    PICTURE_FONT
115  *    GRAPHICS_FONT
116  *    FIXED_WIDTH_FONT
117  *
118  * The font size should be stored in "height" and "width". If the given
119  * font is unavailable then these values must _not_ be changed.
120  *
121  */
os_font_data(int font,int * height,int * width)122 int os_font_data(int font, int *height, int *width)
123 {
124 	/* All fonts of this interface have the same size */
125 	*height = z_header.font_height;
126 	*width = z_header.font_width;
127 
128 	/* Not every font is available in every mode */
129 	if (font == TEXT_FONT)
130 		return TRUE;
131 	if (font == GRAPHICS_FONT && (display == _CGA_ || display >= _EGA_))
132 		return TRUE;
133 	if (font == FIXED_WIDTH_FONT)
134 		return TRUE;
135 
136 	/* Unavailable font */
137 	return FALSE;
138 } /* os_font_data */
139 
140 
141 /*
142  * switch_scrn_attr
143  *
144  * Parts of the screen are usually erased to background colour.  However,
145  * for deleting text in the input routine it can be useful to erase to
146  * the current text background colour.  The two colours can be different,
147  * for example when the reverse text style is used.  This helper function
148  * toggles between the two possible behaviours.
149  *
150  */
switch_scrn_attr(bool flag)151 void switch_scrn_attr(bool flag)
152 {
153 	byte scrn_bg;
154 	byte scrn_fg;
155 
156 	if (flag) {
157 		scrn_bg = text_bg;
158 		scrn_fg = text_fg;
159 	} else {
160 		scrn_bg = bg;
161 		scrn_fg = fg;
162 	}
163 
164 	if (display <= _TEXT_)
165 		scrn_attr = (scrn_bg << 4) | scrn_fg;
166 	else if (display == _CGA_)
167 		scrn_attr = (scrn_bg != BLACK) ? 0xff : 0x00;
168 	else
169 		scrn_attr = scrn_bg;
170 } /* switch_scrn_attr */
171 
172 
173 /*
174  * adjust_style
175  *
176  * Set the current colours. This combines the current colour selection
177  * and the current text style.
178  *
179  */
adjust_style(void)180 static void adjust_style(void)
181 {
182 	static byte amiga_palette[][3] = {
183 		{0x00, 0x00, 0x00},
184 		{0x2a, 0x00, 0x00},
185 		{0x00, 0x2a, 0x00},
186 		{0x3f, 0x3f, 0x15},
187 		{0x00, 0x00, 0x2a},
188 		{0x2a, 0x00, 0x2a},
189 		{0x00, 0x2a, 0x2a},
190 		{0x3f, 0x3f, 0x3f},
191 		{0x30, 0x30, 0x30},
192 		{0x20, 0x20, 0x20},
193 		{0x10, 0x10, 0x10},
194 	};
195 
196 	static byte pc_colour[] = {
197 		BLACK,
198 		RED,
199 		GREEN,
200 		YELLOW,
201 		BLUE,
202 		MAGENTA,
203 		CYAN,
204 		WHITE,
205 		DARKGRAY
206 	};
207 
208 	static byte palette_bg = 0xff;
209 	static byte palette_fg = 0xff;
210 
211 	fg = current_fg;
212 	bg = current_bg;
213 
214 	/* V6 game, Amiga mode: Alter the palette registers if the colours
215 	   of window 0 have changed. DAC register #79 holds the foreground,
216 	   DAC register #64 the background colour. */
217 
218 	if (display == _AMIGA_ && z_header.version == V6 && cwin == 0) {
219 		if (fg < 16 && fg != palette_fg) {
220 			byte R = amiga_palette[fg - 2][0];
221 			byte G = amiga_palette[fg - 2][1];
222 			byte B = amiga_palette[fg - 2][2];
223 
224 			asm mov ax, 0x1010
225 			asm mov bx, 79
226 			asm mov dh, R
227 			asm mov ch, G
228 			asm mov cl, B
229 			asm int 0x10
230 
231 			palette_fg = fg;
232 		}
233 
234 		if (bg < 16 && bg != palette_bg) {
235 			byte R = amiga_palette[bg - 2][0];
236 			byte G = amiga_palette[bg - 2][1];
237 			byte B = amiga_palette[bg - 2][2];
238 
239 			asm mov ax, 0x1010
240 			asm mov bx, 64
241 			asm mov dh, R
242 			asm mov ch, G
243 			asm mov cl, B
244 			asm int 0x10
245 
246 			palette_bg = bg;
247 
248 		}
249 
250 	}
251 
252 	/* Handle colours */
253 	if (fg < 16) {
254 		if (display == _MONO_)
255 			fg = (fg == WHITE_COLOUR) ? LIGHTGRAY : BLACK;
256 		else if (z_header.version == V6 && display == _AMIGA_)
257 			fg = (palette_fg == fg) ? 15 : 0;
258 		else
259 			fg = pc_colour[fg - 2];
260 	} else
261 		fg -= 16;
262 
263 	if (bg < 16) {
264 		if (display == _MONO_)
265 			bg = (bg == WHITE_COLOUR) ? LIGHTGRAY : BLACK;
266 		else if (z_header.version == V6 && display == _AMIGA_)
267 			bg = (palette_bg == bg) ? 0 : 15;
268 		else
269 			bg = pc_colour[bg - 2];
270 
271 	} else
272 		bg -= 16;
273 
274 	/* Handle reverse text style */
275 	if (current_style & REVERSE_STYLE) {
276 		text_fg = (user_reverse_fg != -1) ? user_reverse_fg : bg;
277 		text_bg = (user_reverse_bg != -1) ? user_reverse_bg : fg;
278 	} else {
279 		text_fg = fg;
280 		text_bg = bg;
281 	}
282 
283 	/* Handle emphasis style */
284 	if (current_style & EMPHASIS_STYLE) {
285 		if (display == _MONO_ && text_bg == BLACK)
286 			text_fg = BLUE;	/* blue in monochrome mode is underlined */
287 		if (display == _TEXT_)
288 			text_fg =
289 			    (user_emphasis != -1) ? user_emphasis : YELLOW;
290 	}
291 
292 	/* Handle boldface style */
293 	if (current_style & BOLDFACE_STYLE) {
294 		if (display == _MONO_)
295 			text_fg = WHITE;
296 		if (display == _TEXT_)
297 			text_fg ^= 8;
298 
299 	}
300 
301 	/* Set the screen attribute for scrolling and erasing */
302 	switch_scrn_attr(FALSE);
303 } /* adjust_style */
304 
305 
306 /*
307  * os_set_colour
308  *
309  * Set the foreground and background colours which can be:
310  *
311  *     DEFAULT_COLOUR
312  *     BLACK_COLOUR
313  *     RED_COLOUR
314  *     GREEN_COLOUR
315  *     YELLOW_COLOUR
316  *     BLUE_COLOUR
317  *     MAGENTA_COLOUR
318  *     CYAN_COLOUR
319  *     WHITE_COLOUR
320  *
321  *     MS-DOS 320 columns MCGA mode only:
322  *
323  *     GREY_COLOUR
324  *
325  *     Amiga only:
326  *
327  *     LIGHTGREY_COLOUR
328  *     MEDIUMGREY_COLOUR
329  *     DARKGREY_COLOUR
330  *
331  * There may be more colours in the range from 16 to 255; see the remarks
332  * on os_peek_colour.
333  *
334  */
os_set_colour(int new_foreground,int new_background)335 void os_set_colour(int new_foreground, int new_background)
336 {
337 	current_fg = new_foreground;
338 	current_bg = new_background;
339 
340 	/* Apply changes */
341 	adjust_style();
342 
343 } /* os_set_colour */
344 
345 
346 /*
347  * os_set_text_style
348  *
349  * Set the current text style. Following flags can be set:
350  *
351  *     REVERSE_STYLE
352  *     BOLDFACE_STYLE
353  *     EMPHASIS_STYLE (aka underline aka italics)
354  *     FIXED_WIDTH_STYLE
355  *
356  */
os_set_text_style(int new_style)357 void os_set_text_style(int new_style)
358 {
359 	current_style = new_style;
360 
361 	/* Apply changes */
362 	adjust_style();
363 
364 } /* os_set_text_style */
365 
366 
367 /*
368  * os_set_font
369  *
370  * Set the font for text output. The interpreter takes care not to
371  * choose fonts which aren't supported by the interface.
372  *
373  */
os_set_font(int new_font)374 void os_set_font(int new_font)
375 {
376 	current_font = new_font;
377 } /* os_set_font */
378 
379 
380 /*
381  * write_pattern
382  *
383  * Helper function for drawing characters in EGA and Amiga mode.
384  *
385  */
write_pattern(byte far * screen,byte val,byte mask)386 void write_pattern(byte far * screen, byte val, byte mask)
387 {
388 	if (mask != 0) {
389 		if (display == _CGA_) {
390 			if (text_bg == BLACK)
391 				*screen &= ~mask;
392 			if (text_bg == WHITE)
393 				*screen |= mask;
394 			if (text_fg != text_bg)
395 				*screen ^= val;
396 		} else if (display == _MCGA_) {
397 			byte i;
398 
399 			for (i = 0x80; (mask & i) != 0; i >>= 1)
400 				*screen++ = (val & i) ? text_fg : text_bg;
401 		} else {
402 			asm mov dx, 0x03cf
403 			asm mov al, mask
404 			asm out dx, al
405 			asm les bx, screen
406 			asm mov ch, text_bg
407 			asm mov al, es:[bx]
408 			asm mov es:[bx], ch
409 			asm mov al, val
410 			asm out dx, al
411 			asm mov ch, text_fg
412 			asm mov al, es:[bx]
413 			asm mov es:[bx], ch
414 		}
415 	}
416 } /* write_pattern */
417 
418 
419 /*
420  * os_display_char
421  *
422  * Display a character of the current font using the current colours and
423  * text style. The cursor moves to the next position. Printable codes are
424  * all ASCII values from 32 to 126, ISO Latin-1 characters from 160 to
425  * 255, ZC_GAP (gap between two sentences) and ZC_INDENT (paragraph
426  * indentation). The screen should not be scrolled after printing to the
427  * bottom right corner.
428  *
os_display_char(zchar c)429  */ void os_display_char(zchar c)
430 {
431 	int width = os_char_width(c);
432 
433 	/* Handle accented characters */
434 	if (c >= ZC_LATIN1_MIN
435 	    && (story_id != BEYOND_ZORK || (z_header.flags & GRAPHICS_FLAG)))
436 		if (display == _CGA_ || display == _MCGA_) {
437 			char *ptr = latin1_to_ascii + 3 * (c - ZC_LATIN1_MIN);
438 
439 			char c1 = *ptr++;
440 			char c2 = *ptr++;
441 			char c3 = *ptr++;
442 
443 			os_display_char(c1);
444 
445 			if (c2 != ' ')
446 				os_display_char(c2);
447 			if (c3 != ' ')
448 				os_display_char(c3);
449 
450 			return;
451 
452 		} else if (display == _AMIGA_ && current_font == TEXT_FONT
453 			   && !(current_style & FIXED_WIDTH_STYLE)
454 			   && user_font != 0) {
455 
456 			if (c >= ZC_LATIN1_MIN)
457 				c -= 32;
458 		} else
459 			c = latin1_to_ibm[c - ZC_LATIN1_MIN];
460 
461 	/* Handle special indentations */
462 	if (c == ZC_INDENT) {
463 		os_display_char(' ');
464 		os_display_char(' ');
465 		os_display_char(' ');
466 		return;
467 	}
468 	if (c == ZC_GAP) {
469 		os_display_char(' ');
470 		os_display_char(' ');
471 		return;
472 	}
473 
474 	/* Display character */
475 	if (display <= _TEXT_) {
476 		asm mov ah, 2
477 		asm mov bh, 0
478 		asm mov dh, byte ptr cursor_y
479 		asm mov dl, byte ptr cursor_x
480 		asm int 0x10
481 		asm mov ah, 9
482 		asm mov bh, 0
483 		asm mov bl, byte ptr text_bg
484 		asm mov cl, 4
485 		asm shl bl, cl
486 		asm or bl, byte ptr text_fg
487 		asm mov cx, 1
488 		asm mov al, byte ptr c
489 		asm int 0x10
490 	} else {
491 
492 		void far *table;
493 		word mask;
494 		word val;
495 		byte mask0;
496 		byte mask1;
497 		int align;
498 		int underline;
499 		int boldface;
500 		int type;
501 
502 		int shift = (display != _MCGA_) ? cursor_x % 8 : 0;
503 		int offset = (display != _MCGA_) ? cursor_x / 8 : cursor_x;
504 
505 		int i;
506 
507 		if (current_font == GRAPHICS_FONT) {
508 			table = graphics_font + 8 * (c - 32);
509 			mask = 0xff;
510 			underline = -1;
511 			boldface = -1;
512 			align = 0;
513 			type = 1;
514 		} else if (display == _AMIGA_ && current_font == TEXT_FONT
515 			   && !(current_style & FIXED_WIDTH_STYLE)
516 			   && user_font != 0) {
517 			table = serif_font + 16 * (c - 32);
518 			mask = 0xffff << (16 - width);
519 			underline = 14;
520 			boldface = 1;
521 			align = 0;
522 			type = 2;
523 		} else if (display == _CGA_) {
524 			table = (byte far *) MK_FP(0xf000, 0xfa6e) + 8 * c;
525 			mask = 0xff;
526 			underline = 7;
527 			boldface = (user_bold_typing != -1) ? 1 : -1;
528 			align = 0;
529 			type = 3;
530 		} else if (display >= _EGA_) {
531 			table = (byte far *) getvect(0x43) + z_header.font_height * c;
532 			mask = 0xff;
533 			underline = z_header.font_height - 1;
534 			boldface = (user_bold_typing != -1) ? 1 : -1;
535 			align = 0;
536 			type = 3;
537 		} else {
538 			table = mcga_font + 8 * (c - 32);
539 			mask = 0xff & (0xff << (8 - width));
540 			underline = 7;
541 			boldface = -1;
542 			align = (width + 1 - mcga_width[c - 32]) / 2;
543 			type = 3;
544 		}
545 
546 		mask0 = mask >> shift;
547 		mask1 = mask << (8 - shift);
548 
549 		if (!(current_style & BOLDFACE_STYLE))
550 			boldface = -1;
551 		if (!(current_style & EMPHASIS_STYLE))
552 			underline = -1;
553 
554 		if (display >= _EGA_) {
555 			outport(0x03ce, 0x0205);
556 			outport(0x03ce, 0xff08);
557 		}
558 
559 		for (i = 0; i < z_header.font_height; i++) {
560 			byte far *screen = get_scrnptr(cursor_y + i) + offset;
561 
562 			if (type == 1) {
563 				val =
564 				    *((byte far *) table +
565 				      8 * i / z_header.font_height);
566 			}
567 			if (type == 2)
568 				val = *((word far *) table + i);
569 			if (type == 3)
570 				val = *((byte far *) table + i);
571 
572 			if (align != 0)
573 				val >>= align;
574 
575 			if (boldface == 1)
576 				val |= val >> 1;
577 			if (underline == i)
578 				val ^= mask;
579 
580 			if (type == 2)
581 				write_pattern(screen++, val >> (8 + shift),
582 					      mask >> (8 + shift));
583 
584 			write_pattern(screen + 0, val >> shift, mask0);
585 			write_pattern(screen + 1, val << (8 - shift), mask1);
586 		}
587 	}
588 
589 	/* Move cursor to next position */
590 	cursor_x += width;
591 } /* os_display_char */
592 
593 
594 /*
595  * os_display_string
596  *
597  * Pass a string of characters to os_display_char.
598  *
599  */
os_display_string(const zchar * s)600 void os_display_string(const zchar * s)
601 {
602 	zchar c;
603 
604 	while ((c = *s++) != 0) {
605 		if (c == ZC_NEW_FONT || c == ZC_NEW_STYLE) {
606 
607 			int arg = *s++;
608 
609 			if (c == ZC_NEW_FONT)
610 				os_set_font(arg);
611 			if (c == ZC_NEW_STYLE)
612 				os_set_text_style(arg);
613 
614 		} else
615 			os_display_char(c);
616 	}
617 } /* os_display_string */
618 
619 
620 /*
621  * os_char_width
622  *
623  * Return the width of the character in screen units.
624  *
625  */
626 
os_char_width(zchar c)627 int os_char_width(zchar c)
628 {
629 	/* Handle accented characters */
630 	if (c >= ZC_LATIN1_MIN
631 	    && (story_id != BEYOND_ZORK || (z_header.flags & GRAPHICS_FLAG)))
632 		if (display == _CGA_ || display == _MCGA_) {
633 
634 			const char *ptr =
635 			    latin1_to_ascii + 3 * (c - ZC_LATIN1_MIN);
636 
637 			int width = 0;
638 
639 			char c1 = *ptr++;
640 			char c2 = *ptr++;
641 			char c3 = *ptr++;
642 
643 			width = os_char_width(c1);
644 
645 			if (c2 != ' ')
646 				width += os_char_width(c2);
647 			if (c3 != ' ')
648 				width += os_char_width(c3);
649 
650 			return width;
651 
652 		} else if (display == _AMIGA_ && current_font == TEXT_FONT
653 			   && !(current_style & FIXED_WIDTH_STYLE)
654 			   && user_font != 0)
655 			if (c >= ZC_LATIN1_MIN)
656 				c -= 32;
657 
658 	/* Handle special indentations */
659 	if (c == ZC_INDENT)
660 		return 3 * os_char_width(' ');
661 	if (c == ZC_GAP)
662 		return 2 * os_char_width(' ');
663 
664 	/* Calculate width */
665 	if (display <= _TEXT_)
666 		return 1;
667 	if (display == _CGA_)
668 		return 8;
669 	if (display == _EGA_)
670 		return 8;
671 
672 	if (current_font == GRAPHICS_FONT)
673 		return 8;
674 	if (current_font == FIXED_WIDTH_FONT
675 	    || (current_style & FIXED_WIDTH_STYLE) || (display == _AMIGA_
676 						       && user_font == 0))
677 		return (display == _AMIGA_) ? 8 : 5;
678 
679 	if (display == _MCGA_)
680 		return mcga_width[c - 32];
681 	if (display == _AMIGA_)
682 		return serif_width[c - 32] +
683 		    ((current_style & BOLDFACE_STYLE) ? 1 : 0);
684 
685 	return 0;
686 } /* os_char_width */
687 
688 
689 /*
690  * os_string_width
691  *
692  * Calculate the length of a word in screen units. Apart from letters,
693  * the word may contain special codes:
694  *
695  *    ZC_NEW_STYLE - next character is a new text style
696  *    ZC_NEW_FONT  - next character is a new font
697  *
698  */
os_string_width(const zchar * s)699 int os_string_width(const zchar * s)
700 {
701 	int width = 0;
702 
703 	int saved_font = current_font;
704 	int saved_style = current_style;
705 
706 	zchar c;
707 
708 	while ((c = *s++) != 0) {
709 		if (c == ZC_NEW_STYLE || c == ZC_NEW_FONT) {
710 
711 			int arg = *s++;
712 
713 			if (c == ZC_NEW_FONT)
714 				current_font = arg;
715 			if (c == ZC_NEW_STYLE)
716 				current_style = arg;
717 
718 		} else
719 			width += os_char_width(c);
720 	}
721 	current_font = saved_font;
722 	current_style = saved_style;
723 
724 	return width;
725 } /* os_string_width */
726 
727 
728 /*
729  * os_set_cursor
730  *
731  * Place the text cursor at the given coordinates. Top left is (1,1).
732  *
733  */
os_set_cursor(int y,int x)734 void os_set_cursor(int y, int x)
735 {
736 	cursor_y = y - 1;
737 	cursor_x = x - 1;
738 } /* os_set_cursor */
739 
740 
741 /*
742  * os_more_prompt
743  *
744  * Display a MORE prompt, wait for a keypress and remove the MORE
745  * prompt from the screen.
746  *
747  */
os_more_prompt(void)748 void os_more_prompt(void)
749 {
750 	int saved_x;
751 
752 	/* Save text font and style */
753 	int saved_font = current_font;
754 	int saved_style = current_style;
755 
756 	/* Choose plain text style */
757 	current_font = TEXT_FONT;
758 	current_style = 0;
759 
760 	adjust_style();
761 
762 	/* Wait until the user presses a key */
763 	saved_x = cursor_x;
764 	os_display_string((zchar *) "[MORE]");
765 	os_read_key(0, TRUE);
766 
767 	os_erase_area(cursor_y + 1,
768 		      saved_x + 1, cursor_y + z_header.font_height, cursor_x + 1, -1);
769 
770 	cursor_x = saved_x;
771 
772 	/* Restore text font and style */
773 	current_font = saved_font;
774 	current_style = saved_style;
775 
776 	adjust_style();
777 } /* os_more_prompt */
778