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

games@tekred.TEK.COM (06/29/88)

Submitted by: "Stanley T. Shebs" <shebs%defun@cs.utah.edu>
Comp.sources.games: Volume 4, Issue 90
Archive-name: xconq5/Part02



#! /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 2 (of 18)."
# Contents:  X11.c init.c
# Wrapped by billr@saab on Wed Jun 29 08:55:29 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f X11.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"X11.c\"
else
echo shar: Extracting \"X11.c\" \(35753 characters\)
sed "s/^X//" >X11.c <<'END_OF_X11.c'
X/* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
X/* Copyright 1988 by Chris D. Peterson, MIT. */
X/* Many improvements by Tim Moore, 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: X11.c,v 1.1 88/06/21 12:30:00 shebs Exp $ */
X
X/* Interface implementations for the X11 version of xconq. */
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/* careful of the path of the X header files. */
X
X#ifdef UNIX
X#include <signal.h>   /* needed for ^C disabling */
X#include <X11/Xlib.h>
X#include <X11/Xutil.h>
X#endif UNIX
X
X/* various bitmap definitions. */
X
X#define dots_width 16
X#define dots_height 16
Xstatic char dots_bits[] = {
X   0x01, 0x01,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x10, 0x10,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x01, 0x01,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x10, 0x10,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
X
X#define mask_width 16
X#define mask_height 16
Xstatic char mask_bits[] = {
X   0xe0, 0x03,  0xd8, 0x0f,  0xb4, 0x19,  0x8a, 0x21, 
X   0x86, 0x61,  0x85, 0x41,  0x83, 0xc1,  0xff, 0xff, 
X   0xff, 0xff,  0x83, 0xc1,  0x82, 0xa1,  0x86, 0x61, 
X   0x84, 0x51,  0x98, 0x2d,  0xf0, 0x1b,  0xc0, 0x07};
X
X#define curs_width 16
X#define curs_height 16
Xstatic char curs_bits[] = {
X   0xe0, 0x03,  0x98, 0x0c,  0x84, 0x10,  0x82, 0x20, 
X   0x82, 0x20,  0x81, 0x40,  0x81, 0x40,  0xff, 0x7f, 
X   0x81, 0x40,  0x81, 0x40,  0x82, 0x20,  0x82, 0x20, 
X   0x84, 0x10,  0x98, 0x0c,  0xe0, 0x03,  0x00, 0x00};
X
X#define bomb1_width 32
X#define bomb1_height 32
Xstatic char bomb1_bits[] = {
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0xc0,  0x01, 0x00,  0x00, 0xf0,  0x07, 0x00, 
X   0x00, 0xf0,  0x07, 0x00,  0x00, 0xf8,  0x0f, 0x00, 
X   0x00, 0xf8,  0x0f, 0x00,  0x00, 0xfc,  0x0f, 0x00, 
X   0x00, 0xfe,  0x1f, 0x00,  0x00, 0xfe,  0x3f, 0x00, 
X   0x00, 0xfe,  0x3f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
X
X#define bomb2_width 32
X#define bomb2_height 32
Xstatic char bomb2_bits[] = {
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0xf8,  0x01, 0x00, 
X   0x00, 0xf8,  0x07, 0x00,  0x00, 0xfc,  0x0f, 0x00, 
X   0x00, 0xfc,  0x1f, 0x00,  0x00, 0xfe,  0x1f, 0x00, 
X   0x00, 0xfe,  0x3f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
X   0x00, 0xfc,  0x0f, 0x00,  0x00, 0xf0,  0x07, 0x00, 
X   0x00, 0xf0,  0x03, 0x00,  0x00, 0xe0,  0x03, 0x00, 
X   0x00, 0xf0,  0x07, 0x00,  0x00, 0xf0,  0x07, 0x00, 
X   0x00, 0xf0,  0x0f, 0x00,  0x00, 0xf0,  0x0f, 0x00, 
X   0x00, 0xf8,  0x0f, 0x00,  0x00, 0xf8,  0x1f, 0x00, 
X   0x00, 0xf8,  0x1f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
X   0x00, 0xff,  0x7f, 0x00,  0xc0, 0xff,  0xff, 0x03, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
X
X#define bomb3_width 32
X#define bomb3_height 32
Xstatic char bomb3_bits[] = {
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0xfe, 0xe2,  0xa3, 0x3f, 
X   0x00, 0xfc,  0x1f, 0x00,  0x3c, 0xff,  0x7f, 0x7c, 
X   0x80, 0xff,  0xff, 0x00,  0xc0, 0xff,  0xff, 0x01, 
X   0xc0, 0xff,  0xff, 0x01,  0xe0, 0xff,  0xff, 0x03, 
X   0xe0, 0xff,  0xff, 0x03,  0xe0, 0xff,  0xff, 0x03, 
X   0xe0, 0xff,  0xff, 0x01,  0xe0, 0xff,  0xff, 0x49, 
X   0x82, 0xff,  0xff, 0x34,  0x14, 0xfe,  0x3f, 0x42, 
X   0xe2, 0xff,  0x9f, 0x34,  0x40, 0xfe,  0x3f, 0x41, 
X   0xbe, 0xfd,  0xdf, 0x1e,  0x00, 0xf8,  0x1f, 0x01, 
X   0xfe, 0xfd,  0xdf, 0x7f,  0x00, 0xfc,  0x1f, 0x00, 
X   0x00, 0xfc,  0x1f, 0x00,  0x00, 0xfc,  0x3f, 0x00, 
X   0x00, 0xfe,  0x1f, 0x00,  0x00, 0xfe,  0x3f, 0x00, 
X   0x00, 0xff,  0x3f, 0x00,  0xc0, 0xff,  0xff, 0x00, 
X   0xfc, 0xff,  0xff, 0x3f,  0xfe, 0xff,  0xff, 0x7f, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
X
X#define bomb4_width 32
X#define bomb4_height 32
Xstatic char bomb4_bits[] = {
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0xc0,  0x07, 0x00, 
X   0x00, 0x78,  0x10, 0x00,  0x00, 0x0f,  0x46, 0x00, 
X   0x80, 0x61,  0x81, 0x00,  0xc0, 0x1c,  0x00, 0x01, 
X   0x40, 0x02,  0x00, 0x00,  0x20, 0x01,  0x00, 0x00, 
X   0x20, 0x01,  0x00, 0x00,  0x20, 0x00,  0x00, 0x00, 
X   0x20, 0x00,  0x00, 0x00,  0x40, 0x00,  0x00, 0x00, 
X   0x80, 0x00,  0x00, 0x00,  0x00, 0x02,  0x00, 0x00, 
X   0x00, 0x02,  0x00, 0x00,  0x00, 0x04,  0x00, 0x00, 
X   0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x04,  0x00, 0x00,  0x00, 0x02,  0x00, 0x00, 
X   0x00, 0x01,  0x00, 0x00,  0xc0, 0x00,  0x00, 0x00, 
X   0x2c, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
X   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
X
X/* This is the name of a family of programs, so argv[0] inadequate. */
X
X#define PROGRAMNAME "xconq"
X
X/* Name of default font - why is this wired in? */
X
X#define STANDARD "standard"
X
X/* Magic number meaning that this pixmap intentionally left blank. */
X
X#define NOPIXMAP 17
X
X#define INFOLINES 4
X#define DELAY 100000
X
X#define BH 32
X
X/* Use with caution - variable name "side" embedded! */
X
X#define sd() ((Screeno *) side->display)
X
X#define sdd() (((Screeno *) side->display)->disp)
X
Xtypedef unsigned int unint;
X
X/* GC rules are for different fonts etc, but not colors or bitmaps. */
X
Xtypedef struct a_screen {
X    Display *disp;
X    GC gc;			/* a tmp graphics context for this display */
X    GC flashgc;			/* The gc for drawing the flash lines. */
X    GC textgc;			/* foreground on background text */
X    GC icongc;			/* icon graphics context */
X    GC invicongc;		/* icon gc inverted colors. */
X    GC varicongc;		/* This is an icon gc with variable fgcolor. */
X    GC unitgc;			/* unit bitmap printing gc. */
X    GC unittextgc;		/* unit text printing gc. */
X    GC cleargc;			/* The gc to use for clearing areas. */
X    GC clearbitgc;              /* gc for clearing bitmaps */
X    XFontStruct *textfont;	/* font for text display */
X    XFontStruct *iconfont;	/* utility font with assorted icons */
X    XFontStruct *unitfont;	/* font for unit characters */
X    Pixmap bombpics[4];		/* mushroom clouds */
X    Pixmap unitpics[MAXUTYPES];	/* used instead of font sometimes */
X    Pixmap wbdots, bwdots;	/* blue border and dotted backgrounds */
X    Cursor curs;		/* the cursor object itself */
X} Screeno;
X
Xextern int giventime;
X
X/* Random function declarations. */
X
XXFontStruct * open_font();
XPixmap load_bitmap();
Xvoid get_font_size();
XCursor make_cursor();
X
X/* The array of screen objects. */
X
XScreeno screens[MAXSIDES];      /* All the "screen objects" */
X
X/* Values of parameters generally tied to fonts and the like. */
X
Xint hw = 20;
Xint hh = 22;
Xint hch = 17;
Xint margin = 2;
Xint bd = 1;
X
Xint helpwinlines = 1;           /* size of help window */
X
Xbool rootcursor;                /* true if using parent window's cursor */
X
X/* Put in a default player, probably the invoker of the program. */
X/* An empty host name will confuse everybody. */
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 be bad news. */
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/* Note that the open_display function syncronizes the X server when the */
X/* Debug flag is set. */
X
Xopen_display(side)
XSide *side;
X{
X    side->display = (long) &(screens[side_number(side)]);
X    sdd() = XOpenDisplay(side->host);
X    if (Debug) {
X      XSynchronize(sdd(), TRUE);
X      printf("Synching the X server.\n");
X    }
X    side->main = XCreateSimpleWindow(sdd(), DefaultRootWindow(sdd()),
X				     50, 3, 100, 100,
X				     3, white_color(side), black_color(side));
X    return (sdd() != NULL);
X}
X
X/* A predicate that tests whether our display can safely be written to. */
X
Xactive_display(side)
XSide *side;
X{
X    return (side && side->host && !side->lost && side->display);
X}
X
Xdisplay_width(side)
XSide *side;
X{
X    return ((19 * XDisplayWidth(sdd(), 0)) / 20);
X}
X
Xdisplay_height(side)
XSide *side;
X{
X    return ((19 * XDisplayHeight(sdd(), 0)) / 20);
X}
X
X/* Most X displays have enough screen to do a world map. */
X
Xworld_display(side) Side *side; {  return TRUE;  }
X
X/* Could use handlers for X failures... */
X
X/* Do misc setup thingies. */
X
X/* 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/* X11 also needs gazillions of GCs, since we've got so many fonts and */
X/* colors and bitmaps. */
X
Xinit_misc(side)
XSide *side;
X{
X    int u, w, h;
X    unsigned long mask;
X    XGCValues values;
X    Pixmap mmask, mcurs, dots;
X    GC gc;
X
X    side->margin = margin;
X    side->bd = bd;
X    side->hw = hw;
X    side->hh = hh;
X    side->hch = hch;
X    mask = GCForeground | GCBackground;
X    values.foreground = side->fgcolor;
X    values.background = side->bgcolor;
X    gc = XCreateGC(sdd(), side->main, mask, &values);
X    sd()->gc = XCreateGC(sdd(), side->main, mask, &values);
X    sd()->flashgc = XCreateGC(sdd(), side->main, mask, &values);
X    sd()->textgc = XCreateGC(sdd(), side->main, mask, &values);
X    sd()->icongc = XCreateGC(sdd(), side->main, mask, &values);
X    sd()->varicongc = XCreateGC(sdd(), side->main, mask, &values);
X    sd()->unitgc = XCreateGC(sdd(), side->main, mask, &values);
X    sd()->unittextgc = XCreateGC(sdd(), side->main, mask, &values);
X    values.foreground = side->bgcolor;
X    values.background = side->fgcolor;
X    sd()->invicongc = XCreateGC(sdd(), side->main, mask, &values);
X    values.function = GXclear;
X    mask = GCFunction;
X    sd()->cleargc = XCreateGC(sdd(), side->main, mask, &values);
X
X    sd()->textfont = open_font(side, TEXTFONT, "TextFont", NULL);
X    get_font_size(sd()->textfont, &(side->fw), &(side->fh) );
X    sd()->iconfont = open_font(side, ICONFONT, "IconFont", sd()->textfont);
X    get_font_size(sd()->iconfont, &(side->hw), &(side->hh) );
X    if (period.fontname != NULL && strlen(period.fontname) > 0) {
X	sd()->unitfont = 
X	    open_font(side, period.fontname, "UnitFont", sd()->textfont);
X	get_font_size(sd()->unitfont, &(side->uw), &(side->uh) );
X    } else {
X      	sd()->unitfont = 
X	    open_font(side, STANDARD, "UnitFont", sd()->textfont);
X	get_font_size(sd()->unitfont, &(side->uw), &(side->uh) );
X    }
X    XSetFont(sdd(), sd()->textgc, sd()->textfont->fid);
X    XSetFont(sdd(), sd()->icongc, sd()->iconfont->fid);
X    mask = GCFillStyle | GCGraphicsExposures;
X    values.fill_style = FillSolid;
X    values.graphics_exposures = FALSE;
X    XChangeGC(sdd(), sd()->unitgc, mask, &values);
X    XSetFont(sdd(), sd()->unittextgc, sd()->unitfont->fid);
X    XSetFont(sdd(), sd()->invicongc, sd()->iconfont->fid);
X    XSetFont(sdd(), sd()->varicongc, sd()->iconfont->fid);
X    XSetFunction(sdd(), sd()->flashgc, GXinvert);
X
X    mmask = XCreateBitmapFromData(sdd(), side->main,
X					mask_bits, mask_width, mask_height);
X    mcurs = XCreateBitmapFromData(sdd(), side->main,
X					curs_bits, curs_width, curs_height);
X
X    dots  = XCreateBitmapFromData(sdd(), side->main, 
X				  dots_bits, dots_width, dots_height);
X
X    sd()->bombpics[0] = XCreateBitmapFromData(sdd(), side->main,
X	bomb1_bits, bomb1_width, bomb1_height);
X    sd()->bombpics[1] = XCreateBitmapFromData(sdd(), side->main,
X        bomb2_bits, bomb2_width, bomb2_height);
X    sd()->bombpics[2] = XCreateBitmapFromData(sdd(), side->main,
X	bomb3_bits, bomb3_width, bomb3_height);
X    sd()->bombpics[3] = XCreateBitmapFromData(sdd(), side->main,
X	bomb4_bits, bomb4_width, bomb4_height);
X    for_all_unit_types(u) {
X	if (utypes[u].bitmapname && (strlen(utypes[u].bitmapname) > 0)) {
X	    sd()->unitpics[u] = load_bitmap(side, utypes[u].bitmapname);
X	} else {
X	    utypes[u].bitmapname = NULL;
X	}
X    }
X    if (Debug) printf("Bitmaps stored ...\n");
X
X    sd()->wbdots = XCreatePixmap(sdd(), side->main, dots_width, dots_height,
X				 DefaultDepth(sdd(), 0) );
X    sd()->bwdots = XCreatePixmap(sdd(), side->main, dots_width, dots_height,
X				 DefaultDepth(sdd(), 0) );
X
X    /* Since clearbitgc has to have a depth of 1 we'll */
X    /* hang it off bombpics[0] */
X    mask = GCFunction;
X    values.function = GXclear;
X    sd()->clearbitgc = XCreateGC(sdd(), sd()->bombpics[0], mask, &values);
X
X    XSetForeground(sdd(), gc, side->fgcolor);
X    XSetBackground(sdd(), gc, side->bgcolor);
X    XSetStipple(sdd(), gc, dots);
X    XSetFillStyle(sdd(), gc, FillOpaqueStippled);
X    XFillRectangle(sdd(), sd()->wbdots, gc, 0, 0, dots_width, dots_height);
X
X    XSetForeground(sdd(), gc, side->bgcolor);
X    XSetBackground(sdd(), gc, side->fgcolor);
X    XFillRectangle(sdd(), sd()->bwdots, gc, 0, 0, dots_width, dots_height);
X    if (Debug) printf("Tiles stored ...\n");
X
X    rootcursor = FALSE;
X    XQueryBestCursor(sdd(), side->main, 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) {
X        sd()->curs =
X	  make_cursor(sdd(), mcurs, mmask, white_color(side),
X		      black_color(side), 7, 7);
X	   
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    XFreeGC(sdd(), gc);
X    XFreePixmap(sdd(), dots);
X    XFreePixmap(sdd(), mmask);
X    XFreePixmap(sdd(), mcurs);
X}
X
X/* Since XCreatePixmapCursor() takes XColors and not pixel values we */
X/* have to look the colors associated with the foreground and */
X/* background pixel values up in the color table and pass them to */
X/* XCreatePixmapCursor(). */
X   
XCursor make_cursor(dpy, curs, mask, foreground, background, x, y)
XDisplay *dpy;
XPixmap curs, mask;
Xunsigned long foreground, background;
Xunsigned int x, y;
X{
X    XColor defs[2];
X
X    defs[0].pixel = foreground;
X    defs[1].pixel = background;
X    XQueryColors(dpy, DefaultColormap(dpy, 0), defs, 2);
X    return  XCreatePixmapCursor(dpy, curs, mask, &defs[0], &defs[1], x, y);
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/* necessary. */
X
XXFontStruct *
Xopen_font(side, name, xdefault, altfont)
XSide *side;
Xchar *name, *xdefault;
XXFontStruct * altfont;
X{
X    char *firstname, *altname;
X    XFontStruct * font;
X
X    if ((altname = XGetDefault(sdd(), PROGRAMNAME, xdefault)) != NULL)
X	name = altname;
X    firstname = name;
X    if ((font = XLoadQueryFont(sdd(), name)) == NULL) {
X	make_pathname(XCONQLIB, name, "snf", spbuf);
X	name = spbuf;
X	if ((font = XLoadQueryFont(sdd(), name)) == NULL) {
X	    fprintf(stderr, "Can't open fonts \"%s\" or \"%s\" on \"%s\"\n",
X		    firstname, name, side->host);
X	    if (altfont != NULL) {
X		fprintf(stderr, "Substituting another font...\n");
X		return altfont;
X	    } else {
X		fprintf(stderr, "No font to substitute!!\n");
X		exit(1);
X	    }
X	}
X    }
X    if (Debug) printf("Opened font \"%s\" ...\n", name);
X    return font;
X}
X
X/* Force X11 font fanciness into semblance of X10 font plainness. */
X
Xvoid
Xget_font_size(font, width, height)
XXFontStruct * font;
Xshort *width, *height;
X{
X    *width = font->max_bounds.rbearing - font->min_bounds.lbearing;
X    *height = font->max_bounds.ascent + font->min_bounds.descent;
X    if (Debug) {
X	printf("rbearing = %d lbearing = %d\n",
X	       (int)font->max_bounds.rbearing, (int)font->min_bounds.lbearing);
X	printf("returning font size %d %d\n", (int)*width, (int)*height);
X    }
X}
X
X/* Try to load a bitmap of the given name - can be either X11-only (.b11) */
X/* or X10 (.b) bitmaps, but prefer X11 flavor. */
X
XPixmap
Xload_bitmap(side, name)
XSide *side;
Xchar *name;
X{
X    int w, h, junk, a;
X    Pixmap rslt;
X
X    make_pathname(NULL, name, "b11", spbuf);
X    a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
X    if (a == BitmapSuccess) return rslt;
X    make_pathname(XCONQLIB, name, "b11", spbuf);
X    a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
X    if (a == BitmapSuccess) return rslt;
X    make_pathname(XCONQLIB, name, "b", spbuf);
X    a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
X    if (a == BitmapSuccess) return rslt;
X    fprintf(stderr, "Bitmap name \"%s\" not found anywhere!\n", name);
X    return (-1);
X}
X
X/* This routine has to be able to cope with window managers constraining */
X/* size.  Actually, the main window was already opened when the display */
X/* was opened, so the name is not quite accurate! */
X
Xcreate_main_window(side)
XSide *side;
X{
X    Pixmap dots;
X    XSizeHints hints;
X		  
X    XStoreName(sdd(), side->main, PROGRAMNAME);
X    dots = (side->bonw ? sd()->bwdots : sd()->wbdots); 
X    XSetWindowBackgroundPixmap(sdd(), side->main, dots);
X
X    hints.width = side->mw;
X    hints.height = side->mh;
X    hints.min_width = side->mw;
X    hints.min_height = side->mh;
X    hints.flags = PSize|PMinSize;
X    XSetNormalHints(sdd(), side->main, &hints);
X}
X
X/* Help window is not necessarily a subwindow, though it might be sometimes. */
X
Xcreate_help_window(side)
XSide *side;
X{
X    helpwinlines =
X	max(45, (24 + period.numrtypes + period.numttypes + period.numutypes));
X
X    side->help = XCreateSimpleWindow(sdd(), DefaultRootWindow(sdd()),
X				     0, 0, 80*side->fw+1,
X				     helpwinlines*side->fh+1,
X				     1, side->fgcolor, side->bgcolor);
X    XStoreName(sdd(), side->help, "xconq-help");
X}
X
X/* Subwindow creator. */
X
Xcreate_window(side, x, y, w, h)
XSide *side;
Xint x, y, w, h;
X{
X    return XCreateSimpleWindow(sdd(), side->main, x, y, w, h,
X			       1, side->fgcolor, side->bgcolor);
X}
X
X/* Do little things necesary to make it all go, in this case mapping all */
X/* the windows (except help win). */
X
Xfixup_windows(side)
XSide *side;
X{
X    XMapWindow(sdd(), side->main);
X    XMapSubwindows(sdd(), side->main);
X    if (!giventime) XUnmapWindow(sdd(), side->clock);
X    if (!rootcursor) XDefineCursor(sdd(), 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(sdd(), side->main, KeyPressMask|ExposureMask);
X    XSelectInput(sdd(), side->map,  ButtonPressMask|ExposureMask);
X    XSelectInput(sdd(), side->help, KeyPressMask|ExposureMask);
X}
X
X/* Move windows and change their sizes to correspond with the new sizes of */
X/* viewports, etc */
X
Xreset_misc(side)
XSide *side;
X{
X    Pixmap dots;
X    XSizeHints hints;
X    XGCValues values;
X    unsigned int gcmask;
X
X    dots = (side->bonw ? sd()->bwdots : sd()->wbdots); 
X
X    XResizeWindow(sdd(), side->main, side->mw, side->mh);
X    hints.width = side->mw;  hints.height = side->mh;
X    hints.min_width = side->mw;  hints.min_height = side->mh;
X    hints.flags = PSize|PMinSize;
X    XSetNormalHints(sdd(), side->main, &hints);
X
X    XSetWindowBackgroundPixmap(sdd(), side->main, dots);
X    XSetWindowBackground(sdd(), side->msg, side->bgcolor);
X    XSetWindowBackground(sdd(), side->info, side->bgcolor); 
X    XSetWindowBackground(sdd(), side->prompt, side->bgcolor); 
X    XSetWindowBackground(sdd(), side->map, side->bgcolor);
X    XSetWindowBackground(sdd(), side->timemode, side->bgcolor);
X    XSetWindowBackground(sdd(), side->clock, side->bgcolor);
X    XSetWindowBackground(sdd(), side->state, side->bgcolor);
X    XSetWindowBackground(sdd(), side->help, side->bgcolor);
X    XSetWindowBackground(sdd(), side->sides, side->bgcolor);
X    XSetWindowBackground(sdd(), side->world, side->bgcolor);
X    XSetWindowBorder(sdd(), side->msg, side->fgcolor);
X    XSetWindowBorder(sdd(), side->info, side->fgcolor); 
X    XSetWindowBorder(sdd(), side->prompt, side->fgcolor); 
X    XSetWindowBorder(sdd(), side->map, side->fgcolor);
X    XSetWindowBorder(sdd(), side->timemode, side->fgcolor);
X    XSetWindowBorder(sdd(), side->clock, side->fgcolor);
X    XSetWindowBorder(sdd(), side->state, side->fgcolor);
X    XSetWindowBorder(sdd(), side->help, side->fgcolor);
X    XSetWindowBorder(sdd(), side->sides, side->fgcolor);
X    XSetWindowBorder(sdd(), side->world, side->fgcolor);
X
X    gcmask = GCForeground | GCBackground;
X    values.foreground = side->fgcolor;
X    values.background = side->bgcolor;
X    XChangeGC(sdd(), sd()->gc, gcmask, &values);
X    XChangeGC(sdd(), sd()->flashgc, gcmask, &values);
X    XChangeGC(sdd(), sd()->textgc, gcmask, &values);
X    XChangeGC(sdd(), sd()->icongc, gcmask, &values);
X    XChangeGC(sdd(), sd()->unitgc, gcmask, &values);
X    values.foreground = side->bgcolor;
X    values.background = side->fgcolor;
X    XChangeGC(sdd(), sd()->invicongc, gcmask, &values);
X}
X
X/* Alter the size and position of a window. */
X
Xchange_window(side, win, x, y, w, h)
XSide *side;
XWindow win;
Xint x, y, w, h;
X{
X    unsigned int mask;
X    XWindowChanges changes;
X
X    if (active_display(side)) {
X	if (x >= 0) {
X	    if (w >= 0) {
X		mask = CWX | CWY | CWWidth | CWHeight;
X		changes.x = x;  changes.y = y;
X		changes.width = w;  changes.height = h;
X	    } else {
X		mask = CWX | CWY;
X		changes.x = x;  changes.y = y;
X	    }
X	} else {
X	    mask = CWWidth | CWHeight;
X	    changes.width = w;  changes.height = h;
X	}
X    }
X    XConfigureWindow(sdd(), win, mask, &changes);
X}
X
X/* Return the number of colors - this is used to guess about monochromeness. */
X
Xdisplay_colors(side) Side *side; {  return XDisplayCells(sdd(), 0);  }
X
Xwhite_color(side) Side *side; {  return WhitePixel(sdd(), 0);  }
X
Xblack_color(side) Side *side; {  return BlackPixel(sdd(), 0);  }
X
X/* Get a color set up and warn if not getting what was asked for. */
X
Xlong
Xrequest_color(side, name)
XSide *side;
Xchar *name;
X{
X    XColor c, avail;
X
X    if (Debug) printf("Allocating %s\n", name);
X    XAllocNamedColor(sdd(), DefaultColormap(sdd(), 0), name, &avail, &c);
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 << ConnectionNumber(sdd()));
X	    asides[ConnectionNumber(sdd())] = side;
X	    while (XPending(sdd()) > 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, "error in select!\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		update_clock(asides[i]);
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[BUFSIZE];
X    int nchar, rawx, rawy;
X    unsigned int junk;
X
X    while (TRUE) {
X	XNextEvent(sdd(), &evt);
X	switch (evt.type) {
X	case KeyPress:
X	    if (evt.xkey.window != side->main &&
X		evt.xkey.window != side->help) 
X		return FALSE;
X	    nchar = XLookupString(&evt, buf, BUFSIZE, NULL, NULL);
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 ButtonPress:
X	    if (evt.xbutton.window == side->map) {
X		rawx = evt.xbutton.x;  rawy = evt.xbutton.y; 
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 if (evt.xbutton.window == side->state) {
X		rawx = evt.xbutton.x;  rawy = evt.xbutton.y; 
X		side->reqtype = UNITTYPE;
X		side->requtype = rawy / 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 Expose:
X	    if (evt.xexpose.window == side->main || 
X		evt.xexpose.window == side->map) {
X		flush_input(side);
X		redraw(side);
X	    }
X	    if (Debug) printf("Host %s exposes itself\n", side->host);
X	    return FALSE;
X	    break;
X	default:
X	    case_panic("event type", evt.type);
X	    break;
X	}
X    }
X}
X
X/* Freese everything until given side supplies input, use sparingly. */
X
Xfreeze_wait(side)
XSide *side;
X{
X    XEvent evt;
X    char buf[BUFSIZE];
X    int nchar;
X
X    if (Debug) printf("Waiting for a %s event\n", side->host);
X    flush_input(side);
X    while(TRUE) {
X	XNextEvent(sdd(), &evt);
X	if (evt.type == KeyPress) {
X	    nchar = XLookupString(&evt, buf, BUFSIZE, NULL, NULL);
X	    if (nchar > 0) 
X		return *buf;
X	    else
X		return '\0';
X	}
X    }  
X}
X
X/* Get rid of extra key/mouse clicks. */
X
Xflush_input(side)
XSide *side;
X{
X    if (humanside(side)) XSync(sdd(), 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 (humanside(side)) XFlush(sdd());  
X}
X
X/* General window clearing. */
X
Xclear_window(side, win)
XSide *side;
XWindow win;
X{
X    XClearWindow(sdd(), 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    XSetFillStyle(sdd(), sd()->gc, FillSolid);
X    XSetForeground(sdd(), sd()->gc, color);
X    if (sx1 < sww && sx2 >= sww) {
X	XFillRectangle(sdd(), side->world, sd()->gc,
X		       sx1, sy, (unint) sww - sx1, (unint) side->mm);
X	XFillRectangle(sdd(), side->world, sd()->gc,
X		       0, sy, (unint) sx2 - sww, (unint) side->mm);
X    } else {
X	sx1 %= sww;
X	sx2 %= sww;
X	XFillRectangle(sdd(), side->world, sd()->gc,
X		       sx1, sy, (unint) sx2 - sx1, (unint) side->mm);
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    XSetFunction(sdd(), sd()->gc, GXinvert);
X    /* is this next call really necessary? */
X    XSetLineAttributes(sdd(), sd()->gc, 1, LineSolid, CapButt, JoinMiter);
X    XDrawLine(sdd(), side->world, sd()->gc, sx1, sy1, sx2, sy1);
X    XDrawLine(sdd(), side->world, sd()->gc, sx2, sy1-1, sx2, sy2+1);
X    XDrawLine(sdd(), side->world, sd()->gc, sx2, sy2, sx1, sy2);
X    XDrawLine(sdd(), side->world, sd()->gc, sx1, sy2+1, sx1, sy1-1);
X    XSetFunction(sdd(), sd()->gc, GXcopy);
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    sy += sd()->iconfont->max_bounds.ascent;
X    XSetForeground(sdd(), sd()->icongc, color);
X    XDrawString(sdd(), side->map, sd()->icongc, sx, sy, buf, len);
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    XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy1, sx2, sy2);
X    XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy2, sx2, sy1);
X    flush_output(side);
X    for (i = 0; i < DELAY; ++i);
X    XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy1, sx2, sy2);
X    XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy2, sx2, sy1);
X}
X
X/* The "cursor icon" is just a pair of special chars - nothing to do with */
X/* X's notion of cursors. */
X
Xdraw_cursor_icon(side, sx, sy)
XSide *side;
Xint sx, sy;
X{
X    sy += sd()->iconfont->max_bounds.ascent;
X    XDrawString(sdd(), side->map, sd()->invicongc, sx, sy, "[", 1);
X    XSetForeground(sdd(), sd()->icongc, side->fgcolor);
X    XDrawString(sdd(), side->map, sd()->icongc, sx, sy, "]", 1);
X}
X
X/* Draw the icon for a hex (given as a char). */
X
Xdraw_hex_icon(side, win, sx, sy, color, ch)
XSide *side;
XWindow win;
Xint sx, sy, color;
Xchar ch;
X{
X    XSetForeground(sdd(), sd()->varicongc, color);
X    sy += sd()->iconfont->max_bounds.ascent;
X    XDrawString(sdd(), win, sd()->varicongc, sx, sy, &ch, 1);
X}
X
X/* Draw the number of an unfriendly side (never called for own units). */
X
Xdraw_side_number(side, win, sx, sy, n, color)
XSide *side;
XWindow win;
Xint sx, sy, n, color;
X{
X    char ch = n + '0';
X
X    if (n >= 0) {
X	XSetForeground(sdd(), sd()->varicongc, color);
X	sy += sd()->iconfont->max_bounds.ascent;
X	XDrawString(sdd(), win, sd()->varicongc, sx, sy, &ch, 1);
X    }
X}
X
Xdraw_blast_icon(side, win, sx, sy, type, color)
XSide *side;
XWindow win;
Xint sx, sy, color;
Xchar type;
X{
X    char buf[1];
X
X    XSetForeground(sdd(), sd()->varicongc, color);
X    buf[0] = type;
X    sy += sd()->iconfont->max_bounds.ascent;
X    XDrawString(sdd(), win, sd()->varicongc, sx, sy, buf, 1);
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    /* GC needs to be set for inverted drawing */
X    XDrawRectangle(sdd(), side->map, sd()->gc, 0, 0, sw, sh);
X    flush_output(side);
X}
X
X/* Draw just one of the mushroom cloud shapes. */
X
Xdraw_mushroom(side, x, y, i)
XSide *side;
Xint x, y, i;
X{
X    int sx, sy;
X    int color;
X
X    color = ((side->monochrome || i == 3) ? side->fgcolor : side->bgcolor);
X    xform(side, unwrap(side, x), y, &sx, &sy);
X    XSetForeground(sdd(), sd()->unitgc, color);
X    XSetClipMask(sdd(), sd()->unitgc, sd()->bombpics[i]);
X    XSetClipOrigin(sdd(), sd()->unitgc, sx-BH/4, sy-BH/2);
X    XFillRectangle(sdd(), side->map, sd()->unitgc, sx-BH/4, sy-BH/2, BH, BH);
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	XSetForeground(sdd(), sd()->gc, side->fgcolor);
X	XFillRectangle(sdd(), side->info, sd()->gc,
X		       boxleft + boxwidth/3 - 1, boxoffset - 1,
X		       barwidth + 2, boxheight + 2);
X	XSetForeground(sdd(), sd()->gc, side->bgcolor);
X	XFillRectangle(sdd(), side->info, sd()->gc,
X		       boxleft + boxwidth/3, boxoffset,
X		       barwidth, boxheight);
X	if ( amount > critical)
X	  XSetForeground(sdd(), sd()->gc, side->goodcolor);
X	else
X	  XSetForeground(sdd(), sd()->gc, side->badcolor);
X	XFillRectangle(sdd(), side->info, sd()->gc,
X		       boxleft + boxwidth/3, boxoffset + boxheight - barheight,
X		       barwidth, barheight);
X	draw_text(side, side->info,
X		  boxleft+(boxwidth-strlen(title)*side->fw)/2,
X		  (INFOLINES-1)*side->fh, title, side->fgcolor);
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 buf[1];
X
X    y += 3;			/* fudge factor to make x11 look */
X    x += 2;			/*  like X10 (ugh). */
X    if (utypes[u].bitmapname != NULL ) {
X      XSetForeground(sdd(), sd()->unitgc, color);
X      XSetClipMask(sdd(), sd()->unitgc, sd()->unitpics[u]);
X      XSetClipOrigin(sdd(), sd()->unitgc, x, y);
X      XFillRectangle(sdd(), win, sd()->unitgc, x, y, side->uw, side->uh);
X    } else {
X        XSetForeground(sdd(), sd()->unittextgc, color);
X	buf[0] = utypes[u].uchar;
X	y += sd()->unitfont->max_bounds.ascent;
X	XDrawString(sdd(), win, sd()->unittextgc, x, y, buf, 1);
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    y += sd()->textfont->max_bounds.ascent;
X    if (color != side->bgcolor) {
X	XSetForeground(sdd(), sd()->textgc, color);
X	XDrawImageString(sdd(), win, sd()->textgc, x, y, str, strlen(str));
X    } else {
X	XSetForeground(sdd(), sd()->textgc, side->bgcolor);
X	XSetBackground(sdd(), sd()->textgc, side->fgcolor);
X	XDrawImageString(sdd(), win, sd()->textgc, x, y, str, strlen(str));
X	XSetBackground(sdd(), sd()->textgc, side->bgcolor);
X    }
X}
X
X/* Draw a line through some side's title. */
X
Xdraw_scratchout(side, pos)
XSide *side;
Xint pos;
X{
X    XSetForeground(sdd(), sd()->textgc, side->fgcolor);
X    XDrawLine(sdd(), side->sides, sd()->textgc, 0, pos, 30*side->fw, pos);
X}
X
X/* Beep the beeper! */
X
Xbeep(side)
XSide *side;
X{
X    XBell(sdd(), 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    XEvent evt;
X
X    XMapWindow(sdd(), side->help);
X    /* wait until this window is exposed to return. */
X    XWindowEvent(sdd(), side->help, ExposureMask, &evt);
X    return TRUE;
X}
X
Xconceal_help(side)
XSide *side;
X{
X    XUnmapWindow(sdd(), side->help);
X    flush_output(side);
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(sdd());
X    side->display = (long) NULL;
X}
X
END_OF_X11.c
if test 35753 -ne `wc -c <X11.c`; then
    echo shar: \"X11.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f init.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"init.c\"
else
echo shar: Extracting \"init.c\" \(15558 characters\)
sed "s/^X//" >init.c <<'END_OF_init.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: init.c,v 1.2 88/06/28 10:06:13 shebs Exp $ */
X
X/* Initialization is complicated, because xconq needs lots of setup for */
X/* maps, units, sides, and the like.  The data must also be able to come */
X/* from saved games, scenarios, bare maps in files, period descriptions, */
X/* or be synthesized if necessary. */
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
Xextern char *rawfilenames[];
X
Xextern int numfiles, giventime;
X
Xint good_place();          /* to make gcc happy */
X
X/* Keep track of whether each sort of data has been loaded or not. */
X/* The version isn't important enough to need any sort of flag. */
X
Xbool periodmade, mapmade, globalsmade, sidesmade, unitsmade;
Xbool populations = FALSE;  /* true if populace ever nonzero */
X
Xint favterr[MAXUTYPES];    /* "favorite terrain" of each unit type */
Xint numhexes[MAXUTYPES];   /* temporaries used by country placement */
Xint countryx[MAXSIDES], countryy[MAXSIDES];  /* centers of countries */
Xint snameused[MAXSNAMES];  /* flags side names already used by somebody */
Xint unameused[MAXUNAMES];  /* flags unit names already used */
X
X/* Either load a saved game or load mapfiles from cmd line and then make up */
X/* any stuff that didn't get loaded. */
X
Xinit_game()
X{
X    int i;
X
X    periodmade = mapmade = globalsmade = sidesmade = unitsmade = FALSE;
X
X    if (saved_game()) {
X	printf("Restoring from \"%s\" ...\n", SAVEFILE);
X	load_mapfile(SAVEFILE);
X    } else {
X	for (i = 0; i < numfiles; ++i) {
X	    load_mapfile(rawfilenames[i]);
X	}
X	if (!mapmade) {
X	    printf("Please wait six days while I create the world...\n");
X	    make_up_map();
X	}
X	if (!globalsmade) {
X	    make_up_globals();
X	}
X	if (!sidesmade) {
X	    make_up_sides();
X	}
X	if (numsides <= 0) {
X	    fprintf(stderr, "No player sides in this game!\n");
X	    exit(1);
X	} else if (numsides < numgivens) {
X	    fprintf(stderr,
X		    "Warning: only made %d of the %d sides requested.\n",
X		    numsides, numgivens);
X	}
X	if (!unitsmade) {
X	    make_up_units();
X	}
X    }
X    init_unit_views();
X    fixup_things();
X    printf("\nThe time is %s.\n", period.name);
X}
X
X/* Sort out the mess created by loading some things and creating others. */
X/* Should only be possible to start with 0 units when building a scenario. */
X/* Need to make friends and enemies; normally the machine players gang up */
X/* on the humans. */
X
Xfixup_things()
X{
X    bool hasany;
X    int x, y;
X    Unit *unit;
X    Side *side, *side2;
X
X    if (period.scale != world.scale) {
X	fprintf(stderr,
X		"Reality check: Period is %d km/hex but map is %d km/hex.\n",
X		period.scale, world.scale);
X    }
X    if (no_statistics()) {
X	for_all_units(unit) {
X	    if (!neutral(unit)) unit->side->balance[unit->type][FIRSTUNIT]++;
X	}
X    }
X    for_all_sides(side) {
X	side->timeleft = giventime;
X	hasany = FALSE;
X	for_all_units(unit) {
X	    if (unit->side == side) {
X		hasany = TRUE;
X		break;
X	    }
X	}
X	if (!hasany && (unit = random_start_unit()) != NULL) {
X	    unit_changes_side(unit, side, FIRSTUNIT, -1);
X	    unit->trueside = unit->side;
X	    set_product(unit, period.firstptype);
X	    set_schedule(unit);
X	}
X    }
X    for_all_sides(side) {
X	for_all_sides(side2) {
X	    if (neutral_side(side, side2)) {
X		if (side->host != NULL || side2->host != NULL)
X		    declare_war(side, side2);
X		else
X		    declare_alliance(side, side2);
X	    }
X	}
X    }
X    /* this slowness is necessary to solve chicken/egg problems of loading */
X    /* units and sides from files... */
X    if (period.allseen || world.known) {
X	for_all_sides(side) {
X	    for (x = 0; x < world.width; ++x) {
X		for (y = 0; y < world.height; ++y) {
X		    set_side_view(side, x, y, EMPTY);
X		    if ((unit = unit_at(x, y)) != NULL) {
X			if (utypes[unit->type].alreadyseen ||
X			    utypes[unit->type].seealways ||
X			    unit->side == side) {
X			    see_exact(side, x, y);
X			}
X			if (utypes[unit->type].seealways) {
X			    set_cover(side, x, y, 100);
X			}
X		    }
X		}
X	    }
X	}
X    }
X}
X
Xiview_hex(x, y)
Xint x, y;
X{
X    Unit *unit;
X
X    set_side_view(tmpside, x, y, EMPTY);
X    if ((unit = unit_at(x, y)) != NULL) {
X	if (cover(tmpside, x, y) > 0 || utypes[unit->type].alreadyseen) {
X	    see_exact(tmpside, unit->x, unit->y);
X	}
X    }
X}
X
Xinit_unit_views()
X{
X    Unit *unit;
X
X    for_all_units(unit) {
X	if (!neutral(unit)) {
X	    see_exact(unit->side, unit->x, unit->y);
X	    if (period.knownradius > 0) {
X		tmpside = unit->side;
X		apply_to_area(unit->x, unit->y, period.knownradius, iview_hex);
X	    }
X	}
X    }
X}
X
Xno_statistics()
X{
X    int u;
X    Side *side = sidelist;
X
X    for_all_unit_types(u) if (side->balance[u][FIRSTUNIT] > 0) return FALSE;
X    return TRUE;
X}
X
X/* Invent global values as necessary. */
X
Xmake_up_globals()
X{
X    if (Debug) printf("Going to make up some globals ...\n");
X    global.time = 0;
X    global.endtime = DEFAULTTURNS;
X    global.setproduct = TRUE;
X    global.leavemap = FALSE;
X    global.numconds = 0;
X    if (Debug) printf("... Done making up globals.\n");
X}
X
X/* Create some random sides with default characteristics. */
X
Xmake_up_sides()
X{
X    int i;
X    Side *side;
X
X    if (Debug) printf("Going to make up some sides ...\n");
X    for (i = 0; i < MAXSNAMES; ++i) snameused[i] = FALSE;
X    for (i = 0; i < numgivens; ++i) {
X	side = create_side(random_side_name(), humans[i], hosts[i]);
X	/* Pretty bad if side creation fails... */
X	if (side == NULL) abort();
X    }
X    if (Debug) printf("... Done making up sides.\n");
X}
X
X/* If no units supplied with the map, then make some up and place them. */
X/* There is an option to start with one or with a country. */
X
Xmake_up_units()
X{
X    int u, t, i;
X
X    if (Debug) printf("Going to make up some units ...\n");
X    for_all_unit_types(u) {
X	favterr[u] = 0;   /* doesn't really matter which one */
X	for_all_terrain_types(t) {
X	    if (utypes[u].favored[t] > utypes[u].favored[favterr[u]])
X	    favterr[u] = t;
X	}
X    }
X    /* Check for existence of favorite terrain on map */
X    for (i = 0; i < MAXUNAMES; ++i) unameused[i] = FALSE;
X    place_countries();
X    place_neutrals();
X    if (Debug) printf("... Done making up units.\n");
X}
X
X/* Place all the units belonging to countries.  Once placed, set ownership */
X/* and production appropriately. */
X
Xplace_countries()
X{
X    int x0, y0, u, i, num, first = period.firstutype, numleft[MAXUTYPES];
X    Unit *unit;
X    Side *side;
X
X    for_all_sides(side) {
X	find_a_place(&x0, &y0);
X	if (Debug) printf("Country at %d,%d\n", x0, y0);
X	countryx[side_number(side)] = x0;  countryy[side_number(side)] = y0;
X	place_inhabitants(side, x0, y0);
X	if (first != NOTHING) {
X	    unit = create_unit(first, random_unit_name(first));
X	    occupy_hex(unit, x0, y0);
X	    init_supply(unit);
X	    unit_changes_side(unit, side, FIRSTUNIT, -1);
X	    unit->trueside = unit->side;
X	    set_product(unit, period.firstptype);
X	    set_schedule(unit);
X	}
X	for_all_unit_types(u) {
X	    num = utypes[u].incountry;
X	    if (first == u) num--;
X	    numleft[u] = num;
X	    for (i = 0; i < num; ++i) {
X		unit = create_unit(u, random_unit_name(u));
X		if (place_unit(unit, x0, y0)) {
X		    numleft[u]--;
X		    if (first == NOTHING) {
X			unit_changes_side(unit, side, FIRSTUNIT, -1);
X			unit->trueside = unit->side;
X		    }
X		} else {
X		    kill_unit(unit, -1);
X		}
X	    }
X	}
X	/* second pass for units that have to be occupants */
X	for_all_unit_types(u) {
X	    for (i = 0; i < numleft[u]; ++i) {
X		unit = create_unit(u, random_unit_name(u));
X		if (place_unit(unit, x0, y0)) {
X		    if (first == NOTHING) {
X			unit_changes_side(unit, side, FIRSTUNIT, -1);
X			unit->trueside = unit->side;
X		    } else {
X			/* give up finally - needs to be more informative */
X			fprintf(stderr, "Can't place a %s!\n", utypes[u].name);
X			exit(1);
X		    }
X		}
X	    }
X	}
X    }
X}
X
X/* Work hard to find a place for a side's country.  First make some random *
X/* trials, then start searching from the "center" of the map outwards. */
X/* If neither approach works, things are too screwed up to keep going. */
X
Xfind_a_place(cxp, cyp)
Xint *cxp, *cyp;
X{
X    int tries, x, y, diam = (2 * period.countrysize + 1);
X
X    for (tries = 0; tries < 200; ++tries) {
X	x = random(world.width);
X	x = wrap(x);
X	y = random(world.height - diam) + period.countrysize;
X	if (good_place(x, y)) { 
X	    *cxp = x;  *cyp = y;
X	    if (Debug) printf("Country placed on try %d\n", tries);
X	    return;
X	}
X    }
X    if (search_area(world.width/2, world.height/2,
X		    max(world.width, world.height), good_place, cxp, cyp)) {
X	if (Debug) printf("Country placed after search\n");
X	return;
X    } else {
X	fprintf(stderr, "Can't place all the countries!\n");
X	fprintf(stderr, "Try bigger maps or fewer sides next time.\n");
X	exit(1);
X    }
X}    
X
X/* Decide whether the given location is desirable for a country.  It should */
X/* not be too near or too far from other sides' countries, and there must be */
X/* enough terrain to place all the initial units.  In addition, the center */
X/* of the country must have the right terrain for the firstutype. */
X
Xcount_hexes(x, y)
Xint x, y;
X{
X    int u, terr = terrain_at(x, y);
X
X    for_all_unit_types(u) if (terr == favterr[u]) numhexes[u]++;
X}
X
Xgood_place(cx, cy)
Xint cx, cy;
X{
X    bool toofar = TRUE, notfirst = FALSE;
X    int c, px, py, t, u, x, y, toplace, allhexes, first = period.firstutype;
X
X    for (c = 0; c < numsides; ++c) {
X	px = countryx[c];  py = countryy[c];
X	if (px > 0 && py > 0) {
X	    notfirst = TRUE;
X	    if (distance(cx, cy, px, py) < period.mindistance) return FALSE;
X	    if (distance(cx, cy, px, py) < period.maxdistance) toofar = FALSE;
X	}
X    }
X    if (toofar && notfirst) return FALSE;
X    if (first != NOTHING && terrain_at(cx, cy) != favterr[first])
X	return FALSE;
X    toplace = allhexes = 0;
X    for_all_unit_types(u) numhexes[u] = 0;
X    apply_to_area(cx, cy, period.countrysize, count_hexes);
X    for_all_unit_types(u) {
X	if (utypes[u].incountry > numhexes[u]) return FALSE;
X	toplace += utypes[u].incountry;
X	allhexes += numhexes[u];
X    }
X    return (toplace < allhexes);
X}
X
X/* Place the populace on appropriate terrain within the country. */
X/* If countries overlap, then flip coins to decide about intermix (heh-heh, */
X/* so it resembles 17th-century Germany - more fun that way!). */
X/* The loops are a standard regular hexagon filler. */
X
Xplace_inhabitants(side, x0, y0)
XSide *side;
Xint x0, y0;
X{
X    int x, y, x1, y1, x2, y2, dist = period.countrysize;
X
X    y1 = interior(y0 - dist);
X    y2 = interior(y0 + dist);
X    for (y = y1; y <= y2; ++y) {
X	x1 = x0 - (y < y0 ? (y - y1) : dist);
X	x2 = x0 + (y > y0 ? (y2 - y) : dist);
X	for (x = x1; x <= x2; ++x) {
X	    if (ttypes[terrain_at(wrap(x), y)].inhabitants) {
X		populations = TRUE;
X		if (unpopulated(wrap(x), y) || flip_coin()) {
X		    set_people_at(wrap(x), y, 8+side_number(side));
X		}
X	    }
X	}
X    }
X}
X
X/* The basic conditions that *must* be met by an initial unit placement. */
X
Xint tmputype;
X
Xvalid_place(x, y)
Xint x, y;
X{
X    Unit *unit = unit_at(x, y);
X
X    return ((unit == NULL && utypes[tmputype].favored[terrain_at(x, y)] > 0) ||
X	    (unit != NULL && could_carry(unit->type, tmputype)));
X}
X
X/* Put a unit down somewhere in the designated area, following constraints */
X/* on terrain and adjacency.  Returns success of placement. */
X
X/* "favterr" is poorly and unrobustly handled here... */
X
Xplace_unit(unit, cx, cy)
XUnit *unit;
Xint cx, cy;
X{
X    bool canmove = FALSE;
X    int u = unit->type, t, tries, x, y, chance, r, favterr = 0;
X    int csize = period.countrysize;
X
X    for_all_terrain_types(t) {
X	if (could_move(u, t))
X	    canmove = TRUE;
X	if (utypes[u].favored[t] > utypes[u].favored[favterr])
X	    favterr = t;
X    }
X    tmputype = u;
X    for (tries = 0; tries < 500; ++tries) {
X	x = random(2*csize+1) + cx - csize;  x = wrap(x);
X	y = random(2*csize+1) + cy - csize;  y = interior(y);
X	if (valid_place(x, y) && distance(cx, cy, x, y) <= csize) {
X	    chance = 100;
X	    t = terrain_at(x, y);
X	    if (canmove && !could_move(u, t)) chance -= 90;
X	    for_all_resource_types(r) {
X		if (utypes[u].produce[r] > 0 && utypes[u].productivity[t] == 0)
X		    chance -= 20;
X	    }
X	    if (adj_unit(x, y)) chance -= 70;
X	    if (probability(chance)) {
X		occupy_hex(unit, x, y);
X		init_supply(unit);
X		if (Debug) printf("Unit placed on try %d\n", tries);
X		return TRUE;
X	    }
X	}
X    }
X    if (search_area(cx, cy, csize, valid_place, &x, &y)) {
X	occupy_hex(unit, x, y);
X	init_supply(unit);
X	if (Debug) printf("Unit placed after search\n");
X	return TRUE;
X    }
X    return FALSE;
X}
X
X/* The number of neutral units is given by a parameter, and adjusted by */
X/* the number of units assigned to specific countries.  The number is at */
X/* least 1 (if nonzero density), even for small maps. */
X
Xplace_neutrals()
X{
X    int u, num, i;
X
X    for_all_unit_types(u) {
X	if (utypes[u].density > 0) {
X	    num = (((utypes[u].density * world.width * world.height) / 10000) -
X		   (numsides * utypes[u].incountry));
X	    num = max(1, num);
X	    for (i = 0; i < num; ++i) {
X		place_neutral(create_unit(u, random_unit_name(u)));
X	    }
X	}
X    }
X}
X
X/* Neutral places should be uncommon in hostile terrain.  If we can't find */
X/* a place, just blow it off and go to the next one. */
X
Xplace_neutral(unit)
XUnit *unit;
X{
X    int tries, x, y, u = unit->type;
X
X    for (tries = 0; tries < 500; ++tries) {
X	x = random(world.width);  y = random(world.height - 2) + 1;
X	if ((probability(utypes[u].favored[terrain_at(x, y)])) &&
X	    (unit_at(x, y) == NULL) &&
X	    (!adj_unit(x, y) || flip_coin())) {
X	    occupy_hex(unit, x, y);
X	    init_supply(unit);
X	    return;
X	}
X    }
X    kill_unit(unit, ENDOFWORLD);
X}
X
X/* True if anybody already on given hex or adjacent to it. */
X
Xadj_unit(x, y)
Xint x, y;
X{
X    int d, x1, y1;
X
X    for_all_directions(d) {
X	x1 = wrap(x + dirx[d]);  y1 = y + diry[d];
X	if (unit_at(x1, y1)) return TRUE;
X    }
X    return FALSE;
X}
X
X/* Give the unit what it is declared to have stockpiled already. */
X
Xinit_supply(unit)
XUnit *unit;
X{
X    int r, u = unit->type;
X
X    for_all_resource_types(r) {
X	unit->supply[r] =
X	    (utypes[u].storage[r] * utypes[u].stockpile[r]) / 100;
X    }
X}
X
X/* Pick any name not already used in the giant array of unit names. */
X/* First try randomly, then sequentially. */
X
Xchar *
Xrandom_unit_name(u)
Xint u;
X{
X    int i, n;
X
X    if (utypes[u].named) {
X	for (i = 0; i < period.numunames; ++i) {
X	    if (!unameused[(n = random(period.numunames))]) {
X		unameused[n] = TRUE;
X		return unames[n];
X	    }
X	}
X	for (i = 0; i < period.numunames; ++i) {
X	    if (!unameused[i]) {
X		unameused[i] = TRUE;
X		return unames[i];
X	    }
X	}
X	return NULL;
X    } else {
X	return NULL;
X    }
X}
X
X/* Pick a side name not already used.  Don't get uptight if we ran out of */
X/* names; perhaps a unit will lend a name, and certainly the players will */
X/* notice and change side names manually! */
X
Xchar *
Xrandom_side_name()
X{
X    int i, n;
X
X    for (i = 0; i < period.numsnames; ++i) {
X	if (!snameused[(n = random(period.numsnames))]) {
X	    snameused[n] = TRUE;
X	    return snames[n];
X	}
X    }
X    for (i = 0; i < period.numsnames; ++i) {
X	if (!snameused[i]) {
X	    snameused[i] = TRUE;
X	    return snames[i];
X	}
X    }
X    return "???";
X}
X
X/* Quicky test needed in a couple places. */
X
Xsaved_game()
X{
X    FILE *fp;
X
X    if ((fp = fopen(SAVEFILE, "r")) != NULL) {
X	fclose(fp);
X	return TRUE;
X    } else {
X	return FALSE;
X    }
X}
END_OF_init.c
if test 15558 -ne `wc -c <init.c`; then
    echo shar: \"init.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 2 \(of 18\).
cp /dev/null ark2isdone
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