DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T d

⟦529e21198⟧ TextFile

    Length: 30185 (0x75e9)
    Types: TextFile
    Names: »do.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/X/Xconq/do.c« 

TextFile

/* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
/* This program may be used, copied, modified, and redistributed freely */
/* for noncommercial purposes, so long as this notice remains intact. */

/* RCS $Header: do.c,v 1.1 88/06/21 12:30:06 shebs Exp $ */

/* This file contains almost all command functions. */
/* Help commands are in a separate file. */

#include "config.h"
#include "misc.h"
#include "dir.h"
#include "period.h"
#include "side.h"
#include "unit.h"
#include "map.h"
#include "global.h"

extern bool delaymove;

char *grok_string();

bool reconfig;          /* true when an option needs screen reconfigured */
bool remap;             /* true when only main map needs redrawing */
bool reinfo;            /* true when only info display needs redrawing */
bool tmparea = TRUE;    /* true for area painting, false for bar painting */

/* Things will be totally scrogged if two human players in build mode... */

int tmpterr = 0;	/* temporary terrain type for area operation */
int tmpdist = 0;        /* temporary argument for painting */
int tmpflag;		/* temporary int for area operation */

/* Move in given direction a given distance - used for both single and */
/* automatic multiple moves. */

do_dir(side, dir, n)
Side *side;
int dir, n;
{
    if (side->teach) {
	cache_movedir(side, dir, n);
    } else {
	switch (side->mode) {
	case MOVE:
	    if (side->curunit != NULL) order_movedir(side->curunit, dir, n);
	    break;
	case SURVEY:
	    move_survey(side,
			wrap(side->curx + n*dirx[dir]),
			side->cury + n*diry[dir]);
	    break;
	default:
	    case_panic("mode", side->mode);
	}
    }
}

/* Wake *everything* (that's ours) within the given radius.  Two commands */
/* actually; lowercase is transports only, uppercase is everybody. */

do_wakeup(side, n)
Side *side;
int n;
{
    if (side->teach) {
	cache_awake(side, 1);
    } else {
	wakeup_area(side, n, TRUE);
    }
}

/* Wake up only the main/current unit in a hex. */

do_wakemain(side, n)
Side *side;
int n;
{
    if (side->teach) {
	cache_awake(side, 1);
    } else {
	wakeup_area(side, n, FALSE);
    }
}

/* The area wakeup. */

wake_at(x, y)
int x, y;
{
    Unit *unit = unit_at(x, y);

    if (unit != NULL && (unit->side == tmpside || Build))
	wake_unit(unit, tmpflag);
}

wakeup_area(side, n, occs)
Side *side;
int n, occs;
{
    tmpside = side;
    tmpflag = occs;
    apply_to_area(side->curx, side->cury, n, wake_at);
}

/* Put unit to sleep for a while.  If we sleep it next to something that */
/* might wake it up, then adjust flags so it won't wake up on next turn. */

do_sentry(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    if (side->teach) {
	cache_sentry(side, n);
    } else {
	order_sentry(unit, n);
	if (n > 1 && adj_enemy(unit))
	    unit->orders.flags &= ~(ENEMYWAKE|NEUTRALWAKE);
    }
}

/* Don't move for remainder of turn, but be awake next turn.  This also */
/* hooks into terrain painting, since the space bar is big and convenient. */

do_sit(side, n)
Side *side;
int n;
{
    if (side->mode == SURVEY && Build) {
	paint_terrain(side);
    } else if (side->curunit != NULL) {
	do_sentry(side, side->curunit, 1);
    } else {
	cmd_error(side, "No unit to operate on here!");
    }
}

/* Set unit to move to a given location.  */

x_moveto(side)
Side *side;
{
    if (grok_position(side)) {
	if (side->teach) {
	    cache_moveto(side, side->reqposx, side->reqposy);
	} else if (Build) {
	    leave_hex(side->requnit);
	    occupy_hex(side->requnit, side->reqposx, side->reqposy);
	    make_current(side, side->requnit);
	    all_see_hex(side->curx, side->cury);
	} else {
	    order_moveto(side->requnit, side->reqposx, side->reqposy);
	}
	restore_cur(side);
    } else {
	request_input(side, side->requnit, x_moveto);
    }
}

