DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T c

⟦5230bd092⟧ TextFile

    Length: 9111 (0x2397)
    Types: TextFile
    Names: »curses.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/X/Xconq/curses.c« 

TextFile

/* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
/* This program may be used, copied, modified, and redistributed freely */
/* for noncommercial purposes, so long as this notice remains intact. */

/* RCS $Header: curses.c,v 1.1 88/06/21 12:30:04 shebs Exp $ */

/* Interface implementations for the curses version of xconq. */

/* This file is rather simple, since there is no support for multiple */
/* displays, no flashy graphics, and very little optimization. */

#include "config.h"
#include "misc.h"
#include "period.h"
#include "side.h"
#include "map.h"
#undef bool          /* ugh */
#include <curses.h>

#ifdef UNIX
#include <signal.h>   /* needed for ^C handling */
#endif UNIX

#define INFOLINES 4

int helpwinlines = 1;

/* Positions and sizes of the windows. */

int wx[20], wy[20], ww[20], wh[20];
int nextwin = 0;                /* number of next window to open */

bool alreadyopen = FALSE;       /* flag to prevent double opening */

/* Put in a default player, probably the invoker of the program. */
/* Nonempty host name not actually used, but needed to keep things */
/* straight. */

add_default_player()
{
    add_player(TRUE, "curses");
}

/* Decide what to do about ^C interrupts. */

#ifdef UNIX

stop_handler()
{
    if (numhumans == 0 || Debug) {
	close_displays();
	exit(1);
    }
}

#endif UNIX

init_sighandlers()
{
#ifdef UNIX
    signal(SIGINT, stop_handler);
#endif UNIX
}

/* "Opening" a curses "display" just involves a standard sequence of calls. */
/* Unfortunately, the "standard sequence" varies from system to system... */

open_display(side)
Side *side;
{
    if (!alreadyopen) {
	initscr();
	nonl();
	noecho();
#ifdef HPUX
	cbreak();
#endif HPUX
#ifdef BSD
	crmode();
#endif BSD
	clear();
	side->display = 1L;
	alreadyopen = TRUE;
	return TRUE;
    } else {
	/* if we got here, we're in big trouble, so clean up quickly */
	clear();
	refresh();
	endwin();
        printf("Can't open a second display!\n");
	return FALSE;
    }
}

/* A predicate that tests whether our display can safely be written to. */
/* This is permitted to do side-effects, although curses doesn't need */
/* anything special. */

active_display(side)
Side *side;
{
    return (side != NULL && side->host && !side->lost && side->display);
}

/* Display will use every character position we can get our hands on. */

display_width(side) Side *side; {  return COLS;  }

display_height(side) Side *side; {  return LINES;  }

/* Displaying the world map usually requires a large bitmap display. */

world_display(side) Side *side; {  return FALSE;  }

/* Most sizes of things are 1 (i.e. one character cell). */

init_misc(side)
Side *side;
{
    side->fw = side->fh = side->hh = side->hch = side->uw = side->uh = 1;
    side->hw = 2;
    side->bd = side->margin = 0;
}

/* The "root window" covers our entire display.  In theory, the size of the */
/* screen could exceed what xconq needs, but this is wildly improbable. */

create_main_window(side)
Side *side;
{
    create_window(side, 0, 0, COLS, LINES);
}

/* Subwindow creator. */

create_window(side, x, y, w, h)
Side *side;
int x, y, w, h;
{
    if (x + w > COLS) w = COLS - x;
    if (y + h > LINES) h = LINES - y;
    wx[nextwin] = x;  wy[nextwin] = y;
    ww[nextwin] = w;  wh[nextwin] = h;
    return (nextwin++);
}

/* Help window has to be larger than most terminals allow, so blow it off. */

create_help_window(side) Side *side; {}

/* No special fixups to do. */

fixup_windows(side) Side *side; {}

enable_input(side) Side *side; {}

reset_misc(side) Side *side; {}

/* Moving a window just involves plugging in new values. */

change_window(side, win, x, y, w, h)
Side *side;
int win, x, y, w, h;
{
    if (x + w > COLS) w = COLS - x;
    if (y + h > LINES) h = LINES - y;
    if (x >= 0) {
	wx[win] = x;  wy[win] = y;
    }
    if (w >= 0) {
	ww[win] = w;  wh[win] = h;
    }
}

/* Actually, terminals are really "one-color", but don't take a chance on */
/* confusing the main program. */

display_colors(side) Side *side; {  return 2;  }

white_color(side) Side *side; {  return 1;  }

black_color(side) Side *side; {  return 0;  }

/* Can't actually honor any color requests... */

request_color(side, name) Side *side; char *name; {  return 0;  }

/* Only kind of input is keystrokes, and from only one "display" at that. */

get_input()
{
    char ch;
    extern Side *curside;

    if (active_display(curside)) {
	draw_cursor(curside);
	ch = getch() & 0177;
	curside->reqtype = KEYBOARD;
	curside->reqch = ch;
	return TRUE;
    }
}

/* Wait for any input, don't care what it is. */

freeze_wait(side)
Side *side;
{
    refresh();
    getch();
}

/* Actually would be nice to do something reasonable here. */

