Update interpreters to latest Garglk codebase
[projects/chimara/chimara.git] / interpreters / frotz / glkscreen.c
index 4545124798ba85c4175cdf6a143968c32038d8f4..2d72bfdd11ae8f66b690df268ec0b04d26821bfd 100644 (file)
@@ -1,34 +1,45 @@
+/******************************************************************************
+ *                                                                            *
+ * Copyright (C) 2006-2009 by Tor Andersson.                                  *
+ * Copyright (C) 2010 by Ben Cressey, Chris Spiegel.                          *
+ *                                                                            *
+ * This file is part of Gargoyle.                                             *
+ *                                                                            *
+ * Gargoyle is free software; you can redistribute it and/or modify           *
+ * it under the terms of the GNU General Public License as published by       *
+ * the Free Software Foundation; either version 2 of the License, or          *
+ * (at your option) any later version.                                        *
+ *                                                                            *
+ * Gargoyle is distributed in the hope that it will be useful,                *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with Gargoyle; if not, write to the Free Software                    *
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA *
+ *                                                                            *
+ *****************************************************************************/
+
 /* screen.c - Generic screen manipulation
  *
- *  Copyright (c) 2005 Tor Andersson -- Glk-ified and V6-disabled
- *             Copyright (c) 1995-1997 Stefan Jokisch
- *
- * This file is part of Frotz.
- *
- * Frotz is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Frotz is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *  Portions copyright (c) 1995-1997 Stefan Jokisch.
  */
 
 #include "glkfrotz.h"
 
-static unsigned char statusline[256];
+static zchar statusline[256];
 static int oldstyle = 0;
 static int curstyle = 0;
-static int upperstyle = 0;
-static int lowerstyle = 0;
 static int cury = 1;
 static int curx = 1;
+static int fixforced = 0;
+
+static int curr_fg = -2;
+static int curr_bg = -2;
+static int curr_font = 1;
+static int prev_font = 1;
+static int temp_font = 0;
 
 /* To make the common code happy */
 
@@ -49,6 +60,13 @@ int os_string_width (const zchar *s)
        return width;
 }
 
+int os_string_length (zchar *s)
+{
+       int length = 0;
+       while (*s++) length++;
+       return length;
+}
+
 void os_prepare_sample (int a)
 {
        glk_sound_load_hint(a, 1);
@@ -147,19 +165,26 @@ void reset_status_ht(void)
        {
                glk_window_get_size(gos_upper, NULL, &height);
                if (mach_status_ht != height)
+               {
                        glk_window_set_arrangement(
                                glk_window_get_parent(gos_upper),
                                winmethod_Above | winmethod_Fixed,
                                mach_status_ht, NULL);
+               }
        }
 }
 
-void erase_window (int w)
+void erase_window (zword w)
 {
        if (w == 0)
                glk_window_clear(gos_lower);
        else if (gos_upper)
        {
+#ifdef GARGLK
+                       garglk_set_reversevideo_stream(
+                               glk_window_get_stream(gos_upper),
+                               TRUE);
+#endif /* GARGLK */
                memset(statusline, ' ', sizeof statusline);
                glk_window_clear(gos_upper);
                reset_status_ht();
@@ -167,7 +192,7 @@ void erase_window (int w)
        }
 }
 