/* The command proper. */

do_moveto(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    ask_position(side, "Move to where?");
    request_input(side, unit, x_moveto);
    side->reqposx = side->curx;  side->reqposy = side->cury;
}

/* Auxiliary stuff used when searching for place to return to.  Note that */
/* a good refueling spot will be woken up, so it won't get too far away */
/* before unit has a chance to get there. */
/* Won't find refueling places inside other units, sigh. */

refuel_here(x, y)
int x, y;
{
    Unit *unit = unit_at(x, y);

    if (unit != NULL && unit->side == tmpside && can_carry(unit, tmpunit)) {
	wake_unit(unit, FALSE);
	return TRUE;
    }
    return FALSE;
}

/* Search for a friendly refueler within range and set course for it.  */
/* Warn player and refuse to move if nothing close enough. */

do_return(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    int x, y, u = unit->type, r, range = max(world.width, world.height);

    for_all_resource_types(r) {
	if (utypes[u].tomove[r] > 0) {
	    range = min(range, unit->supply[r] / utypes[u].tomove[r]);
	}
    }
    tmpside = side;
    tmpunit = unit;
    if (search_area(unit->x, unit->y, range, refuel_here, &x, &y)) {
	if (unit->x != x || unit->y != y) {
	    order_moveto(unit, x, y);
	    unit->orders.flags = SHORTESTPATH;
	} else {
	    cmd_error(side, "Already at a resupply point!");
	}
    } else {
	cmd_error(side, "No resupply point in range!");
    }
}

/* Set unit to attempt to follow a coast.  Needs a starting direction, */
/* which can be computed from a position. */

x_coast(side)
Side *side;
{
    int dir;

    if (grok_position(side)) {
	if (side->curx != side->reqposx || side->cury != side->reqposy) {
	    dir = find_dir(side->reqposx - side->curx,
			   side->reqposy - side->cury);
	    if (side->teach) {
		cache_edge(side, dir, side->reqvalue2);
	    } else {
		order_edge(side->requnit, dir, side->reqvalue2);
	    }
	    restore_cur(side);
	} else {
	    cmd_error(side, "No particular direction at own hex??");
	}
    } else {
	request_input(side, side->requnit, x_coast);
    }
}

/* The command proper just sets up the interaction. */

do_coast(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    ask_position(side, "Move in which direction?");
    request_input(side, unit, x_coast);
    side->reqposx = side->curx;  side->reqposy = side->cury;
    side->reqvalue2 = n;
}

/* Set orders to follow a leader unit. */

x_follow(side)
Side *side;
{
    Unit *leader;

    if (grok_position(side)) {
	if ((leader = unit_at(side->reqposx, side->reqposy)) != NULL &&
	    leader->side == side) {
	    if (leader != side->requnit) {
		if (side->teach) {
		    cache_follow(side, leader, side->reqvalue2);
		} else {
		    order_follow(side->requnit, leader, side->reqvalue2);
		}
	    } else {
		cmd_error(side, "Unit can't follow itself!");
	    }
	} else {
	    cmd_error(side, "No unit to follow!");
	}
	restore_cur(side);
    } else {
	request_input(side, side->requnit, x_follow);
    }
}

/* The command proper. */

do_follow(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    ask_position(side, "Which unit to follow?");
    request_input(side, unit, x_follow);
    side->reqposx = side->curx;  side->reqposy = side->cury;
    side->reqvalue2 = n;
}

/* Patrolling goes back and forth between two points.  First point is the */
/* current position. */

x_patrol(side)
Side *side;
{
    if (grok_position(side)) {
	if (side->teach) {
	    cache_patrol(side, side->sounit->x, side->sounit->y,
			 side->reqposx, side->reqposy, side->reqvalue2);
	} else {
	    order_patrol(side->requnit, side->requnit->x, side->requnit->y,
			 side->reqposx, side->reqposy, side->reqvalue2);
	}
	restore_cur(side);
    } else {
	request_input(side, side->requnit, x_patrol);
    }
}

