Sea color to cyan.
[vms-empire.git] / display.c
1 /* $Id$  - (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 #ifdef SYSV
22 #include <string.h>
23 #else
24 #include <strings.h>
25 #endif
26
27 #include <curses.h>
28 #include "empire.h"
29 #include "extern.h"
30
31 static int whose_map = UNOWNED; /* user's or computer's point of view */
32 static int ref_row; /* map loc displayed in upper-left corner */
33 static int ref_col;
34 static int save_sector; /* the currently displayed sector */
35 static int save_cursor; /* currently displayed cursor position */
36 static int change_ok = TRUE; /* true if new sector may be displayed */
37
38 #ifdef A_COLOR
39 void init_colors()
40 {
41     start_color();
42
43     init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK);
44     init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
45     init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
46     init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
47     init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
48     init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
49     init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
50     init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
51 }
52 #endif /* A_COLOR */
53
54 /*
55 This routine is called when the current display has been
56 trashed and no sector is shown on the screen.
57 */
58
59 void kill_display () {
60         whose_map = UNOWNED;
61 }
62
63 /*
64 This routine is called when a new sector may be displayed on the
65 screen even if the location to be displayed is already on the screen.
66 */
67
68 void sector_change () {
69         change_ok = TRUE;
70 }
71
72 /*
73 Return the currently displayed user sector, if any.  If a user
74 sector is not displayed, return -1.
75 */
76
77 int cur_sector () {
78         if (whose_map != USER) return (-1);
79         return (save_sector);
80 }
81
82 /*
83 Return the current position of the cursor.  If the user's map
84 is not on the screen, we return -1.
85 */
86
87 long cur_cursor () {
88         if (whose_map != USER) return (-1);
89         return (save_cursor);
90 }
91
92 /*
93 Display a location on the screen. We figure out the sector the
94 location is in and display that sector.  The cursor is left at
95 the requested location.
96
97 We redisplay the sector only if we either have been requested to
98 redisplay the sector, or if the location is not on the screen.
99 */
100
101 void
102 display_loc (whose, vmap, loc)
103 int whose; /* whose map to display */
104 view_map_t vmap[];
105 long loc; /* location to display */
106 {
107         void print_sector(), show_loc();
108         
109         if (change_ok || whose != whose_map || !on_screen (loc))
110                 print_sector (whose, vmap, loc_sector (loc));
111                 
112         show_loc (vmap, loc);
113 }
114
115 /*
116 Display a location iff the location is on the screen.
117 */
118
119 void
120 display_locx (whose, vmap, loc)
121 int whose; /* whose map to display */
122 view_map_t vmap[];
123 long loc; /* location to display */
124 {
125         if (whose == whose_map && on_screen (loc))
126                 show_loc (vmap, loc);
127 }
128
129 /*
130 Display a location which exists on the screen.
131 */
132
133 void
134 show_loc (vmap, loc)
135 view_map_t vmap[];
136 long loc;
137 {
138         int r, c;
139         
140         r = loc_row (loc);
141         c = loc_col (loc);
142         (void) move (r-ref_row+NUMTOPS, c-ref_col);
143         disp_square(&vmap[loc]);
144         save_cursor = loc; /* remember cursor location */
145         (void) move (r-ref_row+NUMTOPS, c-ref_col);
146 }
147
148 /*
149 Print a sector of the user's on the screen.  If it is already displayed,
150 we do nothing.  Otherwise we redraw the screen.  Someday, some intelligence
151 in doing this might be interesting.  We heavily depend on curses to update
152 the screen in a reasonable fashion.
153
154 If the desired sector
155 is not displayed, we clear the screen.  We then update the screen
156 to reflect the current map.  We heavily depend on curses to correctly
157 optimize the redrawing of the screen.
158
159 When redrawing the screen, we figure out where the
160 center of the sector is in relation to the map.  We then compute
161 the screen coordinates where we want to display the center of the
162 sector.  We will remember the sector displayed, the map displayed,
163 and the map location that appears in the upper-left corner of the
164 screen.
165 */
166  
167 void
168 print_sector (whose, vmap, sector)
169 char whose; /* USER or COMP */
170 view_map_t vmap[]; /* map to display */
171 int sector; /* sector to display */
172 {
173         void display_screen();
174
175         int first_row, first_col, last_row, last_col;
176         int display_rows, display_cols;
177         int r, c;
178
179         save_sector = sector; /* remember last sector displayed */
180         change_ok = FALSE; /* we are displaying a new sector */
181
182         display_rows = lines - NUMTOPS - 1; /* num lines to display */
183         display_cols = cols - NUMSIDES;
184
185         /* compute row and column edges of sector */
186         first_row = sector_row (sector) * ROWS_PER_SECTOR;
187         first_col = sector_col (sector) * COLS_PER_SECTOR;
188         last_row = first_row + ROWS_PER_SECTOR - 1;
189         last_col = first_col + COLS_PER_SECTOR - 1;
190
191         if (!(whose == whose_map /* correct map is on screen? */
192            && ref_row <= first_row /* top row on screen? */
193            && ref_col <= first_col /* first col on screen? */
194            && ref_row + display_rows - 1 >= last_row /* bot row on screen? */
195            && ref_col + display_cols - 1 >= last_col)) /* last col on screen? */
196         (void) clear (); /* erase current screen */
197
198         /* figure out first row and col to print; subtract half
199            the extra lines from the first line */
200
201         ref_row = first_row - (display_rows - ROWS_PER_SECTOR) / 2;
202         ref_col = first_col - (display_cols - COLS_PER_SECTOR) / 2;
203
204         /* try not to go past bottom of map */
205         if (ref_row + display_rows - 1 > MAP_HEIGHT - 1)
206                 ref_row = MAP_HEIGHT - 1 - (display_rows - 1);
207
208         /* never go past top of map */
209         if (ref_row < 0) ref_row = 0;
210
211         /* same with columns */
212         if (ref_col + display_cols - 1 > MAP_WIDTH - 1)
213                 ref_col = MAP_WIDTH - 1 - (display_cols - 1);
214
215         if (ref_col < 0) ref_col = 0;
216
217         whose_map = whose; /* remember whose map is displayed */
218         display_screen (vmap);
219
220         /* print x-coordinates along bottom of screen */
221         for (c = ref_col; c < ref_col + display_cols && c < MAP_WIDTH; c++)
222         if (c % 10 == 0) {
223                 pos_str (lines-1, c-ref_col, "%d", c);
224         }
225         /* print y-coordinates along right of screen */
226         for (r = ref_row; r < ref_row + display_rows && r < MAP_HEIGHT; r++) {
227                 if (r % 2 == 0)
228                         pos_str (r-ref_row+NUMTOPS, cols-NUMSIDES+1, "%2d", r);
229                 else pos_str (r-ref_row+NUMTOPS, cols-NUMSIDES+1, "  ");
230         }
231         /* print round number */
232         (void) sprintf (jnkbuf, "Sector %d Round %d", sector, date);
233         for (r = 0; jnkbuf[r] != '\0'; r++) {
234                 if (r+NUMTOPS >= MAP_HEIGHT) break;
235                 (void) move (r+NUMTOPS, cols-NUMSIDES+4);
236                 (void) addch ((chtype)jnkbuf[r]);
237         }
238 }
239
240 /*
241 Display the contents of a single map square.
242
243 Fancy color hacks are done here. At the moment this is kind of bogus,
244 because the color doesn't convey any extra information, it just looks
245 pretty.
246 */
247
248
249 static disp_square(vp)
250 view_map_t *vp;
251 {
252 #ifdef A_COLOR
253         switch(vp->contents)
254         {
255         case '+':
256                 attron(COLOR_PAIR(COLOR_GREEN));
257                 break;
258         case '.':
259                 attron(COLOR_PAIR(COLOR_CYAN));
260                 break;
261         case 'a':
262         case 'f':
263         case 'p':
264         case 'd':
265         case 'b':
266         case 't':
267         case 'c':
268         case 's':
269         case 'z':
270         case 'X':
271                 attron(COLOR_PAIR(COLOR_RED));
272                 break;
273         default:
274                 attron(COLOR_PAIR(COLOR_WHITE));
275                 break;
276         }
277 #endif /* A_COLOR */
278         (void) addch ((chtype)vp->contents);
279 #ifdef A_COLOR
280         attrset(0);
281         attron(COLOR_PAIR(COLOR_WHITE));
282 #endif /* A_COLOR */
283 }
284
285
286 /*
287 Display the portion of the map that appears on the screen.
288 */
289
290 void display_screen (vmap)
291 view_map_t vmap[];
292 {
293         int display_rows, display_cols;
294         int r, c;
295         long t;
296
297         display_rows = lines - NUMTOPS - 1; /* num lines to display */
298         display_cols = cols - NUMSIDES;
299
300         for (r = ref_row; r < ref_row + display_rows && r < MAP_HEIGHT; r++)
301         for (c = ref_col; c < ref_col + display_cols && c < MAP_WIDTH; c++) {
302                 t = row_col_loc (r, c);
303                 (void) move (r-ref_row+NUMTOPS, c-ref_col);
304                 disp_square(&vmap[t]);
305         }
306 }
307
308 /*
309 Move the cursor in a specified direction.  We return TRUE if the
310 cursor remains in the currently displayed screen, otherwise FALSE.
311 We display the cursor on the screen, if possible.
312 */
313
314 int
315 move_cursor (cursor, offset)
316 long *cursor; /* current cursor position */
317 int offset; /* offset to add to cursor */
318 {
319         long t;
320         int r, c;
321  
322         t = *cursor + offset; /* proposed location */
323         if (!map[t].on_board) return (FALSE); /* trying to move off map */
324         if (!on_screen (t)) return (FALSE); /* loc is off screen */
325         
326         *cursor = t; /* update cursor position */
327         save_cursor = *cursor;
328                
329         r = loc_row (save_cursor);
330         c = loc_col (save_cursor);
331         (void) move (r-ref_row+NUMTOPS, c-ref_col);
332        
333         return (TRUE);
334 }
335
336 /*
337 See if a location is displayed on the screen.
338 */
339
340 int on_screen (loc)
341 long loc;
342 {
343         int new_r, new_c;
344         
345         new_r = loc_row (loc);
346         new_c = loc_col (loc);
347
348         if (new_r < ref_row /* past top of screen */
349          || new_r - ref_row > lines - NUMTOPS - 1 /* past bot of screen? */
350          || new_c < ref_col /* past left edge of screen? */
351          || new_c - ref_col > cols - NUMSIDES) /* past right edge of screen? */
352         return (FALSE);
353
354         return (TRUE);
355 }
356
357 /* Print a view map for debugging. */
358
359 void
360 print_xzoom (vmap)
361 view_map_t *vmap;
362 {
363         print_zoom (vmap);
364 #if 0
365         prompt ("Hit a key: ");
366         (void) get_chx (); /* wait for user */
367 #endif
368 }
369
370 /*
371 Print a condensed version of the map.
372 */
373
374 char zoom_list[] = "XO*tcbsdpfaTCBSDPFAzZ+. ";
375
376 void
377 print_zoom (vmap)
378 view_map_t *vmap;
379 {
380         void print_zoom_cell();
381
382         int row_inc, col_inc;
383         int r, c;
384
385         kill_display ();
386
387         row_inc = (MAP_HEIGHT + lines - NUMTOPS - 1) / (lines - NUMTOPS);
388         col_inc = (MAP_WIDTH + cols - 1) / (cols - 1);
389
390         for (r = 0; r < MAP_HEIGHT; r += row_inc)
391         for (c = 0; c < MAP_WIDTH; c += col_inc)
392         print_zoom_cell (vmap, r, c, row_inc, col_inc);
393
394         pos_str (0, 0, "Round #%d", date);
395         
396         (void) refresh ();
397 }
398
399 /*
400 Print a single cell in condensed format.
401 */
402
403 void
404 print_zoom_cell (vmap, row, col, row_inc, col_inc)
405 view_map_t *vmap;
406 int row, col;
407 int row_inc, col_inc;
408 {
409         int r, c;
410         char cell;
411
412         cell = ' ';
413         for (r = row; r < row + row_inc; r++)
414         for (c = col; c < col + col_inc; c++)
415         if (strchr (zoom_list, vmap[row_col_loc(r,c)].contents)
416                 < strchr (zoom_list, cell))
417         cell = vmap[row_col_loc(r,c)].contents;
418         
419         (void) move (row/row_inc + NUMTOPS, col/col_inc);
420         (void) addch ((chtype)cell);
421 }
422
423 /*
424 Print a condensed version of a pathmap.
425 */
426
427 void
428 print_pzoom (s, pmap, vmap)
429 char *s;
430 path_map_t *pmap;
431 view_map_t *vmap;
432 {
433         void print_pzoom_cell();
434
435         int row_inc, col_inc;
436         int r, c;
437
438         kill_display ();
439
440         row_inc = (MAP_HEIGHT + lines - NUMTOPS - 1) / (lines - NUMTOPS);
441         col_inc = (MAP_WIDTH + cols - 1) / (cols - 1);
442
443         for (r = 0; r < MAP_HEIGHT; r += row_inc)
444         for (c = 0; c < MAP_WIDTH; c += col_inc)
445         print_pzoom_cell (pmap, vmap, r, c, row_inc, col_inc);
446
447         prompt (s);
448         (void) get_chx (); /* wait for user */
449         
450         (void) refresh ();
451 }
452
453 /*
454 Print a single cell of a pathmap in condensed format.
455 We average all squares in the cell and take the mod 10 value.
456 Squares with a value of -1 are printed with '-', squares with
457 a value of INFINITY/2 are printed with 'P', and squares with
458 a value of INFINITY are printed with 'Z'.  Squares with a value
459 between P and Z are printed as U.
460 */
461
462 void
463 print_pzoom_cell (pmap, vmap, row, col, row_inc, col_inc)
464 path_map_t *pmap;
465 view_map_t *vmap;
466 int row, col;
467 int row_inc, col_inc;
468 {
469         int r, c;
470         int sum, d;
471         char cell;
472
473         sum = 0;
474         d = 0; /* number of squares in cell */
475         
476         for (r = row; r < row + row_inc; r++)
477         for (c = col; c < col + col_inc; c++) {
478                 sum += pmap[row_col_loc(r,c)].cost;
479                 d += 1;
480         }
481         sum /= d;
482         
483         if (pmap[row_col_loc(row,col)].terrain == T_PATH) cell = '-';
484         else if (sum < 0) cell = '!';
485         else if (sum == INFINITY/2) cell = 'P';
486         else if (sum == INFINITY) cell = ' ';
487         else if (sum > INFINITY/2) cell = 'U';
488         else {
489                 sum %= 36;
490                 if (sum < 10) cell = sum + '0';
491                 else cell = sum - 10 + 'a';
492         }
493         
494         if (cell == ' ')
495                 print_zoom_cell (vmap, row, col, row_inc, col_inc);
496         else {
497                 (void) move (row/row_inc + NUMTOPS, col/col_inc);
498                 (void) addch ((chtype)cell);
499         }
500 }
501
502 /*
503 Display the score off in the corner of the screen.
504 */
505
506 void
507 display_score ()
508 {
509         pos_str (0, cols-12, " User  Comp");
510         pos_str (1, cols-12, "%5d %5d", user_score, comp_score);
511 }