empire sources (part 2 of 6)

Charles Simmons chuck at amdahl.uts.amdahl.com
Mon Apr 11 10:59:48 AEST 1988



# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# compmove.c edit.c empire.c

echo x - compmove.c
sed -e 's/^X//' > "compmove.c" << '//E*O*F compmove.c//'
X/* %W% %G% %U% - (c) Copyright 1987, 1988 Chuck Simmons */
X
X/*
X *    Copyright (C) 1987, 1988 Chuck Simmons
X * 
X * See the file COPYING, distributed with empire, for restriction
X * and warranty information.
X */
X
X/*
Xcompmove.c -- Make a move for the computer. 
X
XFor each move the user wants us to make, we do the following:
X
X    1)  Handle city production;
X    2)  Move computer's pieces;
X    3)  Check to see if the game is over.
X*/
X
X#ifdef SYSV
X#include <string.h>
X#else
X#include <strings.h>
X#endif
X
X#include <curses.h>
X#include "empire.h"
X#include "extern.h"
X
Xstatic view_map_t emap[MAP_SIZE]; /* pruned explore map */
X
Xvoid
Xcomp_move (nmoves) 
Xint nmoves;
X{
X	void do_cities(), do_pieces(), check_endgame();
X
X	int i;
X	piece_info_t *obj;
X
X	/* Update our view of the world. */
X	
X	for (i = 0; i < NUM_OBJECTS; i++)
X	for (obj = comp_obj[i]; obj != NULL; obj = obj->piece_link.next)
X		scan (comp_map, obj->loc); /* refresh comp's view of world */
X
X	for (i = 1; i <= nmoves; i++) { /* for each move we get... */
X		comment ("Thinking...");
X
X		(void) memcpy (emap, comp_map, MAP_SIZE * sizeof (view_map_t));
X		vmap_prune_explore_locs (emap);
X	
X		do_cities (); /* handle city production */
X		do_pieces (); /* move pieces */
X		
X		if (save_movie) save_movie_screen ();
X		check_endgame (); /* see if game is over */
X
X		topini ();
X		(void) refresh ();
X	}
X}
X
X/*
XHandle city production.  First, we set production for new cities.
XThen we produce new pieces.  After producing a piece, we will see
Xif we should change our production.
X
XOur goals for city production are first, not to change production
Xwhile something is in the process of being built.  Second, we attempt
Xto have enough city producing armies on a continent to counter any
Xthreat on the continent, and to adequately explore and control the
Xcontinent.  Third, we attempt to always have at least one transport
Xproducer.  Fourth, we attempt to maintain a good ratio between the
Xnumber of producers we have of each type of piece.  Fifth, we never
Xbuild carriers, as we don't have a good strategy for moving these.
X*/
X
Xvoid
Xdo_cities () {
X	void comp_prod();
X	
X	int i;
X	int is_lake;
X
X	for (i = 0; i < NUM_CITY; i++) /* new production */
X	if (city[i].owner == COMP) {
X		scan (comp_map, city[i].loc);
X
X		if (city[i].prod == NOPIECE)
X			comp_prod (&city[i], lake (city[i].loc));
X	}
X	for (i = 0; i < NUM_CITY; i++) /* produce and change */
X	if (city[i].owner == COMP) {
X		is_lake = lake (city[i].loc);
X		if (city[i].work++ >= (long)piece_attr[city[i].prod].build_time) {
X			produce (&city[i]);
X			comp_prod (&city[i], is_lake);
X		}
X		/* don't produce ships in lakes */
X		else if (city[i].prod > FIGHTER && city[i].prod != SATELLITE && is_lake)
X			comp_prod (&city[i], is_lake);
X	}
X}
X			
X/*
XDefine ratios for numbers of cities we want producing each object.
X
XEarly in the game, we want to produce armies and transports for
Xrapid expansion.  After a while, we add fighters and pt boats
Xfor exploration.  Later, we add ships of all kinds for control of
Xthe sea.
X*/
X                                 /* A    F    P    S    D    T    C    B   Z*/
Xstatic int ratio1[NUM_OBJECTS] = { 60,   0,  10,   0,   0,  20,   0,   0,  0};
Xstatic int ratio2[NUM_OBJECTS] = { 90,  10,  10,  10,  10,  40,   0,   0,  0};
Xstatic int ratio3[NUM_OBJECTS] = {120,  20,  20,  10,  10,  60,  10,  10,  0};
Xstatic int ratio4[NUM_OBJECTS] = {150,  30,  30,  20,  20,  70,  10,  10,  0};
Xstatic int *ratio;
X
X/*
XSet city production if necessary.
X
XThe algorithm below contains three parts:
X
X1)  Defend continents we own.
X
X2)  Produce a TT and a Satellite.
X
X3)  Meet the ratio requirements given above.
X*/
X
Xvoid
Xcomp_prod (cityp, is_lake)
Xcity_info_t *cityp;
Xint is_lake;
X{
X	void comp_set_prod(), comp_set_needed();
X	
X	int city_count[NUM_OBJECTS]; /* # of cities producing each piece */
X	int cont_map[MAP_SIZE];
X	int total_cities;
X	long i;
X	int comp_ac;
X	city_info_t *p;
X	int need_count, interest;
X	scan_counts_t counts;
X
X	/* Make sure we have army producers for current continent. */
X	
X	/* map out city's continent */
X	vmap_cont (cont_map, comp_map, cityp->loc, '.');
X
X	/* count items of interest on the continent */
X	counts = vmap_cont_scan (cont_map, comp_map);
X	comp_ac = 0; /* no army producing computer cities */
X	
X	for (i = 0; i < MAP_SIZE; i++)
X	if (cont_map[i]) { /* for each cell of continent */
X		if (comp_map[i].contents == 'X') {
X			p = find_city (i);
X			ASSERT (p != NULL && p->owner == COMP);
X			if (p->prod == ARMY) comp_ac += 1;
X		}
X	}
X	/* see if anything of interest is on continent */
X	interest = (counts.unexplored || counts.user_cities
X		 || counts.user_objects[ARMY]
X		 || counts.unowned_cities);
X	
X	/* we want one more army producer than enemy has cities */
X	/* and one more if anything of interest on cont */
X	need_count = counts.user_cities - comp_ac + interest;
X	if (counts.user_cities) need_count += 1;
X	
X	if (need_count > 0) { /* need an army producer? */
X		comp_set_prod (cityp, ARMY);
X		return;
X	}
X	
X	/* Produce armies in new cities if there is a city to attack. */
X	if (counts.user_cities && cityp->prod == NOPIECE) {
X		comp_set_prod (cityp, ARMY);
X		return;
X	}
X
X	/* Produce a TT and SAT if we don't have one. */
X	
X	/* count # of cities producing each piece */
X	for (i = 0; i < NUM_OBJECTS; i++)
X		city_count[i] = 0;
X		
X	total_cities = 0;
X		
X	for (i = 0; i < NUM_CITY; i++)
X	if (city[i].owner == COMP && city[i].prod != NOPIECE) {
X		city_count[city[i].prod] += 1;
X		total_cities += 1;
X	}
X	if (total_cities <= 10) ratio = ratio1;
X	else if (total_cities <= 20) ratio = ratio2;
X	else if (total_cities <= 30) ratio = ratio3;
X	else ratio = ratio4;
X		
X	/* if we have one army producer, and this is it, return */
X	if (city_count[ARMY] == 1 && cityp->prod == ARMY) return;
X	
X	/* first available non-lake becomes a tt producer */
X	if (city_count[TRANSPORT] == 0) {
X		if (!is_lake) {
X			comp_set_prod (cityp, TRANSPORT);
X			return;
X		}
X		/* if we have one army producer that is not on a lake, */
X		/* produce armies here instead */
X		if (city_count[ARMY] == 1) {
X			for (i = 0; i < NUM_CITY; i++)
X			if (city[i].owner == COMP && city[i].prod == ARMY) break;
X		
X			if (!lake (city[i].loc)) {
X				comp_set_prod (cityp, ARMY);
X				return;
X			}
X		}
X	}
X#if 0
X	/* Now we need a SATELLITE. */
X	if (cityp->prod == NOPIECE && city_count[SATELLITE] == 0) {
X		comp_set_prod (cityp, SATELLITE);
X		return;
X	}
X	if (cityp->prod == SATELLITE) return;
X	/* "The satellites are out tonight." -- Lori Anderson */
X#endif
X	/* don't change prod from armies if something on continent */
X	if (cityp->prod == ARMY && interest) return;
X			
X	/* Produce armies in new cities if there is a city to attack. */
X	if (counts.unowned_cities && cityp->prod == NOPIECE) {
X		comp_set_prod (cityp, ARMY);
X		return;
X	}
X
X	/* Set production to item most needed.  Continents with one
X	city and nothing interesting may not produce armies.  We
X	set production for unset cities, and change production for
X	cities that produce objects for which we have many city producers.
X	Ship producers on lakes also get there production changed. */
X	
X	interest = (counts.comp_cities != 1 || interest);
X	
X	if (cityp->prod == NOPIECE
X	    || cityp->prod == ARMY && counts.comp_cities == 1
X	    || overproduced (cityp, city_count)
X	    || cityp->prod > FIGHTER && is_lake)
X		comp_set_needed (cityp, city_count, interest, is_lake);
X}
X	
X/*
XSet production for a computer city to a given type.  Don't
Xreset production if it is already correct.
X*/
X
Xvoid
Xcomp_set_prod (cityp, type)
Xcity_info_t *cityp;
Xint type;
X{
X	if (cityp->prod == type) return;
X	
X	pdebug ("Changing city prod at %d from %d to %d\n",
X		cityp->loc, cityp->prod, type);
X	
X	cityp->prod = type;
X	cityp->work = -(piece_attr[type].build_time / 5);
X}
X
X/*
XSee if a city is producing an object which is being overproduced.
X*/
X
Xint
Xoverproduced (cityp, city_count)
Xcity_info_t *cityp;
Xint *city_count;
X{
X	int i;
X
X	for (i = 0; i < NUM_OBJECTS; i++) {
X		/* return true if changing production would improve balance */
X		if (i != cityp->prod
X		 && ((city_count[cityp->prod] - 1) * ratio[i]
X		   > (city_count[i] + 1) * ratio[cityp->prod]))
X  		return (TRUE);
X	}
X	return (FALSE);
X}
X
X/*
XSee if one type of production is needed more than another type.
XReturn the most-needed type of production.
X*/
X
Xint
Xneed_more (city_count, prod1, prod2)
Xint *city_count;
Xint prod1, prod2;
X{
X	if (city_count[prod1] * ratio[prod2]
X		 <= city_count[prod2] * ratio[prod1])
X	return (prod1);
X
X	else return (prod2);
X}
X
X/*
XFigure out the most needed type of production.  We are passed
Xa flag telling us if armies are ok to produce.
X*/
X
Xvoid
Xcomp_set_needed (cityp, city_count, army_ok, is_lake)
Xcity_info_t *cityp;
Xint *city_count;
Xint army_ok;
Xint is_lake;
X{
X	int best_prod;
X	int prod;
X
X	if (!army_ok) city_count[ARMY] = INFINITY;
X
X	if (is_lake) { /* choose fighter or army */
X		comp_set_prod (cityp, need_more (city_count, ARMY, FIGHTER));
X		return;
X	}
X	/* don't choose fighter */
X	city_count[FIGHTER] = INFINITY;
X	
X	best_prod = ARMY; /* default */
X	for (prod = 0; prod < NUM_OBJECTS; prod++) {
X		best_prod = need_more (city_count, best_prod, prod);
X	}
X	comp_set_prod (cityp, best_prod);
X}
X
X/*
XSee if a city is on a lake.  We define a lake to be a body of
Xwater (where cities are considered to be water) that does not
Xtouch either an attackable city or unexplored territory.
X
XBe careful, because we use the 'emap'.  This predicts whether
Xunexplored territory will be land or water.  The prediction should
Xbe helpful, because small bodies of water that enclose unexplored
Xterritory will appear as solid water.  Big bodies of water should
Xhave unexplored territory on the edges.
X*/
X
Xint
Xlake (loc)
Xlong loc;
X{
X	int cont_map[MAP_SIZE];
X	scan_counts_t counts;
X
X	vmap_cont (cont_map, emap, loc, '+'); /* map lake */
X	counts = vmap_cont_scan (cont_map, emap);
X
X	return !(counts.unowned_cities || counts.user_cities || counts.unexplored);
X}
X
X/*
XMove all computer pieces.
X*/
X
Xstatic view_map_t amap[MAP_SIZE]; /* temp view map */
Xstatic path_map_t path_map[MAP_SIZE];
X
Xvoid
Xdo_pieces () { /* move pieces */
X	void cpiece_move();
X
X	int i;
X	piece_info_t *obj, *next_obj;
X
X	for (i = 0; i < NUM_OBJECTS; i++) { /* loop through obj lists */
X		for (obj = comp_obj[move_order[i]]; obj != NULL;
X		    obj = next_obj) { /* loop through objs in list */
X			next_obj = obj->piece_link.next;
X			cpiece_move (obj); /* yup; move the object */
X		}
X	}
X}
X
X/*
XMove a piece.  We loop until all the moves of a piece are made.  Within
Xthe loop, we find a direction to move that will take us closer to an
Xobjective.
X*/
X
Xvoid
Xcpiece_move (obj)
Xpiece_info_t *obj;
X{
X	void move1();
X
X	int changed_loc;
X	int max_hits;
X	long saved_loc;
X	city_info_t *cityp;
X
X	if (obj->type == SATELLITE) {
X		move_sat (obj);
X		return;
X	}
X	
X	obj->moved = 0; /* not moved yet */
X	changed_loc = FALSE; /* not changed yet */
X	max_hits = piece_attr[obj->type].max_hits;
X
X	if (obj->type == FIGHTER) { /* init fighter range */
X		cityp = find_city (obj->loc);
X		if (cityp != NULL) obj->range = piece_attr[FIGHTER].range;
X	}
X	
X	while (obj->moved < obj_moves (obj)) {
X		saved_loc = obj->loc; /* remember starting location */
X		move1 (obj);
X		if (saved_loc != obj->loc) changed_loc = TRUE;
X		
X		if (obj->type == FIGHTER && obj->hits > 0) {
X			if (comp_map[obj->loc].contents == 'X')
X				obj->moved = piece_attr[FIGHTER].speed;
X			else if (obj->range == 0) {
X				pdebug ("Fighter at %d crashed and burned\n", obj->loc);
X				kill_obj (obj, obj->loc); /* crash & burn */
X			}
X		}
X	}
X	/* if a boat is in port, damaged, and never moved, fix some damage */
X	if (obj->hits > 0 /* live piece? */
X		&& !changed_loc /* object never changed location? */
X		&& obj->type != ARMY && obj->type != FIGHTER /* it is a boat? */
X		&& obj->hits != max_hits /* it is damaged? */
X		&& comp_map[obj->loc].contents == 'X') /* it is in port? */
X	obj->hits++; /* fix some damage */
X}
X
X/*
XMove a piece one square.
X*/
X
Xvoid
Xmove1 (obj)
Xpiece_info_t *obj;
X{
X	void army_move(), transport_move(), fighter_move(), ship_move();
X
X	switch (obj->type) {
X	case ARMY: army_move (obj); break;
X	case TRANSPORT: transport_move (obj); break;
X	case FIGHTER: fighter_move (obj); break;
X	default: ship_move (obj); break;
X	}
X}
X
X/*
XMove an army.
X
XThis is a multi-step algorithm:
X
X1)  See if there is an object we can attack immediately.
XIf so, attack it.
X
X2)  Look for the nearest land objective.
X
X3)  If we find an objective reachable by land, figure out
Xhow far away that objective is.  Based on the found objective,
Xalso figure out how close a loadable tt must be to be of
Xinterest.  If the objective is closer than the tt must be,
Xhead towards the objective.
X
X4)  Otherwise, look for the nearest loading tt (or tt producing
Xcity).  If the nearest loading tt is farther than our land objective,
Xhead towards the land objective.
X
X5)  Otherwise, head for the tt.
X
X6)  If we still have no destination and we are in a city,
Xattempt to leave the city.
X
X7)  Once we have a destination, find the best move toward that
Xdestination.  (If there is no destination, sit around and wait.)
X*/
X
Xvoid
Xarmy_move (obj)
Xpiece_info_t *obj;
X{
X	long move_away();
X	void move_objective();
X	long find_attack();
X	void make_army_load_map(), make_unload_map(), make_tt_load_map();
X	void board_ship();
X	
X	long new_loc;
X	path_map_t path_map2[MAP_SIZE];
X	long new_loc2;
X	int cross_cost; /* cost to enter water */
X	
X	obj->func = 0; /* army doesn't want a tt */
X	if (vmap_at_sea (comp_map, obj->loc)) { /* army can't move? */
X		(void) load_army (obj);
X		obj->moved = piece_attr[ARMY].speed;
X		if (!obj->ship) obj->func = 1; /* load army on ship */
X		return;
X	}
X	if (obj->ship) /* is army on a transport? */
X		new_loc = find_attack (obj->loc, army_attack, "+*");
X	else new_loc = find_attack (obj->loc, army_attack, ".+*");
X		
X	if (new_loc != obj->loc) { /* something to attack? */
X		attack (obj, new_loc); /* attack it */
X		if (map[new_loc].contents == '.' /* moved to ocean? */
X		  && obj->hits > 0) { /* object still alive? */
X			kill_obj (obj, new_loc);
X			scan (user_map, new_loc); /* rescan for user */
X		}
X		return;
X	}
X	if (obj->ship) {
X		if (obj->ship->func == 0) {
X			if (!load_army (obj)) ABORT; /* load army on best ship */
X			return; /* armies stay on a loading ship */
X		}
X		make_unload_map (amap, comp_map);
X		new_loc = vmap_find_wlobj (path_map, amap, obj->loc, &tt_unload);
X		move_objective (obj, path_map, new_loc, " ");
X		return;
X	}
X
X	new_loc = vmap_find_lobj (path_map, comp_map, obj->loc, &army_fight);
X	
X	if (new_loc != obj->loc) { /* something interesting on land? */
X		switch (comp_map[new_loc].contents) {
X		case 'A':
X		case 'O':
X			cross_cost = 60; /* high cost if enemy present */
X			break;
X		case '*':
X			cross_cost = 30; /* medium cost for attackable city */
X			break;
X		case ' ':
X			cross_cost = 14; /* low cost for exploring */
X			break;
X		default:
X			ABORT;
X		}
X		cross_cost = path_map[new_loc].cost * 2 - cross_cost;
X	}
X	else cross_cost = INFINITY;
X	
X	if (new_loc == obj->loc || cross_cost > 0) {
X		/* see if there is something interesting to load */
X		make_army_load_map (obj, amap, comp_map);
X		new_loc2 = vmap_find_lwobj (path_map2, amap, obj->loc, &army_load, cross_cost);
X		
X		if (new_loc2 != obj->loc) { /* found something? */
X			board_ship (obj, path_map2, new_loc2);
X			return;
X		}
X	}
X
X	move_objective (obj, path_map, new_loc, " ");
X}
X
X/*
XRemove pruned explore locs from a view map.
X*/
X
Xvoid
Xunmark_explore_locs (xmap)
Xview_map_t *xmap;
X{
X	long i;
X
X	for (i = 0; i < MAP_SIZE; i++)
X	if (map[i].on_board && xmap[i].contents == ' ')
X		xmap[i].contents = emap[i].contents;
X}
X
X/*
XMake a load map.  We copy the view map and mark each loading
Xtransport and tt producing city with a '$'.
X*/
X
Xvoid
Xmake_army_load_map (obj, xmap, vmap)
Xpiece_info_t *obj;
Xview_map_t *xmap;
Xview_map_t *vmap;
X{
X	piece_info_t *p;
X	int i;
X	
X	(void) memcpy (xmap, vmap, sizeof (view_map_t) * MAP_SIZE);
X
X	/* mark loading transports or cities building transports */
X	for (p = comp_obj[TRANSPORT]; p; p = p->piece_link.next)
X	if (p->func == 0) /* loading tt? */
X	xmap[p->loc].contents = '$';
X	
X	for (i = 0; i < NUM_CITY; i++)
X	if (city[i].owner == COMP && city[i].prod == TRANSPORT) {
X		if (nearby_load (obj, city[i].loc))
X			xmap[city[i].loc].contents = 'x'; /* army is nearby so it can load */
X		else if (nearby_count (city[i].loc) < piece_attr[TRANSPORT].capacity)
X			xmap[city[i].loc].contents = 'x'; /* city needs armies */
X	}
X	
X	if (print_vmap == 'A') print_xzoom (xmap);
X}
X
X/* Return true if an army is considered near a location for loading. */
X
Xint
Xnearby_load (obj, loc)
Xpiece_info_t *obj;
Xlong loc;
X{
X	return obj->func == 1 && dist (obj->loc, loc) <= 2;
X}
X	
X/* Return number of nearby armies. */
X
Xint
Xnearby_count (loc)
Xlong loc;
X{
X	piece_info_t *obj;
X	int count;
X
X	count = 0;
X	for (obj = comp_obj[ARMY]; obj; obj = obj->piece_link.next) {
X		if (nearby_load (obj, loc)) count += 1;
X	}
X	return count;
X}
X
X/* Make load map for a ship. */
X
Xvoid
Xmake_tt_load_map (xmap, vmap)
Xview_map_t *xmap;
Xview_map_t *vmap;
X{
X	piece_info_t *p;
X	
X	(void) memcpy (xmap, vmap, sizeof (view_map_t) * MAP_SIZE);
X
X	/* mark loading armies */
X	for (p = comp_obj[ARMY]; p; p = p->piece_link.next)
X	if (p->func == 1) /* loading army? */
X	xmap[p->loc].contents = '$';
X	
X	if (print_vmap == 'L') print_xzoom (xmap);
X}
X	
X/*
XMake an unload map.  We copy the view map.  We then create
Xa continent map.  For each of our cities, we mark out the continent
Xthat city is on.  Then, for each city that we don't own and which
Xdoesn't appear on our continent map, we set that square to a digit.
X
XWe want to assign weights to each attackable city.
XCities are more valuable if they are on a continent which
Xhas lots of cities.  Cities are also valuable if either it
Xwill be easy for us to take over the continent, or if we
Xneed to defend that continent from an enemy.
X
XTo implement the above, we assign numbers to each city as follows:
X
Xa)  if unowned_cities > user_cities && comp_cities == 0
X       set number to min (total_cities, 9)
X
Xb)  if comp_cities != 0 && user_cities != 0
X       set number to min (total_cities, 9)
X       
Xb)  if enemy_cities == 1 && total_cities == 1, set number to 2.
X    (( taking the sole enemy city on a continent is as good as
X       getting a two city continent ))
X       
Xc)  Any other attackable city is marked with a '0'.
X*/
X
Xstatic int owncont_map[MAP_SIZE];
Xstatic int tcont_map[MAP_SIZE];
X
Xvoid
Xmake_unload_map (xmap, vmap)
Xview_map_t *xmap;
Xview_map_t *vmap;
X{
X	long i;
X	scan_counts_t counts;
X
X	(void) memcpy (xmap, vmap, sizeof (view_map_t) * MAP_SIZE);
X	unmark_explore_locs (xmap);
X	
X	for (i = 0; i < MAP_SIZE; i++)
X		owncont_map[i] = 0; /* nothing marked */
X
X	for (i = 0; i < NUM_CITY; i++)
X	if (city[i].owner == COMP)
X	vmap_mark_up_cont (owncont_map, xmap, city[i].loc, '.');
X
X	for (i = 0; i < MAP_SIZE; i++)
X	if (strchr ("O*", vmap[i].contents)) {
X		int total_cities;
X		
X		vmap_cont (tcont_map, xmap, i, '.'); /* map continent */
X		counts = vmap_cont_scan (tcont_map, xmap);
X		
X		total_cities = counts.unowned_cities
X			     + counts.user_cities
X			     + counts.comp_cities;
X			     
X		if (total_cities > 9) total_cities = 0;
X		
X		if (counts.user_cities && counts.comp_cities)
X			xmap[i].contents = '0' + total_cities;
X
X		else if (counts.unowned_cities > counts.user_cities
X			 && counts.comp_cities == 0)
X			xmap[i].contents = '0' + total_cities;
X
X		else if (counts.user_cities == 1 && counts.comp_cities == 0)
X			xmap[i].contents = '2';
X			
X		else xmap[i].contents = '0';
X	}
X	if (print_vmap == 'U') print_xzoom (xmap);
X}
X
X/*
XLoad an army onto a ship.  First look for an adjacent ship.
XIf that doesn't work, move to the objective, trying to be
Xclose to the ocean.
X*/
X
Xvoid
Xboard_ship (obj, pmap, dest)
Xpiece_info_t *obj;
Xpath_map_t *pmap;
Xlong dest;
X{
X	if (!load_army (obj)) {
X		obj->func = 1; /* loading */
X		move_objective (obj, pmap, dest, "t.");
X	}
X}
X
X/*
XLook for the most full, non-full transport at a location.
XPrefer switching to staying.  If we switch, we force
Xone of the ships to become more full.
X*/
X
Xpiece_info_t *
Xfind_best_tt (best, loc)
Xpiece_info_t *best;
Xlong loc;
X{
X	piece_info_t *p;
X
X	for (p = map[loc].objp; p != NULL; p = p->loc_link.next)
X	if (p->type == TRANSPORT && obj_capacity (p) > p->count) {
X		if (!best) best = p;
X		else if (p->count >= best->count) best = p;
X	}
X	return best;
X}
X
X/*
XLoad an army onto the most full non-full ship.
X*/
X
Xint
Xload_army (obj)
Xpiece_info_t *obj;
X{
X	piece_info_t *p;
X	int i;
X	long x_loc;
X
X	p = find_best_tt (obj->ship, obj->loc); /* look here first */
X
X	for (i = 0; i < 8; i++) { /* try surrounding squares */
X		x_loc = obj->loc + dir_offset[i];
X		if (map[x_loc].on_board)
X			p = find_best_tt (p, x_loc);
X
X	}
X	if (!p) return FALSE; /* no tt to be found */
X
X	if (p->loc == obj->loc) { /* stay in same place */
X		obj->moved = piece_attr[ARMY].speed;
X	}
X	else move_obj (obj, p->loc); /* move to square with ship */
X
X	if (p->ship != obj->ship) { /* reload army to new ship */
X		disembark (obj);
X		embark (p, obj);
X	}
X	return TRUE;
X}
X
X/*
XReturn the first location we find adjacent to the current location of
Xthe correct terrain.
X*/
X
Xlong
Xmove_away (vmap, loc, terrain)
Xview_map_t *vmap;
Xlong loc;
Xchar *terrain;
X{
X	long new_loc;
X	int i;
X
X	for (i = 0; i < 8; i++) {
X		new_loc = loc + dir_offset[i];
X		if (map[new_loc].on_board
X		 && strchr (terrain, vmap[new_loc].contents))
X			return (new_loc);
X	}
X	return (loc);
X}
X
X/*
XLook to see if there is an adjacent object to attack.  We are passed
Xa location and a list of items we attack sorted in order of most
Xvaluable first.  We look at each surrounding on board location.
XIf there is an object we can attack, we return the location of the
Xbest of these.
X*/
X
Xlong
Xfind_attack (loc, obj_list, terrain)
Xlong loc;
Xchar *obj_list;
Xchar *terrain;
X{
X	long new_loc, best_loc;
X	int i, best_val;
X	char *p;
X
X	best_loc = loc; /* nothing found yet */
X	best_val = INFINITY;
X	for (i = 0; i < 8; i++) {
X		new_loc = loc + dir_offset[i];
X
X		if (map[new_loc].on_board /* can we move here? */
X		    && strchr (terrain, map[new_loc].contents)) {
X			p = strchr (obj_list, comp_map[new_loc].contents);
X			if (p != NULL && p - obj_list < best_val) {
X				best_val = p - obj_list;
X				best_loc = new_loc;
X			}
X		}
X	}
X	return (best_loc);
X}
X
X/*
XMove a transport.
X
XThere are two kinds of transports:  loading and unloading.
X
XLoading transports move toward loading armies.  Unloading
Xtransports move toward attackable cities on unowned continents.
X
XAn empty transport is willing to attack adjacent enemy transports.
XTransports become 'loading' when empty, and 'unloading' when full.
X*/
X
Xvoid
Xtransport_move (obj)
Xpiece_info_t *obj;
X{
X	void tt_do_move();
X
X	long new_loc;
X
X	/* empty transports can attack */
X	if (obj->count == 0) { /* empty? */
X		obj->func = 0; /* transport is loading */
X		new_loc = find_attack (obj->loc, tt_attack, ".");
X		if (new_loc != obj->loc) { /* something to attack? */
X			attack (obj, new_loc); /* attack it */
X			return;
X		}
X	}
X
X	if (obj->count == obj_capacity (obj)) /* full? */
X		obj->func = 1; /* unloading */
X
X	if (obj->func == 0) { /* loading? */
X		make_tt_load_map (amap, comp_map);
X		new_loc = vmap_find_wlobj (path_map, amap, obj->loc, &tt_load);
X		
X		if (new_loc == obj->loc) { /* nothing to load? */
X			(void) memcpy (amap, comp_map, MAP_SIZE * sizeof (view_map_t));
X			unmark_explore_locs (amap);
X			if (print_vmap == 'S') print_xzoom (amap);
X			new_loc = vmap_find_wobj (path_map, amap, obj->loc, &tt_explore);
X		}
X		
X		move_objective (obj, path_map, new_loc, "a ");
X	}
X	else {
X		make_unload_map (amap, comp_map);
X		new_loc = vmap_find_wlobj (path_map, amap, obj->loc, &tt_unload);
X		move_objective (obj, path_map, new_loc, " ");
X	}
X}
X
X/*
XMove a fighter.
X
X1)  See if there is an object we can attack immediately.
XIf so, attack it.
X
X2)  Otherwise, if fighter is low on fuel, move toward nearest city
Xif there is one in range.
X
X3)  Otherwise, look for an objective.
X*/
X
Xvoid
Xfighter_move (obj)
Xpiece_info_t *obj;
X{
X	long new_loc;
X
X	new_loc = find_attack (obj->loc, fighter_attack, ".+");
X	if (new_loc != obj->loc) { /* something to attack? */
X		attack (obj, new_loc); /* attack it */
X		return;
X	}
X	/* return to base if low on fuel */
X	if (obj->range <= find_nearest_city (obj->loc, COMP, &new_loc) + 2) {
X		if (new_loc != obj->loc)
X			new_loc = vmap_find_dest (path_map, comp_map, obj->loc,
X						  new_loc, COMP, T_AIR);
X	}
X	else new_loc = obj->loc;
X	
X	if (new_loc == obj->loc) { /* no nearby city? */
X		new_loc = vmap_find_aobj (path_map, comp_map, obj->loc,
X					       &fighter_fight);
X	}
X	move_objective (obj, path_map, new_loc, " ");
X}
X
X/*
XMove a ship.
X
XAttack anything adjacent.  If nothing adjacent, explore or look for
Xsomething to attack.
X*/
X
Xvoid
Xship_move (obj)
Xpiece_info_t *obj;
X{
X	long new_loc;
X	char *adj_list;
X
X	if (obj->hits < piece_attr[obj->type].max_hits) { /* head to port */
X		if (comp_map[obj->loc].contents == 'X') { /* stay in port */
X			obj->moved = piece_attr[obj->type].speed;
X			return;
X		}
X		new_loc = vmap_find_wobj (path_map, comp_map, obj->loc,
X					       &ship_repair);
X		adj_list = ".";
X
X	}
X	else {
X		new_loc = find_attack (obj->loc, ship_attack, ".");
X		if (new_loc != obj->loc) { /* something to attack? */
X			attack (obj, new_loc); /* attack it */
X			return;
X		}
X		/* look for an objective */
X		(void) memcpy (amap, comp_map, MAP_SIZE * sizeof (view_map_t));
X		unmark_explore_locs (amap);
X		if (print_vmap == 'S') print_xzoom (amap);
X		
X		new_loc = vmap_find_wobj (path_map, amap, obj->loc,
X					       &ship_fight);
X		adj_list = ship_fight.objectives;
X	}
X
X	move_objective (obj, path_map, new_loc, adj_list);
X}
X
X/*
XMove to an objective.
X*/
X
Xvoid
Xmove_objective (obj, pathmap, new_loc, adj_list)
Xpiece_info_t *obj;
Xpath_map_t pathmap[];
Xlong new_loc;
Xchar *adj_list;
X{
X	char *terrain;
X	char *attack_list;
X	int d;
X	int reuse; /* true iff we should reuse old map */
X	long old_loc;
X	long old_dest;
X	
X	if (new_loc == obj->loc) {
X		obj->moved = piece_attr[obj->type].speed;
X		obj->range -= 1;
X		pdebug ("No destination found for %d at %d; func=%d\n",
X			obj->type, obj->loc, obj->func);
X		return;
X	}
X	old_loc = obj->loc; /* remember where we are */
X	old_dest = new_loc; /* and where we're going */
X	
X	d = dist (new_loc, obj->loc);
X	reuse = 1; /* try to reuse unless we learn otherwise */
X	
X	if (comp_map[new_loc].contents == ' ' && d == 2) { /* are we exploring? */
X		vmap_mark_adjacent (pathmap, obj->loc);
X		reuse = 0;
X	}
X	else vmap_mark_path (pathmap, comp_map, new_loc); /* find routes to destination */
X	
X	/* path terrain and move terrain may differ */
X	switch (obj->type) {
X	case ARMY: terrain = "+"; break;
X	case FIGHTER: terrain = "+.X"; break;
X	default: terrain = ".X"; break;
X	}
X	
X	new_loc = vmap_find_dir (pathmap, comp_map, obj->loc,
X				 terrain, adj_list);
X	
X	if (new_loc == obj->loc /* path is blocked? */
X	    && (obj->type != ARMY || !obj->ship)) { /* don't unblock armies on a ship */
X		vmap_mark_near_path (pathmap, obj->loc);
X		reuse = 0;
X		new_loc = vmap_find_dir (pathmap, comp_map, obj->loc,
X					 terrain, adj_list);
X	}
X	
X	/* encourage army to leave city */
X	if (new_loc == obj->loc && map[obj->loc].cityp != NULL
X				&& obj->type == ARMY) {
X		new_loc = move_away (comp_map, obj->loc, "+");
X		reuse = 0;
X	}
X	if (new_loc == obj->loc) {
X		obj->moved = piece_attr[obj->type].speed;
X		
X		if (obj->type == ARMY && obj->ship) ;
X		else pdebug ("Cannot move %d at %d toward objective; func=%d\n",
X			     obj->type, obj->loc, obj->func);
X	}
X	else move_obj (obj, new_loc);
X	
X	/* Try to make more moves using same path map. */
X	if (reuse && obj->moved < obj_moves (obj) && obj->loc != old_dest) {
X		/* check for immediate attack */
X		switch (obj->type) {
X		case FIGHTER:
X			if (comp_map[old_dest].contents != 'X' /* watch fuel */
X				&& obj->range <= piece_attr[FIGHTER].range / 2)
X					return;
X			attack_list = fighter_attack;
X			terrain = "+.";
X			break;
X		case ARMY:
X			attack_list = army_attack;
X			if (obj->ship) terrain = "+*";
X			else terrain = "+.*";
X			break;
X		case TRANSPORT:
X			terrain = ".*";
X			if (obj->cargo) attack_list = tt_attack;
X			else attack_list = "*O"; /* causes tt to wake up */
X			break;
X		default:
X			attack_list = ship_attack;
X			terrain = ".";
X			break;
X		}
X		if (find_attack (obj->loc, attack_list, terrain) != obj->loc)
X			return;
X		
X		/* clear old path */
X		pathmap[old_loc].terrain = T_UNKNOWN;
X		for (d = 0; d < 8; d++) {
X			new_loc = old_loc + dir_offset[d];
X			pathmap[new_loc].terrain = T_UNKNOWN;
X		}
X		/* pathmap is already marked, but this should work */
X		move_objective (obj, pathmap, old_dest, adj_list);
X	}
X}
X
X/*
XCheck to see if the game is over.  We count the number of cities
Xowned by each side.  If either side has no cities and no armies, then
Xthe game is over.  If the computer has less than half as many cities
Xand armies as the user, then the computer will give up.
X*/
X
Xvoid
Xcheck_endgame () { /* see if game is over */
X
X	int nuser_city, ncomp_city;
X	int nuser_army, ncomp_army;
X	piece_info_t *p;
X	int i;
X	
X	date += 1; /* one more turn has passed */
X	if (win != 0) return; /* we already know game is over */
X
X	nuser_city = 0; /* nothing counted yet */
X	ncomp_city = 0;
X	nuser_army = 0;
X	ncomp_army = 0;
X	
X	for (i = 0; i < NUM_CITY; i++) {
X		if (city[i].owner == USER) nuser_city++;
X		else if (city[i].owner == COMP) ncomp_city++;
X	}
X	
X	for (p = user_obj[ARMY]; p != NULL; p = p->piece_link.next)
X		nuser_army++;
X	
X	for (p = comp_obj[ARMY]; p != NULL; p = p->piece_link.next)
X		ncomp_army++;
X		
X	if (ncomp_city < nuser_city/3 && ncomp_army < nuser_army/3) {
X		clear_screen ();
X		prompt ("The computer acknowledges defeat. Do");
X		error ("you wish to smash the rest of the enemy? ");
X
X		if (get_chx() !=  'Y') empend ();
X		(void) addstr ("\nThe enemy inadvertantly revealed its code used for");
X		(void) addstr ("\nreceiving battle information. You can display what");
X		(void) addstr ("\nthey've learned with the ''E'' command.");
X		resigned = TRUE;
X		win = 2;
X		automove = FALSE;
X	}
X	else if (ncomp_city == 0 && ncomp_army == 0) {
X		clear_screen ();
X		(void) addstr ("The enemy is incapable of defeating you.\n");
X		(void) addstr ("You are free to rape the empire as you wish.\n");
X	    	(void) addstr ("There may be, however, remnants of the enemy fleet\n");
X	    	(void) addstr ("to be routed out and destroyed.\n");
X		win = 1;
X		automove = FALSE;
X	}
X	else if (nuser_city == 0 && nuser_army == 0) {
X	    	clear_screen ();
X	    	(void) addstr ("You have been rendered incapable of\n");
X	    	(void) addstr ("defeating the rampaging enemy fascists! The\n");
X	    	(void) addstr ("empire is lost. If you have any ships left, you\n");
X	    	(void) addstr ("may attempt to harass enemy shipping.");
X		win = 1;
X		automove = FALSE;
X	}
X}
//E*O*F compmove.c//

