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