#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 01/28/1994 10:42 UTC by campo@sunthpi3
# Source directory /home/sunthpi1/campo/xc5.5.1
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   2610 -rw-r--r-- README.PS
#  75914 -rw------- X11.c
#
# ============= README.PS ==============
if test -f 'README.PS' -a X"$1" != X"-c"; then
	echo 'x - skipping README.PS (File already exists)'
else
echo 'x - extracting README.PS (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README.PS' &&
X   Pisa, Jan 28th, 1994.
X
X	What is PS_VIEW?
X	----------------
X   PS_VIEW is an extension to xconq which allows for dumping (and printing)
view in PostScript(tm) format.  It will not work for cconq.
X   PS_VIEW will take care of loading any custom unit bitmap, but it relies
on the built-in terrain font (including hills).
X
X
X	How to include PS_VIEW into xconq
X	---------------------------------
1) Copy the new `X11.c' file into the xconq source directory 
X   (overwriting the existing file).
X
2) Either
2a1) Edit the `Imakefile': replace the line
ComplexProgramTarget_1($(PROGRAM1), $(XLIB), $(DEPXLIB))
X     with
ComplexProgramTarget_1($(PROGRAM1),XawClientLibs,-lm)
2a2) then type `xmkmf';
X   or
2b) Edit the `Makefile': replace the line
X             XLIB = $(EXTENSIONLIB) $(XLIB)
X    with
X             XLIB = $(EXTENSIONLIB) -lXt -lXmu -lm $(XLIB)
X
3) Type `make xconq'.
4) Type `make install', or, since the library is already installed, 
X   just copy `xconq' to the xconq binary directory.
X
X
X	How to use PS_VIEW
X	------------------
X   While playing xconq, just type `+'. xconq will dump your view into the
file `view.xconq.ps', which you can print on a PostScript printer.  The
output consists in a bunch of hexes, with the terrain icons on known hexes,
unit icons splat on the terrain, side number above the unit (`n' for
neutral, blank for yourself), unit name below (optional).
X
X	How to customize PS_VIEW
X	------------------------
X   The output aspect is controlled by a bunch of variables in the routine
dump_view.  Presently their values are "wired in" into the code (lines 2127
to 2147 of X11.c); you have to edit the file and recompile in order to
change them.  You will probably want to change `page_width' and
`page_height' to suit your needs, and `hex_size' to print larger- or
smaller-scale maps.
X
X	How to improve PS_VIEW
X	----------------------
X   The parameters must be better merged into xconq, e.g., they must 
be settable by resources (and the [o]ption command?).
X   The program could print more fancy legends, like: page numbers,
list of side names, unit balance(?).
X
X   Mail me suggestions and comments. I am a beginner in PostScript
programming; all the `Bitfont' font handling is taken bodily from
`xconq2ps' by Darrin West <west@jade.ab.ca>; the rest is mine.  I would
especially appreciate suggestions for generating cleaner, faster, more
compact PostScript.
X
X        Massimo Campostrini, 
Istituto Nazionale di Fisica Nucleare, Sezione di Pisa,
Piazza Torricelli 2, I56126 Pisa, Italy   ||  Phone: (+39)(50)911272
Internet: campo@sunthpi3.difi.unipi.it    ||  Fax:   (+39)(50)48277
SHAR_EOF
chmod 0644 README.PS ||
echo 'restore of README.PS failed'
Wc_c="`wc -c < 'README.PS'`"
test 2610 -eq "$Wc_c" ||
	echo 'README.PS: original size 2610, current size' "$Wc_c"
fi
# ============= X11.c ==============
if test -f 'X11.c' -a X"$1" != X"-c"; then
	echo 'x - skipping X11.c (File already exists)'
