Updated interpreters
[projects/chimara/chimara.git] / interpreters / frotz / glkscreen.c
1 /******************************************************************************
2  *                                                                            *
3  * Copyright (C) 2006-2009 by Tor Andersson.                                  *
4  * Copyright (C) 2010 by Ben Cressey, Chris Spiegel.                          *
5  *                                                                            *
6  * This file is part of Gargoyle.                                             *
7  *                                                                            *
8  * Gargoyle is free software; you can redistribute it and/or modify           *
9  * it under the terms of the GNU General Public License as published by       *
10  * the Free Software Foundation; either version 2 of the License, or          *
11  * (at your option) any later version.                                        *
12  *                                                                            *
13  * Gargoyle is distributed in the hope that it will be useful,                *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
16  * GNU General Public License for more details.                               *
17  *                                                                            *
18  * You should have received a copy of the GNU General Public License          *
19  * along with Gargoyle; if not, write to the Free Software                    *
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA *
21  *                                                                            *
22  *****************************************************************************/
23
24 /* screen.c - Generic screen manipulation
25  *
26  *  Portions copyright (c) 1995-1997 Stefan Jokisch.
27  */
28
29 #include "glkfrotz.h"
30
31 static zchar statusline[256];
32 static int oldstyle = 0;
33 static int curstyle = 0;
34 static int cury = 1;
35 static int curx = 1;
36 static int fixforced = 0;
37
38 static int curr_fg = -2;
39 static int curr_bg = -2;
40 static int curr_font = 1;
41 static int prev_font = 1;
42 static int temp_font = 0;
43
44 /* To make the common code happy */
45
46 int os_char_width (zchar z)
47 {
48         return 1;
49 }
50
51 int os_string_width (const zchar *s)
52 {
53         int width = 0;
54         zchar c;
55         while ((c = *s++) != 0)
56                 if (c == ZC_NEW_STYLE || c == ZC_NEW_FONT)
57                         s++;
58                 else
59                         width += os_char_width(c);
60         return width;
61 }
62
63 int os_string_length (zchar *s)
64 {
65         int length = 0;
66         while (*s++) length++;
67         return length;
68 }
69
70 void os_prepare_sample (int a)
71 {
72         glk_sound_load_hint(a, 1);
73 }
74
75 void os_finish_with_sample (int a)
76 {
77         glk_sound_load_hint(a, 0);
78 }
79
80 /*
81  * os_start_sample
82  *
83  * Play the given sample at the given volume (ranging from 1 to 8 and
84  * 255 meaning a default volume). The sound is played once or several
85  * times in the background (255 meaning forever). In Z-code 3 the
86  * repeats value is always 0 and the number of repeats is taken from
87  * the sound file itself. The end_of_sound function is called as soon
88  * as the sound finishes.
89  *
90  */
91
92 void os_start_sample (int number, int volume, int repeats, zword eos)
93 {
94         int vol;
95
96         if (!gos_channel)
97         {
98                 gos_channel = glk_schannel_create(0);
99                 if (!gos_channel)
100                         return;
101         }
102
103         switch (volume)
104         {
105         case   1: vol = 0x02000; break;
106         case   2: vol = 0x04000; break;
107         case   3: vol = 0x06000; break;
108         case   4: vol = 0x08000; break;
109         case   5: vol = 0x0a000; break;
110         case   6: vol = 0x0c000; break;
111         case   7: vol = 0x0e000; break;
112         case   8: vol = 0x10000; break;
113         default:  vol = 0x20000; break;
114         }
115
116         /* we dont do repeating or eos-callback for now... */
117         glk_schannel_play_ext(gos_channel, number, 1, 0);
118         glk_schannel_set_volume(gos_channel, vol);
119 }
120
121 void os_stop_sample (int a)
122 {
123         if (!gos_channel)
124                 return;
125         glk_schannel_stop(gos_channel);
126 }
127
128 void os_beep (int volume)
129 {
130 }
131
132 void gos_update_width(void)
133 {
134         glui32 width;
135         if (gos_upper)
136         {
137                 glk_window_get_size(gos_upper, &width, NULL);
138                 h_screen_cols = width;
139                 SET_BYTE(H_SCREEN_COLS, width);
140                 if (curx > width)
141                 {
142                         glk_window_move_cursor(gos_upper, 0, cury-1);
143                         curx = 1;
144                 }
145         }
146 }
147
148 void gos_update_height(void)
149 {
150         glui32 height_upper;
151         glui32 height_lower;
152         if (gos_curwin)
153         {
154                 glk_window_get_size(gos_upper, NULL, &height_upper);
155                 glk_window_get_size(gos_lower, NULL, &height_lower);
156                 h_screen_rows = height_upper + height_lower + 1;
157                 SET_BYTE(H_SCREEN_ROWS, h_screen_rows);
158         }
159 }
160
161 void reset_status_ht(void)
162 {
163         glui32 height;
164         if (gos_upper)
165         {
166                 glk_window_get_size(gos_upper, NULL, &height);
167                 if (mach_status_ht != height)
168                 {
169                         glk_window_set_arrangement(
170                                 glk_window_get_parent(gos_upper),
171                                 winmethod_Above | winmethod_Fixed,
172                                 mach_status_ht, NULL);
173                 }
174         }
175 }
176
177 void erase_window (zword w)
178 {
179         if (w == 0)
180                 glk_window_clear(gos_lower);
181         else if (gos_upper)
182         {
183 #ifdef GARGLK
184                         garglk_set_reversevideo_stream(
185                                 glk_window_get_stream(gos_upper),
186                                 TRUE);
187 #endif /* GARGLK */
188                 memset(statusline, ' ', sizeof statusline);
189                 glk_window_clear(gos_upper);
190                 reset_status_ht();
191                 curr_status_ht = 0;
192         }
193 }
194
195 void split_window (zword lines)
196 {
197         if (!gos_upper)
198                 return;
199         /* The top line is always set for V1 to V3 games */
200         if (h_version < V4)
201                 lines++;
202
203         if (!lines || lines > curr_status_ht)
204         {
205                 glui32 height;
206
207                 glk_window_get_size(gos_upper, NULL, &height);
208                 if (lines != height)
209                         glk_window_set_arrangement(
210                                 glk_window_get_parent(gos_upper),
211                                 winmethod_Above | winmethod_Fixed,
212                                 lines, NULL);
213                 curr_status_ht = lines;
214         }
215         mach_status_ht = lines;
216         if (cury > lines)
217         {
218                 glk_window_move_cursor(gos_upper, 0, 0);
219                 curx = cury = 1;
220         }
221         gos_update_width();
222
223         if (h_version == V3)
224                 glk_window_clear(gos_upper);
225 }
226
227 void restart_screen (void)
228 {
229         erase_window(0);
230         erase_window(1);
231         split_window(0);
232 }
233
234 /*
235  * statusline overflowed the window size ... bad game!
236  * so ... split status text into regions, reformat and print anew.
237  */
238
239 void packspaces(zchar *src, zchar *dst)
240 {
241         int killing = 0;
242         while (*src)
243         {
244                 if (*src == 0x20202020)
245                         *src = ' ';
246                 if (*src == ' ')
247                         killing++;
248                 else
249                         killing = 0;
250                 if (killing > 2)
251                         src++;
252                 else
253                         *dst++ = *src++;
254         }
255         *dst = 0;
256 }
257
258 void smartstatusline (void)
259 {
260         zchar packed[256];
261         zchar buf[256];
262         zchar *a, *b, *c, *d;
263         int roomlen, scorelen, scoreofs;
264         int len, tmp;
265
266         statusline[curx - 1] = 0; /* terminate! */
267
268         packspaces(statusline, packed);
269         //strcpy(packed, statusline);
270         len = os_string_length(packed);
271
272         a = packed;
273         while (a[0] == ' ')
274                 a ++;
275
276         b = a;
277         while (b[0] != 0 && !(b[0] == ' ' && b[1] == ' '))
278                 b ++;
279
280         c = b;
281         while (c[0] == ' ')
282                 c ++;
283
284         d = packed + len - 1;
285         while (d[0] == ' ' && d > c)
286                 d --;
287         if (d[0] != ' ' && d[0] != 0)
288                 d ++;
289         if (d < c)
290                 d = c;
291
292         //printf("smart '%s'\n", packed);
293         //printf("smart %d %d %d %d\n",a-packed,b-packed,c-packed,d-packed);
294
295         roomlen = b - a;
296         scorelen = d - c;
297         scoreofs = h_screen_cols - scorelen - 2;
298         if (scoreofs <= roomlen)
299                 scoreofs = roomlen + 2;
300
301         for (tmp = 0; tmp < h_screen_cols; tmp++)
302                 buf[tmp] = ' ';
303
304         memcpy(buf + 1 + scoreofs, c, scorelen * sizeof(zchar));
305         memcpy(buf + 1, a, roomlen * sizeof(zchar));
306         //if (roomlen >= scoreofs)
307         //      buf[roomlen + 1] = '|';
308
309         glk_window_move_cursor(gos_upper, 0, 0);
310         glk_put_buffer_uni(buf, h_screen_cols);
311         glk_window_move_cursor(gos_upper, cury - 1, curx - 1);
312 }
313
314 void screen_char (zchar c)
315 {
316         if (gos_linepending && (gos_curwin == gos_linewin))
317         {
318                 gos_cancel_pending_line();
319                 if (gos_curwin == gos_upper)
320                 {
321                         curx = 1;
322                         cury ++;
323                 }
324                 if (c == '\n')
325                         return;
326         }
327
328         /* check fixed flag in header, game can change it at whim */
329         int forcefix = ((h_flags & FIXED_FONT_FLAG) != 0);
330         int curfix = ((curstyle & FIXED_WIDTH_STYLE) != 0);
331         if (forcefix && !curfix)
332         {
333                 zargs[0] = 0xf000;      /* tickle tickle! */
334                 z_set_text_style();
335                 fixforced = TRUE;
336         }
337         else if (!forcefix && fixforced)
338         {
339                 zargs[0] = 0xf000;      /* tickle tickle! */
340                 z_set_text_style();
341                 fixforced = FALSE;
342         }
343
344         if (gos_upper && gos_curwin == gos_upper)
345         {
346                 if (c == '\n' || c == ZC_RETURN) {
347                         glk_put_char('\n');
348                         curx = 1;
349                         cury ++;
350                 }
351                 else {
352                         if (cury == 1)
353                         {
354                                 if (curx < sizeof statusline)
355                                         statusline[curx - 1] = c;
356                                 curx++;
357                                 if (curx <= h_screen_cols)
358                                         glk_put_char_uni(c);
359                                 else
360                                         smartstatusline();
361                         }
362                         else
363                         {
364                                 glk_put_char_uni(c);
365                                 curx++;
366                                 if (curx > h_screen_cols) {
367                                         curx = 1;
368                                         cury++;
369                                 }
370                         }
371                 }
372         }
373         else if (gos_curwin == gos_lower)
374         {
375                 if (c == ZC_RETURN)
376                         glk_put_char('\n');
377                 else glk_put_char_uni(c);
378         }
379 }
380
381 void screen_new_line (void)
382 {
383         screen_char('\n');
384 }
385
386 void screen_word (const zchar *s)
387 {
388         zchar c;
389         while ((c = *s++) != 0)
390                 if (c == ZC_NEW_FONT)
391                         s++;
392                 else if (c == ZC_NEW_STYLE)
393                         s++;
394                 else
395                         screen_char (c); 
396 }
397
398 void screen_mssg_on (void)
399 {
400         if (gos_curwin == gos_lower)
401         {
402                 oldstyle = curstyle;
403                 glk_set_style(style_Preformatted);
404                 glk_put_string("\n    ");
405         }
406 }
407
408 void screen_mssg_off (void)
409 {
410         if (gos_curwin == gos_lower)
411         {
412                 glk_put_char('\n');
413                 zargs[0] = 0;
414                 z_set_text_style();
415                 zargs[0] = oldstyle;
416                 z_set_text_style();
417         }
418 }
419
420 /*
421  * z_buffer_mode, turn text buffering on/off.
422  *
423  *              zargs[0] = new text buffering flag (0 or 1)
424  *
425  */
426
427 void z_buffer_mode (void)
428 {
429 }
430
431 /*
432  * z_buffer_screen, set the screen buffering mode.
433  *
434  *      zargs[0] = mode
435  *
436  */
437
438 void z_buffer_screen (void)
439 {
440         store (0);
441 }
442
443 /*
444  * z_erase_line, erase the line starting at the cursor position.
445  *
446  *              zargs[0] = 1 + #units to erase (1 clears to the end of the line)
447  *
448  */
449
450 void z_erase_line (void)
451 {
452         int i;
453
454         if (gos_upper && gos_curwin == gos_upper)
455         {
456                 for (i = 0; i < h_screen_cols + 1 - curx; i++)
457                         glk_put_char(' ');
458                 glk_window_move_cursor(gos_curwin, curx - 1, cury - 1);
459         }
460 }
461
462 /*
463  * z_erase_window, erase a window or the screen to background colour.
464  *
465  *              zargs[0] = window (-3 current, -2 screen, -1 screen & unsplit)
466  *
467  */
468
469 void z_erase_window (void)
470 {
471         short w = zargs[0];
472         if (w == -2)
473         {
474                 if (gos_upper) {
475                         glk_set_window(gos_upper);
476 #ifdef GARGLK
477                         garglk_set_zcolors(curr_fg, curr_bg);
478 #endif /* GARGLK */
479                         glk_window_clear(gos_upper);
480                         glk_set_window(gos_curwin);
481                 }
482                 glk_window_clear(gos_lower);
483         }
484         if (w == -1)
485         {
486                 if (gos_upper) {
487                         glk_set_window(gos_upper);
488 #ifdef GARGLK
489                         garglk_set_zcolors(curr_fg, curr_bg);
490 #endif /* GARGLK */
491                         glk_window_clear(gos_upper);
492                 }
493                 glk_window_clear(gos_lower);
494                 split_window(0);
495                 glk_set_window(gos_lower);
496                 gos_curwin = gos_lower;
497         }
498         if (w == 0)
499                 glk_window_clear(gos_lower);
500         if (w == 1 && gos_upper)
501                 glk_window_clear(gos_upper);
502 }
503
504 /*
505  * z_get_cursor, write the cursor coordinates into a table.
506  *
507  *              zargs[0] = address to write information to
508  *
509  */
510
511 void z_get_cursor (void)
512 {
513         storew ((zword) (zargs[0] + 0), cury);
514         storew ((zword) (zargs[0] + 2), curx);
515 }
516
517 /*
518  * z_print_table, print ASCII text in a rectangular area.
519  *
520  *              zargs[0] = address of text to be printed
521  *              zargs[1] = width of rectangular area
522  *              zargs[2] = height of rectangular area (optional)
523  *              zargs[3] = number of char's to skip between lines (optional)
524  *
525  */
526
527 void z_print_table (void)
528 {
529         zword addr = zargs[0];
530         zword x;
531         int i, j;
532
533         /* Supply default arguments */
534
535         if (zargc < 3)
536                 zargs[2] = 1;
537         if (zargc < 4)
538                 zargs[3] = 0;
539
540         /* Write text in width x height rectangle */
541
542         x = curx;
543
544         for (i = 0; i < zargs[2]; i++) {
545
546                 if (i != 0) {
547                         cury += 1;
548                         curx = x;
549                 }
550
551                 for (j = 0; j < zargs[1]; j++) {
552
553                         zbyte c;
554
555                         LOW_BYTE (addr, c)
556                         addr++;
557
558                         print_char (c);
559                 }
560
561                 addr += zargs[3];
562         }
563 }
564
565 #define zB(i) ((((i >> 10) & 0x1F) << 3) | (((i >> 10) & 0x1F) >> 2))
566 #define zG(i) ((((i >>  5) & 0x1F) << 3) | (((i >>  5) & 0x1F) >> 2))
567 #define zR(i) ((((i      ) & 0x1F) << 3) | (((i      ) & 0x1F) >> 2))
568
569 #define zRGB(i) (zR(i) << 16 | zG(i) << 8 | zB(i))
570
571 /*
572  * z_set_true_colour, set the foreground and background colours
573  * to specific RGB colour values.
574  *
575  *      zargs[0] = foreground colour
576  *      zargs[1] = background colour
577  *      zargs[2] = window (-3 is the current one, optional)
578  *
579  */
580
581 void z_set_true_colour (void)
582 {
583         int zfore = zargs[0];
584         int zback = zargs[1];
585
586         if (!(zfore < 0))
587                 zfore = zRGB(zargs[0]);
588
589         if (!(zback < 0))
590                 zback = zRGB(zargs[1]);
591
592 #ifdef GARGLK
593         garglk_set_zcolors(zfore, zback);
594 #endif /* GARGLK */
595
596         curr_fg = zfore;
597         curr_bg = zback;
598 }
599
600 static int zcolor_map[] = {
601         -2,                                             /*  0 = current */
602         -1,                                             /*  1 = default */
603         0x0000,                                 /*  2 = black */
604         0x001D,                                 /*  3 = red */
605         0x0340,                                 /*  4 = green */
606         0x03BD,                                 /*  5 = yellow */
607         0x59A0,                                 /*  6 = blue */
608         0x7C1F,                                 /*  7 = magenta */
609         0x77A0,                                 /*  8 = cyan */
610         0x7FFF,                                 /*  9 = white */
611         0x5AD6,                                 /* 10 = light grey */
612         0x4631,                                 /* 11 = medium grey */
613         0x2D6B,                                 /* 12 = dark grey */
614 };
615
616 #define zcolor_NUMCOLORS    (13)
617
618 /*
619  * z_set_colour, set the foreground and background colours.
620  *
621  *              zargs[0] = foreground colour
622  *              zargs[1] = background colour
623  *              zargs[2] = window (-3 is the current one, optional)
624  *
625  */
626
627 void z_set_colour (void)
628 {
629         int zfore = zargs[0];
630         int zback = zargs[1];
631
632         switch (zfore)
633         {
634         case -1:
635                 zfore = -3;
636
637         case 0:
638         case 1:
639                 zfore = zcolor_map[zfore];
640                 break;
641
642         default:
643                 if (zfore < zcolor_NUMCOLORS)
644                         zfore = zRGB(zcolor_map[zfore]);
645                 break;
646         }
647
648         switch (zback)
649         {
650         case -1:
651                 zback = -3;
652
653         case 0:
654         case 1:
655                 zback = zcolor_map[zback];
656                 break;
657
658         default:
659                 if (zback < zcolor_NUMCOLORS)
660                         zback = zRGB(zcolor_map[zback]);
661                 break;
662         }
663
664 #ifdef GARGLK
665         garglk_set_zcolors(zfore, zback);
666 #endif /* GARGLK */
667
668         curr_fg = zfore;
669         curr_bg = zback;
670 }
671
672 /*
673  * z_set_font, set the font for text output and store the previous font.
674  *
675  *               zargs[0] = number of font or 0 to keep current font
676  *
677  */
678
679 void z_set_font (void)
680 {
681         zword font = zargs[0];
682
683         switch (font)
684         {
685                 case 0: /* previous font */
686                         temp_font = curr_font;
687                         curr_font = prev_font;
688                         prev_font = temp_font;
689                         zargs[0] = 0xf000;      /* tickle tickle! */
690                         z_set_text_style();
691                         store (curr_font);
692                         break;
693
694                 case 1: /* normal font */
695                         prev_font = curr_font;
696                         curr_font = 1;
697                         zargs[0] = 0xf000;      /* tickle tickle! */
698                         z_set_text_style();
699                         store (prev_font);
700                         break; 
701
702                 case 4: /* fixed-pitch font*/
703                         prev_font = curr_font;
704                         curr_font = 4;
705                         zargs[0] = 0xf000;      /* tickle tickle! */
706                         z_set_text_style();
707                         store (prev_font);
708                         break;
709
710                 case 2: /* picture font, undefined per 1.1 */
711                 case 3: /* character graphics font */
712                 default: /* unavailable */
713                         store (0);
714                         break;
715         }
716 }
717
718 /*
719  * z_set_cursor, set the cursor position or turn the cursor on/off.
720  *
721  *              zargs[0] = y-coordinate or -2/-1 for cursor on/off
722  *              zargs[1] = x-coordinate
723  *              zargs[2] = window (-3 is the current one, optional)
724  *
725  */
726
727 void z_set_cursor (void)
728 {
729         cury = zargs[0];
730         curx = zargs[1];
731
732         if (gos_upper) {
733                 if (cury > mach_status_ht) {
734                         mach_status_ht = cury;
735                         reset_status_ht();
736                 }
737
738                 glk_window_move_cursor(gos_upper, curx - 1, cury - 1);
739         }
740 }
741
742 /*
743  * z_set_text_style, set the style for text output.
744  *
745  *               zargs[0] = style flags to set or 0 to reset text style
746  *
747  */
748
749 void z_set_text_style (void)
750 {
751         int style;
752
753         if (zargs[0] == 0)
754                 curstyle = 0;
755         else if (zargs[0] != 0xf000) /* not tickle time */
756                 curstyle |= zargs[0];
757
758         if (h_flags & FIXED_FONT_FLAG || curr_font == 4)
759                 style = curstyle | FIXED_WIDTH_STYLE;
760         else
761                 style = curstyle;
762
763         if (gos_linepending && gos_curwin == gos_linewin)
764                 return;
765
766         if (style & REVERSE_STYLE)
767         {
768 #ifdef GARGLK
769                 garglk_set_reversevideo(TRUE);
770 #endif /* GARGLK */
771         }
772
773         if (style & FIXED_WIDTH_STYLE)
774         {
775                 if (style & BOLDFACE_STYLE && style & EMPHASIS_STYLE)
776                         glk_set_style(style_BlockQuote);        /* monoz */
777                 else if (style & EMPHASIS_STYLE)
778                         glk_set_style(style_Alert);                     /* monoi */
779                 else if (style & BOLDFACE_STYLE)
780                         glk_set_style(style_Subheader);         /* monob */
781                 else
782                         glk_set_style(style_Preformatted);      /* monor */
783         }
784         else
785         {
786                 if (style & BOLDFACE_STYLE && style & EMPHASIS_STYLE)
787                         glk_set_style(style_Note);                      /* propz */
788                 else if (style & EMPHASIS_STYLE)
789                         glk_set_style(style_Emphasized);        /* propi */
790                 else if (style & BOLDFACE_STYLE)
791                         glk_set_style(style_Header);            /* propb */
792                 else
793                         glk_set_style(style_Normal);            /* propr */
794         }
795
796         if (curstyle == 0)
797         {
798 #ifdef GARGLK
799                 garglk_set_reversevideo(FALSE);
800 #endif /* GARGLK */
801         }
802
803 }
804
805 /*
806  * z_set_window, select the current window.
807  *
808  *              zargs[0] = window to be selected (-3 is the current one)
809  *
810  */
811
812 void z_set_window (void)
813 {
814         int win = zargs[0];
815
816         if (win == 0)
817         {
818                 glk_set_window(gos_lower);
819                 gos_curwin = gos_lower;
820         }
821         else
822         {
823                 if (gos_upper)
824                         glk_set_window(gos_upper);
825                 gos_curwin = gos_upper;
826         }
827
828         if (win == 0)
829                 enable_scripting = TRUE;
830         else
831                 enable_scripting = FALSE;
832
833         zargs[0] = 0xf000;      /* tickle tickle! */
834         z_set_text_style();
835 }
836
837 /*
838  * z_show_status, display the status line for V1 to V3 games.
839  *
840  *              no zargs used
841  *
842  */
843
844 static void pad_status_line (int column)
845 {
846         int spaces;
847         spaces = (h_screen_cols + 1 - curx) - column;
848         while (spaces-- > 0)
849                 print_char(' ');
850 }
851
852 void z_show_status (void)
853 {
854         zword global0;
855         zword global1;
856         zword global2;
857         zword addr;
858
859         bool brief = FALSE;
860
861         if (!gos_upper)
862                 return;
863
864         /* One V5 game (Wishbringer Solid Gold) contains this opcode by
865            accident, so just return if the version number does not fit */
866
867         if (h_version >= V4)
868                 return;
869
870         /* Read all relevant global variables from the memory of the
871            Z-machine into local variables */
872
873         addr = h_globals;
874         LOW_WORD (addr, global0)
875         addr += 2;
876         LOW_WORD (addr, global1)
877         addr += 2;
878         LOW_WORD (addr, global2)
879
880         /* Move to top of the status window, and print in reverse style. */
881
882         glk_set_window(gos_upper);
883         gos_curwin = gos_upper;
884
885         curx = cury = 1;
886         glk_window_move_cursor(gos_upper, 0, 0);
887
888         /* If the screen width is below 55 characters then we have to use
889            the brief status line format */
890
891         if (h_screen_cols < 55)
892                 brief = TRUE;
893
894         /* Print the object description for the global variable 0 */
895
896         print_char (' ');
897         print_object (global0);
898
899         /* A header flag tells us whether we have to display the current
900            time or the score/moves information */
901
902         if (h_config & CONFIG_TIME) {           /* print hours and minutes */
903
904                 zword hours = (global1 + 11) % 12 + 1;
905
906                 pad_status_line (brief ? 15 : 20);
907
908                 print_string ("Time: ");
909
910                 if (hours < 10)
911                         print_char (' ');
912                 print_num (hours);
913
914                 print_char (':');
915
916                 if (global2 < 10)
917                         print_char ('0');
918                 print_num (global2);
919
920                 print_char (' ');
921
922                 print_char ((global1 >= 12) ? 'p' : 'a');
923                 print_char ('m');
924
925         } else {                                                                /* print score and moves */
926
927                 pad_status_line (brief ? 15 : 30);
928
929                 print_string (brief ? "S: " : "Score: ");
930                 print_num (global1);
931
932                 pad_status_line (brief ? 8 : 14);
933
934                 print_string (brief ? "M: " : "Moves: ");
935                 print_num (global2);
936
937         }
938
939         /* Pad the end of the status line with spaces */
940
941         pad_status_line (0);
942
943         /* Return to the lower window */
944
945         glk_set_window(gos_lower);
946         gos_curwin = gos_lower;
947 }
948
949 /*
950  * z_split_window, split the screen into an upper (1) and lower (0) window.
951  *
952  *              zargs[0] = height of upper window in screen units (V6) or #lines
953  *
954  */
955
956 void z_split_window (void)
957 {
958         split_window(zargs[0]);
959 }
960