|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T X
Length: 28618 (0x6fca)
Types: TextFile
Names: »X10.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/X/Xconq/X10.c«
/* 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: X10.c,v 1.1 88/06/21 12:29:56 shebs Exp $ */
/* Interface implementations for the X10 version of xconq. */
/* Warning: all of these routines are "bare", in that active_display */
/* is assumed to have already switched to the correct display. Do not */
/* call these in any other context! */
#include "config.h"
#include "misc.h"
#include "period.h"
#include "side.h"
#include "unit.h"
#include "map.h"
#include "global.h"
/* Some perverse X installations may need to change the Xlib include. */
#ifdef UNIX
#include <signal.h> /* needed for ^C disabling */
#include <X/Xlib.h>
#endif UNIX
/* Bitmap that will become a tile for a dotted background. */
#define dots_width 16
#define dots_height 16
static short dots_bits[] = {
0x0101, 0x0000, 0x0000, 0x0000,
0x1010, 0x0000, 0x0000, 0x0000,
0x0101, 0x0000, 0x0000, 0x0000,
0x1010, 0x0000, 0x0000, 0x0000};
/* Bitmaps to make the "unit cursor" (white box with black surround). */
#define mask_width 16
#define mask_height 16
static short mask_bits[] = {
0x03e0, 0x0fd8, 0x19b4, 0x218a,
0x6186, 0x4185, 0xc183, 0xffff,
0xffff, 0xc183, 0xa182, 0x6186,
0x5184, 0x2d98, 0x1bf0, 0x07c0};
#define curs_width 16
#define curs_height 16
static short curs_bits[] = {
0x03e0, 0x0c98, 0x1084, 0x2082,
0x2082, 0x4081, 0x4081, 0x7fff,
0x4081, 0x4081, 0x2082, 0x2082,
0x1084, 0x0c98, 0x03e0, 0x0000};
/* Large bitmaps to make flashy picture of mushroom cloud. */
#define bomb1_width 32
#define bomb1_height 32
static short bomb1_bits[] = {
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0xc000, 0x0001, 0xf000, 0x0007,
0xf000, 0x0007, 0xf800, 0x000f,
0xf800, 0x000f, 0xfc00, 0x000f,
0xfe00, 0x001f, 0xfe00, 0x003f,
0xfe00, 0x003f, 0xfc00, 0x001f,
0x0000, 0x0000, 0x0000, 0x0000};
#define bomb2_width 32
#define bomb2_height 32
static short bomb2_bits[] = {
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xf800, 0x0001,
0xf800, 0x0007, 0xfc00, 0x000f,
0xfc00, 0x001f, 0xfe00, 0x001f,
0xfe00, 0x003f, 0xfc00, 0x001f,
0xfc00, 0x000f, 0xf000, 0x0007,
0xf000, 0x0003, 0xe000, 0x0003,
0xf000, 0x0007, 0xf000, 0x0007,
0xf000, 0x000f, 0xf000, 0x000f,
0xf800, 0x000f, 0xf800, 0x001f,
0xf800, 0x001f, 0xfc00, 0x001f,
0xff00, 0x007f, 0xffc0, 0x03ff,
0x0000, 0x0000, 0x0000, 0x0000};
#define bomb3_width 32
#define bomb3_height 32
static short bomb3_bits[] = {
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xe2fe, 0x3fa3,
0xfc00, 0x001f, 0xff3c, 0x7c7f,
0xff80, 0x00ff, 0xffc0, 0x01ff,
0xffc0, 0x01ff, 0xffe0, 0x03ff,
0xffe0, 0x03ff, 0xffe0, 0x03ff,
0xffe0, 0x01ff, 0xffe0, 0x49ff,
0xff82, 0x34ff, 0xfe14, 0x423f,
0xffe2, 0x349f, 0xfe40, 0x413f,
0xfdbe, 0x1edf, 0xf800, 0x011f,
0xfdfe, 0x7fdf, 0xfc00, 0x001f,
0xfc00, 0x001f, 0xfc00, 0x003f,
0xfe00, 0x001f, 0xfe00, 0x003f,
0xff00, 0x003f, 0xffc0, 0x00ff,
0xfffc, 0x3fff, 0xfffe, 0x7fff,
0x0000, 0x0000, 0x0000, 0x0000};
#define bomb4_width 32
#define bomb4_height 32
static short bomb4_bits[] = {
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xc000, 0x0007,
0x7800, 0x0010, 0x0f00, 0x0046,
0x6180, 0x0081, 0x1cc0, 0x0100,
0x0240, 0x0000, 0x0120, 0x0000,
0x0120, 0x0000, 0x0020, 0x0000,
0x0020, 0x0000, 0x0040, 0x0000,
0x0080, 0x0000, 0x0200, 0x0000,
0x0200, 0x0000, 0x0400, 0x0000,
0x0400, 0x0000, 0x0000, 0x0000,
0x0400, 0x0000, 0x0000, 0x0000,
0x0400, 0x0000, 0x0000, 0x0000,
0x0400, 0x0000, 0x0200, 0x0000,
0x0100, 0x0000, 0x00c0, 0x0000,
0x002c, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000};
#define INFOLINES 4
/* Beware - this macro mentions a normal variable "side"! */
#define sd() ((Screen *) side->display)
/* The next set of definitions has been carefully designed to work with */
/* 16x16 unit icons. They do not, however, require any particular font */
/* size, and will even work with text fonts properly. */
int hw = 20; /* width of box enclosing hex */
int hh = 22; /* height of box enclosing hex */
int hch = 17; /* center-to-center height is less */
int margin = 2; /* pixels between window edge and text */
int bd = 1; /* width of internal window borders */
int helpwinlines = 1; /* will eventually be size of help window */
/* This structure contains all things that we need to feed to X. */
typedef struct a_screen {
Display *disp; /* the X display structure proper */
Font textfont; /* font for text display */
Font iconfont; /* utility font with assorted icons */
Font unitfont; /* font for unit characters */
Bitmap ccurs, cmask; /* Bitmaps for unit "cursor" */
Bitmap mcurs, mmask; /* bitmaps for cursor that tracks mouse */
Bitmap dots; /* basic dotted background pattern */
Bitmap bombpics[4]; /* mushroom clouds */
Bitmap unitpics[MAXUTYPES]; /* used instead of font sometimes */
Pixmap bdtile, wbdots, bwdots; /* blue border and dotted backgrounds */
Cursor curs; /* the cursor object itself */
} Screen;
extern int giventime;
Screen screens[MAXSIDES]; /* one of those screen objects per side */
bool rootcursor; /* true if cursor creation fails */
/* Put in a default player, probably the invoker of the program. */
/* An empty host name will confuse the program. */
add_default_player()
{
#ifdef UNIX
add_player(TRUE, getenv("DISPLAY"));
#endif UNIX
}
/* Ignore ^C if humans in the game, do it otherwise, including when the */
/* last human player turns into a machine (this is called by option cmd). */
/* Attempts to be more clever seem to cause trouble. */
init_sighandlers()
{
#ifdef UNIX
if (numhumans > 0 && !Debug) {
signal(SIGINT, SIG_IGN);
} else {
signal(SIGINT, SIG_DFL);
}
#endif UNIX
}
/* Since X needs all various objects to do its work, we have to make space */
/* in a per-side structure. */
open_display(side)
Side *side;
{
side->display = (long) &(screens[side_number(side)]);
sd()->disp = XOpenDisplay(side->host);
return (sd()->disp != NULL);
}
/* A predicate that tests whether our display can safely be written to. */
/* If so, it activates the display (so random routines don't need to). */
/* X version 10 has the notion of a "current display". Bad things happen */
/* if you attempt to do anything to any non-current display... */
active_display(side)
Side *side;
{
if (side && side->host && !side->lost && side->display) {
XSetDisplay(sd()->disp);
return TRUE;
} else {
return FALSE;
}
}
/* A little trickery here so that the main window doesn't cover everything. */
display_width(side) Side *side; { return ((19 * DisplayWidth()) / 20); }
display_height(side) Side *side; { return ((19 * DisplayHeight()) / 20); }
/* Most X displays have enough screen to do a world map. */
world_display(side) Side *side; { return TRUE; }
/* Handlers for X catastrophes attempt to do a save first. */
/* Could be more friendly and check success of save, but can't do anything */
/* about it anyway... */
handle_x_error(disp, evt)
Display *disp;
XErrorEvent *evt;
{
printf("\nX error: trying emergency save!\n");
write_savefile(SAVEFILE);
abort();
}
handle_xio_error(disp)
Display *disp;
{
printf("\nX IO error: trying emergency save!\n");
write_savefile(SAVEFILE);
exit(1);
}
/* Xconq needs 2 or 3 fonts - one for normal messages, one for standard */
/* pictures (cursor, terrain pics, etc), and an optional font for a period's */
/* units. The last is optional because bitmaps might be used instead. */
/* The character font is nothing unusual, but the other fonts are not a */
/* standard part of X, so we look for them either in the usual place or in */
/* the library directory, and will even subsitute text if necessary. */
/* Note that xconq will fail utterly if even the text font can't be opened. */
/* Also do the rigmarole to convert all those short arrays into X-approved */
/* Bitmaps. Note that this has to be for *each* display separately (!) */
/* Also get the cursor shape. If the hardware can't hack the desired */
/* cursor size, warn about it and just use the root window's cursor. */
/* 0x0 cursor specs seem to be don't cares - machine can handle any size */
init_misc(side)
Side *side;
{
int u, w, h;
FontInfo fontinfo;
side->margin = margin;
side->bd = bd;
sd()->textfont = open_font(TEXTFONT, "TextFont", NULL);
XQueryFont(sd()->textfont, &fontinfo);
side->fw = fontinfo.width;
side->fh = fontinfo.height;
sd()->iconfont = open_font(ICONFONT, "IconFont", sd()->textfont);
XQueryFont(sd()->iconfont, &fontinfo);
side->hw = max(hw, fontinfo.width);
side->hh = max(hh, fontinfo.height);
side->hch = hch;
if (period.fontname != NULL && strlen(period.fontname) > 0) {
sd()->unitfont =
open_font(period.fontname, "UnitFont", sd()->textfont);
XQueryFont(sd()->unitfont, &fontinfo);
side->uw = fontinfo.width;
side->uh = fontinfo.height;
} else {
sd()->unitfont = sd()->textfont;
side->uw = side->fw; side->uh = side->fh;
}
rootcursor = FALSE;
sd()->dots = XStoreBitmap(dots_width, dots_height, dots_bits);
sd()->mmask = XStoreBitmap(mask_width, mask_height, mask_bits);
sd()->mcurs = XStoreBitmap(curs_width, curs_height, curs_bits);
sd()->cmask = XCharBitmap(sd()->iconfont, '[');
sd()->ccurs = XCharBitmap(sd()->iconfont, ']');
sd()->bombpics[0] = XStoreBitmap(bomb1_width, bomb1_height, bomb1_bits);
sd()->bombpics[1] = XStoreBitmap(bomb2_width, bomb2_height, bomb2_bits);
sd()->bombpics[2] = XStoreBitmap(bomb3_width, bomb3_height, bomb3_bits);
sd()->bombpics[3] = XStoreBitmap(bomb4_width, bomb4_height, bomb4_bits);
for_all_unit_types(u) {
sd()->unitpics[u] = (-1);
if (utypes[u].bitmapname && (strlen(utypes[u].bitmapname) > 0)) {
sd()->unitpics[u] = load_bitmap(side, utypes[u].bitmapname);
}
if (sd()->unitpics[u] < 0) {
utypes[u].bitmapname = NULL;
}
}
if (Debug) printf("Bitmaps stored ...\n");
sd()->bdtile = XMakeTile(side->bdcolor);
XQueryTileShape(dots_width, dots_height, &w, &h);
if (Debug) printf("Allowed tile shape is %dx%d\n", w, h);
if (dots_width != w || dots_height != h) {
fprintf(stderr, "Display %s cannot support %dx%d tiles!\n",
side->host, dots_width, dots_height);
fprintf(stderr, "Substituting a solid background...\n");
sd()->wbdots = BlackPixmap;
sd()->bwdots = WhitePixmap;
} else {
sd()->wbdots =
XMakePixmap(sd()->dots, side->graycolor, side->bgcolor);
sd()->bwdots =
XMakePixmap(sd()->dots, side->bgcolor, side->graycolor);
}
if (Debug) printf("Tiles stored ...\n");
XQueryCursorShape(curs_width, curs_height, &w, &h);
if (Debug) printf("Allowed cursor shape is %dx%d\n", w, h);
if ((w == curs_width && h == curs_height) || (w == 0 && h == 0)) {
sd()->curs = XStoreCursor(sd()->mcurs, sd()->mmask, 7, 7,
side->fgcolor, side->bgcolor, GXcopy);
} else {
fprintf(stderr, "Warning: Can't have %dx%d cursors on \"%s\"!\n",
curs_width, curs_height, side->host);
fprintf(stderr, "Using default cursor...\n");
rootcursor = TRUE;
}
if (Debug) printf("Cursor stored ...\n");
XIOErrorHandler(handle_xio_error);
XErrorHandler(handle_x_error);
}
/* Since font lookup is still not smart among Xs, this is a general routine */
/* that can deal with unopenable, missing, etc, fonts, as well as the use of */
/* .Xdefaults. One of the inputs is another font that can be substituted if */
/* absolutely necessary. */
Font
open_font(name, xdefault, altfont)
char *name, *xdefault;
Font altfont;
{
char *firstname, *altname;
FontInfo *fontinfo;
if ((altname = XGetDefault("xconq", xdefault)) != NULL) name = altname;
firstname = name;
if ((fontinfo = XOpenFont(name)) == NULL) {
make_pathname(XCONQLIB, name, "onx", spbuf);
name = spbuf;
if ((fontinfo = XOpenFont(name)) == NULL) {
fprintf(stderr, "Can't open fonts \"%s\" or \"%s\" on \"%s\"\n",
firstname, name, DisplayName());
if (altfont != 0) {
fprintf(stderr, "Substituting another font...\n");
return altfont;
} else {
fprintf(stderr, "No font to substitute for \"%s\"!!\n", name);
exit(1);
}
}
}
if (Debug) printf("Opened font \"%s\" ...\n", name);
return fontinfo->id;
}
/* Try to load a bitmap of the given name. */
load_bitmap(side, name)
Side *side;
char *name;
{
short **data;
int w, h;
make_pathname(NULL, name, "b", spbuf);
if (XReadBitmapFile(spbuf, &w, &h, &data, NULL, NULL) > 0) {
side->uw = w; side->uh = h;
return XStoreBitmap(w, h, data);
} else {
make_pathname(XCONQLIB, name, "b", spbuf);
if (XReadBitmapFile(spbuf, &w, &h, &data, NULL, NULL) > 0) {
side->uw = w; side->uh = h;
return XStoreBitmap(w, h, data);
} else {
fprintf(stderr, "Bitmap \"%s\" not found!\n", name);
return (-1);
}
}
}
/* The main window can be positioned by the player, but the size is */
/* predetermined. */
create_main_window(side)
Side *side;
{
OpaqueFrame mainframe;
sprintf(spbuf, "=%dx%d", side->mw, side->mh);
mainframe.bdrwidth = 3;
mainframe.border = sd()->bdtile;
mainframe.background = (side->bonw ? sd()->bwdots : sd()->wbdots);
side->main = XCreate("xconq", "xconq", spbuf, "", &mainframe,
side->mw, side->mh);
XStoreName(side->main, "xconq"); /* for iconification */
XMapWindow(side->main);
}
/* Help window is not a subwindow, but sits at a fixed location (not good). */
/* 45 is approximation to number of commands - exactness more complicated. */
create_help_window(side)
Side *side;
{
helpwinlines =
max(45, (24 + period.numrtypes + period.numttypes + period.numutypes));
side->help = XCreateWindow(RootWindow, 0, 0,
80*side->fw, helpwinlines*side->fh,
1, sd()->bdtile, BlackPixmap);
}
/* Subwindow creator. */
Window
create_window(side, x, y, w, h)
Side *side;
int x, y, w, h;
{
return XCreateWindow(side->main, x, y, w, h, 1, sd()->bdtile, BlackPixmap);
}
/* Do little things necesary to make it all go - map all the subwindows */
/* (with possible exception of chess clock), and attach a special cursor */
/* if we had succeeded in defining one previously. */
fixup_windows(side)
Side *side;
{
XMapSubwindows(side->main);
if (!giventime) XUnmapWindow(side->clock);
if (!rootcursor) XDefineCursor(side->map, sd()->curs);
}
/* Specify the sorts of input that will be allowed. */
enable_input(side)
Side *side;
{
XSelectInput(side->main,
KeyPressed|ButtonPressed|ExposeRegion|ExposeWindow);
XSelectInput(side->help,
KeyPressed|ButtonPressed|ExposeRegion|ExposeWindow);
}
/* Rehack anything that might need to be changed as a result of the user */
/* fiddling with options. */
reset_misc(side)
Side *side;
{
Pixmap bg, fg, bd, dots;
bg = (side->bonw ? WhitePixmap : BlackPixmap);
fg = (side->bonw ? BlackPixmap : WhitePixmap);
bd = (side->bonw ? BlackPixmap :
(side->monochrome ? WhitePixmap : sd()->bdtile));
dots = (side->bonw ? sd()->bwdots : sd()->wbdots);
XChangeBackground(side->main, dots);
XChangeBackground(side->map, bg);
XChangeBackground(side->world, bg);
XChangeBackground(side->msg, bg);
XChangeBackground(side->prompt, bg);
XChangeBackground(side->info, bg);
XChangeBackground(side->timemode, bg);
XChangeBackground(side->clock, bg);
XChangeBackground(side->state, bg);
XChangeBackground(side->sides, bg);
XChangeBackground(side->help, bg);
XChangeBorder(side->main, bd);
XChangeBorder(side->map, bd);
XChangeBorder(side->msg, bd);
XChangeBorder(side->prompt, bd);
XChangeBorder(side->info, bd);
XChangeBorder(side->sides, bd);
XChangeBorder(side->timemode, bd);
XChangeBorder(side->clock, bd);
XChangeBorder(side->state, bd);
XChangeBorder(side->world, bd);
XChangeBorder(side->help, bd);
}
/* Alter a window's position and/or size. Negative args indicate things */
/* not to bother changing. */
change_window(side, win, x, y, w, h)
Side *side;
Window win;
int x, y, w, h;
{
if (active_display(side)) {
if (x >= 0) {
if (w >= 0) {
XConfigureWindow(win, x, y, w, h);
} else {
XMoveWindow(win, x, y);
}
} else {
XChangeWindow(win, w, h);
}
}
}
/* Return the number of colors - this is used to guess about monochromeness. */
display_colors(side) Side *side; { return (DisplayCells()); }
white_color(side) Side *side; { return WhitePixel; }
black_color(side) Side *side; { return BlackPixel; }
/* Get a color set up and warn if not getting what was asked for. */
request_color(side, name)
Side *side;
char *name;
{
Color c, avail;
XGetColor(name, &avail, &c);
XGetHardwareColor(&avail);
if (c.red != avail.red || c.green != avail.green || c.blue != avail.blue) {
fprintf(stderr, "Warning: %s color not exact on \"%s\"!\n",
name, side->host);
fprintf(stderr, "Is %d %d %d instead of %d %d %d\n",
avail.red, avail.green, avail.blue, c.red, c.green, c.blue);
}
return avail.pixel;
}
/* Main funnel for input returns both mouse and keyboard events, and maybe */
/* other kinds eventually. Some events like window exposure are handled */
/* strictly locally. */
get_input()
{
#ifdef SELECT2
int i, mask;
Side *side, *asides[32];
mask = 0;
for_all_sides(side) {
if (active_display(side)) {
mask |= (1 << sd()->disp->fd);
asides[sd()->disp->fd] = side;
while (XPending() > 0) {
process_events(side);
}
side->lasttime = time(0);
}
}
if (Debug) {
printf("Waiting for input from ");
for_all_sides(side)
if (active_display(side)) printf("%s ", side->host);
printf("\n");
}
if (select(32, &mask, 0, 0, 0) < 0) {
fprintf(stderr, "get_input: error in select(2)!\n");
abort();
} else {
for (i = 0; i < 32; ++i) {
if (mask & (1 << i)) {
process_events(asides[i]);
asides[i]->timeleft -= (time(0) - asides[i]->lasttime);
}
}
}
#else
extern Side *curside;
/* No simultaneity, but there's no portable way to do it, sigh */
if (active_display(curside) && humanside(curside)) {
if (Debug) printf("Waiting for input from %s\n", curside->host);
process_events(curside);
}
#endif SELECT2
}
/* Look at a single event and fill the request structure appropriately. */
process_events(side)
Side *side;
{
XEvent evt;
char *buf;
int nchar, rawx, rawy, rux, ruy;
Window dummy;
XSetDisplay(sd()->disp);
while (TRUE) {
XNextEvent(&evt);
switch (evt.type) {
case KeyPressed:
buf = XLookupMapping(&evt, &nchar);
if (nchar > 0) {
side->reqtype = KEYBOARD;
side->reqch = *buf;
if (Debug) printf("Host %s returns key '%c'\n",
side->host, side->reqch);
return;
}
break;
case ButtonPressed:
XQueryMouse(side->map, &rawx, &rawy, &dummy);
XQueryMouse(side->state, &rux, &ruy, &dummy);
if (rux < 0) {
side->reqtype = MAPPOS;
deform(side, rawx, rawy, &(side->reqx), &(side->reqy));
if (Debug) printf("Host %s returns map %d %d\n",
side->host, side->reqx, side->reqy);
} else {
side->reqtype = UNITTYPE;
side->requtype = ruy / max(side->hh, side->fh);
if (Debug) printf("Host %s returns unit type %d\n",
side->host, side->requtype);
}
return;
case ExposeRegion:
/* Too much work to be clever about redrawing part of screen */
case ExposeWindow:
if (evt.window == side->main) {
flush_input(side);
redraw(side);
}
if (Debug) printf("Host %s exposes itself\n", side->host);
/* Test so machines with screens don't wedge everybody else... */
if (!humanside(side)) return;
break;
default:
case_panic("event type", evt.type);
break;
}
}
}
/* Freeze everything until the given side supplies any event. Use this */
/* sparingly... */
freeze_wait(side)
Side *side;
{
char *buf;
int nchar;
XEvent evt;
if (Debug) printf("Waiting for a %s event\n", side->host);
XSetDisplay(sd()->disp);
sleep(1);
XSync(TRUE);
XNextEvent(&evt);
return '\0';
}
/* Get rid of extra key/mouse clicks. */
flush_input(side)
Side *side;
{
if (active_display(side)) XSync(TRUE);
}
/* Trivial abstraction - sometimes other routines like to ensure all output */
/* actually on the screen. */
flush_output(side)
Side *side;
{
if (active_display(side)) XFlush();
}
/* General window clearing. */
clear_window(side, win)
Side *side;
Window win;
{
XClear(win);
}
/* Draw a single horizontal constant-color bar on the world map. If part */
/* would not be drawn because of the map's obliqueness, cut it in two and */
/* wrap one of the pieces around. */
draw_bar(side, x, y, len, color)
Side *side;
int x, y, len, color;
{
int sx1, sx2, sy, sww;
w_xform(side, x, y, &sx1, &sy);
w_xform(side, x + len, y, &sx2, &sy);
sww = side->mm * world.width;
if (sx1 < sww && sx2 >= sww) {
XPixSet(side->world, sx1, sy, sww - sx1, side->mm, color);
XPixSet(side->world, 0, sy, sx2 - sww, side->mm, color);
} else {
sx1 %= sww;
sx2 %= sww;
XPixSet(side->world, sx1, sy, sx2 - sx1, side->mm, color);
}
}
/* Invert the outline box on the world map. This is a little tricky, */
/* because we want the lines to run through the middle of the world's */
/* hexes, and because the line drawn should not overlap (or the overlaps */
/* will be doubly inverted and look strange). */
invert_box(side, vcx, vcy)
Side *side;
int vcx, vcy;
{
int x1, y1, x2, y2, sx1, sy1, sx2, sy2, mm2 = side->mm/2;
x1 = vcx - side->vw2 + side->vh2/2; y1 = vcy - side->vh2;
x2 = vcx + side->vw2 - side->vh2/2; y2 = vcy + side->vh2;
w_xform(side, x1, y1, &sx1, &sy1);
w_xform(side, x2, y2, &sx2, &sy2);
sx1 += mm2; sy1 -= mm2; sx2 += mm2; sy2 += mm2;
XLine(side->world, sx1, sy1, sx2, sy1,
1, 1, side->owncolor, GXinvert, AllPlanes);
XLine(side->world, sx2, sy1-1, sx2, sy2+1,
1, 1, side->owncolor, GXinvert, AllPlanes);
XLine(side->world, sx2, sy2, sx1, sy2,
1, 1, side->owncolor, GXinvert, AllPlanes);
XLine(side->world, sx1, sy2+1, sx1, sy1-1,
1, 1, side->owncolor, GXinvert, AllPlanes);
}
/* This interfaces higher-level drawing decisions to the rendition of */
/* individual pieces of display. */
draw_terrain_row(side, sx, sy, buf, len, color)
Side *side;
int sx, sy, len, color;
char *buf;
{
XTextMaskPad(side->map, sx, sy, buf, len, sd()->iconfont,
0, side->hw, color, GXcopy, AllPlanes);
}
/* Flash a pair of lines up, slow enough to draw the eye, but not so slow */
/* as to get in the way. */
flash_position(side, sx, sy)
Side *side;
int sx, sy;
{
int i, sx1, sy1, sx2, sy2;
sx1 = sx - 50 + side->hw/2; sy1 = sy + 50 + side->hch/2;
sx2 = sx + 50 + side->hw/2; sy2 = sy - 50 + side->hch/2;
XLine(side->map, sx1, sy1, sx2, sy2,
1, 1, side->owncolor, GXinvert, AllPlanes);
XLine(side->map, sx1, sy2, sx2, sy1,
1, 1, side->owncolor, GXinvert, AllPlanes);
flush_output(side);
for (i = 0; i < DELAY; ++i);
XLine(side->map, sx1, sy1, sx2, sy2,
1, 1, side->owncolor, GXinvert, AllPlanes);
XLine(side->map, sx1, sy2, sx2, sy1,
1, 1, side->owncolor, GXinvert, AllPlanes);
}
/* The "cursor icon" is just a pair of bitmaps - has nothing to do with */
/* X's notion of cursors. */
draw_cursor_icon(side, sx, sy)
Side *side;
int sx, sy;
{
XPixFill(side->map, sx, sy, side->hw, side->hh,
side->bgcolor, sd()->cmask, GXcopy, AllPlanes);
XPixFill(side->map, sx, sy, side->hw, side->hh,
side->fgcolor, sd()->ccurs, GXcopy, AllPlanes);
}
/* Generic hex drawer. */
draw_hex_icon(side, win, x, y, color, ch)
Side *side;
Window win;
int x, y, color;
char ch;
{
XTextMask(win, x, y, &ch, 1, sd()->iconfont, color);
}
/* For little numbers in the corner of the hex. */
draw_side_number(side, win, x, y, n, color)
Side *side;
Window win;
int x, y, n, color;
{
char ch = n + '0';
if (n >= 0) XTextMask(win, x, y, &ch, 1, sd()->iconfont, color);
}
/* For flashes due to combat. */
draw_blast_icon(side, win, x, y, type, color)
Side *side;
Window win;
int x, y, color;
char type;
{
XTextMask(win, x, y, &type, 1, sd()->iconfont, color);
}
/* Flash the player's screen in an unmistakable way. */
invert_whole_map(side)
Side *side;
{
int sw = side->vw * side->hw, sh = side->vh * side->hh;
XTileFill(side->map, 0, 0, sw, sh, WhitePixmap, 0, GXinvert, AllPlanes);
flush_output(side);
}
/* Draw just one of the mushroom cloud shapes. For color displays, all but */
/* the last one are black, for mono, all are white (foreground color). */
draw_mushroom(side, x, y, i)
Side *side;
int x, y, i;
{
int sx, sy;
xform(side, unwrap(side, x), y, &sx, &sy);
XPixFill(side->map, sx-bomb1_width/4, sy-bomb1_height/2,
bomb1_width, bomb1_height,
((side->monochrome || i == 3) ? side->fgcolor : side->bgcolor),
sd()->bombpics[i], GXcopy, AllPlanes);
flush_output(side);
}
/* Confirm that we can indeed do bar graph displays. */
bar_graphs(side) Side *side; { return TRUE; }
/* Do yet another X-toolkit-type function. This draws a bar graph. */
draw_graph(side, number, amount, total, critical, title)
Side *side;
int number, amount, total, critical;
{
int boxwidth, boxheight, boxoffset, boxleft, barwidth, barheight;
if (total > 0) {
boxwidth = 5*side->fw;
boxheight = (INFOLINES-1)*side->fh - 2*side->margin;
boxoffset = side->margin;
boxleft = 30*side->fw + number * boxwidth;
barwidth = boxwidth / 3;
barheight = (boxheight * amount) / total;
XPixSet(side->info, boxleft + boxwidth/3 - 1, boxoffset - 1,
barwidth + 2, boxheight + 2, side->fgcolor);
XPixSet(side->info, boxleft + boxwidth/3, boxoffset,
barwidth, boxheight, side->bgcolor);
XPixSet(side->info,
boxleft + boxwidth/3, boxoffset + boxheight - barheight,
barwidth, barheight,
(amount > critical ? side->goodcolor : side->badcolor));
XText(side->info,
boxleft+(boxwidth-strlen(title)*side->fw)/2,
(INFOLINES-1)*side->fh,
title, strlen(title),
sd()->textfont, side->fgcolor, side->bgcolor);
}
}
/* Splash a unit image (either bitmap or font char) onto some window. */
draw_unit_icon(side, win, x, y, u, color)
Side *side;
Window win;
int x, y, u, color;
{
char ch;
int px, py;
px = x + (side->hw - side->uw) / 2; py = y + (side->hh - side->uh) / 2;
if (utypes[u].bitmapname != NULL) {
XPixFill(win, px, py, side->uw, side->uh, color,
sd()->unitpics[u], GXcopy, AllPlanes);
} else {
ch = utypes[u].uchar;
XTextMask(win, px, py, &ch, 1, sd()->unitfont, color);
}
}
/* General text drawer. */
draw_text(side, win, x, y, str, color)
Side *side;
Window win;
int x, y, color;
char *str;
{
if (color != side->bgcolor) {
XText(win, x, y, str, strlen(str),
sd()->textfont, color, side->bgcolor);
} else {
XText(win, x, y, str, strlen(str),
sd()->textfont, side->bgcolor, side->fgcolor);
}
}
/* Draw a line through some side's title. */
draw_scratchout(side, pos)
Side *side;
int pos;
{
XLine(side->sides, 0, pos, side->fw * side->sw, pos,
1, 1, side->graycolor, GXcopy, AllPlanes);
}
/* Beep the beeper! */
beep(side)
Side *side;
{
XFeep(0);
}
/* Little routines to pop up the help window and make it go away again */
/* They only get called when display is in use. */
reveal_help(side)
Side *side;
{
XMapWindow(side->help);
return TRUE;
}
conceal_help(side)
Side *side;
{
XUnmapWindow(side->help);
}
/* Shut a single display down, but only if there's one to operate on. */
/* Hit the display slot, for safety. */
close_display(side)
Side *side;
{
XCloseDisplay(sd()->disp);
side->display = (long) NULL;
}