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