/* The command proper. */

do_patrol(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    ask_position(side, "What other endpoint for patrol?");
    request_input(side, unit, x_patrol);
    side->reqposx = side->curx;  side->reqposy = side->cury;
    side->reqvalue2 = n;
}

/* Delay a unit's move until a later time.  The set flag will be recognized */
/* by the movement loops, when deciding which unit to move next. */

do_delay(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    delaymove = TRUE;
    notify(side, "Delaying moving %s.", unit_handle(side, unit));
}

/* Get rid of unit.  Some units cannot be disbanded, but if they can, the */
/* resources go to a transport if one is there.  Disbanding a transport */
/* also disbands all the occupants - oh well. */

do_disband(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    int u = unit->type;

    if (utypes[u].disband || Build) {
	notify(side, "%s goes home.", unit_handle(side, unit));
	if (unit->transport != NULL) recycle_unit(unit, unit->transport);
	kill_unit(unit, DISBAND);
	make_current(side, unit_at(side->curx, side->cury));
    } else {
	cmd_error(side, "You can't just get rid of the %s!", utypes[u].name);
    }
}

/* Reclaim both the unit's supplies and anything used in its making, but */
/* only let a maker of the unit reclaim its ingredients. */

recycle_unit(unit, unit2)
Unit *unit, *unit2;
{
    int u = unit->type, u2 = unit2->type, r, scrap;

    for_all_resource_types(r) {
	transfer_supply(unit, unit2, r, unit->supply[r]);
	if (could_make(u2, u) > 0) {
	    scrap = utypes[u].tomake[r];
	    unit2->supply[r] += (scrap * period.efficiency) / 100;
	}
    }
}

/* Give a unit to another side (possibly to neutrals).  Units that won't */
/* change their sides when captured won't change voluntarily either. */

do_give_unit(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    int u = unit->type;

    if (utypes[u].changeside || Build) {
	unit_changes_side(unit, side_n(n), CAPTURE, PRISONER);
	all_see_hex(unit->x, unit->y);
    } else {
	cmd_error(side, "You can't just give away the %s!", utypes[u].name);
    }
}

/* Marking is for the purpose of rearranging units within a hex. */

do_mark_unit(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    side->markunit = unit;
    notify(side, "%s has been marked.", unit_handle(side, unit));
}

/* This is a clever (if I do say so myself) command to examine all occupants */
/* and suboccupants, in a preorder fashion. */

do_occupant(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    Unit *nextup;

    switch (side->mode) {
    case MOVE:
	cmd_error(side, "Can only look at occupants when in survey mode!");
	break;
    case SURVEY:
	if (unit->occupant != NULL) {
	    make_current(side, unit->occupant);
	} else if (unit->nexthere != NULL) {
	    make_current(side, unit->nexthere);
	} else {
	    nextup = unit->transport;
	    if (nextup != NULL) {
		while (nextup->transport != NULL && nextup->nexthere == NULL) {
		    nextup = nextup->transport;
		}
		if (nextup->nexthere != NULL)
		    make_current(side, nextup->nexthere);
		if (nextup->transport == NULL)
		    make_current(side, nextup);
	    }
	}
	break;
    default:
	case_panic(side->mode, "mode");
	break;
    }
}

/* This can actually do general rearrangement, but defaults to putting the */
/* unit on the first available transport in the hex.  */
/* What about trying to embark a unit on itself or on its previous transp? */

do_embark(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    Unit *mainunit = unit_at(side->curx, side->cury);
    Unit *transport = NULL;

    if (mainunit != unit) {
	if (side->markunit == NULL ||
	    side->markunit->x != unit->x || side->markunit->y != unit->y) {
	    for_all_occupants(mainunit, transport) {
		if (can_carry(transport, unit)) break;
	    }
	} else {
	    transport = side->markunit;
	}
	if (transport != NULL) {
	    leave_hex(unit);
	    occupy_unit(unit, transport);
	} else {
	    cmd_error(side, "No plausible transport!");
	}
    } else {
	cmd_error(side, "Nothing for this unit to get into!");
    }
}

/* Give supplies to a transport.  The argument tells how many to give. */

