Varargs cleanup is almost finished.
[vms-empire.git] / term.c
1 /*
2  *    Copyright (C) 1987, 1988 Chuck Simmons
3  * 
4  * See the file COPYING, distributed with empire, for restriction
5  * and warranty information.
6  */
7
8 /*
9 term.c -- this file contains various routines used to control the
10 user communications area of the terminal.  This area consists of
11 the top 3 lines of the terminal where messages are displayed to the
12 user and input is acquired from the user.
13
14 There are two types of output in this area.  One type is interactive
15 output.  This consists of a prompt line and an error message line.
16 The other type of output is informational output.  The user must
17 be given time to read informational output.
18
19 Whenever input is received, the top three lines are cleared and the
20 screen refreshed as the user has had time to read these lines.  We
21 also clear the 'need_delay' flag, saying that the user has read the
22 information on the screen.
23
24 When information is to be displayed, if the 'need_delay' flag is set,
25 we refresh the screen and pause momentarily to give the user a chance
26 to read the lines.  The new information is then displayed, and the
27 'need_delay' flag is set.
28 */
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <curses.h>
34 #include <ctype.h>
35 #include <stdarg.h>
36
37 #include "empire.h"
38 #include "extern.h"
39
40 static bool need_delay;
41 static FILE *my_stream;
42
43 /*
44 Here are routines that handle printing to the top few lines of the
45 screen.  'topini' should be called at initialization, and whenever
46 we finish printing information to the screen.
47 */
48
49 void
50 topini(void)
51 {
52         info (0, 0, 0);
53 }
54 /*
55 Write a message to one of the top lines.
56 */
57
58 static void vtopmsg(int line, const char *fmt, va_list varglist)
59 /* assemble command in printf(3) style, print to a top line */
60 {
61         char junkbuf[STRSIZE];
62         
63         if (line < 1 || line > NUMTOPS)
64             line = 1;
65         (void) move (line - 1, 0);
66         vsprintf(junkbuf, fmt, varglist);
67         (void) addstr (junkbuf);
68         (void) clrtoeol();
69 }
70
71 void
72 topmsg(int line, char *fmt, ...)
73 {
74         va_list ap;
75
76         va_start(ap, fmt);
77         vtopmsg(line, fmt, ap);
78         va_end(ap);
79 }
80
81 void
82 topmsg1(int line, char *fmt, ...)
83 {
84         va_list ap;
85
86         va_start(ap, fmt);
87         vtopmsg(line, fmt, ap);
88         va_end(ap);
89 }
90
91 void
92 topmsg2(int line, char *fmt, ...) 
93 {
94         va_list ap;
95
96         va_start(ap, fmt);
97         vtopmsg(line, fmt, ap);
98         va_end(ap);
99 }
100
101 /*
102 Print a prompt on the first message line.
103 */
104
105 void
106 prompt(char *fmt, ...)
107 {
108         va_list ap;
109
110         va_start(ap, fmt);
111         vtopmsg(1, fmt, ap);
112         va_end(ap);
113 }
114
115 void
116 prompt1(char *fmt, ...)
117 {
118         va_list ap;
119
120         va_start(ap, fmt);
121         vtopmsg(1, fmt, ap);
122         va_end(ap);
123 }
124
125 void
126 prompt2 (char *fmt, ...)
127 {
128         va_list ap;
129
130         va_start(ap, fmt);
131         vtopmsg(1, fmt, ap);
132         va_end(ap);
133 }
134
135 /*
136 Print an error message on the second message line.
137 */
138
139 void
140 error(char *fmt, ...)
141 {
142         va_list ap;
143
144         va_start(ap, fmt);
145         vtopmsg(2, fmt, ap);
146         va_end(ap);
147 }
148
149 /*
150 Print out extra information.
151 */
152
153 void
154 extra(char *fmt, ...)
155 {
156         va_list ap;
157
158         va_start(ap, fmt);
159         vtopmsg(3, fmt, ap);
160         va_end(ap);
161 }
162
163
164 /*
165 Print out a generic error message.
166 */
167
168 void
169 huh(void)
170 {
171         error ("Type H for Help.");
172 }
173
174 /*
175 Display information on the screen.  If the 'need_delay' flag is set,
176 we force a delay, then print the information.  After we print the
177 information, we set the need_delay flag.
178 */
179
180 void
181 info(char *a, char *b, char *c)
182 {
183         if (need_delay) delay ();
184         topmsg (1, a);
185         topmsg (2, b);
186         topmsg (3, c);
187         need_delay = (a || b || c);
188 }
189
190 void
191 set_need_delay(void) {
192         need_delay = 1;
193 }
194
195 void
196 comment (char *fmt, ...)
197 {
198         va_list ap;
199
200         va_start(ap, fmt);
201         if (need_delay) delay ();
202         topmsg (1, "");
203         topmsg (2, "");
204         vtopmsg (3, fmt, ap);
205         need_delay = (fmt != 0);
206         va_end(ap);
207 }
208         
209 void
210 comment1 (char *fmt, ...)
211 {
212         va_list ap;
213
214         va_start(ap, fmt);
215         if (need_delay) delay ();
216         topmsg (1, "");
217         topmsg (2, "");
218         vtopmsg (3, fmt, ap);
219         need_delay = (fmt != 0);
220         va_end(ap);
221 }
222         
223         
224 void
225 pdebug(char *fmt, ...)
226 {
227         va_list ap;
228
229         if (!print_debug) return;
230
231         va_start(ap, fmt);
232         if (need_delay) delay ();
233         topmsg (1, "");
234         topmsg (2, "");
235         vtopmsg (3, fmt, ap);
236         need_delay = (fmt != 0);
237         va_end(ap);
238 }
239
240 /* kermyt begin */
241
242 void
243 vksend(const char *fmt, va_list varglist)
244 {
245         if(!(my_stream=fopen("info_list.txt","a")))
246         {
247                 error("Cannot open info_list.txt");
248                 return;
249         }
250         vfprintf(my_stream, fmt, varglist);
251         fclose(my_stream);
252         return;
253 }
254
255 void
256 ksend(char *fmt, ...)
257 {
258         va_list ap;
259
260         va_start(ap, fmt);
261         vksend(fmt, ap);
262         va_end(ap);
263 }
264
265 void
266 ksend1(char *fmt, ...)
267 {
268         va_list ap;
269
270         va_start(ap, fmt);
271         vksend(fmt, ap);
272         va_end(ap);
273 }
274 /* kermyt end */
275
276 /*
277 Get a string from the user, echoing characters all the while.
278 */
279
280 void
281 get_str(char *buf, int sizep)
282 {
283         (void) echo();
284         get_strq(buf, sizep);
285         (void) noecho();
286 }
287
288 /*
289 Get a string from the user, ignoring the current echo mode.
290 */
291
292 void
293 get_strq(char *buf, int sizep)
294 {
295         sizep = sizep; /* size of buf, currently unused */
296
297         (void) nocrmode ();
298         (void) refresh ();
299         (void) getstr (buf);
300         need_delay = false;
301         info (0, 0, 0);
302         (void) crmode ();
303 }
304
305 /*
306 Get a character from the user and convert it to uppercase.
307 */
308
309 char
310 get_chx(void)
311 {
312         char c;
313
314         c = get_cq ();
315
316         if (islower(c))
317                 return (toupper(c));
318         else
319                 return (c);
320 }
321
322 /*
323 Input an integer from the user.
324 */
325
326 int
327 getint(char *message)
328 {
329         char buf[STRSIZE];
330         char *p;
331
332         for (;;) { /* until we get a legal number */
333                 prompt (message,0,0,0,0,0,0,0,0);
334                 get_str (buf, sizeof (buf));
335                 
336                 for (p = buf; *p; p++) {
337                         if (*p < '0' || *p > '9') {
338                                 error ("Please enter an integer.",0,0,0,0,0,0,0,0);
339                                 break;
340                         }
341                 }
342                 if (*p == 0) { /* no error yet? */
343                         if (p - buf > 7) /* too many digits? */
344                                 error ("Please enter a small integer.",0,0,0,0,0,0,0,0);
345                         else return (atoi (buf));
346                 }
347         }
348 }
349
350 /*
351 Input a character from the user with echoing.
352 */
353
354 char
355 get_c(void)
356 {
357         char c; /* one char and a null */
358
359         (void) echo ();
360         c = get_cq ();
361         (void) noecho ();
362         return (c);
363 }
364
365 /*
366 Input a character quietly.
367 */
368
369 char
370 get_cq(void)
371 {
372         char c;
373
374         (void) crmode ();
375         (void) refresh ();
376         c = getch ();
377         topini (); /* clear information lines */
378         (void) nocrmode ();
379         return (c);
380 }
381
382 /*
383 Input a yes or no response from the user.  We loop until we get
384 a valid response.  We return true iff the user replies 'y'.
385 */
386
387 bool
388 getyn(char *message)
389 {
390         char c;
391
392         for (;;) {
393                 prompt (message,0,0,0,0,0,0,0,0);
394                 c = get_chx ();
395
396                 if (c == 'Y') return (true);
397                 if (c == 'N') return (false);
398
399                 error ("Please answer Y or N.",0,0,0,0,0,0,0,0);
400         }
401 }
402
403 /*
404 Input an integer in a range.
405 */
406
407 int
408 get_range(char *message, int low, int high)
409 {
410         int result;
411
412         for (;;) {
413                 result = getint (message);
414
415                 if (result >= low && result <= high) return (result);
416
417                 error ("Please enter an integer in the range %d..%d.",low, high,0,0,0,0,0,0);
418         }
419 }
420
421 /*
422 Print a screen of help information.
423 */
424
425 void
426 help(char **text, int nlines)
427 {
428         int i, r, c;
429         int text_lines;
430
431         text_lines = (nlines + 1) / 2; /* lines of text */
432
433         clear_screen ();
434
435         pos_str (NUMTOPS, 1, text[0],0,0,0,0,0,0,0,0); /* mode */
436         pos_str (NUMTOPS, 41, "See empire(6) for more information.",0,0,0,0,0,0,0,0);
437
438         for (i = 1; i < nlines; i++) {
439                 if (i > text_lines)
440                         pos_str (i - text_lines + NUMTOPS + 1, 41, text[i],0,0,0,0,0,0,0,0);
441                 else pos_str (i + NUMTOPS + 1, 1, text[i],0,0,0,0,0,0,0,0);
442         }
443
444         pos_str (text_lines + NUMTOPS + 2,  1, "--Piece---Yours-Enemy-Moves-Hits-Cost",0,0,0,0,0,0,0,0);
445         pos_str (text_lines + NUMTOPS + 2, 41, "--Piece---Yours-Enemy-Moves-Hits-Cost",0,0,0,0,0,0,0,0);
446
447         for (i = 0; i < NUM_OBJECTS; i++) {
448                 if (i >= (NUM_OBJECTS+1)/2) {
449                         r = i - (NUM_OBJECTS+1)/2;
450                         c = 41;
451                 }
452                 else {
453                         r = i;
454                         c = 1;
455                 }
456                 pos_str1 (r + text_lines + NUMTOPS + 3, c,"%-12s%c     %c%6d%5d%6d",
457                         piece_attr[i].nickname,
458                         piece_attr[i].sname,
459                         tolower (piece_attr[i].sname),
460                         piece_attr[i].speed,
461                         piece_attr[i].max_hits,
462                         piece_attr[i].build_time,0,0);          //FLAG
463
464         }
465         (void) refresh ();
466 }
467
468 #define COL_DIGITS ((MAP_WIDTH <= 100) ? 2 : ((MAP_WIDTH <= 1000 ? 3 : (1 / 0))))
469
470 int
471 loc_disp(int loc)
472 {
473   int row = loc / MAP_WIDTH;
474   int nrow = row;
475   int col = loc % MAP_WIDTH;
476   ASSERT (loc == (row * MAP_WIDTH) + col);
477   int i;
478   for (i = COL_DIGITS; i > 0; i--) {
479     nrow *= 10; }
480   move (LINES - 1, 0);
481   return nrow + col;
482 }