Initial revision
authorEric S. Raymond <esr@thyrsus.com>
Thu, 29 Mar 1990 17:03:08 +0000 (17:03 +0000)
committerEric S. Raymond <esr@thyrsus.com>
Thu, 29 Mar 1990 17:03:08 +0000 (17:03 +0000)
display.c [new file with mode: 0644]

diff --git a/display.c b/display.c
new file mode 100644 (file)
index 0000000..d1327ac
--- /dev/null
+++ b/display.c
@@ -0,0 +1,449 @@
+/* $Id$  - (c) Copyright 1987, 1988 Chuck Simmons */
+
+/*
+ *    Copyright (C) 1987, 1988 Chuck Simmons
+ * 
+ * See the file COPYING, distributed with empire, for restriction
+ * and warranty information.
+ */
+
+/*
+display.c -- This file contains routines for displaying sectors and
+moving the cursor about in a sector.  We need to remember the following
+information:
+
+       the current map portion displayed on the screen;
+
+       whether the displayed portion is from the user's or the computer's
+       point of view;
+*/
+
+#ifdef SYSV
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include <curses.h>
+#include "empire.h"
+#include "extern.h"
+
+static int whose_map = UNOWNED; /* user's or computer's point of view */
+static int ref_row; /* map loc displayed in upper-left corner */
+static int ref_col;
+static int save_sector; /* the currently displayed sector */
+static int save_cursor; /* currently displayed cursor position */
+static int change_ok = TRUE; /* true if new sector may be displayed */
+
+/*
+This routine is called when the current display has been
+trashed and no sector is shown on the screen.
+*/
+
+void kill_display () {
+       whose_map = UNOWNED;
+}
+
+/*
+This routine is called when a new sector may be displayed on the
+screen even if the location to be displayed is already on the screen.
+*/
+
+void sector_change () {
+       change_ok = TRUE;
+}
+
+/*
+Return the currently displayed user sector, if any.  If a user
+sector is not displayed, return -1.
+*/
+
+int cur_sector () {
+       if (whose_map != USER) return (-1);
+       return (save_sector);
+}
+
+/*
+Return the current position of the cursor.  If the user's map
+is not on the screen, we return -1.
+*/
+
+long cur_cursor () {
+       if (whose_map != USER) return (-1);
+       return (save_cursor);
+}
+
+/*
+Display a location on the screen. We figure out the sector the
+location is in and display that sector.  The cursor is left at
+the requested location.
+
+We redisplay the sector only if we either have been requested to
+redisplay the sector, or if the location is not on the screen.
+*/
+
+void
+display_loc (whose, vmap, loc)
+int whose; /* whose map to display */
+view_map_t vmap[];
+long loc; /* location to display */
+{
+       void print_sector(), show_loc();
+       
+       if (change_ok || whose != whose_map || !on_screen (loc))
+               print_sector (whose, vmap, loc_sector (loc));
+               
+       show_loc (vmap, loc);
+}
+
+/*
+Display a location iff the location is on the screen.
+*/
+
+void
+display_locx (whose, vmap, loc)
+int whose; /* whose map to display */
+view_map_t vmap[];
+long loc; /* location to display */
+{
+       if (whose == whose_map && on_screen (loc))
+               show_loc (vmap, loc);
+}
+
+/*
+Display a location which exists on the screen.
+*/
+
+void
+show_loc (vmap, loc)
+view_map_t vmap[];
+long loc;
+{
+       int r, c;
+       
+       r = loc_row (loc);
+       c = loc_col (loc);
+       (void) move (r-ref_row+NUMTOPS, c-ref_col);
+       (void) addch ((chtype)vmap[loc].contents);;
+       save_cursor = loc; /* remember cursor location */
+       (void) move (r-ref_row+NUMTOPS, c-ref_col);
+}
+
+/*
+Print a sector of the user's on the screen.  If it is already displayed,
+we do nothing.  Otherwise we redraw the screen.  Someday, some intelligence
+in doing this might be interesting.  We heavily depend on curses to update
+the screen in a reasonable fashion.
+
+If the desired sector
+is not displayed, we clear the screen.  We then update the screen
+to reflect the current map.  We heavily depend on curses to correctly
+optimize the redrawing of the screen.
+
+When redrawing the screen, we figure out where the
+center of the sector is in relation to the map.  We then compute
+the screen coordinates where we want to display the center of the
+sector.  We will remember the sector displayed, the map displayed,
+and the map location that appears in the upper-left corner of the
+screen.
+*/
+void
+print_sector (whose, vmap, sector)
+char whose; /* USER or COMP */
+view_map_t vmap[]; /* map to display */
+int sector; /* sector to display */
+{
+       void display_screen();
+
+       int first_row, first_col, last_row, last_col;
+       int display_rows, display_cols;
+       int r, c;
+
+       save_sector = sector; /* remember last sector displayed */
+       change_ok = FALSE; /* we are displaying a new sector */
+
+       display_rows = lines - NUMTOPS - 1; /* num lines to display */
+       display_cols = cols - NUMSIDES;
+
+       /* compute row and column edges of sector */
+       first_row = sector_row (sector) * ROWS_PER_SECTOR;
+       first_col = sector_col (sector) * COLS_PER_SECTOR;
+       last_row = first_row + ROWS_PER_SECTOR - 1;
+       last_col = first_col + COLS_PER_SECTOR - 1;
+
+       if (!(whose == whose_map /* correct map is on screen? */
+          && ref_row <= first_row /* top row on screen? */
+          && ref_col <= first_col /* first col on screen? */
+          && ref_row + display_rows - 1 >= last_row /* bot row on screen? */
+          && ref_col + display_cols - 1 >= last_col)) /* last col on screen? */
+       (void) clear (); /* erase current screen */
+
+       /* figure out first row and col to print; subtract half
+          the extra lines from the first line */
+
+       ref_row = first_row - (display_rows - ROWS_PER_SECTOR) / 2;
+       ref_col = first_col - (display_cols - COLS_PER_SECTOR) / 2;
+
+       /* try not to go past bottom of map */
+       if (ref_row + display_rows - 1 > MAP_HEIGHT - 1)
+               ref_row = MAP_HEIGHT - 1 - (display_rows - 1);
+
+       /* never go past top of map */
+        if (ref_row < 0) ref_row = 0;
+
+       /* same with columns */
+       if (ref_col + display_cols - 1 > MAP_WIDTH - 1)
+               ref_col = MAP_WIDTH - 1 - (display_cols - 1);
+
+       if (ref_col < 0) ref_col = 0;
+
+        whose_map = whose; /* remember whose map is displayed */
+       display_screen (vmap);
+
+       /* print x-coordinates along bottom of screen */
+       for (c = ref_col; c < ref_col + display_cols && c < MAP_WIDTH; c++)
+       if (c % 10 == 0) {
+               pos_str (lines-1, c-ref_col, "%d", c);
+       }
+       /* print y-coordinates along right of screen */
+       for (r = ref_row; r < ref_row + display_rows && r < MAP_HEIGHT; r++) {
+               if (r % 2 == 0)
+                       pos_str (r-ref_row+NUMTOPS, cols-NUMSIDES+1, "%2d", r);
+               else pos_str (r-ref_row+NUMTOPS, cols-NUMSIDES+1, "  ");
+       }
+       /* print round number */
+       (void) sprintf (jnkbuf, "Sector %d Round %d", sector, date);
+       for (r = 0; jnkbuf[r] != '\0'; r++) {
+               if (r+NUMTOPS >= MAP_HEIGHT) break;
+               (void) move (r+NUMTOPS, cols-NUMSIDES+4);
+               (void) addch ((chtype)jnkbuf[r]);
+       }
+}
+
+/*
+Display the portion of the map that appears on the screen.
+*/
+
+void display_screen (vmap)
+view_map_t vmap[];
+{
+       int display_rows, display_cols;
+       int r, c;
+       long t;
+
+       display_rows = lines - NUMTOPS - 1; /* num lines to display */
+       display_cols = cols - NUMSIDES;
+
+       for (r = ref_row; r < ref_row + display_rows && r < MAP_HEIGHT; r++)
+       for (c = ref_col; c < ref_col + display_cols && c < MAP_WIDTH; c++) {
+               t = row_col_loc (r, c);
+               (void) move (r-ref_row+NUMTOPS, c-ref_col);
+               (void) addch ((chtype)vmap[t].contents);;
+       }
+}
+
+/*
+Move the cursor in a specified direction.  We return TRUE if the
+cursor remains in the currently displayed screen, otherwise FALSE.
+We display the cursor on the screen, if possible.
+*/
+
+int
+move_cursor (cursor, offset)
+long *cursor; /* current cursor position */
+int offset; /* offset to add to cursor */
+{
+       long t;
+       int r, c;
+       t = *cursor + offset; /* proposed location */
+       if (!map[t].on_board) return (FALSE); /* trying to move off map */
+       if (!on_screen (t)) return (FALSE); /* loc is off screen */
+       
+       *cursor = t; /* update cursor position */
+       save_cursor = *cursor;
+              
+       r = loc_row (save_cursor);
+       c = loc_col (save_cursor);
+       (void) move (r-ref_row+NUMTOPS, c-ref_col);
+       
+       return (TRUE);
+}
+
+/*
+See if a location is displayed on the screen.
+*/
+
+int on_screen (loc)
+long loc;
+{
+       int new_r, new_c;
+       
+       new_r = loc_row (loc);
+       new_c = loc_col (loc);
+
+       if (new_r < ref_row /* past top of screen */
+        || new_r - ref_row > lines - NUMTOPS - 1 /* past bot of screen? */
+        || new_c < ref_col /* past left edge of screen? */
+        || new_c - ref_col > cols - NUMSIDES) /* past right edge of screen? */
+       return (FALSE);
+
+       return (TRUE);
+}
+
+/* Print a view map for debugging. */
+
+void
+print_xzoom (vmap)
+view_map_t *vmap;
+{
+       print_zoom (vmap);
+#if 0
+       prompt ("Hit a key: ");
+       (void) get_chx (); /* wait for user */
+#endif
+}
+
+/*
+Print a condensed version of the map.
+*/
+
+char zoom_list[] = "XO*tcbsdpfaTCBSDPFAzZ+. ";
+
+void
+print_zoom (vmap)
+view_map_t *vmap;
+{
+       void print_zoom_cell();
+
+       int row_inc, col_inc;
+       int r, c;
+
+       kill_display ();
+
+       row_inc = (MAP_HEIGHT + lines - NUMTOPS - 1) / (lines - NUMTOPS);
+       col_inc = (MAP_WIDTH + cols - 1) / (cols - 1);
+
+       for (r = 0; r < MAP_HEIGHT; r += row_inc)
+       for (c = 0; c < MAP_WIDTH; c += col_inc)
+       print_zoom_cell (vmap, r, c, row_inc, col_inc);
+
+       pos_str (0, 0, "Round #%d", date);
+       
+       (void) refresh ();
+}
+
+/*
+Print a single cell in condensed format.
+*/
+
+void
+print_zoom_cell (vmap, row, col, row_inc, col_inc)
+view_map_t *vmap;
+int row, col;
+int row_inc, col_inc;
+{
+       int r, c;
+       char cell;
+
+       cell = ' ';
+       for (r = row; r < row + row_inc; r++)
+       for (c = col; c < col + col_inc; c++)
+       if (strchr (zoom_list, vmap[row_col_loc(r,c)].contents)
+               < strchr (zoom_list, cell))
+       cell = vmap[row_col_loc(r,c)].contents;
+       
+       (void) move (row/row_inc + NUMTOPS, col/col_inc);
+       (void) addch ((chtype)cell);
+}
+
+/*
+Print a condensed version of a pathmap.
+*/
+
+void
+print_pzoom (s, pmap, vmap)
+char *s;
+path_map_t *pmap;
+view_map_t *vmap;
+{
+       void print_pzoom_cell();
+
+       int row_inc, col_inc;
+       int r, c;
+
+       kill_display ();
+
+       row_inc = (MAP_HEIGHT + lines - NUMTOPS - 1) / (lines - NUMTOPS);
+       col_inc = (MAP_WIDTH + cols - 1) / (cols - 1);
+
+       for (r = 0; r < MAP_HEIGHT; r += row_inc)
+       for (c = 0; c < MAP_WIDTH; c += col_inc)
+       print_pzoom_cell (pmap, vmap, r, c, row_inc, col_inc);
+
+       prompt (s);
+       (void) get_chx (); /* wait for user */
+       
+       (void) refresh ();
+}
+
+/*
+Print a single cell of a pathmap in condensed format.
+We average all squares in the cell and take the mod 10 value.
+Squares with a value of -1 are printed with '-', squares with
+a value of INFINITY/2 are printed with 'P', and squares with
+a value of INFINITY are printed with 'Z'.  Squares with a value
+between P and Z are printed as U.
+*/
+
+void
+print_pzoom_cell (pmap, vmap, row, col, row_inc, col_inc)
+path_map_t *pmap;
+view_map_t *vmap;
+int row, col;
+int row_inc, col_inc;
+{
+       int r, c;
+       int sum, d;
+       char cell;
+
+       sum = 0;
+       d = 0; /* number of squares in cell */
+       
+       for (r = row; r < row + row_inc; r++)
+       for (c = col; c < col + col_inc; c++) {
+               sum += pmap[row_col_loc(r,c)].cost;
+               d += 1;
+       }
+       sum /= d;
+       
+       if (pmap[row_col_loc(row,col)].terrain == T_PATH) cell = '-';
+       else if (sum < 0) cell = '!';
+       else if (sum == INFINITY/2) cell = 'P';
+       else if (sum == INFINITY) cell = ' ';
+       else if (sum > INFINITY/2) cell = 'U';
+       else {
+               sum %= 36;
+               if (sum < 10) cell = sum + '0';
+               else cell = sum - 10 + 'a';
+       }
+       
+       if (cell == ' ')
+               print_zoom_cell (vmap, row, col, row_inc, col_inc);
+       else {
+               (void) move (row/row_inc + NUMTOPS, col/col_inc);
+               (void) addch ((chtype)cell);
+       }
+}
+
+/*
+Display the score off in the corner of the screen.
+*/
+
+void
+display_score ()
+{
+       pos_str (0, cols-12, " User  Comp");
+       pos_str (1, cols-12, "%5d %5d", user_score, comp_score);
+}