home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume4 / xconq5 / part02 / init.c next >
C/C++ Source or Header  |  1988-06-29  |  16KB  |  594 lines

  1. /* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. /* RCS $Header: init.c,v 1.2 88/06/28 10:06:13 shebs Exp $ */
  6.  
  7. /* Initialization is complicated, because xconq needs lots of setup for */
  8. /* maps, units, sides, and the like.  The data must also be able to come */
  9. /* from saved games, scenarios, bare maps in files, period descriptions, */
  10. /* or be synthesized if necessary. */
  11.  
  12. #include "config.h"
  13. #include "misc.h"
  14. #include "dir.h"
  15. #include "period.h"
  16. #include "side.h"
  17. #include "unit.h"
  18. #include "map.h"
  19. #include "global.h"
  20.  
  21. extern char *rawfilenames[];
  22.  
  23. extern int numfiles, giventime;
  24.  
  25. int good_place();          /* to make gcc happy */
  26.  
  27. /* Keep track of whether each sort of data has been loaded or not. */
  28. /* The version isn't important enough to need any sort of flag. */
  29.  
  30. bool periodmade, mapmade, globalsmade, sidesmade, unitsmade;
  31. bool populations = FALSE;  /* true if populace ever nonzero */
  32.  
  33. int favterr[MAXUTYPES];    /* "favorite terrain" of each unit type */
  34. int numhexes[MAXUTYPES];   /* temporaries used by country placement */
  35. int countryx[MAXSIDES], countryy[MAXSIDES];  /* centers of countries */
  36. int snameused[MAXSNAMES];  /* flags side names already used by somebody */
  37. int unameused[MAXUNAMES];  /* flags unit names already used */
  38.  
  39. /* Either load a saved game or load mapfiles from cmd line and then make up */
  40. /* any stuff that didn't get loaded. */
  41.  
  42. init_game()
  43. {
  44.     int i;
  45.  
  46.     periodmade = mapmade = globalsmade = sidesmade = unitsmade = FALSE;
  47.  
  48.     if (saved_game()) {
  49.     printf("Restoring from \"%s\" ...\n", SAVEFILE);
  50.     load_mapfile(SAVEFILE);
  51.     } else {
  52.     for (i = 0; i < numfiles; ++i) {
  53.         load_mapfile(rawfilenames[i]);
  54.     }
  55.     if (!mapmade) {
  56.         printf("Please wait six days while I create the world...\n");
  57.         make_up_map();
  58.     }
  59.     if (!globalsmade) {
  60.         make_up_globals();
  61.     }
  62.     if (!sidesmade) {
  63.         make_up_sides();
  64.     }
  65.     if (numsides <= 0) {
  66.         fprintf(stderr, "No player sides in this game!\n");
  67.         exit(1);
  68.     } else if (numsides < numgivens) {
  69.         fprintf(stderr,
  70.             "Warning: only made %d of the %d sides requested.\n",
  71.             numsides, numgivens);
  72.     }
  73.     if (!unitsmade) {
  74.         make_up_units();
  75.     }
  76.     }
  77.     init_unit_views();
  78.     fixup_things();
  79.     printf("\nThe time is %s.\n", period.name);
  80. }
  81.  
  82. /* Sort out the mess created by loading some things and creating others. */
  83. /* Should only be possible to start with 0 units when building a scenario. */
  84. /* Need to make friends and enemies; normally the machine players gang up */
  85. /* on the humans. */
  86.  
  87. fixup_things()
  88. {
  89.     bool hasany;
  90.     int x, y;
  91.     Unit *unit;
  92.     Side *side, *side2;
  93.  
  94.     if (period.scale != world.scale) {
  95.     fprintf(stderr,
  96.         "Reality check: Period is %d km/hex but map is %d km/hex.\n",
  97.         period.scale, world.scale);
  98.     }
  99.     if (no_statistics()) {
  100.     for_all_units(unit) {
  101.         if (!neutral(unit)) unit->side->balance[unit->type][FIRSTUNIT]++;
  102.     }
  103.     }
  104.     for_all_sides(side) {
  105.     side->timeleft = giventime;
  106.     hasany = FALSE;
  107.     for_all_units(unit) {
  108.         if (unit->side == side) {
  109.         hasany = TRUE;
  110.         break;
  111.         }
  112.     }
  113.     if (!hasany && (unit = random_start_unit()) != NULL) {
  114.         unit_changes_side(unit, side, FIRSTUNIT, -1);
  115.         unit->trueside = unit->side;
  116.         set_product(unit, period.firstptype);
  117.         set_schedule(unit);
  118.     }
  119.     }
  120.     for_all_sides(side) {
  121.     for_all_sides(side2) {
  122.         if (neutral_side(side, side2)) {
  123.         if (side->host != NULL || side2->host != NULL)
  124.             declare_war(side, side2);
  125.         else
  126.             declare_alliance(side, side2);
  127.         }
  128.     }
  129.     }
  130.     /* this slowness is necessary to solve chicken/egg problems of loading */
  131.     /* units and sides from files... */
  132.     if (period.allseen || world.known) {
  133.     for_all_sides(side) {
  134.         for (x = 0; x < world.width; ++x) {
  135.         for (y = 0; y < world.height; ++y) {
  136.             set_side_view(side, x, y, EMPTY);
  137.             if ((unit = unit_at(x, y)) != NULL) {
  138.             if (utypes[unit->type].alreadyseen ||
  139.                 utypes[unit->type].seealways ||
  140.                 unit->side == side) {
  141.                 see_exact(side, x, y);
  142.             }
  143.             if (utypes[unit->type].seealways) {
  144.                 set_cover(side, x, y, 100);
  145.             }
  146.             }
  147.         }
  148.         }
  149.     }
  150.     }
  151. }
  152.  
  153. iview_hex(x, y)
  154. int x, y;
  155. {
  156.     Unit *unit;
  157.  
  158.     set_side_view(tmpside, x, y, EMPTY);
  159.     if ((unit = unit_at(x, y)) != NULL) {
  160.     if (cover(tmpside, x, y) > 0 || utypes[unit->type].alreadyseen) {
  161.         see_exact(tmpside, unit->x, unit->y);
  162.     }
  163.     }
  164. }
  165.  
  166. init_unit_views()
  167. {
  168.     Unit *unit;
  169.  
  170.     for_all_units(unit) {
  171.     if (!neutral(unit)) {
  172.         see_exact(unit->side, unit->x, unit->y);
  173.         if (period.knownradius > 0) {
  174.         tmpside = unit->side;
  175.         apply_to_area(unit->x, unit->y, period.knownradius, iview_hex);
  176.         }
  177.     }
  178.     }
  179. }
  180.  
  181. no_statistics()
  182. {
  183.     int u;
  184.     Side *side = sidelist;
  185.  
  186.     for_all_unit_types(u) if (side->balance[u][FIRSTUNIT] > 0) return FALSE;
  187.     return TRUE;
  188. }
  189.  
  190. /* Invent global values as necessary. */
  191.  
  192. make_up_globals()
  193. {
  194.     if (Debug) printf("Going to make up some globals ...\n");
  195.     global.time = 0;
  196.     global.endtime = DEFAULTTURNS;
  197.     global.setproduct = TRUE;
  198.     global.leavemap = FALSE;
  199.     global.numconds = 0;
  200.     if (Debug) printf("... Done making up globals.\n");
  201. }
  202.  
  203. /* Create some random sides with default characteristics. */
  204.  
  205. make_up_sides()
  206. {
  207.     int i;
  208.     Side *side;
  209.  
  210.     if (Debug) printf("Going to make up some sides ...\n");
  211.     for (i = 0; i < MAXSNAMES; ++i) snameused[i] = FALSE;
  212.     for (i = 0; i < numgivens; ++i) {
  213.     side = create_side(random_side_name(), humans[i], hosts[i]);
  214.     /* Pretty bad if side creation fails... */
  215.     if (side == NULL) abort();
  216.     }
  217.     if (Debug) printf("... Done making up sides.\n");
  218. }
  219.  
  220. /* If no units supplied with the map, then make some up and place them. */
  221. /* There is an option to start with one or with a country. */
  222.  
  223. make_up_units()
  224. {
  225.     int u, t, i;
  226.  
  227.     if (Debug) printf("Going to make up some units ...\n");
  228.     for_all_unit_types(u) {
  229.     favterr[u] = 0;   /* doesn't really matter which one */
  230.     for_all_terrain_types(t) {
  231.         if (utypes[u].favored[t] > utypes[u].favored[favterr[u]])
  232.         favterr[u] = t;
  233.     }
  234.     }
  235.     /* Check for existence of favorite terrain on map */
  236.     for (i = 0; i < MAXUNAMES; ++i) unameused[i] = FALSE;
  237.     place_countries();
  238.     place_neutrals();
  239.     if (Debug) printf("... Done making up units.\n");
  240. }
  241.  
  242. /* Place all the units belonging to countries.  Once placed, set ownership */
  243. /* and production appropriately. */
  244.  
  245. place_countries()
  246. {
  247.     int x0, y0, u, i, num, first = period.firstutype, numleft[MAXUTYPES];
  248.     Unit *unit;
  249.     Side *side;
  250.  
  251.     for_all_sides(side) {
  252.     find_a_place(&x0, &y0);
  253.     if (Debug) printf("Country at %d,%d\n", x0, y0);
  254.     countryx[side_number(side)] = x0;  countryy[side_number(side)] = y0;
  255.     place_inhabitants(side, x0, y0);
  256.     if (first != NOTHING) {
  257.         unit = create_unit(first, random_unit_name(first));
  258.         occupy_hex(unit, x0, y0);
  259.         init_supply(unit);
  260.         unit_changes_side(unit, side, FIRSTUNIT, -1);
  261.         unit->trueside = unit->side;
  262.         set_product(unit, period.firstptype);
  263.         set_schedule(unit);
  264.     }
  265.     for_all_unit_types(u) {
  266.         num = utypes[u].incountry;
  267.         if (first == u) num--;
  268.         numleft[u] = num;
  269.         for (i = 0; i < num; ++i) {
  270.         unit = create_unit(u, random_unit_name(u));
  271.         if (place_unit(unit, x0, y0)) {
  272.             numleft[u]--;
  273.             if (first == NOTHING) {
  274.             unit_changes_side(unit, side, FIRSTUNIT, -1);
  275.             unit->trueside = unit->side;
  276.             }
  277.         } else {
  278.             kill_unit(unit, -1);
  279.         }
  280.         }
  281.     }
  282.     /* second pass for units that have to be occupants */
  283.     for_all_unit_types(u) {
  284.         for (i = 0; i < numleft[u]; ++i) {
  285.         unit = create_unit(u, random_unit_name(u));
  286.         if (place_unit(unit, x0, y0)) {
  287.             if (first == NOTHING) {
  288.             unit_changes_side(unit, side, FIRSTUNIT, -1);
  289.             unit->trueside = unit->side;
  290.             } else {
  291.             /* give up finally - needs to be more informative */
  292.             fprintf(stderr, "Can't place a %s!\n", utypes[u].name);
  293.             exit(1);
  294.             }
  295.         }
  296.         }
  297.     }
  298.     }
  299. }
  300.  
  301. /* Work hard to find a place for a side's country.  First make some random *
  302. /* trials, then start searching from the "center" of the map outwards. */
  303. /* If neither approach works, things are too screwed up to keep going. */
  304.  
  305. find_a_place(cxp, cyp)
  306. int *cxp, *cyp;
  307. {
  308.     int tries, x, y, diam = (2 * period.countrysize + 1);
  309.  
  310.     for (tries = 0; tries < 200; ++tries) {
  311.     x = random(world.width);
  312.     x = wrap(x);
  313.     y = random(world.height - diam) + period.countrysize;
  314.     if (good_place(x, y)) { 
  315.         *cxp = x;  *cyp = y;
  316.         if (Debug) printf("Country placed on try %d\n", tries);
  317.         return;
  318.     }
  319.     }
  320.     if (search_area(world.width/2, world.height/2,
  321.             max(world.width, world.height), good_place, cxp, cyp)) {
  322.     if (Debug) printf("Country placed after search\n");
  323.     return;
  324.     } else {
  325.     fprintf(stderr, "Can't place all the countries!\n");
  326.     fprintf(stderr, "Try bigger maps or fewer sides next time.\n");
  327.     exit(1);
  328.     }
  329. }    
  330.  
  331. /* Decide whether the given location is desirable for a country.  It should */
  332. /* not be too near or too far from other sides' countries, and there must be */
  333. /* enough terrain to place all the initial units.  In addition, the center */
  334. /* of the country must have the right terrain for the firstutype. */
  335.  
  336. count_hexes(x, y)
  337. int x, y;
  338. {
  339.     int u, terr = terrain_at(x, y);
  340.  
  341.     for_all_unit_types(u) if (terr == favterr[u]) numhexes[u]++;
  342. }
  343.  
  344. good_place(cx, cy)
  345. int cx, cy;
  346. {
  347.     bool toofar = TRUE, notfirst = FALSE;
  348.     int c, px, py, t, u, x, y, toplace, allhexes, first = period.firstutype;
  349.  
  350.     for (c = 0; c < numsides; ++c) {
  351.     px = countryx[c];  py = countryy[c];
  352.     if (px > 0 && py > 0) {
  353.         notfirst = TRUE;
  354.         if (distance(cx, cy, px, py) < period.mindistance) return FALSE;
  355.         if (distance(cx, cy, px, py) < period.maxdistance) toofar = FALSE;
  356.     }
  357.     }
  358.     if (toofar && notfirst) return FALSE;
  359.     if (first != NOTHING && terrain_at(cx, cy) != favterr[first])
  360.     return FALSE;
  361.     toplace = allhexes = 0;
  362.     for_all_unit_types(u) numhexes[u] = 0;
  363.     apply_to_area(cx, cy, period.countrysize, count_hexes);
  364.     for_all_unit_types(u) {
  365.     if (utypes[u].incountry > numhexes[u]) return FALSE;
  366.     toplace += utypes[u].incountry;
  367.     allhexes += numhexes[u];
  368.     }
  369.     return (toplace < allhexes);
  370. }
  371.  
  372. /* Place the populace on appropriate terrain within the country. */
  373. /* If countries overlap, then flip coins to decide about intermix (heh-heh, */
  374. /* so it resembles 17th-century Germany - more fun that way!). */
  375. /* The loops are a standard regular hexagon filler. */
  376.  
  377. place_inhabitants(side, x0, y0)
  378. Side *side;
  379. int x0, y0;
  380. {
  381.     int x, y, x1, y1, x2, y2, dist = period.countrysize;
  382.  
  383.     y1 = interior(y0 - dist);
  384.     y2 = interior(y0 + dist);
  385.     for (y = y1; y <= y2; ++y) {
  386.     x1 = x0 - (y < y0 ? (y - y1) : dist);
  387.     x2 = x0 + (y > y0 ? (y2 - y) : dist);
  388.     for (x = x1; x <= x2; ++x) {
  389.         if (ttypes[terrain_at(wrap(x), y)].inhabitants) {
  390.         populations = TRUE;
  391.         if (unpopulated(wrap(x), y) || flip_coin()) {
  392.             set_people_at(wrap(x), y, 8+side_number(side));
  393.         }
  394.         }
  395.     }
  396.     }
  397. }
  398.  
  399. /* The basic conditions that *must* be met by an initial unit placement. */
  400.  
  401. int tmputype;
  402.  
  403. valid_place(x, y)
  404. int x, y;
  405. {
  406.     Unit *unit = unit_at(x, y);
  407.  
  408.     return ((unit == NULL && utypes[tmputype].favored[terrain_at(x, y)] > 0) ||
  409.         (unit != NULL && could_carry(unit->type, tmputype)));
  410. }
  411.  
  412. /* Put a unit down somewhere in the designated area, following constraints */
  413. /* on terrain and adjacency.  Returns success of placement. */
  414.  
  415. /* "favterr" is poorly and unrobustly handled here... */
  416.  
  417. place_unit(unit, cx, cy)
  418. Unit *unit;
  419. int cx, cy;
  420. {
  421.     bool canmove = FALSE;
  422.     int u = unit->type, t, tries, x, y, chance, r, favterr = 0;
  423.     int csize = period.countrysize;
  424.  
  425.     for_all_terrain_types(t) {
  426.     if (could_move(u, t))
  427.         canmove = TRUE;
  428.     if (utypes[u].favored[t] > utypes[u].favored[favterr])
  429.         favterr = t;
  430.     }
  431.     tmputype = u;
  432.     for (tries = 0; tries < 500; ++tries) {
  433.     x = random(2*csize+1) + cx - csize;  x = wrap(x);
  434.     y = random(2*csize+1) + cy - csize;  y = interior(y);
  435.     if (valid_place(x, y) && distance(cx, cy, x, y) <= csize) {
  436.         chance = 100;
  437.         t = terrain_at(x, y);
  438.         if (canmove && !could_move(u, t)) chance -= 90;
  439.         for_all_resource_types(r) {
  440.         if (utypes[u].produce[r] > 0 && utypes[u].productivity[t] == 0)
  441.             chance -= 20;
  442.         }
  443.         if (adj_unit(x, y)) chance -= 70;
  444.         if (probability(chance)) {
  445.         occupy_hex(unit, x, y);
  446.         init_supply(unit);
  447.         if (Debug) printf("Unit placed on try %d\n", tries);
  448.         return TRUE;
  449.         }
  450.     }
  451.     }
  452.     if (search_area(cx, cy, csize, valid_place, &x, &y)) {
  453.     occupy_hex(unit, x, y);
  454.     init_supply(unit);
  455.     if (Debug) printf("Unit placed after search\n");
  456.     return TRUE;
  457.     }
  458.     return FALSE;
  459. }
  460.  
  461. /* The number of neutral units is given by a parameter, and adjusted by */
  462. /* the number of units assigned to specific countries.  The number is at */
  463. /* least 1 (if nonzero density), even for small maps. */
  464.  
  465. place_neutrals()
  466. {
  467.     int u, num, i;
  468.  
  469.     for_all_unit_types(u) {
  470.     if (utypes[u].density > 0) {
  471.         num = (((utypes[u].density * world.width * world.height) / 10000) -
  472.            (numsides * utypes[u].incountry));
  473.         num = max(1, num);
  474.         for (i = 0; i < num; ++i) {
  475.         place_neutral(create_unit(u, random_unit_name(u)));
  476.         }
  477.     }
  478.     }
  479. }
  480.  
  481. /* Neutral places should be uncommon in hostile terrain.  If we can't find */
  482. /* a place, just blow it off and go to the next one. */
  483.  
  484. place_neutral(unit)
  485. Unit *unit;
  486. {
  487.     int tries, x, y, u = unit->type;
  488.  
  489.     for (tries = 0; tries < 500; ++tries) {
  490.     x = random(world.width);  y = random(world.height - 2) + 1;
  491.     if ((probability(utypes[u].favored[terrain_at(x, y)])) &&
  492.         (unit_at(x, y) == NULL) &&
  493.         (!adj_unit(x, y) || flip_coin())) {
  494.         occupy_hex(unit, x, y);
  495.         init_supply(unit);
  496.         return;
  497.     }
  498.     }
  499.     kill_unit(unit, ENDOFWORLD);
  500. }
  501.  
  502. /* True if anybody already on given hex or adjacent to it. */
  503.  
  504. adj_unit(x, y)
  505. int x, y;
  506. {
  507.     int d, x1, y1;
  508.  
  509.     for_all_directions(d) {
  510.     x1 = wrap(x + dirx[d]);  y1 = y + diry[d];
  511.     if (unit_at(x1, y1)) return TRUE;
  512.     }
  513.     return FALSE;
  514. }
  515.  
  516. /* Give the unit what it is declared to have stockpiled already. */
  517.  
  518. init_supply(unit)
  519. Unit *unit;
  520. {
  521.     int r, u = unit->type;
  522.  
  523.     for_all_resource_types(r) {
  524.     unit->supply[r] =
  525.         (utypes[u].storage[r] * utypes[u].stockpile[r]) / 100;
  526.     }
  527. }
  528.  
  529. /* Pick any name not already used in the giant array of unit names. */
  530. /* First try randomly, then sequentially. */
  531.  
  532. char *
  533. random_unit_name(u)
  534. int u;
  535. {
  536.     int i, n;
  537.  
  538.     if (utypes[u].named) {
  539.     for (i = 0; i < period.numunames; ++i) {
  540.         if (!unameused[(n = random(period.numunames))]) {
  541.         unameused[n] = TRUE;
  542.         return unames[n];
  543.         }
  544.     }
  545.     for (i = 0; i < period.numunames; ++i) {
  546.         if (!unameused[i]) {
  547.         unameused[i] = TRUE;
  548.         return unames[i];
  549.         }
  550.     }
  551.     return NULL;
  552.     } else {
  553.     return NULL;
  554.     }
  555. }
  556.  
  557. /* Pick a side name not already used.  Don't get uptight if we ran out of */
  558. /* names; perhaps a unit will lend a name, and certainly the players will */
  559. /* notice and change side names manually! */
  560.  
  561. char *
  562. random_side_name()
  563. {
  564.     int i, n;
  565.  
  566.     for (i = 0; i < period.numsnames; ++i) {
  567.     if (!snameused[(n = random(period.numsnames))]) {
  568.         snameused[n] = TRUE;
  569.         return snames[n];
  570.     }
  571.     }
  572.     for (i = 0; i < period.numsnames; ++i) {
  573.     if (!snameused[i]) {
  574.         snameused[i] = TRUE;
  575.         return snames[i];
  576.     }
  577.     }
  578.     return "???";
  579. }
  580.  
  581. /* Quicky test needed in a couple places. */
  582.  
  583. saved_game()
  584. {
  585.     FILE *fp;
  586.  
  587.     if ((fp = fopen(SAVEFILE, "r")) != NULL) {
  588.     fclose(fp);
  589.     return TRUE;
  590.     } else {
  591.     return FALSE;
  592.     }
  593. }
  594.