echo x - edit.c
sed -e 's/^X//' > "edit.c" << '//E*O*F edit.c//'
X/* %W% %G% %U% - (c) Copyright 1987, 1988 Chuck Simmons */
X
X/*
X *    Copyright (C) 1987, 1988 Chuck Simmons
X * 
X * See the file COPYING, distributed with empire, for restriction
X * and warranty information.
X */
X
X/*
Xedit.c -- Routines to handle edit mode commands.
X*/
X
X#ifdef SYSV
X#include <string.h>
X#else
X#include <strings.h>
X#endif
X
X#include <curses.h>
X#include <ctype.h>
X#include "empire.h"
X#include "extern.h"
X
Xvoid
Xedit(edit_cursor)
Xlong edit_cursor;
X{
X	char e_cursor();
X	void e_leave(), e_print(), e_random();
X	void e_stasis(), e_move(), e_end(), e_wake(), e_sleep();
X	void e_info(), e_prod(), e_help(), e_explore();
X	void e_fill(), e_land(), e_city_func(), e_transport();
X	void e_attack(), e_repair();
X
X	long path_start;
X	int path_type;
X	char e;
X	
X	path_start = -1; /* not building a path yet */
X	
X	for (;;) { /* until user gives command to leave */
X		display_loc_u (edit_cursor); /* position cursor */
X		e = e_cursor (&edit_cursor); /* handle cursor movement */
X
X		switch (e) {
X		case 'B': /* change city production */
X			e_prod (edit_cursor);
X			break;
X		case 'F': /* fill */
X			e_fill (edit_cursor);
X			break;
X		case 'G': /* explore */
X			e_explore (edit_cursor);
X			break;
X		case 'H': /* help */
X			e_help ();
X			break;
X		case 'I': /* directional stasis */
X			e_stasis (edit_cursor);
X			break;
X		case 'K': /* wake up anything and everything */
X			e_wake (edit_cursor);
X			break;
X		case 'L': /* land plane */
X			e_land (edit_cursor);
X			break;
X		case 'M': /* start move to location */
X			path_type = NOPIECE;
X			e_move (&path_start, edit_cursor);
X			break;
X		case 'N': /* end move to location */
X			e_end (&path_start, edit_cursor, path_type);
X			break;
X		case 'O': /* leave display mode */
X			e_leave ();
X			return;
X		case 'P': /* print new sector */
X			e_print (&edit_cursor);
X			break;
X		case 'R': /* make piece move randomly */
X			e_random (edit_cursor);
X			break;
X		case 'S': /* sleep */
X			e_sleep (edit_cursor);
X			break;
X		case 'T': /* transport army */
X			e_transport (edit_cursor);
X			break;
X		case 'U': /* repair ship */
X			e_repair (edit_cursor);
X			break;
X		case 'V': /* set city function */
X			e_city_func (&path_start, edit_cursor, &path_type);
X			break;
X		case 'Y': /* set army func to attack */
X			e_attack (edit_cursor);
X			break;
X		case '?': /* request info */
X			e_info (edit_cursor);
X			break;
X		case '\014': /* control-L */
X			redraw ();
X			break;
X		default: /* bad command? */
X			huh ();
X			break;
X		}
X	}
X}
X
X/*
XGet the next command.  We handle cursor movement here.
XThis routine is an attempt to make cursor movement reasonably
Xfast.
X*/
X
Xstatic char dirchars[] = "WwEeDdCcXxZzAaQq";
X
Xchar
Xe_cursor (edit_cursor)
Xlong *edit_cursor;
X{
X	char e;
X	char *p;
X	
X	/* set up terminal */
X	(void) crmode ();
X	(void) refresh ();
X	e = getch ();
X	topini (); /* clear any error messages */
X
X	for (;;) {
X		p = strchr (dirchars, e);
X		if (!p) break;
X
X		if (!move_cursor (edit_cursor, dir_offset[(p-dirchars) / 2]))
X			(void) beep ();
X		
X		(void) refresh ();
X		e = getch ();
X	}
X	(void) nocrmode (); /* reset terminal */
X	if (islower (e)) e = upper (e);
X	return e;
X}
X
X/*
XLeave edit mode.
X*/
X
Xvoid
Xe_leave () {
X}
X
X/*
XPrint new sector.
X*/
X
Xvoid
Xe_print (edit_cursor)
Xlong *edit_cursor;
X{
X        int sector;
X	
X	sector = get_range ("New Sector? ", 0, NUM_SECTORS-1);
X
X	/* position cursor at center of sector */
X	*edit_cursor = sector_loc (sector);
X	sector_change (); /* allow change of sector */
X}
X
X/*
XSet the function of a piece.
X*/
X
Xvoid
Xe_set_func (loc, func)
Xlong loc;
Xlong func;
X{
X	piece_info_t *obj;
X	obj = find_obj_at_loc (loc);
X	if (obj != NULL && obj->owner == USER) {
X		obj->func = func;
X		return;
X	}
X	huh (); /* no object here */
X}
X	
X/* Set the function of a city for some piece. */
X
Xvoid
Xe_set_city_func (cityp, type, func)
Xcity_info_t *cityp;
Xint type;
Xlong func;
X{
X	cityp->func[type] = func;
X}
X
X/*
XSet a piece to move randomly.
X*/
X
Xvoid
Xe_random (loc)
Xlong loc;
X{
X	e_set_func (loc, RANDOM);
X}
X
Xvoid
Xe_city_random (cityp, type)
Xcity_info_t *cityp;
Xint type;
X{
X	e_set_city_func (cityp, type, RANDOM);
X}
X
X/*
XPut a ship in fill mode.
X*/
X
Xvoid
Xe_fill (loc)
Xlong loc;
X{
X	if (user_map[loc].contents == 'T' || user_map[loc].contents == 'C')
X		e_set_func (loc, FILL);
X	else huh ();
X}
X
Xvoid
Xe_city_fill (cityp, type)
Xcity_info_t *cityp;
Xint type;
X{
X	if (type == TRANSPORT || type == CARRIER)
X		e_set_city_func (cityp, type, FILL);
X	else huh ();
X}
X
X/*
XSet a piece to explore.
X*/
X
Xvoid
Xe_explore (loc)
Xlong loc;
X{
X	e_set_func (loc, EXPLORE);
X}
X
Xvoid
Xe_city_explore (cityp, type)
Xcity_info_t *cityp;
Xint type;
X{
X	e_set_city_func (cityp, type, EXPLORE);
X}
X
X/*
XSet a fighter to land.
X*/
X
Xvoid
Xe_land (loc)
Xlong loc;
X{
X	if (user_map[loc].contents == 'F')
X		e_set_func (loc, LAND);
X	else huh ();
X}
X/*
XSet an army's function to TRANSPORT.
X*/
X
Xvoid
Xe_transport (loc)
Xlong loc;
X{
X	if (user_map[loc].contents == 'A')
X		e_set_func (loc, WFTRANSPORT);
X	else huh ();
X}
X
X/*
XSet an army's function to ATTACK.
X*/
X
Xvoid
Xe_attack (loc)
Xlong loc;
X{
X	if (user_map[loc].contents == 'A')
X		e_set_func (loc, ARMYATTACK);
X	else huh ();
X}
X
Xvoid
Xe_city_attack (cityp, type)
Xcity_info_t *cityp;
Xint type;
X{
X	if (type == ARMY)
X		e_set_city_func (cityp, type, ARMYATTACK);
X	else huh ();
X}
X
X/*
XSet a ship's function to REPAIR.
X*/
X
Xvoid
Xe_repair (loc)
Xlong loc;
X{
X	if (strchr ("PDSTBC", user_map[loc].contents))
X		e_set_func (loc, REPAIR);
X	else huh ();
X}
X
Xvoid
Xe_city_repair (cityp, type)
Xcity_info_t *cityp;
Xint type;
X{
X	if (type == ARMY || type == FIGHTER || type == SATELLITE)
X		huh ();
X	else e_set_city_func (cityp, type, REPAIR);
X}
X
X/*
XSet object to move in a direction.
X*/
X
Xstatic char dirs[] = "WEDCXZAQ";
X 
Xvoid
Xe_stasis (loc)
Xlong loc;
X{
X	char e;
X	char *p;
X	
X	if (!isupper (user_map[loc].contents)) huh (); /* no object here */
X	else if (user_map[loc].contents == 'X') huh ();
X	else {
X		e = get_chx(); /* get a direction */
X		p = strchr (dirs, e);
X
X		if (p == NULL) huh ();
X		else e_set_func (loc, (long)(MOVE_N - (p - dirs)));
X	}
X}
X
Xvoid
Xe_city_stasis (cityp, type)
Xcity_info_t *cityp;
Xint type;
X{
X	char e;
X	char *p;
X	
X	e = get_chx(); /* get a direction */
X	p = strchr (dirs, e);
X
X	if (p == NULL) huh ();
X	else e_set_city_func (cityp, type, (long)(MOVE_N - (p - dirs)));
X}
X
X/*
XWake up anything and everything.
X*/
X
Xvoid
Xe_wake (loc)
Xlong loc;
X{
X	city_info_t *cityp;
X	piece_info_t *obj;
X	int i;
X
X	cityp = find_city (loc);
X        if (cityp != NULL) {
X		for (i = 0; i < NUM_OBJECTS; i++)
X			cityp->func[i] = NOFUNC;
X	}
X	for (obj = map[loc].objp; obj != NULL; obj = obj->loc_link.next)
X		obj->func = NOFUNC;
X}
X
Xvoid
Xe_city_wake (cityp, type)
Xcity_info_t *cityp;
Xint type;
X{
X	e_set_city_func (cityp, type, NOFUNC);
X}
X
X/*
XSet a city's function.  We get the piece type to set, then
Xthe function itself.
X*/
X
Xvoid
Xe_city_func (path_start, loc, path_type)
Xlong *path_start;
Xlong loc;
Xint *path_type;
X{
X	int type;
X	char e;
X	city_info_t *cityp;
X
X	cityp = find_city (loc);
X	if (!cityp || cityp->owner != USER) {
X		huh ();
X		return;
X	}
X
X	type = get_piece_name();
X	if (type == NOPIECE) {
X		huh ();
X		return;
X	}
X	
X	e = get_chx ();
X	
X	switch (e) {
X	case 'F': /* fill */
X		e_city_fill (cityp, type);
X		break;
X	case 'G': /* explore */
X		e_city_explore (cityp, type);
X		break;
X	case 'I': /* directional stasis */
X		e_city_stasis (cityp, type);
X		break;
X	case 'K': /* turn off function */
X		e_city_wake (cityp, type);
X		break;
X	case 'M': /* start move to location */
X		*path_type = type;
X		e_move (path_start, loc);
X		break;
X	case 'R': /* make piece move randomly */
X		e_city_random (cityp, type);
X		break;
X	case 'U': /* repair ship */
X		e_city_repair (cityp, type);
X		break;
X	case 'Y': /* set army func to attack */
X		e_city_attack (cityp, type);
X		break;
X	default: /* bad command? */
X		huh ();
X		break;
X	}
X}
X
X/*
XBeginning of move to location.
X*/
X
Xvoid
Xe_move (path_start, loc)
Xlong *path_start;
Xlong loc;
X{
X	if (!isupper(user_map[loc].contents)) huh (); /* nothing there? */
X	else if (user_map[loc].contents == 'X') huh (); /* enemy city? */
X        else *path_start = loc;
X}
X
X/*
XEnd of move to location.
X*/
X
Xvoid
Xe_end (path_start, loc, path_type)
Xlong *path_start;
Xlong loc;
Xint path_type;
X{
X	city_info_t *cityp;
X	
X	if (*path_start == -1) huh (); /* no path started? */
X	else if (path_type == NOPIECE) e_set_func (*path_start, loc);
X	else {
X		cityp = find_city (*path_start);
X		ASSERT (cityp);
X		e_set_city_func (cityp, path_type, loc);
X	}
X
X	*path_start = -1; /* remember no path in progress */
X}
X
X/*
XPut a piece to sleep.
X*/
X
Xvoid
Xe_sleep (loc)
Xlong loc;
X{
X	if (user_map[loc].contents == 'O') huh (); /* can't sleep a city */
X	else e_set_func (loc, SENTRY);
X}
X
X/*
XPrint out information about a piece.
X*/
X
Xvoid
Xe_info (edit_cursor)
Xlong edit_cursor;
X{
X	void e_city_info(), e_piece_info();
X
X	char ab;
X
X	ab = user_map[edit_cursor].contents;
X
X	if (ab == 'O') e_city_info (edit_cursor);
X	else if (ab == 'X' && debug) e_city_info (edit_cursor);
X	else if ((ab >= 'A') && (ab <= 'T'))
X		e_piece_info (edit_cursor, ab);
X	else if ((ab >= 'a') && (ab <= 't') && (debug))
X		e_piece_info (edit_cursor, ab);
X	else huh ();
X}
X
X/*
XPrint info about a piece.
X*/
X
Xvoid
Xe_piece_info (edit_cursor, ab)
Xlong edit_cursor;
Xchar ab;
X{
X	piece_info_t *obj;
X	int type;
X	char *p;
X
X	ab = upper (ab);
X	p = strchr (type_chars, ab);
X	type = p - type_chars;
X
X	obj = find_obj (type, edit_cursor);
X	ASSERT (obj != NULL);
X	describe_obj (obj);
X}
X
X/*
XDisplay info on a city.
X*/
X
Xvoid
Xe_city_info (edit_cursor)
Xlong edit_cursor;
X{
X	piece_info_t *obj;
X	city_info_t *cityp;
X	int f, s;
X	char func_buf[STRSIZE];
X	char temp_buf[STRSIZE];
X	char junk_buf2[STRSIZE];
X
X	error (0); /* clear line */
X
X	f = 0; /* no fighters counted yet */
X	for (obj = map[edit_cursor].objp; obj != NULL;
X		obj = obj->loc_link.next)
X			if (obj->type == FIGHTER) f++;
X
X	s = 0; /* no ships counted yet */
X	for (obj = map[edit_cursor].objp; obj != NULL;
X		obj = obj->loc_link.next)
X			if (obj->type >= DESTROYER) s++;
X
X	if (f == 1 && s == 1) 
X		(void) sprintf (jnkbuf, "1 fighter landed, 1 ship docked");
X	else if (f == 1)
X		(void) sprintf (jnkbuf, "1 fighter landed, %d ships docked", s);
X	else if (s == 1)
X		(void) sprintf (jnkbuf, "%d fighters landed, 1 ship docked", f);
X	else (void) sprintf (jnkbuf, "%d fighters landed, %d ships docked", f, s);
X
X	cityp = find_city (edit_cursor);
X	ASSERT (cityp != NULL);
X
X	*func_buf = 0; /* nothing in buffer */
X	for (s = 0; s < NUM_OBJECTS; s++) { /* for each piece */
X		if (cityp->func[s] < 0)
X			(void) sprintf (temp_buf, "%c:%s; ",
X				piece_attr[s].sname,
X				func_name[FUNCI(cityp->func[s])]);
X		else (void) sprintf (temp_buf, "%c: %d;",
X				piece_attr[s].sname,
X				cityp->func[s]);
X		
X		(void) strcat (func_buf, temp_buf);
X	}
X
X	(void) sprintf (junk_buf2,
X		"City at location %d will complete %s on round %d",
X		cityp->loc,
X		piece_attr[cityp->prod].article,
X		date + piece_attr[cityp->prod].build_time - cityp->work);
X
X	info (junk_buf2, jnkbuf, func_buf);
X}
X
X/*
XChange city production.
X*/
X
Xvoid
Xe_prod (loc)
Xlong loc;
X{
X	city_info_t *cityp;
X	
X	cityp = find_city (loc);
X
X	if (cityp == NULL) huh (); /* no city? */
X	else set_prod (cityp);
X}
X
X/*
Xget help
X*/
X
Xvoid
Xe_help () {
X	help (help_edit, edit_lines);
X	prompt ("Press any key to continue: ");
X	(void) get_chx ();
X}
//E*O*F edit.c//

