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