OSDN Git Service

GCU: remove assumed window width of 80 columns in wipe hook
[hengbandforosx/hengbandosx.git] / src / main-gcu.cpp
index 88c3f80..3d60796 100644 (file)
 #include "locale/japanese.h"
 #include "main/sound-definitions-table.h"
 #include "main/sound-of-music.h"
+#include "system/angband-version.h"
 #include "system/angband.h"
+#include "system/player-type-definition.h"
 #include "term/gameterm.h"
 #include "term/term-color-types.h"
+#include "term/z-form.h"
 #include "util/angband-files.h"
 #include "view/display-map.h"
 
  */
 #include <curses.h>
 
-typedef struct term_data term_data;
+/**
+ * Simple rectangle type
+ */
+struct rect_t {
+    int x, y;
+    int cx, cy;
+};
 
+/* Trivial rectangle utility to make code a bit more readable */
+static rect_t rect(int x, int y, int cx, int cy)
+{
+    rect_t r;
+    r.x = x;
+    r.y = y;
+    r.cx = cx;
+    r.cy = cy;
+    return r;
+}
+
+/**
+ * Information about a term
+ */
 struct term_data {
     term_type t;
-
+    rect_t r;
     WINDOW *win;
 };
 
+/* Max number of windows on screen */
 #define MAX_TERM_DATA 4
 
+/* Minimum main term size */
+#define MIN_TERM0_LINES 24
+#define MIN_TERM0_COLS 80
+
+/* Information about our windows */
 static term_data data[MAX_TERM_DATA];
 
 /*
@@ -206,13 +235,9 @@ static term_data data[MAX_TERM_DATA];
 #if defined(_POSIX_VERSION)
 #define USE_TPOSIX
 #else
-#if defined(linux)
-#define USE_TERMIO
-#else
 #define USE_TCHARS
 #endif
 #endif
-#endif
 
 /*
  * Try redefining the colors at startup.
@@ -276,7 +301,7 @@ static concptr ANGBAND_DIR_XTRA_SOUND;
  * todo 有効活用されていない疑惑
  * Flag set once "sound" has been initialized
  */
-static bool can_use_sound = FALSE;
+static bool can_use_sound = false;
 
 /*
  * An array of sound file names
@@ -332,17 +357,23 @@ static int active = 0;
 /*
  * Software flag -- we are allowed to use color
  */
-static int can_use_color = FALSE;
+static int can_use_color = false;
 
 /*
  * Software flag -- we are allowed to change the colors
  */
-static int can_fix_color = FALSE;
+static int can_fix_color = false;
 
 /*
  * Simple Angband to Curses color conversion table
  */
 static int colortable[16];
+
+/**
+ * Background color we should draw with; either BLACK or DEFAULT
+ */
+static int bg_color = COLOR_BLACK;
+
 #endif
 
 /*
@@ -502,7 +533,7 @@ static void keymap_game_prepare(void)
 /*
  * Suspend/Resume
  */
-static errr Term_xtra_gcu_alive(int v)
+static errr game_term_xtra_gcu_alive(int v)
 {
     if (!v) {
         /* Go to normal keymap mode */
@@ -537,7 +568,7 @@ static errr Term_xtra_gcu_alive(int v)
         keymap_game();
     }
 
-    return (0);
+    return 0;
 }
 
 /*
@@ -547,11 +578,12 @@ static bool check_file(concptr s)
 {
     FILE *fff;
     fff = fopen(s, "r");
-    if (!fff)
-        return (FALSE);
+    if (!fff) {
+        return false;
+    }
 
     fclose(fff);
-    return (TRUE);
+    return true;
 }
 
 /*
@@ -560,8 +592,9 @@ static bool check_file(concptr s)
 static bool init_sound(void)
 {
     /* Initialize once */
-    if (can_use_sound)
+    if (can_use_sound) {
         return can_use_sound;
+    }
 
     int i;
     char wav[128];
@@ -576,25 +609,27 @@ static bool init_sound(void)
         path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_SOUND, wav);
 
         /* Save the sound filename, if it exists */
-        if (check_file(buf))
+        if (check_file(buf)) {
             sound_file[i] = string_make(buf);
+        }
     }
 
     /* Sound available */
-    can_use_sound = TRUE;
-    return (can_use_sound);
+    can_use_sound = true;
+    return can_use_sound;
 }
 
 /*
  * Init the "curses" system
  */