do_give(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    bool something = FALSE;
    int u = unit->type, m, r, gift, actual;
    Unit *main = unit->transport;

    if (main != NULL) {
	sprintf(spbuf, "");
	m = main->type;
	for_all_resource_types(r) {
	    gift = (n < 0 ? utypes[m].storage[r] - main->supply[r] : n);
	    if (gift > 0) {
		something = TRUE;
		/* Be stingy if we're low */
		if (2 * unit->supply[r] < utypes[u].storage[r])
		    gift = max(1, gift/2);
		actual = transfer_supply(unit, main, r, gift);
		sprintf(tmpbuf, " %d %s", actual, rtypes[r].name);
		strcat(spbuf, tmpbuf);
	    }
	}
	if (something) {
	    notify(side, "%s gave%s.", unit_handle(side, unit), spbuf);
	} else {
	    notify(side, "%s gave nothing.", unit_handle(side, unit));
	}
    } else {
	cmd_error(side, "Can't transfer supplies here!");
    }
}

/* Take supplies from transport.  Both the transport must have something */
/* left. */

do_take(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    bool something = FALSE;
    int u = unit->type, m, r, need, actual;
    Unit *main = unit->transport;

    if (main != NULL) {
	sprintf(spbuf, "");
	m = main->type;
	for_all_resource_types(r) {
	    need = (n < 0 ? utypes[u].storage[r] - unit->supply[r] : n);
	    if (need > 0) {
		something = TRUE;
		/* Be stingy if we're low */
		if (2 * main->supply[r] < utypes[m].storage[r])
		    need = max(1, need/2);
		actual = transfer_supply(main, unit, r, need);
		sprintf(tmpbuf, " %d %s", actual, rtypes[r].name);
		strcat(spbuf, tmpbuf);
	    }
	}
	if (something) {
	    notify(side, "%s got%s.", unit_handle(side, unit), spbuf);
	} else {
	    notify(side, "%s needed nothing.", unit_handle(side, unit));
	}
    } else {
	cmd_error(side, "Can't transfer supplies here!");
    }
}

/* Take the current player out of the game while letting everybody else */
/* continue on. */

x_resign(side)
Side *side;
{
    if (grok_bool(side)) resign_game(side, side->reqoside);
}

do_resign(side, n)
Side *side;
int n;
{
    ask_bool(side, "Do you really want to give up?", FALSE);
    request_input(side, NULL, x_resign);
    side->reqoside = side_n(n);
}

/* Unconditional resignation - usable by everybody. */

resign_game(side, side2)
Side *side, *side2;
{
    notify_all("Those wimpy %s have given up!", plural_form(side->name));
    if (side2 != NULL) {
	notify_all("... and they gave all their stuff to the %s!",
		   plural_form(side2->name));
    }
    side_loses(side, side2);
}

/* Leave quickly when the boss walks by.  One person can kill a multi-player */
/* game, which isn't too great, but the alternatives are complicated. */
/* The stats file will be left behind, to foment argument about who would */
/* have won... This routine also includes a trapdoor for freezing/unfreezing */
/* machine players when building - mode display will invert to confirm this. */

x_exit(side)
Side *side;
{
    Unit *unit;

    if (grok_bool(side)) {
	close_displays();
	printf("\nThe outcome remains undecided");
	if (numhumans == 1 && side->humanp) {
	    printf(", but you're probably the loser!\n\n", side->host);
	} else {
	    printf("...\n\n");
	}
	/* Need to kill off all units to finish up statistics */
	for_all_units(unit) if (alive(unit)) kill_unit(unit, ENDOFWORLD);
	print_statistics();
	exit(0);
    }
    if (Build) {
	Freeze = !Freeze;
	show_timemode(side);
    }
}

do_exit(side, n)
Side *side;
int n;
{
    ask_bool(side, "Do you REALLY want to end the game for EVERYBODY?",
	     FALSE);
    request_input(side, NULL, x_exit);
}

/* Stuff game state into a file.  By default, it goes into the current */
/* directory.  If building a scenario, will ask about each section, values */
/* of globals, and dest file before actually writing anything. */
/* No capability to write out period at present... */