-void split_window (int lines)
+void split_window (zword lines)
 {
        if (!gos_upper)
                return;
@@ -175,7 +200,7 @@ void split_window (int lines)
        if (h_version < V4)
                lines++;
 
-       if (lines > curr_status_ht)
+       if (!lines || lines > curr_status_ht)
        {
                glui32 height;
 
@@ -211,11 +236,13 @@ void restart_screen (void)
  * so ... split status text into regions, reformat and print anew.
  */
 
-void packspaces(unsigned char *src, unsigned char *dst)
+void packspaces(zchar *src, zchar *dst)
 {
        int killing = 0;
        while (*src)
        {
+               if (*src == 0x20202020)
+                       *src = ' ';
                if (*src == ' ')
                        killing++;
                else
@@ -230,17 +257,15 @@ void packspaces(unsigned char *src, unsigned char *dst)
 
 void smartstatusline (void)
 {
-       unsigned char packed[256];
-       unsigned char buf[256];
-       unsigned char *a, *b, *c, *d;
+       zchar packed[256];
+       zchar buf[256];
+       zchar *a, *b, *c, *d;
        int roomlen, scorelen, scoreofs;
-       int len;
-
-       statusline[curx - 1] = 0; /* terminate! */
+       int len, tmp;
 
        packspaces(statusline, packed);
        //strcpy(packed, statusline);
-       len = strlen(packed);
+       len = os_string_length(packed);
 
        a = packed;
        while (a[0] == ' ')
@@ -268,16 +293,19 @@ void smartstatusline (void)
        roomlen = b - a;
        scorelen = d - c;
        scoreofs = h_screen_cols - scorelen - 2;
+       if (scoreofs <= roomlen)
+               scoreofs = roomlen + 2;
 
-       memset(buf, ' ', h_screen_cols);
-       memcpy(buf + 1 + scoreofs, c, scorelen);
-       memcpy(buf + 1, a, roomlen);
-       if (roomlen >= scoreofs)
-               buf[roomlen + 1] = '|';
+       for (tmp = 0; tmp < h_screen_cols; tmp++)
+               buf[tmp] = ' ';
+
+       memcpy(buf + 1 + scoreofs, c, scorelen * sizeof(zchar));
+       memcpy(buf + 1, a, roomlen * sizeof(zchar));
+       //if (roomlen >= scoreofs)
+       //      buf[roomlen + 1] = '|';
 
        glk_window_move_cursor(gos_upper, 0, 0);
-       glk_set_style(style_User1);
-       glk_put_buffer(buf, h_screen_cols);
+       glk_put_buffer_uni(buf, h_screen_cols);
        glk_window_move_cursor(gos_upper, cury - 1, curx - 1);
 }
 
@@ -295,24 +323,20 @@ void screen_char (zchar c)
                        return;
        }
 
-       if (gos_upper && gos_curwin == gos_upper) {
-               if (cury > mach_status_ht) {
-                       mach_status_ht = cury;
-                       reset_status_ht();
-               }
-       }
-
        /* check fixed flag in header, game can change it at whim */
-       if (gos_curwin == gos_lower)
+       int forcefix = ((h_flags & FIXED_FONT_FLAG) != 0);
+       int curfix = ((curstyle & FIXED_WIDTH_STYLE) != 0);
+       if (forcefix && !curfix)
        {
-               static int forcefix = -1;
-               int curfix = h_flags & FIXED_FONT_FLAG;
-               if (forcefix != curfix)
-               {
-                       forcefix = curfix;
-                       zargs[0] = 0xf000;      /* tickle tickle! */
-                       z_set_text_style();
-               }
+               zargs[0] = 0xf000;      /* tickle tickle! */
+               z_set_text_style();
+               fixforced = TRUE;
+       }
+       else if (!forcefix && fixforced)
+       {
+               zargs[0] = 0xf000;      /* tickle tickle! */
+               z_set_text_style();
+               fixforced = FALSE;
        }
 
        if (gos_upper && gos_curwin == gos_upper)
@@ -325,22 +349,38 @@ void screen_char (zchar c)
                else {
                        if (cury == 1)
                        {
-                               if (curx < sizeof statusline)
+                               if (curx <= ((sizeof statusline / sizeof(zchar)) - 1))
+                               {
                                        statusline[curx - 1] = c;
-                               curx++;
-                               if (curx <= h_screen_cols)
-                                       glk_put_char(c);
+                                       statusline[curx] = 0;
+                               }
+                               if (curx < h_screen_cols)
+                               {
+                                       glk_put_char_uni(c);
+                               }
+                               else if (curx == h_screen_cols)
+                               {
+                                       glk_put_char_uni(c);
+                                       glk_window_move_cursor(gos_curwin, curx-1, cury-1);
+                               }
                                else
+                               {
                                        smartstatusline();
+                               }
+                               curx ++;
                        }
                        else
                        {
-                               glk_put_char(c);
-                               curx++;
-                               if (curx > h_screen_cols) {
-                                       curx = 1;
-                                       cury++;
+                               if (curx < h_screen_cols)
+                               {
+                                       glk_put_char_uni(c);
+                               }
+                               else if (curx == (h_screen_cols))
+                               {
+                                       glk_put_char_uni(c);
+                                       glk_window_move_cursor(gos_curwin, curx-1, cury-1);
                                }
+                               curx++;
                        }
                }
        }
@@ -348,7 +388,7 @@ void screen_char (zchar c)
        {
                if (c == ZC_RETURN)
                        glk_put_char('\n');
-               else glk_put_char(c);
+               else glk_put_char_uni(c);
        }
 }
 
@@ -402,6 +442,18 @@ void z_buffer_mode (void)
 {
 }
 
+/*
+ * z_buffer_screen, set the screen buffering mode.
+ *
+ *     zargs[0] = mode
+ *
+ */
+
+void z_buffer_screen (void)
+{
+       store (0);
+}
+
 /*
  * z_erase_line, erase the line starting at the cursor position.
  *
@@ -433,16 +485,29 @@ void z_erase_window (void)
        short w = zargs[0];
        if (w == -2)
        {
-               if (gos_upper)
+               if (gos_upper) {
+                       glk_set_window(gos_upper);
+#ifdef GARGLK
+                       garglk_set_zcolors(curr_fg, curr_bg);
+#endif /* GARGLK */
                        glk_window_clear(gos_upper);
+                       glk_set_window(gos_curwin);
+               }
                glk_window_clear(gos_lower);
        }
        if (w == -1)
        {
-               if (gos_upper)
+               if (gos_upper) {
+                       glk_set_window(gos_upper);
+#ifdef GARGLK
+                       garglk_set_zcolors(curr_fg, curr_bg);
+#endif /* GARGLK */
                        glk_window_clear(gos_upper);
+               }
                glk_window_clear(gos_lower);
                split_window(0);
+               glk_set_window(gos_lower);
+               gos_curwin = gos_lower;
        }
        if (w == 0)
                glk_window_clear(gos_lower);
