]> git.pond.sub.org Git - empserver/blob - src/util/fairland.c
2628f9d73450cefc92786cf8d41bc6f2a442eaab
[empserver] / src / util / fairland.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2010, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  fairland.c: Create a nice, new world
29  *
30  *  Known contributors to this file:
31  *     Ken Stevens, 1995
32  *     Steve McClure, 1998
33  */
34
35 #include <config.h>
36
37 /* define ORE 1 to add resources, define ORE 0 if you want to use another
38    program to add the resources */
39 static int ORE = 1;
40 static int quiet = 0;
41
42 /* If you don't specify these command line arguments, then these are the
43    defaults */
44 #define DEFAULT_SPIKE 10
45 #define DEFAULT_MOUNTAIN 0
46 #define DEFAULT_CONTDIST 2
47 #define DEFAULT_ISLDIST 1
48
49 /* The following five numbers refer to elevation under which (in the case of
50    fertility or oil) or over which (in the case of iron, gold, and uranium)
51    sectors with that elevation will contain that resource.  Elevation ranges
52    from 0 to 100 */
53
54 /* raise FERT_MAX for more fertility */
55 #define FERT_MAX   56
56
57 /* raise OIL_MAX for more oil */
58 #define OIL_MAX    33
59
60 /* lower IRON_MIN for more iron */
61 #define IRON_MIN   22
62
63 /* lower GOLD_MIN for more gold */
64 #define GOLD_MIN   36
65
66 /* lower URAN_MIN for more uranium */
67 #define URAN_MIN   56
68
69 #include <errno.h>
70 #include <stdarg.h>
71 #include <stdio.h>
72 #include <unistd.h>
73 #include "file.h"
74 #include "misc.h"
75 #include "nat.h"
76 #include "optlist.h"
77 #include "power.h"
78 #include "prototypes.h"
79 #include "sect.h"
80 #include "version.h"
81 #include "xy.h"
82
83 /* do not change these 4 defines */
84 #define LANDMIN         1       /* plate altitude for normal land */
85 #define HILLMIN         34      /* plate altitude for hills */
86 #define PLATMIN         36      /* plate altitude for plateau */
87 #define HIGHMIN         98      /* plate altitude for mountains */
88
89 static void qprint(const char * const fmt, ...)
90     ATTRIBUTE((format (printf, 1, 2)));
91
92 #define DEFAULT_OUTFILE_NAME "newcap_script"
93 static const char *outfile = DEFAULT_OUTFILE_NAME;
94 /* mark the continents with a * so you can tell them
95    from the islands 1 = mark, 0 = don't mark. */
96 static int AIRPORT_MARKER = 0;
97
98 /* don't let the islands crash into each other.
99    1 = don't merge, 0 = merge. */
100 static int DISTINCT_ISLANDS = 1;
101
102 static char *program_name;
103
104 #define STABLE_CYCLE 4          /* stability required for perterbed capitals */
105 #define INFINITY        999     /* a number which means "BIG" */
106
107 /* these defines prevent infinite loops:
108 */
109
110 #define COAST_SEARCH_MAX 200    /* how many times do we look for a coast sector
111                                    when growing continents and islands */
112 #define DRIFT_BEFORE_CHECK ((WORLD_X + WORLD_Y)/2)
113 #define DRIFT_MAX ((WORLD_X + WORLD_Y)*2)
114 #define MOUNTAIN_SEARCH_MAX 1000        /* how long do we try to place mountains */
115
116 /* handy macros:
117 */
118
119 #define new_x(newx) (((newx) + WORLD_X) % WORLD_X)
120 #define new_y(newy) (((newy) + WORLD_Y) % WORLD_Y)
121 #define rnd(x) (random() % (x))
122
123 static int secs;                /* number of sectors grown */
124 static int ctot;                /* total number of continents and islands grown */
125 static int *isecs;              /* array of how large each island is */
126
127 static int nc, sc, di, sp, pm, ni, is, id; /* the 8 args to this program */
128 static unsigned long rnd_seed;  /* optional seed argument */
129 static int *capx, *capy;        /* location of the nc capitals */
130 static int *mc, mcc;            /* array and counter used for stability
131                                    check when perturbing */
132 static int spike;               /* are we spiking? */
133 static int mind;                /* the final distance between capitals that
134                                    we achieved */
135 static int dirx[] = { -2, -1, 1, 2, 1, -1 }; /* gyujnb */
136 static int diry[] = { 0, -1, -1, 0, 1, 1 };
137
138 static int **own;               /* owner of the sector.  -1 means water */
139 static int **elev;              /* elevation of the sectors */
140 static int **sectx, **secty;    /* the sectors for each continent */
141 static int **sectc;             /* which sectors are on the coast? */
142 static int *vector;             /* used for measuring distances */
143 static int *weight;             /* used for placing mountains */
144 static int *dsea, *dmoun;       /* the dist to the ocean and mountain */
145 static int fl_status;           /* is anything wrong? */
146 #define STATUS_NO_ROOM 1        /* there was no room to grow */
147 #define NUMTRIES 10             /* keep trying to grow this many times */
148
149 static const char *numletter =
150     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
151
152 static void help(char *);
153 static void usage(void);
154 static void parse_args(int argc, char *argv[]);
155 static int allocate_memory(void);
156 static void init(void);
157 static int drift(void);
158 static void grow_continents(void);
159 static void create_elevations(void);
160 static void write_sects(void);
161 static void output(void);
162 static int write_newcap_script(void);
163 static int stable(void);
164 static void elevate_land(void);
165 static void elevate_sea(void);
166 static int map_symbol(int x, int y);
167 static void set_coastal_flags(void);
168
169 static void print_vars(void);
170 static void fl_move(int);
171 static void next_coast(int c, int x, int y, int *xp, int *yp);
172 static void grow_islands(void);
173
174 /****************************************************************************
175   MAIN
176 ****************************************************************************/
177
178 int
179 main(int argc, char *argv[])
180 {
181     int opt;
182     char *config_file = NULL;
183     int i = 0;
184
185     program_name = argv[0];
186     rnd_seed = time(NULL);
187
188     while ((opt = getopt(argc, argv, "ae:hioqR:s:v")) != EOF) {
189         switch (opt) {
190         case 'a':
191             AIRPORT_MARKER = 1;
192             break;
193         case 'e':
194             config_file = optarg;
195             break;
196         case 'i':
197             DISTINCT_ISLANDS = 0;
198             break;
199         case 'o':
200             ORE = 0;
201             break;
202         case 'q':
203             quiet = 1;
204             break;
205         case 'R':
206             rnd_seed = strtoul(optarg, NULL, 10);
207             break;
208         case 's':
209             outfile = optarg;
210             break;
211         case 'h':
212             usage();
213             exit(0);
214         case 'v':
215             printf("%s\n\n%s", version, legal);
216             exit(0);
217         default:
218             help(NULL);
219             exit(1);
220         }
221     }
222     parse_args(argc - optind, argv + optind);
223
224     srandom(rnd_seed);
225     empfile_init();
226     if (emp_config(config_file) < 0)
227         exit(1);
228     empfile_fixup();
229
230     if (allocate_memory() == -1)
231         exit(-1);
232     print_vars();
233
234     do {
235         init();
236         if (i)
237             qprint("\ntry #%d (out of %d)...", i + 1, NUMTRIES);
238         qprint("\n\n        #*# ...fairland rips open a rift in the datumplane... #*#\n\n");
239         qprint("seed is %lu\n", rnd_seed);
240         qprint("placing capitals...\n");
241         if (!drift())
242             qprint("fairland: unstable drift -- try increasisg DRIFT_MAX\n");
243         qprint("growing continents...\n");
244         grow_continents();
245     } while (fl_status && ++i < NUMTRIES);
246     if (fl_status) {
247         fputs("ERROR: World not large enough to hold continents\n",
248               stderr);
249         exit(1);
250     }
251     qprint("growing islands:");
252     grow_islands();
253     qprint("\nelevating land...\n");
254     create_elevations();
255     qprint("designating sectors...\n");
256     if (ORE)
257         qprint("adding resources...\n");
258     write_newcap_script();
259
260     if (chdir(gamedir)) {
261         fprintf(stderr, "Can't chdir to %s (%s)\n", gamedir, strerror(errno));
262         exit(EXIT_FAILURE);
263     }
264     if (!ef_open(EF_SECTOR, EFF_MEM | EFF_NOTIME, WORLD_SZ())) {
265         perror("ef_open");
266         exit(1);
267     }
268     write_sects();
269     qprint("writing to sectors file...\n");
270     if (!ef_close(EF_SECTOR))
271         exit(-1);
272
273     output();
274     qprint("\n\nA script for adding all the countries can be found in \"%s\".\n",
275            outfile);
276     if (!ORE)
277         qprint("\t*** Resources have not been added ***\n");
278     exit(0);
279 }
280
281 static void
282 print_vars(void)
283 {
284     if (quiet)
285         return;
286     puts("Creating a planet with:\n");
287     printf("%d continents\n", nc);
288     printf("continent size: %d\n", sc);
289     printf("number of islands: %d\n", ni);
290     printf("average size of islands: %d\n", is);
291     printf("spike: %d%%\n", sp);
292     printf("%d%% of land is mountain (each continent will have %d mountains)\n",
293            pm, (pm * sc) / 100);
294     printf("minimum distance between continents: %d\n", di);
295     printf("minimum distance from islands to continents: %d\n", id);
296     printf("World dimensions: %dx%d\n", WORLD_X, WORLD_Y);
297 }
298
299 static int
300 my_sqrt(int n)
301 {
302     int i;
303
304     for (i = 1; i * i < n * 10000; ++i) ;
305     return (i + 50) / 100;
306 }
307
308 /****************************************************************************
309   PARSE COMMAND LINE ARGUMENTS
310 ****************************************************************************/
311
312 static void
313 help(char *complaint)
314 {
315     if (complaint)
316         fprintf(stderr, "%s: %s\n", program_name, complaint);
317     fprintf(stderr, "Try -h for help.\n");
318 }
319
320 static void
321 usage(void)
322 {
323     printf("Usage: %s [OPTION]... NC SC [NI] [IS] [SP] [PM] [DI] [ID]\n"
324            "  -a              airport marker for continents\n"
325            "  -e CONFIG-FILE  configuration file\n"
326            "                  (default %s)\n"
327            "  -h              display this help and exit\n"
328            "  -i              islands may merge\n"
329            "  -o              don't set resources\n"
330            "  -q              quiet\n"
331            "  -R SEED         seed for random number generator\n"
332            "  -s SCRIPT       name of script to create (default %s)\n"
333            "  NC              number of continents\n"
334            "  SC              continent size\n"
335            "  NI              number of islands (default NC)\n"
336            "  IS              average island size (default SC/2)\n"
337            "  SP              spike percentage: 0 = round, 100 = snake (default %d)\n"
338            "  PM              percentage of land that is mountain (default %d)\n"
339            "  DI              minimum distance between continents (default %d)\n"
340            "  ID              minimum distance from islands to continents (default %d)\n",
341            program_name, dflt_econfig, DEFAULT_OUTFILE_NAME,
342            DEFAULT_SPIKE, DEFAULT_MOUNTAIN, DEFAULT_CONTDIST, DEFAULT_ISLDIST);
343 }
344
345 static void
346 parse_args(int argc, char *argv[])
347 {
348     if (argc < 2) {
349         help("missing arguments");
350         exit(1);
351     }
352     if (argc > 8) {
353         help("too many arguments");
354         exit(1);
355     }
356     nc = atoi(argv[0]);
357     if (nc < 1) {
358         puts("fairland: error -- number of continents must be > 0");
359         exit(1);
360     }
361
362     sc = atoi(argv[1]);
363     if (sc < 1) {
364         puts("fairland: error -- size of continents must be > 0");
365         exit(1);
366     }
367
368     if (argc > 2)
369         ni = atoi(argv[2]);
370     else
371         ni = nc;
372
373     if (argc > 3)
374         is = atoi(argv[3]);
375     else
376         is = sc / 2;
377     if (is < 0)
378         is = 0;
379
380     if (argc > 4)
381         sp = atoi(argv[4]);
382     else
383         sp = DEFAULT_SPIKE;
384     if (sp < 0)
385         sp = 0;
386     if (sp > 100)
387         sp = 100;
388
389     if (argc > 5)
390         pm = atoi(argv[5]);
391     else
392         pm = DEFAULT_MOUNTAIN;
393     if (pm < 0)
394         pm = 0;
395
396     if (argc > 6)
397         di = atoi(argv[6]);
398     else
399         di = DEFAULT_CONTDIST;
400
401     if (di < 0) {
402         puts("fairland: error -- distance between continents must be >= 0");
403         exit(1);
404     }
405     if (di > WORLD_X / 2 || di > WORLD_Y / 2) {
406         puts("fairland: error -- distance between continents too large");
407         exit(1);
408     }
409
410     if (argc > 7)
411         id = atoi(argv[7]);
412     else
413         id = DEFAULT_ISLDIST;
414     if (id < 0) {
415         puts("fairland: error -- distance from islands to continents must be >= 0");
416         exit(1);
417     }
418     if (id > WORLD_X || id > WORLD_Y) {
419         puts("fairland: error -- distance from islands to continents too large");
420         exit(1);
421     }
422     if (nc * sc + nc * my_sqrt(sc) * 2 * (di + 1) > WORLD_X * WORLD_Y) {
423         puts("fairland: error -- world not big enough to fit continents.");
424         puts("arguments must satisfy:");
425         puts("nc*sc*sc + nc*sqrt(sc)*2*(di+1) < WORLD_X * WORLD_Y");
426         exit(1);
427     }
428 }
429
430 /****************************************************************************
431   VARIABLE INITIALIZATION
432 ****************************************************************************/
433
434 static int
435 allocate_memory(void)
436 {
437     int i;
438
439     capx = calloc(nc, sizeof(int));
440     capy = calloc(nc, sizeof(int));
441     vector = calloc(WORLD_X + WORLD_Y, sizeof(int));
442     mc = calloc(STABLE_CYCLE, sizeof(int));
443     own = calloc(WORLD_X, sizeof(int *));
444     elev = calloc(WORLD_X, sizeof(int *));
445     for (i = 0; i < WORLD_X; ++i) {
446         own[i] = calloc(WORLD_Y, sizeof(int));
447         elev[i] = calloc(WORLD_Y, sizeof(int));
448     }
449     sectx = calloc(nc + ni, sizeof(int *));
450     secty = calloc(nc + ni, sizeof(int *));
451     sectc = calloc(nc + ni, sizeof(int *));
452     isecs = calloc(nc + ni, sizeof(int));
453     weight = calloc(MAX(sc, is * 2), sizeof(int));
454     dsea = calloc(MAX(sc, is * 2), sizeof(int));
455     dmoun = calloc(MAX(sc, is * 2), sizeof(int));
456     for (i = 0; i < nc; ++i) {
457         sectx[i] = calloc(sc, sizeof(int));
458         secty[i] = calloc(sc, sizeof(int));
459         sectc[i] = calloc(sc, sizeof(int));
460     }
461     for (i = nc; i < nc + ni; ++i) {
462         sectx[i] = calloc(is * 2, sizeof(int));
463         secty[i] = calloc(is * 2, sizeof(int));
464         sectc[i] = calloc(is * 2, sizeof(int));
465     }
466
467     return 0;
468 }
469
470 static void
471 init(void)
472 {
473     int i, j, xx = 0, yy = 0;
474
475     mcc = 0;
476     fl_status = 0;
477
478     for (i = 0; i < WORLD_X; ++i) {
479         for (j = 0; j < WORLD_Y; ++j) {
480             own[i][j] = -1;
481             elev[i][j] = -INFINITY;
482         }
483     }
484
485     for (i = 0; i < nc; ++i) {
486         if (xx >= WORLD_X) {
487             ++yy;
488             xx = yy % 2;
489             if (yy == WORLD_Y) {
490                 puts("fairland error: world not big enough for all the continents.\n");
491                 exit(1);
492             }
493         }
494         capx[i] = xx;
495         capy[i] = yy;
496         xx += 2;
497     }
498     for (i = 0; i < STABLE_CYCLE; ++i)
499         mc[i] = i;
500 }
501
502 /****************************************************************************
503   DRIFT THE CAPITALS UNTIL THEY ARE AS FAR AWAY FROM EACH OTHER AS POSSIBLE
504 ****************************************************************************/
505
506 /* How isolated is capital j?
507 */
508 static int
509 iso(int j, int newx, int newy)
510 {
511     int i, md, d = WORLD_X + WORLD_Y;
512
513     for (i = 0; i < nc; ++i) {
514         if (i == j)
515             continue;
516         md = mapdist(capx[i], capy[i], newx, newy);
517         if (md < d)
518             d = md;
519     }
520
521     return d;
522 }
523
524 /* Drift all the capitals
525 */
526 static int
527 drift(void)
528 {
529     int i, turns;
530
531     for (turns = 0; turns < DRIFT_MAX; ++turns) {
532         if (turns > DRIFT_BEFORE_CHECK && (mind = stable()))
533             return 1;
534         for (i = 0; i < nc; ++i)
535             fl_move(i);
536     }
537     return 0;
538 }
539
540 /* Check to see if we have stabilized--can we stop drifting the capitals?
541 */
542
543 static int
544 stable(void)
545 {
546     int i, isod, d = 0, stab = 1;
547
548     for (i = 0; i < nc; ++i) {
549         isod = iso(i, capx[i], capy[i]);
550         if (isod > d)
551             d = isod;
552     }
553     for (i = 0; i < STABLE_CYCLE; ++i)
554         if (d != mc[i])
555             stab = 0;
556     mc[mcc] = d;
557     mcc = (mcc + 1) % STABLE_CYCLE;
558     return stab ? d : 0;
559 }
560
561 /* This routine does the actual drifting
562 */
563
564 static void
565 fl_move(int j)
566 {
567     int i, n, newx, newy;
568
569     for (i = rnd(6), n = 0; n < 6; i = (i + 1) % 6, ++n) {
570         newx = new_x(capx[j] + dirx[i]);
571         newy = new_y(capy[j] + diry[i]);
572         if (iso(j, newx, newy) >= iso(j, capx[j], capy[j])) {
573             capx[j] = newx;
574             capy[j] = newy;
575             return;
576         }
577     }
578 }
579
580 /****************************************************************************
581   GROW THE CONTINENTS
582 ****************************************************************************/
583
584 /* Look for a coastal sector of continent c
585 */
586
587 static void
588 find_coast(int c)
589 {
590     int i, j;
591
592     for (i = 0; i < secs; ++i) {
593         sectc[c][i] = 0;
594         for (j = 0; j < 6; ++j)
595             if (own[new_x(sectx[c][i] + dirx[j])][new_y(secty[c][i] + diry[j])] == -1)
596                 sectc[c][i] = 1;
597     }
598 }
599
600 /* Used for measuring distances
601 */
602 static int
603 next_vector(int n)
604 {
605     int i;
606
607     if (n == 1) {
608         vector[0] += 1;
609         vector[0] %= 6;
610         return vector[0];
611     }
612     for (i = 1; i < n && vector[i] == vector[i - 1]; ++i) ;
613     vector[i - 1] += 1;
614     vector[i - 1] %= 6;
615     return i > 1 || vector[0] > 0;
616 }
617
618 /* Test to see if we're allowed to grow there: the arguments di and id
619 */
620 static int
621 try_to_grow(int c, int newx, int newy, int d)
622 {
623     int i, j, px, py;
624
625     for (i = 1; i <= d; ++i) {
626         for (j = 0; j < i; ++j)
627             vector[j] = 0;
628         do {
629             px = newx;
630             py = newy;
631             for (j = 0; j < i; ++j) {
632                 px = new_x(px + dirx[vector[j]]);
633                 py = new_y(py + diry[vector[j]]);
634             }
635             if (own[px][py] != -1 &&
636                 own[px][py] != c &&
637                 (DISTINCT_ISLANDS || own[px][py] < nc))
638                 return 0;
639         } while (next_vector(i));
640     }
641     sectx[c][secs] = newx;
642     secty[c][secs] = newy;
643     own[newx][newy] = c;
644     return 1;
645 }
646
647 /* Move along the coast in a clockwise direction.
648 */
649
650 static void
651 next_coast(int c, int x, int y, int *xp, int *yp)
652 {
653     int i, nx, ny, wat = 0;
654
655     if (secs == 1) {
656         *xp = x;
657         *yp = y;
658         return;
659     }
660
661     for (i = 0; i < 12; ++i) {
662         nx = new_x(x + dirx[i % 6]);
663         ny = new_y(y + diry[i % 6]);
664         if (own[nx][ny] == -1)
665             wat = 1;
666         if (wat && own[nx][ny] == c) {
667             *xp = nx;
668             *yp = ny;
669             return;
670         }
671     }
672 }
673
674 /* Choose a sector to grow from
675 */
676
677 static int
678 new_try(int c)
679 {
680     int i, starti;
681
682     if (secs == 1) {
683         if (sectc[c][0])
684             return 0;
685     } else {
686         i = starti = (spike && sectc[c][secs - 1]) ? secs - 1 : rnd(secs);
687         do {
688             if (sectc[c][i])
689                 return i;
690             i = (i + 1) % secs;
691         } while (i != starti);
692         if (c < nc) {
693             printf("fairland: BUG -- couldn't find coast for continent %c, sector %d.\nPlease mail stevens@math.utoronto.ca.\n",
694                    c + 'a', secs);
695             exit(1);
696         } else
697             return -1;
698     }
699     return -1;
700 }
701
702 /* Grow continent c by 1 sector
703 */
704
705 static int
706 grow_one_sector(int c)
707 {
708     int done, coast_search, try1, x, y, newx, newy, i, n, sx, sy;
709
710     spike = rnd(100) < sp;
711     if ((try1 = new_try(c)) == -1)
712         return 0;
713     x = sx = sectx[c][try1];
714     y = sy = secty[c][try1];
715     coast_search = 0;
716     done = 0;
717     do {
718         if (spike) {
719             for (i = rnd(6), n = 0; n < 12 && !done; i = (i + 1) % 6, ++n) {
720                 newx = new_x(x + dirx[i]);
721                 newy = new_y(y + diry[i]);
722                 if (own[newx][newy] == -1 &&
723                     (n > 5 ||
724                      (own[new_x(x+dirx[(i+5)%6])][new_y(y+diry[(i+5)%6])] == -1 &&
725                       own[new_x(x+dirx[(i+1)%6])][new_y(y+diry[(i+1)%6])] == -1)))
726                     if (try_to_grow(c, newx, newy, c < nc ? di : id))
727                         done = 1;
728             }
729         } else
730             for (i = rnd(6), n = 0; n < 6 && !done; i = (i + 1) % 6, ++n) {
731                 newx = new_x(x + dirx[i]);
732                 newy = new_y(y + diry[i]);
733                 if (own[newx][newy] == -1)
734                     if (try_to_grow(c, newx, newy, c < nc ? di : id))
735                         done = 1;
736             }
737         next_coast(c, x, y, &x, &y);
738         ++coast_search;
739     } while (!done && coast_search < COAST_SEARCH_MAX &&
740              (secs == 1 || x != sx || y != sy));
741     if (!done && c < nc) {
742         qprint("fairland: error -- continent %c had no room to grow!\n",
743                numletter[c % 62]);
744         fl_status |= STATUS_NO_ROOM;
745     }
746     return done;
747 }
748
749 /* Grow all the continents
750 */
751 static void
752 grow_continents(void)
753 {
754     int c;
755
756     for (c = 0; c < nc; ++c) {
757         sectx[c][0] = capx[c];
758         secty[c][0] = capy[c];
759         own[sectx[c][0]][secty[c][0]] = c;
760         sectx[c][1] = new_x(capx[c] + 2);
761         secty[c][1] = capy[c];
762         own[sectx[c][1]][secty[c][1]] = c;
763     }
764
765     for (secs = 2; secs < sc && !fl_status; ++secs) {
766         for (c = 0; c < nc; ++c) {
767             find_coast(c);
768             grow_one_sector(c);
769         }
770     }
771     for (c = 0; c < nc; ++c)
772         find_coast(c);
773
774     if (fl_status)
775         qprint("Only managed to grow %d out of %d sectors.\n", secs, sc);
776     ctot = nc;
777 }
778
779 /****************************************************************************
780   GROW THE ISLANDS
781 ****************************************************************************/
782
783 /* Choose a place to start growing an island from
784 */
785 static int
786 place_island(int c, int *xp, int *yp)
787 {
788     int d, sx, sy;
789     int ssy = rnd(WORLD_Y);
790     int ssx = new_x(rnd(WORLD_X / 2) * 2 + ssy % 2);
791
792     if (ssx > WORLD_X - 2)
793         ssx = new_x(ssx + 2);
794     for (d = di + id; d >= id; --d) {
795         sx = ssx;
796         sy = ssy;
797         *xp = new_x(sx + 2);
798         for (*yp = sy; *xp != sx || *yp != sy; *xp += 2) {
799             if (*xp >= WORLD_X) {
800                 *yp = new_y(*yp + 1);
801                 *xp = *yp % 2;
802                 if (*xp == sx && *yp == sy)
803                     break;
804             }
805             if (own[*xp][*yp] == -1 && try_to_grow(c, *xp, *yp, d))
806                 return 1;
807         }
808     }
809     return 0;
810 }
811
812 /* Grow all the islands
813 */
814
815 static void
816 grow_islands(void)
817 {
818     int c, x, y, isiz;
819
820     for (c = nc; c < nc + ni; ++c) {
821         secs = 0;
822         if (!place_island(c, &x, &y))
823             return;
824         isiz = 1 + rnd(2 * is - 1);
825         do {
826             ++secs;
827             find_coast(c);
828         } while (secs < isiz && grow_one_sector(c));
829         find_coast(c);
830         qprint(" %d(%d)", c - nc + 1, secs);
831         isecs[c] = secs;
832         ctot++;
833     }
834 }
835
836 /****************************************************************************
837   CREATE ELEVATIONS
838 ****************************************************************************/
839 static void
840 create_elevations(void)
841 {
842     elevate_land();
843     elevate_sea();
844 }
845
846 /* Generic function for finding the distance to the closest sea, land, or
847    mountain
848 */
849 static int
850 distance_to_what(int x, int y, int flag)
851 {
852     int j, d, px, py;
853
854     for (d = 1; d < 5; ++d) {
855         for (j = 0; j < d; ++j)
856             vector[j] = 0;
857         do {
858             px = x;
859             py = y;
860             for (j = 0; j < d; ++j) {
861                 px = new_x(px + dirx[vector[j]]);
862                 py = new_y(py + diry[vector[j]]);
863             }
864             switch (flag) {
865             case 0:             /* distance to sea */
866                 if (own[px][py] == -1)
867                     return d;
868                 break;
869             case 1:             /* distance to land */
870                 if (own[px][py] != -1)
871                     return d;
872                 break;
873             case 2:             /* distance to mountain */
874                 if (elev[px][py] == INFINITY)
875                     return d;
876                 break;
877             }
878         } while (next_vector(d));
879     }
880     return d;
881 }
882
883 #define ELEV elev[sectx[c][i]][secty[c][i]]
884 #define distance_to_sea() (sectc[c][i]?1:distance_to_what(sectx[c][i], secty[c][i], 0))
885 #define distance_to_mountain() distance_to_what(sectx[c][i], secty[c][i], 2)
886
887 /* Decide where the mountains go
888 */
889 static void
890 elevate_land(void)
891 {
892     int i, mountain_search, k, c, total, ns, nm, highest, where, h, newk,
893         r, dk;
894
895     for (c = 0; c < ctot; ++c) {
896         total = 0;
897         ns = (c < nc) ? sc : isecs[c];
898         nm = (pm * ns) / 100;
899
900 /* Place the mountains */
901
902         for (i = 0; i < ns; ++i) {
903             dsea[i] = distance_to_sea();
904             weight[i] = (total += (dsea[i] * dsea[i]));
905         }
906
907         for (k = nm, mountain_search = 0;
908              k && mountain_search < MOUNTAIN_SEARCH_MAX;
909              ++mountain_search) {
910             r = rnd(total);
911             for (i = 0; i < ns; ++i)
912                 if (r < weight[i] && ELEV == -INFINITY &&
913                     (c >= nc ||
914                      ((!(capx[c] == sectx[c][i] &&
915                          capy[c] == secty[c][i])) &&
916                       (!(new_x(capx[c] + 2) == sectx[c][i] &&
917                          capy[c] == secty[c][i]))))) {
918                     ELEV = INFINITY;
919                     break;
920                 }
921             --k;
922         }
923
924 /* Elevate land that is not mountain and not capital */
925
926         for (i = 0; i < ns; ++i)
927             dmoun[i] = distance_to_mountain();
928         dk = (ns - nm - ((c < nc) ? 3 : 1) > 0) ?
929           (100 * (HIGHMIN - LANDMIN)) / (ns - nm - ((c < nc) ? 3 : 1)) :
930           100 * INFINITY;
931         for (k = 100 * (HIGHMIN - 1);; k -= dk) {
932             highest = -INFINITY;
933             where = -1;
934             for (i = 0; i < ns; ++i) {
935                 if (ELEV != INFINITY &&
936                     (c >= nc || ((!(capx[c] == sectx[c][i] &&
937                                     capy[c] == secty[c][i])) &&
938                                  (!(new_x(capx[c] + 2) == sectx[c][i] &&
939                                     capy[c] == secty[c][i]))))) {
940                     h = 3 * (5 - dmoun[i]) + dsea[i];
941                     if (h > highest) {
942                         highest = h;
943                         where = i;
944                     }
945                 }
946             }
947             if (where == -1)
948                 break;
949             newk = k / 100;
950             if (newk >= HILLMIN && newk < PLATMIN)
951                 newk = PLATMIN;
952             if (newk < LANDMIN)
953                 newk = LANDMIN;
954             elev[sectx[c][where]][secty[c][where]] = newk;
955             dsea[where] = -INFINITY;
956             dmoun[where] = INFINITY;
957         }
958
959 /* Elevate the mountains and capitals */
960
961         for (i = 0; i < ns; ++i) {
962             if (ELEV == INFINITY) {
963                 if (dsea[i] == 1)
964                     ELEV = HILLMIN + rnd(PLATMIN - HILLMIN);
965                 else
966                     ELEV = HIGHMIN + rnd((256 - HIGHMIN) / 2) +
967                       rnd((256 - HIGHMIN) / 2);
968             } else if ((c < nc &&
969                         ((capx[c] == sectx[c][i] && capy[c] == secty[c][i]))) ||
970                        ((new_x(capx[c] + 2) == sectx[c][i] &&
971                          capy[c] == secty[c][i])))
972                 ELEV = PLATMIN;
973         }
974     }
975 }
976
977 #define distance_to_land() distance_to_what(x, y, 1)
978
979 static void
980 elevate_sea(void)
981 {
982     int x, y;
983
984     for (y = 0; y < WORLD_Y; ++y) {
985         for (x = y % 2; x < WORLD_X; x += 2) {
986             if (elev[x][y] == -INFINITY)
987                 elev[x][y] = -rnd((distance_to_land() * 20 + 27)) - 1;
988         }
989     }
990 }
991
992 /****************************************************************************
993   ADD THE RESOURCES
994 ****************************************************************************/
995
996 static int
997 set_fert(int e)
998 {
999     int fert = 0;
1000     if (e < LANDMIN)
1001         fert = LANDMIN - e + 40;
1002     else if (e < FERT_MAX)
1003         fert = (120 * (FERT_MAX - e)) / (FERT_MAX - LANDMIN);
1004     if (fert > 100)
1005         fert = 100;
1006     return fert;
1007 }
1008
1009 static int
1010 set_oil(int e)
1011 {
1012     int oil = 0;
1013     if (e < LANDMIN)
1014         oil = (LANDMIN - e) * 2 + rnd(2);
1015     else if (e <= OIL_MAX)
1016         oil = (120 * (OIL_MAX - e + 1)) / (OIL_MAX - LANDMIN + 1);
1017     if (oil > 100)
1018         oil = 100;
1019     return oil;
1020 }
1021
1022 static int
1023 set_iron(int e)
1024 {
1025     int iron = 0;
1026     if (e >= IRON_MIN && e < HIGHMIN)
1027         iron = (120 * (e - IRON_MIN + 1)) / (HIGHMIN - IRON_MIN);
1028     if (iron > 100)
1029         iron = 100;
1030     return iron;
1031 }
1032
1033 static int
1034 set_gold(int e)
1035 {
1036     int gold = 0;
1037     if (e >= GOLD_MIN) {
1038         if (e < HIGHMIN)
1039             gold = (80 * (e - GOLD_MIN + 1)) / (HIGHMIN - GOLD_MIN);
1040         else
1041             gold = 100 - 20 * HIGHMIN / e;
1042     }
1043     if (gold > 100)
1044         gold = 100;
1045     return gold;
1046 }
1047
1048 static int
1049 set_uran(int e)
1050 {
1051     int uran = 0;
1052     if (e >= URAN_MIN && e < HIGHMIN)
1053         uran = (120 * (e - URAN_MIN + 1)) / (HIGHMIN - URAN_MIN);
1054     if (uran > 100)
1055         uran = 100;
1056     return uran;
1057 }
1058
1059 static void
1060 add_resources(struct sctstr *sct)
1061 {
1062     sct->sct_fertil = set_fert(sct->sct_elev);
1063     sct->sct_oil = set_oil(sct->sct_elev);
1064     sct->sct_min = set_iron(sct->sct_elev);
1065     sct->sct_gmin = set_gold(sct->sct_elev);
1066     sct->sct_uran = set_uran(sct->sct_elev);
1067 }
1068
1069 /****************************************************************************
1070   DESIGNATE THE SECTORS
1071 ****************************************************************************/
1072
1073 static void
1074 write_sects(void)
1075 {
1076     struct sctstr *sct;
1077     int c, x, y, total;
1078
1079     for (y = 0; y < WORLD_Y; y++) {
1080         for (x = y % 2; x < WORLD_X; x += 2) {
1081             sct = getsectp(x, y);
1082             total = elev[x][y];
1083             if (total < LANDMIN) {
1084                 sct->sct_type = SCT_WATER;
1085             } else if (total < HILLMIN)
1086                 sct->sct_type = SCT_RURAL;
1087             else if (total < PLATMIN)
1088                 sct->sct_type = SCT_MOUNT;
1089             else if (total < HIGHMIN)
1090                 sct->sct_type = SCT_RURAL;
1091             else
1092                 sct->sct_type = SCT_MOUNT;
1093             sct->sct_elev = total;
1094             sct->sct_newtype = sct->sct_type;
1095             if (ORE)
1096                 add_resources(sct);
1097         }
1098     }
1099     if (AIRPORT_MARKER)
1100         for (c = 0; c < nc; ++c) {
1101             sct = getsectp(capx[c], capy[c]);
1102             sct->sct_type = SCT_AIRPT;
1103             sct->sct_newtype = SCT_AIRPT;
1104         }
1105     set_coastal_flags();
1106 }
1107
1108 /****************************************************************************
1109   PRINT A PICTURE OF THE MAP TO YOUR SCREEN
1110 ****************************************************************************/
1111 static void
1112 output(void)
1113 {
1114     int i, j;
1115     if (quiet == 0) {
1116         for (i = 0; i < WORLD_Y; ++i) {
1117             puts("");
1118             if (i % 2)
1119                 printf(" ");
1120             for (j = i % 2; j < WORLD_X; j += 2) {
1121                 if (own[j][i] == -1)
1122                     printf(". ");
1123                 else {
1124                     printf("%c ", map_symbol(j, i));
1125                 }
1126             }
1127         }
1128     }
1129     if (AIRPORT_MARKER)
1130         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");
1131 }
1132
1133 static int
1134 map_symbol(int x, int y)
1135 {
1136     int c, iscap = 0;
1137
1138     for (c = 0; c < nc; ++c)
1139         if ((x == capx[c] && y == capy[c])
1140             || (x == new_x(capx[c] + 2) && y == capy[c]))
1141             iscap = 1;
1142     if ((elev[x][y] >= HILLMIN && elev[x][y] < PLATMIN)
1143         || elev[x][y] >= HIGHMIN)
1144         return '^';
1145     return own[x][y] >= nc ? '%' : iscap ? '#' : numletter[own[x][y] % 62];
1146 }
1147
1148 /***************************************************************************
1149   WRITE A SCRIPT FOR PLACING CAPITALS
1150 ****************************************************************************/
1151 static int
1152 write_newcap_script(void)
1153 {
1154     int c;
1155     FILE *script = fopen(outfile, "w");
1156
1157     if (!script) {
1158         printf("fairland: error, unable to write to %s.\n", outfile);
1159         return -1;
1160     }
1161
1162     for (c = 0; c < nc; ++c) {
1163         fprintf(script, "add %d %d %d n i\n", c + 1, c + 1, c + 1);
1164         if (AIRPORT_MARKER)
1165             fprintf(script, "des %d,%d -\n", capx[c], capy[c]);
1166         fprintf(script, "newcap %d %d,%d\n", c + 1, capx[c], capy[c]);
1167     }
1168     fprintf(script, "add %d visitor visitor v i\n", c + 1);
1169     fclose(script);
1170     return 0;
1171 }
1172
1173 static void
1174 qprint(const char * const fmt, ...)
1175 {
1176     va_list ap;
1177
1178     if (!quiet) {
1179         va_start(ap, fmt);
1180         vfprintf(stdout, fmt, ap);
1181         va_end(ap);
1182     }
1183 }
1184
1185 static void
1186 set_coastal_flags(void)
1187 {
1188     int i, j;
1189     struct sctstr *sp;
1190
1191     qprint("setting coastal flags...\n");
1192     for (i = 0; i < nc; ++i) {
1193         for (j = 0; j < sc; j++) {
1194             sp = getsectp(sectx[i][j], secty[i][j]);
1195             sp->sct_coastal = sectc[i][j];
1196         }
1197     }
1198     for (i = nc; i < nc + ni; ++i) {
1199         for (j = 0; j < isecs[i]; j++) {
1200             sp = getsectp(sectx[i][j], secty[i][j]);
1201             sp->sct_coastal = sectc[i][j];
1202         }
1203     }
1204 }