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 i

⟦fd63a5e29⟧ TextFile

    Length: 15558 (0x3cc6)
    Types: TextFile
    Names: »init.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/X/Xconq/init.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: init.c,v 1.2 88/06/28 10:06:13 shebs Exp $ */

/* Initialization is complicated, because xconq needs lots of setup for */
/* maps, units, sides, and the like.  The data must also be able to come */
/* from saved games, scenarios, bare maps in files, period descriptions, */
/* or be synthesized if necessary. */

#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 char *rawfilenames[];

extern int numfiles, giventime;

int good_place();          /* to make gcc happy */

/* Keep track of whether each sort of data has been loaded or not. */
/* The version isn't important enough to need any sort of flag. */

bool periodmade, mapmade, globalsmade, sidesmade, unitsmade;
bool populations = FALSE;  /* true if populace ever nonzero */

int favterr[MAXUTYPES];    /* "favorite terrain" of each unit type */
int numhexes[MAXUTYPES];   /* temporaries used by country placement */
int countryx[MAXSIDES], countryy[MAXSIDES];  /* centers of countries */
int snameused[MAXSNAMES];  /* flags side names already used by somebody */
int unameused[MAXUNAMES];  /* flags unit names already used */

/* Either load a saved game or load mapfiles from cmd line and then make up */
/* any stuff that didn't get loaded. */

init_game()
{
    int i;

    periodmade = mapmade = globalsmade = sidesmade = unitsmade = FALSE;

    if (saved_game()) {
	printf("Restoring from \"%s\" ...\n", SAVEFILE);
	load_mapfile(SAVEFILE);
    } else {
	for (i = 0; i < numfiles; ++i) {
	    load_mapfile(rawfilenames[i]);
	}
	if (!mapmade) {
	    printf("Please wait six days while I create the world...\n");
	    make_up_map();
	}
	if (!globalsmade) {
	    make_up_globals();
	}
	if (!sidesmade) {
	    make_up_sides();
	}
	if (numsides <= 0) {
	    fprintf(stderr, "No player sides in this game!\n");
	    exit(1);
	} else if (numsides < numgivens) {
	    fprintf(stderr,
		    "Warning: only made %d of the %d sides requested.\n",
		    numsides, numgivens);
	}
	if (!unitsmade) {
	    make_up_units();
	}
    }
    init_unit_views();
    fixup_things();
    printf("\nThe time is %s.\n", period.name);
}

/* Sort out the mess created by loading some things and creating others. */
/* Should only be possible to start with 0 units when building a scenario. */
/* Need to make friends and enemies; normally the machine players gang up */
/* on the humans. */

fixup_things()
{
    bool hasany;
    int x, y;
    Unit *unit;
    Side *side, *side2;

    if (period.scale != world.scale) {
	fprintf(stderr,
		"Reality check: Period is %d km/hex but map is %d km/hex.\n",
		period.scale, world.scale);
    }
    if (no_statistics()) {
	for_all_units(unit) {
	    if (!neutral(unit)) unit->side->balance[unit->type][FIRSTUNIT]++;
	}
    }
    for_all_sides(side) {
	side->timeleft = giventime;
	hasany = FALSE;
	for_all_units(unit) {
	    if (unit->side == side) {
		hasany = TRUE;
		break;
	    }
	}
	if (!hasany && (unit = random_start_unit()) != NULL) {
	    unit_changes_side(unit, side, FIRSTUNIT, -1);
	    unit->trueside = unit->side;
	    set_product(unit, period.firstptype);
	    set_schedule(unit);
	}
    }
    for_all_sides(side) {
	for_all_sides(side2) {
	    if (neutral_side(side, side2)) {
		if (side->host != NULL || side2->host != NULL)
		    declare_war(side, side2);
		else
		    declare_alliance(side, side2);
	    }
	}
    }
    /* this slowness is necessary to solve chicken/egg problems of loading */
    /* units and sides from files... */
    if (period.allseen || world.known) {
	for_all_sides(side) {
	    for (x = 0; x < world.width; ++x) {
		for (y = 0; y < world.height; ++y) {
		    set_side_view(side, x, y, EMPTY);
		    if ((unit = unit_at(x, y)) != NULL) {
			if (utypes[unit->type].alreadyseen ||
			    utypes[unit->type].seealways ||
			    unit->side == side) {
			    see_exact(side, x, y);
			}
			if (utypes[unit->type].seealways) {
			    set_cover(side, x, y, 100);
			}
		    }
		}
	    }
	}
    }
}

