[comp.sources.games] v01i083: xconq - multiplayer strategy game for X-windows, Part03/07

games-request@tekred.UUCP (07/10/87)

Submitted by: "Stanley T. Shebs" <shebs%orion@cs.utah.edu>
Comp.sources.games: Volume 1, Issue 83
Archive-name: xconq/Part03


#! /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 3 (of 7)."
# Contents:  move.c unit.c xconq.6 xconq.h
# Wrapped by billr@tekred on Thu Jul  9 17:45:41 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f move.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"move.c\"
else
echo shar: Extracting \"move.c\" \(16251 characters\)
sed "s/^X//" >move.c <<'END_OF_move.c'
X/* Copyright (c) 1987  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: move.c,v 1.4 87/06/08 21:45:55 shebs Exp $ */
X
X#include "xconq.h"
X
X#define human_order(u) (directorder && human(u))
X
Xbool directorder;  /* True if unit just got unconditional orders. */
Xbool movesuccess;  /* True when unit finally succeeds in a single move. */
X
Xint curx, cury;    /* Current intended position of cursor */
Xint movesleft;     /* Number of moves left for the current unit. */
X
XUnit *curunit;     /* Unit to which all commands apply */
X
X/* Each unit executes its orders once each turn.  First compute how many */
X/* movements are allowed for this turn, then run them down to zero (as long */
X/* as the unit remains alive).  Each individual movement requires a check */
X/* for wakeup conditions followed by dispatch on order type. */
X
X/* We have to do a little fancy footwork with the range, because damaged */
X/* units move slower, but they can't be totally immobilized, since no */
X/* on-site repairs.  And of course there is the flaky calculation that */
X/* allows for fractional movements if desired. */
X
Xxorders(unit)
XUnit *unit;
X{
X    int range, turns, tries;
X
X    if (Debug)
X	printf("%s doing %s\n",
X	       unit_handle(NULL, unit), order_desig(unit->orders));
X
X    curunit = unit;
X
X    /* utype hit points had better be non-zero */
X    range = (utypes[unit->type].range * unit->hp) / utypes[unit->type].hp;
X    range = max(1, range);
X    turns = utypes[unit->type].turns;
X    movesleft =	((range / turns) +
X		 ((gametime % turns) < (range % turns) ? 1 : 0));
X    
X    while (movesleft > 0 && alive(unit)) {
X	movesuccess = FALSE;
X	if (unit->orders.type == AWAKE) {
X	    directorder = TRUE;
X	    if (human(unit)) {
X		human_move(unit);
X	    } else {
X		if (active_display(unit->side)) show_unit(unit);
X		machine_move(unit);
X	    }
X	    if (gaveup) return;
X	    if (movesleft <= 0 || !alive(unit)) break;
X	} else {
X	    directorder = FALSE;
X	}
X	switch (unit->orders.type) {
X	case AWAKE:
X	    fprintf(stderr, "My bogometer just triggered!\n");
X	    break;
X	case SENTRY:
X	    if (unit->orders.rept-- > 0) {
X		movesleft = 0;
X		movesuccess = TRUE;
X	    }
X	    break;
X	case RANDOM:
X	    if (unit->orders.rept-- > 0) {
X		tries = 10;
X		while (tries-- > 0 && !movesuccess) {
X		    move_dir(unit, random_dir());
X		}
X	    }
X	    break;
X	case MOVEDIR:
X	    if (unit->orders.rept-- > 0) {
X		move_dir(unit, unit->orders.parms[0]);
X	    }
X	    break;
X	case MOVETO:
X	    move_to(unit, unit->orders.parms[0], unit->orders.parms[1]);
X	    break;
X	case COAST:
X	    unit->orders.parms[1] = follow_coast(unit,
X						 unit->orders.parms[0],
X						 unit->orders.parms[1]);
X	    break;
X	case BUILD:
X	    if (unit->orders.rept-- > 1) {
X		movesuccess = TRUE;
X	    } else {
X		build_base(unit);
X	    }
X	    break;
X	case FOLLOW:
X	    if (unit->orders.rept-- > 0) {
X		follow_leader(unit, unit->orders.parms[0]);
X	    }
X	    break;
X	case PATROL:
X	    cmd_error("No patrols yet!");
X	    wakeup(unit);
X	    break;
X	case NONE: default:
X	    case_panic("order type", unit->orders.type);
X	}
X	if (alive(unit) && (movesuccess || !human(unit))) {
X	    --movesleft;
X	    consume_supplies(unit);
X	}
X	if (alive(unit) && (!directorder || movesuccess)) {
X	    maybe_wakeup(unit);
X	}
X    }
X}
X
X/* Get movement/orders from a human player, iterating until a valid move */
X/* is received. */
X
Xhuman_move(unit)
XUnit *unit;
X{
X    while (alive(unit) && !movesuccess && unit->orders.type == AWAKE) {
X	show_unit(unit);
X	read_command();
X	/* Following should work even if unit dead... */
X	unshow_unit();
X    }
X}
X
X/* Force unit to try to move in given direction. */
X
Xmove_dir(unit, dir)
XUnit *unit;
Xint dir;
X{
X    move_to_next(unit, dirx[dir], diry[dir], TRUE);
X}
X
X/* This function (and a couple aux fns) encodes most of the rules about how */
X/* units can move.  Attempts to move onto cities or other units are handled */
X/* by other functions below.  Unit will also refuse to move onto the edge of */
X/* the map or into the wrong kind of terrain.  Otherwise, it succeeds in its */
X/* movement and we put it at the new spot.  If at any time, the unit */
X/* could not move and yet was supposed to, it will wake up. */
X
Xmove_to_next(unit, dx, dy, mustgo)
XUnit *unit;
Xint dx, dy, mustgo;
X{
X    int nx, ny;
X    Unit *unit2;
X    City *city;
X    Side *us = unit->side;
X
X    nx = wrap(unit->x + dx);  ny = unit->y + dy;
X
X    if ((city = city_at(nx, ny)) != NULL) {
X	move_to_city(unit, city, dx, dy, mustgo);
X    } else if ((unit2 = unit_at(nx, ny)) != NULL) {
X	move_to_unit(unit, unit2, dx, dy, mustgo);
X    } else if (at_world_edge(nx, ny)) {
X	if (human_order(unit) && mustgo)
X	    notify(us, "%s is at the edge of the world!",
X		   unit_handle(us, unit));
X    } else if (!utypes[unit->type].moveson[terrain(nx, ny)]) {
X	if (human_order(unit) && mustgo)
X	    notify(us, "%s won't go into the %s!",
X		   unit_handle(us, unit), terrnames[terrain(nx, ny)]);
X    } else {
X	move_unit(unit, nx, ny);
X	movesuccess = TRUE;
X    }
X    /* Dead units got that way because they succeeded in moving, so test */
X    /* not needed here. */
X    if (!movesuccess && mustgo) wakeup(unit);
X}
X
X/* An enemy city at the destination will be attacked. */
X/* A friendly city will be entered if not full.  (landing msg for airplanes) */
X
Xmove_to_city(unit, city, dx, dy, mustgo)
XUnit *unit;
XCity *city;
Xint dx, dy, mustgo;
X{
X    Side *us = unit->side;
X
X    if (enemy_side(us, city->side)) {
X	if (unit->goal == NORMAL) {
X	    movesuccess = TRUE;
X	    movesleft -= utypes[unit->type].hittime;
X	    attack_city(unit, city);
X	}
X    } else if (us != city->side) {
X	/* nothing to do if machine player tries to attack friend */
X    } else if (!can_take_in(unit->type, city)) {
X	if (human_order(unit) && mustgo)
X	    notify(us, "%s has no room for %s!",
X		   city->name, unit_handle(us, unit));
X    } else {
X	if (aircraft(unit)) {
X	    /* Aircraft stop moving when they land */
X	    movesleft = 0;
X	    notify(us, "%s lands safely in %s", 
X		   unit_handle(us, unit), city->name);
X	}
X	/* Enter the city */
X	move_unit(unit, city->x, city->y);
X	movesuccess = TRUE;
X    }
X}
X
X/* An enemy unit will be attacked, unless unit is on a transport *and* it */
X/* cannot move to that square anyway. */
X/* Also will refuse if hit prob < 10% (can still defend tho) */
X/* If the attackee is destroyed, then unit will attempt to move in again. */
X/* A friendly transport will be boarded unless it is full. */
X/* Blank refusal to move if any other unit. */
X
Xmove_to_unit(unit, unit2, dx, dy, mustgo)
XUnit *unit, *unit2;
Xint dx, dy, mustgo;
X{
X    Side *us = unit->side;
X
X    if (enemy_side(us, unit2->side)) {
X	if (unit->transport != NULL &&
X	    !utypes[unit->type].moveson[terrain(unit2->x, unit2->y)]) {
X	    if (human_order(unit) && mustgo)
X		notify(us, "%s is a passenger!", unit_handle(us, unit));
X	} else if (utypes[unit->type].hittab[unit2->type] < 10) {
X	    if (human_order(unit) && mustgo)
X		notify(us, "%s refuses to waste ammo!", unit_handle(us, unit));
X	} else if (unit2->hidden &&
X		   side_view(us, unit2->x, unit2->y) == EMPTY) {
X	    notify(us, "%s spots an unidentified %s %s!",
X		   unit_handle(us, unit),
X		   unit2->side->name, unitnames[unit2->type]);
X	    see_something(us, unit2->x, unit2->y, TRUE);
X	} else if (unit->goal == NORMAL) {
X	    movesuccess = TRUE;
X	    movesleft -= utypes[unit->type].hittime;
X	    if (attack_unit(unit, unit2)) {
X		/* if battle won, can try moving again */
X		move_to_next(unit, dx, dy, FALSE);
X	    }
X	} else {
X	    /* here if aircraft blocked on return, etc - no action needed */
X	}
X    } else if (us != unit2->side) {
X	/* nothing to do for allied machine players attacking by accident */
X    } else if (could_carry(unit2, unit)) {
X	if (unit->cargo != NULL) {
X	    if (human_order(unit) && mustgo)
X		notify(us, "No passengers of passengers allowed!");
X	} else if (!can_carry(unit2, unit)) {
X	    if (human_order(unit) && mustgo)
X		notify(us, "%s is full already!", unit_handle(us, unit2));
X	} else {
X	    /* No more moves this turn for passenger */
X	    move_unit(unit, unit2->x, unit2->y);
X	    movesleft = 0;
X	    movesuccess = TRUE;
X	}
X    } else {
X	if (human_order(unit) && mustgo)
X	    notify(us, "%s refuses to attack its friends!",
X		   unit_handle(us, unit));
X    }
X}
X
X/* Perform the act of moving proper. (very simple) */
X
Xmove_unit(unit, nx, ny)
XUnit *unit;
Xint nx, ny;
X{
X    leave_square(unit);
X    occupy_square(unit, nx, ny);
X}
X
X/* Units consume supplies at the rate of 1 per move.  Fortunately, they can */
X/* get more supplies, either by being in a town, on a transport, or in a */
X/* terrain with frequent grocery stores and gas pumps. */
X
Xchar *desertion[] = { "%s dies from starvation!",
X		      "%s runs low on supplies and mutinies!",
X		      "%s runs out of fuel and crashes!" };
X
Xconsume_supplies(unit)
XUnit *unit;
X{
X    Side *us = unit->side;
X    
X    if (!resupplied_here(unit)) {
X	unit->supply -= (unit->cargo != NULL ? 2 : 1);
X    }
X    /* should this be a separate routine? */
X    if (unit->supply <= 0) {
X	notify(us, desertion[utypes[unit->type].domain],
X	       unit_handle(us, unit));
X	adjust_morale(us, -20);
X	adjust_score(us, -5);
X	kill_unit(unit, STARVATION);
X    }
X}
X
X/* True if unit can get supplies while at its present location. */
X
Xresupplied_here(unit)
XUnit *unit;
X{
X    int ux = unit->x, uy = unit->y;
X
X    return ((is_urban(ux, uy)) ||
X	    (unit->transport != NULL) ||
X	    (utypes[unit->type].resupply[terrain(ux, uy)]) ||
X	    (is_adj_resupply(unit->type, ux, uy)));
X}
X
X/* Follow a coast line. This is a version of contour-following, but flaky */
X/* because our terrain is discrete rather than continuous.  The algorithm */
X/* looks backward then goes around in a circle looks for an edge; a square */
X/* the unit can move into, which has an obstacle square adjacent. */
X
Xfollow_coast(unit, cw, olddir)
XUnit *unit;
Xint cw, olddir;
X{
X    int testdir, k;
X    
X    /* try to go in straight line first */
X    if (flip_coin() && direction_works(unit, olddir)) return olddir;
X    testdir = (olddir - 3 * cw + 8) % 8;
X    for (k = 0; k < 8; ++k) {
X	if (direction_works(unit, testdir)) return testdir;
X	testdir = (testdir + cw + 8) % 8;
X    }
X    /* If none of the directions work out... */
X    wakeup(unit);
X    notify(unit->side, "%s can't figure out where to move to!",
X	   unit_handle(unit->side, unit));
X}
X
Xdirection_works(unit, dir)
XUnit *unit;
Xint dir;
X{
X    int nx, ny;
X
X    nx = wrap(unit->x + dirx[dir]);
X    ny = limit(unit->y + diry[dir]);
X    if (utypes[unit->type].moveson[terrain(nx,ny)] > 0 &&
X	adj_obstacle(unit->type, nx, ny)) {
X	move_dir(unit, dir);
X	return TRUE;
X    } else {
X	return FALSE;
X    }
X}
X
X/* This weird-looking routine computes next directions for moving to a */
X/* given spot. */
X/* Some trickinesses:  world is cylindrical, so must resolve ambiguity about */
X/* getting to the same place going either direction (we pick shortest). */
X/* The basic strategy is to move along the diagonal first, since it is more */
X/* constrained.  Along a horizontal or vertical, can go straight or diagonal */
X/* to get around an obstacle. */
X
Xmove_to(unit, tx, ty)
XUnit *unit;
Xint tx, ty;
X{
X    int dx, dxa, dy, dx1, dy1;
X    
X    dx = unit->x - tx;  dy = unit->y - ty;
X
X    if (dx == 0 && dy == 0) {
X	wakeup(unit);
X	return;
X    }
X    dxa = unit->x - (tx + worldwidth);
X    if (abs(dx) > abs(dxa)) dx = dxa;
X    dxa = unit->x - (tx - worldwidth);
X    if (abs(dx) > abs(dxa)) dx = dxa;
X
X    if (dx != 0 && dy != 0) {
X	dx1 = ((dx > 0) ? -1 : 1);
X	dy1 = ((dy > 0) ? -1 : 1);
X	if (abs(dx) == abs(dy)) {
X	    move_to_next(unit, dx1, dy1, TRUE);
X	} else {
X	    move_to_next(unit, dx1, dy1, FALSE);
X	    if (!movesuccess) {
X		if (abs(dx) > abs(dy)) {
X		    dy1 = 0;
X		    move_to_next(unit, dx1, dy1, TRUE);
X		} else {
X		    dx1 = 0;
X		    move_to_next(unit, dx1, dy1, TRUE);
X		}
X	    }
X	}
X    } else if (dx == 0) {
X	dx1 = 0;
X	dy1 = ((dy > 0) ? -1 : 1);
X	move_to_next(unit, dx1, dy1, (dy == 1));
X	if (!movesuccess) {
X	    dx1 = 1;
X	    move_to_next(unit, dx1, dy1, FALSE);
X	    if (!movesuccess) {
X		dx1 = -1;
X		move_to_next(unit, dx1, dy1, TRUE);
X	    }
X	}
X    } else {  /* dy == 0 */
X	dx1 = ((dx > 0) ? -1 : 1);
X	dy1 = 0;
X	move_to_next(unit, dx1, dy1, (dx == 1));
X	if (!movesuccess) {
X	    dy1 = 1;
X	    move_to_next(unit, dx1, dy1, FALSE);
X	    if (!movesuccess) {
X		dy1 = -1;
X		move_to_next(unit, dx1, dy1, TRUE);
X	    }
X	}
X    }
X}
X
X/* When doing a survey, you can move the cursor anywhere and it will show */
X/* what anything is at that square, but without giving away too much! */
X
Xmove_survey(dx, dy)
Xint dx, dy;
X{
X    int nx, ny;
X    Unit *unit;
X    City *city;
X    
X    nx = wrap(curx + dx);  ny = cury + dy;
X    if (at_world_edge(nx, ny)) {
X	ny = cury;
X	beep(curside);
X    }
X    erase_cursor(curside, curx, cury);
X    curx = nx;  cury = ny;
X    put_on_screen(curside, curx, cury);
X    if (seen(curside, curx, cury)) {
X	if ((city = city_at(curx, cury)) != NULL && own(city)) {
X	    show_city(city);
X	} else if ((unit = unit_at(curx, cury)) != NULL && own(unit)) {
X	    show_unit(unit);
X	    curunit = unit;
X	} else {
X	    show_thing_seen(curside, curx, cury);
X	}
X    }
X    draw_cursor(curside, curx, cury);
X}
X
X/* Conduct the construction of a base.  The constructing unit may or may */
X/* not disappear, depending on period and type of unit. */
X
Xbuild_base(unit)
XUnit *unit;
X{
X    int x = unit->x, y = unit->y;
X    City *base;
X    Side *us = unit->side;
X
X    if (utypes[unit->type].garrison) {
X	kill_unit(unit, GARRISON);
X    } else {
X	leave_square(unit);
X    }
X    base = create_city(BASE, x, y, new_base_name(us), us->name,
X		       NOTHING, 0, ctypes[BASE].hp, 0);
X    if (base != NULL) {
X	++numcities;
X	base->side = us;
X	if (us->showcoords)
X	    notify(us, "You have a new base (%s) at %s",
X		   base->name, pos_desig(x, y));
X	else
X	    notify(us, "You have a new base (%s)", base->name);
X    }
X    if (alive(unit)) occupy_square(unit, x, y);
X    update_view(us, x, y);
X}
X
X/* Unit attempts to follow its leader around. */
X
Xfollow_leader(unit, leader)
XUnit *unit, *leader;
X{
X    if (!alive(leader)) {
X	wakeup(unit);
X    } else if (abs(unit->x - leader->y) < 2 && abs(unit->y - leader->y) < 2) {
X    } else {
X	move_to(unit, leader->x, leader->y);
X    }
X}
X
X/* This routine encodes nearly all of the conditions under a unit following */
X/* orders might wake up and request new instructions */
X
Xmaybe_wakeup(unit)
XUnit *unit;
X{
X    int d, x, y;
X    Unit *unit2;
X    City *city2;
X
X    /* repetition on orders has run out */
X    if (unit->orders.rept <= 0) {
X	wakeup(unit);
X	return;
X    }
X    /* first check status of unit itself */
X    if (low_supplies(unit) && unit->cautious && unit->goal == NORMAL) {
X	unit->cautious = FALSE;
X	wakeup(unit);
X	return;
X    }
X    /* now look at neighbors */
X    for (d = 0; d < 8; ++d) {
X	x = wrap(unit->x + dirx[d]);  y = unit->y + diry[d];
X	if (unit->goal == NORMAL) {
X	    if ((unit2 = unit_at(x, y)) != NULL) {
X		if (unit->side != unit2->side) {
X		    if (!unit2->hidden) wake_unit(unit);
X		    if (!unit->hidden) wake_unit(unit2);
X		    return;
X		} else if (can_carry(unit2, unit) &&
X			   unit->transport == NULL &&
X			   unit->orders.type == SENTRY) {
X		    wakeup(unit);
X		    return;
X		}
X	    } else if ((city2 = city_at(x, y)) != NULL) {
X		if (unit->side != city2->side) {
X		    wake_unit(unit); /* get everybody up! */
X		    return;
X		}
X	    }
X	}
X    }
X}
X
Xwould_wakeup(unit)
XUnit *unit;
X{
X    int d, x, y;
X    Unit *unit2;
X    City *city2;
X
X    /* repetition on orders has run out */
X    if (unit->orders.rept <= 0) {
X	return TRUE;
X    }
X    /* first check easy cases */
X    if (low_supplies(unit) && unit->cautious && unit->goal == NORMAL) {
X	return TRUE;
X    }
X    /* now look at neighbors */
X    for (d = 0; d < 8; ++d) {
X	x = unit->x + dirx[d];  y = unit->y + diry[d];
X	if (unit->goal == NORMAL) {
X	    if ((unit2 = unit_at(wrap(x), y)) != NULL) {
X		if (unit->side != unit2->side) {
X		    if (!unit2->hidden) return TRUE;
X		} else if (can_carry(unit2, unit) && unit->transport == NULL) {
X		    return TRUE;
X		}
X	    }
X	    if ((city2 = city_at(wrap(x), y)) != NULL) {
X		if (unit->side != city2->side) {
X		    return TRUE;
X		}
X	    }
X	}
X    }
X    return FALSE;
X}
END_OF_move.c
if test 16251 -ne `wc -c <move.c`; then
    echo shar: \"move.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f unit.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"unit.c\"