-static void Term_init_gcu(term_type *t)
+static void game_term_init_gcu(term_type *t)
 {
     term_data *td = (term_data *)(t->data);
 
     /* Count init's, handle first */
-    if (active++ != 0)
+    if (active++ != 0) {
         return;
+    }
 
     /* Erase the screen */
     (void)wclear(td->win);
@@ -612,7 +647,7 @@ static void Term_init_gcu(term_type *t)
 /*
  * Nuke the "curses" system
  */
-static void Term_nuke_gcu(term_type *t)
+static void game_term_nuke_gcu(term_type *t)
 {
     term_data *td = (term_data *)(t->data);
 
@@ -620,8 +655,9 @@ static void Term_nuke_gcu(term_type *t)
     delwin(td->win);
 
     /* Count nuke's, handle last */
-    if (--active != 0)
+    if (--active != 0) {
         return;
+    }
 
     /* Hack -- make sure the cursor is visible */
     term_xtra(TERM_XTRA_SHAPE, 1);
@@ -653,8 +689,9 @@ static void Term_nuke_gcu(term_type *t)
 static void term_string_push(char *buf)
 {
     int i, l = strlen(buf);
-    for (i = l; i >= 0; i--)
+    for (i = l; i >= 0; i--) {
         term_key_push(buf[i]);
+    }
 }
 
 #ifdef USE_GETCH
@@ -662,7 +699,7 @@ static void term_string_push(char *buf)
 /*
  * Process events, with optional wait
  */
-static errr Term_xtra_gcu_event(int v)
+static errr game_term_xtra_gcu_event(int v)
 {
     int i, k;
 
@@ -672,39 +709,43 @@ static errr Term_xtra_gcu_event(int v)
         char *bp = buf;
 
         /* Paranoia -- Wait for it */
-        nodelay(stdscr, FALSE);
+        nodelay(stdscr, false);
 
         /* Get a keypress */
         i = getch();
 
         /* Broken input is special */
-        if (i == ERR)
+        if (i == ERR) {
             exit_game_panic(p_ptr);
-        if (i == EOF)
+        }
+        if (i == EOF) {
             exit_game_panic(p_ptr);
+        }
 
         *bp++ = (char)i;
 
         /* Do not wait for it */
-        nodelay(stdscr, TRUE);
+        nodelay(stdscr, true);
 
         while ((i = getch()) != EOF) {
-            if (i == ERR)
+            if (i == ERR) {
                 exit_game_panic(p_ptr);
+            }
             *bp++ = (char)i;
-            if (bp == &buf[255])
+            if (bp == &buf[255]) {
                 break;
+            }
         }
 
         /* Wait for it next time */
-        nodelay(stdscr, FALSE);
+        nodelay(stdscr, false);
 
         *bp = '\0';
 #ifdef JP
         char eucbuf[sizeof(buf)];
         /* strlen + 1 を渡して文字列終端('\0')を含めて変換する */
         if (utf8_to_euc(buf, strlen(buf) + 1, eucbuf, sizeof(eucbuf)) < 0) {
-            return (-1);
+            return -1;
         }
 #endif
         term_string_push(_(eucbuf, buf));
@@ -713,26 +754,28 @@ static errr Term_xtra_gcu_event(int v)
     /* Do not wait */
     else {
         /* Do not wait for it */
-        nodelay(stdscr, TRUE);
+        nodelay(stdscr, true);
 
         /* Check for keypresses */
         i = getch();
 
         /* Wait for it next time */
-        nodelay(stdscr, FALSE);
+        nodelay(stdscr, false);
 
         /* None ready */
-        if (i == ERR)
-            return (1);
-        if (i == EOF)
-            return (1);
+        if (i == ERR) {
+            return 1;
+        }
+        if (i == EOF) {
+            return 1;
+        }
 
         /* Enqueue the keypress */
         term_key_push(i);
     }
 
     /* Success */
-    return (0);
+    return 0;
 }
 
 #else /* USE_GETCH */
@@ -740,7 +783,7 @@ static errr Term_xtra_gcu_event(int v)
 /*
  * Process events (with optional wait)
  */
-static errr Term_xtra_gcu_event(int v)
+static errr game_term_xtra_gcu_event(int v)
 {
     int i, k;
 
@@ -754,15 +797,17 @@ static errr Term_xtra_gcu_event(int v)
         i = read(0, bp++, 1);
 
         /* Hack -- Handle bizarre "errors" */
-        if ((i <= 0) && (errno != EINTR))
+        if ((i <= 0) && (errno != EINTR)) {
             exit_game_panic(p_ptr);
+        }
 
         /* Get the current flags for stdin */
         k = fcntl(0, F_GETFL, 0);
 
         /* Oops */
-        if (k < 0)
-            return (1);
+        if (k < 0) {
+            return 1;
+        }
 
         /* Tell stdin not to block */
         if (fcntl(0, F_SETFL, k | O_NDELAY) >= 0) {
@@ -771,8 +816,9 @@ static errr Term_xtra_gcu_event(int v)
             }
 
             /* Replace the flags for stdin */
-            if (fcntl(0, F_SETFL, k))
-                return (1);
+            if (fcntl(0, F_SETFL, k)) {
+                return 1;
+            }
         }
 
         bp[0] = '\0';
@@ -780,7 +826,7 @@ static errr Term_xtra_gcu_event(int v)
         char eucbuf[sizeof(buf)];
         /* strlen + 1 を渡して文字列終端('\0')を含めて変換する */
         if (utf8_to_euc(buf, strlen(buf) + 1, eucbuf, sizeof(eucbuf)) < 0) {
-            return (-1);
+            return -1;
         }
 #endif
         term_string_push(_(eucbuf, buf));
@@ -792,30 +838,34 @@ static errr Term_xtra_gcu_event(int v)
         k = fcntl(0, F_GETFL, 0);
 
         /* Oops */
-        if (k < 0)
-            return (1);
+        if (k < 0) {
+            return 1;
+        }
 
         /* Tell stdin not to block */
-        if (fcntl(0, F_SETFL, k | O_NDELAY) < 0)
-            return (1);
+        if (fcntl(0, F_SETFL, k | O_NDELAY) < 0) {
+            return 1;
+        }
 
         /* Read one byte, if possible */
         i = read(0, buf, 1);
 
         /* Replace the flags for stdin */
-        if (fcntl(0, F_SETFL, k))
-            return (1);
+        if (fcntl(0, F_SETFL, k)) {
+            return 1;
+        }
 
         /* Ignore "invalid" keys */
-        if ((i != 1) || (!buf[0]))
-            return (1);
+        if ((i != 1) || (!buf[0])) {
+            return 1;
+        }
 
         /* Enqueue the keypress */
         term_key_push(buf[0]);
     }
 
     /* Success */
-    return (0);
+    return 0;
 }
 
 #endif /* USE_GETCH */
