home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / Epoc / Palmtime / files / FrotzS5_src.ZIP / Screen.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-17  |  33.9 KB  |  1,602 lines

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