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