@@ -511,6 +576,59 @@ void z_print_table (void)
        }
 }
 
+#define zB(i) ((((i >> 10) & 0x1F) << 3) | (((i >> 10) & 0x1F) >> 2))
+#define zG(i) ((((i >>  5) & 0x1F) << 3) | (((i >>  5) & 0x1F) >> 2))
+#define zR(i) ((((i      ) & 0x1F) << 3) | (((i      ) & 0x1F) >> 2))
+
+#define zRGB(i) (zR(i) << 16 | zG(i) << 8 | zB(i))
+
+/*
+ * z_set_true_colour, set the foreground and background colours
+ * to specific RGB colour values.
+ *
+ *     zargs[0] = foreground colour
+ *     zargs[1] = background colour
+ *     zargs[2] = window (-3 is the current one, optional)
+ *
+ */
+
+void z_set_true_colour (void)
+{
+       int zfore = zargs[0];
+       int zback = zargs[1];
+
+       if (!(zfore < 0))
+               zfore = zRGB(zargs[0]);
+
+       if (!(zback < 0))
+               zback = zRGB(zargs[1]);
+
+#ifdef GARGLK
+       garglk_set_zcolors(zfore, zback);
+#endif /* GARGLK */
+
+       curr_fg = zfore;
+       curr_bg = zback;
+}
+
+static int zcolor_map[] = {
+       -2,                                             /*  0 = current */
+       -1,                                             /*  1 = default */
+       0x0000,                                 /*  2 = black */
+       0x001D,                                 /*  3 = red */
+       0x0340,                                 /*  4 = green */
+       0x03BD,                                 /*  5 = yellow */
+       0x59A0,                                 /*  6 = blue */
+       0x7C1F,                                 /*  7 = magenta */
+       0x77A0,                                 /*  8 = cyan */
+       0x7FFF,                                 /*  9 = white */
+       0x5AD6,                                 /* 10 = light grey */
+       0x4631,                                 /* 11 = medium grey */
+       0x2D6B,                                 /* 12 = dark grey */
+};
+
+#define zcolor_NUMCOLORS    (13)
+
 /*
  * z_set_colour, set the foreground and background colours.
  *
@@ -525,8 +643,44 @@ void z_set_colour (void)
        int zfore = zargs[0];
        int zback = zargs[1];
 
-       if (!(zfore == 0 && zback == 0))
-               garglk_set_zcolors(zfore, zback);
+       switch (zfore)
+       {
+       case -1:
+               zfore = -3;
+
+       case 0:
+       case 1:
+               zfore = zcolor_map[zfore];
+               break;
+
+       default:
+               if (zfore < zcolor_NUMCOLORS)
+                       zfore = zRGB(zcolor_map[zfore]);
+               break;
+       }
+
+       switch (zback)
+       {
+       case -1:
+               zback = -3;
+
+       case 0:
+       case 1:
+               zback = zcolor_map[zback];
+               break;
+
+       default:
+               if (zback < zcolor_NUMCOLORS)
+                       zback = zRGB(zcolor_map[zback]);
+               break;
+       }
+
+#ifdef GARGLK
+       garglk_set_zcolors(zfore, zback);
+#endif /* GARGLK */
+
+       curr_fg = zfore;
+       curr_bg = zback;
 }
 
 /*
@@ -538,6 +692,41 @@ void z_set_colour (void)
 
 void z_set_font (void)
 {
+       zword font = zargs[0];
+
+       switch (font)
+       {
+               case 0: /* previous font */
+                       temp_font = curr_font;
+                       curr_font = prev_font;
+                       prev_font = temp_font;
+                       zargs[0] = 0xf000;      /* tickle tickle! */
+                       z_set_text_style();
+                       store (curr_font);
+                       break;
+
+               case 1: /* normal font */
+                       prev_font = curr_font;
+                       curr_font = 1;
+                       zargs[0] = 0xf000;      /* tickle tickle! */
+                       z_set_text_style();
+                       store (prev_font);
+                       break; 
+
+               case 4: /* fixed-pitch font*/
+                       prev_font = curr_font;
+                       curr_font = 4;
+                       zargs[0] = 0xf000;      /* tickle tickle! */
+                       z_set_text_style();
+                       store (prev_font);
+                       break;
+
+               case 2: /* picture font, undefined per 1.1 */
+               case 3: /* character graphics font */
+               default: /* unavailable */
+                       store (0);
+                       break;
+       }
 }
 
 /*
@@ -553,8 +742,15 @@ void z_set_cursor (void)
 {
        cury = zargs[0];
        curx = zargs[1];
-       if (gos_upper)
+
+       if (gos_upper) {
+               if (cury > mach_status_ht) {
+                       mach_status_ht = cury;
+                       reset_status_ht();
+               }
+
                glk_window_move_cursor(gos_upper, curx - 1, cury - 1);
+       }
 }
 
 /*
@@ -573,7 +769,7 @@ void z_set_text_style (void)
        else if (zargs[0] != 0xf000) /* not tickle time */
                curstyle |= zargs[0];
 