else
echo 'x - extracting X11.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'X11.c' &&
/* Copyright (c) 1987, 1988, 1991  Stanley T. Shebs. */
/* Copyright 1988 by Chris D. Peterson, MIT. */
/* Many improvements by Tim Moore, University of Utah. */
/* This program may be used, copied, modified, and redistributed freely */
/* for noncommercial purposes, so long as this notice remains intact.  */
X
/* Interface implementations for the X11 version of xconq. */
X
X
/*  PS_VIEW: PostScript view output  */
/*  M. Campostrini <campo@sunthpi3.difi.unipi.it>, 1993, 1994.  */
/*  based on xconq2ps by Darrin West <west@jade.ab.ca>, 1992.  */
#define PS_VIEW 
X
X
#include "config.h"
#include "misc.h"
#include "period.h"
#include "side.h"
#include "unit.h"
#include "map.h"
#include "global.h"
X
/* careful of the path of the X header files. */
X
#ifdef UNIX
#include <X11/Xos.h>
#undef SIGCHLD
#include <signal.h>   /* needed for ^C disabling */
#include <errno.h>    /* needed to detect interrupted selects */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/Intrinsic.h>
#include <ctype.h>
#endif /* UNIX */
X
#ifndef XAPPLRESDIR
#define XAPPLRESDIR "/local/lib/x11r4/app-defaults"
#endif
X
X
#ifdef PS_VIEW
#include "version.h"
#include <math.h>
X
/*  font data  */
typedef struct a_font_entry {
X	char ident;
X	char bit1[67], bit2[67];
X      } font_entry;
X
font_entry *entry_index[128];
X
/*  standard font  */
static font_entry xconq_font[] = {
/*  dummy  */
X  {' ', "0", ""},
/*  terrains  */
/*  sea  */
X  {'.', "00400000a0000318801c0700000000080200360d80c1f070000000004010c1b060",
X        "3e0f80000000080200360d80c1f07000000000400000a000011800000000000000"},
/*  shallows  */
X  {',', "00000000380000000007ce0000000073ffc00000003ff1f0000000ff3fe0000000",
X        "3ffe70000000ffcf300000003f7fe00000001cfe0000000000f800000000000000"},
/*  swamp  */
X  {'=', "00000000000001f0000000000004007e44400024801fa4800015007f1570000000",
X        "07ff80f000000207e0222000124fc01240000a80000abf00000000000000000000"},
/*  desert  */
X  {'~', "004000002000008800061200094280490c201a828048525010a2008a092008a500",
X        "e7f6f00501008952202c0a802a2a1088948009028004520000a000000000004000"},
/*  plains  */
X  {'+', "000000000000040100040100040100040100040100040100040100040100fffff0",
X        "040100040100040100040100040100040100040100040100040100000000000000"},
/*  forest  */
X  {'%', "00000000e0000d200012060020e9001c21c036c6404249404d22200128a0560820",
X        "0882401c3100256860448ca0451420180a40028800022300019000004000000000"},
/*  mountains  */
X  {'^', "00000000000000000000000000600000700000d000019800014c00034600065380",
X        "1c88c032a660641120000000000000000000000000000000000000000000000000"},
/*  ice  */
X  {'_', "0000000000000000000010000010000030000038000028000658000658000a5400",
X        "19d40011da00f34bf0e24df0c445f0448280000000000000000000000000000000"},
/*  vacuum  */
X  {':', "000000000000000000000000008000000000000000000000000000000000000000",
X        "000000000100000000000000080000000000000000000000000000000000000000"},
/*  mesa(?)  */
X  {'`', "00400000200000880006120008008043fe200401004810900e87808bfca0088480",
X        "88a48030a4608122002c10802a421088948009028004520000a000000000004000"},
/*  hills  */
X  {'(', "00000000000000000000000000000000000000000000000000f800838610760360",
X        "0c01803800c0e00070000010000000000000000000000000000000000000000000"},
/*  standard period units  */
X  {'i', "0000000004002800708075007e102ea02fc205d405f800b800b8001000100000",""},
X  {'a', "00000000000000000000000003c0fff007fe7ffc3ff800000000000000000000",""},
X  {'f', "00000000000000601fc07fe0070000000006001c0ffc3ffe01e0007000000000",""},
X  {'b', "0000020006000e0006000e0206067ffe7ffe06060e0206000e00060002000000",""},
X  {'d', "000000000000000000000000000005000fc01ff8000000000000000000000000",""},
X  {'s', "0000000000000000000000000000060006003ffc000000000000000000000000",""},
X  {'t', "00000000000000000000000006600ff03ffc1ff8000000000000000000000000",""},
X  {'C', "0000004004002000040000000380ffff7ffe0000000000000000000000000000",""},
X  {'B', "00000000000000000200424036c41ff8ffff7ffe000000000000000000000000",""},
X  {'N', "00000000000000000000000c1fd43ffc3ffc1fd4000c00000000000000000000",""},
X  {'/', "000000c800d000e000c000e00160026004607c6017f0203c0030003000300000",""},
X  {'*', "00000000000000000000100010001000383e2bea3abe3bea7fff000000000000",""},
X  {'@', "000003807280538072e053a072f053d67ef657be7efa55aeffff000000000000",""},
/*  terminator  */
X  {'\0', "0",""}
};
#endif /* PS_VIEW */
X
/* various bitmap definitions. */
X
#include "xconqlogo.icon"
X
#define dots_width 16
#define dots_height 16
static 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
#define mask_width 16
#define mask_height 16
static 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
#define curs_width 16
#define curs_height 16
static 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
#define bomb1_width 32
#define bomb1_height 32
static 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
#define bomb2_width 32
#define bomb2_height 32
static 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
#define bomb3_width 32
#define bomb3_height 32
static 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
#define bomb4_width 32
#define bomb4_height 32
static 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
/* This is the name of a family of programs, so argv[0] inadequate. */
X
#define PROGRAMNAME "xconq"
#define PROGRAMCLASS "XConq"
X
/* Name of default font - why is this wired in? */
X
#define STANDARD "standard"
X
/* Magic number meaning that this pixmap intentionally left blank. */
X
#define NOPIXMAP 17
X
#define INFOLINES 5
X
#define BH 32
X
/* Don't use all of really big displays. */
X
#define MAXDISPLAYWIDTH 900
#define MAXDISPLAYHEIGHT 800
X
/* Use with caution - variable name "side" embedded! */
X
#define sd() ((Screeno *) side->display)
X
#define sdd() (sd()->disp)
X
#define sdds() DefaultScreen(sdd())
X
typedef unsigned int unint;
X
X
/* GC rules are for different fonts etc, but not colors or bitmaps. */
X
typedef 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 helpgc;			/* foreground on background help 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    XFontStruct *helpfont;      /* font for help window */
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    Pixmap logostipple,logopmap;/* the XConq logo bitmap and pixmaps */
X    long logocolor;		/* the color for the logopixmap */
X    Cursor curs;		/* the cursor object itself */
} Screeno;
X
/* resources to retrieve */
X
#define sideoffset(field) XtOffset(Side*, field)
#define displayoffset(field) XtOffset(Screeno*, field)
X
X
static XtResource SideRes[] = {
X  {"map.%s.hexDisplayMode", "Map.Period.HexDisplayMode", "HexDisplayMode",
X     TRUE, sideoffset(showmode), 0, "BorderHex"},
X  {NULL}
},
ColorRes[] = {
X  {"map.%s.ownColor", "Map.Period.Background", "Pixel",
X     FALSE, sideoffset(owncolor), 0, "black"},
X  {"map.%s.alternateColor", "Map.Period.Background", "Pixel",
X     FALSE, sideoffset(altcolor), 0, "blue"},
X  {"map.%s.differentColor", "Map.Period.Background", "Pixel",
X     FALSE, sideoffset(diffcolor), 0, "maroon"},
X  {"map.%s.borderColor", "Map.Period.Foreground", "Pixel",
X     FALSE, sideoffset(bdcolor), 0, "blue"},
X  {"map.%s.grayColor", "Map.Period.Foreground", "Pixel",
X     FALSE, sideoffset(graycolor), 0, "light gray"},
X  {"map.%s.enemyColor", "Map.Period.Foreground", "Pixel",
X     FALSE, sideoffset(enemycolor), 0, "red"},
X  {"map.%s.neutralColor", "Map.Period.Foreground", "Pixel",
X     FALSE, sideoffset(neutcolor), 0, "light gray"},
X  {"map.%s.goodColor", "Map.Period.Foreground", "Pixel",
X     FALSE, sideoffset(goodcolor), 0, "green"},
X  {"map.%s.badColor", "Map.Period.Foreground", "Pixel",
X     FALSE, sideoffset(badcolor), 0, "red"},
X  {NULL}
},
DpyRes[] = {
X  {"textFont", "Font", "Font", TRUE,
X     displayoffset(textfont), 0, TEXTFONT},
X  {"helpFont", "Font", "Font", TRUE,
X     displayoffset(helpfont), 0, HELPFONT},
X  {"iconFont", "Font", "Font", TRUE,
X     displayoffset(iconfont), 0, ICONFONT},
X  {NULL}
};
X
/* Random function declarations. */
X
XXFontStruct * open_font();
Pixmap load_bitmap();
void get_font_size();
Cursor make_cursor();
void program_crash();
X
/* The array of screen objects. */
X
Screeno screens[MAXSIDES];      /* All the "screen objects" */
X
/* Values of parameters generally tied to fonts and the like. */
X
int hw = 20;
int hh = 22;
int hch = 17;
int margin = 2;
int bd = 1;
X
int helpwinlines = 1;           /* size of help window */
X
bool rootcursor;                /* true if using parent window's cursor */
bool windows_up = FALSE;         /* Try to handle initial exposes. */
X
char *routine_executing = "Program Start";
X
/* Put in a default player, probably the invoker of the program. */
/* An empty host name will confuse everybody. */
X
add_default_player()
{
#ifdef UNIX
X    char * default_display = getenv("DISPLAY");
X
X    if (default_display != NULL){
X	add_player(TRUE, default_display);
X    } else {
X	printf("I don't know what display you're on!\n");
X	exit(1);
X    }
#endif /* UNIX */
}
X
#ifndef DEBUG
X
/* Function to print debugging info when a segmentation violation or */
/* bus error occurs. */
X
void program_crash(sig, code, scp, addr)
int sig, code;
struct sigcontext *scp;
char *addr;     
{
X  int i;
X  static bool already_been_here = FALSE;
X
X  close_displays();  
X  printf("Fatal error encountered. Signal %d code %d\n", sig, code);
X  printf("Routine executing %s\n", routine_executing);
X  printf("Procedure stack (incomplete): \n");
X  for (i = 0; i <= procedure_stack_ptr; i++)
X    printf(" %s\n", procedure_executing[i]);
X  if (already_been_here) exit(1);
X  else {
X    already_been_here = TRUE;
X    write_savefile("emergency.save.xconq");
X    if (sig != 2)
X      abort(1);
X    else exit(1);
X  }
}
X
#endif
X
void hang_up(sig, code, scp, addr)
int sig, code;
struct sigcontext *scp;
char *addr;     
{
X  static bool already_been_here = FALSE;
X
X  close_displays();  
X  if (already_been_here) exit(1);
X  else {
X    already_been_here = TRUE;
X    write_savefile(SAVEFILE2);
X    exit(1);
X  }
}
/* Handlers for X catastrophes attempt to do a save first. */
/* Could be more friendly and check success of save, but can't do anything */
/* about it anyway... */
X
static int
handle_x_error (disp, evt)
Display *disp;
XXErrorEvent *evt;
{
X    static int num_errors = 0;
X    char buf[BUFSIZE];
X
X    XGetErrorText(disp, evt->error_code, buf, BUFSIZE);
X    printf("\nX error on display %s: %s\n", DisplayString(disp), buf);
X    if (++num_errors >= 10) {
X        printf("\nX error: trying emergency save!\n");
X        write_savefile(SAVEFILE);
X	exit(1);
X    }
}
X
static int
handle_xio_error (disp)
Display *disp;
{
X    printf("\nX IO error on display %s: trying emergency save!\n",
X	 DisplayString(disp));
X    write_savefile(SAVEFILE);
X    exit(1);
}
X
/* Ignore ^C if humans in the game, do it otherwise, including when the */
/* last human player turns into a machine (this is called by option cmd). */
/* Attempts to be more clever seem to be bad news. */
X
init_sighandlers()
{
#ifdef UNIX
X    if (numhumans > 0 && !Debug) {
X	signal(SIGINT, SIG_IGN);
X    }
#if 0
X    else {
/*	signal(SIGINT, SIG_DFL);*/
X      signal(SIGINT, program_crash);
X    }
X    signal(1, program_crash);
X    signal(SIGINT, program_crash);
#endif
X    signal(SIGHUP, hang_up);
#ifndef DEBUG
X    signal(SIGBUS, program_crash);
X    signal(SIGSEGV, program_crash);
X    signal(SIGFPE, program_crash);
X    signal(SIGILL, program_crash);
X    signal(SIGSYS, program_crash);
X    signal(SIGINT, program_crash);
X    signal(SIGQUIT, program_crash);
X    signal(SIGTERM, program_crash);
#endif
#endif /* UNIX */
X    XSetIOErrorHandler(handle_xio_error);
X    XSetErrorHandler(handle_x_error);
}
X
#ifdef XFONTDIR
static void append_font_path(side, path)
Side *side;
char *path;
{
X    char        **font_path, **new_path;
X    int         npaths, ii;
X
X    font_path = XGetFontPath(sdd(), &npaths);
X
X    for (ii = 0; ii < npaths; ii++) {
X        if (!strcmp(font_path[ii], path)) break;
X    }
X
X    /* I know this looks weird but that's X. */
X    if (ii == npaths) {
X        new_path = (char**)malloc((npaths+1)*sizeof(char*));
X        /*if (!new_path) *****************************************/
X        for (ii=0; ii < npaths; ii++) {
X            new_path[ii] = font_path[ii];
X        }
X        new_path[npaths] = path;
X        XSetFontPath(sdd(), new_path, npaths+1);
X        free(new_path);
X    }
X    XFreeFontPath(font_path);
X    return;
}
#endif /* XFONTDIR */
X
/* Note that the open_display function syncronizes the X server when the */
/* Debug flag is set. */
X
open_display(side)
Side *side;
{
X  side->display = (long) &(screens[side_number(side)]);
X  sdd() = XOpenDisplay(side->host);
X  if (sdd()==NULL) {
X    fprintf(stderr,"Error opening display %s\n", side->host);
X    exit(1);
X  }
X
X  if (Debug) {
X    XSynchronize(sdd(), TRUE);
X    printf("Synching the X server.\n");
X  }
X
X  {
X    XrmDatabase	temp;
X    char	*database;
X    char	path[200];
X
X    XrmInitialize();
X    sprintf(path, "%s/%s", XAPPLRESDIR, PROGRAMCLASS);
X    side->rmdatabase = (long)XrmGetFileDatabase(path);
X    if (side->rmdatabase==NULL) {
X      fprintf(stderr,
X	      "Warning: couldn't open app-defaults file \"%s\", ignoring it\n",
X	      path);
X      side->rmdatabase = (long)XrmGetStringDatabase("");
X    }
X
#ifdef XFONTDIR
X    append_font_path(side, XFONTDIR);
#endif
X
X    database = XResourceManagerString(sdd()); /* grab property off
X						 root window */
X    if (database==NULL) { /* if it's not there then go for $HOME/.Xdefaults */
X      char	*home=getenv("HOME");
X      if (home==NULL) {
X	fprintf(stderr,"No HOME?  you lose all around buddy.\n");
X      } else {
X	sprintf(path,"%s/.Xdefaults", home);
X	temp = XrmGetFileDatabase(path);
X	if (temp==NULL) {
X	  fprintf(stderr,
X		  "Warning: couldn't open X defaults file \"%s\", ignoring it\n",
X		  path);
X	} else {
X	  XrmMergeDatabases(temp,(XrmDatabase *)&side->rmdatabase);
X	}
X      }
X    } else { /* otherwise use the property */
X      XrmMergeDatabases(XrmGetStringDatabase(database),
X			(XrmDatabase *)&side->rmdatabase);
X    }
X  }
X  side->main = XCreateSimpleWindow(sdd(), DefaultRootWindow(sdd()),
X				   50, 3,
X				   display_width(side), display_height(side),
X				   3, white_color(side), black_color(side));
X
X  return 1;
}
X
/* A predicate that tests whether our display can safely be written to. */
X
active_display(side)
Side *side;
{
X    return (side && side->host && !side->lost && side->display);
}
X
display_width(side)
Side *side;
{
X    return min(MAXDISPLAYWIDTH,
X	       ((19 * XDisplayWidth(sdd(), sdds())) / 20));
}
X
display_height(side)
Side *side;
{
X    return min(MAXDISPLAYHEIGHT,
X	       ((19 * XDisplayHeight(sdd(), sdds())) / 20));
}
X
/* Most X displays have enough screen to do a world map. */
X
world_display(side) Side *side; {  return TRUE;  }
X
/* utterly frivolous procedure to create the logo stipple and pixmap */
static void
create_logo(side, gc)
X     Side *side;
X     GC gc;	/* so we don't have to create one */
{
X    XColor	xc;
X    sd()->logostipple = XCreateBitmapFromData(sdd(), side->main,
X        xconqlogo_bits, xconqlogo_width, xconqlogo_height);
X    XSetStipple(sdd(), gc, sd()->logostipple);
X    XSetFillStyle(sdd(), gc, FillOpaqueStippled);
X    xc.red = 0x4000;
X    xc.blue = xc.green = 0x2800;
X    xc.flags = DoRed|DoGreen|DoBlue;
X    XAllocColor(sdd(), DefaultColormap(sdd(), sdds()), &xc);
X    XSetForeground(sdd(), gc, xc.pixel);
X    XSetBackground(sdd(), gc, side->bgcolor);
X    sd()->logopmap = XCreatePixmap(sdd(), side->main, xconqlogo_width,
X				   xconqlogo_height,
X				   DefaultDepth(sdd(), sdds()));
X    XFillRectangle(sdd(), sd()->logopmap, gc, 0, 0, xconqlogo_width,
X				   xconqlogo_height);
}
X
/* this is our fake version of a resource conversion routine.
X   it converts the String in <value> and turns it into an object of
X   type <type> and places it in <dest>.  We assume <dest> points to
X   enough space to hold the object, otherwise why give it to us?
X   The currently supported types are:
X     Pixel:	a string that is either a colorname or a #xxx code
X		is allocated in the colormap and the pixel number
X		is returned in dest.
X     Font:	a font name is turned into a font struct and the
X		pointer to the XFontStruct is returned in dest.
X     HexDispMode: the string is compared to "fullhex"/"borderhex"/
X		"terricons"/"bothicons" with total case insensitivity
X		and converted to one of the corresponding integers
X		from side.h
X
X   If other types become necessary it will be trivial to add them.
X   */
X
convert_thing(side, type, value, dest)
X     Side	*side;
X     char	*type, *value, *dest;
{
X  if (Debug) {
X    printf("converting %s into a %s for %s\n", value, type, side->name);
X  }
X  if (0==strcmp(type, "Pixel")) {
X    XColor	xc;
X    if (Debug) printf("Allocating %s\n", value);
X    if (!XParseColor(sdd(), DefaultColormap(sdd(), sdds()), value, &xc)) {
X      fprintf(stderr, "%s: invalid color spec %s\n", side->host, value);
X      return;
X    }
X    if (!XAllocColor(sdd(), DefaultColormap(sdd(), sdds()), &xc)) {
X      fprintf(stderr, "%s: unable to allocate color %s\n", side->host, value);
X      return;
X    }
X    *(long*)dest = xc.pixel;
X  } else if (0==strcmp(type, "Font")) {
X    XFontStruct **font = (XFontStruct **)dest;
X    *font = XLoadQueryFont(sdd(), value);
X    if (*font == NULL) {
X      fprintf(stderr, "%s: Can't open font %s, ", side->host, value);
X      if (font == &(sd()->textfont)) {
X	fprintf(stderr, "you're hosed\n");
X	exit(1);
X      } else {
X	fprintf(stderr, "trying to substitute text font\n");
X	*font = sd()->textfont;
X      }
X    }
X    if (Debug) printf("Opened font \"%s\" ...\n", value);
X  } else if (0==strcmp(type, "HexDisplayMode")) {
X    static char *hexdispmodes[] = {
X      "FullHex", "BorderHex", "TerrIcons", "BothIcons", NULL };
X    int	i;
X    for (i=0; hexdispmodes[i] != NULL; i++) {
X      if (0==strcasecmp(value, hexdispmodes[i]))
X	break;
X    }
X    if (hexdispmodes[i]!=NULL) {
X      *(short*)dest = i;
X    }
X  } else {
X    fprintf(stderr, "What the heck kind of resource is %s?!\n", type);
X    exit(1);
X  }
}
X
/* src1 contains a prefix, usually the name or class (xconq or XConq).
X   src2 contains a resource path like Map.Period.AltColor or map.%s.altColor.
X   The %s allows us to insert the period name into a resource.
X   dest must have enough space to hold the final string, however
X   big that is >:) */
format_resource_string(src1, src2, dest)
X     char	*src1, *src2, *dest;
{
X  static char	buf[200],*p;
X  sprintf(buf, "%s.%s", src1, src2);
X  sprintf(dest, buf, period.name);
X  for (p=dest; *p; p++)
X    if (*p==' ')
X      *p = '_';
}
X
/* this procedure gets resources from the display's resource database.
X   It uses the toolkit's XtResource structure because it seems to have
X   all the structure memebers we need and looks familiar, but we do
X   use it slightly differently.
X   We retrieve resources that go in the Side structure from the SideRes
X   list.  We retrieve resources that go in the Screeno structure from
X   the DpyRes list */
get_resources(side, resources, base)
X     Side	*side;
X     XtResource	*resources;
X     char	*base;
{
X  XtResource	*res;
X  static char	rmName[200], rmClass[200];
X  char	*rtype, *resval;
X  XrmValue	rval;
X
X  for (res = resources; res->resource_name!=NULL; res++) {
X    if (side->monochrome && !res->resource_size) {
X      /* goofy hack to avoid setting colors on monochrome */
X      continue;
X    }
X    format_resource_string(PROGRAMNAME, res->resource_name, rmName);
X    format_resource_string(PROGRAMCLASS, res->resource_class, rmClass);
X    XrmGetResource((XrmDatabase)side->rmdatabase, rmName,
X		   rmClass, &rtype, &rval);
X    if (rtype==NULL) {
X      resval = res->default_addr;
X    } else if (0!=strcmp(rtype, "String")) {
X      fprintf(stderr, "Whoa!, funky resource type %s for %s\n",
X	      rtype, rmName);
X      resval = res->default_addr;
X    } else {
X      resval = rval.addr;
X    }
X    convert_thing(side, res->resource_type, resval,
X		  base + (res->resource_offset));
X  }
}
X
get_color_resources(side)
X     Side	*side;
{
X  get_resources(side, ColorRes, side);
}
X
/* Could use handlers for X failures... */
X
/* Do misc setup thingies. */
X
/* Do the rigmarole to convert all those short arrays into X-approved */
/* Bitmaps.  Note that this has to be for *each* display separately (!) */
/* Also get the cursor shape.  If the hardware can't hack the desired */
/* cursor size, warn about it and just use the root window's cursor. */
/* 0x0 cursor specs seem to be don't cares - machine can handle any size */
/* X11 also needs gazillions of GCs, since we've got so many fonts and */
/* colors and bitmaps. */
X
init_misc(side)
Side *side;
{
X    int u;
X    unsigned int w, h;
X    unsigned long mask;
X    XGCValues values;
X    Pixmap mmask, mcurs, dots;
X    GC gc;
X    char *name;
X
#ifdef PS_VIEW
X    font_entry *entryp;
X
/*  make index to xconq_font  */
X    for (u=0; u<128; u++) {
X      entry_index[u] = xconq_font;
X    }
X    for (entryp=xconq_font; entryp->ident; entryp++) {
X      entry_index[entryp->ident] = entryp;
X    }
#endif /* PS_VIEW */
X
X    side->margin = margin;
X    side->bd = bd;
X    side->hw = hw;
X    side->hh = hh;
X    side->hch = hch;
X    /* get the name from the display unless the game is being restored from a 
X       save file. */
X    if (!midturnrestore &&
X	(name = XGetDefault(sdd(), PROGRAMNAME, "SideName")) != NULL)
X      side->name = name;
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()->helpgc = 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);
#if 1
X    get_resources(side, SideRes, side);
X    get_resources(side, DpyRes, sd());
X    /* ginit retrieves the colors */
#else
X    sd()->textfont = open_font(side, TEXTFONT, "TextFont", NULL);
X    sd()->helpfont = open_font(side, HELPFONT, "HelpFont", sd()->textfont);
X    sd()->iconfont = open_font(side, ICONFONT, "IconFont", sd()->textfont);
#endif
X    get_font_size(sd()->textfont, &(side->fw), &(side->fh) );
X    get_font_size(sd()->helpfont, &(side->hfw), &(side->hfh) );
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    if (Debug) printf("doing textgc...\n");
X    XSetFont(sdd(), sd()->textgc, sd()->textfont->fid);
X    if (Debug) printf("doing helpfont ...\n");
X    XSetFont(sdd(), sd()->helpgc, sd()->helpfont->fid);
X    if (Debug) printf("doing icongc ...\n");
X    XSetFont(sdd(), sd()->icongc, sd()->iconfont->fid);
X    if (Debug) printf("done fonts ...\n");
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, u);
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(), sdds()));
X    sd()->bwdots = XCreatePixmap(sdd(), side->main, dots_width, dots_height,
X				 DefaultDepth(sdd(), sdds()));
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
X    create_logo(side,gc); /* this procedure changes the GC rather radically */
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("Best cursor size 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
/* Since XCreatePixmapCursor() takes XColors and not pixel values we */
/* have to look the colors associated with the foreground and */
/* background pixel values up in the color table and pass them to */
/* XCreatePixmapCursor(). */
X   
Cursor make_cursor(dpy, curs, mask, foreground, background, x, y)
Display *dpy;
Pixmap curs, mask;
unsigned long foreground, background;
unsigned int x, y;
{
X    XColor defs[2];
X
X    defs[0].pixel = foreground;
X    defs[1].pixel = background;
X    XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), defs, 2);
X    return  XCreatePixmapCursor(dpy, curs, mask, &defs[0], &defs[1], x, y);
}
X
/* Open a font, possibly substituting another font if our desired one is */
/* missing for some reason. */
X
XXFontStruct *
open_font(side, name, xdefault, altfont)
Side *side;
char *name, *xdefault;
XXFontStruct * altfont;
{
X  char *altname;
X  XFontStruct * font;
X
X  if ((altname = XGetDefault(sdd(), PROGRAMNAME, xdefault)) != NULL)
X    name = altname;
X  if ((font = XLoadQueryFont(sdd(), name)) == NULL) {
X    fprintf(stderr, "Can't open font \"%s\" on \"%s\"\n", name, side->host);
X    if (altfont != NULL) {
X      /* ought to display the name... */
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  if (Debug) printf("Opened font \"%s\" ...\n", name);
X  return font;
}
X
/* Force X11 font fanciness into semblance of X10 font plainness. */
X
void
get_font_size(font, width, height)
XXFontStruct * font;
short *width, *height;
{
X    *width = font->max_bounds.width;
X    *height = font->max_bounds.ascent + font->max_bounds.descent;
X    if (Debug) {
X	printf("returning font size %d %d\n", (int)*width, (int)*height);
X    }
}
X
/* Try to load a bitmap of the given name, looking in both the current dir */
/* and the library dir. */
X
Pixmap
load_bitmap(side, u)
Side *side;
int u;
{
X    int hotx, hoty;
X    unsigned int w, h, a;
X    Pixmap rslt;
X    char *name = utypes[u].bitmapname;
X
X    make_pathname(NULL, name, "b", spbuf);
X    a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &hotx, &hoty);
X    if (a == BitmapSuccess) {
#ifdef PS_VIEW
X      store_bitmap(u);
#endif /* PS_VIEW */
X      return rslt;
X    }
X    make_pathname(xconqlib, name, "b", spbuf);
X    a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &hotx, &hoty);
X    if (a == BitmapSuccess) {
#ifdef PS_VIEW
X      store_bitmap(u);
#endif /* PS_VIEW */
X      return rslt;
X    }
X    fprintf(stderr, "Bitmap name \"%s\" not found here or in \"%s\"!\n",
X	    name, xconqlib);
X    return (-1);
}
X
#ifdef PS_VIEW
store_bitmap(u)
int u;
{
X  unsigned int w, h, a, x_hot, y_hot;
X  int row, col, i, mask, hex;
X  unsigned char *data, *dp;
X  font_entry *new_entry;
X  
X  a = XmuReadBitmapDataFromFile (spbuf, &w, &h, &data, &x_hot, &y_hot);
X  new_entry = (font_entry *) malloc(sizeof(font_entry));
X  if (a==BitmapSuccess && new_entry!=NULL) {
X    entry_index[utypes[u].uchar] = new_entry;
X
/*  build hex dump  */
X    i = 0;
X    dp = data;
X    for (row=0; row<h; row++) {
X      hex = 0;
X      for (col=0; col<w; col++) {
X	mask = 1 << (col & 7);
X	hex = (hex<<1) | ((*dp & mask) != 0);
X	if ((col & 3) == 3) {
X	  sprintf(new_entry->bit1 + i, "%x", hex);
X	  hex = 0;
X	  i++;
X	}
X	if ((col & 7) == 7) {
X	  dp++;
X	}
X      }
X      if ((w & 7) != 0) {
X	dp++;
X      }
X      if ((w & 3) != 0) {
X	hex <<= (w & 3);
X	sprintf(new_entry->bit1 + i, "%x", hex);
X	i++;
X      } 
X    }
X    new_entry->bit1[i] = 0;
X    new_entry->bit2[0] = 0;
X    
X  } else {
X    fprintf(stderr, "Something wrong with bitmap \"%s\",\n", spbuf);
X    fprintf(stderr, "will be left blank in PostScript view\n");
X  }
}
X
#endif /* PS_VIEW */
X
/* This routine has to be able to cope with window managers constraining */
/* size.  Actually, the main window was already opened when the display */
/* was opened, so the name is not quite accurate! */
X
create_main_window(side)
Side *side;
{
X    Pixmap dots;
X    XSizeHints hints;
X    XWMHints	wmhints;
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/4;
X    hints.min_height = side->mh/4;
X    hints.flags = PSize|PMinSize;
X    XSetNormalHints(sdd(), side->main, &hints);
X    wmhints.flags = InputHint|IconPixmapHint|WindowGroupHint;
X    wmhints.input = True;
X    wmhints.icon_pixmap = sd()->logostipple;
X    wmhints.window_group = side->main;
X    XSetWMHints(sdd(), side->main, &wmhints);
}
X
/* Help window is not necessarily a subwindow, though it might be sometimes. */
X
create_help_window(side)
Side *side;
{
X    XWMHints	wmhints;
X    helpwinlines =
X	max(55, (24 + period.numrtypes + period.numttypes + period.numutypes));
X
X    side->help = XCreateSimpleWindow(sdd(), DefaultRootWindow(sdd()),
X				     0, 0, 80*side->hfw+1,
X				     helpwinlines*side->hfh+1,
X				     1, side->fgcolor, side->bgcolor);
#if 0
X    /* This is fun but makes the help window hard to read, even in 
X       muted color. */
X    XSetWindowBackgroundPixmap(sdd(), side->help, sd()->logopmap);
#endif
X    XStoreName(sdd(), side->help, "xconq-help");
X
X    wmhints.flags = IconPixmapHint|WindowGroupHint;
X    wmhints.icon_pixmap = sd()->logostipple;
X    wmhints.window_group = side->main;
X    XSetWMHints(sdd(), side->help, &wmhints);
}
X
/* Subwindow creator. */
X
create_window(side, x, y, w, h)
Side *side;
int x, y, w, h;
{
X    return XCreateSimpleWindow(sdd(), side->main, x, y, w, h,
X			       1, side->fgcolor, side->bgcolor);
}
X
/* force x to retain this window. */
set_retain(side, window)
Side *side;
long window;
{
X  XSetWindowAttributes foo;
X  char *retain;
X
X  if ((retain = XGetDefault(sdd(), PROGRAMNAME, "Retain")) == NULL ||
X      0!=strcasecmp(retain, "no")) {
X    foo.backing_store = WhenMapped;
X    XChangeWindowAttributes(sdd(), window, CWBackingStore, &foo);
X  }
}
X
X
/* Do little things necesary to make it all go, in this case mapping all */
/* the windows (except help win). */
X
fixup_windows(side)
Side *side;
{
X    XMapWindow(sdd(), side->main);
X    XMapSubwindows(sdd(), side->main);
X    /* if (!global.giventime) XUnmapWindow(sdd(), side->clock); */
X    if (!rootcursor) XDefineCursor(sdd(), side->map, sd()->curs);
}
X
/* Specify the sorts of input that will be allowed - main window needs to */
/* see mouse buttons so unit type selection works right. */
X
enable_input(side)
Side *side;
{
X    XSelectInput(sdd(), side->main, /* ExposureMask|*/
X		 KeyPressMask|StructureNotifyMask);
X    XSelectInput(sdd(), side->map, ButtonPressMask|ExposureMask);
X    XSelectInput(sdd(), side->state, ButtonPressMask|ExposureMask);
X    XSelectInput(sdd(), side->msg, ButtonPressMask|ExposureMask);
X    XSelectInput(sdd(), side->help, KeyPressMask|ExposureMask);
X    XSelectInput(sdd(), side->info, ExposureMask);
X    XSelectInput(sdd(), side->prompt, ExposureMask);
X    XSelectInput(sdd(), side->world, ButtonPressMask|ExposureMask);
X    XSelectInput(sdd(), side->sides, ExposureMask);
X    XSelectInput(sdd(), side->timemode, ExposureMask);
/*    XSelectInput(sdd(), side->clock, ExposureMask); */
}
X
/* Move windows and change their sizes to correspond with the new sizes of */
/* viewports, etc */
X
reset_misc(side)
Side *side;
{
X    Pixmap dots;
X    XSizeHints hints;
X    XGCValues values;
X    unsigned long 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/4;  hints.min_height = side->mh/4;
X    hints.flags = PSize|PMinSize;
X    XSetNormalHints(sdd(), side->main, &hints);
X    if (Debug)
X      printf("hinting for %dx%d window\n", side->mw, side->mh);
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()->helpgc, 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
/* Alter the size and position of a window. */
X
change_window(side, win, x, y, w, h)
Side *side;
Window win;
int x, y, w, h;
{
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
/* Return the number of colors - this is used to guess about monochromeness. */
X
display_colors(side)
Side *side;
{
X    return XDisplayCells(sdd(), sdds());
}
X
white_color(side)
Side *side;
{
X    return WhitePixel(sdd(), sdds());
}
X
black_color(side)
Side *side;
{
X    return BlackPixel(sdd(), sdds());
}
X
/* Get a color set up and warn if not getting what was asked for.  We can */
/* tolerate being off somewhat.  (Note X rgb value range is 0-65535.) */
X
#define CLOSE_ENOUGH(X,Y) (abs(((int) X) - ((int) Y)) < 2000)
X
long
request_color(side, name, class, fallback)
Side *side;
char *name, *class, *fallback;
{
X    XColor c, avail;
X    static char	rmName[200], rmClass[200];
X    char	*rtype;
X    XrmValue	rval;
X    char	*colorname;
X
X    if (class!=NULL && name!=NULL) {
X      sprintf(rmName, "%s.%s", PROGRAMNAME, name);
X      sprintf(rmClass,"%s.%s", PROGRAMCLASS, class);
X      XrmGetResource((XrmDatabase)side->rmdatabase, rmName,
X		     rmClass, &rtype, &rval);
X      if (rtype==NULL) {
X	colorname = fallback;
X      } else if (0!=strcmp(rtype, "String")) {
X	fprintf(stderr, "Whoa!, funky resource type %s for %s\n",
X		rtype, rmName);
X	colorname = fallback;
X      } else {
X	colorname = rval.addr;
X      }
X    } else {
X      colorname = fallback;
X    }
X
X    if (Debug) printf("Allocating %s\n", colorname);
X    if (!XAllocNamedColor(sdd(), DefaultColormap(sdd(), sdds()),
X			  colorname, &avail, &c)) {
X      fprintf(stderr, "Error: Couldn't allocate color %s!", colorname);
X      return white_color(side);
X    }
X    if (!(CLOSE_ENOUGH(c.red, avail.red) &&
X	  CLOSE_ENOUGH(c.green, avail.green) &&
X	  CLOSE_ENOUGH(c.blue, avail.blue))) {
X	fprintf(stderr, "Warning: %s color is way off on \"%s\"! ",
X		name, side->host);
X	fprintf(stderr, "(%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
/* Main funnel for input returns both mouse and keyboard events, and maybe */
/* other kinds eventually.  Some events like window exposure are handled */
/* strictly locally. */
/*
X  Timeout needed to make it play smooth while still being fair.
X */
/*struct timeval { 
X	long	tv_sec;		/* seconds * /
X	long	tv_usec;	/* and microseconds * /
}; */
X
struct timeval timeout = {0, 500000};
X
get_input()
{
#ifdef SELECT2
X    int i, mask;
X    Side *side, *asides[32];
X    bool waiters = FALSE;
X
X    mask = 0;
X    for_all_sides(side) {
X	if (active_display(side)) {
X	    side->redisplay_ok = TRUE;
X	    mask |= (1 << ConnectionNumber(sdd()));
X	    asides[ConnectionNumber(sdd())] = side;
X	    while (XPending(sdd()) > 0) {
X		process_events(side);
X		waiters = TRUE;
X	    } 
X	    
X	}
X    }
X    if (waiters) {
X      if (Debug) printf("Handled pending events, so didn't need to wait\n");
X      return;
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, &timeout) < 0) {
X      if (errno!=EINTR) {
X	fprintf(stderr, "error in select!\n");
X	abort();
X      }
X    } else {
X	for (i = 0; i < 32; ++i) {
X	    if (mask & (1 << i)) {
X		process_events(asides[i]);
X	      }
X	}
X	for_all_sides(side) {
X	  int delta_time = (time(0) - side->lasttime);
X
X	  side->lasttime = time(0);
X	  if (side->more_units) {
X	    side->timeleft -= delta_time;
X	    side->timetaken += delta_time;
X	    update_clock(side);
X	  }
X	}
X    }
#else
#if 0
#ifdef BOGUS
X    /* this doesn't work anymore */
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    }
#endif
#endif
#endif /* SELECT2 */
}
X
/* Look at a single event and fill the request structure appropriately. */
X
process_events(side)
Side *side;
{
X    XEvent evt;
X    char buf[BUFSIZE];
X    int nchar, rawx, rawy;
X
X    side->reqtype = GARBAGE;
X    XNextEvent(sdd(), &evt);
X    switch (evt.type) {
X    case KeyPress:
X	if (evt.xkey.window != side->main && evt.xkey.window != side->help) 
X	    return;
X	nchar = XLookupString(&(evt.xkey), buf, BUFSIZE, NULL, NULL);
X	if (nchar > 0) {
X	    side->reqtype = KEYBOARD;
X	    side->reqch = *buf;
X	    if (Debug) printf(isprint(toascii(side->reqch)) ?
X			      "Host %s returns key '%c'\n" :
X			      "Host %s returns key '\\%03o'\n" ,
X			      side->host, side->reqch);
X	    if (evt.xkey.window==side->help) {
X	      x_help(side);
X	      /* this little help handler might be a bad idea.
X		 The entire xconq event loop is hacked.  That's
X		 why Stan's redoing it */
X	    } else if (side->reqch == '\014') { /* control l */
X	      redraw(side);
X	      side->reqtype = GARBAGE;
X	    }
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	    side->reqch = (evt.xbutton.state & ShiftMask) ? 1 : 0;
X	    /* the modifier is used by x_command */
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->world) {
X	    rawx = evt.xbutton.x;  rawy = evt.xbutton.y; 
X	    side->reqtype = MAPPOS;
X	    w_deform(side, rawx, rawy, &(side->reqx), &(side->reqy));
X	    if (Debug) printf("Host %s returns world %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	} else if (evt.xbutton.window == side->msg) {
X	  if (evt.xbutton.y < side->nh * side->fh / 2)
X	    side->reqtype = SCROLLUP;
X	  else side->reqtype = SCROLLDOWN;
X	}
X	break;
X    /*case MapNotify:*/
X    case Expose:
#if 0
X	do {
#endif
X	  /* Prevent multiple redisplays in exit robot check */
X	  if (side->redisplay_ok
#if 0
X	      && evt.xexpose.count == 0
#endif
X	      ) {
X	    int	count;
X	    Region	reg;
X	    reg = XCreateRegion();
X	    count=0;
X	    do { /* burn all expose events for this window.
X		    ideally we'd collect a region and just redraw that
X		    part, but we aren't that sophisticated yet */
X	      XRectangle	rect;
X
X	      /*count++;
X	      printf("0x%x %dx%d+%d+%d", evt.xexpose.window,
X		     evt.xexpose.width,evt.xexpose.width,
X		     evt.xexpose.x,evt.xexpose.y); */
X	      rect.x = evt.xexpose.x;
X	      rect.y = evt.xexpose.y;
X	      rect.width = evt.xexpose.width;
X	      rect.height = evt.xexpose.height;
X	      XUnionRectWithRegion(&rect,reg, reg);
X	    } while (XCheckWindowEvent(sdd(), evt.xexpose.window,
X				       ExposureMask, &evt));
X	    XSetRegion(sdd(), sd()->textgc, reg);
X	    /* printf("%d expose events for window 0x%x burned\n",count,
X		   evt.xexpose.window); */
X	    if (evt.xexpose.window == side->map) {
X	      erase_cursor(side);
X	      show_map(side);
X	    } else if (evt.xexpose.window == side->msg) {
X	      show_note(side,FALSE);
X	    } else if (evt.xexpose.window == side->world) {
X	      show_world(side);
X	    } else if (evt.xexpose.window == side->info) {
X	      show_info(side);
X	    } else if (evt.xexpose.window == side->prompt) {
X	      XSetClipMask(sdd(), sd()->textgc, None);
X	      show_prompt(side);
X	    } else if (evt.xexpose.window == side->sides) {
X	      show_all_sides(side,FALSE);
X	    } else if (evt.xexpose.window == side->timemode) {
X	      show_timemode(side,FALSE);
X	    } else if (evt.xexpose.window == side->clock) {
X	      /*	show_clock(side); */
X	    } else if (evt.xexpose.window == side->state) {
X	      XSetRegion(sdd(), sd()->varicongc, reg);
X	      XSetRegion(sdd(), sd()->unitgc, reg);
X	      XSetRegion(sdd(), sd()->unittextgc, reg);
X	      show_state(side,FALSE);
X	      XSetClipMask(sdd(), sd()->varicongc, None);
X	      XSetClipMask(sdd(), sd()->unitgc, None);
X	      XSetClipMask(sdd(), sd()->unittextgc, None);
X	    }  else if (evt.xexpose.window == side->help) {
X	      side->reqtype = KEYBOARD; /* hoo boy :( */
X	      side->reqch = '\014';
X	      x_help(side);
X	    } else if (evt.xexpose.window == side->main) {
X	    } else {
X	      printf("WARNING: Unknown window being redisplayed. \n");
X	      redraw(side);
X	    }
X	    XSetClipMask(sdd(), sd()->textgc, None);
X	    XDestroyRegion(reg);
X	  }
#if 0
X	} while (XCheckMaskEvent(sdd(), ExposureMask, &evt));
X	side->redisplay_ok = FALSE;
X	/* flush_input(side); */
X	if (Debug) printf("Host %s exposes itself\n", side->host);
X	if (!humanside(side))
X	  while (XPending(sdd()) > 0) {
X	    process_events(side);
#define ESCAPE '\033'           /* standard abort character */
X	    if (!humanside(side) && side->reqtype == KEYBOARD &&
X		side->reqch == ESCAPE) {
X	      side->humanp = TRUE;
X	      numhumans++;
X	      init_sighandlers();
X	      return;
X	    }
X	  }
#endif
X	break;
X    case ConfigureNotify:
X	if (Debug) {
X	  printf("Want a %dx%d window\n", evt.xconfigure.width,
X		 evt.xconfigure.height);
X	}
X	if (evt.xconfigure.width != side->mw ||
X	    evt.xconfigure.height != side->mh) {
X	  resize_display(side, evt.xconfigure.width, evt.xconfigure.height);
X	  /* set_sizes has been called already */
X	  reconfigure_display(side,False);
X	} else if (Debug) {
X	  printf(" already got one. (must be stacking or relocation event)\n");
X	}
X	break;
X      case ClientMessage:
X	break;
X    default:
X	/* shouldn't this be left in? */
#if 0
X        case_panic("event type", evt.type);
#endif
X	break;
X    }
}
X
#define ESCAPE '\033'           /* standard abort character */
X
/* Allow a player to exit robot mode, even if he is the only player. */
exit_robot_check()
{
X  Side *side;
X  
X  for_all_sides(side) {
X    if (active_display(side)) {
X      side->redisplay_ok = TRUE;
X      while (XPending(sdd()) > 0) {
X	process_events(side);
X	if (!humanside(side) && side->reqtype == KEYBOARD &&
X	    side->reqch == ESCAPE) {
X	  side->humanp = TRUE;
X	  numhumans++;
X	  init_sighandlers();
X	  return;
X	}
X      } 
X    }
X  }
}
X
/* Freese everything until given side supplies input, use sparingly. */
X
freeze_wait(side)
Side *side;
{
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.xkey), buf, BUFSIZE, NULL, NULL);
X	    if (nchar > 0) 
X		return *buf;
X	    else
X		return '\0';
X	}
X    }  
}
X
/* Get rid of extra key/mouse clicks *only*. */
X
flush_input(side)
Side *side;
{
X    if (!windows_up) {
X	windows_up = TRUE;
X	get_input();
X	/* fetch initial expose event */
X    }
X    if (humanside(side)) {
X	XEvent evt;
X
X	/* discard all pending mouse and keyboard events. */
X	while (XCheckMaskEvent(sdd(), KeyPressMask|ButtonPressMask, &evt));
X	side->reqtype = GARBAGE;
X    }
X    side->reqchange = TRUE;
}
X
/* Trivial abstraction - sometimes other routines like to ensure all output */
/* actually on the screen. */
X
flush_output(side) 
Side *side; 
{  
X    if (humanside(side)) XFlush(sdd());  
X    side->reqchange = TRUE;
}
X
/* General window clearing. */
X
clear_window(side, win)
Side *side;
Window win;
{
X    XClearArea(sdd(), win, 0,0, 0,0, False);
}
X
/* Draw a single horizontal constant-color bar on the world map.  If part */
/* would not be drawn because of the map's obliqueness, cut it in two and */
/* wrap one of the pieces around. */
X
draw_bar(side, x, y, len, color)
Side *side;
int x, y, len, color;
{
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    }
#ifdef STUPIDFLUSH
X    XFlush(sdd());
#endif /* STUPIDFLUSH */
}
X
/* Invert the outline box on the world map.  This is a little tricky, */
/* because we want the lines to run through the middle of the world's */
/* hexes, and because the line drawn should not overlap (or the overlaps */
/* will be doubly inverted and look strange). */
X
invert_box(side, vcx, vcy)
Side *side;
int vcx, vcy;
{
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
/* This interfaces higher-level drawing decisions to the rendition of */
/* individual pieces of display. */
X
draw_terrain_row(side, sx, sy, buf, len, color)
Side *side;
int sx, sy, len, color;
char *buf;
{
X    sy += sd()->iconfont->max_bounds.ascent;
X    XSetForeground(sdd(), sd()->icongc, color);
X    XDrawString(sdd(), side->map, sd()->icongc, sx, sy, buf, len);
#ifdef STUPIDFLUSH
X    XFlush(sdd());
#endif /* STUPIDFLUSH */
}
X
/* Flash a pair of lines up, slow enough to draw the eye, but not so slow */
/* as to get in the way. */
X
flash_position(side, sx, sy, tm)
Side *side;
int sx, sy, tm;
{
X    int sx1, sy1, sx2, sy2;
X
X    if (tm > 0) {
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	nap(tm);
X	XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy1, sx2, sy2);
X	XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy2, sx2, sy1);
X    }
}
X
/* Napping is like sleeping, but maybe shorter.  Arg is milliseconds. */
X
nap(t)
long t;
{
#ifdef UNIX
#ifdef SELECT2
X    struct timeval naptime;
X
X    naptime.tv_usec = (t % 1000) * 1000;
X    naptime.tv_sec = t / 1000;
X    select(0, NULL, NULL, NULL, &naptime);
#else
X    if (t >= 1000) sleep(t/1000);
#endif
#endif /* UNIX */
}
X
/* The "cursor icon" is just a pair of special chars - nothing to do with */
/* X's notion of cursors. */
X
draw_cursor_icon(side, sx, sy)
Side *side;
int sx, sy;
{
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
/* Draw the icon for a hex (given as a char). */
X
draw_hex_icon(side, win, sx, sy, color, ch)
Side *side;
Window win;
int sx, sy, color;
char ch;
{
X    XSetForeground(sdd(), sd()->varicongc, color);
X    sy += sd()->iconfont->max_bounds.ascent;
X    XDrawString(sdd(), win, sd()->varicongc, sx, sy, &ch, 1);
}
X
/* Draw the number of an unfriendly side (never called for own units). */
X
draw_side_number(side, win, sx, sy, n, color)
Side *side;
Window win;
int sx, sy, n, color;
{
X    char ch = n%22;
X
X    ch += (ch<10)?'0':('A' - 10);
X
X    if (n >= 0 && n!=MAXSIDES) {
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
draw_blast_icon(side, win, sx, sy, type, color)
Side *side;
Window win;
int sx, sy, color;
char type;
{
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    flush_output(side);
}
X
/* Flash the player's screen in an unmistakable way. */
X
invert_whole_map(side)
Side *side;
{
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
/* Draw just one of the mushroom cloud shapes. */
X
draw_mushroom(side, x, y, i)
Side *side;
int x, y, i;
{
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), 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
/* Confirm that we can indeed do bar graph displays. */
X
bar_graphs(side) Side *side;  {  return TRUE;  }
X
/* Do yet another X-toolkit-type function.  This draws a bar graph. */
X
draw_graph(side, number, amount, total, critical, title)
Side *side;
int number, amount, total, critical;
{
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
/* Splash a unit image (either bitmap or font char) onto some window. */
X
draw_unit_icon(side, win, x, y, u, color)
Side *side;
Window win;
int x, y, u, color;
{
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
/* General text drawer. */
X
draw_text(side, win, x, y, str, color)
Side *side;
Window win;
int x, y, color;
char *str;
{
X  if (win == side->help) draw_help_text(side, win, x, y, str, color);
X  else {
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    }}
#ifdef STUPIDFLUSH
X    XFlush(sdd());
#endif /* STUPIDFLUSH */
}
X
/* General text drawer. */
X
draw_help_text(side, win, x, y, str, color)
Side *side;
Window win;
int x, y, color;
char *str;
{
X    y += sd()->helpfont->max_bounds.ascent;
X    if (color != side->bgcolor) {
X	XSetForeground(sdd(), sd()->helpgc, color);
X	XDrawString(sdd(), win, sd()->helpgc, x, y, str, strlen(str));
X    } else {
X	XSetForeground(sdd(), sd()->helpgc, side->bgcolor);
X	XSetBackground(sdd(), sd()->helpgc, side->fgcolor);
X	XDrawString(sdd(), win, sd()->helpgc, x, y, str, strlen(str));
X	XSetBackground(sdd(), sd()->helpgc, side->bgcolor);
X    }
}
X
/* Draw a line through some side's title. */
X
draw_scratchout(side, pos)
Side *side;
int pos;
{
X    XSetForeground(sdd(), sd()->textgc, side->fgcolor);
X    XDrawLine(sdd(), side->sides, sd()->textgc, 0, pos, 30*side->fw, pos);
}
X
/* Beep the beeper! */
X
beep(side)
Side *side;
{
X    XBell(sdd(), sdds());
}
X
/* Little routines to pop up the help window and make it go away again */
/* They only get called when display is in use. */
X
reveal_help(side)
Side *side;
{
X    XEvent evt;
X    XWindowAttributes	xwa;
X
X    XMapWindow(sdd(), side->help);
X    XGetWindowAttributes(sdd(), side->help, &xwa);
X    printf("window state: %d\n",xwa.map_state);
X    if (xwa.map_state == IsUnmapped) {
X      /* wait until this window is exposed to return. */
X      XWindowEvent(sdd(), side->help, ExposureMask, &evt);
X    }
X    return TRUE;
}
X
conceal_help(side)
Side *side;
{
X    XUnmapWindow(sdd(), side->help);
X    flush_output(side);
}
X
/* Shut a single display down, but only if there's one to operate on. */
/* Hit the display slot, for safety. */
X
close_display(side)
Side *side;
{
X    XrmDestroyDatabase((XrmDatabase) side->rmdatabase);
X    XCloseDisplay(sdd());
X    side->display = (long) NULL;
}
X
#ifdef PS_VIEW
X
/* check if the unit name is junky (see make_unit_name in unit.c) */
bool 
is_junky(unit)
Unit *unit;
{
X  if (unit==NULL)  return TRUE;
X  if (!isupper(unit->name[0]))  return FALSE;
X  if (!isupper(unit->name[1]))  return FALSE;
X  if (unit->name[2]!='-')  return FALSE;
/*  when a junky name like "XX-*-nn" is saved and restored,
X                it becomes "XX- -nn".  */
X  if (unit->name[3]!=utypes[unit->type].uchar &&
X      utypes[unit->type].uchar!='*')  return FALSE;
X  if (unit->name[4]!='-')  return FALSE;
X  if (!isdigit(unit->name[5]))  return FALSE;
X  return TRUE;
}
X
/*  allocated in mvars.c  */
extern char shortbuf[BUFSIZE];
X
/*  convert to PostScript escape sequences:
X    change '\' to '\\', '(' to '\(', ')' to '\)'  */
char *
add_esc_char(ch)
char ch;
{
X  if (ch=='(' || ch==')' || ch=='\\') {
X    sprintf(shortbuf, "\\%c", ch); }
X  else {
X    sprintf(shortbuf, "%c", ch); }
X
X  return shortbuf;
}
X
char *
add_esc_string(str)
char *str;
{
X  char *ps, *pb;
X  for (ps=str, pb=shortbuf; *ps; ps++, pb++) {
X    if (*ps=='(' || *ps==')' || *ps=='\\') {
X      *pb = '\\'; pb++; }
X    *pb = *ps;
X  }
X  *pb = '\0';
X
X  return shortbuf;
}
X
dump_view(side)
Side *side;
{
X  char ch1, ch2;
X  int x, y, y0, xx, i, j, vs, t, u, s, c, nx, ny;
X  int width, height, page;
X  viewdata view;
X  Side *side2;
X  int ns2;
X  FILE *fp;
X  char buf1[BUFSIZE];
X  char *userp, *hostp, *nam;
X  Unit *unit;
X  font_entry *entryp;
X
/*  parameters, ultimately to be settable by resources and otherwise  */
/*  all length are in PostScript units (1/72 in)  */
X
X  double in, cm, hex_size, hex_border_width, page_width, page_height, 
X         top_margin, bottom_margin, left_margin, right_margin, enemy_gray;
X  int names, corner_coord;
X
X  in = 72.0;
X  cm = in/2.54;
X
/*  --------------------  customization section -------------------- */
X
X  page_width =    8.5*in;  /*  US letter  */
X  page_height =  11.0*in;  /*  US letter  */
X  page_width =   21.0*cm;  /*  A4  */
X  page_height =  29.7*cm;  /*  A4  */
X
/*  title and coordinates are printed in the "margins":
X    make room in top_margin, left_margin and right_margin  */
X  top_margin =    3.0*cm;
X  bottom_margin = 2.0*cm;
X  left_margin =   2.0*cm;
X  right_margin =  2.0*cm;
X
X  hex_size =      0.4*cm;
X  hex_border_width = 0.005*cm;  /*  0 or negative to avoid hex borders  */
X
/*  names = 0:  don't print unit names;
X    names = 1:  print only non-junky unit names;
X    names = 2:  print all unit names.  */
X  names = 1;
X  corner_coord = 1;		/* print coordinates of map corners */
X  enemy_gray = 0.5;		/* gray level for enemies;  0 = black */
X
/*  --------------------  end of customization  -------------------- */
X
X  height = (page_height - top_margin - bottom_margin)*2/sqrt(3.0)/hex_size;
X  width  = (page_width - left_margin - right_margin)/hex_size;
X
/*  open view file  */  
X  strcpy(buf1, VIEWFILE);
X  strcat(buf1, ".ps");
X  if ((fp = fopen(buf1, "w")) == NULL) {
X    notify(side, "Can't open \"%s\";", buf1);
X    strcpy(buf1, "/tmp/");
X    strcat(buf1, VIEWFILE);
X    strcat(buf1, ".ps"); }
X  if ((fp = fopen(buf1, "w")) == NULL) {
X    notify(side, "Can't open \"%s\", view not dumped.", buf1);
X    return;
X  }
X
X
/*  prolog  */
X  fprintf(fp, "%%!PS-Adobe-2.0\n");
X  fprintf(fp, "%%%%BoundingBox: %g %g %g %g\n", left_margin,
X	  top_margin, page_width-left_margin, page_height-top_margin);
X  fprintf(fp, "%%%%Creator: xconq version %s\n", VERSION);
X  userp = getenv("USER");
X  hostp = getenv("HOST");
X  if (userp != 0) {
X    if (hostp != 0) {
X      fprintf(fp, "%%%%For: %s@%s\n", userp, hostp); 
X    } else {
X      fprintf(fp, "%%%%For: %s\n", userp); 
X    }
X  }
X  fprintf(fp, "%%%%DocumentFonts: /Courier-Bold /Helvetica /Times-Bold\n");
X  fprintf(fp, "%%%%Pages: %d\n",
X	  ((world.height+height-1)/height)*((world.width+width-1)/width));
X  fprintf(fp, "%%%%EndComments\n");
X
/*  font  */
X  fprintf(fp, "/newfont 10 dict def\n");
X  fprintf(fp, "newfont begin\n");
X  fprintf(fp, "/FontType 3 def\n");
X  fprintf(fp, "/FontMatrix [1 0 0 1 0 0] def\n");
X  fprintf(fp, "/FontBBox [0 0 0 0] def\n");
X  fprintf(fp, "/Encoding 256 array def\n");
X  fprintf(fp, "0 1 255 {Encoding exch /.notdef put} for\n");
X  fprintf(fp, "Encoding 32 /space put\n");
X
X  for_all_terrain_types(t) {
X    fprintf(fp, "Encoding %d /tc%d put\n", ttypes[t].tchar, t); 
X  }
X  for_all_unit_types(u) {
X    fprintf(fp, "Encoding %d /uc%d put\n", utypes[u].uchar, u);
X  }
X  fprintf(fp, "/BuildChar { 0 begin /char exch def /fontdict exch\n");
X  fprintf(fp, "  def /charname fontdict /Encoding get char get def\n");
X  fprintf(fp, "  /charinfo fontdict /CharData get charname get def\n");
X  fprintf(fp, "  /wx charinfo 0 get def /charbbox charinfo 1 4\n");
X  fprintf(fp, "  getinterval def wx 0 charbbox aload pop\n");
X  fprintf(fp, "  setcachedevice charinfo 5 get charinfo 6 get true\n");
X  fprintf(fp, "  fontdict /imagemaskmatrix get dup 4 charinfo 7 get\n");
X  fprintf(fp, "  put dup 5 charinfo 8 get put charinfo 9 1\n");
X  fprintf(fp, "  getinterval cvx imagemask end } def\n");
X
X  fprintf(fp, "/BuildChar load 0 6 dict put\n");
X  fprintf(fp, "/imagemaskmatrix [20 0 0 -20 0 0] def\n");
X  fprintf(fp, "/CharData %d dict def\n",
X	  period.numttypes + period.numutypes + 2);
X  fprintf(fp, "CharData begin\n");
X  
X  for_all_terrain_types(t) {
X    fprintf(fp, "%% terrain %c = %s\n", ttypes[t].tchar,  ttypes[t].name);
X    fprintf(fp, "/tc%d [.5 0 -1 1 1 20 22 0 0\n", t);
X    if (entry_index[ttypes[t].tchar]->bit2) {
X      fprintf(fp, "<%s \n", entry_index[ttypes[t].tchar]->bit1);
X      fprintf(fp, " %s>\n", entry_index[ttypes[t].tchar]->bit2);
X    } else {
X      fprintf(fp, "<%s>\n", entry_index[ttypes[t].tchar]->bit1);
X  }
X    fprintf(fp, "] def\n");
X  }
X
X  for_all_unit_types(u) {
X    fprintf(fp, "%% unit %c = %s\n", utypes[u].uchar, utypes[u].name);
X    fprintf(fp, "/uc%d [.5 0 -1 1 1 16 16 0 0\n", u);
X    fprintf(fp, "<%s>\n", entry_index[utypes[u].uchar]->bit1);    
X    fprintf(fp, "] def\n");
X  }
X
X  fprintf(fp, "/space [.5 0 0 0 0 1 1 0 0 <> ] def\n");
X  fprintf(fp, "/.notdef [.5 0 0 0 0 1 0 0 <> ] def\n");
X  fprintf(fp, "end\n");
X  fprintf(fp, "/UniqueID 2 def\n");
X  fprintf(fp, "end\n");
X  fprintf(fp, "/Bitfont newfont definefont pop\n");
X
/* draw a row of terrains */
X  fprintf(fp, "/s {gsave show grestore 0 15 neg rmoveto} bind def\n");
/* draw a row of hex borders */
X  fprintf(fp, "/h {gsave -9 mul 0 rmoveto 9 0 rmoveto 0 10 rlineto -1 0\n");
X  fprintf(fp, "  {pop 9 5 rlineto 9 -5 rlineto 0 -10 rlineto -9 -5 rlineto\n");
X  fprintf(fp, "  -9 5 rlineto 18 10 rmoveto} for stroke grestore} bind def\n");
/* show enemy unit */
X  fprintf(fp, "/u {gsave 15 rmoveto 2 -4 rmoveto gsave 14 0 rlineto\n");
X  fprintf(fp, "  0 -12 rlineto -14 0 rlineto 0 12 rlineto 1 setgray fill\n");
X  fprintf(fp, "  grestore 0 2 rmoveto %g setgray show", enemy_gray);
X  fprintf(fp, " 0 setgray /Courier-Bold findfont\n");
X  fprintf(fp, "  9 scalefont setfont -1.5 -4 rmoveto dup stringwidth gsave\n");
X  fprintf(fp, "  pop dup 0.5 add 7 scale -0.5 0 rmoveto 1 0 rlineto\n");
X  fprintf(fp, "  0 1 rlineto -1 0 rlineto 0 -1 rlineto 1 setgray fill\n");
X  fprintf(fp, "  grestore -0.5 mul 0.5 rmoveto show grestore\n");
X  fprintf(fp, "  /Bitfont findfont  18 scalefont setfont} bind def\n");
/* show allied unit */
X  fprintf(fp, "/a {gsave 15 rmoveto 2 -4 rmoveto gsave 14 0 rlineto\n");
X  fprintf(fp, "  0 -12 rlineto -14 0 rlineto 0 12 rlineto 1 setgray fill\n");
X  fprintf(fp, "  grestore 0 2 rmoveto show /Courier-Bold findfont\n");
X  fprintf(fp, "  9 scalefont setfont -1.5 -4 rmoveto dup stringwidth gsave\n");
X  fprintf(fp, "  pop dup 0.5 add 7 scale -0.5 0 rmoveto 1 0 rlineto\n");
X  fprintf(fp, "  0 1 rlineto -1 0 rlineto 0 -1 rlineto 1 setgray fill\n");
X  fprintf(fp, "  grestore -0.5 mul 0.5 rmoveto show grestore\n");
X  fprintf(fp, "  /Bitfont findfont  18 scalefont setfont} bind def\n");
/* show own unit */
X  fprintf(fp, "/f {gsave 15 rmoveto 2 -4 rmoveto gsave 14 0 rlineto\n");
X  fprintf(fp, "  0 -12 rlineto -14 0 rlineto 0 12 rlineto 1 setgray fill\n");
X  fprintf(fp, "  grestore 0 2 rmoveto show grestore} bind def\n");
/* print unit name */
X  fprintf(fp, "/n {gsave neg moveto 9 -4 rmoveto dup stringwidth gsave\n");
X  fprintf(fp, "  pop dup 0.5 add 5 scale -0.5 0 rmoveto 1 0 rlineto\n");
X  fprintf(fp, "  0 1 rlineto -1 0 rlineto 0 -1 rlineto 1 setgray fill\n");
X  fprintf(fp, "  grestore -0.5 mul 0.5 rmoveto show grestore} bind def\n");
X
X  fprintf(fp, "%%%%EndProlog\n");
X  fprintf(fp, "\n");
X
/*  loop over pages  */
X  page = 0;
X  for (i=0; i < (world.height+height-1)/height; i++) {
X    for (j=0; j < (world.width+width-1)/width; j++) {
X
/*  initialize page  */
X      page++;
X      fprintf(fp, "%%%%Page: %d %d\n", page, page);
X      fprintf(fp, "%g %g translate 0 0 moveto\n",
X	      left_margin, page_height-top_margin);
/*  slight asymmetry to make perfectly regular hexes  */
X      fprintf(fp, "%g %g scale ", hex_size/18, hex_size/(10*sqrt(3.0)));
X      fprintf(fp, "%g setlinewidth\n", hex_border_width*18/hex_size);
X
/*  print title */
X      fprintf(fp, "/Times-Bold findfont 12 scalefont setfont\n");
X      fprintf(fp, "%d %d moveto (XCONQ:  %s)\n", 9*width, 20,
X	      add_esc_string(period.name));
X      fprintf(fp, "dup stringwidth pop -0.5 mul 0 rmoveto show\n");
X
X      if (corner_coord) {
/*  print map corner coordinates */
X	fprintf(fp, "/Helvetica findfont 9 scalefont setfont\n");
X
X	y0 = y = world.height-1-i*height;
X	x = wrap(j*width - (y+1)/2 + 4*world.width);
X	fprintf(fp, "%d %d moveto (%d,%d) ", -8, 0, x, y);
X	fprintf(fp, "dup stringwidth pop neg 0 rmoveto show\n");
X
X	nx = min(width, world.width-j*width);
X	x = wrap(j*width+nx-1 - (y+1)/2 + 4*world.width);
X	fprintf(fp, "%d %d moveto (%d,%d) show\n", 18*nx+16, 0, x, y);
X
X	y = max(world.height-(i+1)*height,0);
X	ny = y0 - y;
X	x = wrap(j*width - (y+1)/2 + 4*world.width);
X	fprintf(fp, "%d %d moveto (%d,%d) ", -8, -15*(ny+2)+3, x, y);
X	fprintf(fp, "dup stringwidth pop neg 0 rmoveto show\n");
X
X	x = wrap(j*width+nx-1 - (y+1)/2 + 4*world.width);
X	fprintf(fp, "%d %d moveto (%d,%d) show\n",
X		18*nx+16, -15*(ny+2)+3, x, y);
X      }
X
X      fprintf(fp, "0 0 moveto\n");
X      fprintf(fp, "/Bitfont findfont 18 scalefont setfont\n");
X
X      for (y = world.height-1-i*height;
X	   y >= world.height-(i+1)*height && y >= 0; y--) {
X
/*  show terrain  */
X	fputc('(', fp);
X	if ((y%2) == 0) fputc(' ', fp);
X	nx = min(width, world.width-j*width);
X	for (xx = j*width; xx < j*width+nx; xx++) {
X	  x = wrap(xx - (y+1)/2 + 4*world.width);
X	  view = side_view(side, x, y);
X	  if (view == UNSEEN) {
X	    ch1 = ' ';
X	  } else {
X	    ch1 = ttypes[terrain_at(x, y)].tchar;
X	  }
X	  fprintf(fp, "%s", add_esc_char(ch1));
X	  if (xx < j*width+nx-1) fputc(' ', fp);
X	}
X	if ((y%2) == 1) fputc(' ', fp);
X	fprintf(fp, ") s\n");
X
/*  draw hex borders  */
X	if (hex_border_width>0) {
X	  fprintf(fp, "%d %d h\n", nx-1, (y%2));
X	}
X
/*  show units  */
X	for (xx = j*width; xx < j*width+nx; xx++) {
X	  x = wrap(xx - (y+1)/2 + 4*world.width);
X	  view = side_view(side, x, y);
X	  if (view != UNSEEN && view != EMPTY ) {
X	    ch1 = utypes[vtype(view)].uchar;
X	    ns2 = vside(view);
X	    side2 = side_n(ns2);
X	    if (ns2 == -1 || ns2 == MAXSIDES) {
X	      ch2 = 'n';
X	    } else if (side2 == side) {
X	      ch2 = ' ';
X	    } else {
X	      if (ns2<10) {
X		ch2 = '0' + ns2;
X	      } else {
X		ch2 = 'A' + ns2-10;
X	      }
X	    }
X	    if (ch2 == ' ') {
X	      fprintf(fp, "(%s) %g f\n", add_esc_char(ch1),
X		      (xx-j*width+0.5*(1-y%2))*18);
X	    } else if (allied_side(side2, side)) {
X	      fprintf(fp, "(%c) (%s) %g a\n", ch2, add_esc_char(ch1),
X		      (xx-j*width+0.5*(1-y%2))*18);
X	    }
X	    else {
X	      fprintf(fp, "(%c) (%s) %g u\n", ch2, add_esc_char(ch1),
X		      (xx-j*width+0.5*(1-y%2))*18);
X	    }
X	  }
X	}
X
X      }
X
/*  print unit names  */
X      if (names>0) {
X	fprintf(fp, "/Helvetica findfont 6 scalefont setfont\n");
X	for (y = world.height-1-i*height;
X	     y >= world.height-(i+1)*height && y >= 0; y--) {
X	  for (xx = j*width; xx < j*width+nx; xx++) {
X	    x = wrap(xx - (y+1)/2 + 4*world.width);
X	    view = side_view(side, x, y);
X	    if (view != UNSEEN && view != EMPTY ) {
X	      unit = unit_at(x,y);
X	      if (unit!=NULL) {
X		nam =  unit->name;
X	      } else {
X		nam = NULL;
X	      }
X	      if (nam!=NULL && (names>1 || !is_junky(unit))) {
X		fprintf(fp, "(%s) %g %d n\n", add_esc_string(nam),
X			(xx-j*width+0.5*(1-y%2))*18,
X			(world.height-i*height-y)*15);
X	      }
X	    }
X	  }
X	}
X      }      
X      fprintf(fp, "showpage\n");
X
X    }
X  }
X
X  fprintf(fp, "%%%%Trailer\n");
X  fprintf(fp, "%%%%EOF\n");
X
X  fclose(fp);
X
X  notify(side, "Dumped current view to \"%s\".", buf1);
X
}
X
#else /* PS_VIEW */
X
dump_view(side)
Side *side;
{
X  /* Implement when we figure out how to do full map dumps. */
}
X
#endif /* PS_VIEW */
SHAR_EOF
chmod 0600 X11.c ||
echo 'restore of X11.c failed'
Wc_c="`wc -c < 'X11.c'`"
test 75914 -eq "$Wc_c" ||
	echo 'X11.c: original size 75914, current size' "$Wc_c"
fi
exit 0
