|
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; }