iview_hex(x, y)
int x, y;
{
    Unit *unit;

    set_side_view(tmpside, x, y, EMPTY);
    if ((unit = unit_at(x, y)) != NULL) {
	if (cover(tmpside, x, y) > 0 || utypes[unit->type].alreadyseen) {
	    see_exact(tmpside, unit->x, unit->y);
	}
    }
}

init_unit_views()
{
    Unit *unit;

    for_all_units(unit) {
	if (!neutral(unit)) {
	    see_exact(unit->side, unit->x, unit->y);
	    if (period.knownradius > 0) {
		tmpside = unit->side;
		apply_to_area(unit->x, unit->y, period.knownradius, iview_hex);
	    }
	}
    }
}

no_statistics()
{
    int u;
    Side *side = sidelist;

    for_all_unit_types(u) if (side->balance[u][FIRSTUNIT] > 0) return FALSE;
    return TRUE;
}

/* Invent global values as necessary. */

make_up_globals()
{
    if (Debug) printf("Going to make up some globals ...\n");
    global.time = 0;
    global.endtime = DEFAULTTURNS;
    global.setproduct = TRUE;
    global.leavemap = FALSE;
    global.numconds = 0;
    if (Debug) printf("... Done making up globals.\n");
}

/* Create some random sides with default characteristics. */

make_up_sides()
{
    int i;
    Side *side;

    if (Debug) printf("Going to make up some sides ...\n");
    for (i = 0; i < MAXSNAMES; ++i) snameused[i] = FALSE;
    for (i = 0; i < numgivens; ++i) {
	side = create_side(random_side_name(), humans[i], hosts[i]);
	/* Pretty bad if side creation fails... */
	if (side == NULL) abort();
    }
    if (Debug) printf("... Done making up sides.\n");
}

/* If no units supplied with the map, then make some up and place them. */
/* There is an option to start with one or with a country. */

make_up_units()
{
    int u, t, i;

    if (Debug) printf("Going to make up some units ...\n");
    for_all_unit_types(u) {
	favterr[u] = 0;   /* doesn't really matter which one */
	for_all_terrain_types(t) {
	    if (utypes[u].favored[t] > utypes[u].favored[favterr[u]])
	    favterr[u] = t;
	}
    }
    /* Check for existence of favorite terrain on map */
    for (i = 0; i < MAXUNAMES; ++i) unameused[i] = FALSE;
    place_countries();
    place_neutrals();
    if (Debug) printf("... Done making up units.\n");
}

/* Place all the units belonging to countries.  Once placed, set ownership */
/* and production appropriately. */

place_countries()
{
    int x0, y0, u, i, num, first = period.firstutype, numleft[MAXUTYPES];
    Unit *unit;
    Side *side;

    for_all_sides(side) {
	find_a_place(&x0, &y0);
	if (Debug) printf("Country at %d,%d\n", x0, y0);
	countryx[side_number(side)] = x0;  countryy[side_number(side)] = y0;
	place_inhabitants(side, x0, y0);
	if (first != NOTHING) {
	    unit = create_unit(first, random_unit_name(first));
	    occupy_hex(unit, x0, y0);
	    init_supply(unit);
	    unit_changes_side(unit, side, FIRSTUNIT, -1);
	    unit->trueside = unit->side;
	    set_product(unit, period.firstptype);
	    set_schedule(unit);
	}
	for_all_unit_types(u) {
	    num = utypes[u].incountry;
	    if (first == u) num--;
	    numleft[u] = num;
	    for (i = 0; i < num; ++i) {
		unit = create_unit(u, random_unit_name(u));
		if (place_unit(unit, x0, y0)) {
		    numleft[u]--;
		    if (first == NOTHING) {
			unit_changes_side(unit, side, FIRSTUNIT, -1);
			unit->trueside = unit->side;
		    }
		} else {
		    kill_unit(unit, -1);
		}
	    }
	}
	/* second pass for units that have to be occupants */
	for_all_unit_types(u) {
	    for (i = 0; i < numleft[u]; ++i) {
		unit = create_unit(u, random_unit_name(u));
		if (place_unit(unit, x0, y0)) {
		    if (first == NOTHING) {
			unit_changes_side(unit, side, FIRSTUNIT, -1);
			unit->trueside = unit->side;
		    } else {
			/* give up finally - needs to be more informative */
			fprintf(stderr, "Can't place a %s!\n", utypes[u].name);
			exit(1);
		    }
		}
	    }
	}
    }
}

