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