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