@@ -823,61 +873,103 @@ static errr Term_xtra_gcu_event(int v)
 /*
  * Hack -- make a sound
  */
-static errr Term_xtra_gcu_sound(int v)
+static errr game_term_xtra_gcu_sound(int v)
 {
     char buf[1024];
 
     /* Sound disabled */
-    if (!use_sound)
-        return (1);
+    if (!use_sound) {
+        return 1;
+    }
 
     /* Illegal sound */
-    if ((v < 0) || (v >= SOUND_MAX))
-        return (1);
+    if ((v < 0) || (v >= SOUND_MAX)) {
+        return 1;
+    }
 
     /* Unknown sound */
-    if (!sound_file[v])
-        return (1);
+    if (!sound_file[v]) {
+        return 1;
+    }
 
     sprintf(buf, "./gcusound.sh %s\n", sound_file[v]);
 
-    return (system(buf) < 0);
+    return system(buf) < 0;
+
+    return 0;
+}
+
+static int scale_color(int i, int j, int scale)
+{
+    return (angband_color_table[i][j] * (scale - 1) + 127) / 255;
+}
 
-    return (0);
+static int create_color(int i, int scale)
+{
+    int r = scale_color(i, 1, scale);
+    int g = scale_color(i, 2, scale);
+    int b = scale_color(i, 3, scale);
+    int rgb = 16 + scale * scale * r + scale * g + b;
+    /* In the case of white and black we need to use the ANSI colors */
+    if (r == g && g == b) {
+        if (b == 0) {
+            rgb = 0;
+        }
+        if (b == scale) {
+            rgb = 15;
+        }
+    }
+    return rgb;
 }
 
 /*
  * React to changes
  */
