Get rid of obnoxious visible "have we paused?" state.
[super-star-trek.git] / src / io.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <wchar.h>
4
5 #include "config.h"
6 #include "sst.h"
7 #include "sstlinux.h"
8
9 static int rows, linecount;     /* for paging */
10 static bool pause_latch;
11
12 WINDOW *curwnd;
13 WINDOW *fullscreen_window;
14 WINDOW *srscan_window;
15 WINDOW *report_window;
16 WINDOW *status_window;
17 WINDOW *lrscan_window;
18 WINDOW *message_window;
19 WINDOW *prompt_window;
20
21 static void outro(void)
22 /* wrap up, either normally or due to signal */
23 {
24     if (game.options & OPTION_CURSES) {
25         //clear();
26         //curs_set(1);
27         //refresh();
28         //resetterm();
29         //echo();
30         endwin();
31         putchar('\n');
32     }
33     if (logfp)
34         fclose(logfp);
35 }
36
37 void iostart(void) 
38 {
39     setlocale(LC_ALL, "");
40     bindtextdomain(PACKAGE, LOCALEDIR);
41     textdomain(PACKAGE);
42
43     if (atexit(outro)){
44         fprintf(stderr,"Unable to register outro(), exiting...\n");
45         exit(1);
46     }
47     if (!(game.options & OPTION_CURSES)) {
48         char *ln_env = getenv("LINES");
49         rows = ln_env ? atoi(ln_env) : 25;
50     } else {
51         initscr();
52 #ifdef KEY_MIN
53         keypad(stdscr, TRUE);
54 #endif /* KEY_MIN */
55         saveterm();
56         nonl();
57         cbreak();
58 #ifdef A_COLOR
59         {
60             start_color();
61             init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK);
62             init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
63             init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
64             init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
65             init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
66             init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
67             init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
68             init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
69         }
70 #endif /* A_COLOR */
71         //noecho();
72         fullscreen_window = stdscr;
73         srscan_window     = newwin(12, 25, 0,       0);
74         report_window     = newwin(11, 0,  1,       25);
75         status_window     = newwin(10, 0,  1,       39);
76         lrscan_window     = newwin(5,  0,  0,       64); 
77         message_window    = newwin(0,  0,  12,      0);
78         prompt_window     = newwin(1,  0,  LINES-2, 0); 
79         scrollok(message_window, TRUE);
80         setwnd(fullscreen_window);
81         textcolor(DEFAULT);
82     }
83 }
84
85
86 void waitfor(void)
87 /* wait for user action -- OK to do nothing if on a TTY */
88 {
89     if (game.options & OPTION_CURSES)
90         getch();
91 }
92
93 void pause_reset(void)
94 {
95     pause_latch = false;
96 }
97
98 void pause_game(bool announcement) 
99 {
100     if (pause_latch)
101         return;
102     else {
103         char *prompt;
104         char buf[BUFSIZ];
105         if (announcement) {
106             if (game.skill > SKILL_FAIR)
107                 prompt = _("[ANOUNCEMENT ARRIVING...]");
108             else
109                 prompt = _("[IMPORTANT ANNOUNCEMENT ARRIVING -- PRESS ENTER TO CONTINUE]");
110         }
111         else {
112             if (game.skill > SKILL_FAIR)
113                 prompt = _("[CONTINUE?]");
114             else
115                 prompt = _("[PRESS ENTER TO CONTINUE]");
116
117         }
118         if (game.options & OPTION_CURSES) {
119             drawmaps(0);
120             setwnd(prompt_window);
121             wclear(prompt_window);
122             waddstr(prompt_window, prompt);
123             wgetnstr(prompt_window, buf, sizeof(buf));
124             wclear(prompt_window);
125             wrefresh(prompt_window);
126             setwnd(message_window);
127         } else {
128             putchar('\n');
129             proutn(prompt);
130             fgets(buf, sizeof(buf), stdin);
131             if (announcement) {
132                 int j;
133                 for (j = 0; j < rows; j++)
134                     putchar('\n');
135             }
136             linecount = 0;
137         }
138         pause_latch = true;
139     }
140 }
141
142
143 void skip(int i) 
144 {
145     while (i-- > 0) {
146         if (game.options & OPTION_CURSES) {
147             if (curwnd == message_window && getcury(curwnd) >= getmaxy(curwnd) - 3) {
148                 pause_game(false);
149                 clrscr();
150             } else {
151                 proutn("\n");
152             }
153         } else {
154             linecount++;
155             if (linecount >= rows)
156                 pause_game(false);
157             else
158                 putchar('\n');
159         }
160     }
161 }
162
163 static void vproutn(const char *fmt, va_list ap) 
164 {
165     if (game.options & OPTION_CURSES) {
166         vwprintw(curwnd, fmt, ap);
167         wrefresh(curwnd);
168     }
169     else
170         vprintf(fmt, ap);
171 }
172
173 void proutn(const char *fmt, ...) 
174 {
175     va_list ap;
176     va_start(ap, fmt);
177     vproutn(fmt, ap);
178     va_end(ap);
179 }
180
181 void prout(const char *fmt, ...) 
182 {
183     va_list ap;
184     va_start(ap, fmt);
185     vproutn(fmt, ap);
186     va_end(ap);
187     skip(1);
188 }
189
190 void prouts(const char *fmt, ...) 
191 /* print slowly! */
192 {
193     char buf[BUFSIZ];
194     wchar_t *s, mbuf[BUFSIZ];
195     va_list ap;
196     va_start(ap, fmt);
197     vsprintf(buf, fmt, ap);
198     va_end(ap);
199     mbstowcs(mbuf, buf, BUFSIZ);
200     for (s = mbuf; *s; s++) {
201         /* HOW to convince ncurses to use wchar_t?? */
202         /* WHY putwchar() doesn't work?? */
203         /* OK then, convert back to mbs... */
204         char c[MB_CUR_MAX*2];
205         int n;
206         n = wctomb(c, *s);
207         c[n] = 0;
208         delay(30);
209         proutn(c);
210         if (game.options & OPTION_CURSES)
211             wrefresh(curwnd);
212         else
213             fflush(stdout);
214     }
215     delay(300);
216 }
217
218 void cgetline(char *line, int max)
219 {
220     if (game.options & OPTION_CURSES) {
221         wgetnstr(curwnd, line, max);
222         strcat(line, "\n");
223         wrefresh(curwnd);
224     } else {
225         if (replayfp && !feof(replayfp))
226             fgets(line, max, replayfp);
227         else
228             fgets(line, max, stdin);
229     }
230     if (logfp)
231         fputs(line, logfp);
232     line[strlen(line)-1] = '\0';
233 }
234
235 void setwnd(WINDOW *wnd)
236 /* change windows -- OK for this to be a no-op in tty mode */
237 {
238     if (game.options & OPTION_CURSES) {
239      curwnd=wnd;
240      curs_set(wnd == fullscreen_window || wnd == message_window || wnd == prompt_window);
241     }
242 }
243
244 void clreol(void)
245 /* clear to end of line -- can be a no-op in tty mode */
246 {
247    if (game.options & OPTION_CURSES) {
248        wclrtoeol(curwnd);
249        wrefresh(curwnd);
250    }
251 }
252
253 void clrscr(void)
254 /* clear screen -- can be a no-op in tty mode */
255 {
256    if (game.options & OPTION_CURSES) {
257        wclear(curwnd);
258        wmove(curwnd,0,0);
259        wrefresh(curwnd);
260    }
261    linecount = 0;
262 }
263
264 void textcolor(int color)
265 {
266 #ifdef A_COLOR
267     if (game.options & OPTION_CURSES) {
268         switch(color) {
269         case DEFAULT: 
270             wattrset(curwnd, 0);
271             break;
272         case BLACK: 
273             wattron(curwnd, COLOR_PAIR(COLOR_BLACK));
274             break;
275         case BLUE: 
276             wattron(curwnd, COLOR_PAIR(COLOR_BLUE));
277             break;
278         case GREEN: 
279             wattron(curwnd, COLOR_PAIR(COLOR_GREEN));
280             break;
281         case CYAN: 
282             wattron(curwnd, COLOR_PAIR(COLOR_CYAN));
283             break;
284         case RED: 
285             wattron(curwnd, COLOR_PAIR(COLOR_RED));
286             break;
287         case MAGENTA: 
288             wattron(curwnd, COLOR_PAIR(COLOR_MAGENTA));
289             break;
290         case BROWN: 
291             wattron(curwnd, COLOR_PAIR(COLOR_YELLOW));
292             break;
293         case LIGHTGRAY: 
294             wattron(curwnd, COLOR_PAIR(COLOR_WHITE));
295             break;
296         case DARKGRAY: 
297             wattron(curwnd, COLOR_PAIR(COLOR_BLACK) | A_BOLD);
298             break;
299         case LIGHTBLUE: 
300             wattron(curwnd, COLOR_PAIR(COLOR_BLUE) | A_BOLD);
301             break;
302         case LIGHTGREEN: 
303             wattron(curwnd, COLOR_PAIR(COLOR_GREEN) | A_BOLD);
304             break;
305         case LIGHTCYAN: 
306             wattron(curwnd, COLOR_PAIR(COLOR_CYAN) | A_BOLD);
307             break;
308         case LIGHTRED: 
309             wattron(curwnd, COLOR_PAIR(COLOR_RED) | A_BOLD);
310             break;
311         case LIGHTMAGENTA: 
312             wattron(curwnd, COLOR_PAIR(COLOR_MAGENTA) | A_BOLD);
313             break;
314         case YELLOW: 
315             wattron(curwnd, COLOR_PAIR(COLOR_YELLOW) | A_BOLD);
316             break;
317         case WHITE:
318             wattron(curwnd, COLOR_PAIR(COLOR_WHITE) | A_BOLD);
319             break;
320         }
321     }
322 #endif /* A_COLOR */
323 }
324
325 void highvideo(void)
326 {
327     if (game.options & OPTION_CURSES) {
328         wattron(curwnd, A_REVERSE);
329     }
330 }
331  
332 void commandhook(char *cmd, bool before) {
333 }
334
335 /*
336  * Things past this point have policy implications.
337  */
338
339 void drawmaps(int mode)
340 /* hook to be called after moving to redraw maps */
341 {
342     if (game.options & OPTION_CURSES) {
343         if (mode == 1)
344             sensor();
345         setwnd(srscan_window);
346         wmove(curwnd, 0, 0);
347         srscan();
348         if (mode != 2) {
349             setwnd(status_window);
350             wclear(status_window);
351             wmove(status_window, 0, 0);
352             setwnd(report_window);
353             wclear(report_window);
354             wmove(report_window, 0, 0);
355             status(0);
356             setwnd(lrscan_window);
357             wclear(lrscan_window);
358             wmove(lrscan_window, 0, 0);
359             lrscan();
360         }
361     }
362 }
363
364 static void put_srscan_sym(coord w, char sym)
365 {
366     wmove(srscan_window, w.x+1, w.y*2+2);
367     waddch(srscan_window, sym);
368     wrefresh(srscan_window);
369 }
370
371 void boom(coord w)
372 /* enemy fall down, go boom */ 
373 {
374     if (game.options & OPTION_CURSES) {
375         drawmaps(2);
376         setwnd(srscan_window);
377         wattron(srscan_window, A_REVERSE);
378         put_srscan_sym(w, game.quad[w.x][w.y]);
379         sound(500);
380         delay(1000);
381         nosound();
382         wattroff(srscan_window, A_REVERSE);
383         put_srscan_sym(w, game.quad[w.x][w.y]);
384         delay(500);
385         setwnd(message_window);
386     }
387
388
389 void warble(void)
390 /* sound and visual effects for teleportation */
391 {
392     if (game.options & OPTION_CURSES) {
393         drawmaps(2);
394         setwnd(message_window);
395         sound(50);
396     }
397     prouts("     . . . . .     ");
398     if (game.options & OPTION_CURSES) {
399         delay(1000);
400         nosound();
401     }
402 }
403
404 void tracktorpedo(coord w, int l, int i, int n, int iquad)
405 /* torpedo-track animation */
406 {
407     if (!game.options & OPTION_CURSES) {
408         if (l == 1) {
409             if (n != 1) {
410                 skip(1);
411                 proutn(_("Track for torpedo number %d-  "), i);
412             }
413             else {
414                 skip(1);
415                 proutn(_("Torpedo track- "));
416             }
417         } else if (l==4 || l==9) 
418             skip(1);
419         proutn("%d - %d   ", w.x, w.y);
420     } else {
421         if (!damaged(DSRSENS) || game.condition==docked) {
422             if (i != 1 && l == 1) {
423                 drawmaps(2);
424                 delay(400);
425             }
426             if ((iquad==IHDOT)||(iquad==IHBLANK)){
427                 put_srscan_sym(w, '+');
428                 sound(l*10);
429                 delay(100);
430                 nosound();
431                 put_srscan_sym(w, iquad);
432             }
433             else {
434                 wattron(curwnd, A_REVERSE);
435                 put_srscan_sym(w, iquad);
436                 sound(500);
437                 delay(1000);
438                 nosound();
439                 wattroff(curwnd, A_REVERSE);
440                 put_srscan_sym(w, iquad);
441             }
442         } else {
443             proutn("%d - %d   ", w.x, w.y);
444         }
445     }
446 }
447
448 void makechart(void) 
449 {
450     if (game.options & OPTION_CURSES) {
451         setwnd(message_window);
452         wclear(message_window);
453     }
454     chart();
455     if (game.options & OPTION_TTY) {
456         skip(1);
457     }
458 }
459
460 void prstat(const char *txt, const char *fmt, ...)
461 {
462 #define NSYM 14
463     int i;
464     va_list args;
465     proutn(txt);
466     if (game.options & OPTION_CURSES) {
467         skip(1);
468     } else  {
469         for (i = mblen(txt, strlen(txt)); i < NSYM; i++)
470             proutn(" ");
471     }
472     if (game.options & OPTION_CURSES)
473         setwnd(status_window);
474     va_start(args, fmt);
475     vproutn(fmt, args);
476     va_end(args);
477     skip(1);
478     if (game.options & OPTION_CURSES)
479         setwnd(report_window);
480 }