echo x - empire.c
sed -e 's/^X//' > "empire.c" << '//E*O*F empire.c//'
X/* %W% %G% %U% - (c) Copyright 1987, 1988 Chuck Simmons */
X
X/*
X *    Copyright (C) 1987, 1988 Chuck Simmons
X * 
X * See the file COPYING, distributed with empire, for restriction
X * and warranty information.
X */
X
X/*
Xempire.c -- this file contains initialization code, the main command
Xparser, and the simple commands.
X*/
X
X#include <stdio.h>
X#include <curses.h>
X#include "empire.h"
X#include "extern.h"
X
Xvoid
Xempire () {
X	void do_command();
X	void print_zoom();
X
X	char order;
X
X	ttinit (); /* init tty */
X	rndini (); /* init random number generator */
X
X	clear_screen (); /* nothing on screen */
X	(void) move (7, 0);
X	ver ();
X	pos_str (8, 0, "Detailed directions are in EMPIRE.DOC\n");
X	(void) refresh ();
X
X	if (!restore_game ()) /* try to restore previous game */
X		init_game (); /* otherwise init a new game */
X
X	/* Command loop starts here. */
X
X	for (;;) { /* until user quits */
X	    if (automove) { /* don't ask for cmd in auto mode */
X		user_move ();
X		comp_move (1);
X		save_game ();
X	    }
X	    else {
X		prompt (0); /* blank top line */
X		(void) refresh ();
X	        prompt ("Your orders? ");
X	        order = get_chx (); /* get a command */
X		do_command (order);
X	    }
X	}
X}
X
X/*
XExecute a command.
X*/
X
Xvoid
Xdo_command (orders)
Xchar orders;
X{
X	void c_debug(), c_quit(), c_sector(), c_map(), c_examine();
X	void c_give(), c_movie();
X
X	char e;
X	int ncycle;
X
X	switch (orders) {
X	case 'A': /* turn on auto move mode */
X		automove = TRUE;
X		error ("Now in Auto-Mode");
X		user_move ();
X		comp_move (1);
X		save_game ();
X		break;
X
X	case 'C': /* give a city to the computer */
X		c_give ();
X		break;
X	
X	case 'D': /* display round number */
X		error ("Round #%d", date);
X		break;
X
X	case 'E': /* examine enemy map */
X		if (resigned) c_examine ();
X		else huh (); /* illegal command */
X		break;
X
X	case 'F': /* print map to file */
X		c_map ();
X		break;
X
X	case 'G': /* give one free enemy move */
X		comp_move (1);
X		break;
X
X	case 'H': /* help */
X		help (help_cmd, cmd_lines);
X		break;
X
X	case 'J': /* edit mode */
X		ncycle = cur_sector ();
X		if (ncycle == -1) ncycle = 0;
X		edit (sector_loc (ncycle));
X		break;
X
X	case 'M': /* move */
X		user_move ();
X		comp_move (1);
X		save_game ();
X		break;
X
X	case 'N': /* give enemy free moves */
X		ncycle = getint ("Number of free enemy moves: ");
X		comp_move (ncycle);
X		save_game ();
X		break;
X
X	case 'P': /* print a sector */
X		c_sector ();
X		break;
X
X	case '\026': /* some interrupt */
X	case 'Q': /* quit */
X		c_quit ();
X		break;
X
X	case 'R': /* restore game */
X		clear_screen ();
X		e = restore_game ();
X		break;
X
X	case 'S': /* save game */
X		save_game ();
X		break;
X	
X	case 'T': /* trace: toggle save_movie flag */
X		save_movie = !save_movie;
X		if (save_movie) comment ("Saving movie screens to 'empmovie.dat'.");
X		else comment ("No longer saving movie screens.");
X		break;
X
X	case 'W': /* watch movie */
X		if (resigned || debug) replay_movie ();
X		else error ("You cannot watch movie until computer resigns.");
X		break;
X	
X	case 'Z': /* print compressed map */
X		(void) clear ();
X		print_zoom (user_map);
X		(void) refresh ();
X		break;
X
X	case '\014': /* redraw the screen */
X		redraw ();
X		break;
X
X	case '+': /* change debug state */
X		e = get_chx();
X		if ( e  ==  '+' ) debug = TRUE;
X		else if ( e  ==  '-' ) debug = FALSE;
X		else huh ();
X		break;
X
X	default:
X		if (debug) c_debug (orders); /* debug */
X		else huh (); /* illegal command */
X		break;
X	}
X	e = e; /* keep lint quiet */
X}
X
X/*
XGive an unowned city (if any) to the computer.  We make
Xa list of unowned cities, choose one at random, and mark
Xit as the computers.
X*/
X
Xvoid
Xc_give () {
X	int unowned[NUM_CITY];
X	long i, count;
X
X	count = 0; /* nothing in list yet */
X	for (i = 0; i < NUM_CITY; i++) {
X		if (city[i].owner == UNOWNED) {
X			unowned[count] = i; /* remember this city */
X			count += 1;
X		}
X	}
X	if (count == 0) {
X		error ("There are no unowned cities.");
X		return;
X	}
X	i = irand (count);
X	i = unowned[i]; /* get city index */
X	city[i].owner = COMP;
X	city[i].prod = NOPIECE;
X	city[i].work = 0;
X	scan (comp_map, city[i].loc);
X}
X
X/*
XDebugging commands should be implemented here.  
XThe order cannot be any legal command.
X*/
X
Xvoid
Xc_debug (order)
Xchar order;
X{
X	char e;
X
X	switch (order) {
X	case '#' : c_examine (); break;
X	case '%' : c_movie (); break;
X	
X	case '@': /* change trace state */
X		e = get_chx();
X		if ( e  ==  '+' ) trace_pmap = TRUE;
X		else if ( e  ==  '-' ) trace_pmap = FALSE;
X		else huh ();
X		break;
X
X	case '$': /* change print_debug state */
X		e = get_chx();
X		if ( e  ==  '+' ) print_debug = TRUE;
X		else if ( e  ==  '-' ) print_debug = FALSE;
X		else huh ();
X		break;
X
X	case '&': /* change print_vmap state */
X		print_vmap = get_chx();
X		break;
X
X	default: huh (); break;
X	}
X}
X
X/*
XThe quit command.  Make sure the user really wants to quit.
X*/
X
Xvoid
Xc_quit () {
X	if (getyn ("QUIT - Are you sure? ")) {
X	    empend ();
X	}
X}
X
X/*
XPrint a sector.  Read the sector number from the user
Xand print it.
X*/
X
Xvoid
Xc_sector () {
X	int num;
X
X	num = get_range ("Sector number? ", 0, NUM_SECTORS-1);
X	print_sector_u (num);
X}
X
X/*
XPrint the map to a file.  We ask for a filename, attempt to open the
Xfile, and if successful, print out the user's information to the file.
XWe print the map sideways to make it easier for the user to print
Xout the map.
X*/
X
Xvoid
Xc_map () {
X	FILE *f;
X	int i, j;
X	char line[MAP_HEIGHT+2];
X
X	prompt ("Filename? ");
X	get_str (jnkbuf, STRSIZE);
X
X	f = fopen (jnkbuf, "w");
X	if (f == NULL) {
X		error ("I can't open that file.");
X		return;
X	}
X	for (i = 0; i < MAP_WIDTH; i++) { /* for each column */
X		for (j = MAP_HEIGHT-1; j >= 0; j--) { /* for each row */
X                        line[MAP_HEIGHT-1-j] = user_map[row_col_loc(j,i)].contents;
X		}
X		j = MAP_HEIGHT-1;
X		while (j >= 0 && line[j] == ' ') /* scan off trailing blanks */
X			j -= 1;
X			
X		line[++j] = '\n';
X		line[++j] = 0; /* trailing null */
X		(void) fputs (line, f);
X	}
X	(void) fclose (f);
X}
X
X/*
XAllow user to examine the computer's map.
X*/
X
Xvoid
Xc_examine () {
X	int num;
X
X	num = get_range ("Sector number? ", 0, NUM_SECTORS-1);
X	print_sector_c (num);
X}
X
X/*
XWe give the computer lots of free moves and
XPrint a "zoomed" version of the computer's map.
X*/
X
Xvoid
Xc_movie () {
X	(void) clear ();
X	for (;;) {
X		comp_move (1);
X		print_zoom (comp_map);
X		save_game ();
X#ifdef PROFILE
X		if (date == 125) empend();
X#endif
X	}
X}
//E*O*F empire.c//

echo shar: End of archive 2 \(of 6\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
        MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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



More information about the Alt.sources mailing list