-static errr Term_xtra_gcu_react(void)
+static errr game_term_xtra_gcu_react(void)
 {
 
 #ifdef A_COLOR
 
-    int i;
-
-    /* Cannot handle color redefinition */
-    if (!can_fix_color)
-        return (0);
-
-    /* Set the colors */
-    for (i = 0; i < 16; i++) {
-        /* Set one color (note scaling) */
-        init_color(i, angband_color_table[i][1] * 1000 / 255, angband_color_table[i][2] * 1000 / 255, angband_color_table[i][3] * 1000 / 255);
+    if (!can_change_color()) {
+        if (COLORS == 256 || COLORS == 88) {
+            /* If we have more than 16 colors, find the best matches. These numbers
+             * correspond to xterm/rxvt's builtin color numbers--they do not
+             * correspond to curses' constants OR with curses' color pairs.
+             *
+             * XTerm has 216 (6*6*6) RGB colors, with each RGB setting 0-5.
+             * RXVT has 64 (4*4*4) RGB colors, with each RGB setting 0-3.
+             *
+             * Both also have the basic 16 ANSI colors, plus some extra grayscale
+             * colors which we do not use.
+             */
+            int scale = COLORS == 256 ? 6 : 4;
+            for (int i = 0; i < 16; i++) {
+                int fg = create_color(i, scale);
+                init_pair(i + 1, fg, bg_color);
+                colortable[i] = COLOR_PAIR(i + 1) | A_NORMAL;
+            }
+        }
+    } else {
+        for (int i = 0; i < 16; ++i) {
+            init_color(i,
+                (angband_color_table[i][1] * 1000) / 255,
+                (angband_color_table[i][2] * 1000) / 255,
+                (angband_color_table[i][3] * 1000) / 255);
+        }
     }
 
 #endif
 
     /* Success */
-    return (0);
+    return 0;
 }
 
 /*
  * Handle a "special request"
  */
-static errr Term_xtra_gcu(int n, int v)
+static errr game_term_xtra_gcu(int n, int v)
 {
-    term_data *td = (term_data *)(Term->data);
+    term_data *td = (term_data *)(game_term->data);
 
     /* Analyze the request */
     switch (n) {
@@ -885,7 +977,7 @@ static errr Term_xtra_gcu(int n, int v)
     case TERM_XTRA_CLEAR:
         touchwin(td->win);
         (void)wclear(td->win);
-        return (0);
+        return 0;
 
     /* Make a noise */
     case TERM_XTRA_NOISE:
@@ -893,89 +985,87 @@ static errr Term_xtra_gcu(int n, int v)
 
     /* Make a special sound */
     case TERM_XTRA_SOUND:
-        return (Term_xtra_gcu_sound(v));
+        return game_term_xtra_gcu_sound(v);
 
     /* Flush the Curses buffer */
     case TERM_XTRA_FRESH:
         (void)wrefresh(td->win);
-        return (0);
-
-#ifdef USE_CURS_SET
+        return 0;
 
     /* Change the cursor visibility */
     case TERM_XTRA_SHAPE:
         curs_set(v);
-        return (0);
-
-#endif
+        return 0;
 
     /* Suspend/Resume curses */
     case TERM_XTRA_ALIVE:
-        return (Term_xtra_gcu_alive(v));
+        return game_term_xtra_gcu_alive(v);
 
     /* Process events */
     case TERM_XTRA_EVENT:
-        return (Term_xtra_gcu_event(v));
+        return game_term_xtra_gcu_event(v);
 
     /* Flush events */
     case TERM_XTRA_FLUSH:
-        while (!Term_xtra_gcu_event(FALSE))
+        while (!game_term_xtra_gcu_event(false)) {
             ;
-        return (0);
+        }
+        return 0;
 
     /* Delay */
     case TERM_XTRA_DELAY:
         usleep(1000 * v);
-        return (0);
+        return 0;
 
     /* React to events */
     case TERM_XTRA_REACT:
-        Term_xtra_gcu_react();
-        return (0);
+        game_term_xtra_gcu_react();
+        return 0;
     }
 
     /* Unknown */
-    return (1);
+    return 1;
 }
 
 /*
  * Actually MOVE the hardware cursor
  */
-static errr Term_curs_gcu(int x, int y)
+static errr game_term_curs_gcu(int x, int y)
 {
-    term_data *td = (term_data *)(Term->data);
+    term_data *td = (term_data *)(game_term->data);
 
     /* Literally move the cursor */
     wmove(td->win, y, x);
 
     /* Success */
-    return (0);
+    return 0;
 }
 
 /*
  * Erase a grid of space
  * Hack -- try to be "semi-efficient".
  */
-static errr Term_wipe_gcu(int x, int y, int n)
+static errr game_term_wipe_gcu(int x, int y, int n)
 {
-    term_data *td = (term_data *)(Term->data);
+    term_data *td = (term_data *)(game_term->data);
 
     /* Place cursor */
     wmove(td->win, y, x);
 
     /* Clear to end of line */
-    if (x + n >= 80) {
+    if (x + n >= td->t.wid) {
         wclrtoeol(td->win);
     }
 
     /* Clear some characters */
     else {
-        while (n-- > 0)
+        while (n-- > 0) {
             waddch(td->win, ' ');
+        }
     }
 
     /* Success */
-    return (0);
+    return 0;
 }
 
 #ifdef USE_NCURSES_ACS
@@ -987,9 +1077,9 @@ static errr Term_wipe_gcu(int x, int y, int n)
  * think hard about how map_info() in cave.c should handle the color
  * of something that we here draw in reverse. It's not so simple, alas.
  */
-static void Term_acs_text_gcu(int x, int y, int n, byte a, concptr s)
+static void game_term_acs_text_gcu(int x, int y, int n, byte a, concptr s)
 {
-    term_data *td = (term_data *)(Term->data);
+    term_data *td = (term_data *)(game_term->data);
     int i;
 
     /* position the cursor */
@@ -1011,16 +1101,16 @@ static void Term_acs_text_gcu(int x, int y, int n, byte a, concptr s)
 /*
  * Place some text on the screen using an attribute
  */
-static errr Term_text_gcu(int x, int y, int n, byte a, concptr s)
+static errr game_term_text_gcu(int x, int y, int n, byte a, concptr s)
 {
-    term_data *td = (term_data *)(Term->data);
+    term_data *td = (term_data *)(game_term->data);
 
 #ifdef USE_NCURSES_ACS
     /* do we have colors + 16 ? */
     /* then call special routine for drawing special characters */
     if (a & 0x10) {
-        Term_acs_text_gcu(x, y, n, a, s);
-        return (0);
+        game_term_acs_text_gcu(x, y, n, a, s);
+        return 0;
     }
 #endif
 
@@ -1029,31 +1119,38 @@ static errr Term_text_gcu(int x, int y, int n, byte a, concptr s)
 
 #ifdef A_COLOR
     /* Set the color */
-    if (can_use_color)
+    if (can_use_color) {
         wattrset(td->win, colortable[a & 0x0F]);
+    }
 #endif
 
 #ifdef JP
     char text[1024];
     int text_len = euc_to_utf8(s, n, text, sizeof(text));
     if (text_len < 0) {
-        return (-1);
+        return -1;
     }
 #endif
     /* Add the text */
     waddnstr(td->win, _(text, s), _(text_len, n));
 
     /* Success */
-    return (0);
+    return 0;
 }
 
-static errr term_data_init(term_data *td, int rows, int cols, int y, int x)
+/**
+ * Create a window for the given "term_data" argument.
+ *
+ * Assumes legal arguments.
+ */
+static errr term_data_init_gcu(term_data *td, int rows, int cols, int y, int x)
 {
     term_type *t = &td->t;
 
     /* Make sure the window has a positive size */
-    if (rows <= 0 || cols <= 0)
-        return (0);
+    if (rows <= 0 || cols <= 0) {
+        return 0;
+    }
 
     /* Create a window */
     td->win = newwin(rows, cols, y, x);
@@ -1061,28 +1158,28 @@ static errr term_data_init(term_data *td, int rows, int cols, int y, int x)
     /* Make sure we succeed */
     if (!td->win) {
         plog("Failed to setup curses window.");
-        return (-1);
+        return -1;
     }
 
     /* Initialize the term */
     term_init(t, cols, rows, 256);
 
     /* Avoid the bottom right corner */
-    t->icky_corner = TRUE;
+    t->icky_corner = true;
 
     /* Erase with "white space" */
     t->attr_blank = TERM_WHITE;
     t->char_blank = ' ';
 
     /* Set some hooks */
-    t->init_hook = Term_init_gcu;
-    t->nuke_hook = Term_nuke_gcu;
+    t->init_hook = game_term_init_gcu;
+    t->nuke_hook = game_term_nuke_gcu;
 
     /* Set some more hooks */
-    t->text_hook = Term_text_gcu;
-    t->wipe_hook = Term_wipe_gcu;
-    t->curs_hook = Term_curs_gcu;
-    t->xtra_hook = Term_xtra_gcu;
+    t->text_hook = game_term_text_gcu;
+    t->wipe_hook = game_term_wipe_gcu;
+    t->curs_hook = game_term_curs_gcu;
+    t->xtra_hook = game_term_xtra_gcu;
 
     /* Save the data */
     t->data = td;
@@ -1091,7 +1188,49 @@ static errr term_data_init(term_data *td, int rows, int cols, int y, int x)
     term_activate(t);
 
     /* Success */
-    return (0);
+    return 0;
+}
+
+/**
+ * Simple helper
+ */
+static errr term_data_init(term_data *td)
+{
+    return term_data_init_gcu(td, td->r.cy, td->r.cx, td->r.y, td->r.x);
+}
+
+/* Parse 27,15,*x30 up to the 'x'. * gets converted to a big number
+   Parse 32,* until the end. Return count of numbers parsed */
+static int _parse_size_list(const char *arg, int sizes[], int max)
+{
+    int i = 0;
+    const char *start = arg;
+    const char *stop = arg;
+
+    for (;;) {
+        if (!*stop || !isdigit(*stop)) {
+            if (i >= max) {
+                break;
+            }
+            if (*start == '*') {
+                sizes[i] = 255;
+            } else {
+                /* rely on atoi("23,34,*") -> 23
+                   otherwise, copy [start, stop) into a new buffer first.*/
+                sizes[i] = atoi(start);
+            }
+            i++;
+            if (!*stop || *stop != ',') {
+                break;
+            }
+
+            stop++;
+            start = stop;
+        } else {
+            stop++;
+        }
+    }
+    return i;
 }
 
 static void hook_quit(concptr str)
@@ -1133,9 +1272,19 @@ errr init_gcu(int argc, char *argv[])
     /* Extract the normal keymap */
     keymap_norm_prepare();
 
+    bool nobigscreen = false;
+
+    /* Parse args */
+    for (i = 1; i < argc; i++) {
+        if (prefix(argv[i], "-o")) {
+            nobigscreen = true;
+        }
+    }
+
     /* Initialize for others systems */
-    if (initscr() == (WINDOW *)ERR)
-        return (-1);
+    if (initscr() == (WINDOW *)ERR) {
+        return -1;
+    }
 
     /* Activate hooks */
     quit_aux = hook_quit;
@@ -1143,8 +1292,9 @@ errr init_gcu(int argc, char *argv[])
 
     /* Hack -- Require large screen, or Quit with message */
     i = ((LINES < 24) || (COLS < 80));
-    if (i)
-        quit("Angband needs an 80x24 'curses' screen");
+    if (i) {
+        quit_fmt("%s needs an 80x24 'curses' screen", std::string(VARIANT_NAME).c_str());
+    }
 
 #ifdef A_COLOR
 
@@ -1167,7 +1317,7 @@ errr init_gcu(int argc, char *argv[])
             }
 
             colortable[i] = COLOR_PAIR(i);
-            Term_xtra_gcu_react();
+            game_term_xtra_gcu_react();
         }
     }
     /* Attempt to use colors */
