OSDN Git Service

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