else
echo shar: Extracting \"unit.c\" \(14073 characters\)
sed "s/^X//" >unit.c <<'END_OF_unit.c'
X/* Copyright (c) 1987  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: unit.c,v 1.4 87/06/08 21:45:17 shebs Exp $ */
X
X#include "xconq.h"
X
X/* Since units appear and disappear with distressing regularity (so it seems */
X/* to the player trying to keep up with all of them!), we have a little */
X/* storage manager for them.  Since the manager is bug-prone, there is a */
X/* two-level procedure for getting rid of units.  First the hit points are */
X/* reduced to zero, at which point the unit is considered "dead".  At the */
X/* end of a turn, we actually GC the dead ones.  At this point their side */
X/* slot becomes NULL, and they are available for allocation. */
X
XUnit units[MAXUNITS];  /* array of all units */
XUnit *unitlist;        /* pointer to head of list of units */
X
Xchar unitchars[MAXUTYPES];
X
Xchar *unitnames[MAXUTYPES];
X
Xint numunits;          /* total number of units in existence */
Xint nextid;            /* counter for unique unit identifiers */
X
X/* Init all the unit entries so we can find them when allocating. */
X
Xinit_units()
X{
X    int i;
X
X    for (i = 0; i < MAXUNITS; ++i)
X	units[i].side = NULL;
X    unitlist = NULL;
X    numunits = 0;
X    nextid = 0;
X}
X
X/* Create a new unit of given type, belonging to given side, and at position */
X
XUnit *
Xcreate_new_unit(type, side, x, y)
Xint type, x, y;
XSide *side;
X{
X    Unit *newunit;
X    City *city;
X
X    if ((city = city_at(x, y)) != NULL && !can_take_in(type, city)) {
X	notify(side, "%s too full for another %s",
X	       city->name, unitnames[type]);
X	if (!side->humanp) city->product = NOTHING;
X	return NULL;
X    }
X    adjust_score(side, 10);
X    newunit = create_unit(nextid++, assign_unit_number(type, side), type, side,
X			  utypes[type].hp, utypes[type].supply, TRUE,
X			  utypes[type].canhide, NORMAL);
X    if (newunit != NULL) ++numunits;
X    occupy_square(newunit, x, y);
X    return newunit;
X}
X
X/* Create a unit of given type, belonging to given side, and at position */
X/* This routine is for restoring the state of a unit completely, such as */
X/* from a file. */
X
XUnit *
Xcreate_unit(id, number, type, side, hp, supply, cautious, hidden, goal)
Xint id, type, number, hp, supply, goal;
Xbool cautious, hidden;
XSide *side;
X{
X    int i, j;
X
X    for (i = 0; i < MAXUNITS; ++i) {
X	if (units[i].side == NULL) {
X	    /* fill in all the slots */
X	    units[i].id = id;
X	    units[i].type = type;
X	    units[i].side = side;
X	    units[i].number = number;
X	    units[i].hp = hp;
X	    units[i].supply = supply;
X	    units[i].cautious = cautious;
X	    units[i].hidden = hidden;
X	    units[i].goal = goal;
X	    units[i].orders.type = AWAKE;
X	    units[i].orders.rept = 1;
X	    for (j = 0; j < NUMORDERPARMS; ++j) {
X		units[i].orders.parms[j] = 0;
X	    }
X	    units[i].transport = NULL;
X	    units[i].cargo = NULL;
X	    units[i].nexthere = NULL;
X	    link_in_unit(&units[i]);
X	    return &units[i];
X	}
X    }
X    notify(side, "Can't create more than %d units", MAXUNITS);
X    return NULL;
X}
X
X/* Add unit to front of list.  For this turn, it will move first - later */
X/* it will be sorted into normal position. */
X
X/* should probably insert in right place to get better performance */
X
Xlink_in_unit(unit)
XUnit *unit;
X{
X    unit->next = unitlist;
X    unitlist = unit;
X}
X
X/* A unit occupies a square either by entering the city on that square */
X/* or by having the occupant pointer filled in */
X/* This routine should not be used while units boarding other units */
X
Xoccupy_square(unit, x, y)
XUnit *unit;
Xint x, y;
X{
X    Unit *carg, *transport;
X
X    unit->x = x;  unit->y = y;
X    for (carg = unit->cargo; carg != NULL; carg = carg->nexthere) {
X	carg->x = x;  carg->y = y;
X    }
X
X    if (is_urban(x, y)) {
X	enter_city(unit, city_at(x, y));
X    } else if ((transport = unit_at(x, y)) != NULL) {
X	embark_unit(transport, unit);
X    } else {
X	set_unit_at(x, y, unit);
X	update_view(unit->side, x, y);
X    }
X}
X
X/* Units get restocked, repaired and maybe new orders when entering a city. */
X
Xenter_city(unit, city)
XUnit *unit;
XCity *city;
X{
X    int i;
X    Order neworders;
X
X    unit->nexthere = city->occupant;
X    city->occupant = unit;
X    if (unit->goal == REFUEL) unit->goal = NORMAL;
X    neworders = (city->standing)[unit->type];
X    if (neworders.type != NONE) {
X	if (Debug) printf("Getting orders %s", order_desig(neworders));
X	(unit->orders).type = neworders.type;
X	for (i = 0; i < NUMORDERPARMS; ++i)
X	    (unit->orders).parms[i] = neworders.parms[i];
X	(unit->orders).rept = neworders.rept;
X    }
X}
X
X/* Decide whether city has the capability to house the given unit. */
X
Xcan_take_in(type, city)
Xint type;
XCity *city;
X{
X    int total = 0, tmp;
X    Unit *head;
X    
X    for (head = city->occupant; head != NULL; head = head->nexthere) {
X	if (utypes[head->type].domain == utypes[type].domain) ++total;
X    }
X    tmp = ctypes[city->size].capacity[utypes[type].domain];
X    return (total < tmp);
X}
X
X/* This is true only for transports that have some room left. */
X
Xcan_carry(transport, unit)
XUnit *transport, *unit;
X{
X    return (could_carry(transport, unit) &&
X	    cargo_size(transport, unit->type) < 
X	    utypes[transport->type].capacity[unit->type]);
X}
X
X/* Units become passengers by linking into front of transport's passenger */
X/* list.  They get resupplied (by raiding the transport supplies) and */
X/* wake up (to cancel any auto-moving).  A passenger will get sorted to */
X/* move after transport, at end of turn. */
X
Xembark_unit(transport, unit)
XUnit *transport, *unit;
X{
X    unit->x = transport->x;  unit->y = transport->y;
X    unit->nexthere = transport->cargo;
X    transport->cargo = unit;
X    unit->transport = transport;
X    unit->supply = utypes[unit->type].supply;
X    wakeup(unit);
X}
X
X/* Unit departs from a square by zeroing out pointer if in country or */
X/* being removed from the list of city or transport occupants. */
X/* Must test for transport first, in case transport is in a city itself! */
X
Xleave_square(unit)
XUnit *unit;
X{
X    int x = unit->x, y = unit->y;
X    Unit *carg;
X
X    if (unit->transport != NULL) {
X	disembark_unit(unit, unit->transport);
X    } else if (is_urban(x, y)) {
X	leave_city(unit, city_at(x, y));
X    } else {
X	set_unit_at(x, y, NULL);
X	update_view(unit->side, x, y);
X    }
X    /* trash old values just in case */
X    unit->x = -1;  unit->y = -1;
X    for (carg = unit->cargo; carg != NULL; carg = carg->nexthere) {
X	carg->x = -1;  carg->y = -1;
X    }
X}
X
X/* Leaving a city means unlinking from list of occupants. */
X
Xleave_city(unit, city)
XUnit *unit;
XCity *city;
X{
X    Unit *head;
X
X    if (unit == city->occupant) {
X	city->occupant = unit->nexthere;
X    } else {
X	for (head = city->occupant; head != NULL; head = head->nexthere) {
X	    if (unit == head->nexthere) {
X		head->nexthere = head->nexthere->nexthere;
X		break;
X	    }
X	}
X    }
X    unit->nexthere = NULL;
X}
X
X/* Disembarking unlinks from the list of passengers. */
X
Xdisembark_unit(unit, transport)
XUnit *transport, *unit;
X{
X    Unit *head;
X
X    if (unit == transport->cargo) {
X	transport->cargo = unit->nexthere;
X    } else {
X	for (head = transport->cargo; head != NULL; head = head->nexthere) {
X	    if (unit == head->nexthere) {
X		head->nexthere = head->nexthere->nexthere;
X		break;
X	    }
X	}
X    }
X    unit->nexthere = NULL;
X    unit->transport = NULL;
X}
X
X/* Remove a unit from play.  This is different from making it available for */
X/* reallocation - only the unit flusher can do that.  We remove all the */
X/* passengers too - note that this is not recursive, so passengers had */
X/* better not have passengers themselves. */
X
Xkill_unit(unit, reason)
XUnit *unit;
Xint reason;
X{
X    Unit *carg;
X    
X    (unit->side)->losses[unit->type][reason]++;
X    leave_square(unit);
X    for (carg = unit->cargo; carg != NULL; carg = carg->nexthere) {
X	carg->hp = 0;
X    }
X    unit->hp = 0;
X}
X
X/* Get rid of all dead units at once.  First unit in list is never removed, */
X/* so this potentially has a slow leak in it, although the sorting process */
X/* rescrambles stuff frequently, which ameliorates the problem somewhat. */
X
Xflush_dead_units()
X{
X    Unit *unit, *unitprev;
X
X    for (unitprev = unitlist; unitprev != NULL; unitprev = unitprev->next) {
X	unit = unitprev->next;
X	if (unit == NULL) {
X	} else if (!alive(unit)) {
X	    unitprev->next = unit->next;
X	    unit->side = NULL;
X	    unit->next = NULL;
X	}
X    }
X}
X
X/* Do multiple passes of bubble sort.  This is intended to improve locality */
X/* among unit positions and reduce the amount of scrolling around. */
X/* We don't necessarily do a full sort, number of passes correlated to how */
X/* long the game has been going. */
X/* If slowness objectionable, replace with something clever. */
X
Xsort_units()
X{
X    bool flips;
X    int passes, pass;
X    Unit *prevunit, *unit, *nextunit;
X
X    flips = TRUE;
X    passes = gametime;
X    while (flips && passes-- > 0) {
X	flips = FALSE;
X	prevunit = NULL;
X	unit = unitlist;
X	while (unit != NULL) {
X	    if (unit->next != NULL && !in_order(unit, unit->next)) {
X		flips = TRUE;
X		nextunit = unit->next;
X		if (prevunit != NULL) prevunit->next = nextunit;
X		unit->next = nextunit->next;
X		nextunit->next = unit;
X		prevunit = nextunit;
X		if (unit == unitlist) unitlist = nextunit;
X	    } else {
X		prevunit = unit;
X		unit = unit->next;
X	    }
X	}
X    }
X    if (Debug) printf("%d passes\n", gametime - passes);
X}
X
X/* Elaborate criteria for units being sorted properly, sets order first by */
X/* by y (top to bottom), then x (left to right), then by putting passengers */
X/* after transports.  No sorting on city occupants... */
X
Xin_order(unit1, unit2)
XUnit *unit1, *unit2;
X{
X    if (unit1->y > unit2->y) return TRUE;
X    if (unit1->y < unit2->y) return FALSE;
X    if (unit1->x < unit2->x) return TRUE;
X    if (unit1->x > unit2->x) return FALSE;
X    if (unit1->transport != NULL && unit2->cargo != NULL) return FALSE;
X    return TRUE;
X}
X
X/* A unit runs low on supplies at the halfway point.  Formula is the same */
X/* however passengers affect supplies. */
X
Xlow_supplies(unit)
XUnit *unit;
X{
X    return (2 * unit->supply <= utypes[unit->type].supply);
X}
X
X/* Display random info about the given unit. */
X
Xshow_unit(unit)
XUnit *unit;
X{
X    char cargobuf[BUFSIZE], tmp[BUFSIZE];
X    int i, nums[MAXUTYPES];
X    Unit *carg;
X
X    curx = unit->x;  cury = unit->y;
X
X    put_on_screen(curside, curx, cury);
X
X    if (unit->side == curside || Debug) {
X	if (unit->transport != NULL) {
X	    sprintf(cargobuf, "On %s", unitnames[unit->transport->type]);
X	} else if (unit->cargo != NULL) {
X	    sprintf(cargobuf, "Cargo ");
X	    for (i = 0; i < numutypes; ++i)
X		nums[i] = 0;
X	    for (carg = unit->cargo; carg != NULL; carg = carg->nexthere) {
X		nums[carg->type]++;
X	    }
X	    for (i = 0; i < numutypes; ++i) {
X		if (nums[i] > 0) {
X		    sprintf(tmp, "%d %c  ", nums[i], unitchars[i]);
X		    strcat(cargobuf, tmp);
X		}
X	    }
X	} else {
X	    sprintf(cargobuf, "  -   ");
X	}
X	sprintf(spbuf2,
X		"%s   HP %d/%d   Moves %d   Supply %d/%d   %s",
X		order_desig(unit->orders), unit->hp, utypes[unit->type].hp,
X		movesleft, unit->supply, utypes[unit->type].supply, cargobuf);
X    } else {
X	sprintf(spbuf2, "");
X    }
X    sprintf(spbuf, "%s", unit_handle(curside, unit));
X    if (curside->showcoords) strcat(spbuf, pos_desig(curx, cury));
X    set_current_info(curside, spbuf, spbuf2);
X    show_info(curside);
X    if (humanside(curside)) {
X	if (unit->transport != NULL || city_at(curx, cury)) {
X	    draw_occupier(curside, unit->type, curx, cury);
X	}
X	draw_cursor(curside, curx, cury);
X    }
X}
X
X/* Get rid of all the prompts and stuff - should work for any side. */
X
Xunshow_unit()
X{
X    erase_cursor(curside, curx, cury);
X    clear_info(curside);
X    flush_output();
X}
X
X/* Build a short phrase describing a given unit to a given side. */
X
Xchar unitbuf[BUFSIZE];
X
Xchar *
Xunit_handle(vside, unit)
XSide *vside;
XUnit *unit;
X{
X    if (vside == NULL) {
X	unitbuf[0] = '\0';
X	if (!Debug) return unitbuf;
X    }
X    if (vside == unit->side)
X	sprintf(unitbuf, "your ");
X    else
X	sprintf(unitbuf, "the %s ", unit->side->name);
X    strcat(unitbuf, ordinal(unit->number));
X    strcat(unitbuf, " ");
X    strcat(unitbuf, unitnames[unit->type]);
X    return unitbuf;
X}
X
X/* Return a serial number (for save game purposes). */
X
Xunit_number(unit)
XUnit *unit;
X{
X    return (unit == NULL ? -1 : unit->id);
X}
X
XUnit *
Xfind_unit(n)
Xint n;
X{
X    Unit *unit;
X
X    for (unit = unitlist; unit != NULL; unit = unit->next) {
X	if (unit->id == n) return unit;
X    }
X    fprintf(stderr, "Panic: no unit numbered %d!\n", n);
X    abort();
X}
X
X/* Write everything about a unit into a file. */
X
Xsave_unit(unit, fp)
XUnit *unit;
XFILE *fp;
X{
X    int i;
X
X    fprintf(fp, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d ",
X	    unit->id, unit->number, unit->type, side_number(unit->side),
X	    unit->x, unit->y, unit->hp, unit->supply, unit->cautious,
X	    unit->hidden, unit->goal, unit_number(unit->transport),
X	    unit->orders.type, unit->orders.rept);
X    for (i = 0; i < NUMORDERPARMS; ++i) {
X	fprintf(fp, "%d ", unit->orders.parms[i]);
X    }
X    fprintf(fp, "\n");
X}
X
X/* Read everything back in and try to recreate the same unit. */
X/* "hp" is the hit points - if <= 0, then dead unit, don't restore it. */
X
Xrestore_unit(fp)
XFILE *fp;
X{
X    int i, id, num, utype, sn, x, y, hp;
X    int sup, caut, hid, goal, port, otype, rept;
X    Unit *unit;
X
X    fscanf(fp, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d",
X	   &id, &num, &utype, &sn, &x, &y, &hp,
X	   &sup, &caut, &hid, &goal, &port, &otype, &rept);
X    unit = create_unit(id, num, utype, side_n(sn), hp, sup, caut, hid, goal);
X    unit->orders.type = otype;
X    unit->orders.rept = rept;
X    for (i = 0; i < NUMORDERPARMS; ++i) {
X	fscanf(fp, "%d", &num);
X	if (hp > 0) unit->orders.parms[i] = num;
X    }
X    /* put it down somewhere */
X    if (port >= 0) {
X	embark_unit(find_unit(port), unit);
X    } else if (x >= 0 && y >= 0) {
X	occupy_square(unit, x, y);
X    }
X    if (hp > 0 && Debug)
X	printf("Restored unit %s %s %d\n",
X	       unit->side->name, unitnames[unit->type], unit->number);
X}
X
X
END_OF_unit.c
if test 14073 -ne `wc -c <unit.c`; then
    echo shar: \"unit.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f xconq.6 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"xconq.6\"
