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