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