/* Work hard to find a place for a side's country.  First make some random *
/* trials, then start searching from the "center" of the map outwards. */
/* If neither approach works, things are too screwed up to keep going. */

find_a_place(cxp, cyp)
int *cxp, *cyp;
{
    int tries, x, y, diam = (2 * period.countrysize + 1);

    for (tries = 0; tries < 200; ++tries) {
	x = random(world.width);
	x = wrap(x);
	y = random(world.height - diam) + period.countrysize;
	if (good_place(x, y)) { 
	    *cxp = x;  *cyp = y;
	    if (Debug) printf("Country placed on try %d\n", tries);
	    return;
	}
    }
    if (search_area(world.width/2, world.height/2,
		    max(world.width, world.height), good_place, cxp, cyp)) {
	if (Debug) printf("Country placed after search\n");
	return;
    } else {
	fprintf(stderr, "Can't place all the countries!\n");
	fprintf(stderr, "Try bigger maps or fewer sides next time.\n");
	exit(1);
    }
}    

/* Decide whether the given location is desirable for a country.  It should */
/* not be too near or too far from other sides' countries, and there must be */
/* enough terrain to place all the initial units.  In addition, the center */
/* of the country must have the right terrain for the firstutype. */

count_hexes(x, y)
int x, y;
{
    int u, terr = terrain_at(x, y);

    for_all_unit_types(u) if (terr == favterr[u]) numhexes[u]++;
}

good_place(cx, cy)
int cx, cy;
{
    bool toofar = TRUE, notfirst = FALSE;
    int c, px, py, t, u, x, y, toplace, allhexes, first = period.firstutype;

    for (c = 0; c < numsides; ++c) {
	px = countryx[c];  py = countryy[c];
	if (px > 0 && py > 0) {
	    notfirst = TRUE;
	    if (distance(cx, cy, px, py) < period.mindistance) return FALSE;
	    if (distance(cx, cy, px, py) < period.maxdistance) toofar = FALSE;
	}
    }
    if (toofar && notfirst) return FALSE;
    if (first != NOTHING && terrain_at(cx, cy) != favterr[first])
	return FALSE;
    toplace = allhexes = 0;
    for_all_unit_types(u) numhexes[u] = 0;
    apply_to_area(cx, cy, period.countrysize, count_hexes);
    for_all_unit_types(u) {
	if (utypes[u].incountry > numhexes[u]) return FALSE;
	toplace += utypes[u].incountry;
	allhexes += numhexes[u];
    }
    return (toplace < allhexes);
}

/* Place the populace on appropriate terrain within the country. */
/* If countries overlap, then flip coins to decide about intermix (heh-heh, */
/* so it resembles 17th-century Germany - more fun that way!). */
/* The loops are a standard regular hexagon filler. */

place_inhabitants(side, x0, y0)
Side *side;
int x0, y0;
{
    int x, y, x1, y1, x2, y2, dist = period.countrysize;

    y1 = interior(y0 - dist);
    y2 = interior(y0 + dist);
    for (y = y1; y <= y2; ++y) {
	x1 = x0 - (y < y0 ? (y - y1) : dist);
	x2 = x0 + (y > y0 ? (y2 - y) : dist);
	for (x = x1; x <= x2; ++x) {
	    if (ttypes[terrain_at(wrap(x), y)].inhabitants) {
		populations = TRUE;
		if (unpopulated(wrap(x), y) || flip_coin()) {
		    set_people_at(wrap(x), y, 8+side_number(side));
		}
	    }
	}
    }
}

/* The basic conditions that *must* be met by an initial unit placement. */

int tmputype;

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

    return ((unit == NULL && utypes[tmputype].favored[terrain_at(x, y)] > 0) ||
	    (unit != NULL && could_carry(unit->type, tmputype)));
}

/* Put a unit down somewhere in the designated area, following constraints */
/* on terrain and adjacency.  Returns success of placement. */

/* "favterr" is poorly and unrobustly handled here... */

