OSDN Git Service

Merge remote-tracking branch 'remotes/origin/For2.2.2-Fix-Hourier' into For2.2.2...
[hengband/hengband.git] / src / main-gcu.c
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: 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
34  * Xref: xs4all rec.games.roguelike.angband:86332
35  *
36  * Greg Wooledge <wooledge@kellnet.com> wrote:
37  * > Gwidon S. Naskrent (naskrent@artemida.amu.edu.pl) wrote:
38  *
39  * > >On 30 Mar 1999 13:17:18 GMT, scarblac-spamtrap@pino.selwerd.cx (Remco
40  * > >Gerlich) wrote:
41  *
42  * > >>I recently switched to Linux, and *bands work fine. I like
43  * > >>to play them in consoles, not in X. However, colour is wrong.
44  * > >>"Slate" and "light slate" are always light blue, instead
45  * > >>of some shade of grey. Colours are fine in X.
46  *
47  * > I actually noticed the Linux console color issue a very long time ago,
48  * > but since I always play under X, I never really investigated it.
49  *
50  * > You're absolutely right, though -- the Linux console colors are not
51  * > "right" for Angband.
52  *
53  *    I've noticed this myself, so I spent the evening fixing it.
54  * Well, sorta fixing it.  It's not perfect yet, and it may not be
55  * possible to get it perfect with VGA hardware and/or the current
56  * Linux kernel.
57  *
58  * > OK, reading on in terminfo(5):
59  *
60  * >    Color Handling
61  * >        Most color terminals are either `Tektronix-like'  or  `HP-
62  * >        like'.   Tektronix-like terminals have a predefined set of
63  * >        N colors (where N usually 8), and can  set  character-cell
64  * >        foreground and background characters independently, mixing
65  * >        them into N * N color-pairs.  On  HP-like  terminals,  the
66  * >        use must set each color pair up separately (foreground and
67  * >        background are  not  independently  settable).   Up  to  M
68  * >        color-pairs  may  be  set  up  from  2*M different colors.
69  * >        ANSI-compatible terminals are Tektronix-like.
70  *
71  * > The "linux" terminfo entry is definitely in the "Tektronix-like" family.
72  * > It has the "setaf" and "setab" capabilities for setting the foreground
73  * > and background colors to one of 8 basically hard-coded values:
74  *
75  * >              Color       #define       Value       RGB
76  * >              black     COLOR_BLACK       0     0, 0, 0
77  * >              red       COLOR_RED         1     max,0,0
78  * >              green     COLOR_GREEN       2     0,max,0
79  * >              yellow    COLOR_YELLOW      3     max,max,0
80  * >              blue      COLOR_BLUE        4     0,0,max
81  * >              magenta   COLOR_MAGENTA     5     max,0,max
82  * >              cyan      COLOR_CYAN        6     0,max,max
83  * >              white     COLOR_WHITE       7     max,max,max
84  *
85  *    Well, not quite.  Using certain escape sequences, an
86  * application (or better yet, curses) can redefine the colors (at
87  * least some of them) and then those are used.  Read the
88  * curs_color manpage, and the part about "ccc" and "initc" in the
89  * terminfo manpage.  This is what the part of main-gcu inside the
90  * "if (can_fix_color)" code does.
91  *
92  * > So, what does this mean to the Angband player?  Well, it means that
93  * > either there's nothing you can do about the console colors as long as
94  * > straight curses/ncurses is used, or if there is something to be done,
95  * > I'm not clever enough to figure out how to do it.
96  *
97  *    Well, it is possible, though you have to patch main-gcu
98  * and edit a terminfo entry.  Apparently the relevant code in
99  * main-gcu was never tested (it's broken in at least one major
100  * way).  Apply the patch at the end of this message (notice that
101  * we need to define REDEFINE_COLORS at some point near the
102  * beginning of the file).
103  *    Next, write this termcap entry to a file:
104  *
105  * linux-c|linux console 1.3.6+ with private palette for each virtual console,
106  *         ccc,
107  *         colors#16, pairs#64,
108  *         initc=\E]P%x%p1%{16}%/%02x%p1%{16}%/%02x%p1%{16}%/%02x,
109  *         oc=\E]R,
110  *         use=linux,
111  *
112  * and run "tic" on it to produce a new terminfo entry called
113  * "linux-c".  Especially note the "ccc" flag which says that we
114  * can redefine colors.  The ugly "initc" string is what tells
115  * the console how to redefine a color.  Now, just set your TERM
116  * variable to "linux-c" and try Angband again.  If I've
117  * remembered to tell you everything that I've done, you should
118  * get the weird light-blue slate changed to a gray.
119  *    Now, there are still lots of problems with this.
120  * Something (I don't think it's curses, either the kernel or
121  * the hardware itself) seems to be ignoring my color changes to
122  * colors 6 and 7, which is annoying.  Also, the normal "white"
123  * color is now way too bright, but it's now necessary to
124  * distinguish it from the other grays.
125  *    The kernel seems to support 16 colors, but you can
126  * only switch to 8 of those, due to VT102 compatibility, it
127  * seems.  I think it would be possible to patch the kernel and
128  * allow all 16 colors to be used, but I haven't built up the
129  * nerve to try that yet.
130  *    Let me know if you can improve on this any.  Some of
131  * this may actually work differently on other hardware (ugh).
132  *
133  *    Keldon
134  *
135  */
136
137 /*
138  * To use this file, you must define "USE_GCU" in the Makefile.
139  *
140  * Hack -- note that "angband.h" is included AFTER the #ifdef test.
141  * This was necessary because of annoying "curses.h" silliness.
142  *
143  * Note that this file is not "intended" to support non-Unix machines,
144  * nor is it intended to support VMS or other bizarre setups.
145  *
146  * Also, this package assumes that the underlying "curses" handles both
147  * the "nonl()" and "cbreak()" commands correctly, see the "OPTION" below.
148  *
149  * This code should work with most versions of "curses" or "ncurses",
150  * and the "main-ncu.c" file (and USE_NCU define) are no longer used.
151  *
152  * See also "USE_CAP" and "main-cap.c" for code that bypasses "curses"
153  * and uses the "termcap" information directly, or even bypasses the
154  * "termcap" information and sends direct vt100 escape sequences.
155  *
156  * XXX XXX XXX Consider the use of "savetty()" and "resetty()".
157  */
158
159 #include "angband.h"
160 #include "io/exit-panic.h"
161 #include "files.h"
162 #include "term.h"
163
164 #ifdef USE_GCU
165
166 /*
167  * Hack -- play games with "bool"
168  */
169 #undef bool
170
171 /*
172  * Include the proper "header" file
173  */
174 # include <curses.h>
175
176 typedef struct term_data term_data;
177
178 struct term_data
179 {
180    term t;
181
182    WINDOW *win;
183 };
184
185 #define MAX_TERM_DATA 4
186
187 static term_data data[MAX_TERM_DATA];
188
189
190 /*
191  * Hack -- try to guess which systems use what commands
192  * Hack -- allow one of the "USE_Txxxxx" flags to be pre-set.
193  * Mega-Hack -- try to guess when "POSIX" is available.
194  * If the user defines two of these, we will probably crash.
195  */
196 #if !defined(USE_TERMIO) && !defined(USE_TCHARS)
197 # if defined(_POSIX_VERSION)
198 #  define USE_TPOSIX
199 # else
200 #  if defined(linux)
201 #   define USE_TERMIO
202 #  else
203 #   define USE_TCHARS
204 #  endif
205 # endif
206 #endif
207
208 /*
209  * Try redefining the colors at startup.
210  */
211 #define REDEFINE_COLORS
212
213 /*
214  * POSIX stuff
215  */
216 #ifdef USE_TPOSIX
217 # include <sys/ioctl.h>
218 # include <termios.h>
219 #endif
220
221 /*
222  * One version needs this file
223  */
224 #ifdef USE_TERMIO
225 # include <sys/ioctl.h>
226 # include <termio.h>
227 #endif
228
229 /*
230  * The other needs this file
231  */
232 #ifdef USE_TCHARS
233 # include <sys/ioctl.h>
234 # include <sys/resource.h>
235 # include <sys/param.h>
236 # include <sys/file.h>
237 # include <sys/types.h>
238 #endif
239
240 #include <locale.h>
241
242 /*
243  * XXX XXX Hack -- POSIX uses "O_NONBLOCK" instead of "O_NDELAY"
244  *
245  * They should both work due to the "(i != 1)" test below.
246  */
247 #ifndef O_NDELAY
248 # define O_NDELAY O_NONBLOCK
249 #endif
250
251 /*
252  * OPTION: some machines lack "cbreak()"
253  * On these machines, we use an older definition
254  */
255 /* #define cbreak() crmode() */
256
257 /*
258  * OPTION: some machines cannot handle "nonl()" and "nl()"
259  * On these machines, we can simply ignore those commands.
260  */
261 /* #define nonl() */
262 /* #define nl() */
263
264  /*
265   * Standard sound names
266   */
267 static const concptr angband_sound_name[SOUND_MAX] =
268 {
269         "dummy",
270         "hit",
271         "miss",
272         "flee",
273         "drop",
274         "kill",
275         "level",
276         "death",
277         "study",
278         "teleport",
279         "shoot",
280         "quaff",
281         "zap",
282         "walk",
283         "tpother",
284         "hitwall",
285         "eat",
286         "store1",
287         "store2",
288         "store3",
289         "store4",
290         "dig",
291         "opendoor",
292         "shutdoor",
293         "tplevel",
294         "scroll",
295         "buy",
296         "sell",
297         "warn",
298         "rocket",
299         "n_kill",
300         "u_kill",
301         "quest",
302         "heal",
303         "x_heal",
304         "bite",
305         "claw",
306         "m_spell",
307         "summon",
308         "breath",
309         "ball",
310         "m_heal",
311         "atkspell",
312         "evil",
313         "touch",
314         "sting",
315         "crush",
316         "slime",
317         "wail",
318         "winner",
319         "fire",
320         "acid",
321         "elec",
322         "cold",
323         "illegal",
324         "fail",
325         "wakeup",
326         "invuln",
327         "fall",
328         "pain",
329         "destitem",
330         "moan",
331         "show",
332         "unused",
333         "explode",
334         "glass",
335         "reflect",
336 };
337
338 static concptr ANGBAND_DIR_XTRA_SOUND;
339
340 /*
341  * todo 有効活用されていない疑惑
342  * Flag set once "sound" has been initialized
343  */
344 static bool can_use_sound = FALSE;
345
346 /*
347  * An array of sound file names
348  */
349 static concptr sound_file[SOUND_MAX];
350
351 /*
352  * Save the "normal" and "angband" terminal settings
353  */
354
355 #ifdef USE_TPOSIX
356
357 static struct termios  norm_termios;
358
359 static struct termios  game_termios;
360
361 #endif
362
363 #ifdef USE_TERMIO
364
365 static struct termio  norm_termio;
366
367 static struct termio  game_termio;
368
369 #endif
370
371 #ifdef USE_TCHARS
372 static struct ltchars norm_speciax_chars;
373 static struct sgttyb  norm_ttyb;
374 static struct tchars  norm_tchars;
375 static int            norm_locax_chars;
376
377 static struct ltchars game_speciax_chars;
378 static struct sgttyb  game_ttyb;
379 static struct tchars  game_tchars;
380 static int            game_locax_chars;
381 #endif
382
383 /*
384  * Hack -- Number of initialized "term" structures
385  */
386 static int active = 0;
387
388 #ifdef A_COLOR
389 /*
390  * Hack -- define "A_BRIGHT" to be "A_BOLD", because on many
391  * machines, "A_BRIGHT" produces ugly "inverse" video.
392  */
393 #ifndef A_BRIGHT
394 # define A_BRIGHT A_BOLD
395 #endif
396
397 /*
398  * Software flag -- we are allowed to use color
399  */
400 static int can_use_color = FALSE;
401
402 /*
403  * Software flag -- we are allowed to change the colors
404  */
405 static int can_fix_color = FALSE;
406
407 /*
408  * Simple Angband to Curses color conversion table
409  */
410 static int colortable[16];
411 #endif
412
413 /*
414  * Place the "keymap" into its "normal" state
415  */
416 static void keymap_norm(void)
417 {
418 #ifdef USE_TPOSIX
419    /* restore the saved values of the special chars */
420    (void)tcsetattr(0, TCSAFLUSH, &norm_termios);
421 #endif
422
423 #ifdef USE_TERMIO
424    /* restore the saved values of the special chars */
425    (void)ioctl(0, TCSETA, (char *)&norm_termio);
426 #endif
427
428 #ifdef USE_TCHARS
429    /* restore the saved values of the special chars */
430    (void)ioctl(0, TIOCSLTC, (char *)&norm_speciax_chars);
431    (void)ioctl(0, TIOCSETP, (char *)&norm_ttyb);
432    (void)ioctl(0, TIOCSETC, (char *)&norm_tchars);
433    (void)ioctl(0, TIOCLSET, (char *)&norm_locax_chars);
434 #endif
435 }
436
437
438 /*
439  * Place the "keymap" into the "game" state
440  */
441 static void keymap_game(void)
442 {
443 #ifdef USE_TPOSIX
444    /* restore the saved values of the special chars */
445    (void)tcsetattr(0, TCSAFLUSH, &game_termios);
446 #endif
447
448 #ifdef USE_TERMIO
449    /* restore the saved values of the special chars */
450    (void)ioctl(0, TCSETA, (char *)&game_termio);
451 #endif
452
453 #ifdef USE_TCHARS
454    /* restore the saved values of the special chars */
455    (void)ioctl(0, TIOCSLTC, (char *)&game_speciax_chars);
456    (void)ioctl(0, TIOCSETP, (char *)&game_ttyb);
457    (void)ioctl(0, TIOCSETC, (char *)&game_tchars);
458    (void)ioctl(0, TIOCLSET, (char *)&game_locax_chars);
459 #endif
460 }
461
462
463 /*
464  * Save the normal keymap
465  */
466 static void keymap_norm_prepare(void)
467 {
468 #ifdef USE_TPOSIX
469    /* Get the normal keymap */
470    tcgetattr(0, &norm_termios);
471 #endif
472
473 #ifdef USE_TERMIO
474    /* Get the normal keymap */
475    (void)ioctl(0, TCGETA, (char *)&norm_termio);
476 #endif
477
478 #ifdef USE_TCHARS
479    /* Get the normal keymap */
480    (void)ioctl(0, TIOCGETP, (char *)&norm_ttyb);
481    (void)ioctl(0, TIOCGLTC, (char *)&norm_speciax_chars);
482    (void)ioctl(0, TIOCGETC, (char *)&norm_tchars);
483    (void)ioctl(0, TIOCLGET, (char *)&norm_locax_chars);
484 #endif
485 }
486
487
488 /*
489  * Save the keymaps (normal and game)
490  */
491 static void keymap_game_prepare(void)
492 {
493 #ifdef USE_TPOSIX
494    /* Acquire the current mapping */
495    tcgetattr(0, &game_termios);
496
497    /* Force "Ctrl-C" to interupt */
498    game_termios.c_cc[VINTR] = (char)3;
499
500    /* Force "Ctrl-Z" to suspend */
501    game_termios.c_cc[VSUSP] = (char)26;
502
503    /* Hack -- Leave "VSTART/VSTOP" alone */
504
505    /* Disable the standard control characters */
506    game_termios.c_cc[VQUIT] = (char)-1;
507    game_termios.c_cc[VERASE] = (char)-1;
508    game_termios.c_cc[VKILL] = (char)-1;
509    game_termios.c_cc[VEOF] = (char)-1;
510    game_termios.c_cc[VEOL] = (char)-1;
511
512    /* Normally, block until a character is read */
513    game_termios.c_cc[VMIN] = 1;
514    game_termios.c_cc[VTIME] = 0;
515 #endif
516
517 #ifdef USE_TERMIO
518    /* Acquire the current mapping */
519    (void)ioctl(0, TCGETA, (char *)&game_termio);
520
521    /* Force "Ctrl-C" to interupt */
522    game_termio.c_cc[VINTR] = (char)3;
523
524    /* Force "Ctrl-Z" to suspend */
525    game_termio.c_cc[VSUSP] = (char)26;
526
527    /* Disable the standard control characters */
528    game_termio.c_cc[VQUIT] = (char)-1;
529    game_termio.c_cc[VERASE] = (char)-1;
530    game_termio.c_cc[VKILL] = (char)-1;
531    game_termio.c_cc[VEOF] = (char)-1;
532    game_termio.c_cc[VEOL] = (char)-1;
533
534    /* Normally, block until a character is read */
535    game_termio.c_cc[VMIN] = 1;
536    game_termio.c_cc[VTIME] = 0;
537 #endif
538
539 #ifdef USE_TCHARS
540    /* Get the default game characters */
541    (void)ioctl(0, TIOCGETP, (char *)&game_ttyb);
542    (void)ioctl(0, TIOCGLTC, (char *)&game_speciax_chars);
543    (void)ioctl(0, TIOCGETC, (char *)&game_tchars);
544    (void)ioctl(0, TIOCLGET, (char *)&game_locax_chars);
545
546    /* Force suspend (^Z) */
547    game_speciax_chars.t_suspc = (char)26;
548
549    /* Cancel some things */
550    game_speciax_chars.t_dsuspc = (char)-1;
551    game_speciax_chars.t_rprntc = (char)-1;
552    game_speciax_chars.t_flushc = (char)-1;
553    game_speciax_chars.t_werasc = (char)-1;
554    game_speciax_chars.t_lnextc = (char)-1;
555
556    /* Force interupt (^C) */
557    game_tchars.t_intrc = (char)3;
558
559    /* Force start/stop (^Q, ^S) */
560    game_tchars.t_startc = (char)17;
561    game_tchars.t_stopc = (char)19;
562
563    /* Cancel some things */
564    game_tchars.t_quitc = (char)-1;
565    game_tchars.t_eofc = (char)-1;
566    game_tchars.t_brkc = (char)-1;
567 #endif
568 }
569
570
571
572 /*
573  * Suspend/Resume
574  */
575 static errr Term_xtra_gcu_alive(int v)
576 {
577    if (!v)
578    {
579       /* Go to normal keymap mode */
580       keymap_norm();
581
582       /* Restore modes */
583       nocbreak();
584       echo();
585       nl();
586
587       /* Hack -- make sure the cursor is visible */
588       Term_xtra(TERM_XTRA_SHAPE, 1);
589
590       /* Flush the curses buffer */
591       (void)refresh();
592
593       /* this moves curses to bottom right corner */
594       mvcur(getcury(curscr), getcurx(curscr), LINES - 1, 0);
595
596       /* Exit curses */
597       endwin();
598
599       /* Flush the output */
600       (void)fflush(stdout);
601    }
602    else
603    {
604       /* Restore the settings */
605       cbreak();
606       noecho();
607       nonl();
608
609       /* Go to angband keymap mode */
610       keymap_game();
611    }
612
613    return (0);
614 }
615
616
617 /*
618  * Check for existance of a file
619  */
620 static bool check_file(concptr s)
621 {
622    FILE *fff;
623    fff = fopen(s, "r");
624    if (!fff) return (FALSE);
625
626    fclose(fff);
627    return (TRUE);
628 }
629
630
631 /*
632  * Initialize sound
633  */
634 static bool init_sound(void)
635 {
636    /* Initialize once */
637         if (can_use_sound) return can_use_sound;
638
639         int i;
640         char wav[128];
641         char buf[1024];
642
643         /* Prepare the sounds */
644         for (i = 1; i < SOUND_MAX; i++)
645         {
646                 /* Extract name of sound file */
647                 sprintf(wav, "%s.wav", angband_sound_name[i]);
648
649                 /* Access the sound */
650                 path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_SOUND, wav);
651
652                 /* Save the sound filename, if it exists */
653                 if (check_file(buf)) sound_file[i] = string_make(buf);
654         }
655
656         /* Sound available */
657         can_use_sound = TRUE;
658         return (can_use_sound);
659 }
660
661
662 /*
663  * Init the "curses" system
664  */
665 static void Term_init_gcu(term *t)
666 {
667    term_data *td = (term_data *)(t->data);
668
669    /* Count init's, handle first */
670    if (active++ != 0) return;
671
672    /* Erase the screen */
673    (void)wclear(td->win);
674
675    /* Reset the cursor */
676    (void)wmove(td->win, 0, 0);
677
678    /* Flush changes */
679    (void)wrefresh(td->win);
680
681    /* Game keymap */
682    keymap_game();
683 }
684
685
686 /*
687  * Nuke the "curses" system
688  */
689 static void Term_nuke_gcu(term *t)
690 {
691    term_data *td = (term_data *)(t->data);
692
693    /* Delete this window */
694    delwin(td->win);
695
696    /* Count nuke's, handle last */
697    if (--active != 0) return;
698
699    /* Hack -- make sure the cursor is visible */
700    Term_xtra(TERM_XTRA_SHAPE, 1);
701
702 #ifdef A_COLOR
703   /* Reset colors to defaults */
704   start_color();
705 #endif
706
707    /* This moves curses to bottom right corner */
708    mvcur(getcury(curscr), getcurx(curscr), LINES - 1, 0);
709
710    /* Flush the curses buffer */
711    (void)refresh();
712
713    /* Exit curses */
714    endwin();
715
716    /* Flush the output */
717    (void)fflush(stdout);
718
719    /* Normal keymap */
720    keymap_norm();
721 }
722
723 #ifdef USE_GETCH
724
725 /*
726  * Process events, with optional wait
727  */
728 static errr Term_xtra_gcu_event(int v)
729 {
730    int i, k;
731
732    /* Wait */
733    if (v)
734    {
735       /* Paranoia -- Wait for it */
736       nodelay(stdscr, FALSE);
737
738       /* Get a keypress */
739       i = getch();
740
741       /* Mega-Hack -- allow graceful "suspend" */
742       for (k = 0; (k < 10) && (i == ERR); k++) i = getch();
743
744       /* Broken input is special */
745       if (i == ERR) exit_game_panic(p_ptr);
746       if (i == EOF) exit_game_panic(p_ptr);
747    }
748
749    /* Do not wait */
750    else
751    {
752       /* Do not wait for it */
753       nodelay(stdscr, TRUE);
754
755       /* Check for keypresses */
756       i = getch();
757
758       /* Wait for it next time */
759       nodelay(stdscr, FALSE);
760
761       /* None ready */
762       if (i == ERR) return (1);
763       if (i == EOF) return (1);
764    }
765
766    /* Enqueue the keypress */
767    Term_keypress(i);
768
769    /* Success */
770    return (0);
771 }
772
773 #else /* USE_GETCH */
774
775 /*
776  * Process events (with optional wait)
777  */
778 static errr Term_xtra_gcu_event(int v)
779 {
780    int i, k;
781
782    char buf[2];
783
784    /* Wait */
785    if (v)
786    {
787       /* Wait for one byte */
788       i = read(0, buf, 1);
789
790       /* Hack -- Handle bizarre "errors" */
791       if ((i <= 0) && (errno != EINTR)) exit_game_panic(p_ptr);
792    }
793
794    /* Do not wait */
795    else
796    {
797       /* Get the current flags for stdin */
798       k = fcntl(0, F_GETFL, 0);
799
800       /* Oops */
801       if (k < 0) return (1);
802
803       /* Tell stdin not to block */
804       if (fcntl(0, F_SETFL, k | O_NDELAY) < 0) return (1);
805
806       /* Read one byte, if possible */
807       i = read(0, buf, 1);
808
809       /* Replace the flags for stdin */
810       if (fcntl(0, F_SETFL, k)) return (1);
811    }
812
813    /* Ignore "invalid" keys */
814    if ((i != 1) || (!buf[0])) return (1);
815
816    /* Enqueue the keypress */
817    Term_keypress(buf[0]);
818
819    /* Success */
820    return (0);
821 }
822
823 #endif   /* USE_GETCH */
824
825 /*
826  * Hack -- make a sound
827  */
828 static errr Term_xtra_gcu_sound(int v)
829 {
830    char buf[1024];
831
832    /* Sound disabled */
833    if (!use_sound) return (1);
834
835    /* Illegal sound */
836    if ((v < 0) || (v >= SOUND_MAX)) return (1);
837
838    /* Unknown sound */
839    if (!sound_file[v]) return (1);
840
841    sprintf(buf,"./gcusound.sh %s\n", sound_file[v]);
842    
843    return (system(buf) < 0);
844
845    return (0);
846
847 }
848
849
850 /*
851  * React to changes
852  */
853 static errr Term_xtra_gcu_react(void)
854 {
855
856 #ifdef A_COLOR
857
858         int i;
859
860         /* Cannot handle color redefinition */
861         if (!can_fix_color) return (0);
862
863         /* Set the colors */
864         for (i = 0; i < 16; i++)
865         {
866                 /* Set one color (note scaling) */
867                 init_color(i, angband_color_table[i][1] * 1000 / 255,
868                               angband_color_table[i][2] * 1000 / 255,
869                               angband_color_table[i][3] * 1000 / 255);
870         }
871
872 #endif
873
874         /* Success */
875         return (0);
876 }
877
878
879 /*
880  * Handle a "special request"
881  */
882 static errr Term_xtra_gcu(int n, int v)
883 {
884    term_data *td = (term_data *)(Term->data);
885
886    /* Analyze the request */
887    switch (n)
888    {
889       /* Clear screen */
890       case TERM_XTRA_CLEAR:
891       touchwin(td->win);
892       (void)wclear(td->win);
893       return (0);
894
895       /* Make a noise */
896       case TERM_XTRA_NOISE:
897       return write(1, "\007", 1) != 1;
898
899       /* Make a special sound */
900       case TERM_XTRA_SOUND:
901          return (Term_xtra_gcu_sound(v));
902
903       /* Flush the Curses buffer */
904       case TERM_XTRA_FRESH:
905       (void)wrefresh(td->win);
906       return (0);
907
908 #ifdef USE_CURS_SET
909
910       /* Change the cursor visibility */
911       case TERM_XTRA_SHAPE:
912       curs_set(v);
913       return (0);
914
915 #endif
916
917       /* Suspend/Resume curses */
918       case TERM_XTRA_ALIVE:
919       return (Term_xtra_gcu_alive(v));
920
921       /* Process events */
922       case TERM_XTRA_EVENT:
923       return (Term_xtra_gcu_event(v));
924
925       /* Flush events */
926       case TERM_XTRA_FLUSH:
927       while (!Term_xtra_gcu_event(FALSE));
928       return (0);
929
930       /* Delay */
931       case TERM_XTRA_DELAY:
932       usleep(1000 * v);
933       return (0);
934
935       /* React to events */
936       case TERM_XTRA_REACT:
937       Term_xtra_gcu_react();
938       return (0);
939
940    }
941
942
943    /* Unknown */
944    return (1);
945 }
946
947
948 /*
949  * Actually MOVE the hardware cursor
950  */
951 static errr Term_curs_gcu(int x, int y)
952 {
953    term_data *td = (term_data *)(Term->data);
954
955    /* Literally move the cursor */
956    wmove(td->win, y, x);
957
958    /* Success */
959    return (0);
960 }
961
962
963 /*
964  * Erase a grid of space
965  * Hack -- try to be "semi-efficient".
966  */
967 static errr Term_wipe_gcu(int x, int y, int n)
968 {
969    term_data *td = (term_data *)(Term->data);
970
971    /* Place cursor */
972    wmove(td->win, y, x);
973
974    /* Clear to end of line */
975    if (x + n >= 80)
976    {
977       wclrtoeol(td->win);
978    }
979
980    /* Clear some characters */
981    else
982    {
983       while (n-- > 0) waddch(td->win, ' ');
984    }
985
986    /* Success */
987    return (0);
988 }
989
990 #ifdef USE_NCURSES_ACS
991 /*
992  * this function draws some ACS characters on the screen
993  * for DOS-based users: these are the graphical chars (blocks, lines etc)
994  *
995  * unix-gurus: before you start adding other attributes like A_REVERSE
996  * think hard about how map_info() in cave.c should handle the color
997  * of something that we here draw in reverse. It's not so simple, alas.
998  */
999 static void Term_acs_text_gcu(int x, int y, int n, byte a, concptr s)
1000 {
1001    term_data *td = (term_data *)(Term->data);
1002    int i;
1003
1004    /* position the cursor */
1005    wmove(td->win, y, x);
1006
1007 #ifdef A_COLOR
1008    /* Set the color */
1009    wattrset(td->win, colortable[a & 0x0F]);
1010 #endif
1011
1012    for (i=0; i < n; i++)
1013    {
1014       /* add acs_map of a */
1015       waddch(td->win, acs_map[(int)s[i]]);
1016    }
1017    wattrset(td->win, WA_NORMAL);
1018 }
1019 #endif
1020
1021 /*
1022  * Place some text on the screen using an attribute
1023  */
1024 static errr Term_text_gcu(int x, int y, int n, byte a, concptr s)
1025 {
1026    term_data *td = (term_data *)(Term->data);
1027
1028    int i;
1029
1030    char text[81];
1031
1032 #ifdef USE_NCURSES_ACS
1033    /* do we have colors + 16 ? */
1034    /* then call special routine for drawing special characters */
1035    if (a & 0x10)
1036    {
1037       Term_acs_text_gcu(x, y, n, a, s);
1038       return(0);
1039    }
1040 #endif
1041
1042    /* Obtain a copy of the text */
1043    for (i = 0; i < n; i++) text[i] = s[i];    text[n] = 0;
1044
1045    /* Move the cursor and dump the string */
1046    wmove(td->win, y, x);
1047
1048 #ifdef A_COLOR
1049    /* Set the color */
1050    if (can_use_color) wattrset(td->win, colortable[a & 0x0F]);
1051 #endif
1052
1053    /* Add the text */
1054    waddstr(td->win, text);
1055
1056    /* Success */
1057    return (0);
1058 }
1059
1060
1061
1062 static errr term_data_init(term_data *td, int rows, int cols, int y, int x)
1063 {
1064    term *t = &td->t;
1065
1066    /* Make sure the window has a positive size */
1067    if (rows <= 0 || cols <= 0) return (0);
1068
1069    /* Create a window */
1070    td->win = newwin(rows, cols, y, x);
1071
1072    /* Make sure we succeed */
1073    if (!td->win)
1074    {
1075       plog("Failed to setup curses window.");
1076       return (-1);
1077    }
1078
1079    /* Initialize the term */
1080    term_init(t, cols, rows, 256);
1081
1082    /* Avoid the bottom right corner */
1083    t->icky_corner = TRUE;
1084
1085    /* Erase with "white space" */
1086    t->attr_blank = TERM_WHITE;
1087    t->char_blank = ' ';
1088
1089    /* Set some hooks */
1090    t->init_hook = Term_init_gcu;
1091    t->nuke_hook = Term_nuke_gcu;
1092
1093    /* Set some more hooks */
1094    t->text_hook = Term_text_gcu;
1095    t->wipe_hook = Term_wipe_gcu;
1096    t->curs_hook = Term_curs_gcu;
1097    t->xtra_hook = Term_xtra_gcu;
1098
1099    /* Save the data */
1100    t->data = td;
1101
1102    /* Activate it */
1103    Term_activate(t);
1104
1105
1106    /* Success */
1107    return (0);
1108 }
1109
1110
1111 static void hook_quit(concptr str)
1112 {
1113         /* Unused */
1114         (void)str;
1115
1116        /* Exit curses */
1117        endwin();
1118 }
1119
1120
1121 /*
1122  * Prepare "curses" for use by the file "term.c"
1123  *
1124  * Installs the "hook" functions defined above, and then activates
1125  * the main screen "term", which clears the screen and such things.
1126  *
1127  * Someone should really check the semantics of "initscr()"
1128  */
1129 errr init_gcu(int argc, char *argv[])
1130 {
1131    int i;
1132
1133    int num_term = 4, next_win = 0;
1134    char path[1024];
1135
1136    /* Unused */
1137    (void)argc;
1138    (void)argv;
1139
1140
1141    setlocale(LC_ALL, "");
1142
1143    /* Build the "sound" path */
1144    path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "sound");
1145
1146    /* Allocate the path */
1147    ANGBAND_DIR_XTRA_SOUND = string_make(path);
1148
1149    /* Extract the normal keymap */
1150    keymap_norm_prepare();
1151
1152    /* Initialize for others systems */
1153    if (initscr() == (WINDOW*)ERR) return (-1);
1154
1155    /* Activate hooks */
1156    quit_aux = hook_quit;
1157    core_aux = hook_quit;
1158
1159    /* Hack -- Require large screen, or Quit with message */
1160    i = ((LINES < 24) || (COLS < 80));
1161    if (i) quit("Angband needs an 80x24 'curses' screen");
1162
1163
1164 #ifdef A_COLOR
1165
1166    /*** Init the Color-pairs and set up a translation table ***/
1167
1168    /* Do we have color, and enough color, available? */
1169    can_use_color = ((start_color() != ERR) && has_colors() &&
1170                     (COLORS >= 8) && (COLOR_PAIRS >= 8));
1171
1172 #ifdef REDEFINE_COLORS
1173         /* Can we change colors? */
1174         can_fix_color = (can_use_color && can_change_color() &&
1175                          (COLORS >= 16) && (COLOR_PAIRS > 8));
1176 #endif
1177
1178    /* Attempt to use customized colors */
1179    if (can_fix_color)
1180    {
1181       /* Prepare the color pairs */
1182            for (i = 1; i <= 15; i++)
1183            {
1184                    if (init_pair(i, i, 0) == ERR)
1185                    {
1186                            quit("Color pair init failed");
1187                    }
1188
1189                    colortable[i] = COLOR_PAIR(i);
1190                    Term_xtra_gcu_react();
1191            }
1192    }
1193    /* Attempt to use colors */
1194    else if (can_use_color)
1195    {
1196                 /* Color-pair 0 is *always* WHITE on BLACK */
1197
1198                 /* Prepare the color pairs */
1199                 init_pair(1, COLOR_RED,     COLOR_BLACK);
1200                 init_pair(2, COLOR_GREEN,   COLOR_BLACK);
1201                 init_pair(3, COLOR_YELLOW,  COLOR_BLACK);
1202                 init_pair(4, COLOR_BLUE,    COLOR_BLACK);
1203                 init_pair(5, COLOR_MAGENTA, COLOR_BLACK);
1204                 init_pair(6, COLOR_CYAN,    COLOR_BLACK);
1205                 init_pair(7, COLOR_BLACK,   COLOR_BLACK);
1206
1207                 /* Prepare the "Angband Colors" -- Bright white is too bright */
1208                 /* Changed in Drangband. Cyan as grey sucks -- -TM- */
1209                 colortable[0] = (COLOR_PAIR(7) | A_NORMAL);     /* Black */
1210                 colortable[1] = (COLOR_PAIR(0) | A_BRIGHT);     /* White */
1211                 colortable[2] = (COLOR_PAIR(0) | A_NORMAL);     /* Grey XXX */
1212                 colortable[3] = (COLOR_PAIR(1) | A_BRIGHT);     /* Orange XXX */
1213                 colortable[4] = (COLOR_PAIR(1) | A_NORMAL);     /* Red */
1214                 colortable[5] = (COLOR_PAIR(2) | A_NORMAL);     /* Green */
1215                 colortable[6] = (COLOR_PAIR(4) | A_BRIGHT);     /* Blue */
1216                 colortable[7] = (COLOR_PAIR(3) | A_NORMAL);     /* Umber */
1217                 colortable[8] = (COLOR_PAIR(7) | A_BRIGHT);     /* Dark-grey XXX */
1218                 colortable[9] = (COLOR_PAIR(0) | A_NORMAL);     /* Light-grey XXX */
1219                 colortable[10] = (COLOR_PAIR(5) | A_BRIGHT);    /* Purple */
1220                 colortable[11] = (COLOR_PAIR(3) | A_BRIGHT);    /* Yellow */
1221                 colortable[12] = (COLOR_PAIR(5) | A_NORMAL);    /* Light Red XXX */
1222                 colortable[13] = (COLOR_PAIR(2) | A_BRIGHT);    /* Light Green */
1223                 colortable[14] = (COLOR_PAIR(6) | A_BRIGHT);    /* Light Blue */
1224                 colortable[15] = (COLOR_PAIR(3) | A_NORMAL);    /* Light Umber XXX */
1225
1226    }
1227
1228 #endif
1229
1230    /* Handle "arg_sound" */
1231    if (use_sound != arg_sound)
1232    {
1233       /* Initialize (if needed) */
1234       if (arg_sound && !init_sound())
1235       {
1236          /* Warning */
1237          plog("Cannot initialize sound!");
1238
1239          /* Cannot enable */
1240          arg_sound = FALSE;
1241       }
1242
1243       /* Change setting */
1244       use_sound = arg_sound;
1245    }
1246
1247    /* Try graphics */
1248    if (arg_graphics)
1249    {
1250       /* if USE_NCURSES_ACS is defined, we can do something with graphics in curses! */
1251 #ifdef USE_NCURSES_ACS
1252       use_graphics = TRUE;
1253 #endif
1254    }
1255
1256    /*** Low level preparation ***/
1257
1258 #ifdef USE_GETCH
1259
1260    /* Paranoia -- Assume no waiting */
1261    nodelay(stdscr, FALSE);
1262
1263 #endif
1264
1265    /* Prepare */
1266    cbreak();
1267    noecho();
1268    nonl();
1269    raw();
1270
1271    /* Extract the game keymap */
1272    keymap_game_prepare();
1273
1274
1275    /*** Now prepare the term(s) ***/
1276    for (i = 0; i < num_term; i++)
1277    {
1278       int rows, cols;
1279       int y, x;
1280
1281       switch (i)
1282       {
1283          /* Upper left */
1284          case 0: rows = 24;
1285             cols = 80;
1286             y = x = 0;
1287             break;
1288          /* Lower left */
1289          case 1: rows = LINES - 25;
1290             cols = 80;
1291             y = 24;
1292             x = 0;
1293             break;
1294          /* Upper right */
1295          case 2: rows = 24;
1296             cols = COLS - 81;
1297             y = 0;
1298             x = 81;
1299             break;
1300          /* Lower right */
1301          case 3: rows = LINES - 25;
1302             cols = COLS - 81;
1303             y = 24;
1304             x = 81;
1305             break;
1306          /* XXX */
1307          default: rows = cols = 0;
1308              y = x = 0;
1309              break;
1310       }
1311
1312       /* No non-windows */
1313       if (rows <= 0 || cols <= 0) continue;
1314
1315       /* Initialize */
1316       term_data_init(&data[next_win], rows, cols, y, x);
1317
1318       /* Store */
1319       angband_term[next_win] = Term;
1320
1321       next_win++;
1322    }
1323
1324    /* Activate the "Angband" window screen */
1325    Term_activate(&data[0].t);
1326
1327    /* Store */
1328    term_screen = &data[0].t;
1329
1330    /* Success */
1331    return (0);
1332 }
1333
1334
1335 #endif /* USE_GCU */
1336
1337