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