place_unit(unit, cx, cy)
Unit *unit;
int cx, cy;
{
    bool canmove = FALSE;
    int u = unit->type, t, tries, x, y, chance, r, favterr = 0;
    int csize = period.countrysize;

    for_all_terrain_types(t) {
	if (could_move(u, t))
	    canmove = TRUE;
	if (utypes[u].favored[t] > utypes[u].favored[favterr])
	    favterr = t;
    }
    tmputype = u;
    for (tries = 0; tries < 500; ++tries) {
	x = random(2*csize+1) + cx - csize;  x = wrap(x);
	y = random(2*csize+1) + cy - csize;  y = interior(y);
	if (valid_place(x, y) && distance(cx, cy, x, y) <= csize) {
	    chance = 100;
	    t = terrain_at(x, y);
	    if (canmove && !could_move(u, t)) chance -= 90;
	    for_all_resource_types(r) {
		if (utypes[u].produce[r] > 0 && utypes[u].productivity[t] == 0)
		    chance -= 20;
	    }
	    if (adj_unit(x, y)) chance -= 70;
	    if (probability(chance)) {
		occupy_hex(unit, x, y);
		init_supply(unit);
		if (Debug) printf("Unit placed on try %d\n", tries);
		return TRUE;
	    }
	}
    }
    if (search_area(cx, cy, csize, valid_place, &x, &y)) {
	occupy_hex(unit, x, y);
	init_supply(unit);
	if (Debug) printf("Unit placed after search\n");
	return TRUE;
    }
    return FALSE;
}

/* The number of neutral units is given by a parameter, and adjusted by */
/* the number of units assigned to specific countries.  The number is at */
/* least 1 (if nonzero density), even for small maps. */

place_neutrals()
{
    int u, num, i;

    for_all_unit_types(u) {
	if (utypes[u].density > 0) {
	    num = (((utypes[u].density * world.width * world.height) / 10000) -
		   (numsides * utypes[u].incountry));
	    num = max(1, num);
	    for (i = 0; i < num; ++i) {
		place_neutral(create_unit(u, random_unit_name(u)));
	    }
	}
    }
}

/* Neutral places should be uncommon in hostile terrain.  If we can't find */
/* a place, just blow it off and go to the next one. */

place_neutral(unit)
Unit *unit;
{
    int tries, x, y, u = unit->type;

    for (tries = 0; tries < 500; ++tries) {
	x = random(world.width);  y = random(world.height - 2) + 1;
	if ((probability(utypes[u].favored[terrain_at(x, y)])) &&
	    (unit_at(x, y) == NULL) &&
	    (!adj_unit(x, y) || flip_coin())) {
	    occupy_hex(unit, x, y);
	    init_supply(unit);
	    return;
	}
    }
    kill_unit(unit, ENDOFWORLD);
}

/* True if anybody already on given hex or adjacent to it. */

adj_unit(x, y)
int x, y;
{
    int d, x1, y1;

    for_all_directions(d) {
	x1 = wrap(x + dirx[d]);  y1 = y + diry[d];
	if (unit_at(x1, y1)) return TRUE;
    }
    return FALSE;
}

/* Give the unit what it is declared to have stockpiled already. */

init_supply(unit)
Unit *unit;
{
    int r, u = unit->type;

    for_all_resource_types(r) {
	unit->supply[r] =
	    (utypes[u].storage[r] * utypes[u].stockpile[r]) / 100;
    }
}

/* Pick any name not already used in the giant array of unit names. */
/* First try randomly, then sequentially. */

char *
random_unit_name(u)
int u;
{
    int i, n;

    if (utypes[u].named) {
	for (i = 0; i < period.numunames; ++i) {
	    if (!unameused[(n = random(period.numunames))]) {
		unameused[n] = TRUE;
		return unames[n];
	    }
	}
	for (i = 0; i < period.numunames; ++i) {
	    if (!unameused[i]) {
		unameused[i] = TRUE;
		return unames[i];
	    }
	}
	return NULL;
    } else {
	return NULL;
    }
}

/* Pick a side name not already used.  Don't get uptight if we ran out of */
/* names; perhaps a unit will lend a name, and certainly the players will */
/* notice and change side names manually! */

char *
random_side_name()
{
    int i, n;

    for (i = 0; i < period.numsnames; ++i) {
	if (!snameused[(n = random(period.numsnames))]) {
	    snameused[n] = TRUE;
	    return snames[n];
	}
    }
    for (i = 0; i < period.numsnames; ++i) {
	if (!snameused[i]) {
	    snameused[i] = TRUE;
	    return snames[i];
	}
    }
    return "???";
}

/* Quicky test needed in a couple places. */

saved_game()
{
    FILE *fp;

    if ((fp = fopen(SAVEFILE, "r")) != NULL) {
	fclose(fp);
	return TRUE;
    } else {
	return FALSE;
    }
}