Maxes seas light blue for greater visibility.
[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(A_BOLD | COLOR_PAIR(COLOR_BLUE));
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 #endif /* A_COLOR */
282 }
283
284
285 /*
286 Display the portion of the map that appears on the screen.
287 */
288
289 void display_screen (vmap)
290 view_map_t vmap[];
291 {
292         int display_rows, display_cols;
293         int r, c;
294         long t;
295
296         display_rows = lines - NUMTOPS - 1; /* num lines to display */
297         display_cols = cols - NUMSIDES;
298
299         for (r = ref_row; r < ref_row + display_rows && r < MAP_HEIGHT; r++)
300         for (c = ref_col; c < ref_col + display_cols && c < MAP_WIDTH; c++) {
301                 t = row_col_loc (r, c);
302                 (void) move (r-ref_row+NUMTOPS, c-ref_col);
303                 disp_square(&vmap[t]);
304         }
305 }
306
307 /*
308 Move the cursor in a specified direction.  We return TRUE if the
309 cursor remains in the currently displayed screen, otherwise FALSE.
310 We display the cursor on the screen, if possible.
311 */
312
313 int
314 move_cursor (cursor, offset)
315 long *cursor; /* current cursor position */
316 int offset; /* offset to add to cursor */
317 {
318         long t;
319         int r, c;
320  
321         t = *cursor + offset; /* proposed location */
322         if (!map[t].on_board) return (FALSE); /* trying to move off map */
323         if (!on_screen (t)) return (FALSE); /* loc is off screen */
324         
325         *cursor = t; /* update cursor position */
326         save_cursor = *cursor;
327                
328         r = loc_row (save_cursor);
329         c = loc_col (save_cursor);
330         (void) move (r-ref_row+NUMTOPS, c-ref_col);
331        
332         return (TRUE);
333 }
334
335 /*
336 See if a location is displayed on the screen.
337 */
338
339 int on_screen (loc)
340 long loc;
341 {
342         int new_r, new_c;
343         
344         new_r = loc_row (loc);
345         new_c = loc_col (loc);
346
347         if (new_r < ref_row /* past top of screen */
348          || new_r - ref_row > lines - NUMTOPS - 1 /* past bot of screen? */
349          || new_c < ref_col /* past left edge of screen? */
350          || new_c - ref_col > cols - NUMSIDES) /* past right edge of screen? */
351         return (FALSE);
352
353         return (TRUE);
354 }
355
356 /* Print a view map for debugging. */
357
358 void
359 print_xzoom (vmap)
360 view_map_t *vmap;
361 {
362         print_zoom (vmap);
363 #if 0
364         prompt ("Hit a key: ");
365         (void) get_chx (); /* wait for user */
366 #endif
367 }
368
369 /*
370 Print a condensed version of the map.
371 */
372
373 char zoom_list[] = "XO*tcbsdpfaTCBSDPFAzZ+. ";
374
375 void
376 print_zoom (vmap)
377 view_map_t *vmap;
378 {
379         void print_zoom_cell();
380
381         int row_inc, col_inc;
382         int r, c;
383
384         kill_display ();
385
386         row_inc = (MAP_HEIGHT + lines - NUMTOPS - 1) / (lines - NUMTOPS);
387         col_inc = (MAP_WIDTH + cols - 1) / (cols - 1);
388
389         for (r = 0; r < MAP_HEIGHT; r += row_inc)
390         for (c = 0; c < MAP_WIDTH; c += col_inc)
391         print_zoom_cell (vmap, r, c, row_inc, col_inc);
392
393         pos_str (0, 0, "Round #%d", date);
394         
395         (void) refresh ();
396 }
397
398 /*
399 Print a single cell in condensed format.
400 */
401
402 void
403 print_zoom_cell (vmap, row, col, row_inc, col_inc)
404 view_map_t *vmap;
405 int row, col;
406 int row_inc, col_inc;
407 {
408         int r, c;
409         char cell;
410
411         cell = ' ';
412         for (r = row; r < row + row_inc; r++)
413         for (c = col; c < col + col_inc; c++)
414         if (strchr (zoom_list, vmap[row_col_loc(r,c)].contents)
415                 < strchr (zoom_list, cell))
416         cell = vmap[row_col_loc(r,c)].contents;
417         
418         (void) move (row/row_inc + NUMTOPS, col/col_inc);
419         (void) addch ((chtype)cell);
420 }
421
422 /*
423 Print a condensed version of a pathmap.
424 */
425
426 void
427 print_pzoom (s, pmap, vmap)
428 char *s;
429 path_map_t *pmap;
430 view_map_t *vmap;
431 {
432         void print_pzoom_cell();
433
434         int row_inc, col_inc;
435         int r, c;
436
437         kill_display ();
438
439         row_inc = (MAP_HEIGHT + lines - NUMTOPS - 1) / (lines - NUMTOPS);
440         col_inc = (MAP_WIDTH + cols - 1) / (cols - 1);
441
442         for (r = 0; r < MAP_HEIGHT; r += row_inc)
443         for (c = 0; c < MAP_WIDTH; c += col_inc)
444         print_pzoom_cell (pmap, vmap, r, c, row_inc, col_inc);
445
446         prompt (s);
447         (void) get_chx (); /* wait for user */
448         
449         (void) refresh ();
450 }
451
452 /*
453 Print a single cell of a pathmap in condensed format.
454 We average all squares in the cell and take the mod 10 value.
455 Squares with a value of -1 are printed with '-', squares with
456 a value of INFINITY/2 are printed with 'P', and squares with
457 a value of INFINITY are printed with 'Z'.  Squares with a value
458 between P and Z are printed as U.
459 */
460
461 void
462 print_pzoom_cell (pmap, vmap, row, col, row_inc, col_inc)
463 path_map_t *pmap;
464 view_map_t *vmap;
465 int row, col;
466 int row_inc, col_inc;
467 {
468         int r, c;
469         int sum, d;
470         char cell;
471
472         sum = 0;
473         d = 0; /* number of squares in cell */
474         
475         for (r = row; r < row + row_inc; r++)
476         for (c = col; c < col + col_inc; c++) {
477                 sum += pmap[row_col_loc(r,c)].cost;
478                 d += 1;
479         }
480         sum /= d;
481         
482         if (pmap[row_col_loc(row,col)].terrain == T_PATH) cell = '-';
483         else if (sum < 0) cell = '!';
484         else if (sum == INFINITY/2) cell = 'P';
485         else if (sum == INFINITY) cell = ' ';
486         else if (sum > INFINITY/2) cell = 'U';
487         else {
488                 sum %= 36;
489                 if (sum < 10) cell = sum + '0';
490                 else cell = sum - 10 + 'a';
491         }
492         
493         if (cell == ' ')
494                 print_zoom_cell (vmap, row, col, row_inc, col_inc);
495         else {
496                 (void) move (row/row_inc + NUMTOPS, col/col_inc);
497                 (void) addch ((chtype)cell);
498         }
499 }
500
501 /*
502 Display the score off in the corner of the screen.
503 */
504
505 void
506 display_score ()
507 {
508         pos_str (0, cols-12, " User  Comp");
509         pos_str (1, cols-12, "%5d %5d", user_score, comp_score);
510 }