flush_input(side) Side *side;  {}

/* Trivial abstraction - sometimes other routines like to ensure all output */
/* actually on the screen. */

flush_output(side) Side *side;  {  refresh();  }

/* General window clearing. */

clear_window(side, win)
Side *side;
int win;
{
    int i;

    if (wx[win] == 0 && wy[win] == 0 && ww[win] == COLS && wh[win] == LINES) {
	clear();
    } else {
	for (i = 0; i < ww[win]; ++i) tmpbuf[i] = ' ';
	tmpbuf[ww[win]] = '\0';
	for (i = 0; i < wh[win]; ++i) mvaddstr(wy[win]+i, wx[win], tmpbuf);
    }
}

/* No world display for curses. */

draw_bar(side, x, y, len, color) Side *side; int x, y, len, color; {}

invert_box(side, vcx, vcy) Side *side; int vcx, vcy; {}

/* This interfaces higher-level drawing decisions to the rendition of */
/* individual pieces of display.  Note that a display mode determines */
/* whether one or two terrain characters get drawn. */

draw_terrain_row(side, x, y, buf, len, color)
Side *side;
int x, y, len, color;
char *buf;
{
    int i, xi = x;

    for (i = 0; i < len; ++i) {
	if (xi >= wx[side->map] + ww[side->map] - 2) break;
	if (cur_at(side->map, xi, y)) {
	    addch(buf[i]);
	    addch((side->showmode == BORDERHEX ? ' ' : buf[i]));
	}
	xi += 2;
    }
}

/* Don't just position the cursor, but also clip and return the decision. */

cur_at(win, x, y)
int win, x, y;
{
    if (x < 0 || x >= ww[win] || y < 0 || y >= wh[win]) {
	return FALSE;
    } else {
	move(wy[win] + y, wx[win] + x);
	return TRUE;
    }
}

/* Curses is never flashy... */

flash_position(side, x, y) Side *side; int x, y; {}

/* Curses cursor drawing is quite easy! (but ineffective? - see input fns) */

draw_cursor_icon(side, x, y)
Side *side;
int x, y;
{
    cur_at(side->map, x, y);
    refresh();
}

/* Doesn't seem to be necessary. */

draw_hex_icon(side, win, x, y, color, ch)
Side *side;
int win, x, y, color;
char ch;
{
}

/* Splash a unit character onto some window. */

draw_unit_icon(side, win, x, y, u, color)
Side *side;
int win;
int x, y, u, color;
{
    if (cur_at(win, x, y)) {
	addch(utypes[u].uchar);
	addch(' ');   /* inefficient, sigh */
    }
}

/* Use the second position in a "hex" for identification of enemies. */

draw_side_number(side, win, x, y, n, color)
Side *side;
int win, x, y, n, color;
{
    if (cur_at(win, x+1, y)) addch((n == -1) ? '`' : n + '0');
}

/* Curses has enough trouble splatting stuff on the screen without doing */
/* little flashes too... */

draw_blast_icon(side, win, x, y, type, color)
Side *side;
int win, x, y, type, color;
{
}

/* Unfortunately, terminals usually can't flash their screens. */

invert_whole_map(side) Side *side; {}

/* Mushroom clouds don't come out real well either. */
/* This could be a little more elaborate. */

draw_mushroom(side, x, y, i)
Side *side;
int x, y, i;
{
    int sx, sy;

    xform(side, unwrap(side, x), y, &sx, &sy);
    if (cur_at(side->map, sx, sy)) {
	addstr("##");
	flush_output(side);
	if (i > 0) {
	    if (cur_at(side->map, sx-1, sy+1)) addstr("####");
	    if (cur_at(side->map, sx-2, sy)) addstr("######");
	    if (cur_at(side->map, sx-1, sy-1)) addstr("####");
	    flush_output(side);
	}
    }
}

/* Indicate that bar graphs are out of the question. */

bar_graphs(side) Side *side;  {  return FALSE;  }

/* Thus this routine can be empty. */

draw_graph(side, number, amount, total, title)
Side *side;
int number, amount, total;
{
}

/* Drawing text is easy, as long as we can ignore the color of it. */
/* Need to do manual clipping though. */

draw_text(side, win, x, y, str, color)
Side *side;
int win;
int x, y, color;
char *str;
{
    int i;

    if (cur_at(win, x, y)) {
	for (i = 0; i < strlen(str); ++i) {
	    if (x + i >= ww[win]) return;
	    addch(str[i]);
	}
    }
}

/* Can't draw lines, but this will substitute, sort of. */

draw_scratchout(side, pos)
Side *side;
int pos;
{
    int i;

    for (i = 0; i < 20; i += 2) {
	if (cur_at(side->sides, i, pos)) addch('-');
    }
}

/* Beep the beeper! */

beep(side)
Side *side;
{
    putchar('\007');
}

/* Most help info is printable also. */

reveal_help(side)
Side *side;
{
    notify(side, "Screen too small - writing into files instead.");
    do_printables(side, 0);
    return FALSE;
}

conceal_help(side) Side *side; {}

/* Shut a single display down - presumably only called once. */

close_display(side)
Side *side;
{
    clear();
    refresh();
    endwin();
}