else
echo shar: Extracting \"xconq.6\" \(4968 characters\)
sed "s/^X//" >xconq.6 <<'END_OF_xconq.6'
X.TH XCONQ 6 Utah
X.SH NAME
Xxconq - X-based strategy game
X.SH SYNOPSIS
X.B
Xxconq
X[ options ] ...
X.SH DESCRIPTION
X.I Xconq
Xis a multi-player strategic wargame.
XYour goal is to save the world from the evil empires attempting to
Xtake over.  You get cities, armies, airplanes, and ships with which to
Xaccomplish your task.  Success is achieved by the total elimination
Xof the other sides, whether by conquest, revolt, or surrender.
X.PP
XAlthough the game can get complicated, to start you need only
Xknow about the help command '?', which is valid at any time.
XYou start with only one city, which makes things even simpler.
XYour first input will be to set the city to produce some kind
Xof military unit, after that you will be prompted to move the unit
Xwhen it has been built (takes a few turns).  The game keeps going
Xuntil one side is left in action, who is then declared the winner.
XIf the installer has set it up, a statistical summary will be written
Xinto a file stats.xconq.
X.PP
XBy default,
X.I Xconq
Xstarts up with one human (on the display in $DISPLAY) and one
Xmachine, playing on a randomly generated 60x35 world.  Options are
Xavailable to set numbers and kinds of players, as well as the
Xkind of map used.
X.SH OPTIONS
X.TP 5
X.I host:display
Xadds a human player to the game and assigns to the given host and display.
XPlayers get created in the same order as they appear on the command line,
Xinterleaved with the players created via -e and -A.
X.TP 5
X.B \-A \fIhost:display\fP
Xattaches a machine player to the given display.  Ideal for those who like
Xto watch.
X.TP 5
X.B \-c
Xtoggles a feature that
Xallows each turn to take only a certain number of inputs.
XThe default on this is set by the installer.
X.TP 5
X.B \-e \fInumber\fP
Xsets the number of machine players not attached to displays (defaults to 1).
XMachine players are always effectively allied with each other.
X.TP 5
X.B \-m \fIname\fP
Xsets the map to be either a named map in the library directory
Xor interprets the name as a file name, and attempts to read it.  The format
Xmust be that generated by
X.I mkmap(6).
X.TP 5
X.B \-M \fIwidth height\fP
Xgenerates a random map of the given size.  There are both upper and lower
Xbounds on the possible values.
X(currently 35 to 300 in width, 35 to 160 in height)
X.TP 5
X.B \-r
Xremoves the local display from the list of players.  If used, this option
Xshould come before any other player specifications.
X.TP 5
X.B \-s \fIname\fP
Xrestore the game from the given save file.  If the name is that of a preset
Xscenario in the library diretory, start up that scenario.
X.TP 5
X.B \-t
Xtoggles a feature that
Xallows each turn to be no more than 15 seconds in length.
XThe default on this is set by the installer.
X.TP 5
X.B \-v
Xmake the entire world seen by all players at the outset.
XThis is useful if exploration
Xis deemed to be time-consuming, or if the map is already known to everybody.
X.SH EXAMPLES
X.TP 8
X.B
Xxconq
XOne human on local display, one computer, 60x35 random map
X.TP 8
X.B
Xxconq -m crater
XOne human vs one machine, on the "crater lake" map
X.TP 8
X.B
Xxconq -e 0 foo:0 bar:0
XThree humans (local, foo, and bar displays), 60x35 random map
X.TP 8
X.B
Xxconq -e 2 -M 35 35 -A baz:0
XOne human, three machines (one on display baz:0), 35x35 random map
X.TP 8
X.B
Xxconq -e 3 -m earth1 -r foo:0 bar:0 -A baz:0
XSix players (4 machine, 1 on baz:0; 2 human, on foo:0 and bar:0), all playing
Xon a 360x122 map of the earth.  Major!
X.SH "X DEFAULTS"
X.TP 8
X.B SideName
XName that will be given to the player starting up the game.  (Other sides
Xcan only get random names, sorry.)
X.TP 8
X.B BodyFont
XFont for all text.
X.TP 8
X.B IconFont
XFont for pictures of units (will be different for different periods).
X.SH AUTHOR
XStan Shebs (shebs@cs.utah.edu)
X.SH FILES
X\fIsave.xconq\fP	saved game
X.br
X\fIstats.xconq\fP	performance statistics for a game
X.br
X\fIparms.xconq\fP	listing of units and their characteristics
X.br
X\fI/usr/games/lib/xconq/*.map\fP	predefined maps
X.br
X\fI/usr/games/lib/xconq/*.scn\fP	predefined maps
X.br
X\fI/usr/games/lib/xconq/*.onx\fP	fonts for various periods
X.br
X\fI/usr/games/lib/xconq/xconq.news\fP	news about features/additions
X.SH "SEE ALSO"
Xmkmap(6)
X.br
X.IR "Liberating the World (made simple)"
X.SH DIAGNOSTICS
XIf a given display cannot be opened, then
X.I xconq
Xissues a warning, convert that player into a non-hosted machine player,
Xand continues.  Omission of an
X.I xhost
Xcommand on the other end is likely to be the most common cause of this problem.
X.PP
XIf the icon fonts cannot be found or opened, letters will be substituted.
X.PP
XThere are some panic messages which usually precede a core dump by a few
Xmilliseconds.
X.SH BUGS
XMany (but not infinite).  Some annoying behaviors are actually features.
X
XMachine players are still somewhat stupid.  However, 
X"xconq -v -e 6" will provide
Xa challenge even for experienced players.
X
XThe timer ("-t") doesn't seem to work.
X
XGame saving is incomplete.  Enough is saved to play again, but statistics and
Xmaybe other things are not saved.
END_OF_xconq.6
if test 4968 -ne `wc -c <xconq.6`; then
    echo shar: \"xconq.6\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f xconq.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"xconq.h\"
else
echo shar: Extracting \"xconq.h\" \(16185 characters\)
sed "s/^X//" >xconq.h <<'END_OF_xconq.h'
X/* Copyright (c) 1987  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: xconq.h,v 1.6 87/06/07 11:37:59 shebs Exp $ */
X
X/* Global definitions for xconq.  Nearly everything needed by more than */
X/* one file is here, which is why it's rather large. */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X
X#define TRUE (1)
X#define FALSE (0)
X
X#define bool char
X
X/* Get the file of things that usually need to be tweaked. */
X
X#include "config.h"
X
X#ifdef XWINDOWS
X#include <X/Xlib.h>
X#endif XWINDOWS
X
X/* General classes of units - we exclude amphibious, spaceships, etc */
X
X#define NUMDOMAINS 3
X
X/* These values are used in period descriptions, so be careful! */
X
X#define LAND  0
X#define WATER 1
X#define AIR   2
X
X#define landtype(x) (utypes[x].domain == LAND)
X
X#define watertype(x) (utypes[x].domain == WATER)
X
X#define airtype(x) (utypes[x].domain == AIR)
X
X#define land(x) (landtype((x)->type))
X
X#define ship(x)  (watertype((x)->type))
X
X#define aircraft(x) (airtype((x)->type))
X
X#define DOMNAMES { "land", "sea", "air" }
X
X/* Definitions about units */
X
X#define NOTHING -1
X
X#define alive(u) ((u)->hp > 0)
X
X#define producing(city) ((city)->product != NOTHING)
X
X/* terrain types */
X
X#define MAXTERRTYPES 16
X
X#define NUMTERRTYPES 7
X
X#define SEA        0
X#define SHOALS     1
X#define OPEN       2
X#define FOREST     3
X#define DESERT     4
X#define MOUNTAINS  5
X#define ICE        6
X
X#define TERRCHARS   ".,+%~^_"
X
X#define TERRNAMES  { "sea", "shallows", "plains", "forest", \
X		     "desert", "mountains", "ice" }
X
X#define terrain(x,y) (world[x][y].type & 15)
X
X#define urb(x,y) (((world[x][y].type)>>4) & 3)
X
X#define is_urban(x,y) (urb(x, y))
X
X#define set_square(x,y,t,c) (world[x][y].type = ((c)<<4)|(t))
X
X#define unit_at(x,y) (is_urban((x),(y)) ? NULL : world[x][y].ptr.unit)
X
X#define set_unit_at(x,y,u) (world[x][y].ptr.unit = (u))
X
X#define city_at(x,y) (is_urban((x),(y)) ? world[x][y].ptr.city : NULL)
X
X#define set_city_at(x,y,c) (world[x][y].ptr.city = (c))
X
X/* Types of cities */
X
X#define MAXCTYPES  4
X
X#define RURAL      0
X#define BASE       1
X#define TOWN       2
X#define CITY       3
X
X/* unit order types */
X
X#define NUMORDERTYPES 10
X
X#define NONE     0
X#define AWAKE    1
X#define SENTRY   2
X#define RANDOM   3
X#define MOVEDIR  4
X#define MOVETO   5
X#define COAST    6
X#define BUILD    7
X#define FOLLOW   8
X#define PATROL   9
X
X#define ORDERCHARS " wsrdmf lp"
X			 
X#define ORDERNAMES \
X  { "None", "Awake", "Sentry", "Random", "Dir Move", \
X    "Move to", "Follow Coast", "Build Base", "Follow Leader", "Patrol" }
X
X#define SHORTORDERNAMES { "No", "Aw", "Sn", "Rn", "Mv", \
X			  "MT", "FC", "BB", "FL", "Pa" }
X
X/* Types of arguments that orders require */
X
X#define NOARG     0
X#define DIR       1
X#define POS       2
X#define ORIENT    3
X#define LEADER    4
X#define WAYPOINTS 5
X
X#define ORDERARGS \
X  { NOARG, NOARG, NOARG, NOARG, DIR, POS, ORIENT, NOARG, LEADER, WAYPOINTS }
X
X#define ORDERARGNAMES \
X  { "no args", "no args", "no args", "no args", "direction to move", \
X    "destination", "orientation", "no args", "unit", "waypoints" }
X
X#define NUMORDERPARMS 6
X
X/* definitions for directions of the compass */
X			 
X#define NORTH 0
X#define NE    1
X#define EAST  2
X#define SE    3
X#define SOUTH 4
X#define SW    5
X#define WEST  6
X#define NW    7
X			 
X#define DIRNAMES { "N", "NE", "E", "SE", "S", "SW", "W", "NW" }
X
X#define DIRX { 0, 1, 1,  1,  0, -1, -1, -1 }
X#define DIRY { 1, 1, 0, -1, -1, -1,  0,  1 }
X
X/* Definitions about sides */
X
X#define humanside(x) ((x) != NULL && (x)->humanp)
X
X#define human(x) ((x) != NULL && humanside((x)->side))
X
X#define own(x)     ((x)->side == curside)
X
X#define enemy(x)   ((x)->side != curside)
X
X#define neutral(x) ((x)->side == NULL)
X
X/* outcomes of unit-vs-unit combat (not currently used) */
X
X#define ADVANCE 0
X#define STAY    1
X#define RETREAT 2
X
X/* Ways in which a city can be attacked */
X
X/* These values are used in period descriptions, so be careful! */
X
X#define NOWAY   0
X#define BOMBARD 1
X#define ASSAULT 2
X#define FLATTEN 3
X
X/* Kinds of goals that a unit might be programmed to go for */
X
X#define NORMAL  1
X#define MISSION 2
X#define LOADING 3
X#define REFUEL  4
X
X/* Modes governing the interpretation of input */
X
X#define MOVE      0
X#define SURVEY    1
X
X#define MODENAMES { "Move", "Survey" }
X
X/* Morale levels */
X
X#define MINMORALE    1
X#define SATISFIED 5000
X#define MAXMORALE 9999
X
X/* Fates of cities */
X
X#define CAPTURED 1
X#define REVOLTED 2
X#define FLATTENED 3
X#define NUKED 4
X
X/* Strategies available to machine players */
X
X#define NUMSTRATEGIES 6
X
X#define ATTACK    0
X#define SEARCHOUT 1
X#define PLANAHEAD 2
X#define NUKETHEM  3
X#define FANATIC   4
X#define HIDEOUT   5
X
X#define POINTS { 500, 1000, 2000, 2000, 1000, 3000 }
X
X/* Types of input that may be encountered */
X
X#define KEYBOARD 1
X#define MOUSE    2
X
X/* For statistics purposes */
X
X#define MAXREASONS 9
X
X#define UNITDEFEAT 0
X#define CITYDEFEAT 1
X#define STARVATION 2
X#define PRISONER 3
X#define GARRISON 4
X#define DISBAND 5
X#define SURRENDER 6
X#define VICTOR 7
X#define ENDOFWORLD 8
X
X#define REASONNAMES "Unit  City  Supp  Pris  Garr  Disb  Surr   Win  Quit"
X
X/* Random definitions not classifiable elsewhere */
X
X#define MAXTRIES 500
X
X/* Definition of the "side" structure - one for each player in the game */
X
Xtypedef struct a_side {
X    char *name;             /* name used for display */
X    char *host;             /* which host is this side attached to */
X    bool humanp;            /* is this side played by a person? */
X    int basenum;            /* number of next base */
X    int score;              /* current score assigned to that side */
X    bool lost;              /* true if this side was knocked out */
X    int territory;          /* number of cities (1 city = 5 towns, etc) */
X    int morale;             /* population's opinion on chances */
X    int strategy;           /* current strategy used by machine player */
X    int stratparms[3];      /* parameters of strategy */
X    int counts[MAXUTYPES];  /* array of numbers for identifying units */
X    unsigned char *view;    /* pointer to array of view info */
X    struct a_side *next;    /* pointer to next in list */
X#ifdef XWINDOWS
X    Display *display;       /* side's display structure */
X    bool fewcolors;         /* true if needs to use icons for terrain also */
X    int vwid, vhgt, vwid2, vhgt2;
X    int vcx, vcy;           /* center square in the view */
X    int lastvcx, lastvcy;   /* last center square (-1,-1 initially) */
X    int lastx, lasty;       /* last current x and y (-1,-1 initially) */
X    /* Redrawing buffers */
X    char noticebuf[MAXNOTES][BUFSIZE];
X    char infobuf[2][BUFSIZE];
X    char promptbuf[BUFSIZE];
X    char titlebuf[BUFSIZE];         /* used on hosted displays (NS) */
X    /* X objects */
X    Window main, map, world, msg, prompt, info;
X    Window time, clock, mode, state, sides, help;
X    Font msgfont, iconfont;
X    FontInfo *msgfontinfo, *iconfontinfo;
X    Bitmap ccurs, cmask, mcurs, mmask, dots, bombpics[3];
X    Pixmap bordertile, dotpix;
X    Cursor curs;
X    int bdcolor, bgcolor, fgcolor;  /* standard symbolic colors */
X    int owncolor, enemycolor, graycolor, curscolor;  /* less standard colors */
X    int sqcolor[MAXTERRTYPES];  /* colors for terrain */
X#endif XWINDOWS
X    /* player options */
X    bool warpmouse;        /* if true, mouse cursor is moved around */
X    bool showcoords;       /* if true, coordinates displayed */
X    /* statistics for a side */
X    int atkstats[MAXUTYPES][MAXUTYPES];
X    int hitstats[MAXUTYPES][MAXUTYPES];
X    int cityatks[MAXUTYPES][MAXCTYPES];
X    int cityhits[MAXUTYPES][MAXCTYPES];
X    int losses[MAXUTYPES][MAXREASONS];
X    int production[MAXCTYPES];
X    int completion[MAXCTYPES];
X} Side;
X
X/* Definition of an "order", which is the means by which a unit keeps */
X/* track of what it should do.  Needs the encapsulation because orders */
X/* show up in both cities and units. */
X
Xtypedef struct a_order {
X    int type;                /* type of order (awake, random, etc) */
X    int rept;                 /* number to repeat order */
X    int parms[NUMORDERPARMS]; /* random parameters for order */
X} Order;
X
X/* Unit type descriptions go into a single structure. */
X
Xtypedef struct utype {
X    char uchar;            /* character used in prompts */
X    char *name;            /* the name (frequently used!) */
X    char *note;            /* one-line description */
X    int domain;            /* land, water, air */
X    int range;             /* how far it can move in a certain num of turns */
X    int turns;             /* the certain num of turns (usually 1) */
X    int randmove;          /* randomness of move */
X    int supply;            /* starting amount of supplies */
X    int hp;                /* hit points */
X    int schedule;          /* normal production schedule */
X    int startup;           /* production schedule for first */
X    bool canhide;          /* true if unit not always seen */
X    bool moveson[NUMTERRTYPES]; /* how many moves on given terrain (unused) */
X    int resupply[NUMTERRTYPES]; /* resupply if on terrain */
X    int adj[NUMTERRTYPES]; /* resupply if next to terrain */
X    int hittab[MAXUTYPES]; /* chance of hitting other units */
X    int power;             /* how many points it hits for */
X    int hittime;           /* extra moves to attack */
X    int hitsupply;         /* extra supply used in attack */
X    int vscity[MAXCTYPES]; /* chance of succeeding against city */
X    int powervscity[MAXCTYPES];  /* parameter for success action */
X    int cityvs[MAXCTYPES]; /* chance of city hitting back */
X    int capacity[MAXUTYPES];  /* carrying capacity for other units */
X    int buildtime;         /* time to build a base */
X    int garrison;          /* true if unit needed to garrison base */
X} Utype;
X
X/* Individual units have a completely different structure. */
X
Xtypedef struct a_unit {
X    int id;                    /* unique id (for save/restore) */
X    int number;                /* semi-unique id number */
X    int type;                  /* type (army, ship, etc) */
X    Side *side;                /* whose side this unit is on */
X    int x, y;                  /* position of unit on map */
X    int hp;                    /* how much damage it can take */
X    int supply;                /* how many turns of food&fuel unit has */
X    int cautious;              /* when true, unit tries to survive */
X    int hidden;                /* true if unit cannot be seen */
X    int goal;                  /* current goal (affects behav sometimes) */
X    Order orders;              /* current orders being carried out */
X    struct a_unit *cargo;      /* pointer to first unit being carried */
X    struct a_unit *transport;  /* pointer to transporter if any */
X    struct a_unit *nexthere;   /* pointer to fellow cargo or city occupant */
X    struct a_unit *next;       /* next unit in list of all units */
X} Unit;
X
X/* Definitions of city types. */
X
Xtypedef struct ctype {
X    char cchar;                /* character representing */
X    char *name;                /* general name for this size */
X    char *note;                /* thumbnail sketch of type */
X    int hp;                    /* number of hit points */
X    int recovery;              /* how many turns to regain a hit point */
X    int siege;                 /* chance to resist a siege */
X    int mgain;                 /* morale gain if captured */
X    int mloss;                 /* morale loss if lost */
X    char capacity[NUMDOMAINS]; /* capacity for units (of each domain) */
X} Ctype;
X
X/* Cities contain data about their production schedule, as well as */
X/* standing orders for units and a list of units in the city. */
X
Xtypedef struct a_city {
X    char *name;                 /* printable name of the city */
X    char size;                  /* different sizes of cities */
X    Side *side;                 /* whose side this city is on */
X    char *sname;                /* name of the side if starts here (NS) */
X    int x, y;                   /* position of the city */
X    char product;               /* type of unit city is producing */
X    int schedule;               /* when the unit will be done */
X    int hp;                     /* hit points left */
X    int produced[MAXUTYPES];    /* how many units have been produced */
X    Order standing[MAXUTYPES];  /* orders that will be passed to units */
X    Unit *occupant;             /* pointer to list of units in city (NS) */
X    struct a_city *next;        /* next city in list of all cities */
X} City;
X
X/* This structure should be as small as possible, since it is an */
X/* individual entry in the array containing the entire world. */
X
Xtypedef struct a_square {
X    char type;            /* terrain type at this spot */
X    union {
X	City *city;       /* pointer to city if any */
X	Unit *unit;       /* pointer to unit if any */
X    } ptr;
X} Square;
X
X/* The world itself. */
X
Xextern Square world[MAXWIDTH][MAXHEIGHT];
X
Xextern int worldwidth, worldheight, greenwich, equator, scale;
X
Xextern char terrchars[], *terrnames[];
X
X/* Side variables. */
X
Xextern Side *sidelist, *curside, *create_side(), *side_n();
X
Xextern int numgivens, numhosts, numsides, numinaction;
X
Xextern char *hosts[];
X
Xextern bool humans[];
X
X/* City variables. */
X
Xextern Ctype ctypes[];
X
Xextern City *citylist, *create_city(), *random_start_city();
X
Xextern int numctypes, numcities;
X
Xextern char citychars[], *citynames[];
X
X/* Unit variables. */
X
Xextern Utype utypes[];
X
Xextern Unit *unitlist, *curunit;
Xextern Unit *create_new_unit(), *create_unit(), *find_unit();
X
Xextern int numutypes, numunits, nextid, orderargs[];
X
Xextern char unitchars[], *unitnames[], orderchars[], *ordernames[];
Xextern char *orderargnames[];
X
X/* miscellaneous */
X
Xextern bool timedout, usecount, usetimer, countedout, gaveup, beepedplayer;
Xextern bool directorder, movesuccess;
X
Xextern char spbuf[], spbuf2[], version[];
Xextern char programname[], rawmapname[], mapname[], rawsavename[], savename[];
Xextern char *ordinal(), *plural_form(), *pos_desig(), *read_message();
Xextern char *side_desig(), *order_desig();
Xextern char *unit_handle(), *city_handle();
Xextern char *getenv(), *temp_name();
X
Xextern int dirx[], diry[];
Xextern int gametime, countdown;
Xextern int avgstrat, enemyx, enemyy, adjx, adjy;
Xextern int mode, pushedmode, movesleft, curx, cury, newx, newy;
Xextern int numinputs;
Xextern int vwid, vhgt, vwid2, vhgt2, mapmag, fw, fh;
X
X/* Debugging declarations.  Depending on the cpp flag, "Debug" will either */
X/* turn into a variable settable from the command line, or into FALSE. */
X
X#ifdef DEBUGGING
Xextern bool debug;
X#define Debug debug
X#else
X#define Debug FALSE
X#endif
X
X/* Manipulation of bytes encoding views of things. */
X
X#define seen(s,x,y) (side_view(s, x, y))
X
X#define buildview(a,cu,t) (((a+1)<<5)|(cu)|(t))
X
X#define valign(v) ((((v)>>5) & 0x07)-1)
X#define vthing(v) ((v) & 0x10)
X#define vtype(v)  ((v) & 0x0f)
X
X#define VCITY 0x10
X#define VUNIT 0x00
X
X#define UNSEEN 0x00
X#define EMPTY  0x10
X
X#define side_view(s,x,y) (((s)->view)[worldwidth*(y)+(x)])
X
X#define set_side_view(s,x,y,v) (((s)->view)[worldwidth*(y)+(x)] = (v))
X
X/* Some more handy macros. */
X
X#define abs(x) (((x) < 0) ? (0-(x)) : (x))
X
X#define min(x,y) (((x) < (y)) ? (x) : (y))
X
X#define max(x,y) (((x) > (y)) ? (x) : (y))
X
X#define between(lo,n,hi) ((lo) <= (n) && (n) <= (hi))
X
X/* This little macro implements wraparound in the x direction. */
X/* The stupid add is for the benefit of brain-damaged mod operators. */
X
X#define wrap(x) (((x) + 4*worldwidth) % worldwidth)
X
X#define limit(y) (max(0, min((worldheight-1), (y))))
X
X#define flip_coin() (random(45) % 2)
X
X#define probability(n) (random(100) < (n))
X
X#define spy() (!random(40))
X
X#define random_dir() (random(8))
X
X#define could_capture(utype,ctype) (utypes[utype].vscity[ctype] == ASSAULT)
X
X#define could_carry(u1,u2) (utypes[(u1)->type].capacity[(u2)->type] > 0)
X
X#define for_all_units(var) for (var = unitlist; var != NULL; var = var->next)
X
X#define for_all_cities(var) for (var = citylist; var != NULL; var = var->next)
X
X#define for_all_sides(var) for (var = sidelist; var != NULL; var = var->next)
END_OF_xconq.h
if test 16185 -ne `wc -c <xconq.h`; then
    echo shar: \"xconq.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 7\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 7 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0