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