]> git.pond.sub.org Git - empserver/blob - src/util/land.c
Import of Empire 4.2.12
[empserver] / src / util / land.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  *  land.c: New version of empcre - Create the land masses in the game
29  * 
30  *  Known contributors to this file:
31  *     James Anderson, 1987
32  *     Dave Pare, 1989
33  */
34
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include "var.h"
38 #include "misc.h"
39 #include "power.h"
40 #include "nat.h"
41 #include "sect.h"
42 #include "gamesdef.h"
43 #include "file.h"
44 #include "xy.h"
45 #include "prototypes.h"
46
47 #define rnd(x) (random() % (x))
48
49 #define XPLATES         ((WORLD_X) / 2) /* basically world x-y size */
50 #define YPLATES         (WORLD_Y)
51 #define XSIZE           (XPLATES)
52 #define YSIZE           (YPLATES)
53
54 #define BIGV            256             /* used in making altitude */
55 #define SMALLV          128             /* ex-ocean: rnd(SMALLV) - rnd(BIGV) */
56
57 typedef enum plates {
58         OCEAN, ISLAND, CONTINENT
59 } plate_e;
60
61 #define LANDMIN         1               /* plate altitude for normal land */
62 #define HILLMIN         34              /* plate altitude for hills */
63 #define PLATMIN         36              /* plate altitude for plateau */
64 #define HIGHMIN         98              /* plate altitude for mountains */
65
66 #define LANDCH          60                  /* land plate percentage */
67 #define NUMLAND         (YPLATES * XPLATES * LANDCH)/100
68 #define NUMISLE         NUMLAND/5           /* 1 isle for 5 land */
69 #define NUMWATER        (XPLATES * YPLATES) - (NUMLAND + NUMISLE)
70
71 #define SECTRANGE       3               /* smoothing area */
72 #define MINCONTDIST     2               /* minimum continent distance */
73 #define CHUNKSIZE       2               /* basic land block size */
74 #define NEWCONTDIST     (rnd(mincontdist) + mincontdist)
75                                         /* dist away from others for newcont */
76 #define NUMCHUNKS       70              /* number of CHUNKS per cont */
77
78 struct  sctstr sects[YSIZE][XSIZE];
79
80 plate_e plates[YPLATES][XPLATES];
81 int     world[YSIZE][XSIZE];
82
83 int     sectrange = SECTRANGE;
84 int     mincontdist = MINCONTDIST;
85 int     chunksize = CHUNKSIZE;
86 int     numchunks = NUMCHUNKS;
87 int     numisle = NUMISLE;
88
89 static void initworld();
90 static void growcont();
91 static void newcont();
92 static int verify();
93 static int makeland();
94 static void make_altitude();
95 static int total_land();
96 static void make_sects();
97 static void land_sct_init(coord x, coord y, s_char *ptr);
98
99
100 int
101 main(argc, argv)
102         int     argc;
103         s_char  **argv;
104 {
105         extern  struct empfile empfile[];
106         register int n;
107         int     x, y;
108         int     i, j;
109         time_t  now;
110         int     fd;
111         int     left;
112         int     big;
113
114         if (argc > 1 && argc != 6) {
115                 printf("usage: %s sectrange mincontdist chunksize numchunks numisle\n",
116                         *argv);
117                 return -1;
118         }
119         if (argc == 6) {
120                 sectrange = atoi(argv[1]);
121                 mincontdist = atoi(argv[2]);
122                 chunksize = atoi(argv[3]);
123                 numchunks = atoi(argv[4]);
124                 numisle = atoi(argv[5]);
125         }
126         printf("sectrange: %d\n", sectrange);
127         printf("mincontdist: %d\n", mincontdist);
128         printf("chunksize: %d\n", chunksize);
129         printf("numchunks: %d\n", numchunks);
130         printf("numisle: %d\n", numisle);
131         fd = open(empfile[EF_SECTOR].file, O_RDWR|O_CREAT|O_TRUNC, 0660);
132         if (fd < 0) {
133                 perror(empfile[EF_SECTOR].file);
134                 return -1;
135         }
136         time(&now);
137         srandom(now+getpid());
138         initworld((plate_e *)plates);
139         left = NUMLAND;
140         printf("Creating continents");
141         while (left > 0) {
142                 big = (left / (numchunks * 3 * chunksize*chunksize)) + 1;
143                 for (n=0; n<big; n++) {
144                         newcont(plates, &x, &y, NEWCONTDIST);
145                         left -= makeland(plates, x, y, chunksize, CONTINENT);
146                 }
147                 for (n=0; n < big * numchunks; n++) {
148                         growcont(plates, &x, &y);
149                         left -= makeland(plates, x, y, chunksize, CONTINENT);
150                         if ((n % numchunks) == 0) {
151                                 printf(".");
152                                 fflush(stdout);
153                         }
154                 }
155         }
156         printf("\n");
157         printf("Creating islands");
158         for (n = 0; n < numisle; n++) {
159                 /* find an open spot */
160                 while (plates[(i = rnd(YPLATES))][(j = rnd(XPLATES))] != OCEAN)
161                         ;
162                 plates[i][j] = ISLAND;
163         }
164         printf("\n");
165         printf("Making altitude\n");
166         make_altitude(plates, world);
167         printf("Creating sectors\n");
168         make_sects(world, sects);
169         printf("Writing sectors\n");
170         n = write(fd, sects, sizeof(sects));
171         if (n < 0) {
172                 perror(empfile[EF_SECTOR].file);
173                 return -1;
174         }
175         if (n != sizeof(sects)) {
176                 printf("%s: partial write\n", empfile[EF_SECTOR].file);
177                 return -1;
178         }
179         close(fd);
180         exit(0);
181 }
182
183 static void
184 initworld(plates)
185         register plate_e *plates;
186 {
187         register int i;
188
189         for (i=0; i<XPLATES*YPLATES; i++)
190                 *plates++ = OCEAN;
191 }
192
193 static void
194 growcont(plates, xp, yp)
195         register plate_e plates[YPLATES][XPLATES];
196         int     *xp;
197         int     *yp;
198 {
199         int     x, y;
200
201         /* merge with another one */
202         while (plates[(y=rnd(YPLATES))][(x=rnd(XPLATES))] == OCEAN)
203                 ;
204         *xp = x;
205         *yp = y;
206 }
207
208 static void
209 newcont(plates, xp, yp, dist)
210         register plate_e plates[YPLATES][XPLATES];
211         int     *xp;
212         int     *yp;
213         int     dist;
214 {
215         register int x, y;
216         int     i;
217
218         for (i=0; i < 30; i++) { 
219                 y = rnd(YPLATES);
220                 x = rnd(XPLATES);
221                 if (verify(plates, x, y, OCEAN, dist))
222                         break;
223         }
224         if (i == 30) {
225                 growcont(plates, xp, yp);
226         } else {
227                 *xp = x;
228                 *yp = y;
229         }
230 }
231
232 /*
233  * verify that with "dist", there are only type "what" sectors
234  * returns 0 if fail, 1 if success.
235  */
236 static int
237 verify(plates, x, y, what, dist)
238         register plate_e plates[YPLATES][XPLATES];
239         int     x;
240         int     y;
241         int     what;
242         int     dist;
243 {
244         register int xbase, ybase;
245         register int x1, y1;
246
247         for (ybase = y - dist; ybase <= y + dist; ybase++) {
248                 for (xbase = x - dist; xbase <= x + dist; xbase++) {
249                         /* normalize to world coords */
250                         y1 = ybase < 0 ? ybase+YPLATES : ybase % YPLATES;
251                         x1 = xbase < 0 ? xbase+XPLATES : xbase % XPLATES;
252                         if (plates[y1][x1] != what)
253                                 return 0;
254                 }
255         }
256         return 1;
257 }
258
259 static int
260 makeland(plates, x, y, dist, what)
261         register plate_e plates[YPLATES][XPLATES];
262         int     x;
263         int     y;
264         int     dist;
265         int     what;
266 {
267         register int xbase, ybase;
268         register int xfail, yfail;
269         register int x1, y1;
270         int     created;
271
272         created = 0;
273         for (ybase = y - dist; ybase <= y + dist; ybase++) {
274                 yfail = y - ybase;
275                 if (yfail < 0)
276                         yfail = -yfail;
277                 y1 = ybase < 0 ? ybase+YPLATES : ybase % YPLATES;
278                 for (xbase = x - dist; xbase <= x + dist; xbase++) {
279                         x1 = xbase < 0 ? xbase+XPLATES : xbase % XPLATES;
280                         if (plates[y1][x1] != OCEAN)
281                                 continue;
282                         xfail = x - x1;
283                         if (xfail < 0)
284                                 xfail = -xfail;
285                         if (xfail < yfail)
286                                 xfail = yfail;
287                         if (xfail < dist-1 || !rnd(xfail + 1) ||
288                             !rnd(xfail + 1)) {
289                                 plates[y1][x1] = what;
290                                 created++;
291                         }
292                 }
293         }
294         return created;
295 }
296
297 static void
298 make_altitude(plates, world)
299         register plate_e plates[YPLATES][XPLATES];
300         register int world[YSIZE][XSIZE];
301 {
302         register int x, y;
303
304         for (y = 0; y < YPLATES; y++) {
305                 for (x = 0; x < XPLATES; x++) {
306                         switch (plates[y][x]) {
307                         case OCEAN:
308                                 /*-BIGV, -SMALLV/2, SMALLV*/
309                                 world[y][x] = rnd(SMALLV) - rnd(BIGV);
310                                 break;
311                         case ISLAND:
312                                 /*-BIGV, 0, BIGV*/
313                                 world[y][x] = rnd(BIGV) - rnd(BIGV) + 2;
314                                 break;
315                         case CONTINENT:
316                                 /*-SMALLV, SMALLV/2, BIGV*/
317                                 world[y][x] = rnd(BIGV) - rnd(SMALLV);
318                         }
319                 }
320         }
321 }
322
323 static int
324 total_land(world, xbase, ybase, range)
325         register int world[YSIZE][XSIZE];
326         register int xbase;
327         int ybase;
328         register int range;
329 {
330         register int x;
331         register int xmax;
332         register int total;
333         register int *row;
334         int     y;
335         int     ymax;
336
337         total = 0;
338         xmax = xbase + range;
339         ymax = ybase + range;
340         for (y = ybase; y < ymax; y++) {
341                 row = world[y % YSIZE];
342                 for (x = xbase; x < xmax; x++)
343                         total += row[x % XSIZE];
344         }
345         return total;
346 }
347
348 static void
349 make_sects(world, sects)
350         register int world[YSIZE][XSIZE];
351         struct sctstr *sects;
352 {
353         register struct sctstr *sct;
354         register int i;
355         register int x, y;
356         int     elev[12+12+3]; /* # sects from -12 to 12 in steps of 10 elev */
357         int     range;
358         int     rangesq;
359         int     total;
360         int     sum;
361
362         for (i = 0; i < 12+12+3; i++)
363                 elev[i] = 0;
364         sum = 0;
365         sct = sects;
366         for (y = 0; y < YSIZE; y++) {
367                 for (x = 0; x < XSIZE; x++, sct++) {
368                         land_sct_init(x*2 + (y & 01), y, (s_char *)sct);
369                         range = 3 + rnd(sectrange);
370                         rangesq = range * range;
371                         total = total_land(world, x, y, range) / rangesq;
372                         if (total < LANDMIN) {
373                                 sct->sct_type = SCT_WATER;
374                         } else if (total < HILLMIN)
375                                 sct->sct_type = SCT_RURAL;
376                         else if (total < PLATMIN)
377                                 sct->sct_type = SCT_MOUNT;
378                         else if (total < HIGHMIN)
379                                 sct->sct_type = SCT_RURAL;
380                         else
381                                 sct->sct_type = SCT_MOUNT;
382                         sct->sct_elev = total;
383                         sct->sct_newtype = sct->sct_type;
384                         sum += total;
385                         if (total < -129)
386                                 elev[0]++;
387                         else
388                                 if (total > 129)
389                                         elev[26]++;
390                                 else
391                                         elev[13+total/10]++;
392                 }
393         }
394         for (i = 0; i < 12+12+3; i++)
395                 if (elev[i] != 0)
396                         printf("%4d sectors elevation %4d to %4d\n",
397                                 elev[i], 10*i - 140, 10*i - 130);
398 }
399
400 static void
401 land_sct_init(coord x, coord y, s_char *ptr)
402 {
403         struct  sctstr *sp = (struct sctstr *) ptr;
404
405         sp->ef_type = EF_SECTOR;
406         sp->sct_x = x;
407         sp->sct_y = y;
408         sp->sct_dist_x = x;
409         sp->sct_dist_y = y;
410 }