00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <config.h>
00036
00037
00038
00039 static int ORE = 1;
00040 static int quiet = 0;
00041
00042
00043
00044 #define DEFAULT_SPIKE 10
00045 #define DEFAULT_MOUNTAIN 0
00046 #define DEFAULT_CONTDIST 2
00047 #define DEFAULT_ISLDIST 1
00048
00049
00050
00051
00052
00053
00054
00055 #define FERT_MAX 56
00056
00057
00058 #define OIL_MAX 33
00059
00060
00061 #define IRON_MIN 22
00062
00063
00064 #define GOLD_MIN 36
00065
00066
00067 #define URAN_MIN 56
00068
00069 #include <stdarg.h>
00070 #include <stdio.h>
00071 #include <unistd.h>
00072 #include "file.h"
00073 #include "misc.h"
00074 #include "nat.h"
00075 #include "optlist.h"
00076 #include "power.h"
00077 #include "prototypes.h"
00078 #include "sect.h"
00079 #include "version.h"
00080 #include "xy.h"
00081
00082
00083 #define LANDMIN 1
00084 #define HILLMIN 34
00085 #define PLATMIN 36
00086 #define HIGHMIN 98
00087
00088 static void qprint(const char * const fmt, ...)
00089 ATTRIBUTE((format (printf, 1, 2)));
00090
00091 #define DEFAULT_OUTFILE_NAME "newcap_script"
00092 static const char *outfile = DEFAULT_OUTFILE_NAME;
00093
00094
00095 static int AIRPORT_MARKER = 0;
00096
00097
00098
00099 static int DISTINCT_ISLANDS = 1;
00100
00101 static char *program_name;
00102
00103 #define XSIZE ((WORLD_X) / 2)
00104 #define YSIZE (WORLD_Y)
00105 #define STABLE_CYCLE 4
00106 #define INFINITY 999
00107
00108
00109
00110
00111 #define COAST_SEARCH_MAX 200
00112
00113 #define DRIFT_BEFORE_CHECK ((WORLD_X + WORLD_Y)/2)
00114 #define DRIFT_MAX ((WORLD_X + WORLD_Y)*2)
00115 #define MOUNTAIN_SEARCH_MAX 1000
00116
00117
00118
00119
00120 #define new_x(newx) (((newx) + WORLD_X) % WORLD_X)
00121 #define new_y(newy) (((newy) + WORLD_Y) % WORLD_Y)
00122 #define rnd(x) (random() % (x))
00123
00124 int secs;
00125 int ctot;
00126 int *isecs;
00127
00128 int nc, sc, di, sp, pm, ni, is, id;
00129 unsigned long rnd_seed;
00130 int *capx, *capy;
00131 int *mc, mcc;
00132
00133 int spike;
00134 int mind;
00135
00136 int dirx[] = { -2, -1, 1, 2, 1, -1 };
00137 int diry[] = { 0, -1, -1, 0, 1, 1 };
00138
00139 int **own;
00140 int **elev;
00141 int **sectx, **secty;
00142 int **sectc;
00143 int *vector;
00144 int *weight;
00145 int *dsea, *dmoun;
00146 FILE *sect_fptr;
00147 struct sctstr **sects;
00148 struct sctstr *sectsbuf;
00149 int fl_status;
00150 #define STATUS_NO_ROOM 1
00151 #define NUMTRIES 10
00152
00153 const char *numletter =
00154 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
00155
00156 static void help(char *);
00157 static void usage(void);
00158 static void parse_args(int argc, char *argv[]);
00159 static int allocate_memory(void);
00160 static void init(void);
00161 static int drift(void);
00162 static void grow_continents(void);
00163 static void create_elevations(void);
00164 static void write_sects(void);
00165 static int write_file(void);
00166 static void output(void);
00167 static int write_newcap_script(void);
00168 static int stable(void);
00169 static void elevate_land(void);
00170 static void elevate_sea(void);
00171 static int map_symbol(int x, int y);
00172 static void fl_sct_init(coord, coord, struct sctstr *);
00173 static void set_coastal_flags(void);
00174
00175 static void print_vars(void);
00176 static void fl_move(int);
00177 static void next_coast(int c, int x, int y, int *xp, int *yp);
00178 static void grow_islands(void);
00179
00180
00181
00182
00183
00184 int
00185 main(int argc, char *argv[])
00186 {
00187 int opt;
00188 char *config_file = NULL;
00189 int i = 0;
00190
00191 program_name = argv[0];
00192 rnd_seed = time(NULL);
00193
00194 while ((opt = getopt(argc, argv, "ae:hioqR:s:v")) != EOF) {
00195 switch (opt) {
00196 case 'a':
00197 AIRPORT_MARKER = 1;
00198 break;
00199 case 'e':
00200 config_file = optarg;
00201 break;
00202 case 'i':
00203 DISTINCT_ISLANDS = 0;
00204 break;
00205 case 'o':
00206 ORE = 0;
00207 break;
00208 case 'q':
00209 quiet = 1;
00210 break;
00211 case 'R':
00212 rnd_seed = strtoul(optarg, NULL, 10);
00213 break;
00214 case 's':
00215 outfile = optarg;
00216 break;
00217 case 'h':
00218 usage();
00219 exit(0);
00220 case 'v':
00221 printf("%s\n\n%s", version, legal);
00222 exit(0);
00223 default:
00224 help(NULL);
00225 exit(1);
00226 }
00227 }
00228 srandom(rnd_seed);
00229 if (emp_config(config_file))
00230 exit(1);
00231
00232 parse_args(argc - optind, argv + optind);
00233 if (allocate_memory() == -1)
00234 exit(-1);
00235 print_vars();
00236
00237 do {
00238 init();
00239 if (i)
00240 qprint("\ntry #%d (out of %d)...", i + 1, NUMTRIES);
00241 qprint("\n\n #*# ...fairland rips open a rift in the datumplane... #*#\n\n");
00242 qprint("seed is %lu\n", rnd_seed);
00243 qprint("placing capitals...\n");
00244 if (!drift())
00245 qprint("fairland: unstable drift -- try increasisg DRIFT_MAX\n");
00246 qprint("growing continents...\n");
00247 grow_continents();
00248 } while (fl_status && ++i < NUMTRIES);
00249 if (fl_status) {
00250 fputs("ERROR: World not large enough to hold continents\n",
00251 stderr);
00252 exit(1);
00253 }
00254 qprint("growing islands:");
00255 grow_islands();
00256 qprint("\nelevating land...\n");
00257 create_elevations();
00258 qprint("designating sectors...\n");
00259 if (ORE)
00260 qprint("adding resources...\n");
00261 write_sects();
00262 qprint("writing to sectors file...\n");
00263 if (write_file() == -1)
00264 exit(-1);
00265 output();
00266 write_newcap_script();
00267 if (!ORE)
00268 qprint("\t*** Resources have not been added ***\n");
00269 exit(0);
00270 }
00271
00272 static void
00273 print_vars(void)
00274 {
00275 if (quiet)
00276 return;
00277 puts("Creating a planet with:\n");
00278 printf("%d continents\n", nc);
00279 printf("continent size: %d\n", sc);
00280 printf("number of islands: %d\n", ni);
00281 printf("average size of islands: %d\n", is);
00282 printf("spike: %d%%\n", sp);
00283 printf("%d%% of land is mountain (each continent will have %d mountains)\n",
00284 pm, (pm * sc) / 100);
00285 printf("minimum distance between continents: %d\n", di);
00286 printf("minimum distance from islands to continents: %d\n", id);
00287 printf("World dimensions: %dx%d\n", WORLD_X, WORLD_Y);
00288 }
00289
00290 static int
00291 my_sqrt(int n)
00292 {
00293 int i;
00294
00295 for (i = 1; i * i < n * 10000; ++i) ;
00296 return (i + 50) / 100;
00297 }
00298
00299
00300
00301
00302
00303 static void
00304 help(char *complaint)
00305 {
00306 if (complaint)
00307 fprintf(stderr, "%s: %s\n", program_name, complaint);
00308 fprintf(stderr, "Try -h for help.\n");
00309 }
00310
00311 static void
00312 usage(void)
00313 {
00314 printf("Usage: %s [OPTION]... NC SC [NI] [IS] [SP] [PM] [DI] [ID]\n"
00315 " -a airport marker for continents\n"
00316 " -e CONFIG-FILE configuration file\n"
00317 " (default %s)\n"
00318 " -h display this help and exit\n"
00319 " -i islands may merge\n"
00320 " -o don't set resources\n"
00321 " -q quiet\n"
00322 " -R SEED seed for random number generator\n"
00323 " -s SCRIPT name of script to create (default %s)\n"
00324 " NC number of continents\n"
00325 " SC continent size\n"
00326 " NI number of islands (default NC)\n"
00327 " IS average island size (default SC/2)\n"
00328 " SP spike percentage: 0 = round, 100 = snake (default %d)\n"
00329 " PM percentage of land that is mountain (default %d)\n"
00330 " DI minimum distance between continents (default %d)\n"
00331 " ID minimum distance from islands to continents (default %d)\n",
00332 program_name, dflt_econfig, DEFAULT_OUTFILE_NAME,
00333 DEFAULT_SPIKE, DEFAULT_MOUNTAIN, DEFAULT_CONTDIST, DEFAULT_ISLDIST);
00334 }
00335
00336 static void
00337 parse_args(int argc, char *argv[])
00338 {
00339 if (argc < 2) {
00340 help("missing arguments");
00341 exit(1);
00342 }
00343 if (argc > 8) {
00344 help("too many arguments");
00345 exit(1);
00346 }
00347 nc = atoi(argv[0]);
00348 if (nc < 1) {
00349 puts("fairland: error -- number of continents must be > 0");
00350 exit(1);
00351 }
00352
00353 sc = atoi(argv[1]);
00354 if (sc < 1) {
00355 puts("fairland: error -- size of continents must be > 0");
00356 exit(1);
00357 }
00358
00359 if (argc > 2)
00360 ni = atoi(argv[2]);
00361 else
00362 ni = nc;
00363
00364 if (argc > 3)
00365 is = atoi(argv[3]);
00366 else
00367 is = sc / 2;
00368 if (is < 0)
00369 is = 0;
00370
00371 if (argc > 4)
00372 sp = atoi(argv[4]);
00373 else
00374 sp = DEFAULT_SPIKE;
00375 if (sp < 0)
00376 sp = 0;
00377 if (sp > 100)
00378 sp = 100;
00379
00380 if (argc > 5)
00381 pm = atoi(argv[5]);
00382 else
00383 pm = DEFAULT_MOUNTAIN;
00384 if (pm < 0)
00385 pm = 0;
00386
00387 if (argc > 6)
00388 di = atoi(argv[6]);
00389 else
00390 di = DEFAULT_CONTDIST;
00391
00392 if (di < 0) {
00393 puts("fairland: error -- distance between continents must be >= 0");
00394 exit(1);
00395 }
00396 if (di > WORLD_X / 2 || di > WORLD_Y / 2) {
00397 puts("fairland: error -- distance between continents too large");
00398 exit(1);
00399 }
00400
00401 if (argc > 7)
00402 id = atoi(argv[7]);
00403 else
00404 id = DEFAULT_ISLDIST;
00405 if (id < 0) {
00406 puts("fairland: error -- distance from islands to continents must be >= 0");
00407 exit(1);
00408 }
00409 if (id > WORLD_X || id > WORLD_Y) {
00410 puts("fairland: error -- distance from islands to continents too large");
00411 exit(1);
00412 }
00413 if (nc * sc + nc * my_sqrt(sc) * 2 * (di + 1) > WORLD_X * WORLD_Y) {
00414 puts("fairland: error -- world not big enough to fit continents.");
00415 puts("arguments must satisfy:");
00416 puts("nc*sc*sc + nc*sqrt(sc)*2*(di+1) < WORLD_X * WORLD_Y");
00417 exit(1);
00418 }
00419 }
00420
00421
00422
00423
00424
00425 static int
00426 allocate_memory(void)
00427 {
00428 int i;
00429 char *fname;
00430
00431 fname = malloc(strlen(gamedir) + 1 + strlen(empfile[EF_SECTOR].file) + 1);
00432 sprintf(fname, "%s/%s", gamedir, empfile[EF_SECTOR].file);
00433 sect_fptr = fopen(fname, "wb");
00434 if (sect_fptr == NULL) {
00435 perror(fname);
00436 return -1;
00437 }
00438 free(fname);
00439 sectsbuf = calloc((YSIZE * XSIZE), sizeof(struct sctstr));
00440 sects = calloc(YSIZE, sizeof(struct sctstr *));
00441 for (i = 0; i < YSIZE; i++)
00442 sects[i] = §sbuf[XSIZE * i];
00443 capx = calloc(nc, sizeof(int));
00444 capy = calloc(nc, sizeof(int));
00445 vector = calloc(WORLD_X + WORLD_Y, sizeof(int));
00446 mc = calloc(STABLE_CYCLE, sizeof(int));
00447 own = calloc(WORLD_X, sizeof(int *));
00448 elev = calloc(WORLD_X, sizeof(int *));
00449 for (i = 0; i < WORLD_X; ++i) {
00450 own[i] = calloc(WORLD_Y, sizeof(int));
00451 elev[i] = calloc(WORLD_Y, sizeof(int));
00452 }
00453 sectx = calloc(nc + ni, sizeof(int *));
00454 secty = calloc(nc + ni, sizeof(int *));
00455 sectc = calloc(nc + ni, sizeof(int *));
00456 isecs = calloc(nc + ni, sizeof(int));
00457 weight = calloc(MAX(sc, is * 2), sizeof(int));
00458 dsea = calloc(MAX(sc, is * 2), sizeof(int));
00459 dmoun = calloc(MAX(sc, is * 2), sizeof(int));
00460 for (i = 0; i < nc; ++i) {
00461 sectx[i] = calloc(sc, sizeof(int));
00462 secty[i] = calloc(sc, sizeof(int));
00463 sectc[i] = calloc(sc, sizeof(int));
00464 }
00465 for (i = nc; i < nc + ni; ++i) {
00466 sectx[i] = calloc(is * 2, sizeof(int));
00467 secty[i] = calloc(is * 2, sizeof(int));
00468 sectc[i] = calloc(is * 2, sizeof(int));
00469 }
00470
00471 return 0;
00472 }
00473
00474 static void
00475 init(void)
00476 {
00477 int i, j, xx = 0, yy = 0;
00478
00479 mcc = 0;
00480 fl_status = 0;
00481
00482 for (i = 0; i < WORLD_X; ++i) {
00483 for (j = 0; j < WORLD_Y; ++j) {
00484 own[i][j] = -1;
00485 elev[i][j] = -INFINITY;
00486 }
00487 }
00488
00489 for (i = 0; i < nc; ++i, xx += 2) {
00490 if (xx >= WORLD_X) {
00491 ++yy;
00492 xx = yy % 2;
00493 if (yy == WORLD_Y) {
00494 puts("fairland error: world not big enough for all the continents.\n");
00495 exit(1);
00496 }
00497 }
00498 capx[i] = xx;
00499 capy[i] = yy;
00500 }
00501 for (i = 0; i < STABLE_CYCLE; ++i)
00502 mc[i] = i;
00503 }
00504
00505
00506
00507
00508
00509
00510
00511 static int
00512 iso(int j, int newx, int newy)
00513 {
00514 int i, md, d = WORLD_X + WORLD_Y;
00515
00516 for (i = 0; i < nc; ++i) {
00517 if (i == j)
00518 continue;
00519 md = mapdist(capx[i], capy[i], newx, newy);
00520 if (md < d)
00521 d = md;
00522 }
00523
00524 return d;
00525 }
00526
00527
00528
00529 static int
00530 drift(void)
00531 {
00532 int i, turns;
00533
00534 for (turns = 0; turns < DRIFT_MAX; ++turns) {
00535 if (turns > DRIFT_BEFORE_CHECK && (mind = stable()))
00536 return 1;
00537 for (i = 0; i < nc; ++i)
00538 fl_move(i);
00539 }
00540 return 0;
00541 }
00542
00543
00544
00545
00546 static int
00547 stable(void)
00548 {
00549 int i, isod, d = 0, stab = 1;
00550
00551 for (i = 0; i < nc; ++i) {
00552 isod = iso(i, capx[i], capy[i]);
00553 if (isod > d)
00554 d = isod;
00555 }
00556 for (i = 0; i < STABLE_CYCLE; ++i)
00557 if (d != mc[i])
00558 stab = 0;
00559 mc[mcc] = d;
00560 mcc = (mcc + 1) % STABLE_CYCLE;
00561 return stab ? d : 0;
00562 }
00563
00564
00565
00566
00567 static void
00568 fl_move(int j)
00569 {
00570 int i, n, newx, newy;
00571
00572 for (i = rnd(6), n = 0; n < 6; i = (i + 1) % 6, ++n) {
00573 newx = new_x(capx[j] + dirx[i]);
00574 newy = new_y(capy[j] + diry[i]);
00575 if (iso(j, newx, newy) >= iso(j, capx[j], capy[j])) {
00576 capx[j] = newx;
00577 capy[j] = newy;
00578 return;
00579 }
00580 }
00581 }
00582
00583
00584
00585
00586
00587
00588
00589
00590 static void
00591 find_coast(int c)
00592 {
00593 int i, j;
00594
00595 for (i = 0; i < secs; ++i) {
00596 sectc[c][i] = 0;
00597 for (j = 0; j < 6; ++j)
00598 if (own[new_x(sectx[c][i] + dirx[j])][new_y(secty[c][i] + diry[j])] == -1)
00599 sectc[c][i] = 1;
00600 }
00601 }
00602
00603
00604
00605 static int
00606 next_vector(int n)
00607 {
00608 int i;
00609
00610 if (n == 1) {
00611 vector[0] += 1;
00612 vector[0] %= 6;
00613 return vector[0];
00614 }
00615 for (i = 1; i < n && vector[i] == vector[i - 1]; ++i) ;
00616 vector[i - 1] += 1;
00617 vector[i - 1] %= 6;
00618 return i > 1 || vector[0] > 0;
00619 }
00620
00621
00622
00623 static int
00624 try_to_grow(int c, int newx, int newy, int d)
00625 {
00626 int i, j, px, py;
00627
00628 for (i = 1; i <= d; ++i) {
00629 for (j = 0; j < i; ++j)
00630 vector[j] = 0;
00631 do {
00632 px = newx;
00633 py = newy;
00634 for (j = 0; j < i; ++j) {
00635 px = new_x(px + dirx[vector[j]]);
00636 py = new_y(py + diry[vector[j]]);
00637 }
00638 if (own[px][py] != -1 &&
00639 own[px][py] != c &&
00640 (DISTINCT_ISLANDS || own[px][py] < nc))
00641 return 0;
00642 } while (next_vector(i));
00643 }
00644 sectx[c][secs] = newx;
00645 secty[c][secs] = newy;
00646 own[newx][newy] = c;
00647 return 1;
00648 }
00649
00650
00651
00652
00653 static void
00654 next_coast(int c, int x, int y, int *xp, int *yp)
00655 {
00656 int i, nx, ny, wat = 0;
00657
00658 if (secs == 1) {
00659 *xp = x;
00660 *yp = y;
00661 return;
00662 }
00663
00664 for (i = 0; i < 12; ++i) {
00665 nx = new_x(x + dirx[i % 6]);
00666 ny = new_y(y + diry[i % 6]);
00667 if (own[nx][ny] == -1)
00668 wat = 1;
00669 if (wat && own[nx][ny] == c) {
00670 *xp = nx;
00671 *yp = ny;
00672 return;
00673 }
00674 }
00675 }
00676
00677
00678
00679
00680 static int
00681 new_try(int c)
00682 {
00683 int i, starti;
00684
00685 if (secs == 1) {
00686 if (sectc[c][0])
00687 return 0;
00688 } else {
00689 i = starti = (spike && sectc[c][secs - 1]) ? secs - 1 : rnd(secs);
00690 do {
00691 if (sectc[c][i])
00692 return i;
00693 i = (i + 1) % secs;
00694 } while (i != starti);
00695 if (c < nc) {
00696 printf("fairland: BUG -- couldn't find coast for continent %c, sector %d.\nPlease mail stevens@math.utoronto.ca.\n",
00697 c + 'a', secs);
00698 exit(1);
00699 } else
00700 return -1;
00701 }
00702 return -1;
00703 }
00704
00705
00706
00707
00708 static int
00709 grow_one_sector(int c)
00710 {
00711 int done, coast_search, try1, x, y, newx, newy, i, n, sx, sy;
00712
00713 spike = rnd(100) < sp;
00714 if ((try1 = new_try(c)) == -1)
00715 return 0;
00716 x = sx = sectx[c][try1];
00717 y = sy = secty[c][try1];
00718 coast_search = 0;
00719 done = 0;
00720 do {
00721 if (spike) {
00722 for (i = rnd(6), n = 0; n < 12 && !done; i = (i + 1) % 6, ++n) {
00723 newx = new_x(x + dirx[i]);
00724 newy = new_y(y + diry[i]);
00725 if (own[newx][newy] == -1 &&
00726 (n > 5 ||
00727 (own[new_x(x+dirx[(i+5)%6])][new_y(y+diry[(i+5)%6])] == -1 &&
00728 own[new_x(x+dirx[(i+1)%6])][new_y(y+diry[(i+1)%6])] == -1)))
00729 if (try_to_grow(c, newx, newy, c < nc ? di : id))
00730 done = 1;
00731 }
00732 } else
00733 for (i = rnd(6), n = 0; n < 6 && !done; i = (i + 1) % 6, ++n) {
00734 newx = new_x(x + dirx[i]);
00735 newy = new_y(y + diry[i]);
00736 if (own[newx][newy] == -1)
00737 if (try_to_grow(c, newx, newy, c < nc ? di : id))
00738 done = 1;
00739 }
00740 next_coast(c, x, y, &x, &y);
00741 ++coast_search;
00742 } while (!done && coast_search < COAST_SEARCH_MAX &&
00743 (secs == 1 || x != sx || y != sy));
00744 if (!done && c < nc) {
00745 qprint("fairland: error -- continent %c had no room to grow!\n",
00746 numletter[c % 62]);
00747 fl_status |= STATUS_NO_ROOM;
00748 }
00749 return done;
00750 }
00751
00752
00753
00754 static void
00755 grow_continents(void)
00756 {
00757 int c;
00758
00759 for (c = 0; c < nc; ++c) {
00760 sectx[c][0] = capx[c];
00761 secty[c][0] = capy[c];
00762 own[sectx[c][0]][secty[c][0]] = c;
00763 sectx[c][1] = new_x(capx[c] + 2);
00764 secty[c][1] = capy[c];
00765 own[sectx[c][1]][secty[c][1]] = c;
00766 }
00767
00768 for (secs = 2; secs < sc && !fl_status; ++secs) {
00769 for (c = 0; c < nc; ++c) {
00770 find_coast(c);
00771 grow_one_sector(c);
00772 }
00773 }
00774 for (c = 0; c < nc; ++c)
00775 find_coast(c);
00776
00777 if (fl_status)
00778 qprint("Only managed to grow %d out of %d sectors.\n", secs, sc);
00779 ctot = nc;
00780 }
00781
00782
00783
00784
00785
00786
00787
00788 static int
00789 place_island(int c, int *xp, int *yp)
00790 {
00791 int d, sx, sy;
00792 int ssy = rnd(WORLD_Y);
00793 int ssx = new_x(rnd(WORLD_X / 2) * 2 + ssy % 2);
00794
00795 if (ssx > WORLD_X - 2)
00796 ssx = new_x(ssx + 2);
00797 for (d = di + id; d >= id; --d) {
00798 sx = ssx;
00799 sy = ssy;
00800 *xp = new_x(sx + 2);
00801 for (*yp = sy; *xp != sx || *yp != sy; *xp += 2) {
00802 if (*xp >= WORLD_X) {
00803 *yp = new_y(*yp + 1);
00804 *xp = *yp % 2;
00805 if (*xp == sx && *yp == sy)
00806 break;
00807 }
00808 if (own[*xp][*yp] == -1 && try_to_grow(c, *xp, *yp, d))
00809 return 1;
00810 }
00811 }
00812 return 0;
00813 }
00814
00815
00816
00817
00818 static void
00819 grow_islands(void)
00820 {
00821 int c, x, y, isiz;
00822
00823 for (c = nc; c < nc + ni; ++c) {
00824 secs = 0;
00825 if (!place_island(c, &x, &y))
00826 return;
00827 isiz = 1 + rnd(2 * is - 1);
00828 do {
00829 ++secs;
00830 find_coast(c);
00831 } while (secs < isiz && grow_one_sector(c));
00832 find_coast(c);
00833 qprint(" %d(%d)", c - nc + 1, secs);
00834 isecs[c] = secs;
00835 ctot = c;
00836 }
00837 }
00838
00839
00840
00841
00842 static void
00843 create_elevations(void)
00844 {
00845 elevate_land();
00846 elevate_sea();
00847 }
00848
00849
00850
00851
00852 static int
00853 distance_to_what(int x, int y, int flag)
00854 {
00855 int j, d, px, py;
00856
00857 for (d = 1; d < 5; ++d) {
00858 for (j = 0; j < d; ++j)
00859 vector[j] = 0;
00860 do {
00861 px = x;
00862 py = y;
00863 for (j = 0; j < d; ++j) {
00864 px = new_x(px + dirx[vector[j]]);
00865 py = new_y(py + diry[vector[j]]);
00866 }
00867 switch (flag) {
00868 case 0:
00869 if (own[px][py] == -1)
00870 return d;
00871 break;
00872 case 1:
00873 if (own[px][py] != -1)
00874 return d;
00875 break;
00876 case 2:
00877 if (elev[px][py] == INFINITY)
00878 return d;
00879 break;
00880 }
00881 } while (next_vector(d));
00882 }
00883 return d;
00884 }
00885
00886 #define ELEV elev[sectx[c][i]][secty[c][i]]
00887 #define distance_to_sea() (sectc[c][i]?1:distance_to_what(sectx[c][i], secty[c][i], 0))
00888 #define distance_to_mountain() distance_to_what(sectx[c][i], secty[c][i], 2)
00889
00890
00891
00892 static void
00893 elevate_land(void)
00894 {
00895 int i, mountain_search, k, c, total, ns, nm, highest, where, h, newk,
00896 r, dk;
00897
00898 for (c = 0; c < ctot; ++c) {
00899 total = 0;
00900 ns = (c < nc) ? sc : isecs[c];
00901 nm = (pm * ns) / 100;
00902
00903
00904
00905 for (i = 0; i < ns; ++i) {
00906 dsea[i] = distance_to_sea();
00907 weight[i] = (total += (dsea[i] * dsea[i]));
00908 }
00909
00910 for (k = nm, mountain_search = 0;
00911 k && mountain_search < MOUNTAIN_SEARCH_MAX;
00912 ++mountain_search) {
00913 r = rnd(total);
00914 for (i = 0; i < ns; ++i)
00915 if (r < weight[i] && ELEV == -INFINITY &&
00916 (c >= nc ||
00917 ((!(capx[c] == sectx[c][i] &&
00918 capy[c] == secty[c][i])) &&
00919 (!(new_x(capx[c] + 2) == sectx[c][i] &&
00920 capy[c] == secty[c][i]))))) {
00921 ELEV = INFINITY;
00922 break;
00923 }
00924 --k;
00925 }
00926
00927
00928
00929 for (i = 0; i < ns; ++i)
00930 dmoun[i] = distance_to_mountain();
00931 dk = (ns - nm - ((c < nc) ? 3 : 1) > 0) ?
00932 (100 * (HIGHMIN - LANDMIN)) / (ns - nm - ((c < nc) ? 3 : 1)) :
00933 100 * INFINITY;
00934 for (k = 100 * (HIGHMIN - 1);; k -= dk) {
00935 highest = -INFINITY;
00936 where = -1;
00937 for (i = 0; i < ns; ++i) {
00938 if (ELEV != INFINITY &&
00939 (c >= nc || ((!(capx[c] == sectx[c][i] &&
00940 capy[c] == secty[c][i])) &&
00941 (!(new_x(capx[c] + 2) == sectx[c][i] &&
00942 capy[c] == secty[c][i]))))) {
00943 h = 3 * (5 - dmoun[i]) + dsea[i];
00944 if (h > highest) {
00945 highest = h;
00946 where = i;
00947 }
00948 }
00949 }
00950 if (where == -1)
00951 break;
00952 newk = k / 100;
00953 if (newk >= HILLMIN && newk < PLATMIN)
00954 newk = PLATMIN;
00955 if (newk < LANDMIN)
00956 newk = LANDMIN;
00957 elev[sectx[c][where]][secty[c][where]] = newk;
00958 dsea[where] = -INFINITY;
00959 dmoun[where] = INFINITY;
00960 }
00961
00962
00963
00964 for (i = 0; i < ns; ++i) {
00965 if (ELEV == INFINITY) {
00966 if (dsea[i] == 1)
00967 ELEV = HILLMIN + rnd(PLATMIN - HILLMIN);
00968 else
00969 ELEV = HIGHMIN + rnd((256 - HIGHMIN) / 2) +
00970 rnd((256 - HIGHMIN) / 2);
00971 } else if ((c < nc &&
00972 ((capx[c] == sectx[c][i] && capy[c] == secty[c][i]))) ||
00973 ((new_x(capx[c] + 2) == sectx[c][i] &&
00974 capy[c] == secty[c][i])))
00975 ELEV = PLATMIN;
00976 }
00977 }
00978 }
00979
00980 #define distance_to_land() distance_to_what(x, y, 1)
00981
00982 static void
00983 elevate_sea(void)
00984 {
00985 int x, y;
00986
00987 for (y = 0; y < WORLD_Y; ++y) {
00988 for (x = y % 2; x < WORLD_X; x += 2) {
00989 if (elev[x][y] == -INFINITY)
00990 elev[x][y] = -rnd((distance_to_land() * 20 + 27)) - 1;
00991 }
00992 }
00993 }
00994
00995
00996
00997
00998
00999 static int
01000 set_fert(int e)
01001 {
01002 int fert = 0;
01003 if (e < LANDMIN)
01004 fert = LANDMIN - e + 40;
01005 else if (e < FERT_MAX)
01006 fert = (120 * (FERT_MAX - e)) / (FERT_MAX - LANDMIN);
01007 if (fert > 100)
01008 fert = 100;
01009 return fert;
01010 }
01011
01012 static int
01013 set_oil(int e)
01014 {
01015 int oil = 0;
01016 if (e < LANDMIN)
01017 oil = (LANDMIN - e) * 2 + rnd(2);
01018 else if (e <= OIL_MAX)
01019 oil = (120 * (OIL_MAX - e + 1)) / (OIL_MAX - LANDMIN + 1);
01020 if (oil > 100)
01021 oil = 100;
01022 return oil;
01023 }
01024
01025 static int
01026 set_iron(int e)
01027 {
01028 int iron = 0;
01029 if (e >= IRON_MIN && e < HIGHMIN)
01030 iron = (120 * (e - IRON_MIN + 1)) / (HIGHMIN - IRON_MIN);
01031 if (iron > 100)
01032 iron = 100;
01033 return iron;
01034 }
01035
01036 static int
01037 set_gold(int e)
01038 {
01039 int gold = 0;
01040 if (e >= GOLD_MIN) {
01041 if (e < HIGHMIN)
01042 gold = (80 * (e - GOLD_MIN + 1)) / (HIGHMIN - GOLD_MIN);
01043 else
01044 gold = 100 - 20 * HIGHMIN / e;
01045 }
01046 if (gold > 100)
01047 gold = 100;
01048 return gold;
01049 }
01050
01051 static int
01052 set_uran(int e)
01053 {
01054 int uran = 0;
01055 if (e >= URAN_MIN && e < HIGHMIN)
01056 uran = (120 * (e - URAN_MIN + 1)) / (HIGHMIN - URAN_MIN);
01057 if (uran > 100)
01058 uran = 100;
01059 return uran;
01060 }
01061
01062 static void
01063 add_resources(struct sctstr *sct)
01064 {
01065 sct->sct_fertil = set_fert(sct->sct_elev);
01066 sct->sct_oil = set_oil(sct->sct_elev);
01067 sct->sct_min = set_iron(sct->sct_elev);
01068 sct->sct_gmin = set_gold(sct->sct_elev);
01069 sct->sct_uran = set_uran(sct->sct_elev);
01070 }
01071
01072
01073
01074
01075
01076 static void
01077 write_sects(void)
01078 {
01079 struct sctstr *sct;
01080 int c, x, y, total;
01081
01082
01083 sct = sectsbuf;
01084 for (y = 0; y < YSIZE; y++) {
01085 for (x = 0; x < XSIZE; x++, sct++) {
01086 fl_sct_init(x * 2 + (y & 1), y, sct);
01087 total = elev[sct->sct_x][y];
01088 if (total < LANDMIN) {
01089 sct->sct_type = SCT_WATER;
01090 } else if (total < HILLMIN)
01091 sct->sct_type = SCT_RURAL;
01092 else if (total < PLATMIN)
01093 sct->sct_type = SCT_MOUNT;
01094 else if (total < HIGHMIN)
01095 sct->sct_type = SCT_RURAL;
01096 else
01097 sct->sct_type = SCT_MOUNT;
01098 sct->sct_elev = total;
01099 sct->sct_newtype = sct->sct_type;
01100 if (ORE)
01101 add_resources(sct);
01102 }
01103 }
01104 if (AIRPORT_MARKER)
01105 for (c = 0; c < nc; ++c) {
01106 sects[capy[c]][capx[c] / 2 + capy[c] % 2].sct_type = SCT_AIRPT;
01107 sects[capy[c]][capx[c] / 2 + capy[c] % 2].sct_newtype = SCT_AIRPT;
01108 }
01109 set_coastal_flags();
01110 }
01111
01112
01113
01114
01115 static int
01116 write_file(void)
01117 {
01118 int n;
01119
01120 n = fwrite(sectsbuf, sizeof(struct sctstr), YSIZE * XSIZE, sect_fptr);
01121 if (n <= 0) {
01122 perror(empfile[EF_SECTOR].file);
01123 return -1;
01124 }
01125 if (n != YSIZE * XSIZE) {
01126 printf("%s:partial write\n", empfile[EF_SECTOR].file);
01127 return -1;
01128 }
01129 fclose(sect_fptr);
01130 return 0;
01131 }
01132
01133
01134
01135
01136 static void
01137 output(void)
01138 {
01139 int i, j;
01140 if (quiet == 0) {
01141 for (i = 0; i < WORLD_Y; ++i) {
01142 puts("");
01143 if (i % 2)
01144 printf(" ");
01145 for (j = i % 2; j < WORLD_X; j += 2) {
01146 if (own[j][i] == -1)
01147 printf(". ");
01148 else {
01149 printf("%c ", map_symbol(j, i));
01150 }
01151 }
01152 }
01153 }
01154 if (AIRPORT_MARKER)
01155 printf("\n\nEach continent is marked by a \"*\" on the map (to distinguish them from\nthe islands). You can redesignate these airfields to wilderness sectors\none at a time, each time you add a new country to the game.\n");
01156 }
01157
01158 static int
01159 map_symbol(int x, int y)
01160 {
01161 int c, iscap = 0;
01162
01163 for (c = 0; c < nc; ++c)
01164 if ((x == capx[c] && y == capy[c])
01165 || (x == new_x(capx[c] + 2) && y == capy[c]))
01166 iscap = 1;
01167 if ((elev[x][y] >= HILLMIN && elev[x][y] < PLATMIN)
01168 || elev[x][y] >= HIGHMIN)
01169 return '^';
01170 return own[x][y] >= nc ? '%' : iscap ? '#' : numletter[own[x][y] % 62];
01171 }
01172
01173
01174
01175
01176 static int
01177 write_newcap_script(void)
01178 {
01179 int c;
01180 FILE *script = fopen(outfile, "w");
01181
01182 if (!script) {
01183 printf("fairland: error, unable to write to %s.\n", outfile);
01184 return -1;
01185 }
01186
01187 for (c = 0; c < nc; ++c) {
01188 fprintf(script, "add %d %d %d n i\n", c + 1, c + 1, c + 1);
01189 if (AIRPORT_MARKER)
01190 fprintf(script, "des %d,%d -\n", capx[c], capy[c]);
01191 fprintf(script, "newcap %d %d,%d\n", c + 1, capx[c], capy[c]);
01192 }
01193 fprintf(script, "add %d visitor visitor v i\n", c + 1);
01194 ++c;
01195 fclose(script);
01196 qprint("\n\nA script for adding all the countries can be found in \"%s\".\n",
01197 outfile);
01198 return 0;
01199 }
01200
01201 static void
01202 qprint(const char * const fmt, ...)
01203 {
01204 va_list ap;
01205
01206 if (!quiet) {
01207 va_start(ap, fmt);
01208 vfprintf(stdout, fmt, ap);
01209 va_end(ap);
01210 }
01211 }
01212
01213 static void
01214 fl_sct_init(coord x, coord y, struct sctstr *sp)
01215 {
01216 sp->ef_type = EF_SECTOR;
01217 sp->sct_x = x;
01218 sp->sct_y = y;
01219 sp->sct_dist_x = x;
01220 sp->sct_dist_y = y;
01221 sp->sct_road = 0;
01222 sp->sct_rail = 0;
01223 sp->sct_defense = 0;
01224 sp->sct_coastal = 1;
01225 }
01226
01227 static void
01228 set_coastal_flags(void)
01229 {
01230 int i, j;
01231
01232 qprint("setting coastal flags...\n");
01233 for (i = 0; i < nc; ++i)
01234 for (j = 0; j < sc; j++)
01235 sects[secty[i][j]][sectx[i][j] / 2].sct_coastal = sectc[i][j];
01236 for (i = nc; i < nc + ni; ++i)
01237 for (j = 0; j < isecs[i]; j++)
01238 sects[secty[i][j]][sectx[i][j] / 2].sct_coastal = sectc[i][j];
01239 }