x_save_1(side)
Side *side;
{
    char *sects, *fname;
    int sdetail = 1, udetail = 1;

    if ((sects = grok_string(side)) != NULL) {
	fname = "random.scn";
	sprintf(spbuf, "------");
	if (iindex('v', sects) >= 0) spbuf[0] = '+';
	if (iindex('p', sects) >= 0) spbuf[1] = '+';
	if (iindex('m', sects) >= 0) spbuf[2] = '+';
	if (iindex('g', sects) >= 0) spbuf[3] = '+';
	if (iindex('s', sects) >= 0) spbuf[4] = '+';
	if (iindex('u', sects) >= 0) spbuf[5] = '+';
	if (iindex('s', sects) >= 0) {
	    sdetail = 1;
	    if (isdigit(sects[iindex('s', sects)+1]))
		sdetail = sects[iindex('s', sects)+1] - '0';
	}
	if (iindex('u', sects) >= 0) {
	    udetail = 1;
	    if (isdigit(sects[iindex('u', sects)+1]))
		udetail = sects[iindex('u', sects)+1] - '0';
	}
	notify(side, "Mapfile with sections %s will be saved to \"%s\" ...",
	       spbuf, fname);
	if (write_scenario(fname, spbuf, sdetail, udetail)) {
	    notify(side, "Done writing to \"%s\".", fname);
	} else {
	    cmd_error(side, "Can't open file \"%s\"!", fname);
	}
    } else {
	request_input(side, NULL, x_save_1);
    }
}

/* Make a header appropriate to a save file, write the file, and leave. */

x_save_2(side)
Side *side;
{
    if (grok_bool(side)) {
	notify_all("Game will be saved to \"%s\" ...", SAVEFILE);
	if (write_savefile(SAVEFILE)) {
	    close_displays();
	    exit(0);
	} else {
	    cmd_error(side, "Can't open file \"%s\"!", SAVEFILE);
	}
    }
}

/* The command proper just sets up different handlers, depending on */
/* whether we're building (and therefore saving a scenario/fragment), or */
/* saving as much game state as possible, for resumption later. */

do_save(side, n)
Side *side;
int n;
{
    if (Build) {
	ask_string(side, "Sections to write?", "ms1u1");
	request_input(side, NULL, x_save_1);
    } else {
	ask_bool(side, "You really want to save?", FALSE);
	request_input(side, NULL, x_save_2);
    }
}

/* Redraw everything using the same code as when windows need a redraw. */

do_redraw(side, n)
Side *side;
int n;
{
    redraw(side);
}

/* Name or rename the current unit or a given side.  We make a copy of the */
/* string after it's been successfully read, just in case. */

x_name(side)
Side *side;
{
    char *name;
    Side *side2;

    if ((name = grok_string(side)) == NULL) {
	request_input(side, side->requnit, x_name);
    } else if (strlen(name) == 0) {
	notify(side, "Name not changed.");
    } else if (side->requnit != NULL) {
	side->requnit->name = copy_string(name);
    } else if (side->reqoside != NULL) {
	side->reqoside->name = copy_string(name);
	for_all_sides(side2) show_all_sides(side2);
    } else {
	cmd_error(side, "Nothing to name!");
    }
}

/* The command proper decides between unit and side naming. */

do_name(side, n)
Side *side;
int n;
{
    if (side->curunit != NULL) {
	ask_string(side, "New name for unit:", side->curunit->name);
    } else {
	ask_string(side, "New name for yourself:", side->name);
	side->reqoside = side;
    }
    request_input(side, side->curunit, x_name);
}

/* Designate the current location as the center of action and sort all */
/* of our own units relative to it. */

do_center(side, n)
Side *side;
int n;
{
    side->cx = side->curx;  side->cy = side->cury;
    sort_units();
    notify(side, "Units reordered.");
}

/* Hook command to set miscellaneous options.  Can't do from command line */
/* because each display may want different behavior.  This routine can */
/* change the display dramatically, but it should only redraw if a change */
/* has actually been made. */

/* Conversion to machine player is irreversible, so we confirm it first. */