-       if (h_flags & FIXED_FONT_FLAG)
+       if (h_flags & FIXED_FONT_FLAG || curr_font == 4)
                style = curstyle | FIXED_WIDTH_STYLE;
        else
                style = curstyle;
@@ -583,25 +779,41 @@ void z_set_text_style (void)
 
        if (style & REVERSE_STYLE)
        {
-               if (gos_curwin == gos_upper && gos_upper) {
-                       glk_set_style(style_User1);
-               }
+#ifdef GARGLK
                garglk_set_reversevideo(TRUE);
+#endif /* GARGLK */
+       }
+
+       if (style & FIXED_WIDTH_STYLE)
+       {
+               if (style & BOLDFACE_STYLE && style & EMPHASIS_STYLE)
+                       glk_set_style(style_BlockQuote);        /* monoz */
+               else if (style & EMPHASIS_STYLE)
+                       glk_set_style(style_Alert);                     /* monoi */
+               else if (style & BOLDFACE_STYLE)
+                       glk_set_style(style_Subheader);         /* monob */
+               else
+                       glk_set_style(style_Preformatted);      /* monor */
        }
-       else if (style & FIXED_WIDTH_STYLE)
-               glk_set_style(style_Preformatted);
-       else if (style & BOLDFACE_STYLE && style & EMPHASIS_STYLE)
-               glk_set_style(style_Alert);
-       else if (style & BOLDFACE_STYLE)
-               glk_set_style(style_Subheader);
-       else if (style & EMPHASIS_STYLE)
-               glk_set_style(style_Emphasized);
        else
-               glk_set_style(style_Normal);
+       {
+               if (style & BOLDFACE_STYLE && style & EMPHASIS_STYLE)
+                       glk_set_style(style_Note);                      /* propz */
+               else if (style & EMPHASIS_STYLE)
+                       glk_set_style(style_Emphasized);        /* propi */
+               else if (style & BOLDFACE_STYLE)
+                       glk_set_style(style_Header);            /* propb */
+               else
+                       glk_set_style(style_Normal);            /* propr */
+       }
 
-       if (curstyle == 0) {
+       if (curstyle == 0)
+       {
+#ifdef GARGLK
                garglk_set_reversevideo(FALSE);
+#endif /* GARGLK */
        }
+
 }
 
 /*
@@ -615,29 +827,25 @@ void z_set_window (void)
 {
        int win = zargs[0];
 
-       if (gos_curwin == gos_lower)
-               lowerstyle = curstyle;
-       else
-               upperstyle = curstyle;
-
        if (win == 0)
        {
                glk_set_window(gos_lower);
                gos_curwin = gos_lower;
-               curstyle = lowerstyle;
        }
        else
        {
                if (gos_upper)
                        glk_set_window(gos_upper);
                gos_curwin = gos_upper;
-               curstyle = upperstyle;
        }
 
-        if (win == 0)
-            enable_scripting = TRUE;
-        else
-            enable_scripting = FALSE;
+       if (win == 0)
+               enable_scripting = TRUE;
+       else
+               enable_scripting = FALSE;
+
+       zargs[0] = 0xf000;      /* tickle tickle! */
+       z_set_text_style();
 }
 
 /*
@@ -688,9 +896,12 @@ void z_show_status (void)
        glk_set_window(gos_upper);
        gos_curwin = gos_upper;
 
+#ifdef GARGLK
+       garglk_set_reversevideo(TRUE);
+#endif /* GARGLK */
+
        curx = cury = 1;
        glk_window_move_cursor(gos_upper, 0, 0);
-       glk_set_style(style_User1);
 
        /* If the screen width is below 55 characters then we have to use
           the brief status line format */