[comp.sources.games] v04i097: xconq5 - version 5 of the strategy game for X-windows and curses, Part09/18

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