x_options_2(side)
Side *side;
{
    if (grok_bool(side)) {
	side->humanp = !side->humanp;
	numhumans--;
	init_sighandlers();
    }
}

x_options(side)
Side *side;
{
    int n = side->reqvalue2;
    char opt;

    if ((opt = grok_char(side)) != '\0') {
	switch (opt) {
	case '?':
	    notify(side, "Change (D)isplay Mode, (G)raph, Win (H)eight,");
	    notify(side, "(I)nverse Video, (M)onochrome, (N)otice Buffer");
	    notify(side, "(R)obot, Win (W)idth");
	    break;
	case 'd':
	    remap = TRUE;
	    side->showmode = (side->showmode + 1) % 4;
	    break;
	case 'g':
	    reinfo = TRUE;
	    side->graphical = !side->graphical;
	    break;
	case 'h':
	    if (n < 5 || n > world.height) {
		cmd_error(side, "Bad height %d!", n);
	    } else {
		if (n != side->vh) reconfig = TRUE;
		side->vh = n;
	    }
	    break;
	case 'i':
	    if (side->monochrome) {
		reconfig = TRUE;
		side->bonw = !side->bonw;
	    } else {
		cmd_error(side, "Inverse video is only for monochrome!");
	    }
	    break;
	case 'm':
	    reconfig = TRUE;
	    side->monochrome = !side->monochrome;
	    side->bonw = FALSE;
	    break;
	case 'n':
	    if (n < 1 || n > MAXNOTES) {
		cmd_error(side, "Bad number of notes %d!", n);
	    } else {
		if (n != side->nh) reconfig = TRUE;
		side->nh = n;
	    }
	    break;
	case 'r':	
	    if (side->mode == MOVE) {
		ask_bool(side,
			 "Do you really want to become a machine?", FALSE);
		request_input(side, NULL, x_options_2);
		return;
	    } else {
		cmd_error(side, "Must be in move mode!");
	    }
	    break;
	case 'w':
	    if (n < 5 || n > world.width || n > BUFSIZE) {
		cmd_error(side, "Bad width %d!", n);
	    } else {
		if (n != side->vw) reconfig = TRUE;
		side->vw = n;
	    }
	    break;
	default:
	    cmd_error(side, "unrecognized option '%c'", opt);
	    break;
	}
	if (remap) {
	    undraw_box(side);
	    show_map(side);
	}
	if (reinfo) show_info(side);
	if (reconfig) reconfigure_display(side);
    } else {
	request_input(side, NULL, x_options);
    }
}

/* The command proper. */

do_options(side, n)
Side *side;
int n;
{
    reinfo = remap = reconfig = FALSE;
    ask_char(side, "Options:", "dghimnrw");
    request_input(side, NULL, x_options);
    side->reqvalue2 = n;
}

/* Set standing orders for a unit of a given type that enters a given city. */
/* Space for standing orders is dynamically allocated the first time we */
/* request some orders. */

x_standing_1(side)
Side *side;
{
    int type;

    if ((type = grok_unit_type(side)) >= 0) {
	if (type != NOTHING) get_standing_order(side, type);
    } else {
	request_input(side, side->requnit, x_standing_1);
    } 
}

/* The command proper starts the ball rolling by prompting for the type */
/* of unit that will get standing orders.  Of course, if a unit is not of */
/* a type that has occupants, standing orders are pretty useless.  Also, */
/* if only one type of occupant is possible, then no need to ask. */

do_standing(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    int u;

    u = ask_unit_type(side, "Type of occupant to get standing orders",
		      utypes[unit->type].capacity);
    if (u < 0) {
	show_standing_orders(side, unit);
	request_input(side, unit, x_standing_1);
	side->sounit = unit;
    } else if (u == NOTHING) {
	cmd_error(side, "This unit never has occupants to give orders to!");
    } else {
	show_standing_orders(side, unit);
	get_standing_order(side, u);
    }
}

/* A standing order is acquired by snarfing the next order and saving it */
/* rather than applying it to some unit. */

