games@tekred.TEK.COM (07/01/88)
Submitted by: "Stanley T. Shebs" <shebs%defun@cs.utah.edu> Comp.sources.games: Volume 4, Issue 97 Archive-name: xconq5/Part09 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 9 (of 18)." # Contents: X10.c lib/1987.map phases.c # Wrapped by billr@saab on Wed Jun 29 08:55:45 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f X10.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"X10.c\" else echo shar: Extracting \"X10.c\" \(28618 characters\) sed "s/^X//" >X10.c <<'END_OF_X10.c' X/* Copyright (c) 1987, 1988 Stanley T. Shebs, University of Utah. */ X/* This program may be used, copied, modified, and redistributed freely */ X/* for noncommercial purposes, so long as this notice remains intact. */ X X/* RCS $Header: X10.c,v 1.1 88/06/21 12:29:56 shebs Exp $ */ X X/* Interface implementations for the X10 version of xconq. */ X X/* Warning: all of these routines are "bare", in that active_display */ X/* is assumed to have already switched to the correct display. Do not */ X/* call these in any other context! */ X X#include "config.h" X#include "misc.h" X#include "period.h" X#include "side.h" X#include "unit.h" X#include "map.h" X#include "global.h" X X/* Some perverse X installations may need to change the Xlib include. */ X X#ifdef UNIX X#include <signal.h> /* needed for ^C disabling */ X#include <X/Xlib.h> X#endif UNIX X X/* Bitmap that will become a tile for a dotted background. */ X X#define dots_width 16 X#define dots_height 16 Xstatic short dots_bits[] = { X 0x0101, 0x0000, 0x0000, 0x0000, X 0x1010, 0x0000, 0x0000, 0x0000, X 0x0101, 0x0000, 0x0000, 0x0000, X 0x1010, 0x0000, 0x0000, 0x0000}; X X/* Bitmaps to make the "unit cursor" (white box with black surround). */ X X#define mask_width 16 X#define mask_height 16 Xstatic short mask_bits[] = { X 0x03e0, 0x0fd8, 0x19b4, 0x218a, X 0x6186, 0x4185, 0xc183, 0xffff, X 0xffff, 0xc183, 0xa182, 0x6186, X 0x5184, 0x2d98, 0x1bf0, 0x07c0}; X X#define curs_width 16 X#define curs_height 16 Xstatic short curs_bits[] = { X 0x03e0, 0x0c98, 0x1084, 0x2082, X 0x2082, 0x4081, 0x4081, 0x7fff, X 0x4081, 0x4081, 0x2082, 0x2082, X 0x1084, 0x0c98, 0x03e0, 0x0000}; X X/* Large bitmaps to make flashy picture of mushroom cloud. */ X X#define bomb1_width 32 X#define bomb1_height 32 Xstatic short bomb1_bits[] = { X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0xc000, 0x0001, 0xf000, 0x0007, X 0xf000, 0x0007, 0xf800, 0x000f, X 0xf800, 0x000f, 0xfc00, 0x000f, X 0xfe00, 0x001f, 0xfe00, 0x003f, X 0xfe00, 0x003f, 0xfc00, 0x001f, X 0x0000, 0x0000, 0x0000, 0x0000}; X X#define bomb2_width 32 X#define bomb2_height 32 Xstatic short bomb2_bits[] = { X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0xf800, 0x0001, X 0xf800, 0x0007, 0xfc00, 0x000f, X 0xfc00, 0x001f, 0xfe00, 0x001f, X 0xfe00, 0x003f, 0xfc00, 0x001f, X 0xfc00, 0x000f, 0xf000, 0x0007, X 0xf000, 0x0003, 0xe000, 0x0003, X 0xf000, 0x0007, 0xf000, 0x0007, X 0xf000, 0x000f, 0xf000, 0x000f, X 0xf800, 0x000f, 0xf800, 0x001f, X 0xf800, 0x001f, 0xfc00, 0x001f, X 0xff00, 0x007f, 0xffc0, 0x03ff, X 0x0000, 0x0000, 0x0000, 0x0000}; X X#define bomb3_width 32 X#define bomb3_height 32 Xstatic short bomb3_bits[] = { X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0xe2fe, 0x3fa3, X 0xfc00, 0x001f, 0xff3c, 0x7c7f, X 0xff80, 0x00ff, 0xffc0, 0x01ff, X 0xffc0, 0x01ff, 0xffe0, 0x03ff, X 0xffe0, 0x03ff, 0xffe0, 0x03ff, X 0xffe0, 0x01ff, 0xffe0, 0x49ff, X 0xff82, 0x34ff, 0xfe14, 0x423f, X 0xffe2, 0x349f, 0xfe40, 0x413f, X 0xfdbe, 0x1edf, 0xf800, 0x011f, X 0xfdfe, 0x7fdf, 0xfc00, 0x001f, X 0xfc00, 0x001f, 0xfc00, 0x003f, X 0xfe00, 0x001f, 0xfe00, 0x003f, X 0xff00, 0x003f, 0xffc0, 0x00ff, X 0xfffc, 0x3fff, 0xfffe, 0x7fff, X 0x0000, 0x0000, 0x0000, 0x0000}; X X#define bomb4_width 32 X#define bomb4_height 32 Xstatic short bomb4_bits[] = { X 0x0000, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0xc000, 0x0007, X 0x7800, 0x0010, 0x0f00, 0x0046, X 0x6180, 0x0081, 0x1cc0, 0x0100, X 0x0240, 0x0000, 0x0120, 0x0000, X 0x0120, 0x0000, 0x0020, 0x0000, X 0x0020, 0x0000, 0x0040, 0x0000, X 0x0080, 0x0000, 0x0200, 0x0000, X 0x0200, 0x0000, 0x0400, 0x0000, X 0x0400, 0x0000, 0x0000, 0x0000, X 0x0400, 0x0000, 0x0000, 0x0000, X 0x0400, 0x0000, 0x0000, 0x0000, X 0x0400, 0x0000, 0x0200, 0x0000, X 0x0100, 0x0000, 0x00c0, 0x0000, X 0x002c, 0x0000, 0x0000, 0x0000, X 0x0000, 0x0000, 0x0000, 0x0000}; X X#define INFOLINES 4 X X/* Beware - this macro mentions a normal variable "side"! */ X X#define sd() ((Screen *) side->display) X X/* The next set of definitions has been carefully designed to work with */ X/* 16x16 unit icons. They do not, however, require any particular font */ X/* size, and will even work with text fonts properly. */ X Xint hw = 20; /* width of box enclosing hex */ Xint hh = 22; /* height of box enclosing hex */ Xint hch = 17; /* center-to-center height is less */ Xint margin = 2; /* pixels between window edge and text */ Xint bd = 1; /* width of internal window borders */ X Xint helpwinlines = 1; /* will eventually be size of help window */ X X/* This structure contains all things that we need to feed to X. */ X Xtypedef struct a_screen { X Display *disp; /* the X display structure proper */ X Font textfont; /* font for text display */ X Font iconfont; /* utility font with assorted icons */ X Font unitfont; /* font for unit characters */ X Bitmap ccurs, cmask; /* Bitmaps for unit "cursor" */ X Bitmap mcurs, mmask; /* bitmaps for cursor that tracks mouse */ X Bitmap dots; /* basic dotted background pattern */ X Bitmap bombpics[4]; /* mushroom clouds */ X Bitmap unitpics[MAXUTYPES]; /* used instead of font sometimes */ X Pixmap bdtile, wbdots, bwdots; /* blue border and dotted backgrounds */ X Cursor curs; /* the cursor object itself */ X} Screen; X Xextern int giventime; X XScreen screens[MAXSIDES]; /* one of those screen objects per side */ X Xbool rootcursor; /* true if cursor creation fails */ X X/* Put in a default player, probably the invoker of the program. */ X/* An empty host name will confuse the program. */ X Xadd_default_player() X{ X#ifdef UNIX X add_player(TRUE, getenv("DISPLAY")); X#endif UNIX X} X X/* Ignore ^C if humans in the game, do it otherwise, including when the */ X/* last human player turns into a machine (this is called by option cmd). */ X/* Attempts to be more clever seem to cause trouble. */ X Xinit_sighandlers() X{ X#ifdef UNIX X if (numhumans > 0 && !Debug) { X signal(SIGINT, SIG_IGN); X } else { X signal(SIGINT, SIG_DFL); X } X#endif UNIX X} X X/* Since X needs all various objects to do its work, we have to make space */ X/* in a per-side structure. */ X Xopen_display(side) XSide *side; X{ X side->display = (long) &(screens[side_number(side)]); X sd()->disp = XOpenDisplay(side->host); X return (sd()->disp != NULL); X} X X/* A predicate that tests whether our display can safely be written to. */ X/* If so, it activates the display (so random routines don't need to). */ X/* X version 10 has the notion of a "current display". Bad things happen */ X/* if you attempt to do anything to any non-current display... */ X Xactive_display(side) XSide *side; X{ X if (side && side->host && !side->lost && side->display) { X XSetDisplay(sd()->disp); X return TRUE; X } else { X return FALSE; X } X} X X/* A little trickery here so that the main window doesn't cover everything. */ X Xdisplay_width(side) Side *side; { return ((19 * DisplayWidth()) / 20); } X Xdisplay_height(side) Side *side; { return ((19 * DisplayHeight()) / 20); } X X/* Most X displays have enough screen to do a world map. */ X Xworld_display(side) Side *side; { return TRUE; } X X/* Handlers for X catastrophes attempt to do a save first. */ X/* Could be more friendly and check success of save, but can't do anything */ X/* about it anyway... */ X Xhandle_x_error(disp, evt) XDisplay *disp; XXErrorEvent *evt; X{ X printf("\nX error: trying emergency save!\n"); X write_savefile(SAVEFILE); X abort(); X} X Xhandle_xio_error(disp) XDisplay *disp; X{ X printf("\nX IO error: trying emergency save!\n"); X write_savefile(SAVEFILE); X exit(1); X} X X/* Xconq needs 2 or 3 fonts - one for normal messages, one for standard */ X/* pictures (cursor, terrain pics, etc), and an optional font for a period's */ X/* units. The last is optional because bitmaps might be used instead. */ X/* The character font is nothing unusual, but the other fonts are not a */ X/* standard part of X, so we look for them either in the usual place or in */ X/* the library directory, and will even subsitute text if necessary. */ X/* Note that xconq will fail utterly if even the text font can't be opened. */ X X/* Also do the rigmarole to convert all those short arrays into X-approved */ X/* Bitmaps. Note that this has to be for *each* display separately (!) */ X/* Also get the cursor shape. If the hardware can't hack the desired */ X/* cursor size, warn about it and just use the root window's cursor. */ X/* 0x0 cursor specs seem to be don't cares - machine can handle any size */ X Xinit_misc(side) XSide *side; X{ X int u, w, h; X FontInfo fontinfo; X X side->margin = margin; X side->bd = bd; X sd()->textfont = open_font(TEXTFONT, "TextFont", NULL); X XQueryFont(sd()->textfont, &fontinfo); X side->fw = fontinfo.width; X side->fh = fontinfo.height; X sd()->iconfont = open_font(ICONFONT, "IconFont", sd()->textfont); X XQueryFont(sd()->iconfont, &fontinfo); X side->hw = max(hw, fontinfo.width); X side->hh = max(hh, fontinfo.height); X side->hch = hch; X if (period.fontname != NULL && strlen(period.fontname) > 0) { X sd()->unitfont = X open_font(period.fontname, "UnitFont", sd()->textfont); X XQueryFont(sd()->unitfont, &fontinfo); X side->uw = fontinfo.width; X side->uh = fontinfo.height; X } else { X sd()->unitfont = sd()->textfont; X side->uw = side->fw; side->uh = side->fh; X } X rootcursor = FALSE; X sd()->dots = XStoreBitmap(dots_width, dots_height, dots_bits); X sd()->mmask = XStoreBitmap(mask_width, mask_height, mask_bits); X sd()->mcurs = XStoreBitmap(curs_width, curs_height, curs_bits); X sd()->cmask = XCharBitmap(sd()->iconfont, '['); X sd()->ccurs = XCharBitmap(sd()->iconfont, ']'); X sd()->bombpics[0] = XStoreBitmap(bomb1_width, bomb1_height, bomb1_bits); X sd()->bombpics[1] = XStoreBitmap(bomb2_width, bomb2_height, bomb2_bits); X sd()->bombpics[2] = XStoreBitmap(bomb3_width, bomb3_height, bomb3_bits); X sd()->bombpics[3] = XStoreBitmap(bomb4_width, bomb4_height, bomb4_bits); X for_all_unit_types(u) { X sd()->unitpics[u] = (-1); X if (utypes[u].bitmapname && (strlen(utypes[u].bitmapname) > 0)) { X sd()->unitpics[u] = load_bitmap(side, utypes[u].bitmapname); X } X if (sd()->unitpics[u] < 0) { X utypes[u].bitmapname = NULL; X } X } X if (Debug) printf("Bitmaps stored ...\n"); X sd()->bdtile = XMakeTile(side->bdcolor); X XQueryTileShape(dots_width, dots_height, &w, &h); X if (Debug) printf("Allowed tile shape is %dx%d\n", w, h); X if (dots_width != w || dots_height != h) { X fprintf(stderr, "Display %s cannot support %dx%d tiles!\n", X side->host, dots_width, dots_height); X fprintf(stderr, "Substituting a solid background...\n"); X sd()->wbdots = BlackPixmap; X sd()->bwdots = WhitePixmap; X } else { X sd()->wbdots = X XMakePixmap(sd()->dots, side->graycolor, side->bgcolor); X sd()->bwdots = X XMakePixmap(sd()->dots, side->bgcolor, side->graycolor); X } X if (Debug) printf("Tiles stored ...\n"); X XQueryCursorShape(curs_width, curs_height, &w, &h); X if (Debug) printf("Allowed cursor shape is %dx%d\n", w, h); X if ((w == curs_width && h == curs_height) || (w == 0 && h == 0)) { X sd()->curs = XStoreCursor(sd()->mcurs, sd()->mmask, 7, 7, X side->fgcolor, side->bgcolor, GXcopy); X } else { X fprintf(stderr, "Warning: Can't have %dx%d cursors on \"%s\"!\n", X curs_width, curs_height, side->host); X fprintf(stderr, "Using default cursor...\n"); X rootcursor = TRUE; X } X if (Debug) printf("Cursor stored ...\n"); X XIOErrorHandler(handle_xio_error); X XErrorHandler(handle_x_error); X} X X/* Since font lookup is still not smart among Xs, this is a general routine */ X/* that can deal with unopenable, missing, etc, fonts, as well as the use of */ X/* .Xdefaults. One of the inputs is another font that can be substituted if */ X/* absolutely necessary. */ X XFont Xopen_font(name, xdefault, altfont) Xchar *name, *xdefault; XFont altfont; X{ X char *firstname, *altname; X FontInfo *fontinfo; X X if ((altname = XGetDefault("xconq", xdefault)) != NULL) name = altname; X firstname = name; X if ((fontinfo = XOpenFont(name)) == NULL) { X make_pathname(XCONQLIB, name, "onx", spbuf); X name = spbuf; X if ((fontinfo = XOpenFont(name)) == NULL) { X fprintf(stderr, "Can't open fonts \"%s\" or \"%s\" on \"%s\"\n", X firstname, name, DisplayName()); X if (altfont != 0) { X fprintf(stderr, "Substituting another font...\n"); X return altfont; X } else { X fprintf(stderr, "No font to substitute for \"%s\"!!\n", name); X exit(1); X } X } X } X if (Debug) printf("Opened font \"%s\" ...\n", name); X return fontinfo->id; X} X X/* Try to load a bitmap of the given name. */ X Xload_bitmap(side, name) XSide *side; Xchar *name; X{ X short **data; X int w, h; X X make_pathname(NULL, name, "b", spbuf); X if (XReadBitmapFile(spbuf, &w, &h, &data, NULL, NULL) > 0) { X side->uw = w; side->uh = h; X return XStoreBitmap(w, h, data); X } else { X make_pathname(XCONQLIB, name, "b", spbuf); X if (XReadBitmapFile(spbuf, &w, &h, &data, NULL, NULL) > 0) { X side->uw = w; side->uh = h; X return XStoreBitmap(w, h, data); X } else { X fprintf(stderr, "Bitmap \"%s\" not found!\n", name); X return (-1); X } X } X} X X/* The main window can be positioned by the player, but the size is */ X/* predetermined. */ X Xcreate_main_window(side) XSide *side; X{ X OpaqueFrame mainframe; X X sprintf(spbuf, "=%dx%d", side->mw, side->mh); X mainframe.bdrwidth = 3; X mainframe.border = sd()->bdtile; X mainframe.background = (side->bonw ? sd()->bwdots : sd()->wbdots); X side->main = XCreate("xconq", "xconq", spbuf, "", &mainframe, X side->mw, side->mh); X XStoreName(side->main, "xconq"); /* for iconification */ X XMapWindow(side->main); X} X X/* Help window is not a subwindow, but sits at a fixed location (not good). */ X/* 45 is approximation to number of commands - exactness more complicated. */ X Xcreate_help_window(side) XSide *side; X{ X helpwinlines = X max(45, (24 + period.numrtypes + period.numttypes + period.numutypes)); X X side->help = XCreateWindow(RootWindow, 0, 0, X 80*side->fw, helpwinlines*side->fh, X 1, sd()->bdtile, BlackPixmap); X} X X/* Subwindow creator. */ X XWindow Xcreate_window(side, x, y, w, h) XSide *side; Xint x, y, w, h; X{ X return XCreateWindow(side->main, x, y, w, h, 1, sd()->bdtile, BlackPixmap); X} X X/* Do little things necesary to make it all go - map all the subwindows */ X/* (with possible exception of chess clock), and attach a special cursor */ X/* if we had succeeded in defining one previously. */ X Xfixup_windows(side) XSide *side; X{ X XMapSubwindows(side->main); X if (!giventime) XUnmapWindow(side->clock); X if (!rootcursor) XDefineCursor(side->map, sd()->curs); X} X X/* Specify the sorts of input that will be allowed. */ X Xenable_input(side) XSide *side; X{ X XSelectInput(side->main, X KeyPressed|ButtonPressed|ExposeRegion|ExposeWindow); X XSelectInput(side->help, X KeyPressed|ButtonPressed|ExposeRegion|ExposeWindow); X} X X/* Rehack anything that might need to be changed as a result of the user */ X/* fiddling with options. */ X Xreset_misc(side) XSide *side; X{ X Pixmap bg, fg, bd, dots; X X bg = (side->bonw ? WhitePixmap : BlackPixmap); X fg = (side->bonw ? BlackPixmap : WhitePixmap); X bd = (side->bonw ? BlackPixmap : X (side->monochrome ? WhitePixmap : sd()->bdtile)); X dots = (side->bonw ? sd()->bwdots : sd()->wbdots); X XChangeBackground(side->main, dots); X XChangeBackground(side->map, bg); X XChangeBackground(side->world, bg); X XChangeBackground(side->msg, bg); X XChangeBackground(side->prompt, bg); X XChangeBackground(side->info, bg); X XChangeBackground(side->timemode, bg); X XChangeBackground(side->clock, bg); X XChangeBackground(side->state, bg); X XChangeBackground(side->sides, bg); X XChangeBackground(side->help, bg); X XChangeBorder(side->main, bd); X XChangeBorder(side->map, bd); X XChangeBorder(side->msg, bd); X XChangeBorder(side->prompt, bd); X XChangeBorder(side->info, bd); X XChangeBorder(side->sides, bd); X XChangeBorder(side->timemode, bd); X XChangeBorder(side->clock, bd); X XChangeBorder(side->state, bd); X XChangeBorder(side->world, bd); X XChangeBorder(side->help, bd); X} X X/* Alter a window's position and/or size. Negative args indicate things */ X/* not to bother changing. */ X Xchange_window(side, win, x, y, w, h) XSide *side; XWindow win; Xint x, y, w, h; X{ X if (active_display(side)) { X if (x >= 0) { X if (w >= 0) { X XConfigureWindow(win, x, y, w, h); X } else { X XMoveWindow(win, x, y); X } X } else { X XChangeWindow(win, w, h); X } X } X} X X/* Return the number of colors - this is used to guess about monochromeness. */ X Xdisplay_colors(side) Side *side; { return (DisplayCells()); } X Xwhite_color(side) Side *side; { return WhitePixel; } X Xblack_color(side) Side *side; { return BlackPixel; } X X/* Get a color set up and warn if not getting what was asked for. */ X Xrequest_color(side, name) XSide *side; Xchar *name; X{ X Color c, avail; X X XGetColor(name, &avail, &c); X XGetHardwareColor(&avail); X if (c.red != avail.red || c.green != avail.green || c.blue != avail.blue) { X fprintf(stderr, "Warning: %s color not exact on \"%s\"!\n", X name, side->host); X fprintf(stderr, "Is %d %d %d instead of %d %d %d\n", X avail.red, avail.green, avail.blue, c.red, c.green, c.blue); X } X return avail.pixel; X} X X/* Main funnel for input returns both mouse and keyboard events, and maybe */ X/* other kinds eventually. Some events like window exposure are handled */ X/* strictly locally. */ X Xget_input() X{ X#ifdef SELECT2 X int i, mask; X Side *side, *asides[32]; X X mask = 0; X for_all_sides(side) { X if (active_display(side)) { X mask |= (1 << sd()->disp->fd); X asides[sd()->disp->fd] = side; X while (XPending() > 0) { X process_events(side); X } X side->lasttime = time(0); X } X } X if (Debug) { X printf("Waiting for input from "); X for_all_sides(side) X if (active_display(side)) printf("%s ", side->host); X printf("\n"); X } X if (select(32, &mask, 0, 0, 0) < 0) { X fprintf(stderr, "get_input: error in select(2)!\n"); X abort(); X } else { X for (i = 0; i < 32; ++i) { X if (mask & (1 << i)) { X process_events(asides[i]); X asides[i]->timeleft -= (time(0) - asides[i]->lasttime); X } X } X } X#else X extern Side *curside; X X /* No simultaneity, but there's no portable way to do it, sigh */ X if (active_display(curside) && humanside(curside)) { X if (Debug) printf("Waiting for input from %s\n", curside->host); X process_events(curside); X } X#endif SELECT2 X} X X/* Look at a single event and fill the request structure appropriately. */ X Xprocess_events(side) XSide *side; X{ X XEvent evt; X char *buf; X int nchar, rawx, rawy, rux, ruy; X Window dummy; X X XSetDisplay(sd()->disp); X while (TRUE) { X XNextEvent(&evt); X switch (evt.type) { X case KeyPressed: X buf = XLookupMapping(&evt, &nchar); X if (nchar > 0) { X side->reqtype = KEYBOARD; X side->reqch = *buf; X if (Debug) printf("Host %s returns key '%c'\n", X side->host, side->reqch); X return; X } X break; X case ButtonPressed: X XQueryMouse(side->map, &rawx, &rawy, &dummy); X XQueryMouse(side->state, &rux, &ruy, &dummy); X if (rux < 0) { X side->reqtype = MAPPOS; X deform(side, rawx, rawy, &(side->reqx), &(side->reqy)); X if (Debug) printf("Host %s returns map %d %d\n", X side->host, side->reqx, side->reqy); X } else { X side->reqtype = UNITTYPE; X side->requtype = ruy / max(side->hh, side->fh); X if (Debug) printf("Host %s returns unit type %d\n", X side->host, side->requtype); X } X return; X case ExposeRegion: X /* Too much work to be clever about redrawing part of screen */ X case ExposeWindow: X if (evt.window == side->main) { X flush_input(side); X redraw(side); X } X if (Debug) printf("Host %s exposes itself\n", side->host); X /* Test so machines with screens don't wedge everybody else... */ X if (!humanside(side)) return; X break; X default: X case_panic("event type", evt.type); X break; X } X } X} X X/* Freeze everything until the given side supplies any event. Use this */ X/* sparingly... */ X Xfreeze_wait(side) XSide *side; X{ X char *buf; X int nchar; X XEvent evt; X X if (Debug) printf("Waiting for a %s event\n", side->host); X XSetDisplay(sd()->disp); X sleep(1); X XSync(TRUE); X XNextEvent(&evt); X return '\0'; X} X X/* Get rid of extra key/mouse clicks. */ X Xflush_input(side) XSide *side; X{ X if (active_display(side)) XSync(TRUE); X} X X/* Trivial abstraction - sometimes other routines like to ensure all output */ X/* actually on the screen. */ X Xflush_output(side) XSide *side; X{ X if (active_display(side)) XFlush(); X} X X/* General window clearing. */ X Xclear_window(side, win) XSide *side; XWindow win; X{ X XClear(win); X} X X/* Draw a single horizontal constant-color bar on the world map. If part */ X/* would not be drawn because of the map's obliqueness, cut it in two and */ X/* wrap one of the pieces around. */ X Xdraw_bar(side, x, y, len, color) XSide *side; Xint x, y, len, color; X{ X int sx1, sx2, sy, sww; X X w_xform(side, x, y, &sx1, &sy); X w_xform(side, x + len, y, &sx2, &sy); X sww = side->mm * world.width; X if (sx1 < sww && sx2 >= sww) { X XPixSet(side->world, sx1, sy, sww - sx1, side->mm, color); X XPixSet(side->world, 0, sy, sx2 - sww, side->mm, color); X } else { X sx1 %= sww; X sx2 %= sww; X XPixSet(side->world, sx1, sy, sx2 - sx1, side->mm, color); X } X} X X/* Invert the outline box on the world map. This is a little tricky, */ X/* because we want the lines to run through the middle of the world's */ X/* hexes, and because the line drawn should not overlap (or the overlaps */ X/* will be doubly inverted and look strange). */ X Xinvert_box(side, vcx, vcy) XSide *side; Xint vcx, vcy; X{ X int x1, y1, x2, y2, sx1, sy1, sx2, sy2, mm2 = side->mm/2; X X x1 = vcx - side->vw2 + side->vh2/2; y1 = vcy - side->vh2; X x2 = vcx + side->vw2 - side->vh2/2; y2 = vcy + side->vh2; X w_xform(side, x1, y1, &sx1, &sy1); X w_xform(side, x2, y2, &sx2, &sy2); X sx1 += mm2; sy1 -= mm2; sx2 += mm2; sy2 += mm2; X XLine(side->world, sx1, sy1, sx2, sy1, X 1, 1, side->owncolor, GXinvert, AllPlanes); X XLine(side->world, sx2, sy1-1, sx2, sy2+1, X 1, 1, side->owncolor, GXinvert, AllPlanes); X XLine(side->world, sx2, sy2, sx1, sy2, X 1, 1, side->owncolor, GXinvert, AllPlanes); X XLine(side->world, sx1, sy2+1, sx1, sy1-1, X 1, 1, side->owncolor, GXinvert, AllPlanes); X} X X/* This interfaces higher-level drawing decisions to the rendition of */ X/* individual pieces of display. */ X Xdraw_terrain_row(side, sx, sy, buf, len, color) XSide *side; Xint sx, sy, len, color; Xchar *buf; X{ X XTextMaskPad(side->map, sx, sy, buf, len, sd()->iconfont, X 0, side->hw, color, GXcopy, AllPlanes); X} X X/* Flash a pair of lines up, slow enough to draw the eye, but not so slow */ X/* as to get in the way. */ X Xflash_position(side, sx, sy) XSide *side; Xint sx, sy; X{ X int i, sx1, sy1, sx2, sy2; X X sx1 = sx - 50 + side->hw/2; sy1 = sy + 50 + side->hch/2; X sx2 = sx + 50 + side->hw/2; sy2 = sy - 50 + side->hch/2; X XLine(side->map, sx1, sy1, sx2, sy2, X 1, 1, side->owncolor, GXinvert, AllPlanes); X XLine(side->map, sx1, sy2, sx2, sy1, X 1, 1, side->owncolor, GXinvert, AllPlanes); X flush_output(side); X for (i = 0; i < DELAY; ++i); X XLine(side->map, sx1, sy1, sx2, sy2, X 1, 1, side->owncolor, GXinvert, AllPlanes); X XLine(side->map, sx1, sy2, sx2, sy1, X 1, 1, side->owncolor, GXinvert, AllPlanes); X} X X/* The "cursor icon" is just a pair of bitmaps - has nothing to do with */ X/* X's notion of cursors. */ X Xdraw_cursor_icon(side, sx, sy) XSide *side; Xint sx, sy; X{ X XPixFill(side->map, sx, sy, side->hw, side->hh, X side->bgcolor, sd()->cmask, GXcopy, AllPlanes); X XPixFill(side->map, sx, sy, side->hw, side->hh, X side->fgcolor, sd()->ccurs, GXcopy, AllPlanes); X} X X/* Generic hex drawer. */ X Xdraw_hex_icon(side, win, x, y, color, ch) XSide *side; XWindow win; Xint x, y, color; Xchar ch; X{ X XTextMask(win, x, y, &ch, 1, sd()->iconfont, color); X} X X/* For little numbers in the corner of the hex. */ X Xdraw_side_number(side, win, x, y, n, color) XSide *side; XWindow win; Xint x, y, n, color; X{ X char ch = n + '0'; X X if (n >= 0) XTextMask(win, x, y, &ch, 1, sd()->iconfont, color); X} X X/* For flashes due to combat. */ X Xdraw_blast_icon(side, win, x, y, type, color) XSide *side; XWindow win; Xint x, y, color; Xchar type; X{ X XTextMask(win, x, y, &type, 1, sd()->iconfont, color); X} X X/* Flash the player's screen in an unmistakable way. */ X Xinvert_whole_map(side) XSide *side; X{ X int sw = side->vw * side->hw, sh = side->vh * side->hh; X X XTileFill(side->map, 0, 0, sw, sh, WhitePixmap, 0, GXinvert, AllPlanes); X flush_output(side); X} X X/* Draw just one of the mushroom cloud shapes. For color displays, all but */ X/* the last one are black, for mono, all are white (foreground color). */ X Xdraw_mushroom(side, x, y, i) XSide *side; Xint x, y, i; X{ X int sx, sy; X X xform(side, unwrap(side, x), y, &sx, &sy); X XPixFill(side->map, sx-bomb1_width/4, sy-bomb1_height/2, X bomb1_width, bomb1_height, X ((side->monochrome || i == 3) ? side->fgcolor : side->bgcolor), X sd()->bombpics[i], GXcopy, AllPlanes); X flush_output(side); X} X X/* Confirm that we can indeed do bar graph displays. */ X Xbar_graphs(side) Side *side; { return TRUE; } X X/* Do yet another X-toolkit-type function. This draws a bar graph. */ X Xdraw_graph(side, number, amount, total, critical, title) XSide *side; Xint number, amount, total, critical; X{ X int boxwidth, boxheight, boxoffset, boxleft, barwidth, barheight; X X if (total > 0) { X boxwidth = 5*side->fw; X boxheight = (INFOLINES-1)*side->fh - 2*side->margin; X boxoffset = side->margin; X boxleft = 30*side->fw + number * boxwidth; X barwidth = boxwidth / 3; X barheight = (boxheight * amount) / total; X XPixSet(side->info, boxleft + boxwidth/3 - 1, boxoffset - 1, X barwidth + 2, boxheight + 2, side->fgcolor); X XPixSet(side->info, boxleft + boxwidth/3, boxoffset, X barwidth, boxheight, side->bgcolor); X XPixSet(side->info, X boxleft + boxwidth/3, boxoffset + boxheight - barheight, X barwidth, barheight, X (amount > critical ? side->goodcolor : side->badcolor)); X XText(side->info, X boxleft+(boxwidth-strlen(title)*side->fw)/2, X (INFOLINES-1)*side->fh, X title, strlen(title), X sd()->textfont, side->fgcolor, side->bgcolor); X } X} X X/* Splash a unit image (either bitmap or font char) onto some window. */ X Xdraw_unit_icon(side, win, x, y, u, color) XSide *side; XWindow win; Xint x, y, u, color; X{ X char ch; X int px, py; X X px = x + (side->hw - side->uw) / 2; py = y + (side->hh - side->uh) / 2; X if (utypes[u].bitmapname != NULL) { X XPixFill(win, px, py, side->uw, side->uh, color, X sd()->unitpics[u], GXcopy, AllPlanes); X } else { X ch = utypes[u].uchar; X XTextMask(win, px, py, &ch, 1, sd()->unitfont, color); X } X} X X/* General text drawer. */ X Xdraw_text(side, win, x, y, str, color) XSide *side; XWindow win; Xint x, y, color; Xchar *str; X{ X if (color != side->bgcolor) { X XText(win, x, y, str, strlen(str), X sd()->textfont, color, side->bgcolor); X } else { X XText(win, x, y, str, strlen(str), X sd()->textfont, side->bgcolor, side->fgcolor); X } X} X X/* Draw a line through some side's title. */ X Xdraw_scratchout(side, pos) XSide *side; Xint pos; X{ X XLine(side->sides, 0, pos, side->fw * side->sw, pos, X 1, 1, side->graycolor, GXcopy, AllPlanes); X} X X/* Beep the beeper! */ X Xbeep(side) XSide *side; X{ X XFeep(0); X} X X/* Little routines to pop up the help window and make it go away again */ X/* They only get called when display is in use. */ X Xreveal_help(side) XSide *side; X{ X XMapWindow(side->help); X return TRUE; X} X Xconceal_help(side) XSide *side; X{ X XUnmapWindow(side->help); X} X X/* Shut a single display down, but only if there's one to operate on. */ X/* Hit the display slot, for safety. */ X Xclose_display(side) XSide *side; X{ X XCloseDisplay(sd()->disp); X side->display = (long) NULL; X} END_OF_X10.c if test 28618 -ne `wc -c <X10.c`; then echo shar: \"X10.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f lib/1987.map -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"lib/1987.map\" else echo shar: Extracting \"lib/1987.map\" \(7700 characters\) sed "s/^X//" >lib/1987.map <<'END_OF_lib/1987.map' XXconq 1 -----+ Cities in 1987, keyed to the 1-degree map Xearth1.map XUnits 362 1 0 X* Stockholm 137,120 -1 X* Leningrad 149,120 -1 X* Niznij*Tagil 180,119 -1 X* Jaroslavi 160,118 -1 X* Krasnojarsk 213,118 -1 X* Riga 146,117 -1 X@ Gorky 165,117 -1 X* Sverdlovsk 182,117 -1 X* T'umen' 187,117 -1 X* Tomsk 206,117 -1 X* Belfast 115,116 -1 X@ Glasgow 117,116 -1 X* Newcastle 119,116 -1 X@ Copenhagen 134,116 -1 X@ Moscow 159,116 -1 X@ Novosibirsk 204,116 -1 X* Hull 122,115 -1 X* Konigsberg 143,115 -1 X* Vilnius 148,115 -1 X* Chelabinsk 184,115 -1 X* Kurgan 188,115 -1 X* Petropavlovsk 192,115 -1 X* Omsk 196,115 -1 X* Kemerovo 208,115 -1 X* Edmonton 9,114 -1 X* Dublin 116,114 -1 X@ Manchester 120,114 -1 X@ Hamburg 132,114 -1 X* Gdansk 141,114 -1 X* Minsk 150,114 -1 X* Br'ansk 157,114 -1 X* Kujbyshev 173,114 -1 X* Magnitogorsk 182,114 -1 X* Barnaul 205,114 -1 X* Novokuzneck 210,114 -1 X/ P.*Kamchatkij 282,114 -1 X@ London 123,113 -1 X@ Rotterdam 128,113 -1 X@ Berlin 137,113 -1 X* Warsaw 145,113 -1 X* Irkutsk 228,113 -1 X* Chita 237,113 -1 X* Calgary 9,112 -1 X* Bristol 119,112 -1 X/ Dover 124,112 -1 X* Dortmund 131,112 -1 X* Essen 132,112 -1 X* Orenburg 179,112 -1 X* Ulan*Ude 232,112 -1 X* Brussels 128,111 -1 X* Frankfurt 134,111 -1 X* Prague 139,111 -1 X@ Kiev 155,111 -1 X* Kharkov 161,111 -1 X* Blagoveshchenk 252,111 -1 X* Komsomol'sk 261,111 -1 X* Vancouver 2,110 -1 X* Winnipeg 27,110 -1 X* Le*Havre 125,110 -1 X* Karaganda 198,110 -1 X* Ust'*Kamenogorsk 207,110 -1 X@ Paris 128,109 -1 X* Stuttgart 135,109 -1 X* Munich 137,109 -1 X* Vienna 142,109 -1 X* Dnepropetrovsk 161,109 -1 X@ Doneck 163,109 -1 X* Volgograd 170,109 -1 X* Chabarovsk 261,109 -1 X@ Seattle 4,108 -1 X* St.*John's 72,108 -1 X* Nantes 124,108 -1 X* Budapest 145,108 -1 X* Ulaan*Bataar 232,108 -1 X* Qiqihaer 249,108 -1 X* Odessa 157,107 -1 X* Astrachan' 175,107 -1 X* Portland 4,106 -1 X@ Montreal/Quebec 53,106 -1 X* Lyon 131,106 -1 X* Torino 134,106 -1 X@ Milan 136,106 -1 X* Zagreb 143,106 -1 X@ Haerbin 253,106 -1 X* Minneapolis-St.*Paul 34,105 -1 X@ Toronto 49,105 -1 X* Bordeaux 127,105 -1 X* Nice 134,105 -1 X* Genoa 136,105 -1 X* Belgrade 148,105 -1 X* Bucharest 154,105 -1 X* Milwaukee 39,104 -1 X* Bilbao 125,104 -1 X* Toulouse 129,104 -1 X* Marseilles 132,104 -1 X* Alma-Ata 204,104 -1 X* Changchun 253,104 -1 X* Vladivostok 259,104 -1 X* Sapporo 269,104 -1 X@ Detroit 45,103 -1 X* Buffalo 50,103 -1 X* Rochester 52,103 -1 X@ Boston 57,103 -1 X* Sofia 152,103 -1 X* Frunze 203,103 -1 X* Omaha 33,102 -1 X@ Chicago 41,102 -1 X* Porto 120,102 -1 X* Zaragoza 128,102 -1 X* Barcelona 131,102 -1 X* Rome 142,102 -1 X@ Istanbul 157,102 -1 X* Tbilisi 173,102 -1 X@ Tashkent 198,102 -1 X@ Shengyang 252,102 -1 X* Changjin 258,102 -1 X* Salt*Lake*City 18,101 -1 X* Cleveland 48,101 -1 X* Pittsburgh 50,101 -1 X@ New*York 56,101 -1 X@ Madrid 126,101 -1 X* Thessaloniki 153,101 -1 X* Baku 179,101 -1 X* Baoding 244,101 -1 X* Aomori 270,101 -1 X@ Denver 25,100 -1 X* Kansas*City 35,100 -1 X* Indianapolis 43,100 -1 X* Cincinnati 45,100 -1 X@ Philadelphia 54,100 -1 X* Valencia 129,100 -1 X* Ankara 162,100 -1 X* Erzurum 171,100 -1 X* Jerevan 174,100 -1 X@ Beijing 246,100 -1 X* Dairen 251,100 -1 X* Pyongyang 255,100 -1 X* Sacramento 9,99 -1 X* St.*Louis 40,99 -1 X@ Washington*DC 53,99 -1 X@ Lisbon 122,99 -1 X/ Cordoba 125,99 -1 X* Athens 154,99 -1 X* Izmir 158,99 -1 X* Tabriz 177,99 -1 X* Dusanbe 199,99 -1 X* Tianjin 248,99 -1 X* Sendai 271,99 -1 X@ San*Francisco 8,98 -1 X* Wichita 33,98 -1 X* Palermo 144,98 -1 X* Adana 166,98 -1 X@ Taiyuan 243,98 -1 X@ Seoul 257,98 -1 X* Niigata 269,98 -1 X* Tulsa 36,97 -1 X* Nashville 45,97 -1 X* Norfolk 55,97 -1 X@ Algiers 135,97 -1 X* Tunis 142,97 -1 X* Aleppo 169,97 -1 X* Mashhad 191,97 -1 X* Xining 233,97 -1 X* Kanazawa 268,97 -1 X* Albuquerque 25,96 -1 X* Oklahoma*City 34,96 -1 X* Oran 132,96 -1 X* Tehran 183,96 -1 X* Zhengzhou 245,96 -1 X* Kwangjin 258,96 -1 X* Pusan 260,96 -1 X@ Nagoya 269,96 -1 X@ Tokyo 271,96 -1 X@ Los*Angeles 14,95 -1 X* Kabul 202,95 -1 X@ Xi'an 241,95 -1 X* Xuzhou 250,95 -1 X* Hiroshima 266,95 -1 X@ Osaka 268,95 -1 X* Phoenix 20,94 -1 X* Birmingham 46,94 -1 X* Atlanta 48,94 -1 X* Casablanca 125,94 -1 X* Fez 127,94 -1 X* Fukuoka 263,94 -1 X* San*Diego 17,93 -1 X@ Dallas/Ft*Worth 37,93 -1 X@ Tel*Aviv 169,93 -1 X* Baghdad 179,93 -1 X* Esfahan 185,93 -1 X* Huainan 250,93 -1 X@ Nanjing 252,93 -1 X* Tucson 23,92 -1 X* El*Paso 27,92 -1 X* Marrakech 126,92 -1 X* Benghazi 154,92 -1 X@ Alexandria 164,92 -1 X* Qandahar 199,92 -1 X* Lahore 208,92 -1 X* Kagoshima 264,92 -1 X* New*Orleans 44,91 -1 X* Jacksonville 53,91 -1 X* Tripoli 151,91 -1 X* Multan 206,91 -1 X* Chengdu 239,91 -1 X@ Wuhan 249,91 -1 X* San*Antonio 36,90 -1 X@ Houston 39,90 -1 X@ Cairo 164,90 -1 X@ Chonqing 241,90 -1 X* Ningbao 256,90 -1 X* Chihuahua 29,89 -1 X/ Las*Palmas 119,89 -1 X@ Delhi 213,89 -1 X* Changsha 248,89 -1 X* Nanchang 251,89 -1 X* Tampa 53,88 -1 X* Asyut 168,87 -1 X* Jaipur 212,87 -1 X* Kanpur 216,87 -1 X* Fuzhou 256,87 -1 X* Naha 264,87 -1 X* Monterrey 36,86 -1 X* Miami 56,86 -1 X@ Karachi 203,86 -1 X* Allahabad 218,86 -1 X* Patna 222,86 -1 X* Kunming 239,86 -1 X* Aswan 170,85 -1 X* T'aipei 259,85 -1 X* Ahmadabad 210,84 -1 X* Bhopal 215,84 -1 X* Dacca 228,84 -1 X* Guangzhou 250,84 -1 X* San*Luis*Potosi 37,83 -1 X* La*Habana 56,83 -1 X@ Calcutta 227,83 -1 X* Mandalay 235,83 -1 X@ Hong*Kong 253,83 -1 X* Kaohsiun 259,83 -1 X* Honolulu 341,82 -1 X* Mecca 178,82 -1 X* Surat 212,82 -1 X* Nagpur 218,82 -1 X* Ha-noi 244,82 -1 X* Guadalajara 36,81 -1 X* Santiago*de*Cuba 64,81 -1 X@ Mexico*City 40,80 -1 X* Veracruz 43,80 -1 X* Haikou 250,80 -1 X* Kingston 64,79 -1 X* Port-au-Prince 68,79 -1 X* Santo*Domingo 71,79 -1 X* San*Juan 74,79 -1 X@ Bombay 214,79 -1 X* Poona 216,78 -1 X* Hyderabad 219,78 -1 X* Rangoon 237,78 -1 X* Khartoum 174,76 -1 X/ Asmera 180,76 -1 X* Da-nang 249,76 -1 X* Tegucigalpa 55,75 -1 X* Dakar 125,75 -1 X@ Manila 263,75 -1 X/ San*Salvador 53,74 -1 X* Aden 187,74 -1 X* Bangalore 220,74 -1 X* Madras 222,74 -1 X* Bangkok 243,74 -1 X* Managua 57,73 -1 X/ Bamako 135,73 -1 X* Kano 152,73 -1 X* Coimbatore 220,72 -1 X* Phnom-Penh 248,72 -1 X* Baranquilla 69,71 -1 X* Maracaibo 72,71 -1 X@ Caracas 78,71 -1 X* Sai-gon 252,71 -1 X* Cebu 268,71 -1 X* Panama*City 65,70 -1 X* Conakry 131,70 -1 X/ Ogbomosho 66,69 -1 X* Adis*Adeba 184,69 -1 X* Cucuta 73,68 -1 X* Kumasi 143,68 -1 X* Panama*Canal 157,68 -1 X* Medellin 71,67 -1 X* Accra 146,67 -1 X* Lagos 150,67 -1 X* Colombo 227,67 -1 X* Abidjan 142,66 -1 X* Bogota 73,65 -1 X* Port*Harcourt 155,65 -1 X* Douala 158,65 -1 X* Yaounde 160,65 -1 X* Cali 71,64 -1 X* Medan 246,64 -1 X* Kuala*Lumpur 249,64 -1 X* Mogadishu 194,63 -1 X@ Singapore 252,62 -1 X* Mboudaka 168,61 -1 X* Quito 71,60 -1 X* Belem 102,59 -1 X* Kampala 183,59 -1 X* Nairobi 187,59 -1 X* Palembang 253,59 -1 X* Guayaquil 71,58 -1 X* Iquitos 78,57 -1 X* Manaus 91,57 -1 X* Banjarmasin 266,57 -1 X* Fortaleza 113,56 -1 X* Kinshasa 167,56 -1 X/ Mombasa 191,56 -1 X* Matadi 166,55 -1 X* Ujung*Pendang 272,55 -1 X@ Jakarta 260,54 -1 X* Dar-es-Salaam 192,53 -1 X* Surabaya 266,53 -1 X* Recife 118,52 -1 X* Luanda 167,52 -1 X* Port*Moresby 302,51 -1 X* Lubumbashi 183,49 -1 X* Lima 79,48 -1 X* Salvador 117,48 -1 X/ Darwin 287,48 -1 X* Blantyre 192,45 -1 X* Majanga 204,45 -1 X* La*Paz 89,44 -1 X* Goiania 108,44 -1 X/ Cairns 303,43 -1 X* Salisbury 190,42 -1 X* Antananarivo 206,42 -1 X* Belo*Horizonte 116,41 -1 X@ Rio*de*Janeiro 117,38 -1 X* Antofagasta 91,37 -1 X@ Sao*Paulo 115,37 -1 X* Asuncion 105,35 -1 X* Curitiba 113,35 -1 X* Cordoba 97,34 -1 X@ Johannesburg 191,34 -1 X* Brisbane 316,33 -1 X* Porto*Alegre 113,31 -1 X* Foo*Bar 191,31 -1 X* Bloemfontein 100,30 -1 X* Durban 195,30 -1 X* Valparaiso 94,28 -1 X* Mendoza 97,28 -1 X* Unknown 105,28 -1 X* Perth 282,28 -1 X* Santiago 96,27 -1 X@ Buenos*Aires 108,27 -1 X* Montevideo 110,27 -1 X* Cape*Town 185,27 -1 X* Port*Elizabeth 192,27 -1 X@ Sydney 317,27 -1 X* Adelaide 306,26 -1 X* Canberra 316,25 -1 X* Mar*del*Plata 110,24 -1 X* Auckland 342,24 -1 X@ Melbourne 314,23 -1 X/ Hobart 319,17 -1 X* Christchurch 344,17 -1 END_OF_lib/1987.map if test 7700 -ne `wc -c <lib/1987.map`; then echo shar: \"lib/1987.map\" unpacked with wrong size! fi # end of overwriting check fi if test -f phases.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"phases.c\" else echo shar: Extracting \"phases.c\" \(15072 characters\) sed "s/^X//" >phases.c <<'END_OF_phases.c' X/* Copyright (c) 1987, 1988 Stanley T. Shebs, University of Utah. */ X/* This program may be used, copied, modified, and redistributed freely */ X/* for noncommercial purposes, so long as this notice remains intact. */ X X/* RCS $Header: phases.c,v 1.1 88/06/21 12:30:38 shebs Exp $ */ X X/* This file includes all turn phases except init, movement, and endgame. */ X X#include "config.h" X#include "misc.h" X#include "dir.h" X#include "period.h" X#include "side.h" X#include "unit.h" X#include "map.h" X#include "global.h" X X/* Should probably be in period.h */ X X#define will_garrison(u1, u2) (utypes[u1].guard[u2] > 0) X X/* Spying phase reveals other sides' secrets. This phase also automatically */ X/* updates allies's view of each other's units; not every turn, but fairly */ X/* regularly (can do briefing at any time, of course). Spying will reveal */ X/* hex even if never seen before (dubious). */ X Xspy_phase() X{ X Side *side, *other; X X if (Debug) printf("Entering spy phase\n"); X for_all_sides(side) { X if (probability(period.spychance)) { X other = side_n(random(numsides)); X if (other != NULL && !other->lost && !allied_side(side, other)) { X if (period.spychance < 20) { X notify(side, "You found out some of the %s dispositions!!", X other->name); X } X reveal_side(other, side, period.spyquality); X } X } X for_all_sides(other) { X if (allied_side(other, side) && side != other && probability(20)) { X reveal_side(side, other, 100); X } X } X } X} X X/* The disaster phase handles revolts, surrenders, accidents, and attrition. */ X/* Note that accidents and attrition happen even if unit changes sides. */ X/* Also, revolts happen first, so something that revolts may subsequently */ X/* surrender to nearby unit. */ X Xdisaster_phase() X{ X Unit *unit; X X if (Debug) printf("Entering disaster phase\n"); X for_all_units(unit) { X if (alive(unit)) unit_revolt(unit); X if (alive(unit)) unit_surrender(unit); X if (alive(unit)) unit_accident(unit); X if (alive(unit)) unit_attrition(unit); X } X} X X/* A unit revolts by going back to its "true side" (which is usually set at */ X/* unit creation time). The base revolt chance is worst case if morale is */ X/* variable; a unit at maximum (nonzero) morale will never revolt. */ X Xunit_revolt(unit) XUnit *unit; X{ X int u = unit->type, maxmor, chance; X Side *oldside = unit->side; X X if (utypes[u].revolt > 0) { X chance = utypes[u].revolt; X maxmor = utypes[u].maxmorale; X if (maxmor > 0) chance = (chance * (maxmor - unit->morale)) / maxmor; X if (unit->trueside != oldside && random(10000) < chance) { X notify(oldside, "%s revolts!", unit_handle(oldside, unit)); X unit_changes_side(unit, unit->trueside, CAPTURE, DISASTER); X see_exact(oldside, unit->x, unit->y); X draw_hex(oldside, unit->x, unit->y, TRUE); X all_see_hex(unit->x, unit->y); X } X } X} X X/* Units may also surrender to adjacent enemy units, but only to a type */ X/* that is both visible and capable of capturing the unit surrendering. */ X/* Neutrals have to be treated differently, since they don't have a view */ X/* to work from. We sort of compute the view "on the fly". */ X Xunit_surrender(unit) XUnit *unit; X{ X bool surrounded = TRUE; X int u = unit->type, chance, d, x, y, view; X Unit *unit2, *eunit = NULL; X Side *us = unit->side, *es; X X if (utypes[u].surrender > 0 || utypes[u].siege > 0) { X chance = 0; X for_all_directions(d) { X x = wrap(unit->x + dirx[d]); y = limit(unit->y + diry[d]); X if (neutral(unit)) { X if (((unit2 = unit_at(x, y)) != NULL) && X (probability(utypes[unit2->type].visibility)) && X (could_capture(unit2->type, u))) { X chance += utypes[u].surrender; X eunit = unit2; X } else { X surrounded = FALSE; X } X } else { X view = side_view(us, x, y); X if (view == EMPTY || view == UNSEEN) { X surrounded = FALSE; X } else { X es = side_n(vside(view)); X if (enemy_side(us, es) && could_capture(vtype(view), u)) { X chance += utypes[u].surrender; X if (unit_at(x, y)) eunit = unit_at(x, y); X } X } X } X } X if (surrounded && eunit) chance += utypes[u].siege; X if (random(10000) < chance) { X if (eunit) { X notify(eunit->side, "%s has surrendered to you!", X unit_handle(eunit->side, unit)); X notify(us, "%s has surrendered to the %s!", X unit_handle(us, unit), plural_form(eunit->side->name)); X capture_unit(eunit, unit); X } X } X } X} X X/* Accidents will happen!... Kill off any occupants of course. */ X Xunit_accident(unit) XUnit *unit; X{ X int u = unit->type; X Side *us = unit->side; X X if (random(10000) < utypes[u].accident[terrain_at(unit->x, unit->y)]) { X notify(us, "%s %s!", unit_handle(us, unit), utypes[u].accidentmsg); X kill_unit(unit, DISASTER); X } X} X X/* Attrition only takes out a few hp at a time, but can be deadly... */ X/* Occupants lost only if unit lost (do we care?) */ X Xunit_attrition(unit) XUnit *unit; X{ X int u = unit->type; X Side *us = unit->side; X X if (random(10000) < utypes[u].attrition[terrain_at(unit->x, unit->y)]) { X unit->hp -= utypes[u].attdamage; X notify(us, "%s %s!%s", X unit_handle(us, unit), utypes[u].attritionmsg, X (unit->hp <= 0 ? " The blow is fatal!" : "")); X if (unit->hp <= 0) kill_unit(unit, DISASTER); X } X} X X/* Repair always proceeds each turn, as long as the repairing unit is not */ X/* crippled. A unit can repair itself, its transport, and its occupants. */ X X/* Another activity of units is to build other units. The code here has to */ X/* be a little tricky because players need to get opportunities to cancel */ X/* and to idle units, plus not get asked about units that don't usually */ X/* produce things. */ X X/* The order of repair vs building means scarce supplies used on existing */ X/* units first. */ X Xbuild_phase() X{ X Unit *unit, *occ; X X if (Debug) printf("Entering build phase\n"); X for_all_units(unit) { X if (alive(unit) && !cripple(unit)) { X repair_unit(unit, unit); X for_all_occupants(unit, occ) repair_unit(unit, occ); X if (unit->transport != NULL) repair_unit(unit, unit->transport); X work_on_new_unit(unit); X } X } X} X X/* One arbitrary unit repairs another only if actually needed. Rate is */ X/* always less than 1 hp/turn; this is a practical limit on max hp values */ X/* if reasonably rapid repair is desired. If unit being repaired was badly */ X/* damaged (crippled), then we'll use up same resources as needed for */ X/* construction, and if a resource type is missing, then repairs will not */ X/* proceed at all. */ X Xrepair_unit(unit, unit2) XUnit *unit, *unit2; X{ X int u = unit->type, u2 = unit2->type, r; X X if ((unit2->hp < utypes[u2].hp) && could_repair(u, u2)) { X if ((global.time % utypes[u].repair[u2]) == 0) { X if (cripple(unit2)) { X for_all_resource_types(r) { X if (unit->supply[r] < utypes[u2].tomake[r]) return; X } X for_all_resource_types(r) X unit->supply[r] -= utypes[u2].tomake[r] / utypes[u2].hp; X } X unit2->hp++; X } X } X} X X/* Machine players need opportunities to change their production. */ X/* Neutrals never produce (what could they do with the results?). */ X/* Construction may be constrained by lack of resources, so don't count */ X/* down on schedule or use up building materials unless we actually have */ X/* enough. */ X Xwork_on_new_unit(unit) XUnit *unit; X{ X int u = unit->type, r; X X if (!neutral(unit)) { X if (producing(unit)) { X for_all_resource_types(r) { X if (unit->supply[r] < utypes[unit->product].tomake[r]) return; X } X for_all_resource_types(r) { X unit->supply[r] -= utypes[unit->product].tomake[r]; X } X unit->schedule--; X if (unit->schedule <= 0) { X if (complete_new_unit(unit, unit->product)) { X if (!utypes[u].maker) { X set_product(unit, NOTHING); X } else { X set_schedule(unit); X } X } else { X unit->schedule++; X } X } X } else { X if (unit->schedule > 0) unit->schedule--; X } X } X} X X/* When one unit produces another, it may be that one can occupy the other, */ X/* in either direction. So we have to make sure that both ways work. */ X/* Also the builder may become the garrison, so we have to get it out of */ X/* the way before deciding about fiddling around. */ X/* Morale of new unit is slightly more than morale of building unit. */ X/* Returns success of the whole process. */ X Xcomplete_new_unit(unit, type) XUnit *unit; Xint type; X{ X bool success = FALSE; X int ux = unit->x, uy = unit->y; X Unit *mainunit, *newunit; X Side *us = unit->side; X X if (will_garrison(unit->type, type)) leave_hex(unit); X if ((newunit = create_unit(type, NULL)) != NULL) { X mainunit = unit_at(ux, uy); X if (mainunit == NULL) { X if (could_occupy(type, terrain_at(ux, uy))) { X assign_unit_to_side(newunit, us); X occupy_hex(newunit, ux, uy); X success = TRUE; X } else { X notify(us, "%s can't go here!", unit_handle(us, newunit)); X kill_unit(newunit, DISASTER); X } X } else if (could_carry(mainunit->type, type)) { X if (can_carry(mainunit, newunit)) { X assign_unit_to_side(newunit, us); X occupy_hex(newunit, ux, uy); X success = TRUE; X } else { X notify(us, "%s will delay completion of %s until it has room.", X unit_handle(us, unit), utypes[type].name); X kill_unit(newunit, -1); X } X } else if (could_carry(type, mainunit->type)) { X if (could_occupy(type, terrain_at(ux, uy))) { X assign_unit_to_side(newunit, us); X occupy_hex(newunit, ux, uy); X success = TRUE; X } else { X notify(us, "%s can't go here!", unit_handle(us, newunit)); X kill_unit(newunit, DISASTER); X } X } else { X notify(us, "Idiots! - %s can't build a %s in a %s!\n", X unit_handle(us, unit), X utypes[type].name, utypes[mainunit->type].name); X kill_unit(newunit, DISASTER); X } X } X if (will_garrison(unit->type, type)) occupy_hex(unit, ux, uy); X if (success) { X if (utypes[type].named) newunit->name = make_unit_name(newunit); X newunit->morale = min(newunit->morale, unit->morale + 1); X unit->built++; X (us->balance[type][PRODUCED])++; X (us->units[type])++; X if (will_garrison(unit->type, type)) kill_unit(unit, GARRISON); X update_state(us, type); X if (Debug) printf("%s is completed\n", unit_handle(NULL, newunit)); X } X return success; X} X X/* The main routine does production, distribution, and discarding in order. */ X Xsupply_phase() X{ X int u, r, t, amt, dist, x, y, x1, y1, x2, y2; X Unit *unit, *ounit, *occ; X X if (Debug) printf("Entering supply phase\n"); X flush_dead_units(); X /* Make new resources but don't clip to storage capacity yet */ X for_all_units(unit) { X u = unit->type; X for_all_resource_types(r) { X t = terrain_at(unit->x, unit->y); X amt = (utypes[u].produce[r] * utypes[u].productivity[t]) / 100; X if (cripple(unit)) X amt = (amt * unit->hp) / (utypes[u].crippled + 1); X unit->supply[r] += amt; X } X } X /* Move stuff around - hopefully will get rid of any excess */ X for_all_units(unit) { X for_all_resource_types(r) { X dist = utypes[unit->type].outlength[r]; X y1 = unit->y - dist; X y2 = unit->y + dist; X for (y = y1; y <= y2; ++y) { X if (between(0, y, world.height-1)) { X x1 = unit->x - (y < unit->y ? (y - y1) : dist); X x2 = unit->x + (y > unit->y ? (y2 - y) : dist); X for (x = x1; x <= x2; ++x) { X ounit = unit_at(wrap(x), y); X if (ounit != NULL && alive(ounit) && X ounit->side == unit->side) { X try_transfer(unit, ounit, r); X for_all_occupants(ounit, occ) X try_transfer(unit, occ, r); X } X } X } X } X } X } X /* Throw away any excess */ X for_all_units(unit) { X u = unit->type; X for_all_resource_types(r) { X unit->supply[r] = min(unit->supply[r], utypes[u].storage[r]); X } X } X} X X/* The middle subphase of supply uses this routine to move supplies around */ X/* between units far apart or on the same hex. */ X Xtry_transfer(from, to, r) XUnit *from, *to; Xint r; X{ X int nd; X X if (from == to) return; X if (utypes[to->type].inlength[r] >= X distance(from->x, from->y, to->x, to->y)) { X if ((nd = utypes[to->type].storage[r] - to->supply[r]) > 0) { X if (can_satisfy_need(from, r, nd)) { X transfer_supply(from, to, r, nd); X } else if (can_satisfy_need(from, r, max(1, nd/2))) { X transfer_supply(from, to, r, max(1, nd/2)); X } X } X } X} X X/* This estimates what can be spared. Note that total transfer of requested */ X/* amount is not a good idea, since the supplies might be essential to the */ X/* unit that has them first. If we're more than half full, or the request */ X/* is less than 1/5 of our supply, then we can spare it. */ X Xcan_satisfy_need(unit, r, need) XUnit *unit; Xint r, need; X{ X return (((2 * unit->supply[r]) > (utypes[unit->type].storage[r])) || X (need < (utypes[unit->type].storage[r] / 5))); X} X X/* Move supply from one unit to another. Don't move more than is possible; */ X/* check both from and to amounts and capacities. */ X Xtransfer_supply(from, to, r, amount) XUnit *from, *to; Xint r, amount; X{ X amount = min(amount, from->supply[r]); X amount = min(amount, utypes[to->type].storage[r] - to->supply[r]); X from->supply[r] -= amount; X to->supply[r] += amount; X if (Debug) printf("%s receives %d %s\n", X unit_handle(NULL, to), amount, rtypes[r].name); X return amount; X} X X/* Handle constant consumption, which is a post process to movement. */ X/* Don't care about current side in this phase. This is also a handy */ X/* place to count up all of a side's resources, for use by win/lose tests. */ X Xconsumption_phase() X{ X int r; X Unit *unit; X Side *side; X X if (Debug) printf("Entering consumption phase\n"); X for_all_sides(side) { X for_all_resource_types(r) { X side->resources[r] = 0; X } X } X for_all_units(unit) { X if (alive(unit)) { X unit_consumes(unit); X } X } X} X X/* Consume the constant overhead part of supply consumption. */ X/* Usage by movement is subtracted from overhead first. */ X/* Finally, credit side with the unit's remaining supplies. */ X Xunit_consumes(unit) XUnit *unit; X{ X int u = unit->type, r, usedup; X X for_all_resource_types(r) { X if (utypes[u].consume[r] > 0) { X usedup = unit->actualmoves * utypes[u].tomove[r]; X if (usedup < utypes[u].consume[r]) X unit->supply[r] -= (utypes[u].consume[r] - usedup); X if (unit->supply[r] <= 0 && !in_supply(unit)) { X exhaust_supply(unit); X return; X } X } X if (!neutral(unit)) unit->side->resources[r] += unit->supply[r]; X } X} X X/* What happens to a unit that runs out of a supply. If it can survive */ X/* on no supplies, then there may be a few turns of grace, depending on */ X/* how the dice roll... */ X Xexhaust_supply(unit) XUnit *unit; X{ X if (probability(100 - utypes[unit->type].survival)) { X notify(unit->side, "%s %s!", X unit_handle(unit->side, unit), utypes[unit->type].starvemsg); X kill_unit(unit, STARVATION); X } X} X X/* Check if the unit has ready access to a source of supplies. */ X Xin_supply(unit) XUnit *unit; X{ X if (unit->transport != NULL) return TRUE; X /* needs to be more sophisticated and account for supply lines */ X return FALSE; X} END_OF_phases.c if test 15072 -ne `wc -c <phases.c`; then echo shar: \"phases.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 9 \(of 18\). cp /dev/null ark9isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 18 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0