Crossfire Server, Trunk
land.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 
4 #define MAX_SIZE 3000
5 #define MAX(x,y) ((x)>(y)?(x):(y))
6 
7 #define BASE_ALT -100
8 
9 /* make this a global to avoid stack overflow */
11 
12 /* This function writes out the crossfire maps. So shoot me for
13  * using compiled in constants - I'm not going to use this so much
14  * that I wanted to do anything too easy.
15  */
16 
17 #define MAP_FORMAT "world_%03d_%03d"
18 
19 /* Maps are square */
20 
21 #define MAP_SIZE 50
22 
23 /* There will be a total of 2500 maps (eek) - 50 in
24  * each direction. startx and starty are where to start
25  * numbering from. I chose 100 for a few reasons - 1) it
26  * gives room to the left and above to add some things (another
27  * continent for that matter), and 2) since the format allows
28  * for up to 1000 in each direction, this seemed reasonable.
29  * Note - if you do the math, and have 1000 * 1000 maps, each
30  * with 50*50 spaces, you have a total of 2.5 billion spaces.
31  * So hopefully that should be large enough.
32  */
33 
34 int startx=100, starty=100;
35 
36 typedef enum {
37  None=0,
41  Swamp=4,
43  Grass=6,
44  Desert=7,
45  Brush=8,
47  Jungle=10,
48  Tree1=11,
49  Tree2=12,
50  Woods1=13,
51  Woods2=14,
52  Woods3=15,
53  Hills=16,
55  Steppe=18,
58  WasteLand=21, /*Now just higher mountain */
59  Beach = 22,
62 
63 char *Terrain_Names[][2] = {
64  /* these are the archetype names. They are in the same order
65  * as the Terrain_Types above. Note many terrain types are not
66  * included because handling them would be too difficult.
67  */
68  {"None", "0, 0, 0 "},
69  {"deep_sea", "0 0 127 "},
70  {"sea", "0 0 192 "},
71  {"shallow_sea", "0 0 255 "}, /* wading depth */
72  {"swamp", "12 161 64 "},
73  {"deep_swamp", "155 175 164 "},
74  {"grass", "0 255 0 "},
75  {"desert", "222 218 135 "},
76  {"brush", "1 144 1 "},
77  {"evergreens", "0 128 0 "},
78  {"jungle_1", "0 176 0 "},
79  {"tree", "4 133 01 "},
80  {"evergreen", "20 209 0 "},
81  {"woods", "4 115 01 "},
82  {"woods_2", "1 182 02 "},
83  {"woods_3", "4 153 02 "},
84  {"hills", "166 160 70 "},
85  {"hills_rocky", "166 155 70 "},
86  {"steppe", "150 97 34 "},
87  {"mountain", "183 190 190 "},
88  {"mountain2", "191 196 185 "},
89  {"mountain4", "215 215 215 "},
90  /* Maybe need to put in order? */
91  {"beach", "232 228 165 "},
92  {"mountain5", "255 255 255 "},
93 };
94 
95 
96 
97 void write_crossfire_maps(int mapy, int mapx)
98 {
99  int x, y,n,q, nx, ny,r1,r2,ax=0,ay=0, j, k;
100  char name[512];
101  FILE *fp;
102  Terrain_Types *terrain;
103 
104  terrain = calloc(mapx * mapy * sizeof(Terrain_Types), sizeof(Terrain_Types));
105 
106  /* First fill in the water and the highest of peaks */
107  for (x=0; x<mapx; x++) {
108  for (y=0; y<mapy; y++) {
109  if (altitude[y][x] < -5000) {
110  terrain[x + y * mapx] = DeepWater;
111  } else if (altitude[y][x] < -99) {
112  terrain[x + y * mapx] = MediumWater;
113  } else if (altitude[y][x] < 1) {
114  terrain[x + y * mapx] = ShallowWater;
115  } else if (altitude[y][x] >=25000) {
116  terrain[x + y * mapx] = VeryHighMountain;
117  }
118  }
119  }
120  /* Basically, take a random bit and populate the area with terrain.
121  * We do this so it won't be totally monolithic (have several forest types
122  * for example), yet patches will be the same thing, eg, a stretch of
123  * desert, which wouldn't work very well if we just chose randomly
124  * for each space.
125  */
126 
127  for (n=0; n<(mapx * mapy) / 100; n++) {
128  do {
129  x = random() % mapx;
130  y = random() % mapy;
131  } while ( terrain[x + y * mapx] == None);
132 
133  nx = x + 40;
134  if (nx > mapx) nx=mapx;
135  ny = y + 40;
136  if (ny > mapy) ny = mapy;
137  r1 = random();
138  r2 = random();
139  for (x = nx-40; x<nx; x++) {
140  for (y=ny-40; y<ny; y++) {
141  if (terrain[x + y * mapx] != None) continue;
142 
143  /* near the edges, don't always fill in so that hopefully something
144  * else will fill in and smooth these out some
145  */
146  if ( (x < (nx -30) || y < (ny - 30) || x > (nx -10) || y > (ny - 10)) &&
147  random() % 2) continue;
148 
149  if (altitude[y][x] < 10) {
150  terrain[x + y * mapx] = Swamp + (r1 % 2);
151  }
152  else if (altitude[y][x] < 75){
153  terrain[x + y * mapx] = Beach;
154  }
155  else if (altitude[y][x] < 1000) {
156  terrain[x + y * mapx] = Grass + (r1 % 3);
157  } else if (altitude[y][x] < 3000) {
158  terrain[x + y * mapx] = EverGreens + (r1 % 9);
159  } else if (altitude[y][x] < 5000) {
160  terrain[x + y * mapx] = Hills + (r2 % 3);
161  } else if (altitude[y][x] < 9000) {
162  terrain[x + y * mapx] = Mountain;
163  } else if (altitude[y][x] < 12000) {
164  terrain[x + y * mapx] = HighMountain;
165  } else if (altitude[y][x] < 25000) {
166  /* Not really precisely wasteland, but wastelands are impassable */
167  terrain[x + y * mapx] = WasteLand;
168  }
169  else fprintf(stderr,"altitude %d did not get filled in?\n", altitude[y][x]);
170  }
171  }
172  }
173  /* Now just fill in the spaces randomly. */
174  n=0;
175  r1 = random();
176  r2 = random();
177  for (x=0; x<mapx; x++) {
178  for (y=0; y<mapy; y++) {
179  if (terrain[x + y * mapx] != None) continue;
180  n++;
181  if (altitude[y][x] < 10) {
182  terrain[x + y * mapx] = Swamp + (r1 % 2);
183  }
184  else if (altitude[y][x] < 75){
185  terrain[x + y * mapx] = Beach;
186  }
187  else if (altitude[y][x] < 1000) {
188  terrain[x + y * mapx] = Grass + (r1 % 3);
189  } else if (altitude[y][x] < 3000) {
190  terrain[x + y * mapx] = EverGreens + (r2 % 9);
191  } else if (altitude[y][x] < 5000) {
192  terrain[x + y * mapx] = Hills + (r2 % 3);
193  } else if (altitude[y][x] < 9000) {
194  terrain[x + y * mapx] = Mountain;
195  } else if (altitude[y][x] < 12000) {
196  terrain[x + y * mapx] = HighMountain;
197  } else if (altitude[y][x] < 25000) {
198  terrain[x + y * mapx] = WasteLand;
199  }
200  }
201  }
202  fprintf(stderr,"Filled in %d spaces\n",n);
203  if ((mapx / MAP_SIZE) * MAP_SIZE != mapx ||
204  (mapy / MAP_SIZE) * MAP_SIZE != mapy) {
205  fprintf(stderr,"Warning - generated map does not evenly tile.\n");
206  }
207  for (nx= startx; nx<(startx + (mapx/ MAP_SIZE)); nx++) {
208  for (ny= starty; ny<(starty + (mapy/ MAP_SIZE)); ny++) {
209  ax = (nx - startx) * MAP_SIZE;
210  ay = (ny - starty) * MAP_SIZE;
211 
212  sprintf(name,MAP_FORMAT,nx,ny);
213  if ((fp=fopen(name, "w"))==NULL) {
214  fprintf(stderr,"unable to open %s\n", name);
215  }
216  /* Write the header for the map */
217  fprintf(fp,"arch map\n");
218  fprintf(fp,"name %s\n", name);
219  fprintf(fp,"width %d\n", MAP_SIZE);
220  fprintf(fp,"height %d\n", MAP_SIZE);
221  /* Not used right now, but useful to include */
222  fprintf(fp,"outdoor 1\n");
223 
224  /* don't do difficult, reset time, or enter coordinates */
225  /* Set up the tile paths */
226  if (ny != starty) {
227  fprintf(fp,"tile_path_1 ");
228  fprintf(fp,MAP_FORMAT,nx, ny-1);
229  fprintf(fp,"\n");
230  }
231  if ((nx+1) < startx + (mapx/ MAP_SIZE)) {
232  fprintf(fp,"tile_path_2 ");
233  fprintf(fp,MAP_FORMAT,nx+1, ny);
234  fprintf(fp,"\n");
235  }
236  if ((ny+1) < starty + (mapy/ MAP_SIZE)) {
237  fprintf(fp,"tile_path_3 ");
238  fprintf(fp,MAP_FORMAT,nx, ny+1);
239  fprintf(fp,"\n");
240  }
241  if (nx != startx) {
242  fprintf(fp,"tile_path_4 ");
243  fprintf(fp,MAP_FORMAT,nx-1, ny);
244  fprintf(fp,"\n");
245  }
246  fprintf(fp,"end\n");
247  for (x = 0; x<50; x++) {
248  for (y = 0; y < 50; y++) {
249  q = terrain[x + ax + (y + ay)* mapx];
250  fprintf(fp, "arch %s\n",Terrain_Names[q][0]);
251  fprintf(fp,"x %d\n", x);
252  fprintf(fp,"y %d\n", y);
253  q = altitude[y + ay ][x + ax];
254  if (q< -32000) q = -32000;
255  if (q > 32000) q = 32000;
256  fprintf(fp,"elevation %d\n", q);
257  fprintf(fp,"end\n");
258  }
259  }
260  fclose(fp);
261  }
262  }
263 
264  fp = fopen("cmap", "w");
265  fprintf(fp, "P3 %d %d 255\n", mapy, mapx);
266  for (y=0; y < mapy; y++) {
267  for (x=0; x < mapx; x++) {
268  fprintf(fp, "%s", Terrain_Names[terrain[x + y * mapx]][1]);
269  }
270  fprintf(fp, "\n");
271  }
272  exit(0);
273 }
274 
275 
276 
277 main(int argc, char *argv)
278 {
279  int x, y, max_x=500, max_y=500, seed, land=300000, npasses=40, newalt, wpasses=50, water=50000;
280  int n, i, j, k, l, z, w, r, a, write_maps=0;
281  FILE *fp, *lp;
282  int junk;
283  char c;
284  extern char *optarg;
285 
286  seed = time(NULL);
287  while ((c = getopt(argc, argv,"x:y:X:Y:s:l:n:w:p:m"))!=-1) {
288  switch (c) {
289  case 'l':
290  land = atoi(optarg);
291  if (land < 11 ) {
292  fprintf(stderr,"-l must be at least 11\n");
293  exit(1);
294  }
295  break;
296 
297  case 'w':
298  water = atoi(optarg);
299  if (water < 1 ) {
300  fprintf(stderr,"-w must be at least 1\n");
301  exit(1);
302  }
303  break;
304 
305  case 'p':
306  wpasses = atoi(optarg);
307  if (wpasses < 1 ) {
308  fprintf(stderr,"-w must be at least 1\n");
309  exit(1);
310  }
311  break;
312 
313  case 'n':
314  npasses = atoi(optarg);
315  if (npasses < 10 ) {
316  fprintf(stderr,"-n must be at least 10\n");
317  exit(1);
318  }
319  break;
320 
321  case 'x':
322  max_x = atoi(optarg);
323  break;
324 
325  case 'y':
326  max_y = atoi(optarg);
327  break;
328 
329  case 'X':
330  startx = atoi(optarg);
331 
332  case 'Y':
333  starty = atoi(optarg);
334  break;
335 
336  case 's':
337  seed = atoi(optarg);
338  break;
339 
340  case 'm':
341  write_maps=1;
342  break;
343  }
344  }
345  if (max_x > MAX_SIZE || max_y > MAX_SIZE) {
346  fprintf(stderr,"Max X and Y size is %d\n", MAX_SIZE);
347  exit(1);
348  }
349 
350  fprintf(stderr,"Making %d X %d map, seed %d, land %d, passes = %d\n", max_x, max_y, seed, land, npasses);
351  fprintf(stderr,"wpasses =%d, water=%d\n", wpasses, water);
352  fprintf(stderr,"-x %d -y %d -X %d -Y %d -s %d -p %d -n %d -w %d -l %d\n",
353  max_x, max_y, startx, starty, seed, wpasses, npasses, water, land);
354 
355  srandom(seed);
356 
357  for (x=20; x < max_x-20; x++)
358  for (y=20; y < max_y-20; y++)
359  altitude[x][y] = BASE_ALT;
360 
361  for (x=0; x<max_x; x++) {
362  for (y=0; y<20; y++) {
363  altitude[x][y] = (y -20 ) * 100;
364  altitude[x][max_y - y] = (y -20 ) * 100;
365  }
366  }
367 
368  for (y=10; y<max_y-10; y++) {
369  for (x=0; x<20; x++) {
370  altitude[x][y] = (x - 20) * 100;
371  altitude[max_x - x][y] = (x - 20) * 100;
372  }
373  }
374 
375  /* This basically produces areas of high variance (eg, islands, peaks, valleys, etc) */
376 
377  for (l=0; l<npasses; l++) {
378  x = random()%max_x;
379  y = random()%max_y;
380  /* Weigh our selected starting position a little more towards the center
381  * so the continent is more in the center
382  */
383  if (random() % 2) {
384  x += random()%max_x;
385  y += random()%max_y;
386  x /=2;
387  y /=2;
388  }
389  n = random()%500+800;
390 
391  /* For some portion, try to find a pixel we have yet to modify */
392  if (l> (npasses * 15) / 20) {
393  int tries=0;
394  while (altitude[x][y] == BASE_ALT) {
395  x = random()%max_x;
396  y = random()%max_y;
397  if (random() % 2) {
398  x += random()%max_x;
399  y += random()%max_y;
400  x /=2;
401  y /=2;
402  }
403  tries++;
404  if (tries > 50) {
405  fprintf(stderr,"did not find free space within %d tries\n", tries);
406  break;
407  }
408  }
409 
410  }
411 
412  for (k=1; k< land ; k++) {
413  r = random()%4;
414  switch (r) {
415  case 0: if (x<max_x-1) x++; else x -= random() % (max_x/2); break;
416  case 1: if (y<max_y-1) y++; else y -= random() % (max_y/2); break;
417  case 2: if (x) x--; else x+= random() % (max_x/2); break;
418  case 3: if (y) y--; else y+= random() % (max_y/2); break;
419  }
420  altitude[x][y] += n;
421  if (random()%k < 100)
422  n -= 1;
423  }
424  }
425 
426  /* Make lakes and ocean trenches.
427  * General note - it works better to have more passes, but each
428  * pass doing less working - this results in more consistent lakes
429  * and ocean trenching.
430  */
431  for (l=0; l<wpasses; l++) {
432  /* for a small portion, we lower the area we make */
433  n = random()%1500-2000;
434 
435  x = random()% max_x;
436  y = random()% max_y;
437 
438  while (altitude[x][y] > BASE_ALT || altitude[x][y]<-7000) {
439  x = random()% max_x;
440  y = random()% max_y;
441  }
442  for (k=1; k< water ; k++) {
443  r = random()%4;
444  switch (r) {
445  case 0: if (x<max_x-1) x++; break;
446  case 1: if (y<max_y-1) y++; break;
447  case 2: if (x) x--; break;
448  case 3: if (y) y--; break;
449  }
450  altitude[x][y] += n;
451  if (random()%k < 100)
452  n += 1; /*less dramatic as things go on */
453  }
454  }
455 
456 
457  /* This block seems to average out the spaces somewhat to prevent
458  * cliffs and the like.
459  */
460 #define NUM_PASSES 3
461  r = 10;
462  for (k=0; k<NUM_PASSES; k++) {
463  for (x=2; x<max_x-2; x++) {
464  for (y=2; y<max_y - 2; y++) {
465  newalt = (altitude[x][y] * r + altitude[x-1][y] +
466  altitude[x][y-1] + altitude[x-1][y-1] +
467  altitude[x+1][y] + altitude[x][y+1] +
468  altitude[x+1][y+1] + altitude[x+1][y-1] +
469  altitude[x-1][y+1]) / (r+8);
470  if (altitude[x][y] < 10 || altitude[x][y] > newalt) altitude[x][y] = newalt;
471  }
472  }
473  for (x=max_x-2; x>2; x--) {
474  for (y=max_y-2; y>2; y--) {
475  newalt = (altitude[x][y] * r + altitude[x-1][y] +
476  altitude[x][y-1] + altitude[x-1][y-1] +
477  altitude[x+1][y] + altitude[x][y+1] +
478  altitude[x+1][y+1] + altitude[x+1][y-1] +
479  altitude[x-1][y+1]) / (r+8);
480  if (altitude[x][y] < 10 || altitude[x][y] > newalt) altitude[x][y] = newalt;
481  }
482  }
483  }
484 
485 /* Make this 100 so that we eliminate/reduce the lakiness of
486  * the map that is otherwise generated - otherwise, the map
487  * looks like an archipelago
488  */
489 #define AVG_PT -10
490 
491  /* water - does the same as above, but try to more equally balance the spaces*/
492  r = 1;
493  for (k=0; k<40; k++) {
494  for (x=2; x<max_x-2; x++) {
495  for (y=2; y<max_y -2; y++) {
496  if (altitude[x][y] < AVG_PT)
497  altitude[x][y] = (altitude[x][y] * r + altitude[x-1][y] +
498  altitude[x][y-1] + altitude[x-1][y-1] +
499  altitude[x+1][y] + altitude[x][y+1] +
500  altitude[x+1][y+1] + altitude[x+1][y-1] +
501  altitude[x-1][y+1]) / (r+8);
502  }
503  }
504  for (x=max_x-2; x>2; x--) {
505  for (y=max_y-2; y>2; y--) {
506  if (altitude[x][y] < AVG_PT)
507  altitude[x][y] = (altitude[x][y] * r + altitude[x-1][y] +
508  altitude[x][y-1] + altitude[x-1][y-1] +
509  altitude[x+1][y] + altitude[x][y+1] +
510  altitude[x+1][y+1] + altitude[x+1][y-1] +
511  altitude[x-1][y+1]) / (r+8);
512  }
513  }
514  }
515  if (write_maps)
516  write_crossfire_maps(max_x, max_y);
517 
518  /* Now write the data out */
519 
520  fp = fopen("lmap", "w");
521  lp = fopen("pmap", "w");
522  fprintf(fp, "P3 %d %d 255\n", max_y, max_x);
523  for (j=0; j < max_x; j++) {
524  for (k=0; k < max_y; k++) {
525  junk = altitude[j][k];
526  fprintf(lp, "%d ", altitude[j][k]);
527  if (junk < -5000)
528  fprintf(fp, "0 0 127 ");
529  /* Shallow water should really be just at the coastal
530  * area, so put a big gap between shallow and deep.
531  * this also evens out the occurrence of the different types
532  * to be more equal
533  */
534  else if (junk < -99)
535  fprintf(fp, "0 0 192 ");
536  else if (junk < 1)
537  fprintf(fp, "0 0 255 ");
538  else if (junk < 1000)
539  fprintf(fp, "0 240 0 ");
540  else if (junk < 2000)
541  fprintf(fp, "0 220 0 ");
542  else if (junk < 3000)
543  fprintf(fp, "0 200 0 ");
544  else if (junk < 4000)
545  fprintf(fp, "0 180 0 ");
546  else if (junk < 5000)
547  fprintf(fp, "0 160 0 ");
548  else if (junk < 6000)
549  fprintf(fp, "255 130 71 ");
550  else if (junk < 8000)
551  fprintf(fp, "238 121 66 ");
552  else if (junk < 10000)
553  fprintf(fp, "205 104 57 ");
554  else if (junk < 12000)
555  fprintf(fp, "139 71 38 ");
556  else
557  fprintf(fp, "255 255 255 ");
558  }
559  fprintf(fp, "\n");
560  }
561  exit(0);
562 }
banquet.l
l
Definition: banquet.py:164
AVG_PT
#define AVG_PT
diamondslots.x
x
Definition: diamondslots.py:15
BASE_ALT
#define BASE_ALT
Definition: land.c:7
write_crossfire_maps
void write_crossfire_maps(int mapy, int mapx)
Definition: land.c:97
c
static event_registration c
Definition: citylife.cpp:425
disinfect.a
a
Definition: disinfect.py:13
Terrain_Types
Terrain_Types
Definition: land.c:36
ShallowWater
@ ShallowWater
Definition: land.c:40
Moving_Fog.z
z
Definition: Moving_Fog.py:17
Grass
@ Grass
Definition: land.c:43
DeepWater
@ DeepWater
Definition: land.c:38
Steppe
@ Steppe
Definition: land.c:55
Terrain_Names
char * Terrain_Names[][2]
Definition: land.c:63
item.q
q
Definition: item.py:32
Woods1
@ Woods1
Definition: land.c:50
main
main(int argc, char *argv)
Definition: land.c:277
DeepSwamp
@ DeepSwamp
Definition: land.c:42
Tree1
@ Tree1
Definition: land.c:48
Jungle
@ Jungle
Definition: land.c:47
Hills
@ Hills
Definition: land.c:53
starty
int starty
Definition: land.c:34
Woods2
@ Woods2
Definition: land.c:51
Brush
@ Brush
Definition: land.c:45
MAX_SIZE
#define MAX_SIZE
Definition: land.c:4
HillsRocky
@ HillsRocky
Definition: land.c:54
WasteLand
@ WasteLand
Definition: land.c:58
startx
int startx
Definition: land.c:34
MediumWater
@ MediumWater
Definition: land.c:39
Beach
@ Beach
Definition: land.c:59
HighMountain
@ HighMountain
Definition: land.c:57
Tree2
@ Tree2
Definition: land.c:49
diamondslots.y
y
Definition: diamondslots.py:16
altitude
int altitude[MAX_SIZE][MAX_SIZE]
Definition: land.c:10
MAP_FORMAT
#define MAP_FORMAT
Definition: land.c:17
Woods3
@ Woods3
Definition: land.c:52
NUM_PASSES
#define NUM_PASSES
MAP_SIZE
#define MAP_SIZE
Definition: land.c:21
VeryHighMountain
@ VeryHighMountain
Definition: land.c:60
None
@ None
Definition: land.c:37
Swamp
@ Swamp
Definition: land.c:41
Mountain
@ Mountain
Definition: land.c:56
ring_occidental_mages.r
r
Definition: ring_occidental_mages.py:6
give.name
name
Definition: give.py:27
EverGreens
@ EverGreens
Definition: land.c:46
Desert
@ Desert
Definition: land.c:44