get_standing_order(side, type)
Side *side;
int type;
{
    if (side->requnit->standing == NULL) {
	side->requnit->standing =
	    (StandingOrder *) malloc(sizeof(StandingOrder));
    }
    side->teach = TRUE;
    side->soutype = type;
    side->tmporder = (Order *) malloc(sizeof(Order));
    notify(side, "Next input order will become the standing order.");
    show_timemode(side);
    request_command(side);
}

/* Survey mode allows player to look around (and change things) by moving */
/* cursor.  The same command toggles in and out, so need a case statement. */
/* Players waiting their turn will be in survey mode, but can't get out. */

do_survey_mode(side, n)
Side *side;
int n;
{
    switch (side->mode) {
    case MOVE:
	survey_mode(side);
	break;
    case SURVEY:
	if (side == curside) {
	    move_mode(side);
	} else {
	    cmd_error(side, "Not your turn yet!");
	}
	break;
    default:
	case_panic("mode", side->mode);
    }
}

/* Change what a unit is producing. */

do_product(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    if (!global.setproduct) {
	cmd_error(side, "No construction changes allowed in this game!");
    } else {
	if (!can_produce(unit)) {
	    cmd_error(side, "This unit can't build anything!");
	} else {
	    if (!utypes[unit->type].maker) {
		wake_unit(unit, FALSE);
	    }
	    request_new_product(unit);
	}
    }
}

/* Set a unit to not produce anything (yes, this really is useful). */

do_idle(side, unit, n)
Side *side;
Unit *unit;
int n;
{
    if (!global.setproduct) {
	cmd_error(side, "No production changes allowed in this scenario!");
    } else {
	set_product(unit, NOTHING);
	unit->schedule = n;
	show_info(side);
    }
}

/* Send a short (1 line) message to another player.  Some messages are */
/* recognized specially, causing various actions. */

x_message(side)
Side *side;
{
    char *msg;
    Side *side3;

    if ((msg = grok_string(side)) != NULL) {
	if (side->reqoside == NULL) {
	    if (msg != NULL && strlen(msg) > 0) {
		notify_all("The %s announce: %s",
			   plural_form(side->name), msg);
	    }
	} else if (strcmp(msg, "briefing") == 0) {
	    notify(side->reqoside, "Receiving a briefing from the %s...",
		   plural_form(side->name));
	    reveal_side(side, side->reqoside, 100);
	    notify(side, "You just briefed the %s on your position.",
		   plural_form(side->reqoside->name));
	} else if (strcmp(msg, "alliance") == 0) {
	    notify(side, "You propose a formal alliance with the %s.",
		   plural_form(side->reqoside->name));
	    side->attitude[side_number(side->reqoside)] = ALLY;
	    if (side->reqoside->attitude[side_number(side)] >= ALLY) {
		declare_alliance(side, side->reqoside);
		for_all_sides(side3) redraw(side3);
	    } else {
		notify(side->reqoside, "The %s propose a formal alliance.",
		       plural_form(side->name));
	    }
	} else if (strcmp(msg, "neutral") == 0) {
	    notify(side, "You propose neutrality with the %s.",
		   plural_form(side->reqoside->name));
	    side->attitude[side_number(side->reqoside)] = NEUTRAL;
	    if (side->reqoside->attitude[side_number(side)] == NEUTRAL) {
		declare_neutrality(side, side->reqoside);
		for_all_sides(side3) redraw(side3);
	    } else {
		notify(side->reqoside, "The %s propose neutrality.",
		       plural_form(side->name));
	    }
	} else if (strcmp(msg, "war") == 0) {
	    notify(side, "You declare war on the %s!",
		   plural_form(side->reqoside->name));
	    declare_war(side, side->reqoside);
	    for_all_sides(side3) redraw(side3);
	} else if (strlen(msg) > 0) {
	    notify(side->reqoside, "The %s say to you: %s",
		   plural_form(side->name), msg);
	} else {
	    notify(side, "You keep your mouth shut.");
	}
    } else {
	request_input(side, NULL, x_message);
    }
}

/* The command proper. */