@@ -1213,7 +1363,7 @@ errr init_gcu(int argc, char *argv[])
             plog("Cannot initialize sound!");
 
             /* Cannot enable */
-            arg_sound = FALSE;
+            arg_sound = false;
         }
 
         /* Change setting */
@@ -1224,7 +1374,7 @@ errr init_gcu(int argc, char *argv[])
     if (arg_graphics) {
         /* if USE_NCURSES_ACS is defined, we can do something with graphics in curses! */
 #ifdef USE_NCURSES_ACS
-        use_graphics = TRUE;
+        use_graphics = true;
 #endif
     }
 
@@ -1233,7 +1383,7 @@ errr init_gcu(int argc, char *argv[])
 #ifdef USE_GETCH
 
     /* Paranoia -- Assume no waiting */
-    nodelay(stdscr, FALSE);
+    nodelay(stdscr, false);
 
 #endif
 
@@ -1247,56 +1397,219 @@ errr init_gcu(int argc, char *argv[])
     keymap_game_prepare();
 
     /*** Now prepare the term(s) ***/
-    for (i = 0; i < num_term; i++) {
-        int rows, cols;
-        int y, x;
-
-        switch (i) {
-        /* Upper left */
-        case 0:
-            rows = 24;
-            cols = 80;
-            y = x = 0;
-            break;
-        /* Lower left */
-        case 1:
-            rows = LINES - 25;
-            cols = 80;
-            y = 24;
-            x = 0;
-            break;
-        /* Upper right */
-        case 2:
-            rows = 24;
-            cols = COLS - 81;
-            y = 0;
-            x = 81;
-            break;
-        /* Lower right */
-        case 3:
-            rows = LINES - 25;
-            cols = COLS - 81;
-            y = 24;
-            x = 81;
-            break;
-        /* XXX */
-        default:
-            rows = cols = 0;
-            y = x = 0;
-            break;
-        }
+    if (nobigscreen) {
+        /* Create several terms */
+        for (i = 0; i < num_term; i++) {
+            int rows, cols, y, x;
+
+            /* Decide on size and position */
+            switch (i) {
+            /* Upper left */
+            case 0: {
+                rows = 24;
+                cols = 80;
+                y = x = 0;
+                break;
+            }
+
+            /* Lower left */
+            case 1: {
+                rows = LINES - 25;
+                cols = 80;
+                y = 25;
+                x = 0;
+                break;
+            }
+
+            /* Upper right */
+            case 2: {
+                rows = 24;
+                cols = COLS - 81;
+                y = 0;
+                x = 81;
+                break;
+            }
+
+            /* Lower right */
+            case 3: {
+                rows = LINES - 25;
+                cols = COLS - 81;
+                y = 25;
+                x = 81;
+                break;
+            }
 
-        /* No non-windows */
-        if (rows <= 0 || cols <= 0)
-            continue;
+            /* XXX */
+            default: {
+                rows = cols = y = x = 0;
+                break;
+            }
+            }
+
+            /* Skip non-existant windows */
+            if (rows <= 0 || cols <= 0) {
+                continue;
+            }
 
-        /* Initialize */
-        term_data_init(&data[next_win], rows, cols, y, x);
+            /* Create a term */
+            term_data_init_gcu(&data[next_win], rows, cols, y, x);
 
-        /* Store */
-        angband_term[next_win] = Term;
+            /* Remember the term */
+            angband_term[next_win] = &data[next_win].t;
 
-        next_win++;
+            /* One more window */
+            next_win++;
+        }
+    } else
+    /* Parse Args and Prepare the Terminals. Rectangles are specified
+      as Width x Height, right? The game will allow you to have two
+      strips of extra terminals, one on the right and one on the bottom.
+      The map terminal will than fit in as big as possible in the remaining
+      space.
+      Examples:
+        angband -mgcu -- -right 30x27,* -bottom *x7 will layout as
+        Term-0: Map (COLS-30)x(LINES-7) | Term-1: 30x27
+        --------------------------------|----------------------
+        <----Term-3: (COLS-30)x7------->| Term-2: 30x(LINES-27)
+        composband -mgcu -- -bottom *x7 -right 30x27,* will layout as
+        Term-0: Map (COLS-30)x(LINES-7) | Term-2: 30x27
+                                        |------------------------------
+                                        | Term-3: 30x(LINES-27)
+        ---------------------------------------------------------------
+        <----------Term-1: (COLS)x7----------------------------------->
+        Notice the effect on the bottom terminal by specifying its argument
+        second or first. Notice the sequence numbers for the various terminals
+        as you will have to blindly configure them in the window setup screen.
+        EDIT: Added support for -left and -top.
+    */
+    {
+        rect_t remaining = rect(0, 0, COLS, LINES);
+        int spacer_cx = 1;
+        int spacer_cy = 1;
+        int next_term = 1;
+        int term_ct = 1;
+
+        for (i = 1; i < argc; i++) {
+            if (streq(argv[i], "-spacer")) {
+                i++;
+                if (i >= argc) {
+                    quit("Missing size specifier for -spacer");
+                }
+                sscanf(argv[i], "%dx%d", &spacer_cx, &spacer_cy);
+            } else if (streq(argv[i], "-right") || streq(argv[i], "-left")) {
+                const char *arg, *tmp;
+                bool left = streq(argv[i], "-left");
+                int cx, cys[MAX_TERM_DATA] = { 0 }, ct, j, x, y;
+
+                i++;
+                if (i >= argc) {
+                    quit(format("Missing size specifier for -%s", left ? "left" : "right"));
+                }
+
+                arg = argv[i];
+                tmp = strchr(arg, 'x');
+                if (!tmp) {
+                    quit(format("Expected something like -%s 60x27,* for two %s hand terminals of 60 columns, the first 27 lines and the second whatever is left.", left ? "left" : "right", left ? "left" : "right"));
+                }
+                cx = atoi(arg);
+                remaining.cx -= cx;
+                if (left) {
+                    x = remaining.x;
+                    y = remaining.y;
+                    remaining.x += cx;
+                } else {
+                    x = remaining.x + remaining.cx;
+                    y = remaining.y;
+                }
+                remaining.cx -= spacer_cx;
+                if (left) {
+                    remaining.x += spacer_cx;
+                }
+
+                tmp++;
+                ct = _parse_size_list(tmp, cys, MAX_TERM_DATA);
+                for (j = 0; j < ct; j++) {
+                    int cy = cys[j];
+                    if (y + cy > remaining.y + remaining.cy) {
+                        cy = remaining.y + remaining.cy - y;
+                    }
+                    if (next_term >= MAX_TERM_DATA) {
+                        quit(format("Too many terminals. Only %d are allowed.", MAX_TERM_DATA));
+                    }
+                    if (cy <= 0) {
+                        quit(format("Out of bounds in -%s: %d is too large (%d rows max for this strip)",
+                            left ? "left" : "right", cys[j], remaining.cy));
+                    }
+                    data[next_term++].r = rect(x, y, cx, cy);
+                    y += cy + spacer_cy;
+                    term_ct++;
+                }
+            } else if (streq(argv[i], "-top") || streq(argv[i], "-bottom")) {
+                const char *arg, *tmp;
+                bool top = streq(argv[i], "-top");
+                int cy, cxs[MAX_TERM_DATA] = { 0 }, ct, j, x, y;
+
+                i++;
+                if (i >= argc) {
+                    quit(format("Missing size specifier for -%s", top ? "top" : "bottom"));
+                }
+
+                arg = argv[i];
+                tmp = strchr(arg, 'x');
+                if (!tmp) {
+                    quit(format("Expected something like -%s *x7 for a single %s terminal of 7 lines using as many columns as are available.", top ? "top" : "bottom", top ? "top" : "bottom"));
+                }
+                tmp++;
+                cy = atoi(tmp);
+                ct = _parse_size_list(arg, cxs, MAX_TERM_DATA);
+
+                remaining.cy -= cy;
+                if (top) {
+                    x = remaining.x;
+                    y = remaining.y;
+                    remaining.y += cy;
+                } else {
+                    x = remaining.x;
+                    y = remaining.y + remaining.cy;
+                }
+                remaining.cy -= spacer_cy;
+                if (top) {
+                    remaining.y += spacer_cy;
+                }
+
+                tmp++;
+                for (j = 0; j < ct; j++) {
+                    int cx = cxs[j];
+                    if (x + cx > remaining.x + remaining.cx) {
+                        cx = remaining.x + remaining.cx - x;
+                    }
+                    if (next_term >= MAX_TERM_DATA) {
+                        quit(format("Too many terminals. Only %d are allowed.", MAX_TERM_DATA));
+                    }
+                    if (cx <= 0) {
+                        quit(format("Out of bounds in -%s: %d is too large (%d cols max for this strip)",
+                            top ? "top" : "bottom", cxs[j], remaining.cx));
+                    }
+                    data[next_term++].r = rect(x, y, cx, cy);
+                    x += cx + spacer_cx;
+                    term_ct++;
+                }
+            }
+        }
+
+        /* Map Terminal */
+        if (remaining.cx < MIN_TERM0_COLS || remaining.cy < MIN_TERM0_LINES) {
+            quit_fmt("Failed: %s needs an %dx%d map screen, not %dx%d", std::string(VARIANT_NAME).c_str(), MIN_TERM0_COLS, MIN_TERM0_LINES, remaining.cx, remaining.cy);
+        }
+        data[0].r = remaining;
+        term_data_init(&data[0]);
+        angband_term[0] = game_term;
+
+        /* Child Terminals */
+        for (next_term = 1; next_term < term_ct; next_term++) {
+            term_data_init(&data[next_term]);
+            angband_term[next_term] = game_term;
+        }
     }
 
     /* Activate the "Angband" window screen */
@@ -1306,7 +1619,7 @@ errr init_gcu(int argc, char *argv[])
     term_screen = &data[0].t;
 
     /* Success */
-    return (0);
+    return 0;
 }
 
 #endif /* USE_GCU */