]> git.pond.sub.org Git - empserver/blob - src/util/fairland.c
Make fairland record the island number in the deity territory
[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            "  -h              display this help and exit\n"
325            "  -i              islands may merge\n"
326            "  -o              don't set resources\n"
327            "  -q              quiet\n"
328            "  -R SEED         seed for random number generator\n"
329            "  -s SCRIPT       name of script to create (default %s)\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     if (sp < 0)
382         sp = 0;
383     if (sp > 100)
384         sp = 100;
385
386     if (argc > 5)
387         pm = atoi(argv[5]);
388     else
389         pm = DEFAULT_MOUNTAIN;
390     if (pm < 0)
391         pm = 0;
392
393     if (argc > 6)
394         di = atoi(argv[6]);
395     else
396         di = DEFAULT_CONTDIST;
397
398     if (di < 0) {
399         puts("fairland: error -- distance between continents must be >= 0");
400         exit(1);
401     }
402     if (di > WORLD_X / 2 || di > WORLD_Y / 2) {
403         puts("fairland: error -- distance between continents too large");
404         exit(1);
405     }
406
407     if (argc > 7)
408         id = atoi(argv[7]);
409     else
410         id = DEFAULT_ISLDIST;
411     if (id < 0) {
412         puts("fairland: error -- distance from islands to continents must be >= 0");
413         exit(1);
414     }
415     if (id > WORLD_X || id > WORLD_Y) {
416         puts("fairland: error -- distance from islands to continents too large");
417         exit(1);
418     }
419     if (nc * sc + nc * my_sqrt(sc) * 2 * (di + 1) > WORLD_X * WORLD_Y) {
420         puts("fairland: warning -- world might be too small to fit continents.");
421         puts("arguments should satisfy:");
422         puts("nc*sc*sc + nc*sqrt(sc)*2*(di+1) < WORLD_X * WORLD_Y");
423     }
424 }
425
426 /****************************************************************************
427   VARIABLE INITIALIZATION
428 ****************************************************************************/
429
430 static void
431 allocate_memory(void)
432 {
433     int i;
434
435     capx = calloc(nc, sizeof(int));
436     capy = calloc(nc, sizeof(int));
437     vector = calloc(WORLD_X + WORLD_Y, sizeof(int));
438     mc = calloc(STABLE_CYCLE, sizeof(int));
439     own = calloc(WORLD_X, sizeof(int *));
440     elev = calloc(WORLD_X, sizeof(int *));
441     for (i = 0; i < WORLD_X; ++i) {
442         own[i] = calloc(WORLD_Y, sizeof(int));
443         elev[i] = calloc(WORLD_Y, sizeof(int));
444     }
445     sectx = calloc(nc + ni, sizeof(int *));
446     secty = calloc(nc + ni, sizeof(int *));
447     sectc = calloc(nc + ni, sizeof(int *));
448     isecs = calloc(nc + ni, sizeof(int));
449     weight = calloc(MAX(sc, is * 2), sizeof(int));
450     dsea = calloc(MAX(sc, is * 2), sizeof(int));
451     dmoun = calloc(MAX(sc, is * 2), sizeof(int));
452     for (i = 0; i < nc; ++i) {
453         sectx[i] = calloc(sc, sizeof(int));
454         secty[i] = calloc(sc, sizeof(int));
455         sectc[i] = calloc(sc, sizeof(int));
456     }
457     for (i = nc; i < nc + ni; ++i) {
458         sectx[i] = calloc(is * 2, sizeof(int));
459         secty[i] = calloc(is * 2, sizeof(int));
460         sectc[i] = calloc(is * 2, sizeof(int));
461     }
462
463 }
464
465 static void
466 init(void)
467 {
468     int i, j, xx = 0, yy = 0;
469
470     mcc = 0;
471     fl_status = 0;
472
473     for (i = 0; i < WORLD_X; ++i) {
474         for (j = 0; j < WORLD_Y; ++j) {
475             own[i][j] = -1;
476             elev[i][j] = -INFINITY;
477         }
478     }
479
480     for (i = 0; i < nc; ++i) {
481         if (xx >= WORLD_X) {
482             ++yy;
483             xx = yy % 2;
484             if (yy == WORLD_Y) {
485                 puts("fairland error: world not big enough for all the continents.\n");
486                 exit(1);
487             }
488         }
489         capx[i] = xx;
490         capy[i] = yy;
491         xx += 2;
492     }
493     for (i = 0; i < STABLE_CYCLE; ++i)
494         mc[i] = i;
495 }
496
497 /****************************************************************************
498   DRIFT THE CAPITALS UNTIL THEY ARE AS FAR AWAY FROM EACH OTHER AS POSSIBLE
499 ****************************************************************************/
500
501 /* How isolated is capital j?
502 */
503 static int
504 iso(int j, int newx, int newy)
505 {
506     int i, md, d = WORLD_X + WORLD_Y;
507
508     for (i = 0; i < nc; ++i) {
509         if (i == j)
510             continue;
511         md = mapdist(capx[i], capy[i], newx, newy);
512         if (md < d)
513             d = md;
514     }
515
516     return d;
517 }
518
519 /* Drift all the capitals
520 */
521 static int
522 drift(void)
523 {
524     int i, turns;
525
526     for (turns = 0; turns < DRIFT_MAX; ++turns) {
527         if (turns > DRIFT_BEFORE_CHECK && (mind = stable()))
528             return 1;
529         for (i = 0; i < nc; ++i)
530             fl_move(i);
531     }
532     return 0;
533 }
534
535 /* Check to see if we have stabilized--can we stop drifting the capitals?
536 */
537
538 static int
539 stable(void)
540 {
541     int i, isod, d = 0, stab = 1;
542
543     for (i = 0; i < nc; ++i) {
544         isod = iso(i, capx[i], capy[i]);
545         if (isod > d)
546             d = isod;
547     }
548     for (i = 0; i < STABLE_CYCLE; ++i)
549         if (d != mc[i])
550             stab = 0;
551     mc[mcc] = d;
552     mcc = (mcc + 1) % STABLE_CYCLE;
553     return stab ? d : 0;
554 }
555
556 /* This routine does the actual drifting
557 */
558
559 static void
560 fl_move(int j)
561 {
562     int i, n, newx, newy;
563
564     for (i = roll0(6), n = 0; n < 6; i = (i + 1) % 6, ++n) {
565         newx = new_x(capx[j] + dirx[i]);
566         newy = new_y(capy[j] + diry[i]);
567         if (iso(j, newx, newy) >= iso(j, capx[j], capy[j])) {
568             capx[j] = newx;
569             capy[j] = newy;
570             return;
571         }
572     }
573 }
574
575 /****************************************************************************
576   GROW THE CONTINENTS
577 ****************************************************************************/
578
579 /* Look for a coastal sector of continent c
580 */
581
582 static void
583 find_coast(int c)
584 {
585     int i, j;
586
587     for (i = 0; i < secs; ++i) {
588         sectc[c][i] = 0;
589         for (j = 0; j < 6; ++j)
590             if (own[new_x(sectx[c][i] + dirx[j])][new_y(secty[c][i] + diry[j])] == -1)
591                 sectc[c][i] = 1;
592     }
593 }
594
595 /* Used for measuring distances
596 */
597 static int
598 next_vector(int n)
599 {
600     int i;
601
602     if (n == 1) {
603         vector[0] += 1;
604         vector[0] %= 6;
605         return vector[0];
606     }
607     for (i = 1; i < n && vector[i] == vector[i - 1]; ++i) ;
608     vector[i - 1] += 1;
609     vector[i - 1] %= 6;
610     return i > 1 || vector[0] > 0;
611 }
612
613 /* Test to see if we're allowed to grow there: the arguments di and id
614 */
615 static int
616 try_to_grow(int c, int newx, int newy, int d)
617 {
618     int i, j, px, py;
619
620     for (i = 1; i <= d; ++i) {
621         for (j = 0; j < i; ++j)
622             vector[j] = 0;
623         do {
624             px = newx;
625             py = newy;
626             for (j = 0; j < i; ++j) {
627                 px = new_x(px + dirx[vector[j]]);
628                 py = new_y(py + diry[vector[j]]);
629             }
630             if (own[px][py] != -1 &&
631                 own[px][py] != c &&
632                 (DISTINCT_ISLANDS || own[px][py] < nc))
633                 return 0;
634         } while (next_vector(i));
635     }
636     sectx[c][secs] = newx;
637     secty[c][secs] = newy;
638     own[newx][newy] = c;
639     return 1;
640 }
641
642 /* Move along the coast in a clockwise direction.
643 */
644
645 static void
646 next_coast(int c, int x, int y, int *xp, int *yp)
647 {
648     int i, nx, ny, wat = 0;
649
650     if (secs == 1) {
651         *xp = x;
652         *yp = y;
653         return;
654     }
655
656     for (i = 0; i < 12; ++i) {
657         nx = new_x(x + dirx[i % 6]);
658         ny = new_y(y + diry[i % 6]);
659         if (own[nx][ny] == -1)
660             wat = 1;
661         if (wat && own[nx][ny] == c) {
662             *xp = nx;
663             *yp = ny;
664             return;
665         }
666     }
667 }
668
669 /* Choose a sector to grow from
670 */
671
672 static int
673 new_try(int c)
674 {
675     int i, starti;
676
677     if (secs == 1) {
678         if (sectc[c][0])
679             return 0;
680     } else {
681         i = starti = (spike && sectc[c][secs - 1]) ? secs - 1 : roll0(secs);
682         do {
683             if (sectc[c][i])
684                 return i;
685             i = (i + 1) % secs;
686         } while (i != starti);
687         assert(c >= nc);
688         return -1;
689     }
690     return -1;
691 }
692
693 /* Grow continent c by 1 sector
694 */
695
696 static int
697 grow_one_sector(int c)
698 {
699     int done, coast_search, try1, x, y, newx, newy, i, n, sx, sy;
700
701     spike = roll0(100) < sp;
702     if ((try1 = new_try(c)) == -1)
703         return 0;
704     x = sx = sectx[c][try1];
705     y = sy = secty[c][try1];
706     coast_search = 0;
707     done = 0;
708     do {
709         if (spike) {
710             for (i = roll0(6), n = 0; n < 12 && !done; i = (i + 1) % 6, ++n) {
711                 newx = new_x(x + dirx[i]);
712                 newy = new_y(y + diry[i]);
713                 if (own[newx][newy] == -1 &&
714                     (n > 5 ||
715                      (own[new_x(x+dirx[(i+5)%6])][new_y(y+diry[(i+5)%6])] == -1 &&
716                       own[new_x(x+dirx[(i+1)%6])][new_y(y+diry[(i+1)%6])] == -1)))
717                     if (try_to_grow(c, newx, newy, c < nc ? di : id))
718                         done = 1;
719             }
720         } else
721             for (i = roll0(6), n = 0; n < 6 && !done; i = (i + 1) % 6, ++n) {
722                 newx = new_x(x + dirx[i]);
723                 newy = new_y(y + diry[i]);
724                 if (own[newx][newy] == -1)
725                     if (try_to_grow(c, newx, newy, c < nc ? di : id))
726                         done = 1;
727             }
728         next_coast(c, x, y, &x, &y);
729         ++coast_search;
730     } while (!done && coast_search < COAST_SEARCH_MAX &&
731              (secs == 1 || x != sx || y != sy));
732     if (!done && c < nc) {
733         qprint("fairland: error -- continent %c had no room to grow!\n",
734                numletter[c % 62]);
735         fl_status |= STATUS_NO_ROOM;
736     }
737     return done;
738 }
739
740 /* Grow all the continents
741 */
742 static void
743 grow_continents(void)
744 {
745     int c;
746
747     for (c = 0; c < nc; ++c) {
748         sectx[c][0] = capx[c];
749         secty[c][0] = capy[c];
750         own[sectx[c][0]][secty[c][0]] = c;
751         sectx[c][1] = new_x(capx[c] + 2);
752         secty[c][1] = capy[c];
753         own[sectx[c][1]][secty[c][1]] = c;
754     }
755
756     for (secs = 2; secs < sc && !fl_status; ++secs) {
757         for (c = 0; c < nc; ++c) {
758             find_coast(c);
759             grow_one_sector(c);
760         }
761     }
762     for (c = 0; c < nc; ++c)
763         find_coast(c);
764
765     if (fl_status)
766         qprint("Only managed to grow %d out of %d sectors.\n", secs, sc);
767     ctot = nc;
768 }
769
770 /****************************************************************************
771   GROW THE ISLANDS
772 ****************************************************************************/
773
774 /* Choose a place to start growing an island from
775 */
776 static int
777 place_island(int c, int *xp, int *yp)
778 {
779     int d, sx, sy;
780     int ssy = roll0(WORLD_Y);
781     int ssx = new_x(roll0(WORLD_X / 2) * 2 + ssy % 2);
782
783     if (ssx > WORLD_X - 2)
784         ssx = new_x(ssx + 2);
785     for (d = di + id; d >= id; --d) {
786         sx = ssx;
787         sy = ssy;
788         *xp = new_x(sx + 2);
789         for (*yp = sy; *xp != sx || *yp != sy; *xp += 2) {
790             if (*xp >= WORLD_X) {
791                 *yp = new_y(*yp + 1);
792                 *xp = *yp % 2;
793                 if (*xp == sx && *yp == sy)
794                     break;
795             }
796             if (own[*xp][*yp] == -1 && try_to_grow(c, *xp, *yp, d))
797                 return 1;
798         }
799     }
800     return 0;
801 }
802
803 /* Grow all the islands
804 */
805
806 static void
807 grow_islands(void)
808 {
809     int c, x, y, isiz;
810
811     for (c = nc; c < nc + ni; ++c) {
812         secs = 0;
813         if (!place_island(c, &x, &y))
814             return;
815         isiz = roll(2 * is - 1);
816         do {
817             ++secs;
818             find_coast(c);
819         } while (secs < isiz && grow_one_sector(c));
820         find_coast(c);
821         qprint(" %d(%d)", c - nc + 1, secs);
822         isecs[c] = secs;
823         ctot++;
824     }
825 }
826
827 /****************************************************************************
828   CREATE ELEVATIONS
829 ****************************************************************************/
830 static void
831 create_elevations(void)
832 {
833     elevate_land();
834     elevate_sea();
835 }
836
837 /* Generic function for finding the distance to the closest sea, land, or
838    mountain
839 */
840 static int
841 distance_to_what(int x, int y, int flag)
842 {
843     int j, d, px, py;
844
845     for (d = 1; d < 5; ++d) {
846         for (j = 0; j < d; ++j)
847             vector[j] = 0;
848         do {
849             px = x;
850             py = y;
851             for (j = 0; j < d; ++j) {
852                 px = new_x(px + dirx[vector[j]]);
853                 py = new_y(py + diry[vector[j]]);
854             }
855             switch (flag) {
856             case 0:             /* distance to sea */
857                 if (own[px][py] == -1)
858                     return d;
859                 break;
860             case 1:             /* distance to land */
861                 if (own[px][py] != -1)
862                     return d;
863                 break;
864             case 2:             /* distance to mountain */
865                 if (elev[px][py] == INFINITY)
866                     return d;
867                 break;
868             }
869         } while (next_vector(d));
870     }
871     return d;
872 }
873
874 #define ELEV elev[sectx[c][i]][secty[c][i]]
875 #define distance_to_sea() (sectc[c][i]?1:distance_to_what(sectx[c][i], secty[c][i], 0))
876 #define distance_to_mountain() distance_to_what(sectx[c][i], secty[c][i], 2)
877
878 /* Decide where the mountains go
879 */
880 static void
881 elevate_land(void)
882 {
883     int i, mountain_search, k, c, total, ns, nm, highest, where, h, newk,
884         r, dk;
885
886     for (c = 0; c < ctot; ++c) {
887         total = 0;
888         ns = (c < nc) ? sc : isecs[c];
889         nm = (pm * ns) / 100;
890
891 /* Place the mountains */
892
893         for (i = 0; i < ns; ++i) {
894             dsea[i] = distance_to_sea();
895             weight[i] = (total += (dsea[i] * dsea[i]));
896         }
897
898         for (k = nm, mountain_search = 0;
899              k && mountain_search < MOUNTAIN_SEARCH_MAX;
900              ++mountain_search) {
901             r = roll0(total);
902             for (i = 0; i < ns; ++i)
903                 if (r < weight[i] && ELEV == -INFINITY &&
904                     (c >= nc ||
905                      ((!(capx[c] == sectx[c][i] &&
906                          capy[c] == secty[c][i])) &&
907                       (!(new_x(capx[c] + 2) == sectx[c][i] &&
908                          capy[c] == secty[c][i]))))) {
909                     ELEV = INFINITY;
910                     break;
911                 }
912             --k;
913         }
914
915 /* Elevate land that is not mountain and not capital */
916
917         for (i = 0; i < ns; ++i)
918             dmoun[i] = distance_to_mountain();
919         dk = (ns - nm - ((c < nc) ? 3 : 1) > 0) ?
920           (100 * (HIGHMIN - LANDMIN)) / (ns - nm - ((c < nc) ? 3 : 1)) :
921           100 * INFINITY;
922         for (k = 100 * (HIGHMIN - 1);; k -= dk) {
923             highest = -INFINITY;
924             where = -1;
925             for (i = 0; i < ns; ++i) {
926                 if (ELEV != INFINITY &&
927                     (c >= nc || ((!(capx[c] == sectx[c][i] &&
928                                     capy[c] == secty[c][i])) &&
929                                  (!(new_x(capx[c] + 2) == sectx[c][i] &&
930                                     capy[c] == secty[c][i]))))) {
931                     h = 3 * (5 - dmoun[i]) + dsea[i];
932                     if (h > highest) {
933                         highest = h;
934                         where = i;
935                     }
936                 }
937             }
938             if (where == -1)
939                 break;
940             newk = k / 100;
941             if (newk >= HILLMIN && newk < PLATMIN)
942                 newk = PLATMIN;
943             if (newk < LANDMIN)
944                 newk = LANDMIN;
945             elev[sectx[c][where]][secty[c][where]] = newk;
946             dsea[where] = -INFINITY;
947             dmoun[where] = INFINITY;
948         }
949
950 /* Elevate the mountains and capitals */
951
952         for (i = 0; i < ns; ++i) {
953             if (ELEV == INFINITY) {
954                 if (dsea[i] == 1)
955                     ELEV = HILLMIN + roll0(PLATMIN - HILLMIN);
956                 else
957                     ELEV = HIGHMIN + roll0((256 - HIGHMIN) / 2) +
958                       roll0((256 - HIGHMIN) / 2);
959             } else if (c < nc &&
960                        (((capx[c] == sectx[c][i] && capy[c] == secty[c][i])) ||
961                         ((new_x(capx[c] + 2) == sectx[c][i] &&
962                           capy[c] == secty[c][i]))))
963                 ELEV = PLATMIN;
964         }
965     }
966 }
967
968 #define distance_to_land() distance_to_what(x, y, 1)
969
970 static void
971 elevate_sea(void)
972 {
973     int x, y;
974
975     for (y = 0; y < WORLD_Y; ++y) {
976         for (x = y % 2; x < WORLD_X; x += 2) {
977             if (elev[x][y] == -INFINITY)
978                 elev[x][y] = -roll(distance_to_land() * 20 + 27);
979         }
980     }
981 }
982
983 /****************************************************************************
984   ADD THE RESOURCES
985 ****************************************************************************/
986
987 static int
988 set_fert(int e)
989 {
990     int fert = 0;
991     if (e < LANDMIN)
992         fert = LANDMIN - e + 40;
993     else if (e < FERT_MAX)
994         fert = (120 * (FERT_MAX - e)) / (FERT_MAX - LANDMIN);
995     if (fert > 100)
996         fert = 100;
997     return fert;
998 }
999
1000 static int
1001 set_oil(int e)
1002 {
1003     int oil = 0;
1004     if (e < LANDMIN)
1005         oil = (LANDMIN - e) * 2 + roll0(2);
1006     else if (e <= OIL_MAX)
1007         oil = (120 * (OIL_MAX - e + 1)) / (OIL_MAX - LANDMIN + 1);
1008     if (oil > 100)
1009         oil = 100;
1010     return oil;
1011 }
1012
1013 static int
1014 set_iron(int e)
1015 {
1016     int iron = 0;
1017     if (e >= IRON_MIN && e < HIGHMIN)
1018         iron = (120 * (e - IRON_MIN + 1)) / (HIGHMIN - IRON_MIN);
1019     if (iron > 100)
1020         iron = 100;
1021     return iron;
1022 }
1023
1024 static int
1025 set_gold(int e)
1026 {
1027     int gold = 0;
1028     if (e >= GOLD_MIN) {
1029         if (e < HIGHMIN)
1030             gold = (80 * (e - GOLD_MIN + 1)) / (HIGHMIN - GOLD_MIN);
1031         else
1032             gold = 100 - 20 * HIGHMIN / e;
1033     }
1034     if (gold > 100)
1035         gold = 100;
1036     return gold;
1037 }
1038
1039 static int
1040 set_uran(int e)
1041 {
1042     int uran = 0;
1043     if (e >= URAN_MIN && e < HIGHMIN)
1044         uran = (120 * (e - URAN_MIN + 1)) / (HIGHMIN - URAN_MIN);
1045     if (uran > 100)
1046         uran = 100;
1047     return uran;
1048 }
1049
1050 static void
1051 add_resources(struct sctstr *sct)
1052 {
1053     sct->sct_fertil = set_fert(sct->sct_elev);
1054     sct->sct_oil = set_oil(sct->sct_elev);
1055     sct->sct_min = set_iron(sct->sct_elev);
1056     sct->sct_gmin = set_gold(sct->sct_elev);
1057     sct->sct_uran = set_uran(sct->sct_elev);
1058 }
1059
1060 /****************************************************************************
1061   DESIGNATE THE SECTORS
1062 ****************************************************************************/
1063
1064 static void
1065 write_sects(void)
1066 {
1067     struct sctstr *sct;
1068     int c, x, y, total;
1069
1070     for (y = 0; y < WORLD_Y; y++) {
1071         for (x = y % 2; x < WORLD_X; x += 2) {
1072             sct = getsectp(x, y);
1073             total = elev[x][y];
1074             if (total < LANDMIN) {
1075                 sct->sct_type = SCT_WATER;
1076             } else if (total < HILLMIN)
1077                 sct->sct_type = SCT_RURAL;
1078             else if (total < PLATMIN)
1079                 sct->sct_type = SCT_MOUNT;
1080             else if (total < HIGHMIN)
1081                 sct->sct_type = SCT_RURAL;
1082             else
1083                 sct->sct_type = SCT_MOUNT;
1084             sct->sct_elev = total;
1085             sct->sct_newtype = sct->sct_type;
1086             sct->sct_dterr = own[sct->sct_x][y] + 1;
1087             if (ORE)
1088                 add_resources(sct);
1089         }
1090     }
1091     if (AIRPORT_MARKER)
1092         for (c = 0; c < nc; ++c) {
1093             sct = getsectp(capx[c], capy[c]);
1094             sct->sct_type = SCT_AIRPT;
1095             sct->sct_newtype = SCT_AIRPT;
1096         }
1097     set_coastal_flags();
1098 }
1099
1100 /****************************************************************************
1101   PRINT A PICTURE OF THE MAP TO YOUR SCREEN
1102 ****************************************************************************/
1103 static void
1104 output(void)
1105 {
1106     int i, j;
1107     if (quiet == 0) {
1108         for (i = 0; i < WORLD_Y; ++i) {
1109             puts("");
1110             if (i % 2)
1111                 printf(" ");
1112             for (j = i % 2; j < WORLD_X; j += 2) {
1113                 if (own[j][i] == -1)
1114                     printf(". ");
1115                 else {
1116                     printf("%c ", map_symbol(j, i));
1117                 }
1118             }
1119         }
1120     }
1121     if (AIRPORT_MARKER)
1122         printf("\n\nEach continent is marked by a \"*\" on the map (to distinguish them from\n"
1123                "the islands).  You can redesignate these airfields to wilderness sectors\n"
1124                "one at a time, each time you add a new country to the game.\n");
1125 }
1126
1127 static int
1128 map_symbol(int x, int y)
1129 {
1130     int c, iscap = 0;
1131
1132     for (c = 0; c < nc; ++c)
1133         if ((x == capx[c] && y == capy[c])
1134             || (x == new_x(capx[c] + 2) && y == capy[c]))
1135             iscap = 1;
1136     if ((elev[x][y] >= HILLMIN && elev[x][y] < PLATMIN)
1137         || elev[x][y] >= HIGHMIN)
1138         return '^';
1139     return own[x][y] >= nc ? '%' : iscap ? '#' : numletter[own[x][y] % 62];
1140 }
1141
1142 /***************************************************************************
1143   WRITE A SCRIPT FOR PLACING CAPITALS
1144 ****************************************************************************/
1145 static int
1146 write_newcap_script(void)
1147 {
1148     int c;
1149     FILE *script = fopen(outfile, "w");
1150
1151     if (!script) {
1152         printf("fairland: error, unable to write to %s.\n", outfile);
1153         return -1;
1154     }
1155
1156     for (c = 0; c < nc; ++c) {
1157         fprintf(script, "add %d %d %d p\n", c + 1, c + 1, c + 1);
1158         if (AIRPORT_MARKER)
1159             fprintf(script, "des %d,%d -\n", capx[c], capy[c]);
1160         fprintf(script, "newcap %d %d,%d\n", c + 1, capx[c], capy[c]);
1161     }
1162     fprintf(script, "add %d visitor visitor v\n", c + 1);
1163     fclose(script);
1164     return 0;
1165 }
1166
1167 static void
1168 qprint(const char *const fmt, ...)
1169 {
1170     va_list ap;
1171
1172     if (!quiet) {
1173         va_start(ap, fmt);
1174         vfprintf(stdout, fmt, ap);
1175         va_end(ap);
1176     }
1177 }
1178
1179 static void
1180 set_coastal_flags(void)
1181 {
1182     int i, j;
1183     struct sctstr *sp;
1184
1185     qprint("setting coastal flags...\n");
1186     for (i = 0; i < nc; ++i) {
1187         for (j = 0; j < sc; j++) {
1188             sp = getsectp(sectx[i][j], secty[i][j]);
1189             sp->sct_coastal = sectc[i][j];
1190         }
1191     }
1192     for (i = nc; i < nc + ni; ++i) {
1193         for (j = 0; j < isecs[i]; j++) {
1194             sp = getsectp(sectx[i][j], secty[i][j]);
1195             sp->sct_coastal = sectc[i][j];
1196         }
1197     }
1198 }