do_message(side, n)
Side *side;
int n;
{
    char prompt[BUFSIZE];
    Side *side2;

    side2 = side_n(n);
    side->reqoside = side2;
    if (side != side2) {
	if (side2) {
	    sprintf(prompt, "Say to the %s: ", plural_form(side2->name));
	} else {
	    sprintf(prompt, "Broadcast: ");
	}
	ask_string(side, prompt, NULL);
	request_input(side, NULL, x_message);
    } else {
	cmd_error(side, "You mumble to yourself.");
    }
}

/* Add a new player to the game. */
/* Should use arg to decide whether to convert machine player (or just */
/* use if available?)  Also needs to decide if new player is human and */
/* which host to open, then go through side's startup seq and open disp. */
/* Issues of cached values (?) and war/alliance setup and uses of numsides. */

do_add_player(side, n)
Side *side;
int n;
{
    notify(side, "Sorry, can't add new players yet!");
}

/* Command to display the program version.  Looks wired in, but of course */
/* this is not something that we want to be easily changeable! */
/* This will also show data about other sides. */

do_version(side, n)
Side *side;
int n;
{
   notify(side, " ");
   notify(side,
	  "XCONQ version %s", version);
   notify(side,
	  "(c) Copyright 1987, 1988  Stanley T. Shebs, University of Utah");
   notify(side, " ");
   if (Debug || Build) reveal_side(NULL, side, 100);
}

/* Create any unit anywhere.  It gets the usual initial supply, and its */
/* current side is also its true side (i.e. it will never revolt). */

x_unit(side)
Side *side;
{
    int u;
    Unit *unit;

    if ((u = grok_unit_type(side)) >= 0) {
	if (u != NOTHING) {
	    unit = create_unit(u, NULL);
	    occupy_hex(unit, side->curx, side->cury);
	    init_supply(unit);
	    unit_changes_side(unit, side->reqoside, -1, -1);
	    unit->trueside = unit->side;
	    make_current(side, unit);
	    all_see_hex(side->curx, side->cury);
	}
    } else {
	ask_unit_type(side, "Type of unit to create?", NULL);
	request_input(side, NULL, x_unit);
    }
}

/* The command function proper, which only works in Build mode. */

do_unit(side, n)
Side *side;
int n;
{
    if (Build) {
	if (unit_at(side->curx, side->cury) == NULL) {
	    ask_unit_type(side, "Type of unit to create?", NULL);
	    side->reqoside = side_n(n);
	    request_input(side, NULL, x_unit);
	} else {
	    cmd_error(side, "Unit already here!");
	}
    } else {
	cmd_error(side, "Not building a mapfile!");
    }
}

/* Terrain editing alters a hexagonal area of given radius.  If only one */
/* hex changed (the default), just update that alone; otherwise, go ahead */
/* and redraw everything. */

/* The command itself just sets up what will be drawn. */

do_terrain(side, terr, n)
Side *side;
int terr, n;
{
    tmpterr = terr;
    tmpdist = min(abs(n), world.width);
    tmparea = (n >= 0);
    notify(side, "Will now paint %d hex %s of %s.",
	   tmpdist, (tmparea ? "radius areas" : "bars"), ttypes[tmpterr].name);
}

/* Function to change just one hex and to echo that change. */
/* Don't need to make it show instantly, can wait. */

set_one_hex(x, y)
int x, y;
{
    set_terrain_at(x, y, tmpterr);
    see_exact(tmpside, x, y);
    draw_hex(tmpside, x, y, FALSE);
}

/* Painting operation is activated by the "sit" command. */

paint_terrain(side)
Side *side;
{
    int i;

    tmpside = side;
    if (tmparea) {
	apply_to_area(side->curx, side->cury, tmpdist, set_one_hex);
    } else {
	for (i = 0; i < tmpdist; ++i)
	    set_one_hex(wrap(side->curx + i), side->cury);
    }
}

/* Generic command error routine - beeps display etc. */

/*VARARGS*/
cmd_error(side, control, a1, a2, a3, a4, a5, a6)
Side *side;
char *control, *a1, *a2, *a3, *a4, *a5, *a6;
{
    notify(side, control, a1, a2, a3, a4, a5, a6);
    if (active_display(side)) beep(side);
}