ANSIfy the code by making void prototype declarations explicit.
[vms-empire.git] / display.c
1 /* $Id: display.c,v 1.12 2006/07/25 16:58:26 esr Exp esr $  - (c) Copyright 1987, 1988 Chuck Simmons */
2
3 /*
4  *    Copyright (C) 1987, 1988 Chuck Simmons
5  * 
6  * See the file COPYING, distributed with empire, for restriction
7  * and warranty information.
8  */
9
10 /*
11 display.c -- This file contains routines for displaying sectors and
12 moving the cursor about in a sector.  We need to remember the following
13 information:
14
15         the current map portion displayed on the screen;
16
17         whether the displayed portion is from the user's or the computer's
18         point of view;
19 */
20
21 #include <string.h>
22 #include <curses.h>
23 #include "empire.h"
24 #include "extern.h"
25
26 static int whose_map = UNOWNED; /* user's or computer's point of view */
27 static int ref_row; /* map loc displayed in upper-left corner */
28 static int ref_col;
29 static int save_sector; /* the currently displayed sector */
30 static int save_cursor; /* currently displayed cursor position */
31 static int change_ok = TRUE; /* true if new sector may be displayed */
32
33 static void show_loc(view_map_t vmap[],long loc);
34 static void disp_square(view_map_t *vp);
35 int on_screen(long loc);
36
37 #ifdef A_COLOR
38 void init_colors(void)
39 {
40     start_color();
41
42     init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK);
43     init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
44     init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
45     init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
46     init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
47     init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
48     init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
49     init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
50 }
51 #endif /* A_COLOR */
52
53 /*
54 Used for win announcements 
55  */
56 void announce (char *msg) {
57     (void) addstr (msg);
58 }
59
60 /*
61 This routine is called when the current display has been
62 trashed and no sector is shown on the screen.
63 */
64
65 void kill_display (void) {
66         whose_map = UNOWNED;
67 }
68
69 /*
70 This routine is called when a new sector may be displayed on the
71 screen even if the location to be displayed is already on the screen.
72 */
73
74 void sector_change (void) {
75         change_ok = TRUE;
76 }
77
78 /*
79 Return the currently displayed user sector, if any.  If a user
80 sector is not displayed, return -1.
81 */
82
83 int cur_sector (void) {
84         if (whose_map != USER) return (-1);
85         return (save_sector);
86 }
87
88 /*
89 Return the current position of the cursor.  If the user's map
90 is not on the screen, we return -1.
91 */
92
93 long cur_cursor (void) {
94         if (whose_map != USER) return (-1);
95         return (save_cursor);
96 }
97
98 /*
99 Display a location on the screen. We figure out the sector the
100 location is in and display that sector.  The cursor is left at
101 the requested location.
102
103 We redisplay the sector only if we either have been requested to
104 redisplay the sector, or if the location is not on the screen.
105 */
106
107 void
108 display_loc (whose, vmap, loc)
109 int whose; /* whose map to display */
110 view_map_t vmap[];
111 long loc; /* location to display */
112 {
113         if (change_ok || whose != whose_map || !on_screen (loc))
114                 print_sector (whose, vmap, loc_sector (loc));
115                 
116         show_loc (vmap, loc);
117 }
118
119 /*
120 Display a location iff the location is on the screen.
121 */
122
123 void
124 display_locx (whose, vmap, loc)
125 int whose; /* whose map to display */
126 view_map_t vmap[];
127 long loc; /* location to display */
128 {
129         if (whose == whose_map && on_screen (loc))
130                 show_loc (vmap, loc);
131 }
132
133 /*
134 Display a location which exists on the screen.
135 */
136
137 void
138 show_loc (vmap, loc)
139 view_map_t vmap[];
140 long loc;
141 {
142         int r, c;
143         
144         r = loc_row (loc);
145         c = loc_col (loc);
146         (void) move (r-ref_row+NUMTOPS, c-ref_col);
147         disp_square(&vmap[loc]);
148         save_cursor = loc; /* remember cursor location */
149         (void) move (r-ref_row+NUMTOPS, c-ref_col);
150 }
151
152 /*
153 Print a sector of the user's on the screen.  If it is already displayed,
154 we do nothing.  Otherwise we redraw the screen.  Someday, some intelligence
155 in doing this might be interesting.  We heavily depend on curses to update
156 the screen in a reasonable fashion.
157
158 If the desired sector
159 is not displayed, we clear the screen.  We then update the screen
160 to reflect the current map.  We heavily depend on curses to correctly
161 optimize the redrawing of the screen.
162
163 When redrawing the screen, we figure out where the
164 center of the sector is in relation to the map.  We then compute
165 the screen coordinates where we want to display the center of the
166 sector.  We will remember the sector displayed, the map displayed,
167 and the map location that appears in the upper-left corner of the
168 screen.
169 */
170  
171 void
172 print_sector (whose, vmap, sector)
173 char whose; /* USER or COMP */
174 view_map_t vmap[]; /* map to display */
175 int sector; /* sector to display */
176 {
177         void display_screen();
178
179         int first_row, first_col, last_row, last_col;
180         int display_rows, display_cols;
181         int r, c;
182
183         save_sector = sector; /* remember last sector displayed */
184         change_ok = FALSE; /* we are displaying a new sector */
185
186         display_rows = lines - NUMTOPS - 1; /* num lines to display */
187         display_cols = cols - NUMSIDES;
188
189         /* compute row and column edges of sector */
190         first_row = sector_row (sector) * ROWS_PER_SECTOR;
191         first_col = sector_col (sector) * COLS_PER_SECTOR;
192         last_row = first_row + ROWS_PER_SECTOR - 1;
193         last_col = first_col + COLS_PER_SECTOR - 1;
194
195         if (!(whose == whose_map /* correct map is on screen? */
196            && ref_row <= first_row /* top row on screen? */
197            && ref_col <= first_col /* first col on screen? */
198            && ref_row + display_rows - 1 >= last_row /* bot row on screen? */
199            && ref_col + display_cols - 1 >= last_col)) /* last col on screen? */
200         (void) clear (); /* erase current screen */
201
202         /* figure out first row and col to print; subtract half
203            the extra lines from the first line */
204
205         ref_row = first_row - (display_rows - ROWS_PER_SECTOR) / 2;
206         ref_col = first_col - (display_cols - COLS_PER_SECTOR) / 2;
207
208         /* try not to go past bottom of map */
209         if (ref_row + display_rows - 1 > MAP_HEIGHT - 1)
210                 ref_row = MAP_HEIGHT - 1 - (display_rows - 1);
211
212         /* never go past top of map */
213         if (ref_row < 0) ref_row = 0;
214
215         /* same with columns */
216         if (ref_col + display_cols - 1 > MAP_WIDTH - 1)
217                 ref_col = MAP_WIDTH - 1 - (display_cols - 1);
218
219         if (ref_col < 0) ref_col = 0;
220
221         whose_map = whose; /* remember whose map is displayed */
222         display_screen (vmap);
223
224         /* print x-coordinates along bottom of screen */
225         for (c = ref_col; c < ref_col + display_cols && c < MAP_WIDTH; c++)
226         if (c % 10 == 0) {
227                 pos_str (lines-1, c-ref_col, "%d", c,0,0,0,0,0,0,0);
228         }
229         /* print y-coordinates along right of screen */
230         for (r = ref_row; r < ref_row + display_rows && r < MAP_HEIGHT; r++) {
231                 if (r % 2 == 0)
232                         pos_str (r-ref_row+NUMTOPS, cols-NUMSIDES+1, "%2d", r,0,0,0,0,0,0,0);
233                 else pos_str (r-ref_row+NUMTOPS, cols-NUMSIDES+1, "  ",0,0,0,0,0,0,0,0);
234         }
235         /* print round number */
236         (void) sprintf (jnkbuf, "Sector %d Round %ld", sector, date);
237         for (r = 0; jnkbuf[r] != '\0'; r++) {
238                 if (r+NUMTOPS >= MAP_HEIGHT) break;
239                 (void) move (r+NUMTOPS, cols-NUMSIDES+4);
240                 (void) addch ((chtype)jnkbuf[r]);
241         }
242 }
243
244 /*
245 Display the contents of a single map square.
246
247 Fancy color hacks are done here. At the moment this is kind of bogus,
248 because the color doesn't convey any extra information, it just looks
249 pretty.
250 */
251
252
253 static void disp_square(vp)
254 view_map_t *vp;
255 {
256 #ifdef A_COLOR
257         switch(vp->contents)
258         {
259         case '+':
260                 attron(COLOR_PAIR(COLOR_GREEN));
261                 break;
262         case '.':
263                 attron(COLOR_PAIR(COLOR_CYAN));
264                 break;
265         case 'a':
266         case 'f':
267         case 'p':
268         case 'd':
269         case 'b':
270         case 't':
271         case 'c':
272         case 's':
273         case 'z':
274         case 'X':
275                 attron(COLOR_PAIR(COLOR_RED));
276                 break;
277         default:
278                 attron(COLOR_PAIR(COLOR_WHITE));
279                 break;
280         }
281 #endif /* A_COLOR */
282         (void) addch ((chtype)vp->contents);
283 #ifdef A_COLOR
284         attrset(0);
285         attron(COLOR_PAIR(COLOR_WHITE));
286 #endif /* A_COLOR */
287 }
288
289
290 /*
291 Display the portion of the map that appears on the screen.
292 */
293
294 void display_screen (vmap)
295 view_map_t vmap[];
296 {
297         int display_rows, display_cols;
298         int r, c;
299         long t;
300
301         display_rows = lines - NUMTOPS - 1; /* num lines to display */
302         display_cols = cols - NUMSIDES;
303
304         for (r = ref_row; r < ref_row + display_rows && r < MAP_HEIGHT; r++)
305         for (c = ref_col; c < ref_col + display_cols && c < MAP_WIDTH; c++) {
306                 t = row_col_loc (r, c);
307                 (void) move (r-ref_row+NUMTOPS, c-ref_col);
308                 disp_square(&vmap[t]);
309         }
310 }
311
312 /*
313 Move the cursor in a specified direction.  We return TRUE if the
314 cursor remains in the currently displayed screen, otherwise FALSE.
315 We display the cursor on the screen, if possible.
316 */
317
318 int
319 move_cursor (cursor, offset)
320 long *cursor; /* current cursor position */
321 int offset; /* offset to add to cursor */
322 {
323         long t;
324         int r, c;
325  
326         t = *cursor + offset; /* proposed location */
327         if (!map[t].on_board) return (FALSE); /* trying to move off map */
328         if (!on_screen (t)) return (FALSE); /* loc is off screen */
329         
330         *cursor = t; /* update cursor position */
331         save_cursor = *cursor;
332                
333         r = loc_row (save_cursor);
334         c = loc_col (save_cursor);
335         (void) move (r-ref_row+NUMTOPS, c-ref_col);
336        
337         return (TRUE);
338 }
339
340 /*
341 See if a location is displayed on the screen.
342 */
343
344 int on_screen (loc)
345 long loc;
346 {
347         int new_r, new_c;
348         
349         new_r = loc_row (loc);
350         new_c = loc_col (loc);
351
352         if (new_r < ref_row /* past top of screen */
353          || new_r - ref_row > lines - NUMTOPS - 1 /* past bot of screen? */
354          || new_c < ref_col /* past left edge of screen? */
355          || new_c - ref_col > cols - NUMSIDES) /* past right edge of screen? */
356         return (FALSE);
357
358         return (TRUE);
359 }
360
361 /* Print a view map for debugging. */
362
363 void
364 print_xzoom (vmap)
365 view_map_t *vmap;
366 {
367         print_zoom (vmap);
368 #if 0
369         prompt ("Hit a key: ",0,0,0,0,0,0,0,0);
370         (void) get_chx (); /* wait for user */
371 #endif
372 }
373
374 /*
375 Print a condensed version of the map.
376 */
377
378 char zoom_list[] = "XO*tcbsdpfaTCBSDPFAzZ+. ";
379
380 void
381 print_zoom (vmap)
382 view_map_t *vmap;
383 {
384         void print_zoom_cell ();
385
386         int row_inc, col_inc;
387         int r, c;
388
389         kill_display ();
390
391         row_inc = (MAP_HEIGHT + lines - NUMTOPS - 1) / (lines - NUMTOPS);
392         col_inc = (MAP_WIDTH + cols - 1) / (cols - 1);
393
394         for (r = 0; r < MAP_HEIGHT; r += row_inc)
395         for (c = 0; c < MAP_WIDTH; c += col_inc)
396         print_zoom_cell (vmap, r, c, row_inc, col_inc);
397
398         pos_str (0, 0, "Round #%d", date,0,0,0,0,0,0,0);
399         
400         (void) refresh ();
401 }
402
403 /*
404 Print a single cell in condensed format.
405 */
406
407 void
408 print_zoom_cell (vmap, row, col, row_inc, col_inc)
409 view_map_t *vmap;
410 int row, col;
411 int row_inc, col_inc;
412 {
413         int r, c;
414         char cell;
415
416         cell = ' ';
417         for (r = row; r < row + row_inc; r++)
418         for (c = col; c < col + col_inc; c++)
419         if (strchr (zoom_list, vmap[row_col_loc(r,c)].contents)
420                 < strchr (zoom_list, cell))
421         cell = vmap[row_col_loc(r,c)].contents;
422         
423         (void) move (row/row_inc + NUMTOPS, col/col_inc);
424         (void) addch ((chtype)cell);
425 }
426
427 /*
428 Print a condensed version of a pathmap.
429 */
430
431 void
432 print_pzoom (s, pmap, vmap)
433 char *s;
434 path_map_t *pmap;
435 view_map_t *vmap;
436 {
437         void print_pzoom_cell();
438
439         int row_inc, col_inc;
440         int r, c;
441
442         kill_display ();
443
444         row_inc = (MAP_HEIGHT + lines - NUMTOPS - 1) / (lines - NUMTOPS);
445         col_inc = (MAP_WIDTH + cols - 1) / (cols - 1);
446
447         for (r = 0; r < MAP_HEIGHT; r += row_inc)
448         for (c = 0; c < MAP_WIDTH; c += col_inc)
449         print_pzoom_cell (pmap, vmap, r, c, row_inc, col_inc);
450
451         prompt (s,0,0,0,0,0,0,0,0);
452         (void) get_chx (); /* wait for user */
453         
454         (void) refresh ();
455 }
456
457 /*
458 Print a single cell of a pathmap in condensed format.
459 We average all squares in the cell and take the mod 10 value.
460 Squares with a value of -1 are printed with '-', squares with
461 a value of INFINITY/2 are printed with 'P', and squares with
462 a value of INFINITY are printed with 'Z'.  Squares with a value
463 between P and Z are printed as U.
464 */
465
466 void
467 print_pzoom_cell (pmap, vmap, row, col, row_inc, col_inc)
468 path_map_t *pmap;
469 view_map_t *vmap;
470 int row, col;
471 int row_inc, col_inc;
472 {
473         int r, c;
474         int sum, d;
475         char cell;
476
477         sum = 0;
478         d = 0; /* number of squares in cell */
479         
480         for (r = row; r < row + row_inc; r++)
481         for (c = col; c < col + col_inc; c++) {
482                 sum += pmap[row_col_loc(r,c)].cost;
483                 d += 1;
484         }
485         sum /= d;
486         
487         if (pmap[row_col_loc(row,col)].terrain == T_PATH) cell = '-';
488         else if (sum < 0) cell = '!';
489         else if (sum == INFINITY/2) cell = 'P';
490         else if (sum == INFINITY) cell = ' ';
491         else if (sum > INFINITY/2) cell = 'U';
492         else {
493                 sum %= 36;
494                 if (sum < 10) cell = sum + '0';
495                 else cell = sum - 10 + 'a';
496         }
497         
498         if (cell == ' ')
499                 print_zoom_cell (vmap, row, col, row_inc, col_inc);
500         else {
501                 (void) move (row/row_inc + NUMTOPS, col/col_inc);
502                 (void) addch ((chtype)cell);
503         }
504 }
505
506 /*
507 Display the score off in the corner of the screen.
508 */
509
510 void
511 display_score (void)
512 {
513         pos_str (1, cols-12, " User  Comp",0,0,0,0,0,0,0,0);
514         pos_str (2, cols-12, "%5d %5d", user_score, comp_score,0,0,0,0,0,0);
515 }
516
517 /*
518 Clear the end of a specified line starting at the specified column.
519 */
520
521 void
522 clreol(linep, colp)
523 int linep, colp;
524 {
525         (void) move (linep, colp);
526         (void) clrtoeol();
527 }
528
529 /*
530 Initialize the terminal.
531 */
532
533 void
534 ttinit(void)
535 {
536         (void) initscr();
537         (void) noecho();
538         (void) crmode();
539 #ifdef A_COLOR
540         init_colors();
541 #endif /* A_COLOR */
542         lines = LINES;
543         cols = COLS;
544         if (lines > MAP_HEIGHT + NUMTOPS + 1)
545                 lines = MAP_HEIGHT + NUMTOPS + 1;
546         if (cols > MAP_WIDTH + NUMSIDES)
547                 cols = MAP_WIDTH + NUMSIDES;
548 }
549
550
551 /*
552 Clear the screen.  We must also kill information maintained about the
553 display.
554 */
555
556 void
557 clear_screen (void) {
558         (void) clear ();
559         (void) refresh ();
560         kill_display ();
561 }
562
563 /*
564 Redraw the screen.
565 */
566
567 void 
568 redisplay (void) {
569         (void) refresh ();
570 }
571
572 void
573 redraw (void) {
574         (void) clearok (curscr, TRUE);
575         (void) refresh ();
576 }
577
578 /*
579 Wait a little bit to give user a chance to see a message.  We refresh
580 the screen and pause for a few milliseconds.
581 */
582
583 void
584 delay (void) {
585         int t = delay_time;
586         int i = 500;
587         (void) refresh ();
588         if (t > i) {
589           (void) move (LINES - 1, 0);
590         }
591         for (; t > 0; t -= i) {
592           (void) napms ((t > i) ? i : t); /* pause a bit */
593           if (t > i) {
594             addstr ("*");
595             refresh (); 
596           }
597         }
598 }
599
600 /*
601 Clean up the display.  This routine gets called as we leave the game.
602 */
603
604 void
605 close_disp(void)
606 {
607         (void) move (LINES - 1, 0);
608         (void) clrtoeol ();
609         (void) refresh ();
610         (void) endwin ();
611 }
612
613 /*
614 Position the cursor and output a string.
615 */
616
617 void
618 pos_str1 (row, col, str, a, b, c, d, e, f, g, h)
619 int row, col;
620 char *str, *a;
621 int b, c, d, e, f, g, h;
622 {
623         (void) move (row, col);
624         addprintf1 (str, a, b, c, d, e, f, g, h);
625 }
626 void
627 pos_str (row, col, str, a, b, c, d, e, f, g, h)
628 int row, col;
629 char *str;
630 int a, b, c, d, e, f, g, h;
631 {
632         (void) move (row, col);
633         addprintf (str, a, b, c, d, e, f, g, h);
634 }
635
636 void
637 /* VARARGS1 */
638 addprintf (str, a, b, c, d, e, f, g, h)
639 char *str;
640 int a, b, c, d, e, f, g, h;
641 {
642         char junkbuf[STRSIZE];
643         
644         (void) sprintf (junkbuf, str, a, b, c, d, e, f, g, h);
645         (void) addstr (junkbuf);
646 }
647 void
648 /* VARARGS1 */
649 addprintf1 (str, a, b, c, d, e, f, g, h)
650 char *str;
651 char *a;
652 int b, c, d, e, f, g, h;
653 {
654         char junkbuf[STRSIZE];
655         
656         (void) sprintf (junkbuf, str, a, b, c, d, e, f, g, h);
657         (void) addstr (junkbuf);
658 }
659 void
660 /* VARARGS1 */
661 addprintf2 (str, a, b, c, d, e, f, g, h)
662 char *str;
663 char *a, *e, *f;
664 int b, c, d, g, h;
665 {
666         char junkbuf[STRSIZE];
667         
668         (void) sprintf (junkbuf, str, a, b, c, d, e, f, g, h);
669         (void) addstr (junkbuf);
670 }
671
672 /*
673 Print a single cell in condensed format.
674 */
675
676 extern char zoom_list[];
677
678 void
679 print_movie_cell (mbuf, row, col, row_inc, col_inc)
680 char *mbuf;
681 int row, col;
682 int row_inc, col_inc;
683 {
684         int r, c;
685         char cell;
686
687         cell = ' ';
688         for (r = row; r < row + row_inc; r++)
689         for (c = col; c < col + col_inc; c++)
690         if (strchr (zoom_list, mbuf[row_col_loc(r,c)])
691                 < strchr (zoom_list, cell))
692         cell = mbuf[row_col_loc(r,c)];
693         
694         (void) move (row/row_inc + NUMTOPS, col/col_inc);
695         (void) addch ((chtype)cell);
696 }