#include #include #define MAX_SIZE 3000 #define MAX(x,y) ((x)>(y)?(x):(y)) #define BASE_ALT -100 /* make this a global to avoid stack overflow */ int altitude[MAX_SIZE][MAX_SIZE]; /* This function writes out the crossfire maps. So shoot me for * using compiled in constants - I'm not going to use this so much * that I wanted to do anything too easy. */ #define MAP_FORMAT "world_%03d_%03d" /* Maps are square */ #define MAP_SIZE 50 /* There will be a total of 2500 maps (eek) - 50 in * each diretion. STARTX and STARTY are where to start * numbering from. I chose 100 for a few reasons - 1) it * gives room to the left and above to add some things (another * continent for that matter), and 2) since the format allows * for up to 1000 in each direction, this seemed reasonable. * Note - if you do the math, and have 1000 * 1000 maps, each * with 50*50 spaces, you have a total of 2.5 billion spaces. * So hopefully that should be large enough. */ #define STARTX 100 #define STARTY 100 typedef enum { None=0, DeepWater=1, MediumWater=2, ShallowWater=3, Swamp=4, DeepSwamp=5, Grass=6, Desert=7, Brush=8, EverGreens=9, Jungle=10, Tree1=11, Tree2=12, Woods1=13, Woods2=14, Woods3=15, Hills=16, HillsRocky=17, Steppe=17, Mountain=19, HighMountain=20, WasteLand=21 } Terrain_Types; char *Terrain_Names[][2] = { /* these are the archetype names. They are in the same order * as the Terrain_Types above. Note many terrain types are not * included because handling them would be too difficult. */ {"None", "0, 0, 0 "}, {"deep_sea", "0 0 127 "}, {"sea", "0 0 192 "}, {"shallow_sea", "0 0 255 "}, /* wading depth */ {"swamp", "12 161 64 "}, {"deep_swamp", "155 175 164 "}, {"grass", "0 255 0 "}, {"desert", "222 218 135 "}, {"brush", "1 144 1 "}, {"evergreens", "0 128 0 "}, {"jungle_1", "0 176 0 "}, {"tree", "4 133 01 "}, {"evergreen", "20 209 0 "}, {"woods", "4 115 01 "}, {"woods_2", "1 182 02 "}, {"woods_3", "4 153 02 "}, {"hills", "166 160 70 "}, {"hills_rocky", "166 155 70 "}, {"steppe", "150 97 34 "}, {"mountain", "183 190 190 "}, {"mountain2", "191 196 185 "}, {"wasteland", "255 255 255 "}, }; void write_crossfire_maps(int mapx, int mapy) { int x, y,n,q, nx, ny,r1,r2,ax=0,ay=0, j, k; char name[512]; FILE *fp; Terrain_Types *terrain; terrain = calloc(mapx * mapy * sizeof(Terrain_Types), sizeof(Terrain_Types)); /* First fill in the water and the highest of peaks */ for (x=0; x=12000) { /* Not really precisely wasteland, but wastelands are impassable */ terrain[x + y * mapx] = WasteLand; } } } /* Basically, take a random bit and populate the area with terrain. * We do this so it won't be totally monolythic (have several forest types * for example), yet patches will be the same thing, eg, a stretch of * desert, which wouldn't work very well if we just chose randomly * for each space. */ for (n=0; n<(mapx * mapy) / 100; n++) { do { x = random() % mapx; y = random() % mapy; } while ( terrain[x + y * mapx] == None); nx = x + 40; if (nx > mapx) nx=mapx; ny = y + 40; if (ny > mapy) ny = mapy; r1 = random(); r2 = random(); for (x = nx-40; x (nx -10) || y > (ny - 10)) && random() % 2) continue; if (altitude[y][x] < 10) { terrain[x + y * mapx] = Swamp + (r1 % 2); } else if (altitude[y][x] < 1000) { terrain[x + y * mapx] = Grass + (r1 % 3); } else if (altitude[y][x] < 3000) { terrain[x + y * mapx] = EverGreens + (r1 % 9); } else if (altitude[y][x] < 5000) { terrain[x + y * mapx] = Hills + (r2 % 3); } else if (altitude[y][x] < 9000) { terrain[x + y * mapx] = Mountain; } else if (altitude[y][x] < 12000) { terrain[x + y * mapx] = HighMountain; } else fprintf(stderr,"altitude %d did not get filled in?\n", altitude[y][x]); } } } /* Now just fill in the spaces randomly. */ n=0; r1 = random(); r2 = random(); for (x=0; x 32000) q = 32000; fprintf(fp,"elevation %d\n", q); fprintf(fp,"end\n"); } } fclose(fp); } } fp = fopen("cmap", "w"); fprintf(fp, "P3 %d %d 255\n", mapy, mapx); for (y=0; y < mapy; y++) { for (x=0; x < mapx; x++) { fprintf(fp, Terrain_Names[terrain[x + y * mapx]][1]); } fprintf(fp, "\n"); } exit(0); } main(int argc, char *argv) { int x, y, max_x=500, max_y=500, seed, land=300000, npasses=40, newalt, wpasses=50, water=50000; int n, i, j, k, l, z, w, r, a, write_maps=0; FILE *fp, *lp; int junk; char c; extern char *optarg; seed = time(NULL); while ((c = getopt(argc, argv,"x:y:s:l:n:w:p:m"))!=-1) { switch (c) { case 'l': land = atoi(optarg); if (land < 11 ) { fprintf(stderr,"-l must be at least 11\n"); exit(1); } break; case 'w': water = atoi(optarg); if (water < 1 ) { fprintf(stderr,"-w must be at least 1\n"); exit(1); } break; case 'p': wpasses = atoi(optarg); if (wpasses < 1 ) { fprintf(stderr,"-w must be at least 1\n"); exit(1); } break; case 'n': npasses = atoi(optarg); if (npasses < 10 ) { fprintf(stderr,"-n must be at least 10\n"); exit(1); } break; case 'x': max_x = atoi(optarg); break; case 'y': max_y = atoi(optarg); break; case 's': seed = atoi(optarg); break; case 'm': write_maps=1; break; } } if (max_x > MAX_SIZE || max_y > MAX_SIZE) { fprintf(stderr,"Max X and Y size is %d\n", MAX_SIZE); exit(1); } fprintf(stderr,"Making %d X %d map, seed %d, land %d, passes = %d\n", max_x, max_y, seed, land, npasses); fprintf(stderr,"wpasses =%d, water=%d\n", wpasses, water); fprintf(stderr,"-x %d -y %d -s %d -p %d -n %d -w %d -l %d\n", max_x, max_y, seed, wpasses, npasses, water, land); srandom(seed); for (x=20; x < max_x-20; x++) for (y=20; y < max_y-20; y++) altitude[x][y] = BASE_ALT; for (x=0; x (npasses * 15) / 20) { int tries=0; while (altitude[x][y] == BASE_ALT) { x = random()%max_x; y = random()%max_y; if (random() % 2) { x += random()%max_x; y += random()%max_y; x /=2; y /=2; } tries++; if (tries > 50) { fprintf(stderr,"did not find free space within %d tries\n", tries); break; } } } for (k=1; k< land ; k++) { r = random()%4; switch (r) { case 0: if (x BASE_ALT || altitude[x][y]<-7000) { x = random()% max_x; y = random()% max_y; } for (k=1; k< water ; k++) { r = random()%4; switch (r) { case 0: if (x newalt) altitude[x][y] = newalt; } } for (x=max_x-2; x>2; x--) { for (y=max_y-2; y>2; y--) { newalt = (altitude[x][y] * r + altitude[x-1][y] + altitude[x][y-1] + altitude[x-1][y-1] + altitude[x+1][y] + altitude[x][y+1] + altitude[x+1][y+1] + altitude[x+1][y-1] + altitude[x-1][y+1]) / (r+8); if (altitude[x][y] < 10 || altitude[x][y] > newalt) altitude[x][y] = newalt; } } } /* Make this 100 so that we eliminate/reduce the lakiness of * the map that is otherwise generated - otherwise, the map * looks like an archipelligo */ #define AVG_PT -10 /* water - does the same as above, but try to more equally balnace the spaces*/ r = 1; for (k=0; k<40; k++) { for (x=2; x2; x--) { for (y=max_y-2; y>2; y--) { if (altitude[x][y] < AVG_PT) altitude[x][y] = (altitude[x][y] * r + altitude[x-1][y] + altitude[x][y-1] + altitude[x-1][y-1] + altitude[x+1][y] + altitude[x][y+1] + altitude[x+1][y+1] + altitude[x+1][y-1] + altitude[x-1][y+1]) / (r+8); } } } if (write_maps) write_crossfire_maps(max_x, max_y); /* Now write the data out */ fp = fopen("lmap", "w"); lp = fopen("pmap", "w"); fprintf(fp, "P3 %d %d 255\n", max_y, max_x); for (j=0; j < max_x; j++) { for (k=0; k < max_y; k++) { junk = altitude[j][k]; fprintf(lp, "%d ", altitude[j][k]); if (junk < -5000) fprintf(fp, "0 0 127 "); /* Shallow water should really be just at the coastal * area, so put a big gap between shallow and deep. * this also evens out the occurance of the different types * to be more equal */ else if (junk < -99) fprintf(fp, "0 0 192 "); else if (junk < 1) fprintf(fp, "0 0 255 "); else if (junk < 1000) fprintf(fp, "0 240 0 "); else if (junk < 2000) fprintf(fp, "0 220 0 "); else if (junk < 3000) fprintf(fp, "0 200 0 "); else if (junk < 4000) fprintf(fp, "0 180 0 "); else if (junk < 5000) fprintf(fp, "0 160 0 "); else if (junk < 6000) fprintf(fp, "255 130 71 "); else if (junk < 8000) fprintf(fp, "238 121 66 "); else if (junk < 10000) fprintf(fp, "205 104 57 "); else if (junk < 12000) fprintf(fp, "139 71 38 "); else fprintf(fp, "255 255 255 "); } fprintf(fp, "\n"); } exit(0); }