OSDN Git Service

[Refactor] Use built-in literals for bool types
[hengbandforosx/hengbandosx.git] / src / main-gcu.cpp
1 /* File: main-gcu.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison, and others
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10
11 /* Purpose: Allow use of Unix "curses" with Angband -BEN- */
12
13 /*
14  * This file has been modified to use multiple text windows if your screen
15  * is larger than 80x25.  By Keldon Jones (keldon@umr.edu).
16  *
17  * Also included is Keldon Jones patch to get better colors. To switch to
18  * a term that supports this, see this posting:
19  *
20  * From keldon@umr.edu Thu Apr 01 05:40:14 1999
21  * Sender: KELDON JONES <keldon@saucer.cc.umr.edu>
22  * From: Keldon Jones <keldon@umr.edu>
23  * Subject: Re: Linux colour prob (Or: question for Greg)
24  * Newsgroups: rec.games.roguelike.angband
25  * References: <slrn7g1jlp.gj9.scarblac-spamtrap@flits104-37.flits.rug.nl> <3700f96b.1593384@news.polsl.gliwice.pl> <slrn7g36er.fm4.wooledge@jekyll.local>
26  * X-Newsreader: TIN [UNIX 1.3 unoff BETA 970625; 9000/780 HP-UX B.10.20]
27  * NNTP-Posting-Host: saucer.cc.umr.edu
28  * X-NNTP-Posting-Host: saucer.cc.umr.edu
29  * Message-ID: <370306be.0@news.cc.umr.edu>
30  * Date: 1 Apr 99 05:40:14 GMT
31  * Organization: University of Missouri - Rolla
32  * Lines: 199
33  * Path:
34  * xs4all!xs4all!newsfeed.wirehub.nl!news-peer.gip.net!news.gsl.net!gip.net!news.he.net!mercury.cts.com!alpha.sky.net!news.missouri.edu!news.cc.umr.edu!not-for-mail
35  * Xref: xs4all rec.games.roguelike.angband:86332
36  *
37  * Greg Wooledge <wooledge@kellnet.com> wrote:
38  * > Gwidon S. Naskrent (naskrent@artemida.amu.edu.pl) wrote:
39  *
40  * > >On 30 Mar 1999 13:17:18 GMT, scarblac-spamtrap@pino.selwerd.cx (Remco
41  * > >Gerlich) wrote:
42  *
43  * > >>I recently switched to Linux, and *bands work fine. I like
44  * > >>to play them in consoles, not in X. However, colour is wrong.
45  * > >>"Slate" and "light slate" are always light blue, instead
46  * > >>of some shade of grey. Colours are fine in X.
47  *
48  * > I actually noticed the Linux console color issue a very long time ago,
49  * > but since I always play under X, I never really investigated it.
50  *
51  * > You're absolutely right, though -- the Linux console colors are not
52  * > "right" for Angband.
53  *
54  *    I've noticed this myself, so I spent the evening fixing it.
55  * Well, sorta fixing it.  It's not perfect yet, and it may not be
56  * possible to get it perfect with VGA hardware and/or the current
57  * Linux kernel.
58  *
59  * > OK, reading on in terminfo(5):
60  *
61  * >    Color Handling
62  * >        Most color terminals are either `Tektronix-like'  or  `HP-
63  * >        like'.   Tektronix-like terminals have a predefined set of
64  * >        N colors (where N usually 8), and can  set  character-cell
65  * >        foreground and background characters independently, mixing
66  * >        them into N * N color-pairs.  On  HP-like  terminals,  the
67  * >        use must set each color pair up separately (foreground and
68  * >        background are  not  independently  settable).   Up  to  M
69  * >        color-pairs  may  be  set  up  from  2*M different colors.
70  * >        ANSI-compatible terminals are Tektronix-like.
71  *
72  * > The "linux" terminfo entry is definitely in the "Tektronix-like" family.
73  * > It has the "setaf" and "setab" capabilities for setting the foreground
74  * > and background colors to one of 8 basically hard-coded values:
75  *
76  * >              Color       #define       Value       RGB
77  * >              black     COLOR_BLACK       0     0, 0, 0
78  * >              red       COLOR_RED         1     max,0,0
79  * >              green     COLOR_GREEN       2     0,max,0
80  * >              yellow    COLOR_YELLOW      3     max,max,0
81  * >              blue      COLOR_BLUE        4     0,0,max
82  * >              magenta   COLOR_MAGENTA     5     max,0,max
83  * >              cyan      COLOR_CYAN        6     0,max,max
84  * >              white     COLOR_WHITE       7     max,max,max
85  *
86  *    Well, not quite.  Using certain escape sequences, an
87  * application (or better yet, curses) can redefine the colors (at
88  * least some of them) and then those are used.  Read the
89  * curs_color manpage, and the part about "ccc" and "initc" in the
90  * terminfo manpage.  This is what the part of main-gcu inside the
91  * "if (can_fix_color)" code does.
92  *
93  * > So, what does this mean to the Angband player?  Well, it means that
94  * > either there's nothing you can do about the console colors as long as
95  * > straight curses/ncurses is used, or if there is something to be done,
96  * > I'm not clever enough to figure out how to do it.
97  *
98  *    Well, it is possible, though you have to patch main-gcu
99  * and edit a terminfo entry.  Apparently the relevant code in
100  * main-gcu was never tested (it's broken in at least one major
101  * way).  Apply the patch at the end of this message (notice that
102  * we need to define REDEFINE_COLORS at some point near the
103  * beginning of the file).
104  *    Next, write this termcap entry to a file:
105  *
106  * linux-c|linux console 1.3.6+ with private palette for each virtual console,
107  *         ccc,
108  *         colors#16, pairs#64,
109  *         initc=\E]P%x%p1%{16}%/%02x%p1%{16}%/%02x%p1%{16}%/%02x,
110  *         oc=\E]R,
111  *         use=linux,
112  *
113  * and run "tic" on it to produce a new terminfo entry called
114  * "linux-c".  Especially note the "ccc" flag which says that we
115  * can redefine colors.  The ugly "initc" string is what tells
116  * the console how to redefine a color.  Now, just set your TERM
117  * variable to "linux-c" and try Angband again.  If I've
118  * remembered to tell you everything that I've done, you should
119  * get the weird light-blue slate changed to a gray.
120  *    Now, there are still lots of problems with this.
121  * Something (I don't think it's curses, either the kernel or
122  * the hardware itself) seems to be ignoring my color changes to
123  * colors 6 and 7, which is annoying.  Also, the normal "white"
124  * color is now way too bright, but it's now necessary to
125  * distinguish it from the other grays.
126  *    The kernel seems to support 16 colors, but you can
127  * only switch to 8 of those, due to VT102 compatibility, it
128  * seems.  I think it would be possible to patch the kernel and
129  * allow all 16 colors to be used, but I haven't built up the
130  * nerve to try that yet.
131  *    Let me know if you can improve on this any.  Some of
132  * this may actually work differently on other hardware (ugh).
133  *
134  *    Keldon
135  *
136  */
137
138 /*
139  * To use this file, you must define "USE_GCU" in the Makefile.
140  *
141  * Hack -- note that "angband.h" is included AFTER the #ifdef test.
142  * This was necessary because of annoying "curses.h" silliness.
143  *
144  * Note that this file is not "intended" to support non-Unix machines,
145  * nor is it intended to support VMS or other bizarre setups.
146  *
147  * Also, this package assumes that the underlying "curses" handles both
148  * the "nonl()" and "cbreak()" commands correctly, see the "OPTION" below.
149  *
150  * This code should work with most versions of "curses" or "ncurses",
151  * and the "main-ncu.c" file (and USE_NCU define) are no longer used.
152  *
153  * See also "USE_CAP" and "main-cap.c" for code that bypasses "curses"
154  * and uses the "termcap" information directly, or even bypasses the
155  * "termcap" information and sends direct vt100 escape sequences.
156  *
157  * XXX XXX XXX Consider the use of "savetty()" and "resetty()".
158  */
159
160 #include "game-option/runtime-arguments.h"
161 #include "game-option/special-options.h"
162 #include "io/exit-panic.h"
163 #include "io/files-util.h"
164 #include "locale/japanese.h"
165 #include "main/sound-definitions-table.h"
166 #include "main/sound-of-music.h"
167 #include "system/angband.h"
168 #include "system/player-type-definition.h"
169 #include "term/gameterm.h"
170 #include "term/term-color-types.h"
171 #include "util/angband-files.h"
172 #include "view/display-map.h"
173
174 #ifdef USE_GCU
175
176 /*
177  * Hack -- play games with "bool"
178  */
179 #if __STDC_VERSION__ < 199901L
180 #undef bool
181 #endif
182
183 /*
184  * Include the proper "header" file
185  */
186 #include <curses.h>
187
188 /**
189  * Simple rectangle type
190  */
191 struct rect_s {
192     int x, y;
193     int cx, cy;
194 };
195 typedef struct rect_s rect_t, *rect_ptr;
196
197 /* Trivial rectangle utility to make code a bit more readable */
198 static rect_t rect(int x, int y, int cx, int cy)
199 {
200     rect_t r;
201     r.x = x;
202     r.y = y;
203     r.cx = cx;
204     r.cy = cy;
205     return r;
206 }
207
208 /**
209  * Information about a term
210  */
211 struct term_data {
212     term_type t;
213     rect_t r;
214     WINDOW *win;
215 };
216
217 /* Max number of windows on screen */
218 #define MAX_TERM_DATA 4
219
220 /* Minimum main term size */
221 #define MIN_TERM0_LINES 24
222 #define MIN_TERM0_COLS 80
223
224 /* Information about our windows */
225 static term_data data[MAX_TERM_DATA];
226
227 /*
228  * Hack -- try to guess which systems use what commands
229  * Hack -- allow one of the "USE_Txxxxx" flags to be pre-set.
230  * Mega-Hack -- try to guess when "POSIX" is available.
231  * If the user defines two of these, we will probably crash.
232  */
233 #if !defined(USE_TCHARS)
234 #if defined(_POSIX_VERSION)
235 #define USE_TPOSIX
236 #else
237 #define USE_TCHARS
238 #endif
239 #endif
240
241 /*
242  * Try redefining the colors at startup.
243  */
244 #define REDEFINE_COLORS
245
246 /*
247  * POSIX stuff
248  */
249 #ifdef USE_TPOSIX
250 #include <sys/ioctl.h>
251 #include <termios.h>
252 #endif
253
254 /*
255  * One version needs this file
256  */
257 #ifdef USE_TERMIO
258 #include <sys/ioctl.h>
259 #include <termio.h>
260 #endif
261
262 /*
263  * The other needs this file
264  */
265 #ifdef USE_TCHARS
266 #include <sys/file.h>
267 #include <sys/ioctl.h>
268 #include <sys/param.h>
269 #include <sys/resource.h>
270 #include <sys/types.h>
271 #endif
272
273 #include <locale.h>
274
275 /*
276  * XXX XXX Hack -- POSIX uses "O_NONBLOCK" instead of "O_NDELAY"
277  *
278  * They should both work due to the "(i != 1)" test below.
279  */
280 #ifndef O_NDELAY
281 #define O_NDELAY O_NONBLOCK
282 #endif
283
284 /*
285  * OPTION: some machines lack "cbreak()"
286  * On these machines, we use an older definition
287  */
288 /* #define cbreak() crmode() */
289
290 /*
291  * OPTION: some machines cannot handle "nonl()" and "nl()"
292  * On these machines, we can simply ignore those commands.
293  */
294 /* #define nonl() */
295 /* #define nl() */
296
297 static concptr ANGBAND_DIR_XTRA_SOUND;
298
299 /*
300  * todo 有効活用されていない疑惑
301  * Flag set once "sound" has been initialized
302  */
303 static bool can_use_sound = false;
304
305 /*
306  * An array of sound file names
307  */
308 static concptr sound_file[SOUND_MAX];
309
310 /*
311  * Save the "normal" and "angband" terminal settings
312  */
313
314 #ifdef USE_TPOSIX
315
316 static struct termios norm_termios;
317
318 static struct termios game_termios;
319
320 #endif
321
322 #ifdef USE_TERMIO
323
324 static struct termio norm_termio;
325
326 static struct termio game_termio;
327
328 #endif
329
330 #ifdef USE_TCHARS
331 static struct ltchars norm_speciax_chars;
332 static struct sgttyb norm_ttyb;
333 static struct tchars norm_tchars;
334 static int norm_locax_chars;
335
336 static struct ltchars game_speciax_chars;
337 static struct sgttyb game_ttyb;
338 static struct tchars game_tchars;
339 static int game_locax_chars;
340 #endif
341
342 /*
343  * Hack -- Number of initialized "term" structures
344  */
345 static int active = 0;
346
347 #ifdef A_COLOR
348 /*
349  * Hack -- define "A_BRIGHT" to be "A_BOLD", because on many
350  * machines, "A_BRIGHT" produces ugly "inverse" video.
351  */
352 #ifndef A_BRIGHT
353 #define A_BRIGHT A_BOLD
354 #endif
355
356 /*
357  * Software flag -- we are allowed to use color
358  */
359 static int can_use_color = false;
360
361 /*
362  * Software flag -- we are allowed to change the colors
363  */
364 static int can_fix_color = false;
365
366 /*
367  * Simple Angband to Curses color conversion table
368  */
369 static int colortable[16];
370
371 /**
372  * Background color we should draw with; either BLACK or DEFAULT
373  */
374 static int bg_color = COLOR_BLACK;
375
376 #endif
377
378 /*
379  * Place the "keymap" into its "normal" state
380  */
381 static void keymap_norm(void)
382 {
383 #ifdef USE_TPOSIX
384     /* restore the saved values of the special chars */
385     (void)tcsetattr(0, TCSAFLUSH, &norm_termios);
386 #endif
387
388 #ifdef USE_TERMIO
389     /* restore the saved values of the special chars */
390     (void)ioctl(0, TCSETA, (char *)&norm_termio);
391 #endif
392
393 #ifdef USE_TCHARS
394     /* restore the saved values of the special chars */
395     (void)ioctl(0, TIOCSLTC, (char *)&norm_speciax_chars);
396     (void)ioctl(0, TIOCSETP, (char *)&norm_ttyb);
397     (void)ioctl(0, TIOCSETC, (char *)&norm_tchars);
398     (void)ioctl(0, TIOCLSET, (char *)&norm_locax_chars);
399 #endif
400 }
401
402 /*
403  * Place the "keymap" into the "game" state
404  */
405 static void keymap_game(void)
406 {
407 #ifdef USE_TPOSIX
408     /* restore the saved values of the special chars */
409     (void)tcsetattr(0, TCSAFLUSH, &game_termios);
410 #endif
411
412 #ifdef USE_TERMIO
413     /* restore the saved values of the special chars */
414     (void)ioctl(0, TCSETA, (char *)&game_termio);
415 #endif
416
417 #ifdef USE_TCHARS
418     /* restore the saved values of the special chars */
419     (void)ioctl(0, TIOCSLTC, (char *)&game_speciax_chars);
420     (void)ioctl(0, TIOCSETP, (char *)&game_ttyb);
421     (void)ioctl(0, TIOCSETC, (char *)&game_tchars);
422     (void)ioctl(0, TIOCLSET, (char *)&game_locax_chars);
423 #endif
424 }
425
426 /*
427  * Save the normal keymap
428  */
429 static void keymap_norm_prepare(void)
430 {
431 #ifdef USE_TPOSIX
432     /* Get the normal keymap */
433     tcgetattr(0, &norm_termios);
434 #endif
435
436 #ifdef USE_TERMIO
437     /* Get the normal keymap */
438     (void)ioctl(0, TCGETA, (char *)&norm_termio);
439 #endif
440
441 #ifdef USE_TCHARS
442     /* Get the normal keymap */
443     (void)ioctl(0, TIOCGETP, (char *)&norm_ttyb);
444     (void)ioctl(0, TIOCGLTC, (char *)&norm_speciax_chars);
445     (void)ioctl(0, TIOCGETC, (char *)&norm_tchars);
446     (void)ioctl(0, TIOCLGET, (char *)&norm_locax_chars);
447 #endif
448 }
449
450 /*
451  * Save the keymaps (normal and game)
452  */
453 static void keymap_game_prepare(void)
454 {
455 #ifdef USE_TPOSIX
456     /* Acquire the current mapping */
457     tcgetattr(0, &game_termios);
458
459     /* Force "Ctrl-C" to interupt */
460     game_termios.c_cc[VINTR] = (char)3;
461
462     /* Force "Ctrl-Z" to suspend */
463     game_termios.c_cc[VSUSP] = (char)26;
464
465     /* Hack -- Leave "VSTART/VSTOP" alone */
466
467     /* Disable the standard control characters */
468     game_termios.c_cc[VQUIT] = (char)-1;
469     game_termios.c_cc[VERASE] = (char)-1;
470     game_termios.c_cc[VKILL] = (char)-1;
471     game_termios.c_cc[VEOF] = (char)-1;
472     game_termios.c_cc[VEOL] = (char)-1;
473
474     /* Normally, block until a character is read */
475     game_termios.c_cc[VMIN] = 1;
476     game_termios.c_cc[VTIME] = 0;
477 #endif
478
479 #ifdef USE_TERMIO
480     /* Acquire the current mapping */
481     (void)ioctl(0, TCGETA, (char *)&game_termio);
482
483     /* Force "Ctrl-C" to interupt */
484     game_termio.c_cc[VINTR] = (char)3;
485
486     /* Force "Ctrl-Z" to suspend */
487     game_termio.c_cc[VSUSP] = (char)26;
488
489     /* Disable the standard control characters */
490     game_termio.c_cc[VQUIT] = (char)-1;
491     game_termio.c_cc[VERASE] = (char)-1;
492     game_termio.c_cc[VKILL] = (char)-1;
493     game_termio.c_cc[VEOF] = (char)-1;
494     game_termio.c_cc[VEOL] = (char)-1;
495
496     /* Normally, block until a character is read */
497     game_termio.c_cc[VMIN] = 1;
498     game_termio.c_cc[VTIME] = 0;
499 #endif
500
501 #ifdef USE_TCHARS
502     /* Get the default game characters */
503     (void)ioctl(0, TIOCGETP, (char *)&game_ttyb);
504     (void)ioctl(0, TIOCGLTC, (char *)&game_speciax_chars);
505     (void)ioctl(0, TIOCGETC, (char *)&game_tchars);
506     (void)ioctl(0, TIOCLGET, (char *)&game_locax_chars);
507
508     /* Force suspend (^Z) */
509     game_speciax_chars.t_suspc = (char)26;
510
511     /* Cancel some things */
512     game_speciax_chars.t_dsuspc = (char)-1;
513     game_speciax_chars.t_rprntc = (char)-1;
514     game_speciax_chars.t_flushc = (char)-1;
515     game_speciax_chars.t_werasc = (char)-1;
516     game_speciax_chars.t_lnextc = (char)-1;
517
518     /* Force interupt (^C) */
519     game_tchars.t_intrc = (char)3;
520
521     /* Force start/stop (^Q, ^S) */
522     game_tchars.t_startc = (char)17;
523     game_tchars.t_stopc = (char)19;
524
525     /* Cancel some things */
526     game_tchars.t_quitc = (char)-1;
527     game_tchars.t_eofc = (char)-1;
528     game_tchars.t_brkc = (char)-1;
529 #endif
530 }
531
532 /*
533  * Suspend/Resume
534  */
535 static errr Term_xtra_gcu_alive(int v)
536 {
537     if (!v) {
538         /* Go to normal keymap mode */
539         keymap_norm();
540
541         /* Restore modes */
542         nocbreak();
543         echo();
544         nl();
545
546         /* Hack -- make sure the cursor is visible */
547         term_xtra(TERM_XTRA_SHAPE, 1);
548
549         /* Flush the curses buffer */
550         (void)refresh();
551
552         /* this moves curses to bottom right corner */
553         mvcur(getcury(curscr), getcurx(curscr), LINES - 1, 0);
554
555         /* Exit curses */
556         endwin();
557
558         /* Flush the output */
559         (void)fflush(stdout);
560     } else {
561         /* Restore the settings */
562         cbreak();
563         noecho();
564         nonl();
565
566         /* Go to angband keymap mode */
567         keymap_game();
568     }
569
570     return (0);
571 }
572
573 /*
574  * Check for existance of a file
575  */
576 static bool check_file(concptr s)
577 {
578     FILE *fff;
579     fff = fopen(s, "r");
580     if (!fff)
581         return false;
582
583     fclose(fff);
584     return true;
585 }
586
587 /*
588  * Initialize sound
589  */
590 static bool init_sound(void)
591 {
592     /* Initialize once */
593     if (can_use_sound)
594         return can_use_sound;
595
596     int i;
597     char wav[128];
598     char buf[1024];
599
600     /* Prepare the sounds */
601     for (i = 1; i < SOUND_MAX; i++) {
602         /* Extract name of sound file */
603         sprintf(wav, "%s.wav", angband_sound_name[i]);
604
605         /* Access the sound */
606         path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_SOUND, wav);
607
608         /* Save the sound filename, if it exists */
609         if (check_file(buf))
610             sound_file[i] = string_make(buf);
611     }
612
613     /* Sound available */
614     can_use_sound = true;
615     return (can_use_sound);
616 }
617
618 /*
619  * Init the "curses" system
620  */
621 static void Term_init_gcu(term_type *t)
622 {
623     term_data *td = (term_data *)(t->data);
624
625     /* Count init's, handle first */
626     if (active++ != 0)
627         return;
628
629     /* Erase the screen */
630     (void)wclear(td->win);
631
632     /* Reset the cursor */
633     (void)wmove(td->win, 0, 0);
634
635     /* Flush changes */
636     (void)wrefresh(td->win);
637
638     /* Game keymap */
639     keymap_game();
640 }
641
642 /*
643  * Nuke the "curses" system
644  */
645 static void Term_nuke_gcu(term_type *t)
646 {
647     term_data *td = (term_data *)(t->data);
648
649     /* Delete this window */
650     delwin(td->win);
651
652     /* Count nuke's, handle last */
653     if (--active != 0)
654         return;
655
656     /* Hack -- make sure the cursor is visible */
657     term_xtra(TERM_XTRA_SHAPE, 1);
658
659 #ifdef A_COLOR
660     /* Reset colors to defaults */
661     start_color();
662 #endif
663
664     /* This moves curses to bottom right corner */
665     mvcur(getcury(curscr), getcurx(curscr), LINES - 1, 0);
666
667     /* Flush the curses buffer */
668     (void)refresh();
669
670     /* Exit curses */
671     endwin();
672
673     /* Flush the output */
674     (void)fflush(stdout);
675
676     /* Normal keymap */
677     keymap_norm();
678 }
679
680 /*
681  * Push multiple keys reversal
682  */
683 static void term_string_push(char *buf)
684 {
685     int i, l = strlen(buf);
686     for (i = l; i >= 0; i--)
687         term_key_push(buf[i]);
688 }
689
690 #ifdef USE_GETCH
691
692 /*
693  * Process events, with optional wait
694  */
695 static errr Term_xtra_gcu_event(int v)
696 {
697     int i, k;
698
699     /* Wait */
700     if (v) {
701         char buf[256];
702         char *bp = buf;
703
704         /* Paranoia -- Wait for it */
705         nodelay(stdscr, false);
706
707         /* Get a keypress */
708         i = getch();
709
710         /* Broken input is special */
711         if (i == ERR)
712             exit_game_panic(p_ptr);
713         if (i == EOF)
714             exit_game_panic(p_ptr);
715
716         *bp++ = (char)i;
717
718         /* Do not wait for it */
719         nodelay(stdscr, true);
720
721         while ((i = getch()) != EOF) {
722             if (i == ERR)
723                 exit_game_panic(p_ptr);
724             *bp++ = (char)i;
725             if (bp == &buf[255])
726                 break;
727         }
728
729         /* Wait for it next time */
730         nodelay(stdscr, false);
731
732         *bp = '\0';
733 #ifdef JP
734         char eucbuf[sizeof(buf)];
735         /* strlen + 1 を渡して文字列終端('\0')を含めて変換する */
736         if (utf8_to_euc(buf, strlen(buf) + 1, eucbuf, sizeof(eucbuf)) < 0) {
737             return (-1);
738         }
739 #endif
740         term_string_push(_(eucbuf, buf));
741     }
742
743     /* Do not wait */
744     else {
745         /* Do not wait for it */
746         nodelay(stdscr, true);
747
748         /* Check for keypresses */
749         i = getch();
750
751         /* Wait for it next time */
752         nodelay(stdscr, false);
753
754         /* None ready */
755         if (i == ERR)
756             return (1);
757         if (i == EOF)
758             return (1);
759
760         /* Enqueue the keypress */
761         term_key_push(i);
762     }
763
764     /* Success */
765     return (0);
766 }
767
768 #else /* USE_GETCH */
769
770 /*
771  * Process events (with optional wait)
772  */
773 static errr Term_xtra_gcu_event(int v)
774 {
775     int i, k;
776
777     char buf[256];
778
779     /* Wait */
780     if (v) {
781         char *bp = buf;
782
783         /* Wait for one byte */
784         i = read(0, bp++, 1);
785
786         /* Hack -- Handle bizarre "errors" */
787         if ((i <= 0) && (errno != EINTR))
788             exit_game_panic(p_ptr);
789
790         /* Get the current flags for stdin */
791         k = fcntl(0, F_GETFL, 0);
792
793         /* Oops */
794         if (k < 0)
795             return (1);
796
797         /* Tell stdin not to block */
798         if (fcntl(0, F_SETFL, k | O_NDELAY) >= 0) {
799             if ((i = read(0, bp, 254)) > 0) {
800                 bp += i;
801             }
802
803             /* Replace the flags for stdin */
804             if (fcntl(0, F_SETFL, k))
805                 return (1);
806         }
807
808         bp[0] = '\0';
809 #ifdef JP
810         char eucbuf[sizeof(buf)];
811         /* strlen + 1 を渡して文字列終端('\0')を含めて変換する */
812         if (utf8_to_euc(buf, strlen(buf) + 1, eucbuf, sizeof(eucbuf)) < 0) {
813             return (-1);
814         }
815 #endif
816         term_string_push(_(eucbuf, buf));
817     }
818
819     /* Do not wait */
820     else {
821         /* Get the current flags for stdin */
822         k = fcntl(0, F_GETFL, 0);
823
824         /* Oops */
825         if (k < 0)
826             return (1);
827
828         /* Tell stdin not to block */
829         if (fcntl(0, F_SETFL, k | O_NDELAY) < 0)
830             return (1);
831
832         /* Read one byte, if possible */
833         i = read(0, buf, 1);
834
835         /* Replace the flags for stdin */
836         if (fcntl(0, F_SETFL, k))
837             return (1);
838
839         /* Ignore "invalid" keys */
840         if ((i != 1) || (!buf[0]))
841             return (1);
842
843         /* Enqueue the keypress */
844         term_key_push(buf[0]);
845     }
846
847     /* Success */
848     return (0);
849 }
850
851 #endif /* USE_GETCH */
852
853 /*
854  * Hack -- make a sound
855  */
856 static errr Term_xtra_gcu_sound(int v)
857 {
858     char buf[1024];
859
860     /* Sound disabled */
861     if (!use_sound)
862         return (1);
863
864     /* Illegal sound */
865     if ((v < 0) || (v >= SOUND_MAX))
866         return (1);
867
868     /* Unknown sound */
869     if (!sound_file[v])
870         return (1);
871
872     sprintf(buf, "./gcusound.sh %s\n", sound_file[v]);
873
874     return (system(buf) < 0);
875
876     return (0);
877 }
878
879 static int scale_color(int i, int j, int scale)
880 {
881     return (angband_color_table[i][j] * (scale - 1) + 127) / 255;
882 }
883
884 static int create_color(int i, int scale)
885 {
886     int r = scale_color(i, 1, scale);
887     int g = scale_color(i, 2, scale);
888     int b = scale_color(i, 3, scale);
889     int rgb = 16 + scale * scale * r + scale * g + b;
890     /* In the case of white and black we need to use the ANSI colors */
891     if (r == g && g == b) {
892         if (b == 0)
893             rgb = 0;
894         if (b == scale)
895             rgb = 15;
896     }
897     return rgb;
898 }
899
900 /*
901  * React to changes
902  */
903 static errr Term_xtra_gcu_react(void)
904 {
905
906 #ifdef A_COLOR
907
908     if (!can_change_color()) {
909         if (COLORS == 256 || COLORS == 88) {
910             /* If we have more than 16 colors, find the best matches. These numbers
911              * correspond to xterm/rxvt's builtin color numbers--they do not
912              * correspond to curses' constants OR with curses' color pairs.
913              *
914              * XTerm has 216 (6*6*6) RGB colors, with each RGB setting 0-5.
915              * RXVT has 64 (4*4*4) RGB colors, with each RGB setting 0-3.
916              *
917              * Both also have the basic 16 ANSI colors, plus some extra grayscale
918              * colors which we do not use.
919              */
920             int scale = COLORS == 256 ? 6 : 4;
921             for (int i = 0; i < 16; i++) {
922                 int fg = create_color(i, scale);
923                 init_pair(i + 1, fg, bg_color);
924                 colortable[i] = COLOR_PAIR(i + 1) | A_NORMAL;
925             }
926         }
927     } else {
928         for (int i = 0; i < 16; ++i) {
929             init_color(i,
930                 (angband_color_table[i][1] * 1000) / 255,
931                 (angband_color_table[i][2] * 1000) / 255,
932                 (angband_color_table[i][3] * 1000) / 255);
933         }
934     }
935
936 #endif
937
938     /* Success */
939     return (0);
940 }
941
942 /*
943  * Handle a "special request"
944  */
945 static errr Term_xtra_gcu(int n, int v)
946 {
947     term_data *td = (term_data *)(Term->data);
948
949     /* Analyze the request */
950     switch (n) {
951     /* Clear screen */
952     case TERM_XTRA_CLEAR:
953         touchwin(td->win);
954         (void)wclear(td->win);
955         return (0);
956
957     /* Make a noise */
958     case TERM_XTRA_NOISE:
959         return write(1, "\007", 1) != 1;
960
961     /* Make a special sound */
962     case TERM_XTRA_SOUND:
963         return (Term_xtra_gcu_sound(v));
964
965     /* Flush the Curses buffer */
966     case TERM_XTRA_FRESH:
967         (void)wrefresh(td->win);
968         return (0);
969
970     /* Change the cursor visibility */
971     case TERM_XTRA_SHAPE:
972         curs_set(v);
973         return (0);
974
975     /* Suspend/Resume curses */
976     case TERM_XTRA_ALIVE:
977         return (Term_xtra_gcu_alive(v));
978
979     /* Process events */
980     case TERM_XTRA_EVENT:
981         return (Term_xtra_gcu_event(v));
982
983     /* Flush events */
984     case TERM_XTRA_FLUSH:
985         while (!Term_xtra_gcu_event(false))
986             ;
987         return (0);
988
989     /* Delay */
990     case TERM_XTRA_DELAY:
991         usleep(1000 * v);
992         return (0);
993
994     /* React to events */
995     case TERM_XTRA_REACT:
996         Term_xtra_gcu_react();
997         return (0);
998     }
999
1000     /* Unknown */
1001     return (1);
1002 }
1003
1004 /*
1005  * Actually MOVE the hardware cursor
1006  */
1007 static errr Term_curs_gcu(int x, int y)
1008 {
1009     term_data *td = (term_data *)(Term->data);
1010
1011     /* Literally move the cursor */
1012     wmove(td->win, y, x);
1013
1014     /* Success */
1015     return (0);
1016 }
1017
1018 /*
1019  * Erase a grid of space
1020  * Hack -- try to be "semi-efficient".
1021  */
1022 static errr Term_wipe_gcu(int x, int y, int n)
1023 {
1024     term_data *td = (term_data *)(Term->data);
1025
1026     /* Place cursor */
1027     wmove(td->win, y, x);
1028
1029     /* Clear to end of line */
1030     if (x + n >= 80) {
1031         wclrtoeol(td->win);
1032     }
1033
1034     /* Clear some characters */
1035     else {
1036         while (n-- > 0)
1037             waddch(td->win, ' ');
1038     }
1039
1040     /* Success */
1041     return (0);
1042 }
1043
1044 #ifdef USE_NCURSES_ACS
1045 /*
1046  * this function draws some ACS characters on the screen
1047  * for DOS-based users: these are the graphical chars (blocks, lines etc)
1048  *
1049  * unix-gurus: before you start adding other attributes like A_REVERSE
1050  * think hard about how map_info() in cave.c should handle the color
1051  * of something that we here draw in reverse. It's not so simple, alas.
1052  */
1053 static void Term_acs_text_gcu(int x, int y, int n, byte a, concptr s)
1054 {
1055     term_data *td = (term_data *)(Term->data);
1056     int i;
1057
1058     /* position the cursor */
1059     wmove(td->win, y, x);
1060
1061 #ifdef A_COLOR
1062     /* Set the color */
1063     wattrset(td->win, colortable[a & 0x0F]);
1064 #endif
1065
1066     for (i = 0; i < n; i++) {
1067         /* add acs_map of a */
1068         waddch(td->win, acs_map[(int)s[i]]);
1069     }
1070     wattrset(td->win, WA_NORMAL);
1071 }
1072 #endif
1073
1074 /*
1075  * Place some text on the screen using an attribute
1076  */
1077 static errr Term_text_gcu(int x, int y, int n, byte a, concptr s)
1078 {
1079     term_data *td = (term_data *)(Term->data);
1080
1081 #ifdef USE_NCURSES_ACS
1082     /* do we have colors + 16 ? */
1083     /* then call special routine for drawing special characters */
1084     if (a & 0x10) {
1085         Term_acs_text_gcu(x, y, n, a, s);
1086         return (0);
1087     }
1088 #endif
1089
1090     /* Move the cursor and dump the string */
1091     wmove(td->win, y, x);
1092
1093 #ifdef A_COLOR
1094     /* Set the color */
1095     if (can_use_color)
1096         wattrset(td->win, colortable[a & 0x0F]);
1097 #endif
1098
1099 #ifdef JP
1100     char text[1024];
1101     int text_len = euc_to_utf8(s, n, text, sizeof(text));
1102     if (text_len < 0) {
1103         return (-1);
1104     }
1105 #endif
1106     /* Add the text */
1107     waddnstr(td->win, _(text, s), _(text_len, n));
1108
1109     /* Success */
1110     return (0);
1111 }
1112
1113 /**
1114  * Create a window for the given "term_data" argument.
1115  *
1116  * Assumes legal arguments.
1117  */
1118 static errr term_data_init_gcu(term_data *td, int rows, int cols, int y, int x)
1119 {
1120     term_type *t = &td->t;
1121
1122     /* Make sure the window has a positive size */
1123     if (rows <= 0 || cols <= 0)
1124         return (0);
1125
1126     /* Create a window */
1127     td->win = newwin(rows, cols, y, x);
1128
1129     /* Make sure we succeed */
1130     if (!td->win) {
1131         plog("Failed to setup curses window.");
1132         return (-1);
1133     }
1134
1135     /* Initialize the term */
1136     term_init(t, cols, rows, 256);
1137
1138     /* Avoid the bottom right corner */
1139     t->icky_corner = true;
1140
1141     /* Erase with "white space" */
1142     t->attr_blank = TERM_WHITE;
1143     t->char_blank = ' ';
1144
1145     /* Set some hooks */
1146     t->init_hook = Term_init_gcu;
1147     t->nuke_hook = Term_nuke_gcu;
1148
1149     /* Set some more hooks */
1150     t->text_hook = Term_text_gcu;
1151     t->wipe_hook = Term_wipe_gcu;
1152     t->curs_hook = Term_curs_gcu;
1153     t->xtra_hook = Term_xtra_gcu;
1154
1155     /* Save the data */
1156     t->data = td;
1157
1158     /* Activate it */
1159     term_activate(t);
1160
1161     /* Success */
1162     return (0);
1163 }
1164
1165 /**
1166  * Simple helper
1167  */
1168 static errr term_data_init(term_data *td)
1169 {
1170     return term_data_init_gcu(td, td->r.cy, td->r.cx, td->r.y, td->r.x);
1171 }
1172
1173 /* Parse 27,15,*x30 up to the 'x'. * gets converted to a big number
1174    Parse 32,* until the end. Return count of numbers parsed */
1175 static int _parse_size_list(const char *arg, int sizes[], int max)
1176 {
1177     int i = 0;
1178     const char *start = arg;
1179     const char *stop = arg;
1180
1181     for (;;) {
1182         if (!*stop || !isdigit(*stop)) {
1183             if (i >= max)
1184                 break;
1185             if (*start == '*')
1186                 sizes[i] = 255;
1187             else {
1188                 /* rely on atoi("23,34,*") -> 23
1189                    otherwise, copy [start, stop) into a new buffer first.*/
1190                 sizes[i] = atoi(start);
1191             }
1192             i++;
1193             if (!*stop || *stop != ',')
1194                 break;
1195
1196             stop++;
1197             start = stop;
1198         } else
1199             stop++;
1200     }
1201     return i;
1202 }
1203
1204 static void hook_quit(concptr str)
1205 {
1206     /* Unused */
1207     (void)str;
1208
1209     /* Exit curses */
1210     endwin();
1211 }
1212
1213 /*
1214  * Prepare "curses" for use by the file "term.c"
1215  *
1216  * Installs the "hook" functions defined above, and then activates
1217  * the main screen "term", which clears the screen and such things.
1218  *
1219  * Someone should really check the semantics of "initscr()"
1220  */
1221 errr init_gcu(int argc, char *argv[])
1222 {
1223     int i;
1224
1225     int num_term = 4, next_win = 0;
1226     char path[1024];
1227
1228     /* Unused */
1229     (void)argc;
1230     (void)argv;
1231
1232     setlocale(LC_ALL, "");
1233
1234     /* Build the "sound" path */
1235     path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "sound");
1236
1237     /* Allocate the path */
1238     ANGBAND_DIR_XTRA_SOUND = string_make(path);
1239
1240     /* Extract the normal keymap */
1241     keymap_norm_prepare();
1242
1243     bool nobigscreen = false;
1244
1245     /* Parse args */
1246     for (i = 1; i < argc; i++) {
1247         if (prefix(argv[i], "-o")) {
1248             nobigscreen = true;
1249         }
1250     }
1251
1252     /* Initialize for others systems */
1253     if (initscr() == (WINDOW *)ERR)
1254         return (-1);
1255
1256     /* Activate hooks */
1257     quit_aux = hook_quit;
1258     core_aux = hook_quit;
1259
1260     /* Hack -- Require large screen, or Quit with message */
1261     i = ((LINES < 24) || (COLS < 80));
1262     if (i)
1263         quit("Angband needs an 80x24 'curses' screen");
1264
1265 #ifdef A_COLOR
1266
1267     /*** Init the Color-pairs and set up a translation table ***/
1268
1269     /* Do we have color, and enough color, available? */
1270     can_use_color = ((start_color() != ERR) && has_colors() && (COLORS >= 8) && (COLOR_PAIRS >= 8));
1271
1272 #ifdef REDEFINE_COLORS
1273     /* Can we change colors? */
1274     can_fix_color = (can_use_color && can_change_color() && (COLORS >= 16) && (COLOR_PAIRS > 8));
1275 #endif
1276
1277     /* Attempt to use customized colors */
1278     if (can_fix_color) {
1279         /* Prepare the color pairs */
1280         for (i = 1; i <= 15; i++) {
1281             if (init_pair(i, i, 0) == ERR) {
1282                 quit("Color pair init failed");
1283             }
1284
1285             colortable[i] = COLOR_PAIR(i);
1286             Term_xtra_gcu_react();
1287         }
1288     }
1289     /* Attempt to use colors */
1290     else if (can_use_color) {
1291         /* Color-pair 0 is *always* WHITE on BLACK */
1292
1293         /* Prepare the color pairs */
1294         init_pair(1, COLOR_RED, COLOR_BLACK);
1295         init_pair(2, COLOR_GREEN, COLOR_BLACK);
1296         init_pair(3, COLOR_YELLOW, COLOR_BLACK);
1297         init_pair(4, COLOR_BLUE, COLOR_BLACK);
1298         init_pair(5, COLOR_MAGENTA, COLOR_BLACK);
1299         init_pair(6, COLOR_CYAN, COLOR_BLACK);
1300         init_pair(7, COLOR_BLACK, COLOR_BLACK);
1301
1302         /* Prepare the "Angband Colors" -- Bright white is too bright */
1303         /* Changed in Drangband. Cyan as grey sucks -- -TM- */
1304         colortable[0] = (COLOR_PAIR(7) | A_NORMAL); /* Black */
1305         colortable[1] = (COLOR_PAIR(0) | A_BRIGHT); /* White */
1306         colortable[2] = (COLOR_PAIR(0) | A_NORMAL); /* Grey XXX */
1307         colortable[3] = (COLOR_PAIR(1) | A_BRIGHT); /* Orange XXX */
1308         colortable[4] = (COLOR_PAIR(1) | A_NORMAL); /* Red */
1309         colortable[5] = (COLOR_PAIR(2) | A_NORMAL); /* Green */
1310         colortable[6] = (COLOR_PAIR(4) | A_BRIGHT); /* Blue */
1311         colortable[7] = (COLOR_PAIR(3) | A_NORMAL); /* Umber */
1312         colortable[8] = (COLOR_PAIR(7) | A_BRIGHT); /* Dark-grey XXX */
1313         colortable[9] = (COLOR_PAIR(0) | A_NORMAL); /* Light-grey XXX */
1314         colortable[10] = (COLOR_PAIR(5) | A_BRIGHT); /* Purple */
1315         colortable[11] = (COLOR_PAIR(3) | A_BRIGHT); /* Yellow */
1316         colortable[12] = (COLOR_PAIR(5) | A_NORMAL); /* Light Red XXX */
1317         colortable[13] = (COLOR_PAIR(2) | A_BRIGHT); /* Light Green */
1318         colortable[14] = (COLOR_PAIR(6) | A_BRIGHT); /* Light Blue */
1319         colortable[15] = (COLOR_PAIR(3) | A_NORMAL); /* Light Umber XXX */
1320     }
1321
1322 #endif
1323
1324     /* Handle "arg_sound" */
1325     if (use_sound != arg_sound) {
1326         /* Initialize (if needed) */
1327         if (arg_sound && !init_sound()) {
1328             /* Warning */
1329             plog("Cannot initialize sound!");
1330
1331             /* Cannot enable */
1332             arg_sound = false;
1333         }
1334
1335         /* Change setting */
1336         use_sound = arg_sound;
1337     }
1338
1339     /* Try graphics */
1340     if (arg_graphics) {
1341         /* if USE_NCURSES_ACS is defined, we can do something with graphics in curses! */
1342 #ifdef USE_NCURSES_ACS
1343         use_graphics = true;
1344 #endif
1345     }
1346
1347     /*** Low level preparation ***/
1348
1349 #ifdef USE_GETCH
1350
1351     /* Paranoia -- Assume no waiting */
1352     nodelay(stdscr, false);
1353
1354 #endif
1355
1356     /* Prepare */
1357     cbreak();
1358     noecho();
1359     nonl();
1360     raw();
1361
1362     /* Extract the game keymap */
1363     keymap_game_prepare();
1364
1365     /*** Now prepare the term(s) ***/
1366     if (nobigscreen) {
1367         /* Create several terms */
1368         for (i = 0; i < num_term; i++) {
1369             int rows, cols, y, x;
1370
1371             /* Decide on size and position */
1372             switch (i) {
1373             /* Upper left */
1374             case 0: {
1375                 rows = 24;
1376                 cols = 80;
1377                 y = x = 0;
1378                 break;
1379             }
1380
1381             /* Lower left */
1382             case 1: {
1383                 rows = LINES - 25;
1384                 cols = 80;
1385                 y = 25;
1386                 x = 0;
1387                 break;
1388             }
1389
1390             /* Upper right */
1391             case 2: {
1392                 rows = 24;
1393                 cols = COLS - 81;
1394                 y = 0;
1395                 x = 81;
1396                 break;
1397             }
1398
1399             /* Lower right */
1400             case 3: {
1401                 rows = LINES - 25;
1402                 cols = COLS - 81;
1403                 y = 25;
1404                 x = 81;
1405                 break;
1406             }
1407
1408             /* XXX */
1409             default: {
1410                 rows = cols = y = x = 0;
1411                 break;
1412             }
1413             }
1414
1415             /* Skip non-existant windows */
1416             if (rows <= 0 || cols <= 0)
1417                 continue;
1418
1419             /* Create a term */
1420             term_data_init_gcu(&data[next_win], rows, cols, y, x);
1421
1422             /* Remember the term */
1423             angband_term[next_win] = &data[next_win].t;
1424
1425             /* One more window */
1426             next_win++;
1427         }
1428     } else
1429     /* Parse Args and Prepare the Terminals. Rectangles are specified
1430       as Width x Height, right? The game will allow you to have two
1431       strips of extra terminals, one on the right and one on the bottom.
1432       The map terminal will than fit in as big as possible in the remaining
1433       space.
1434       Examples:
1435         angband -mgcu -- -right 30x27,* -bottom *x7 will layout as
1436         Term-0: Map (COLS-30)x(LINES-7) | Term-1: 30x27
1437         --------------------------------|----------------------
1438         <----Term-3: (COLS-30)x7------->| Term-2: 30x(LINES-27)
1439         composband -mgcu -- -bottom *x7 -right 30x27,* will layout as
1440         Term-0: Map (COLS-30)x(LINES-7) | Term-2: 30x27
1441                                         |------------------------------
1442                                         | Term-3: 30x(LINES-27)
1443         ---------------------------------------------------------------
1444         <----------Term-1: (COLS)x7----------------------------------->
1445         Notice the effect on the bottom terminal by specifying its argument
1446         second or first. Notice the sequence numbers for the various terminals
1447         as you will have to blindly configure them in the window setup screen.
1448         EDIT: Added support for -left and -top.
1449     */
1450     {
1451         rect_t remaining = rect(0, 0, COLS, LINES);
1452         int spacer_cx = 1;
1453         int spacer_cy = 1;
1454         int next_term = 1;
1455         int term_ct = 1;
1456
1457         for (i = 1; i < argc; i++) {
1458             if (streq(argv[i], "-spacer")) {
1459                 i++;
1460                 if (i >= argc)
1461                     quit("Missing size specifier for -spacer");
1462                 sscanf(argv[i], "%dx%d", &spacer_cx, &spacer_cy);
1463             } else if (streq(argv[i], "-right") || streq(argv[i], "-left")) {
1464                 const char *arg, *tmp;
1465                 bool left = streq(argv[i], "-left");
1466                 int cx, cys[MAX_TERM_DATA] = { 0 }, ct, j, x, y;
1467
1468                 i++;
1469                 if (i >= argc)
1470                     quit(format("Missing size specifier for -%s", left ? "left" : "right"));
1471
1472                 arg = argv[i];
1473                 tmp = strchr(arg, 'x');
1474                 if (!tmp)
1475                     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"));
1476                 cx = atoi(arg);
1477                 remaining.cx -= cx;
1478                 if (left) {
1479                     x = remaining.x;
1480                     y = remaining.y;
1481                     remaining.x += cx;
1482                 } else {
1483                     x = remaining.x + remaining.cx;
1484                     y = remaining.y;
1485                 }
1486                 remaining.cx -= spacer_cx;
1487                 if (left)
1488                     remaining.x += spacer_cx;
1489
1490                 tmp++;
1491                 ct = _parse_size_list(tmp, cys, MAX_TERM_DATA);
1492                 for (j = 0; j < ct; j++) {
1493                     int cy = cys[j];
1494                     if (y + cy > remaining.y + remaining.cy)
1495                         cy = remaining.y + remaining.cy - y;
1496                     if (next_term >= MAX_TERM_DATA)
1497                         quit(format("Too many terminals. Only %d are allowed.", MAX_TERM_DATA));
1498                     if (cy <= 0) {
1499                         quit(format("Out of bounds in -%s: %d is too large (%d rows max for this strip)",
1500                             left ? "left" : "right", cys[j], remaining.cy));
1501                     }
1502                     data[next_term++].r = rect(x, y, cx, cy);
1503                     y += cy + spacer_cy;
1504                     term_ct++;
1505                 }
1506             } else if (streq(argv[i], "-top") || streq(argv[i], "-bottom")) {
1507                 const char *arg, *tmp;
1508                 bool top = streq(argv[i], "-top");
1509                 int cy, cxs[MAX_TERM_DATA] = { 0 }, ct, j, x, y;
1510
1511                 i++;
1512                 if (i >= argc)
1513                     quit(format("Missing size specifier for -%s", top ? "top" : "bottom"));
1514
1515                 arg = argv[i];
1516                 tmp = strchr(arg, 'x');
1517                 if (!tmp)
1518                     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"));
1519                 tmp++;
1520                 cy = atoi(tmp);
1521                 ct = _parse_size_list(arg, cxs, MAX_TERM_DATA);
1522
1523                 remaining.cy -= cy;
1524                 if (top) {
1525                     x = remaining.x;
1526                     y = remaining.y;
1527                     remaining.y += cy;
1528                 } else {
1529                     x = remaining.x;
1530                     y = remaining.y + remaining.cy;
1531                 }
1532                 remaining.cy -= spacer_cy;
1533                 if (top)
1534                     remaining.y += spacer_cy;
1535
1536                 tmp++;
1537                 for (j = 0; j < ct; j++) {
1538                     int cx = cxs[j];
1539                     if (x + cx > remaining.x + remaining.cx)
1540                         cx = remaining.x + remaining.cx - x;
1541                     if (next_term >= MAX_TERM_DATA)
1542                         quit(format("Too many terminals. Only %d are allowed.", MAX_TERM_DATA));
1543                     if (cx <= 0) {
1544                         quit(format("Out of bounds in -%s: %d is too large (%d cols max for this strip)",
1545                             top ? "top" : "bottom", cxs[j], remaining.cx));
1546                     }
1547                     data[next_term++].r = rect(x, y, cx, cy);
1548                     x += cx + spacer_cx;
1549                     term_ct++;
1550                 }
1551             }
1552         }
1553
1554         /* Map Terminal */
1555         if (remaining.cx < MIN_TERM0_COLS || remaining.cy < MIN_TERM0_LINES)
1556             quit(format("Failed: angband needs an %dx%d map screen, not %dx%d", MIN_TERM0_COLS, MIN_TERM0_LINES, remaining.cx, remaining.cy));
1557         data[0].r = remaining;
1558         term_data_init(&data[0]);
1559         angband_term[0] = Term;
1560
1561         /* Child Terminals */
1562         for (next_term = 1; next_term < term_ct; next_term++) {
1563             term_data_init(&data[next_term]);
1564             angband_term[next_term] = Term;
1565         }
1566     }
1567
1568     /* Activate the "Angband" window screen */
1569     term_activate(&data[0].t);
1570
1571     /* Store */
1572     term_screen = &data[0].t;
1573
1574     /* Success */
1575     return (0);
1576 }
1577
1578 #endif /* USE_GCU */