1 /* screen.c - Generic screen manipulation
2 * Copyright (c) 1995-1997 Stefan Jokisch
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 */
20
21 #include "frotz.h"
22
23 extern void set_header_extension(int, zword);
24
25 extern int direct_call(zword);
26
27 static struct {
28 enum story story_id;
29 int pic;
30 int pic1;
31 int pic2;
32 } mapper[] = {
33 { ZORK_ZERO, 5, 497, 498},
34 { ZORK_ZERO, 6, 501, 502},
35 { ZORK_ZERO, 7, 499, 500},
36 { ZORK_ZERO, 8, 503, 504},
37 { ARTHUR, 54, 170, 171},
38 { SHOGUN, 50, 61, 62},
39 { UNKNOWN, 0, 0, 0}
40 };
41
42 /* These are usually out of date. Always update before using. */
43 static int font_height = 1;
44 static int font_width = 1;
45
46 static bool input_redraw = FALSE;
47 static bool more_prompts = TRUE;
48 static bool discarding = FALSE;
49 static bool cursor = TRUE;
50
51 static int input_window = 0;
52
53 static Zwindow wp[8], *cwp = wp;
54
curwinrec()55 Zwindow *curwinrec()
56 {
57 return cwp;
58 }
59
60
61 /*
62 * winarg0
63 *
64 * Return the window number in zargs[0]. In V6 only, -3 refers to the
65 * current window.
66 *
67 */
winarg0(void)68 static zword winarg0(void)
69 {
70 if (z_header.version == V6 && (short)zargs[0] == -3)
71 return cwin;
72
73 if (zargs[0] >= ((z_header.version == V6) ? 8 : 2))
74 runtime_error(ERR_ILL_WIN);
75
76 return zargs[0];
77 } /* winarg0 */
78
79
80 /*
81 * winarg2
82 *
83 * Return the (optional) window number in zargs[2]. -3 refers to the
84 * current window. This optional window number was only used by some
85 * V6 opcodes: set_cursor, set_margins, set_colour.
86 *
87 */
winarg2(void)88 static zword winarg2(void)
89 {
90 if (zargc < 3 || (short)zargs[2] == -3)
91 return cwin;
92
93 if (zargs[2] >= 8)
94 runtime_error(ERR_ILL_WIN);
95
96 return zargs[2];
97 } /* winarg2 */
98
99
100 /*
101 * update_cursor
102 *
103 * Move the hardware cursor to make it match the window properties.
104 *
105 */
update_cursor(void)106 static void update_cursor(void)
107 {
108 os_set_cursor(cwp->y_pos + cwp->y_cursor - 1,
109 cwp->x_pos + cwp->x_cursor - 1);
110 } /* update_cursor */
111
112
113 /*
114 * reset_cursor
115 *
116 * Reset the cursor of a given window to its initial position.
117 *
118 */
reset_cursor(zword win)119 static void reset_cursor(zword win)
120 {
121 int lines = 0;
122
123 if (z_header.version <= V4 && win == 0)
124 lines = wp[0].y_size / hi(wp[0].font_size) - 1;
125
126 wp[win].y_cursor = hi(wp[0].font_size) * lines + 1;
127 wp[win].x_cursor = wp[win].left + 1;
128
129 if (win == cwin)
130 update_cursor();
131 } /* reset_cursor */
132
133
134 /*
135 * reset_screen
136 *
137 * Do any interface-independent screen cleanup prior to exiting the game.
138 *
139 */
reset_screen(void)140 void reset_screen(void)
141 {
142 if (need_newline_at_exit)
143 new_line();
144 } /* reset_screen */
145
146
147 /*
148 * set_more_prompts
149 *
150 * Turn more prompts on/off.
151 *
152 */
set_more_prompts(bool flag)153 void set_more_prompts(bool flag)
154 {
155 if (flag && !more_prompts)
156 cwp->line_count = 0;
157 more_prompts = flag;
158 } /* set_more_prompts */
159
160
161 /*
162 * units_left
163 *
164 * Return the #screen units from the cursor to the end of the line.
165 *
166 */
units_left(void)167 static int units_left(void)
168 {
169 return cwp->x_size - cwp->right - cwp->x_cursor + 1;
170 } /* units_left */
171
172
173 /*
174 * get_max_width
175 *
176 * Return maximum width of a line in the given window. This is used in
177 * connection with the extended output stream #3 call in V6.
178 *
179 */
get_max_width(zword win)180 zword get_max_width(zword win)
181 {
182 if (z_header.version == V6) {
183 if (win >= 8)
184 runtime_error(ERR_ILL_WIN);
185 return wp[win].x_size - wp[win].left - wp[win].right;
186 } else
187 return 0xffff;
188 } /* get_max_width */
189
190
191 /*
192 * countdown
193 *
194 * Decrement the newline counter. Call the newline interrupt when the
195 * counter hits zero. This is a helper function for screen_new_line.
196 *
197 */
countdown(void)198 static void countdown(void)
199 {
200 if (cwp->nl_countdown != 0) {
201 if (--cwp->nl_countdown == 0)
202 direct_call(cwp->nl_routine);
203 }
204 } /* countdown */
205
206
207 /*
208 * screen_new_line
209 *
210 * Print a newline to the screen.
211 *
212 */
screen_new_line(void)213 void screen_new_line(void)
214 {
215 if (discarding)
216 return;
217
218 /* Handle newline interrupts at the start (for most cases) */
219 if (z_header.interpreter_number != INTERP_MSDOS || story_id != ZORK_ZERO
220 || z_header.release != 393)
221 countdown();
222
223 /* Check whether the last input line gets destroyed */
224 if (input_window == cwin)
225 input_redraw = TRUE;
226
227 /* If the cursor has not reached the bottom line, then move it to
228 the next line; otherwise scroll the window or reset the cursor
229 to the top left. */
230 cwp->x_cursor = cwp->left + 1;
231
232 os_font_data(0, &font_height, &font_width);
233 if (cwp->y_cursor + 2 * font_height - 1 > cwp->y_size)
234 if (enable_scrolling) {
235 zword y = cwp->y_pos;
236 zword x = cwp->x_pos;
237 os_scroll_area(y,
238 x,
239 y + cwp->y_size - 1,
240 x + cwp->x_size - 1, font_height);
241 } else
242 cwp->y_cursor = 1;
243 else
244 cwp->y_cursor += font_height;
245
246 update_cursor();
247
248 /* See if we need to print a more prompt (unless the game has set
249 the line counter to -999 in order to suppress more prompts). */
250 if (enable_scrolling && (short)cwp->line_count != -999) {
251 zword above = (cwp->y_cursor - 1) / font_height;
252 zword below = (cwp->y_size - cwp->y_cursor + 1) / font_height;
253 cwp->line_count++;
254 if ((short)cwp->line_count >= (short)above + below - 1) {
255 if (more_prompts)
256 os_more_prompt();
257 cwp->line_count = f_setup.context_lines;
258 }
259 }
260
261 /* Handle newline interrupts at the end for Zork Zero under DOS */
262 if (z_header.interpreter_number == INTERP_MSDOS && story_id == ZORK_ZERO
263 && z_header.release == 393)
264 countdown();
265 } /* screen_new_line */
266
267
268 /*
269 * screen_char
270 *
271 * Display a single character on the screen.
272 *
273 */
screen_char(zchar c)274 void screen_char(zchar c)
275 {
276 int width;
277
278 if (discarding)
279 return;
280
281 if (c == ZC_INDENT && cwp->x_cursor != cwp->left + 1)
282 c = ' ';
283
284 if (units_left() < (width = os_char_width(c))) {
285 if (!enable_wrapping) {
286 cwp->x_cursor = cwp->x_size - cwp->right;
287 return;
288 }
289 screen_new_line();
290 }
291 os_display_char(c);
292 cwp->x_cursor += width;
293
294 } /* screen_char */
295
296
297 /*
298 * screen_word
299 *
300 * Display a string of characters on the screen. If the word doesn't fit
301 * then use wrapping or clipping depending on the current setting of the
302 * enable_wrapping flag.
303 *
304 */
screen_word(const zchar * s)305 void screen_word(const zchar * s)
306 {
307 int width;
308
309 if (discarding)
310 return;
311
312 if (*s == ZC_INDENT && cwp->x_cursor != cwp->left + 1)
313 screen_char(*s++);
314
315 if (units_left() < (width = os_string_width(s))) {
316 if (!enable_wrapping) {
317 zchar c;
318 while ((c = *s++) != 0) {
319 if (c == ZC_NEW_FONT || c == ZC_NEW_STYLE) {
320 int arg = (int)*s++;
321 if (c == ZC_NEW_FONT)
322 os_set_font(arg);
323 if (c == ZC_NEW_STYLE)
324 os_set_text_style(arg);
325 } else
326 screen_char(c);
327 }
328 return;
329 }
330 if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP)
331 width = os_string_width(++s);
332
333 #ifdef AMIGA
334 if (cwin == 0)
335 Justifiable();
336 #endif
337
338 screen_new_line();
339 }
340 os_display_string(s);
341 cwp->x_cursor += width;
342 } /* screen_word */
343
344
345 /*
346 * screen_write_input
347 *
348 * Display an input line on the screen. This is required during playback.
349 *
350 */
screen_write_input(const zchar * buf,zchar key)351 void screen_write_input(const zchar * buf, zchar key)
352 {
353 int width;
354
355 if (units_left() < (width = os_string_width(buf)))
356 screen_new_line();
357
358 os_display_string(buf);
359 cwp->x_cursor += width;
360
361 if (key == ZC_RETURN)
362 screen_new_line();
363 } /* screen_write_input */
364
365
366 /*
367 * screen_erase_input
368 *
369 * Remove an input line that has already been printed from the screen
370 * as if it was deleted by the player. This could be necessary during
371 * playback.
372 *
373 */
screen_erase_input(const zchar * buf)374 void screen_erase_input(const zchar * buf)
375 {
376 if (buf[0] != 0) {
377 int width = os_string_width(buf);
378
379 zword y;
380 zword x;
381
382 cwp->x_cursor -= width;
383
384 y = cwp->y_pos + cwp->y_cursor - 1;
385 x = cwp->x_pos + cwp->x_cursor - 1;
386
387 os_font_data(0, &font_height, &font_width);
388 os_erase_area(y, x, y + font_height - 1, x + width - 1, -1);
389 os_set_cursor(y, x);
390 }
391 } /* screen_erase_input */
392
393
394 /*
395 * console_read_input
396 *
397 * Read an input line from the keyboard and return the terminating key.
398 *
399 */
console_read_input(int max,zchar * buf,zword timeout,bool continued)400 zchar console_read_input(int max, zchar * buf, zword timeout, bool continued)
401 {
402 zchar key;
403 int i;
404
405 /* Make sure there is some space for input */
406 if (cwin == 0 && units_left() + os_string_width(buf) < 10 * font_width)
407 screen_new_line();
408
409 /* Make sure the input line is visible */
410 if (continued && input_redraw)
411 screen_write_input(buf, -1);
412
413 input_window = cwin;
414 input_redraw = FALSE;
415
416 /* Get input line from IO interface */
417 cwp->x_cursor -= os_string_width(buf);
418 key = os_read_line(max, buf, timeout, units_left(), continued);
419 cwp->x_cursor += os_string_width(buf);
420
421 if (key != ZC_TIME_OUT) {
422 for (i = 0; i < 8; i++)
423 wp[i].line_count = 0;
424 }
425
426 /* Add a newline if the input was terminated normally */
427 if (key == ZC_RETURN)
428 screen_new_line();
429
430 return key;
431 } /* console_read_input */
432
433
434 /*
435 * console_read_key
436 *
437 * Read a single keystroke and return it.
438 *
439 */
console_read_key(zword timeout)440 zchar console_read_key(zword timeout)
441 {
442 zchar key;
443 int i;
444
445 key = os_read_key(timeout, cursor);
446
447 if (key != ZC_TIME_OUT)
448 for (i = 0; i < 8; i++)
449 wp[i].line_count = 0;
450
451 return key;
452
453 } /* console_read_key */
454
455
456 /*
457 * update_attributes
458 *
459 * Set the three enable_*** variables to make them match the attributes
460 * of the current window.
461 *
462 */
update_attributes(void)463 static void update_attributes(void)
464 {
465 zword attr = cwp->attribute;
466
467 enable_wrapping = attr & 1;
468 enable_scrolling = attr & 2;
469 enable_scripting = attr & 4;
470 enable_buffering = attr & 8;
471
472 /* Some story files forget to select wrapping for printing hints */
473
474 if (story_id == ZORK_ZERO && z_header.release == 366)
475 if (cwin == 0)
476 enable_wrapping = TRUE;
477 if (story_id == SHOGUN && z_header.release <= 295)
478 if (cwin == 0)
479 enable_wrapping = TRUE;
480 } /* update_attributes */
481
482
483 /*
484 * refresh_text_style
485 *
486 * Set the right text style. This can be necessary when the fixed font
487 * flag is changed, or when a new window is selected, or when the game
488 * uses the set_text_style opcode.
489 *
490 */
refresh_text_style(void)491 void refresh_text_style(void)
492 {
493 zword style;
494
495 if (z_header.version != V6) {
496 style = wp[0].style;
497
498 if (cwin != 0 || z_header.flags & FIXED_FONT_FLAG)
499 style |= FIXED_WIDTH_STYLE;
500 } else
501 style = cwp->style;
502
503 if (!ostream_memory && ostream_screen && enable_buffering) {
504 print_char(ZC_NEW_STYLE);
505 print_char(style);
506
507 } else
508 os_set_text_style(style);
509 } /* refresh_text_style */
510
511
512 /*
513 * set_window
514 *
515 * Set the current window. In V6 every window has its own set of window
516 * properties such as colours, text style, cursor position and size.
517 *
518 */
set_window(zword win)519 static void set_window(zword win)
520 {
521 flush_buffer();
522
523 cwin = win;
524 cwp = wp + win;
525
526 update_attributes();
527
528 if (z_header.version == V6) {
529 os_set_colour(lo(cwp->colour), hi(cwp->colour));
530
531 if (os_font_data(cwp->font, &font_height, &font_width))
532 os_set_font(cwp->font);
533
534 os_set_text_style(cwp->style);
535 } else
536 refresh_text_style();
537
538 if (z_header.version != V6 && win != 0) {
539 wp[win].y_cursor = 1;
540 wp[win].x_cursor = 1;
541 }
542
543 update_cursor();
544 } /* set_window */
545
546
547 /*
548 * erase_window
549 *
550 * Erase a window to background colour.
551 *
552 */
erase_window(zword win)553 void erase_window(zword win)
554 {
555 zword y = wp[win].y_pos;
556 zword x = wp[win].x_pos;
557
558 if (z_header.version == V6 && win != cwin
559 && z_header.interpreter_number != INTERP_AMIGA)
560 os_set_colour(lo(wp[win].colour), hi(wp[win].colour));
561
562 os_erase_area(y,
563 x, y + wp[win].y_size - 1, x + wp[win].x_size - 1, win);
564
565 if (z_header.version == V6 && win != cwin
566 && z_header.interpreter_number != INTERP_AMIGA)
567 os_set_colour(lo(cwp->colour), hi(cwp->colour));
568
569 reset_cursor(win);
570
571 wp[win].line_count = 0;
572 } /* erase_window */
573
574
575 /*
576 * split_window
577 *
578 * Divide the screen into upper (1) and lower (0) windows. In V3 the upper
579 * window appears below the status line.
580 *
581 */
split_window(zword height)582 void split_window(zword height)
583 {
584 zword stat_height = 0;
585
586 flush_buffer();
587
588 /* Calculate height of status line and upper window */
589 if (z_header.version != V6)
590 height *= hi(wp[1].font_size);
591
592 if (z_header.version <= V3)
593 stat_height = hi(wp[7].font_size);
594
595 /* Cursor of upper window mustn't be swallowed by the lower window */
596 wp[1].y_cursor += wp[1].y_pos - 1 - stat_height;
597
598 wp[1].y_pos = 1 + stat_height;
599 wp[1].y_size = height;
600
601 if ((short)wp[1].y_cursor > (short)wp[1].y_size)
602 reset_cursor(1);
603
604 /* Cursor of lower window mustn't be swallowed by the upper window */
605 wp[0].y_cursor += wp[0].y_pos - 1 - stat_height - height;
606
607 wp[0].y_pos = 1 + stat_height + height;
608 wp[0].y_size = z_header.screen_height - stat_height - height;
609
610 if ((short)wp[0].y_cursor < 1)
611 reset_cursor(0);
612
613 /* Erase the upper window in V3 only */
614 if (z_header.version == V3 && height != 0)
615 erase_window(1);
616
617 } /* split_window */
618
619
620 /*
621 * erase_screen
622 *
623 * Erase the entire screen to background colour.
624 *
625 */
erase_screen(zword win)626 static void erase_screen(zword win)
627 {
628 int i;
629
630 os_erase_area(1, 1, z_header.screen_height, z_header.screen_width, -2);
631
632 if ((short)win == -1) {
633 split_window(0);
634 set_window(0);
635 reset_cursor(0);
636 }
637
638 for (i = 0; i < 8; i++)
639 wp[i].line_count = 0;
640
641 } /* erase_screen */
642
643
644 /*
645 * resize_screen
646 *
647 * Try to adapt the window properties to a new screen size.
648 *
649 */
resize_screen(void)650 void resize_screen(void)
651 {
652 /* V6 games are asked to redraw. Other versions have no means for that
653 so we do what we can. */
654 if (z_header.version == V6)
655 z_header.flags |= REFRESH_FLAG;
656 else {
657 int scroll, h;
658
659 wp[0].x_size = z_header.screen_width;
660 if (wp[0].x_cursor > z_header.screen_width)
661 wp[0].x_cursor = z_header.screen_width;
662 wp[1].x_size = z_header.screen_width;
663 if (wp[1].x_cursor > z_header.screen_width)
664 wp[1].x_cursor = z_header.screen_width;
665 wp[7].x_size = z_header.screen_width;
666 if (wp[7].x_cursor > z_header.screen_width)
667 wp[7].x_cursor = z_header.screen_width;
668
669 h = z_header.screen_height - wp[1].y_size - wp[7].y_size;
670 if (h > 0) {
671 wp[0].y_size = h;
672 scroll = wp[0].y_cursor - wp[0].y_size;
673 } else {
674 /* Just make a one line window at the bottom of the screen. */
675 /*XXX We should probably adjust the other windows. But how? */
676 wp[0].y_size = 1;
677 scroll =
678 wp[0].y_pos + wp[0].y_cursor - z_header.screen_height - 1;
679 wp[0].y_pos = z_header.screen_height;
680 }
681 if (scroll > 0) {
682 wp[0].y_cursor = wp[0].y_size;
683 os_repaint_window(0, wp[0].y_pos + scroll, wp[0].y_pos,
684 wp[0].x_pos, wp[0].y_size,
685 wp[0].x_size);
686 }
687 }
688 } /* resize_screen */
689
690
691 /*
692 * restart_screen
693 *
694 * Prepare the screen for a new game.
695 *
696 */
restart_screen(void)697 void restart_screen(void)
698 {
699 /* Use default settings */
700 os_set_colour(z_header.default_foreground, z_header.default_background);
701
702 if (os_font_data(TEXT_FONT, &font_height, &font_width))
703 os_set_font(TEXT_FONT);
704
705 os_set_text_style(0);
706
707 cursor = TRUE;
708
709 /* Initialise window properties */
710 mwin = 1;
711 for (cwp = wp; cwp < wp + 8; cwp++) {
712 cwp->y_pos = 1;
713 cwp->x_pos = 1;
714 cwp->y_size = 0;
715 cwp->x_size = 0;
716 cwp->y_cursor = 1;
717 cwp->x_cursor = 1;
718 cwp->left = 0;
719 cwp->right = 0;
720 cwp->nl_routine = 0;
721 cwp->nl_countdown = 0;
722 cwp->style = 0;
723 cwp->colour =
724 (z_header.default_background << 8) | z_header.default_foreground;
725 cwp->font = TEXT_FONT;
726 cwp->font_size = (font_height << 8) | font_width;
727 cwp->attribute = 8;
728 }
729
730 /* Prepare lower/upper windows and status line */
731 wp[0].attribute = 15;
732
733 wp[0].left = f_setup.left_margin;
734 wp[0].right = f_setup.right_margin;
735
736 wp[0].x_size = z_header.screen_width;
737 wp[1].x_size = z_header.screen_width;
738
739 if (z_header.version <= V3)
740 wp[7].x_size = z_header.screen_width;
741
742 os_restart_game(RESTART_WPROP_SET);
743
744 /* Clear the screen, unsplit it and select window 0 */
745 erase_screen((zword) (-1));
746
747 } /* restart_screen */
748
749
750 /*
751 * validate_click
752 *
753 * Return false if the last mouse click occurred outside the current
754 * mouse window; otherwise write the mouse arrow coordinates to the
755 * memory of the header extension table and return true.
756 *
757 */
validate_click(void)758 bool validate_click(void)
759 {
760 if (mwin >= 0) {
761 if (mouse_y < wp[mwin].y_pos
762 || mouse_y >= wp[mwin].y_pos + wp[mwin].y_size)
763 return FALSE;
764 if (mouse_x < wp[mwin].x_pos
765 || mouse_x >= wp[mwin].x_pos + wp[mwin].x_size)
766 return FALSE;
767
768 z_header.x_mouse_y = mouse_y - wp[mwin].y_pos + 1;
769 z_header.x_mouse_x = mouse_x - wp[mwin].x_pos + 1;
770 } else {
771 if (mouse_y < 1 || mouse_y > z_header.screen_height)
772 return FALSE;
773 if (mouse_x < 1 || mouse_x > z_header.screen_width)
774 return FALSE;
775
776 z_header.x_mouse_y = mouse_y;
777 z_header.x_mouse_x = mouse_x;
778
779 }
780
781 if (z_header.version != V6) {
782 z_header.x_mouse_y = (z_header.x_mouse_y - 1) / z_header.font_height + 1;
783 z_header.x_mouse_x = (z_header.x_mouse_x - 1) / z_header.font_width + 1;
784 }
785
786 set_header_extension(HX_MOUSE_Y, z_header.x_mouse_y);
787 set_header_extension(HX_MOUSE_X, z_header.x_mouse_x);
788
789 return TRUE;
790 } /* validate_click */
791
792
793 /*
794 * screen_mssg_on
795 *
796 * Start printing a so-called debugging message. The contents of the
797 * message are passed to the message stream, a Frotz specific output
798 * stream with maximum priority.
799 *
800 */
screen_mssg_on(void)801 void screen_mssg_on(void)
802 {
803 if (cwin == 0) { /* messages in window 0 only */
804 os_set_text_style(0);
805
806 if (cwp->x_cursor != cwp->left + 1)
807 screen_new_line();
808
809 screen_char(ZC_INDENT);
810 } else
811 discarding = TRUE; /* discard messages in other windows */
812 } /* screen_mssg_on */
813
814
815 /*
816 * screen_mssg_off
817 *
818 * Stop printing a "debugging" message.
819 *
820 */
screen_mssg_off(void)821 void screen_mssg_off(void)
822 {
823 if (cwin == 0) { /* messages in window 0 only */
824 screen_new_line();
825 refresh_text_style();
826 } else
827 discarding = FALSE; /* message has been discarded */
828
829 } /* screen_mssg_off */
830
831
832 /*
833 * z_buffer_mode, turn text buffering on/off.
834 *
835 * zargs[0] = new text buffering flag (0 or 1)
836 *
837 */
z_buffer_mode(void)838 void z_buffer_mode(void)
839 {
840 /* Infocom's V6 games rarely use the buffer_mode opcode. If they do
841 then only to print text immediately, without any delay. This was
842 used to give the player some sign of life while the game was
843 spending much time on parsing a complicated input line. (To turn
844 off word wrapping, V6 games use the window_style opcode instead.)
845 Today we can afford to ignore buffer_mode in V6. */
846
847 if (z_header.version != V6) {
848 flush_buffer();
849 wp[0].attribute &= ~8;
850
851 if (zargs[0] != 0)
852 wp[0].attribute |= 8;
853
854 update_attributes();
855 }
856 } /* z_buffer_mode */
857
858
859 /*
860 * z_draw_picture, draw a picture.
861 *
862 * zargs[0] = number of picture to draw
863 * zargs[1] = y-coordinate of top left corner
864 * zargs[2] = x-coordinate of top left corner
865 *
866 */
z_draw_picture(void)867 void z_draw_picture(void)
868 {
869 zword pic = zargs[0];
870
871 zword y = zargs[1];
872 zword x = zargs[2];
873
874 int i;
875
876 flush_buffer();
877
878 if (y == 0) /* use cursor line if y-coordinate is 0 */
879 y = cwp->y_cursor;
880 if (x == 0) /* use cursor column if x-coordinate is 0 */
881 x = cwp->x_cursor;
882
883 y += cwp->y_pos - 1;
884 x += cwp->x_pos - 1;
885
886 /* The following is necessary to make Amiga and Macintosh story
887 files work with MCGA graphics files. Some screen-filling
888 pictures of the original Amiga release like the borders of
889 Zork Zero were split into several MCGA pictures (left, right
890 and top borders). We pretend this has not happened. */
891
892 for (i = 0; mapper[i].story_id != UNKNOWN; i++) {
893 if (story_id == mapper[i].story_id && pic == mapper[i].pic) {
894 int height1, width1;
895 int height2, width2;
896
897 int delta = 0;
898
899 os_picture_data(pic, &height1, &width1);
900 os_picture_data(mapper[i].pic2, &height2, &width2);
901
902 if (story_id == ARTHUR && pic == 54)
903 delta = z_header.screen_width / 160;
904
905 os_draw_picture(mapper[i].pic1, y + height1, x + delta);
906 os_draw_picture(mapper[i].pic2, y + height1,
907 x + width1 - width2 - delta);
908
909 }
910 }
911
912 os_draw_picture(pic, y, x);
913 if (story_id == SHOGUN)
914 if (pic == 3) {
915 int height, width;
916
917 os_picture_data(59, &height, &width);
918 os_draw_picture(59, y, z_header.screen_width - width + 1);
919 }
920 } /* z_draw_picture */
921
922
923 /*
924 * z_erase_line, erase the line starting at the cursor position.
925 *
926 * zargs[0] = 1 + #units to erase (1 clears to the end of the line)
927 *
928 */
z_erase_line(void)929 void z_erase_line(void)
930 {
931 zword pixels = zargs[0];
932 zword y, x;
933
934 flush_buffer();
935
936 /* Clipping at the right margin of the current window */
937 if (--pixels == 0 || pixels > units_left())
938 pixels = units_left();
939
940 /* Erase from cursor position */
941 y = cwp->y_pos + cwp->y_cursor - 1;
942 x = cwp->x_pos + cwp->x_cursor - 1;
943
944 os_font_data(0, &font_height, &font_width);
945 os_erase_area(y, x, y + font_height - 1, x + pixels - 1, -1);
946 } /* z_erase_line */
947
948
949 /*
950 * z_erase_picture, erase a picture with background colour.
951 *
952 * zargs[0] = number of picture to erase
953 * zargs[1] = y-coordinate of top left corner (optional)
954 * zargs[2] = x-coordinate of top left corner (optional)
955 *
956 */
z_erase_picture(void)957 void z_erase_picture(void)
958 {
959 int height, width;
960
961 zword y = zargs[1];
962 zword x = zargs[2];
963
964 flush_buffer();
965
966 if (y == 0) /* use cursor line if y-coordinate is 0 */
967 y = cwp->y_cursor;
968 if (x == 0) /* use cursor column if x-coordinate is 0 */
969 x = cwp->x_cursor;
970
971 os_picture_data(zargs[0], &height, &width);
972
973 y += cwp->y_pos - 1;
974 x += cwp->x_pos - 1;
975
976 os_erase_area(y, x, y + height - 1, x + width - 1, -1);
977 } /* z_erase_picture */
978
979
980 /*
981 * z_erase_window, erase a window or the screen to background colour.
982 *
983 * zargs[0] = window (-3 current, -2 screen, -1 screen & unsplit)
984 *
985 */
z_erase_window(void)986 void z_erase_window(void)
987 {
988 flush_buffer();
989
990 if ((short)zargs[0] == -1 || (short)zargs[0] == -2)
991 erase_screen(zargs[0]);
992 else
993 erase_window(winarg0());
994 } /* z_erase_window */
995
996
997 /*
998 * z_get_cursor, write the cursor coordinates into a table.
999 *
1000 * zargs[0] = address to write information to
1001 *
1002 */
z_get_cursor(void)1003 void z_get_cursor(void)
1004 {
1005 zword y, x;
1006
1007 flush_buffer();
1008
1009 y = cwp->y_cursor;
1010 x = cwp->x_cursor;
1011
1012 if (z_header.version != V6) { /* convert to grid positions */
1013 y = (y - 1) / z_header.font_height + 1;
1014 x = (x - 1) / z_header.font_width + 1;
1015 }
1016
1017 storew((zword) (zargs[0] + 0), y);
1018 storew((zword) (zargs[0] + 2), x);
1019 } /* z_get_cursor */
1020
1021
1022 /*
1023 * z_get_wind_prop, store the value of a window property.
1024 *
1025 * zargs[0] = window (-3 is the current one)
1026 * zargs[1] = number of window property to be stored
1027 *
1028 */
z_get_wind_prop(void)1029 void z_get_wind_prop(void)
1030 {
1031 flush_buffer();
1032
1033 if (zargs[1] >= 16)
1034 runtime_error(ERR_ILL_WIN_PROP);
1035
1036 store(((zword *) (wp + winarg0()))[zargs[1]]);
1037 } /* z_get_wind_prop */
1038
1039
1040 /*
1041 * z_mouse_window, select a window as mouse window.
1042 *
1043 * zargs[0] = window number (-3 is the current) or -1 for the screen
1044 *
1045 */
z_mouse_window(void)1046 void z_mouse_window(void)
1047 {
1048 mwin = ((short)zargs[0] == -1) ? -1 : winarg0();
1049 } /* z_mouse_window */
1050
1051
1052 /*
1053 * z_move_window, place a window on the screen.
1054 *
1055 * zargs[0] = window (-3 is the current one)
1056 * zargs[1] = y-coordinate
1057 * zargs[2] = x-coordinate
1058 *
1059 */
z_move_window(void)1060 void z_move_window(void)
1061 {
1062 zword win = winarg0();
1063
1064 flush_buffer();
1065
1066 wp[win].y_pos = zargs[1];
1067 wp[win].x_pos = zargs[2];
1068
1069 if (win == cwin)
1070 update_cursor();
1071 } /* z_move_window */
1072
1073
1074 /*
1075 * z_picture_data, get information on a picture or the graphics file.
1076 *
1077 * zargs[0] = number of picture or 0 for the graphics file
1078 * zargs[1] = address to write information to
1079 *
1080 */
z_picture_data(void)1081 void z_picture_data(void)
1082 {
1083 zword pic = zargs[0];
1084 zword table = zargs[1];
1085
1086 int height, width;
1087 int i;
1088
1089 bool avail = os_picture_data(pic, &height, &width);
1090
1091 for (i = 0; mapper[i].story_id != UNKNOWN; i++)
1092 if (story_id == mapper[i].story_id) {
1093 if (pic == mapper[i].pic) {
1094 int height2, width2;
1095
1096 avail &=
1097 os_picture_data(mapper[i].pic1, &height2,
1098 &width2);
1099 avail &=
1100 os_picture_data(mapper[i].pic2, &height2,
1101 &width2);
1102
1103 height += height2;
1104
1105 } else if (pic == mapper[i].pic1
1106 || pic == mapper[i].pic2)
1107 avail = FALSE;
1108 }
1109
1110 storew((zword) (table + 0), (zword) (height));
1111 storew((zword) (table + 2), (zword) (width));
1112
1113 branch(avail);
1114 } /* z_picture_data */
1115
1116
1117 /*
1118 * z_picture_table, prepare a group of pictures for faster display.
1119 *
1120 * zargs[0] = address of table holding the picture numbers
1121 *
1122 */
z_picture_table(void)1123 void z_picture_table(void)
1124 {
1125 /* This opcode is used by Shogun and Zork Zero when the player
1126 * encounters built-in games such as Peggleboz. Nowadays it is
1127 * not very helpful to hold the picture data in memory because
1128 * even a small disk cache avoids re-loading of data.
1129 */
1130 } /* z_picture_table */
1131
1132
1133 /*
1134 * z_print_table, print ASCII text in a rectangular area.
1135 *
1136 * zargs[0] = address of text to be printed
1137 * zargs[1] = width of rectangular area
1138 * zargs[2] = height of rectangular area (optional)
1139 * zargs[3] = number of char's to skip between lines (optional)
1140 *
1141 */
z_print_table(void)1142 void z_print_table(void)
1143 {
1144 zword addr = zargs[0];
1145 zword x;
1146 int i, j;
1147
1148 flush_buffer();
1149
1150 /* Supply default arguments */
1151 if (zargc < 3)
1152 zargs[2] = 1;
1153 if (zargc < 4)
1154 zargs[3] = 0;
1155
1156 /* Write text in width x height rectangle */
1157 x = cwp->x_cursor;
1158
1159 for (i = 0; i < zargs[2]; i++) {
1160 if (i != 0) {
1161 if (z_header.version != V6 && cwin == 0) {
1162 new_line();
1163 } else {
1164 flush_buffer();
1165 os_font_data(0, &font_height, &font_width);
1166 cwp->y_cursor += font_height;
1167 cwp->x_cursor = x;
1168 update_cursor();
1169 }
1170 }
1171
1172 for (j = 0; j < zargs[1]; j++) {
1173 zbyte c;
1174
1175 LOW_BYTE(addr, c)
1176 addr++;
1177 print_char(c);
1178 }
1179 addr += zargs[3];
1180 }
1181 } /* z_print_table */
1182
1183
1184 /*
1185 * z_put_wind_prop, set the value of a window property.
1186 *
1187 * zargs[0] = window (-3 is the current one)
1188 * zargs[1] = number of window property to set
1189 * zargs[2] = value to set window property to
1190 *
1191 */
z_put_wind_prop(void)1192 void z_put_wind_prop(void)
1193 {
1194 flush_buffer();
1195
1196 if (zargs[1] >= 16)
1197 runtime_error(ERR_ILL_WIN_PROP);
1198
1199 ((zword *) (wp + winarg0()))[zargs[1]] = zargs[2];
1200 } /* z_put_wind_prop */
1201
1202
1203 /*
1204 * z_scroll_window, scroll a window up or down.
1205 *
1206 * zargs[0] = window (-3 is the current one)
1207 * zargs[1] = #screen units to scroll up (positive) or down (negative)
1208 *
1209 */
z_scroll_window(void)1210 void z_scroll_window(void)
1211 {
1212 zword win = winarg0();
1213 zword y, x;
1214
1215 flush_buffer();
1216
1217 /* Use the correct set of colours when scrolling the window */
1218 if (win != cwin && z_header.interpreter_number != INTERP_AMIGA)
1219 os_set_colour(lo(wp[win].colour), hi(wp[win].colour));
1220
1221 y = wp[win].y_pos;
1222 x = wp[win].x_pos;
1223
1224 os_scroll_area(y,
1225 x,
1226 y + wp[win].y_size - 1,
1227 x + wp[win].x_size - 1, (short)zargs[1]);
1228
1229 if (win != cwin && z_header.interpreter_number != INTERP_AMIGA)
1230 os_set_colour(lo(cwp->colour), hi(cwp->colour));
1231 } /* z_scroll_window */
1232
1233
1234 /*
1235 * z_set_colour, set the foreground and background colours.
1236 *
1237 * zargs[0] = foreground colour
1238 * zargs[1] = background colour
1239 * zargs[2] = window (-3 is the current one, optional)
1240 *
1241 */
z_set_colour(void)1242 void z_set_colour(void)
1243 {
1244 zword win = (z_header.version == V6) ? winarg2() : 0;
1245
1246 zword fg = zargs[0];
1247 zword bg = zargs[1];
1248
1249 flush_buffer();
1250
1251 if ((short)fg == -1) /* colour -1 is the colour at the cursor */
1252 fg = os_peek_colour();
1253 if ((short)bg == -1)
1254 bg = os_peek_colour();
1255
1256 if (fg == 0) /* colour 0 means keep current colour */
1257 fg = lo(wp[win].colour);
1258 if (bg == 0)
1259 bg = hi(wp[win].colour);
1260
1261 if (fg == 1) /* colour 1 is the system default colour */
1262 fg = z_header.default_foreground;
1263 if (bg == 1)
1264 bg = z_header.default_background;
1265
1266 if (z_header.version == V6 && z_header.interpreter_number == INTERP_AMIGA)
1267 /* Changing colours of window 0 affects the entire screen */
1268 if (win == 0) {
1269 int i;
1270 for (i = 1; i < 8; i++) {
1271 zword bg2 = hi(wp[i].colour);
1272 zword fg2 = lo(wp[i].colour);
1273
1274 if (bg2 < 16)
1275 bg2 =
1276 (bg2 == lo(wp[0].colour)) ? fg : bg;
1277 if (fg2 < 16)
1278 fg2 =
1279 (fg2 == lo(wp[0].colour)) ? fg : bg;
1280
1281 wp[i].colour = (bg2 << 8) | fg2;
1282
1283 }
1284
1285 }
1286
1287 wp[win].colour = (bg << 8) | fg;
1288
1289 if (win == cwin || z_header.version != V6)
1290 os_set_colour(fg, bg);
1291 } /* z_set_colour */
1292
1293
1294 /*
1295 * z_set_font, set the font for text output and store the previous font.
1296 *
1297 * zargs[0] = number of font or 0 to keep current font
1298 *
1299 */
z_set_font(void)1300 void z_set_font(void)
1301 {
1302 zword win = (z_header.version == V6) ? cwin : 0;
1303 zword font = zargs[0];
1304
1305 if (font != 0) {
1306 if (os_font_data(font, &font_height, &font_width)) {
1307 store(wp[win].font);
1308 wp[win].font = font;
1309 wp[win].font_size = (font_height << 8) | font_width;
1310
1311 if (!ostream_memory && ostream_screen
1312 && enable_buffering) {
1313 print_char(ZC_NEW_FONT);
1314 print_char(font);
1315
1316 } else
1317 os_set_font(font);
1318 } else
1319 store(0);
1320 } else
1321 store(wp[win].font);
1322 } /* z_set_font */
1323
1324
1325 /*
1326 * z_set_cursor, set the cursor position or turn the cursor on/off.
1327 *
1328 * zargs[0] = y-coordinate or -2/-1 for cursor on/off
1329 * zargs[1] = x-coordinate
1330 * zargs[2] = window (-3 is the current one, optional)
1331 *
1332 */
z_set_cursor(void)1333 void z_set_cursor(void)
1334 {
1335 zword win = (z_header.version == V6) ? winarg2() : 1;
1336
1337 zword y = zargs[0];
1338 zword x = zargs[1];
1339
1340 flush_buffer();
1341
1342 /* Supply default arguments */
1343 if (zargc < 3)
1344 zargs[2] = -3;
1345
1346 /* Handle cursor on/off */
1347 if ((short)y < 0) {
1348 if ((short)y == -2)
1349 cursor = TRUE;
1350 if ((short)y == -1)
1351 cursor = FALSE;
1352 return;
1353 }
1354
1355 /* Convert grid positions to screen units if this is not V6 */
1356 if (z_header.version != V6) {
1357 if (cwin == 0)
1358 return;
1359 y = (y - 1) * z_header.font_height + 1;
1360 x = (x - 1) * z_header.font_width + 1;
1361 }
1362
1363 /* Protect the margins */
1364 if (y == 0) /* use cursor line if y-coordinate is 0 */
1365 y = wp[win].y_cursor;
1366 if (x == 0) /* use cursor column if x-coordinate is 0 */
1367 x = wp[win].x_cursor;
1368 if (x <= wp[win].left || x > wp[win].x_size - wp[win].right)
1369 x = wp[win].left + 1;
1370
1371 /* Move the cursor */
1372 wp[win].y_cursor = y;
1373 wp[win].x_cursor = x;
1374
1375 if (win == cwin)
1376 update_cursor();
1377 } /* z_set_cursor */
1378
1379
1380 /*
1381 * z_set_margins, set the left and right margins of a window.
1382 *
1383 * zargs[0] = left margin in pixels
1384 * zargs[1] = right margin in pixels
1385 * zargs[2] = window (-3 is the current one, optional)
1386 *
1387 */
z_set_margins(void)1388 void z_set_margins(void)
1389 {
1390 zword win = winarg2();
1391
1392 flush_buffer();
1393
1394 wp[win].left = zargs[0];
1395 wp[win].right = zargs[1];
1396
1397 /* Protect the margins */
1398 if (wp[win].x_cursor <= zargs[0]
1399 || wp[win].x_cursor > wp[win].x_size - zargs[1]) {
1400
1401 wp[win].x_cursor = zargs[0] + 1;
1402
1403 if (win == cwin)
1404 update_cursor();
1405 }
1406 } /* z_set_margins */
1407
1408
1409 /*
1410 * z_set_text_style, set the style for text output.
1411 *
1412 * zargs[0] = style flags to set or 0 to reset text style
1413 *
1414 */
z_set_text_style(void)1415 void z_set_text_style(void)
1416 {
1417 zword win = (z_header.version == V6) ? cwin : 0;
1418 zword style = zargs[0];
1419
1420 wp[win].style |= style;
1421
1422 if (style == 0)
1423 wp[win].style = 0;
1424
1425 refresh_text_style();
1426 } /* z_set_text_style */
1427
1428
1429 /*
1430 * z_set_window, select the current window.
1431 *
1432 * zargs[0] = window to be selected (-3 is the current one)
1433 *
1434 */
z_set_window(void)1435 void z_set_window(void)
1436 {
1437 set_window(winarg0());
1438 } /* z_set_window */
1439
1440
1441 /*
1442 * pad_status_line
1443 *
1444 * Pad the status line with spaces up to the given position.
1445 *
1446 */
pad_status_line(int column)1447 static void pad_status_line(int column)
1448 {
1449 int spaces;
1450
1451 flush_buffer();
1452
1453 spaces = units_left() / os_char_width(' ') - column;
1454
1455 /* while (spaces--) */
1456 /* Justin Wesley's fix for narrow displays (Agenda PDA) */
1457 while (spaces-- > 0)
1458 screen_char(' ');
1459 } /* pad_status_line */
1460
1461
1462 /*
1463 * z_show_status, display the status line for V1 to V3 games.
1464 *
1465 * no zargs used
1466 *
1467 */
z_show_status(void)1468 void z_show_status(void)
1469 {
1470 zword global0;
1471 zword global1;
1472 zword global2;
1473 zword addr;
1474
1475 bool brief = FALSE;
1476
1477 /* One V5 game (Wishbringer Solid Gold) contains this opcode by
1478 accident, so just return if the version number does not fit */
1479 if (z_header.version >= V4)
1480 return;
1481
1482 /* Read all relevant global variables from the memory of the
1483 Z-machine into local variables */
1484 addr = z_header.globals;
1485 LOW_WORD(addr, global0)
1486 addr += 2;
1487 LOW_WORD(addr, global1)
1488 addr += 2;
1489 LOW_WORD(addr, global2)
1490 /* Frotz uses window 7 for the status line. Don't forget to select
1491 reverse and fixed width text style */
1492 set_window(7);
1493
1494 print_char(ZC_NEW_STYLE);
1495 print_char(REVERSE_STYLE | FIXED_WIDTH_STYLE);
1496
1497 /* If the screen width is below 55 characters then we have to use
1498 the brief status line format */
1499 if (z_header.screen_cols < 55)
1500 brief = TRUE;
1501
1502 /* Print the object description for the global variable 0 */
1503 print_char(' ');
1504 print_object(global0);
1505
1506 /* A header flag tells us whether we have to display the current
1507 time or the score/moves information */
1508 if (z_header.config & CONFIG_TIME) { /* print hours and minutes */
1509 zword hours;
1510
1511 /* Cutthroats puts 111 in the hour when the PC is not
1512 * wearing a watch. Most (all?) Infocom's interpreters
1513 * save for the Amiga one would handle 24-hour conversion
1514 * to am/pm notation by subtracting 12 from the hour if it's
1515 * greater than 12. So, by putting 111 in there,
1516 * subtracting 12 results in 99. The Amiga interpreter and
1517 * all modern interpreters do the conversion correctly.
1518 * The result is 3.
1519 */
1520 if (story_id == CUTTHROATS && global1 >= 12)
1521 hours = 99;
1522 else
1523 hours = (global1 + 11) % 12 + 1;
1524
1525 pad_status_line(brief ? 15 : 20);
1526 print_string("Time: ");
1527 if (hours < 10)
1528 print_char(' ');
1529 print_num(hours);
1530 print_char(':');
1531 if (global2 < 10)
1532 print_char('0');
1533 print_num(global2);
1534 print_char(' ');
1535 print_char((global1 >= 12) ? 'p' : 'a');
1536 print_char('m');
1537 } else { /* print score and moves */
1538 pad_status_line(brief ? 15 : 30);
1539 print_string(brief ? "S: " : "Score: ");
1540 print_num(global1);
1541 pad_status_line(brief ? 8 : 14);
1542 print_string(brief ? "M: " : "Moves: ");
1543 print_num(global2);
1544 }
1545
1546 /* Pad the end of the status line with spaces */
1547 pad_status_line(0);
1548
1549 /* Return to the lower window */
1550 set_window(0);
1551 } /* z_show_status */
1552
1553
1554 /*
1555 * z_split_window, split the screen into an upper (1) and lower (0) window.
1556 *
1557 * zargs[0] = height of upper window in screen units (V6) or #lines
1558 *
1559 */
z_split_window(void)1560 void z_split_window(void)
1561 {
1562 split_window(zargs[0]);
1563 } /* z_split_window */
1564
1565
1566 /*
1567 * z_window_size, change the width and height of a window.
1568 *
1569 * zargs[0] = window (-3 is the current one)
1570 * zargs[1] = new height in screen units
1571 * zargs[2] = new width in screen units
1572 *
1573 */
z_window_size(void)1574 void z_window_size(void)
1575 {
1576 zword win = winarg0();
1577
1578 flush_buffer();
1579
1580 wp[win].y_size = zargs[1];
1581 wp[win].x_size = zargs[2];
1582
1583 /* Keep the cursor within the window */
1584
1585 if (wp[win].y_cursor > zargs[1] || wp[win].x_cursor > zargs[2])
1586 reset_cursor(win);
1587 } /* z_window_size */
1588
1589
1590 /*
1591 * z_window_style, set / clear / toggle window attributes.
1592 *
1593 * zargs[0] = window (-3 is the current one)
1594 * zargs[1] = window attribute flags
1595 * zargs[2] = operation to perform (optional, defaults to 0)
1596 *
1597 */
z_window_style(void)1598 void z_window_style(void)
1599 {
1600 zword win = winarg0();
1601 zword flags = zargs[1];
1602
1603 flush_buffer();
1604
1605 /* Supply default arguments */
1606
1607 if (zargc < 3)
1608 zargs[2] = 0;
1609
1610 /* Set window style */
1611
1612 switch (zargs[2]) {
1613 case 0:
1614 wp[win].attribute = flags;
1615 break;
1616 case 1:
1617 wp[win].attribute |= flags;
1618 break;
1619 case 2:
1620 wp[win].attribute &= ~flags;
1621 break;
1622 case 3:
1623 wp[win].attribute ^= flags;
1624 break;
1625 }
1626
1627 if (cwin == win)
1628 update_attributes();
1629 } /* z_window_style */
1630
1631
1632 /*
1633 * get_window_colours
1634 *
1635 * Get the colours for a given window.
1636 *
1637 */
get_window_colours(zword win,zbyte * fore,zbyte * back)1638 void get_window_colours(zword win, zbyte * fore, zbyte * back)
1639 {
1640 *fore = lo(wp[win].colour);
1641 *back = hi(wp[win].colour);
1642 } /* get_window_colours */
1643
1644
1645 /*
1646 * get_window_font
1647 *
1648 * Get the font for a given window.
1649 *
1650 */
get_window_font(zword win)1651 zword get_window_font(zword win)
1652 {
1653 zword font = wp[win].font;
1654
1655 if (font == TEXT_FONT) {
1656 if (z_header.version != V6) {
1657 if (win != 0 || z_header.flags & FIXED_FONT_FLAG)
1658 font = FIXED_WIDTH_FONT;
1659 } else {
1660 if (wp[win].style & FIXED_WIDTH_STYLE)
1661 font = FIXED_WIDTH_FONT;
1662 }
1663 }
1664 return font;
1665 } /* get_window_font */
1666
1667
1668 /*
1669 * colour_in_use
1670 *
1671 * Check if a colour is set in any window.
1672 *
1673 */
colour_in_use(zword colour)1674 int colour_in_use(zword colour)
1675 {
1676 int max = (z_header.version == V6) ? 8 : 2;
1677 int i;
1678
1679 for (i = 0; i < max; i++) {
1680 zword bg = hi(wp[i].colour);
1681 zword fg = lo(wp[i].colour);
1682
1683 if (colour == fg || colour == bg)
1684 return 1;
1685 }
1686 return 0;
1687
1688 } /* colour_in_use */
1689
1690
1691 /*
1692 * get_current_window
1693 *
1694 * Get the currently active window.
1695 *
1696 */
get_current_window(void)1697 zword get_current_window(void)
1698 {
1699 return cwp - wp;
1700 } /* get_current_window */
1701