OSDN Git Service

[Feature] 啓蒙/周辺感知で壁の中の壁も感知する / 壁に囲まれた壁を表示するオプション #643
[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 "term/gameterm.h"
169 #include "term/term-color-types.h"
170 #include "util/angband-files.h"
171 #include "view/display-map.h"
172
173 #ifdef USE_GCU
174
175 /*
176  * Hack -- play games with "bool"
177  */
178 #if __STDC_VERSION__ < 199901L
179 #undef bool
180 #endif
181
182 /*
183  * Include the proper "header" file
184  */
185 #include <curses.h>
186
187 typedef struct term_data term_data;
188
189 struct term_data {
190     term_type t;
191
192     WINDOW *win;
193 };
194
195 #define MAX_TERM_DATA 4
196
197 static term_data data[MAX_TERM_DATA];
198
199 /*
200  * Hack -- try to guess which systems use what commands
201  * Hack -- allow one of the "USE_Txxxxx" flags to be pre-set.
202  * Mega-Hack -- try to guess when "POSIX" is available.
203  * If the user defines two of these, we will probably crash.
204  */
205 #if !defined(USE_TCHARS)
206 #if defined(_POSIX_VERSION)
207 #define USE_TPOSIX
208 #else
209 #if defined(linux)
210 #define USE_TERMIO
211 #else
212 #define USE_TCHARS
213 #endif
214 #endif
215 #endif
216
217 /*
218  * Try redefining the colors at startup.
219  */
220 #define REDEFINE_COLORS
221
222 /*
223  * POSIX stuff
224  */
225 #ifdef USE_TPOSIX
226 #include <sys/ioctl.h>
227 #include <termios.h>
228 #endif
229
230 /*
231  * One version needs this file
232  */
233 #ifdef USE_TERMIO
234 #include <sys/ioctl.h>
235 #include <termio.h>
236 #endif
237
238 /*
239  * The other needs this file
240  */
241 #ifdef USE_TCHARS
242 #include <sys/file.h>
243 #include <sys/ioctl.h>
244 #include <sys/param.h>
245 #include <sys/resource.h>
246 #include <sys/types.h>
247 #endif
248
249 #include <locale.h>
250
251 /*
252  * XXX XXX Hack -- POSIX uses "O_NONBLOCK" instead of "O_NDELAY"
253  *
254  * They should both work due to the "(i != 1)" test below.
255  */
256 #ifndef O_NDELAY
257 #define O_NDELAY O_NONBLOCK
258 #endif
259
260 /*
261  * OPTION: some machines lack "cbreak()"
262  * On these machines, we use an older definition
263  */
264 /* #define cbreak() crmode() */
265
266 /*
267  * OPTION: some machines cannot handle "nonl()" and "nl()"
268  * On these machines, we can simply ignore those commands.
269  */
270 /* #define nonl() */
271 /* #define nl() */
272
273 static concptr ANGBAND_DIR_XTRA_SOUND;
274
275 /*
276  * todo 有効活用されていない疑惑
277  * Flag set once "sound" has been initialized
278  */
279 static bool can_use_sound = FALSE;
280
281 /*
282  * An array of sound file names
283  */
284 static concptr sound_file[SOUND_MAX];
285
286 /*
287  * Save the "normal" and "angband" terminal settings
288  */
289
290 #ifdef USE_TPOSIX
291
292 static struct termios norm_termios;
293
294 static struct termios game_termios;
295
296 #endif
297
298 #ifdef USE_TERMIO
299
300 static struct termio norm_termio;
301
302 static struct termio game_termio;
303
304 #endif
305
306 #ifdef USE_TCHARS
307 static struct ltchars norm_speciax_chars;
308 static struct sgttyb norm_ttyb;
309 static struct tchars norm_tchars;
310 static int norm_locax_chars;
311
312 static struct ltchars game_speciax_chars;
313 static struct sgttyb game_ttyb;
314 static struct tchars game_tchars;
315 static int game_locax_chars;
316 #endif
317
318 /*
319  * Hack -- Number of initialized "term" structures
320  */
321 static int active = 0;
322
323 #ifdef A_COLOR
324 /*
325  * Hack -- define "A_BRIGHT" to be "A_BOLD", because on many
326  * machines, "A_BRIGHT" produces ugly "inverse" video.
327  */
328 #ifndef A_BRIGHT
329 #define A_BRIGHT A_BOLD
330 #endif
331
332 /*
333  * Software flag -- we are allowed to use color
334  */
335 static int can_use_color = FALSE;
336
337 /*
338  * Software flag -- we are allowed to change the colors
339  */
340 static int can_fix_color = FALSE;
341
342 /*
343  * Simple Angband to Curses color conversion table
344  */
345 static int colortable[16];
346 #endif
347
348 /*
349  * Place the "keymap" into its "normal" state
350  */
351 static void keymap_norm(void)
352 {
353 #ifdef USE_TPOSIX
354     /* restore the saved values of the special chars */
355     (void)tcsetattr(0, TCSAFLUSH, &norm_termios);
356 #endif
357
358 #ifdef USE_TERMIO
359     /* restore the saved values of the special chars */
360     (void)ioctl(0, TCSETA, (char *)&norm_termio);
361 #endif
362
363 #ifdef USE_TCHARS
364     /* restore the saved values of the special chars */
365     (void)ioctl(0, TIOCSLTC, (char *)&norm_speciax_chars);
366     (void)ioctl(0, TIOCSETP, (char *)&norm_ttyb);
367     (void)ioctl(0, TIOCSETC, (char *)&norm_tchars);
368     (void)ioctl(0, TIOCLSET, (char *)&norm_locax_chars);
369 #endif
370 }
371
372 /*
373  * Place the "keymap" into the "game" state
374  */
375 static void keymap_game(void)
376 {
377 #ifdef USE_TPOSIX
378     /* restore the saved values of the special chars */
379     (void)tcsetattr(0, TCSAFLUSH, &game_termios);
380 #endif
381
382 #ifdef USE_TERMIO
383     /* restore the saved values of the special chars */
384     (void)ioctl(0, TCSETA, (char *)&game_termio);
385 #endif
386
387 #ifdef USE_TCHARS
388     /* restore the saved values of the special chars */
389     (void)ioctl(0, TIOCSLTC, (char *)&game_speciax_chars);
390     (void)ioctl(0, TIOCSETP, (char *)&game_ttyb);
391     (void)ioctl(0, TIOCSETC, (char *)&game_tchars);
392     (void)ioctl(0, TIOCLSET, (char *)&game_locax_chars);
393 #endif
394 }
395
396 /*
397  * Save the normal keymap
398  */
399 static void keymap_norm_prepare(void)
400 {
401 #ifdef USE_TPOSIX
402     /* Get the normal keymap */
403     tcgetattr(0, &norm_termios);
404 #endif
405
406 #ifdef USE_TERMIO
407     /* Get the normal keymap */
408     (void)ioctl(0, TCGETA, (char *)&norm_termio);
409 #endif
410
411 #ifdef USE_TCHARS
412     /* Get the normal keymap */
413     (void)ioctl(0, TIOCGETP, (char *)&norm_ttyb);
414     (void)ioctl(0, TIOCGLTC, (char *)&norm_speciax_chars);
415     (void)ioctl(0, TIOCGETC, (char *)&norm_tchars);
416     (void)ioctl(0, TIOCLGET, (char *)&norm_locax_chars);
417 #endif
418 }
419
420 /*
421  * Save the keymaps (normal and game)
422  */
423 static void keymap_game_prepare(void)
424 {
425 #ifdef USE_TPOSIX
426     /* Acquire the current mapping */
427     tcgetattr(0, &game_termios);
428
429     /* Force "Ctrl-C" to interupt */
430     game_termios.c_cc[VINTR] = (char)3;
431
432     /* Force "Ctrl-Z" to suspend */
433     game_termios.c_cc[VSUSP] = (char)26;
434
435     /* Hack -- Leave "VSTART/VSTOP" alone */
436
437     /* Disable the standard control characters */
438     game_termios.c_cc[VQUIT] = (char)-1;
439     game_termios.c_cc[VERASE] = (char)-1;
440     game_termios.c_cc[VKILL] = (char)-1;
441     game_termios.c_cc[VEOF] = (char)-1;
442     game_termios.c_cc[VEOL] = (char)-1;
443
444     /* Normally, block until a character is read */
445     game_termios.c_cc[VMIN] = 1;
446     game_termios.c_cc[VTIME] = 0;
447 #endif
448
449 #ifdef USE_TERMIO
450     /* Acquire the current mapping */
451     (void)ioctl(0, TCGETA, (char *)&game_termio);
452
453     /* Force "Ctrl-C" to interupt */
454     game_termio.c_cc[VINTR] = (char)3;
455
456     /* Force "Ctrl-Z" to suspend */
457     game_termio.c_cc[VSUSP] = (char)26;
458
459     /* Disable the standard control characters */
460     game_termio.c_cc[VQUIT] = (char)-1;
461     game_termio.c_cc[VERASE] = (char)-1;
462     game_termio.c_cc[VKILL] = (char)-1;
463     game_termio.c_cc[VEOF] = (char)-1;
464     game_termio.c_cc[VEOL] = (char)-1;
465
466     /* Normally, block until a character is read */
467     game_termio.c_cc[VMIN] = 1;
468     game_termio.c_cc[VTIME] = 0;
469 #endif
470
471 #ifdef USE_TCHARS
472     /* Get the default game characters */
473     (void)ioctl(0, TIOCGETP, (char *)&game_ttyb);
474     (void)ioctl(0, TIOCGLTC, (char *)&game_speciax_chars);
475     (void)ioctl(0, TIOCGETC, (char *)&game_tchars);
476     (void)ioctl(0, TIOCLGET, (char *)&game_locax_chars);
477
478     /* Force suspend (^Z) */
479     game_speciax_chars.t_suspc = (char)26;
480
481     /* Cancel some things */
482     game_speciax_chars.t_dsuspc = (char)-1;
483     game_speciax_chars.t_rprntc = (char)-1;
484     game_speciax_chars.t_flushc = (char)-1;
485     game_speciax_chars.t_werasc = (char)-1;
486     game_speciax_chars.t_lnextc = (char)-1;
487
488     /* Force interupt (^C) */
489     game_tchars.t_intrc = (char)3;
490
491     /* Force start/stop (^Q, ^S) */
492     game_tchars.t_startc = (char)17;
493     game_tchars.t_stopc = (char)19;
494
495     /* Cancel some things */
496     game_tchars.t_quitc = (char)-1;
497     game_tchars.t_eofc = (char)-1;
498     game_tchars.t_brkc = (char)-1;
499 #endif
500 }
501
502 /*
503  * Suspend/Resume
504  */
505 static errr Term_xtra_gcu_alive(int v)
506 {
507     if (!v) {
508         /* Go to normal keymap mode */
509         keymap_norm();
510
511         /* Restore modes */
512         nocbreak();
513         echo();
514         nl();
515
516         /* Hack -- make sure the cursor is visible */
517         term_xtra(TERM_XTRA_SHAPE, 1);
518
519         /* Flush the curses buffer */
520         (void)refresh();
521
522         /* this moves curses to bottom right corner */
523         mvcur(getcury(curscr), getcurx(curscr), LINES - 1, 0);
524
525         /* Exit curses */
526         endwin();
527
528         /* Flush the output */
529         (void)fflush(stdout);
530     } else {
531         /* Restore the settings */
532         cbreak();
533         noecho();
534         nonl();
535
536         /* Go to angband keymap mode */
537         keymap_game();
538     }
539
540     return (0);
541 }
542
543 /*
544  * Check for existance of a file
545  */
546 static bool check_file(concptr s)
547 {
548     FILE *fff;
549     fff = fopen(s, "r");
550     if (!fff)
551         return (FALSE);
552
553     fclose(fff);
554     return (TRUE);
555 }
556
557 /*
558  * Initialize sound
559  */
560 static bool init_sound(void)
561 {
562     /* Initialize once */
563     if (can_use_sound)
564         return can_use_sound;
565
566     int i;
567     char wav[128];
568     char buf[1024];
569
570     /* Prepare the sounds */
571     for (i = 1; i < SOUND_MAX; i++) {
572         /* Extract name of sound file */
573         sprintf(wav, "%s.wav", angband_sound_name[i]);
574
575         /* Access the sound */
576         path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_SOUND, wav);
577
578         /* Save the sound filename, if it exists */
579         if (check_file(buf))
580             sound_file[i] = string_make(buf);
581     }
582
583     /* Sound available */
584     can_use_sound = TRUE;
585     return (can_use_sound);
586 }
587
588 /*
589  * Init the "curses" system
590  */
591 static void Term_init_gcu(term_type *t)
592 {
593     term_data *td = (term_data *)(t->data);
594
595     /* Count init's, handle first */
596     if (active++ != 0)
597         return;
598
599     /* Erase the screen */
600     (void)wclear(td->win);
601
602     /* Reset the cursor */
603     (void)wmove(td->win, 0, 0);
604
605     /* Flush changes */
606     (void)wrefresh(td->win);
607
608     /* Game keymap */
609     keymap_game();
610 }
611
612 /*
613  * Nuke the "curses" system
614  */
615 static void Term_nuke_gcu(term_type *t)
616 {
617     term_data *td = (term_data *)(t->data);
618
619     /* Delete this window */
620     delwin(td->win);
621
622     /* Count nuke's, handle last */
623     if (--active != 0)
624         return;
625
626     /* Hack -- make sure the cursor is visible */
627     term_xtra(TERM_XTRA_SHAPE, 1);
628
629 #ifdef A_COLOR
630     /* Reset colors to defaults */
631     start_color();
632 #endif
633
634     /* This moves curses to bottom right corner */
635     mvcur(getcury(curscr), getcurx(curscr), LINES - 1, 0);
636
637     /* Flush the curses buffer */
638     (void)refresh();
639
640     /* Exit curses */
641     endwin();
642
643     /* Flush the output */
644     (void)fflush(stdout);
645
646     /* Normal keymap */
647     keymap_norm();
648 }
649
650 /*
651  * Push multiple keys reversal
652  */
653 static void term_string_push(char *buf)
654 {
655     int i, l = strlen(buf);
656     for (i = l; i >= 0; i--)
657         term_key_push(buf[i]);
658 }
659
660 #ifdef USE_GETCH
661
662 /*
663  * Process events, with optional wait
664  */
665 static errr Term_xtra_gcu_event(int v)
666 {
667     int i, k;
668
669     /* Wait */
670     if (v) {
671         char buf[256];
672         char *bp = buf;
673
674         /* Paranoia -- Wait for it */
675         nodelay(stdscr, FALSE);
676
677         /* Get a keypress */
678         i = getch();
679
680         /* Broken input is special */
681         if (i == ERR)
682             exit_game_panic(p_ptr);
683         if (i == EOF)
684             exit_game_panic(p_ptr);
685
686         *bp++ = (char)i;
687
688         /* Do not wait for it */
689         nodelay(stdscr, TRUE);
690
691         while ((i = getch()) != EOF) {
692             if (i == ERR)
693                 exit_game_panic(p_ptr);
694             *bp++ = (char)i;
695             if (bp == &buf[255])
696                 break;
697         }
698
699         /* Wait for it next time */
700         nodelay(stdscr, FALSE);
701
702         *bp = '\0';
703 #ifdef JP
704         char eucbuf[sizeof(buf)];
705         /* strlen + 1 を渡して文字列終端('\0')を含めて変換する */
706         if (utf8_to_euc(buf, strlen(buf) + 1, eucbuf, sizeof(eucbuf)) < 0) {
707             return (-1);
708         }
709 #endif
710         term_string_push(_(eucbuf, buf));
711     }
712
713     /* Do not wait */
714     else {
715         /* Do not wait for it */
716         nodelay(stdscr, TRUE);
717
718         /* Check for keypresses */
719         i = getch();
720
721         /* Wait for it next time */
722         nodelay(stdscr, FALSE);
723
724         /* None ready */
725         if (i == ERR)
726             return (1);
727         if (i == EOF)
728             return (1);
729
730         /* Enqueue the keypress */
731         term_key_push(i);
732     }
733
734     /* Success */
735     return (0);
736 }
737
738 #else /* USE_GETCH */
739
740 /*
741  * Process events (with optional wait)
742  */
743 static errr Term_xtra_gcu_event(int v)
744 {
745     int i, k;
746
747     char buf[256];
748
749     /* Wait */
750     if (v) {
751         char *bp = buf;
752
753         /* Wait for one byte */
754         i = read(0, bp++, 1);
755
756         /* Hack -- Handle bizarre "errors" */
757         if ((i <= 0) && (errno != EINTR))
758             exit_game_panic(p_ptr);
759
760         /* Get the current flags for stdin */
761         k = fcntl(0, F_GETFL, 0);
762
763         /* Oops */
764         if (k < 0)
765             return (1);
766
767         /* Tell stdin not to block */
768         if (fcntl(0, F_SETFL, k | O_NDELAY) >= 0) {
769             if ((i = read(0, bp, 254)) > 0) {
770                 bp += i;
771             }
772
773             /* Replace the flags for stdin */
774             if (fcntl(0, F_SETFL, k))
775                 return (1);
776         }
777
778         bp[0] = '\0';
779 #ifdef JP
780         char eucbuf[sizeof(buf)];
781         /* strlen + 1 を渡して文字列終端('\0')を含めて変換する */
782         if (utf8_to_euc(buf, strlen(buf) + 1, eucbuf, sizeof(eucbuf)) < 0) {
783             return (-1);
784         }
785 #endif
786         term_string_push(_(eucbuf, buf));
787     }
788
789     /* Do not wait */
790     else {
791         /* Get the current flags for stdin */
792         k = fcntl(0, F_GETFL, 0);
793
794         /* Oops */
795         if (k < 0)
796             return (1);
797
798         /* Tell stdin not to block */
799         if (fcntl(0, F_SETFL, k | O_NDELAY) < 0)
800             return (1);
801
802         /* Read one byte, if possible */
803         i = read(0, buf, 1);
804
805         /* Replace the flags for stdin */
806         if (fcntl(0, F_SETFL, k))
807             return (1);
808
809         /* Ignore "invalid" keys */
810         if ((i != 1) || (!buf[0]))
811             return (1);
812
813         /* Enqueue the keypress */
814         term_key_push(buf[0]);
815     }
816
817     /* Success */
818     return (0);
819 }
820
821 #endif /* USE_GETCH */
822
823 /*
824  * Hack -- make a sound
825  */
826 static errr Term_xtra_gcu_sound(int v)
827 {
828     char buf[1024];
829
830     /* Sound disabled */
831     if (!use_sound)
832         return (1);
833
834     /* Illegal sound */
835     if ((v < 0) || (v >= SOUND_MAX))
836         return (1);
837
838     /* Unknown sound */
839     if (!sound_file[v])
840         return (1);
841
842     sprintf(buf, "./gcusound.sh %s\n", sound_file[v]);
843
844     return (system(buf) < 0);
845
846     return (0);
847 }
848
849 /*
850  * React to changes
851  */
852 static errr Term_xtra_gcu_react(void)
853 {
854
855 #ifdef A_COLOR
856
857     int i;
858
859     /* Cannot handle color redefinition */
860     if (!can_fix_color)
861         return (0);
862
863     /* Set the colors */
864     for (i = 0; i < 16; i++) {
865         /* Set one color (note scaling) */
866         init_color(i, angband_color_table[i][1] * 1000 / 255, angband_color_table[i][2] * 1000 / 255, angband_color_table[i][3] * 1000 / 255);
867     }
868
869 #endif
870
871     /* Success */
872     return (0);
873 }
874
875 /*
876  * Handle a "special request"
877  */
878 static errr Term_xtra_gcu(int n, int v)
879 {
880     term_data *td = (term_data *)(Term->data);
881
882     /* Analyze the request */
883     switch (n) {
884     /* Clear screen */
885     case TERM_XTRA_CLEAR:
886         touchwin(td->win);
887         (void)wclear(td->win);
888         return (0);
889
890     /* Make a noise */
891     case TERM_XTRA_NOISE:
892         return write(1, "\007", 1) != 1;
893
894     /* Make a special sound */
895     case TERM_XTRA_SOUND:
896         return (Term_xtra_gcu_sound(v));
897
898     /* Flush the Curses buffer */
899     case TERM_XTRA_FRESH:
900         (void)wrefresh(td->win);
901         return (0);
902
903 #ifdef USE_CURS_SET
904
905     /* Change the cursor visibility */
906     case TERM_XTRA_SHAPE:
907         curs_set(v);
908         return (0);
909
910 #endif
911
912     /* Suspend/Resume curses */
913     case TERM_XTRA_ALIVE:
914         return (Term_xtra_gcu_alive(v));
915
916     /* Process events */
917     case TERM_XTRA_EVENT:
918         return (Term_xtra_gcu_event(v));
919
920     /* Flush events */
921     case TERM_XTRA_FLUSH:
922         while (!Term_xtra_gcu_event(FALSE))
923             ;
924         return (0);
925
926     /* Delay */
927     case TERM_XTRA_DELAY:
928         usleep(1000 * v);
929         return (0);
930
931     /* React to events */
932     case TERM_XTRA_REACT:
933         Term_xtra_gcu_react();
934         return (0);
935     }
936
937     /* Unknown */
938     return (1);
939 }
940
941 /*
942  * Actually MOVE the hardware cursor
943  */
944 static errr Term_curs_gcu(int x, int y)
945 {
946     term_data *td = (term_data *)(Term->data);
947
948     /* Literally move the cursor */
949     wmove(td->win, y, x);
950
951     /* Success */
952     return (0);
953 }
954
955 /*
956  * Erase a grid of space
957  * Hack -- try to be "semi-efficient".
958  */
959 static errr Term_wipe_gcu(int x, int y, int n)
960 {
961     term_data *td = (term_data *)(Term->data);
962
963     /* Place cursor */
964     wmove(td->win, y, x);
965
966     /* Clear to end of line */
967     if (x + n >= 80) {
968         wclrtoeol(td->win);
969     }
970
971     /* Clear some characters */
972     else {
973         while (n-- > 0)
974             waddch(td->win, ' ');
975     }
976
977     /* Success */
978     return (0);
979 }
980
981 #ifdef USE_NCURSES_ACS
982 /*
983  * this function draws some ACS characters on the screen
984  * for DOS-based users: these are the graphical chars (blocks, lines etc)
985  *
986  * unix-gurus: before you start adding other attributes like A_REVERSE
987  * think hard about how map_info() in cave.c should handle the color
988  * of something that we here draw in reverse. It's not so simple, alas.
989  */
990 static void Term_acs_text_gcu(int x, int y, int n, byte a, concptr s)
991 {
992     term_data *td = (term_data *)(Term->data);
993     int i;
994
995     /* position the cursor */
996     wmove(td->win, y, x);
997
998 #ifdef A_COLOR
999     /* Set the color */
1000     wattrset(td->win, colortable[a & 0x0F]);
1001 #endif
1002
1003     for (i = 0; i < n; i++) {
1004         /* add acs_map of a */
1005         waddch(td->win, acs_map[(int)s[i]]);
1006     }
1007     wattrset(td->win, WA_NORMAL);
1008 }
1009 #endif
1010
1011 /*
1012  * Place some text on the screen using an attribute
1013  */
1014 static errr Term_text_gcu(int x, int y, int n, byte a, concptr s)
1015 {
1016     term_data *td = (term_data *)(Term->data);
1017
1018 #ifdef USE_NCURSES_ACS
1019     /* do we have colors + 16 ? */
1020     /* then call special routine for drawing special characters */
1021     if (a & 0x10) {
1022         Term_acs_text_gcu(x, y, n, a, s);
1023         return (0);
1024     }
1025 #endif
1026
1027     /* Move the cursor and dump the string */
1028     wmove(td->win, y, x);
1029
1030 #ifdef A_COLOR
1031     /* Set the color */
1032     if (can_use_color)
1033         wattrset(td->win, colortable[a & 0x0F]);
1034 #endif
1035
1036 #ifdef JP
1037     char text[1024];
1038     int text_len = euc_to_utf8(s, n, text, sizeof(text));
1039     if (text_len < 0) {
1040         return (-1);
1041     }
1042 #endif
1043     /* Add the text */
1044     waddnstr(td->win, _(text, s), _(text_len, n));
1045
1046     /* Success */
1047     return (0);
1048 }
1049
1050 static errr term_data_init(term_data *td, int rows, int cols, int y, int x)
1051 {
1052     term_type *t = &td->t;
1053
1054     /* Make sure the window has a positive size */
1055     if (rows <= 0 || cols <= 0)
1056         return (0);
1057
1058     /* Create a window */
1059     td->win = newwin(rows, cols, y, x);
1060
1061     /* Make sure we succeed */
1062     if (!td->win) {
1063         plog("Failed to setup curses window.");
1064         return (-1);
1065     }
1066
1067     /* Initialize the term */
1068     term_init(t, cols, rows, 256);
1069
1070     /* Avoid the bottom right corner */
1071     t->icky_corner = TRUE;
1072
1073     /* Erase with "white space" */
1074     t->attr_blank = TERM_WHITE;
1075     t->char_blank = ' ';
1076
1077     /* Set some hooks */
1078     t->init_hook = Term_init_gcu;
1079     t->nuke_hook = Term_nuke_gcu;
1080
1081     /* Set some more hooks */
1082     t->text_hook = Term_text_gcu;
1083     t->wipe_hook = Term_wipe_gcu;
1084     t->curs_hook = Term_curs_gcu;
1085     t->xtra_hook = Term_xtra_gcu;
1086
1087     /* Save the data */
1088     t->data = td;
1089
1090     /* Activate it */
1091     term_activate(t);
1092
1093     /* Success */
1094     return (0);
1095 }
1096
1097 static void hook_quit(concptr str)
1098 {
1099     /* Unused */
1100     (void)str;
1101
1102     /* Exit curses */
1103     endwin();
1104 }
1105
1106 /*
1107  * Prepare "curses" for use by the file "term.c"
1108  *
1109  * Installs the "hook" functions defined above, and then activates
1110  * the main screen "term", which clears the screen and such things.
1111  *
1112  * Someone should really check the semantics of "initscr()"
1113  */
1114 errr init_gcu(int argc, char *argv[])
1115 {
1116     int i;
1117
1118     int num_term = 4, next_win = 0;
1119     char path[1024];
1120
1121     /* Unused */
1122     (void)argc;
1123     (void)argv;
1124
1125     setlocale(LC_ALL, "");
1126
1127     /* Build the "sound" path */
1128     path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "sound");
1129
1130     /* Allocate the path */
1131     ANGBAND_DIR_XTRA_SOUND = string_make(path);
1132
1133     /* Extract the normal keymap */
1134     keymap_norm_prepare();
1135
1136     /* Initialize for others systems */
1137     if (initscr() == (WINDOW *)ERR)
1138         return (-1);
1139
1140     /* Activate hooks */
1141     quit_aux = hook_quit;
1142     core_aux = hook_quit;
1143
1144     /* Hack -- Require large screen, or Quit with message */
1145     i = ((LINES < 24) || (COLS < 80));
1146     if (i)
1147         quit("Angband needs an 80x24 'curses' screen");
1148
1149 #ifdef A_COLOR
1150
1151     /*** Init the Color-pairs and set up a translation table ***/
1152
1153     /* Do we have color, and enough color, available? */
1154     can_use_color = ((start_color() != ERR) && has_colors() && (COLORS >= 8) && (COLOR_PAIRS >= 8));
1155
1156 #ifdef REDEFINE_COLORS
1157     /* Can we change colors? */
1158     can_fix_color = (can_use_color && can_change_color() && (COLORS >= 16) && (COLOR_PAIRS > 8));
1159 #endif
1160
1161     /* Attempt to use customized colors */
1162     if (can_fix_color) {
1163         /* Prepare the color pairs */
1164         for (i = 1; i <= 15; i++) {
1165             if (init_pair(i, i, 0) == ERR) {
1166                 quit("Color pair init failed");
1167             }
1168
1169             colortable[i] = COLOR_PAIR(i);
1170             Term_xtra_gcu_react();
1171         }
1172     }
1173     /* Attempt to use colors */
1174     else if (can_use_color) {
1175         /* Color-pair 0 is *always* WHITE on BLACK */
1176
1177         /* Prepare the color pairs */
1178         init_pair(1, COLOR_RED, COLOR_BLACK);
1179         init_pair(2, COLOR_GREEN, COLOR_BLACK);
1180         init_pair(3, COLOR_YELLOW, COLOR_BLACK);
1181         init_pair(4, COLOR_BLUE, COLOR_BLACK);
1182         init_pair(5, COLOR_MAGENTA, COLOR_BLACK);
1183         init_pair(6, COLOR_CYAN, COLOR_BLACK);
1184         init_pair(7, COLOR_BLACK, COLOR_BLACK);
1185
1186         /* Prepare the "Angband Colors" -- Bright white is too bright */
1187         /* Changed in Drangband. Cyan as grey sucks -- -TM- */
1188         colortable[0] = (COLOR_PAIR(7) | A_NORMAL); /* Black */
1189         colortable[1] = (COLOR_PAIR(0) | A_BRIGHT); /* White */
1190         colortable[2] = (COLOR_PAIR(0) | A_NORMAL); /* Grey XXX */
1191         colortable[3] = (COLOR_PAIR(1) | A_BRIGHT); /* Orange XXX */
1192         colortable[4] = (COLOR_PAIR(1) | A_NORMAL); /* Red */
1193         colortable[5] = (COLOR_PAIR(2) | A_NORMAL); /* Green */
1194         colortable[6] = (COLOR_PAIR(4) | A_BRIGHT); /* Blue */
1195         colortable[7] = (COLOR_PAIR(3) | A_NORMAL); /* Umber */
1196         colortable[8] = (COLOR_PAIR(7) | A_BRIGHT); /* Dark-grey XXX */
1197         colortable[9] = (COLOR_PAIR(0) | A_NORMAL); /* Light-grey XXX */
1198         colortable[10] = (COLOR_PAIR(5) | A_BRIGHT); /* Purple */
1199         colortable[11] = (COLOR_PAIR(3) | A_BRIGHT); /* Yellow */
1200         colortable[12] = (COLOR_PAIR(5) | A_NORMAL); /* Light Red XXX */
1201         colortable[13] = (COLOR_PAIR(2) | A_BRIGHT); /* Light Green */
1202         colortable[14] = (COLOR_PAIR(6) | A_BRIGHT); /* Light Blue */
1203         colortable[15] = (COLOR_PAIR(3) | A_NORMAL); /* Light Umber XXX */
1204     }
1205
1206 #endif
1207
1208     /* Handle "arg_sound" */
1209     if (use_sound != arg_sound) {
1210         /* Initialize (if needed) */
1211         if (arg_sound && !init_sound()) {
1212             /* Warning */
1213             plog("Cannot initialize sound!");
1214
1215             /* Cannot enable */
1216             arg_sound = FALSE;
1217         }
1218
1219         /* Change setting */
1220         use_sound = arg_sound;
1221     }
1222
1223     /* Try graphics */
1224     if (arg_graphics) {
1225         /* if USE_NCURSES_ACS is defined, we can do something with graphics in curses! */
1226 #ifdef USE_NCURSES_ACS
1227         use_graphics = TRUE;
1228 #endif
1229     }
1230
1231     /*** Low level preparation ***/
1232
1233 #ifdef USE_GETCH
1234
1235     /* Paranoia -- Assume no waiting */
1236     nodelay(stdscr, FALSE);
1237
1238 #endif
1239
1240     /* Prepare */
1241     cbreak();
1242     noecho();
1243     nonl();
1244     raw();
1245
1246     /* Extract the game keymap */
1247     keymap_game_prepare();
1248
1249     /*** Now prepare the term(s) ***/
1250     for (i = 0; i < num_term; i++) {
1251         int rows, cols;
1252         int y, x;
1253
1254         switch (i) {
1255         /* Upper left */
1256         case 0:
1257             rows = 24;
1258             cols = 80;
1259             y = x = 0;
1260             break;
1261         /* Lower left */
1262         case 1:
1263             rows = LINES - 25;
1264             cols = 80;
1265             y = 24;
1266             x = 0;
1267             break;
1268         /* Upper right */
1269         case 2:
1270             rows = 24;
1271             cols = COLS - 81;
1272             y = 0;
1273             x = 81;
1274             break;
1275         /* Lower right */
1276         case 3:
1277             rows = LINES - 25;
1278             cols = COLS - 81;
1279             y = 24;
1280             x = 81;
1281             break;
1282         /* XXX */
1283         default:
1284             rows = cols = 0;
1285             y = x = 0;
1286             break;
1287         }
1288
1289         /* No non-windows */
1290         if (rows <= 0 || cols <= 0)
1291             continue;
1292
1293         /* Initialize */
1294         term_data_init(&data[next_win], rows, cols, y, x);
1295
1296         /* Store */
1297         angband_term[next_win] = Term;
1298
1299         next_win++;
1300     }
1301
1302     /* Activate the "Angband" window screen */
1303     term_activate(&data[0].t);
1304
1305     /* Store */
1306     term_screen = &data[0].t;
1307
1308     /* Success */
1309     return (0);
1310 }
1311
1312 #endif /* USE_GCU */