|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T i
Length: 15558 (0x3cc6) Types: TextFile Names: »init.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/X/Xconq/init.c«
/* 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; } }