Complete.Org: Mailing Lists: Archives: freeciv-dev: December 1998:
[Freeciv-Dev] mapgen
Home

[Freeciv-Dev] mapgen

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: freeciv-dev@xxxxxxxxxxx
Subject: [Freeciv-Dev] mapgen
From: Peter Schaefer <schaefer@xxxxxxxxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 05 Dec 1998 00:48:21 +0100

.. In an effort to keep the mapgen as rugged
while giving in to a new mapgen proposed by
someone who's cloaking behind iquin@xxxxxxxxxxxxxxxx,
I've prepared a new mapgen 2 and 3.

The generator grows the islands faster on the
border than the old one(I think).
This means islands may have lakes.
Terrain distribution is delegated to a function.
Rivers avoid clustering.

Mapgen 2 is creating one big island per player.
Mapgen 3 is creating a big island that is shared by 2 or 3
players. This should be more interesting than the 
'one island, one player' game.
Both 2 and 3 will generate additional small islands. 

On the bad side, the generator performs slower than the old
one, which is noticable for big maps. 
Maybe there is just some tuning needed.
( I raised the number of times the generator tries placing
 islands a lot ).

There is a function adjust_terrain_param which
is a start in making the parameters that are used
for the map generators work alike for mapgen 1, 2 and 3.
I vote for interpreting most of them as percent.
The other way is to try figuring out what they mean for
mapgenerator 1, which is not straightforward.

A function counting usable sea is added to map.c which should
be helpful for someone modifying ai.
(Like in build-harbor-if-count-gt-x).

I want to have this in cvs because I've had enough of
testing iquin's code for saneness and I'd prefer to have the cvs
take control of it now.
I've tested with maps like 200x30 mass 80 players 14 (takes 60 secs),
and 40x30 mass 80 players 14.

And thanks to iquin!
--
Peter Schaefer           mailto:schaefer@xxxxxxxxxxxxxxxxxxxxxxxxxxx     
X-Url: http://wwwhoppe.math.uni-augsburg.de/~schaefer/
coz' hackers LOVE irix
--- freeciv/common/map.ccvs     Mon Nov 23 15:32:47 1998
+++ freeciv/common/map.c        Mon Nov 23 20:30:18 1998
@@ -146,22 +146,58 @@
 }
 
 /***************************************************************
-...
+ The following two function should always be used, such
+ that hand optimizations need only be performed once.
+ using isnt_ is faster than using is_ sometimes.
+ is terrain close diagonally or gridwise ?
 ***************************************************************/
 int is_terrain_near_tile(int x, int y, enum tile_terrain_type t)
 {
-  if (map_get_terrain(x, y+1)==t)   return 1;
-  if (map_get_terrain(x-1, y-1)==t) return 1;
-  if (map_get_terrain(x-1, y)==t)   return 1;
   if (map_get_terrain(x-1, y+1)==t) return 1;
   if (map_get_terrain(x+1, y-1)==t) return 1;
-  if (map_get_terrain(x+1, y)==t)   return 1;
+  if (map_get_terrain(x-1, y-1)==t) return 1;
   if (map_get_terrain(x+1, y+1)==t) return 1;
+  if (map_get_terrain(x, y+1)==t)   return 1;
+  if (map_get_terrain(x-1, y)==t)   return 1;
+  if (map_get_terrain(x+1, y)==t)   return 1;
   if (map_get_terrain(x, y-1)==t)   return 1;
   return 0;
 }
 
 /***************************************************************
+ is no terrain close diagonally or gridwise ?
+***************************************************************/
+int isnt_terrain_near_tile(int x, int y, enum tile_terrain_type t)
+{
+  if (map_get_terrain(x-1, y+1)!=t) return 1;
+  if (map_get_terrain(x+1, y-1)!=t) return 1;
+  if (map_get_terrain(x-1, y-1)!=t) return 1;
+  if (map_get_terrain(x+1, y+1)!=t) return 1;
+  if (map_get_terrain(x, y+1)!=t)   return 1;
+  if (map_get_terrain(x-1, y)!=t)   return 1;
+  if (map_get_terrain(x+1, y)!=t)   return 1;
+  if (map_get_terrain(x, y-1)!=t)   return 1;
+  return 0;
+}
+
+/***************************************************************
+  counts tiles close to x,y having terrain t
+***************************************************************/
+int count_terrain_near_tile(int x, int y, enum tile_terrain_type t)
+{
+  int rval= 0;
+  if (map_get_terrain(x, y+1)==t)   rval++;
+  if (map_get_terrain(x-1, y-1)==t) rval++;
+  if (map_get_terrain(x-1, y)==t)   rval++;
+  if (map_get_terrain(x-1, y+1)==t) rval++;
+  if (map_get_terrain(x+1, y-1)==t) rval++;
+  if (map_get_terrain(x+1, y)==t)   rval++;
+  if (map_get_terrain(x+1, y+1)==t) rval++;
+  if (map_get_terrain(x, y-1)==t)   rval++;
+  return rval;
+}
+
+/***************************************************************
 ...
 ***************************************************************/
 int is_at_coast(int x, int y)
@@ -176,6 +212,7 @@
 
 int is_coastline(int x,int y) 
 {
+  /*if (map_get_terrain(x,y)!=T_OCEAN)   return 0;*/
   if (map_get_terrain(x-1,y)!=T_OCEAN)   return 1;
   if (map_get_terrain(x-1,y-1)!=T_OCEAN) return 1;
   if (map_get_terrain(x-1,y+1)!=T_OCEAN) return 1;
--- freeciv/common/map.hcvs     Mon Nov 23 15:32:58 1998
+++ freeciv/common/map.h        Mon Nov 23 20:23:50 1998
@@ -141,6 +141,8 @@
 int map_move_cost(struct unit *punit, int x1, int y1);
 struct tile_type *get_tile_type(enum tile_terrain_type type);
 int is_terrain_near_tile(int x, int y, enum tile_terrain_type t);
+int isnt_terrain_near_tile(int x, int y, enum tile_terrain_type t);
+int count_terrain_near_tile(int x, int y, enum tile_terrain_type t);
 int is_coastline(int x,int y);
 int terrain_is_clean(int x, int y);
 int is_at_coast(int x, int y);
@@ -164,7 +166,6 @@
 int map_build_road_time(int x, int y);
 int map_build_irrigation_time(int x, int y);
 int map_build_mine_time(int x, int y);
-
 
 #define MAP_DEFAULT_MOUNTAINS    40
 #define MAP_MIN_MOUNTAINS        10
--- freeciv/server/mapgen.c     Sat Dec  5 01:02:24 1998
+++ mapgen.c    Sat Dec  5 00:58:12 1998
@@ -10,30 +10,29 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 ***********************************************************************/
-#include <log.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
 #include <sys/time.h>
 
-#include <map.h>
-#include <game.h>
-#include <shared.h>
+#include "log.h"
+#include "map.h"
+#include "game.h"
+#include "shared.h"
+#include "assert.h"
 
-#include <aitools.h>
-#include <assert.h>
+#define hmap(x,y) &height_map[(y)*map.xsize+map_adjust_x(x)]
+
 void make_huts(int number);
 void add_specials(int prob);
 void mapgenerator1(void);
 void mapgenerator2(void);
 void mapgenerator3(void);
-void spread(int spr);
 void smooth_map();
-void add_height(int x,int y, int radius);
 void adjust_map(int minval);
 void init_workmap(void);
-int *height_map;
 
+int *height_map;
 int maxval=0;
 int forests=0;
 
@@ -47,22 +46,6 @@
 }
 
 /**************************************************************************
- is this y coordinate in the arctic zone?
-**************************************************************************/
-int arctic_y(int y)
-{
-  return (y < map.ysize/10 || y > map.ysize*9/10);
-}
-
-/**************************************************************************
- Is this y coordinate in the desert zone?
-**************************************************************************/
-int desert_y(int y)
-{
-  return (y > map.ysize*4/10  &&  y < map.ysize*6/10);
-}
-
-/**************************************************************************
   make_mountains() will convert all squares that are higher than thill to
   mountains and hills. Notice that thill will be adjusted according to
   the map.mountains value, so increase map.mountains and you'll get more 
@@ -506,6 +489,7 @@
   int oldisles, goodisles;
   int guard1=0;
 
+if (map.generator != 1) return;
   for (y=0;y<map.ysize;y++)
     for (x=0;x<map.xsize;x++)
       map_set_continent(x, y, 0);
@@ -522,8 +506,6 @@
        isles++;
       }
  
-/* fnord -- Syela */
-
   if (loaded)                 /* only make the continents if loaded game*/
     return;
 
@@ -669,7 +651,7 @@
        }
       }
     }
-  } 
+  }
 }
 
 /**************************************************************************
@@ -690,13 +672,12 @@
   /* also, don't delete (the handcrafted!) tiny islands in a scenario */
   if (map.generator != 0) {
     init_workmap();
-    if (map.generator == 3 ){
+    if (map.generator == 3 )
       mapgenerator3();
-    } else if( map.generator == 2 ){
+    if( map.generator == 2 )
       mapgenerator2();
-    } else {
+    if( map.generator == 1 )
       mapgenerator1();
-    }
     filter_land();
   }
 
@@ -708,9 +689,36 @@
 }
 
 /**************************************************************************
+ readjust terrain counts so that it makes sense for mapgen 1, 2 and 3
+ idea: input is the number of terrain
+ mapgen 1 needs custom parameters, 
+ mapgen 2 and 3 use percents, currently.
+ Ultimately, I hope all parameters below will be percent, 
+ or weights, including a grass weight.
+**************************************************************************/
+void adjust_terrain_param(){
+  int i;
+  int mapgrass = 15;
+  if(map.generator==1)
+    return;
+
+  map.riverlength/= 10;
+
+  i = mapgrass+ map.riverlength + map.mountains
+               + map.deserts + map.forestsize + map.swampsize;
+  if(i>100){
+    map.riverlength= map.riverlength*100/i;
+    map.mountains= map.mountains*100/i;
+    map.forestsize= map.forestsize*100/i;
+    map.swampsize= map.swampsize*100/i;
+  }
+}
+
+
+/**************************************************************************
   this next block is only for debug purposes and could be removed
 **************************************************************************/
-char terrai_chars[] = {'a','D', 'F', 'g', 'h', 'j', 'M', '*', 'p', 'R', 
'%','T', 'U' };
+char terrai_chars[] = {'a','D', 'F', 'g', 'h', 'j', 'M', '.', 'p', 'R', 
's','T', 'U' };
 
 void print_map(void)
 {
@@ -765,652 +773,6 @@
        tile_init(map_get_tile(x, y));
 }
 
-/*****************************************************************************
-  The rest of this file is only used in  mapgenerator 2, and should not be 
-  confused with the previous stuff.
-*****************************************************************************/
-int ymax = 20;
-int xmax = 20;
-int size = 100;
-int startsize = 100;
-int xs; 
-int ys;
-int dx;
-int dy;
-
-long int landmass;/* long int so that multiplication results fit */
-
-/* statics for fillisland, initialized by setup fill island */
-
-long int riversbucket=0;
-long int mountainsbucket=0;
-long int hillsbucket=0;
-long int forestbucket=0;
-long int mixedbucket=0;
-
-long int riverscapacity=0;
-long int mountainscapacity=0;
-long int hillscapacity=0;
-long int forestcapacity=0;
-long int mixedcapacity=0;
-
-int riversstep=0;
-int mountainsstep=0;
-int hillsstep=0;
-int foreststep=0;
-int mixedstep=0;
-
-/**************************************************************************
-  This sets up a line drawer so that numbers of terrain will match
-**************************************************************************/
-void setup_fillisland(void)
-{
-  long int total=0;  
-  long int swampsize, deserts, mountains, forestsize, riverlength;
-
-  swampsize = ((map.xsize*map.ysize)*map.swampsize+500)/1000;
-  deserts   = ((map.xsize*map.ysize)*map.deserts+500)/1000;
-  mountains = ((map.xsize*map.ysize)*map.mountains+500)/1000;
-  forestsize= ((map.xsize*map.ysize)*map.forestsize+500)/1000;
-  riverlength= map.riverlength;
-
-  total+= swampsize;
-  total+= deserts;
-  total+= riverlength;
-  total+= mountains;
-  total+= forestsize;
-  /* mixed = deserts + swamps */
-
-  if(4*total>3*landmass) /* never allow more than 3/4 strange stuff */{
-    swampsize   = ( swampsize*3*landmass )/( 4*total );
-    deserts     = ( deserts*3*landmass )/( 4*total );
-    riverlength = ( riverlength*3*landmass )/( 4*total );
-    mountains   = ( mountains*3*landmass )/( 4*total );
-    forestsize  = ( forestsize*3*landmass )/( 4*total );
-  }
- 
-  riversstep   = riverlength;
-  mountainsstep= (1*mountains+2)/3;
-  hillsstep    = (2*mountains+1)/3;
-  foreststep   = forestsize;
-  mixedstep    = swampsize+deserts;
-
-  riverscapacity   = (landmass*3)/4;
-  mountainscapacity= (landmass*3)/4;
-  hillscapacity    = (landmass*3)/4;
-  forestcapacity   = (landmass*3)/4;
-  mixedcapacity    = (landmass*3)/4;
-
-  /* centered regular line 
-  riversbucket    = (-riverscapacity)/2;
-  mountainsbucket = (-mountainscapacity)/2;
-  hillsbucket     = (-hillscapacity)/2;
-  forestbucket    = (-forestcapacity)/2;
-  mixedbucket     = (-mixedcapacity)/2;
-  */
-
-  /* randomized line */
-  riversbucket    = - myrand(riverscapacity);
-  mountainsbucket = - myrand(mountainscapacity);
-  hillsbucket     = - myrand(hillscapacity);
-  forestbucket    = - myrand(forestcapacity);
-  mixedbucket     = - myrand(mixedcapacity);
-}
-
-/**************************************************************************
-  a wrapper
-**************************************************************************/
-int mini_map(int x, int y)
-{
-  return height_map[y*xmax + x];
-}
-
-/**************************************************************************
-  fill an island with different types of terrain,
-**************************************************************************/
-void fillisland(int xp, int yp)
-{
-  /* defaults reflect the setup of the original generator2 */
-  int rivers = 1;
-  int mountains = 3;
-  int hills = 6; 
-  int forest = 10;
-  int mixed  = 5;
-  int x,y;
-  int dir=-1;
-  
-  int fudge= 0; /* fudge factor to compensate programming errors (if >0) */
-                  
-  /* what we do is draw chunks of lines */
-  if(size>0) fudge=size;
-  riversbucket    += riversstep*(startsize-fudge);
-  mountainsbucket += mountainsstep*(startsize-fudge);
-  hillsbucket     += hillsstep*(startsize-fudge);
-  forestbucket    += foreststep*(startsize-fudge);
-  mixedbucket     += mixedstep*(startsize-fudge);  
-
-  if( riversbucket>0 )
-    { /* is optimizer able to compress x=a%b; y=a/b; to one divmod asm ?! */
-      rivers      = riversbucket/riverscapacity; 
-      rivers++;
-      riversbucket-= rivers*riverscapacity; 
-    }
-  else 
-    rivers=0;
-
-  if( mountainsbucket>0 )
-    { 
-      mountains      = mountainsbucket/mountainscapacity; 
-      mountains++;
-      mountainsbucket-= mountains*mountainscapacity; 
-    }
-  else 
-    mountains=0;
-
-  if( hillsbucket>0 )
-    { 
-      hills      = hillsbucket/hillscapacity; 
-      hills++;
-      hillsbucket-= hills*hillscapacity; 
-    }
-  else 
-    hills=0;
-
-  if( forestbucket>0 )
-    { 
-      forest      = forestbucket/forestcapacity; 
-      forest++; 
-      forestbucket-= forest*forestcapacity; 
-    }
-  else 
-    forest=0;
-
-  if( mixedbucket>0 )
-    { 
-      mixed      = mixedbucket/mixedcapacity; 
-      mixed++;
-      mixedbucket-= mixed*mixedcapacity; 
-    }
-  else 
-    mixed=0;
-
-  /* printf("line: %i/%i\th%i f%i r%i M%i m%i\n",
-        startsize,size,hills,forest,rivers,mountains,mixed); */
- 
-  x = xp + xmax / 2;
-  y = yp + ymax / 2;
-
-  while (rivers >0) {
-    x = myrand(xmax) + xp;
-    y = myrand(ymax) + yp;
-    if (map_get_terrain(x,y) == T_GRASSLAND &&
-       ( !is_terrain_near_tile(x, y, T_OCEAN) || !myrand(6) )
-       ) {
-      dir = myrand(4);
-      map_set_terrain(x, y, T_RIVER); mixed--;
-      rivers--;
-
-
-      while (!is_terrain_near_tile(x, y, T_OCEAN)) {
-       switch (dir) {
-       case 0:
-         x--;
-         break;
-       case 1:
-         y--;
-         break;
-       case 2:
-         x++;
-         break;
-       case 3:
-         y++;
-         break;
-       }
-       if (map_get_terrain(x,y) == T_GRASSLAND ){ 
-         map_set_terrain(x,y, T_RIVER); mixed--;
-         rivers--;
-       }
-       else 
-         break;
-
-       if (is_terrain_near_tile(x, y, T_OCEAN)) 
-         break;
-
-       switch ((dir + myrand(3) - 1 + 4)%4) {
-       case 0:
-         x--;
-         break;
-       case 1:
-         y--;
-         break;
-       case 2:
-         x++;
-         break;
-       case 3:
-         y++;
-       }
-       if (map_get_terrain(x,y) == T_GRASSLAND ){
-         map_set_terrain(x,y, T_RIVER); mixed--;
-         rivers--;
-       }
-       else
-         break;
-      }
-    }
-  }
-
-
-  while (mountains >0) {
-    x = myrand(xmax) + xp;
-    y = myrand(ymax) + yp;
-    if (map_get_terrain(x,y) == T_GRASSLAND &&
-       ( !is_terrain_near_tile(x, y, T_OCEAN) || !myrand(6) )
-       ) {
-      map_set_terrain(x, y, T_MOUNTAINS);
-      mountains--;
-    }    
-  }
-
-  while (hills >0) {
-    x = myrand(xmax) + xp;
-    y = myrand(ymax) + yp;
-    if (map_get_terrain(x,y) == T_GRASSLAND &&
-       ( !is_terrain_near_tile(x, y, T_OCEAN) || !myrand(6) )
-       ) {
-      map_set_terrain(x, y, T_HILLS);
-      hills--;
-    }    
-  }
-
-  while (forest >0) {
-    x = myrand(xmax-1) + xp;
-    y = myrand(ymax-1) + yp;
-    if (map_get_terrain(x,y) == T_GRASSLAND) {
-      map_set_terrain(x, y, T_FOREST);
-      forest--;
-      if (forest>0 && map_get_terrain(x+1,y) == T_GRASSLAND && myrand(3)) {
-       map_set_terrain(x+1, y, T_FOREST);
-       forest--;
-      }
-      if (forest>0 && map_get_terrain(x,y+1) == T_GRASSLAND && myrand(3)) {
-       map_set_terrain(x, y+1, T_FOREST);
-       forest--;
-      }
-      if (forest>0 && map_get_terrain(x+1,y+1) == T_GRASSLAND && myrand(3)) {
-       map_set_terrain(x+1, y+1, T_FOREST);
-       forest--;
-      }
-    }    
-  }
-
-  while (mixed > 0) {
-    x = myrand(xmax) + xp;
-    y = myrand(ymax) + yp;
-    if (map_get_terrain(x,y) == T_GRASSLAND) {
-      if (arctic_y(y)) {
-       map_set_terrain(x, y, T_TUNDRA);
-       mixed--;
-      } else if (desert_y(y) && is_terrain_near_tile(x, y, T_OCEAN)) {
-       map_set_terrain(x, y, T_DESERT);
-       mixed--;
-       if (mixed>0 && map_get_terrain(x+1,y) == T_GRASSLAND && myrand(3)) {
-         map_set_terrain(x+1, y, T_DESERT);
-         mixed--;
-       }
-       if (mixed>0 && map_get_terrain(x,y+1) == T_GRASSLAND && myrand(3)) {
-         map_set_terrain(x, y+1, T_DESERT);
-         mixed--;
-       }
-       if (mixed>0 && map_get_terrain(x+1,y+1) == T_GRASSLAND && myrand(3)) {
-         map_set_terrain(x+1, y+1, T_DESERT);
-         mixed--;
-       }
-      } else {
-       if (desert_y(y))
-         map_set_terrain(x, y, T_JUNGLE);
-       else 
-         map_set_terrain(x, y, T_SWAMP);
-       mixed--;
-      }
-    }
-  }
-
-  for (y = 0; y < ymax; y++)
-    for (x = 0; x < ymax; x++) {
-      if (map_get_terrain(xp +x, yp+y) == T_GRASSLAND && !myrand(3)) {
-       map_set_terrain(xp+x, y+yp, T_PLAINS);
-      }
-    }
-}
-
-/**************************************************************************
-  copy the newly created island to the real map, notice that T_OCEAN is
-  used as mask so other island won't get destroyed.
-**************************************************************************/
-void placeisland(int xp, int yp)
-{
-  int x,y;
-  for (y = 0 ; y < dy ; y++) 
-    for (x = 0 ; x < dx ; x++) {
-      if (mini_map(xs+x, y+ys) != T_OCEAN) 
-       map_set_terrain(xp + x, yp + y, mini_map(xs+x, ys+y));
-    }
-}
-
-/**************************************************************************
-  is there a neighbour square in the 4 basic directions?
-**************************************************************************/
-int neighbour(int x, int y)
-{
-  if ( x == 0 || x == xmax - 1 || y==0 || y == ymax -1) return 0;
-  return (mini_map(x+1, y) + mini_map(x-1, y) + mini_map(x, y+1) + mini_map(x, 
y-1));
-}
-
-/**************************************************************************
-  is there a neighbour square in any of the 8 directions?
-**************************************************************************/
-int neighbour8(int x, int y)
-{
-  if ( x == 0 || x == xmax - 1 || y==0 || y == ymax -1) return 0;
-  return(neighbour(x,y) + mini_map(x+1, y-1) + mini_map(x-1, y-1) + 
mini_map(x+1, y+1) + mini_map(x-1, y+1));
-}
-
-/**************************************************************************
-  we need this to convert tbe 0 based ocean representation to 2 
-**************************************************************************/
-void floodocean(int x, int y)
-{
-  if (x < 0 || x == xmax) return;
-  if (y < 0 || y == ymax) return;
-  if (mini_map(x,y) == 0) {
-    height_map[y*xmax + x] = 2;
-    floodocean(x - 1, y);
-    floodocean(x + 1, y);
-    floodocean(x , y - 1);
-    floodocean(x , y + 1);
-  }
-}
-
-/**************************************************************************
-  this procedure will generate 1 island
-**************************************************************************/
-void makeisland(void)
-{
-  int x,y;
-  
-  if( xmax*ymax/2< size )
-    {    
-     flog(LOG_NORMAL,"island too large(%i)\n",startsize);
-     size= (xmax-1)*(ymax-1)/2;
-    }
-
-  xs = xmax/2 -1;
-  ys = ymax/2 -1;
-  dx = 3;
-  dy = 3;
-  for (y = 0 ; y < ymax ; y++) {
-    for (x = 0 ; x < xmax ; x++) {
-      height_map[y * xmax + x]=0;
-    }
-  }
-  startsize= size;
-  height_map[(ymax/2)*xmax + xmax/2] = 1;
-  while (size > 0) {
-    x = myrand(dx) + xs;
-    y = myrand(dy) + ys;
-    if (mini_map(x, y) == 0 && neighbour(x,y)) {
-      height_map[y*xmax + x] = 1;
-      size--;
-      if (x <= xs) {
-       xs--;
-       dx++;
-      }
-      if (x == xs+dx - 1) dx++;
-      if (y <= ys) {
-       ys--;
-       dy++;
-      }
-      if (y == ys+dy - 1) dy++;
-    }
-  }
-  for (y = 0 ; y < ymax - 1; y++) 
-    for (x = 0; x < xmax - 1; x++) {
-      if (neighbour8(x, y) == 1 && mini_map(x, y) == 1) {
-       height_map[y*xmax + x] = 0;
-       size--;
-      }
-    }
-  floodocean(0,0);
-  for (y = 0 ; y < ymax; y++) 
-    for (x = 0; x < xmax; x++) {
-      if (mini_map(x, y) == 0) {
-       height_map[y*xmax + x] = 1;
-       size++;
-      }
-      if (mini_map(x, y) == 1) 
-       height_map[y*xmax + x] = T_GRASSLAND;
-      else 
-       height_map[y*xmax + x] = T_OCEAN;
-    }
-}
-
-/**************************************************************************
-  this procedure finds a place to drop the current island
-**************************************************************************/
-int findislandspot(int *xplace, int *yplace)
-{
-  int x, y;
-  int rx, ry;
-  int taken;
-  int tries;
-  tries = 100;
-  while( tries-->0 ) {
-    rx = myrand(map.xsize);
-    ry = myrand(map.ysize-dy-6) + 3;
-    taken = 0;
-    for (y = 0; y < dy && !taken; y++)
-      for (x = 0; x < dx && !taken; x++) {
-         if (map_get_terrain(rx + x, ry + y) != T_OCEAN) {
-           taken = 1;
-         }
-       }
-    if (!taken) {
-      *xplace = rx;
-      *yplace = ry;
-      return 1;
-    }
-  }
-  return 0;
-}
-
-/**************************************************************************
-  this is mapgenerator2. The highlevel routine that ties the knots together
-**************************************************************************/
-
-void mapgenerator2()
-{
-  int i,j=0;
-  int xp,yp;
-  int x,y;
-  long int islandmass;
-  int islands;
-
-  if( game.nplayers<=3 )
-    islands= 2*game.nplayers+1;
-  else 
-    islands= 7;
-
-  landmass= ( map.xsize * (map.ysize-6) * map.landpercent+50 )/100;
-  /* we need a factor of 7/10 or sth. like that because the coast
-     of islands actually takes up lots of space too */
-  islandmass= ( (landmass*7)/10+islands-1 )/islands;
-
-  if( map.xsize < 40 || map.ysize < 25 || map.landpercent>50 || islandmass>350 
)
-    { flog(LOG_NORMAL,"falling back to generator 1\n"); mapgenerator1(); 
return; }
-
-  if(islandmass<6)
-    islandmass= 6;
-  if(islandmass>350)
-    islandmass=350;/* !PS: cough */
-
-  while( (xmax*ymax)<3*islandmass)
-    { xmax++; ymax++; }
-   
-  height_map =(int *) malloc (sizeof(int)*xmax*ymax);
-
-  for (y = 0 ; y < map.ysize ; y++) 
-    for (x = 0 ; x < map.xsize ; x++) {
-      map_set_terrain(x,y, T_OCEAN);
-    }
-  for (x = 0 ; x < map.xsize; x++) {
-    map_set_terrain(x,0, T_ARCTIC);
-    if (myrand(100)>50) 
-      map_set_terrain(x,1, T_ARCTIC);
-    map_set_terrain(x, map.ysize-1, T_ARCTIC);
-    if (myrand(100)>50) 
-      map_set_terrain(x,map.ysize-2, T_ARCTIC);
-  }
-  
-  setup_fillisland();
-
-    i= islands;
-    while( i>0 &&  ++j<500 ) {
-      size = islandmass;
-     makeisland();
-      if( findislandspot(&xp, &yp) )
-       {
-         placeisland(xp, yp);
-         fillisland(xp, yp);
-         i--;
-       }
-    }
-
-  if(j==500)
-    flog(LOG_NORMAL, "generator 2 didn't place all islands; %i islands not 
placed.", i );
-  
-    /*  print_map();*/
-  free(height_map);
-}
-
-/**************************************************************************
- this is mapgenerator3. Works exactly as 2, with additional small islands
-**************************************************************************/
-void mapgenerator3()
-{
-  int i,j=0;
-  int xp,yp;
-  int x,y;
-  long int islandmass, massleft;
-  long int maxmassdiv6=20;
-  int bigislands;
-
-  bigislands= game.nplayers;
-
-  landmass= ( map.xsize * (map.ysize-6) * map.landpercent )/100;
-  /* subtracting the arctics */
-  if( landmass>3*map.ysize+game.nplayers*3 ){
-    landmass-= 3*map.ysize;
-  }
-
-  massleft= landmass;
-  islandmass= (landmass +bigislands-1 )/(3*bigislands);
-  if(islandmass<4*maxmassdiv6 )
-    islandmass= (landmass +bigislands-1 )/(2*bigislands);
-  if(islandmass<3*maxmassdiv6 && game.nplayers*2<landmass )
-    islandmass= (landmass)/(bigislands);
-
-  if( map.xsize < 40 || map.ysize < 40 || map.landpercent>80 )
-    { flog(LOG_NORMAL,"falling back to generator 2"); mapgenerator2(); return; 
}
-
-  if(map.landpercent>50)
-    { flog(LOG_NORMAL,"high landmass - this may take a few seconds"); }
-
-  if(islandmass<2)
-    islandmass= 2;
-  if(islandmass>maxmassdiv6*6)
-    islandmass= maxmassdiv6*6;/* !PS: let's try this */
-
-
-  while( xmax*ymax < 3*islandmass )
-    { xmax++; ymax++; }
-  height_map =(int *) malloc (sizeof(int)*xmax*ymax);
-
-  for (y = 0 ; y < map.ysize ; y++) 
-    for (x = 0 ; x < map.xsize ; x++) {
-      map_set_terrain(x,y, T_OCEAN);
-    }
-  for (x = 0 ; x < map.xsize; x++) {
-    map_set_terrain(x,0, T_ARCTIC);
-    if (myrand(100)>50) 
-      map_set_terrain(x,1, T_ARCTIC);
-    map_set_terrain(x, map.ysize-1, T_ARCTIC);
-    if (myrand(100)>50) 
-      map_set_terrain(x,map.ysize-2, T_ARCTIC);
-  }
-  
-  setup_fillisland();
-
-    i= 0;
-    while( i<bigislands && massleft>0 && ++j<500 ) {
-      size = islandmass;
-      makeisland();
-      if( findislandspot(&xp, &yp) )
-       {
-         placeisland(xp, yp);
-         fillisland(xp, yp);
-         i++;
-         massleft-= islandmass;
-       }
-    }
-
-  if(j==500)
-    flog(LOG_NORMAL, "generator 3 didn't place all big islands.");
-
-  free(height_map);
-
-  islandmass= islandmass/3;
-  if(islandmass<20)
-    islandmass= (islandmass*11)/8;
-  /*!PS: I'd like to mult by 3/2, but starters might make trouble then*/
-  if(islandmass<2)
-    islandmass= 2;
-
-  xmax= 13; ymax=13;
-  while( xmax*ymax < 3*islandmass )
-    { xmax++; ymax++; }
-  height_map =(int *) malloc (sizeof(int)*xmax*ymax);
-
-  /* !PS: the limit for isles is 100, but I get 
-     "failed writing data to socket" for i close 100 */
-    while( i<80 && massleft>0 && ++j< 1500 ) {
-      if(j<1000)
-       size = myrand((islandmass+1)/2+1)+islandmass/2;
-      else
-       size = myrand((islandmass+1)/2+1);
-      if(size<2) size=2;
-      makeisland();
-      if( findislandspot(&xp, &yp) )
-       {
-         placeisland(xp, yp);
-         fillisland(xp, yp);
-         i++;
-         massleft-= startsize;
-       }
-    }
-
-  if(j==1500)
-    flog(LOG_NORMAL, "generator 3 left %li landmass unplaced.",massleft);
-
-    /*  print_map();*/
-  free(height_map);
-
-  /* !PS: problem left to solve: make sure players start on big islands */
-  /* make big islands further apart ? => new algorithm */
-}
-
-
-
-
 /**************************************************************************
   mapgenerator1, highlevel function, that calls all the previous functions
 **************************************************************************/
@@ -1529,3 +891,324 @@
     }
 }
 
+/**************************************************************************
+  globals for generator 2 & 3
+**************************************************************************/
+static int isleindex, n, e, s, w;
+static long int totalmass; /* better a global than a duplicate formula */
+
+/**************************************************************************
+  fill an island with up four types of terrains, rivers have extra code
+**************************************************************************/
+static void fillisland(int coast, long int *bucket,
+               enum tile_terrain_type warm0, enum tile_terrain_type warm1,
+               enum tile_terrain_type cold0, enum tile_terrain_type cold1)
+{
+  int x, y, i, capac;
+
+  if (*bucket <= 0) return;
+  capac = totalmass;
+  i = *bucket / capac,
+  i++;
+  *bucket -= i * capac;
+  while (i) {
+    y = myrand(s - n) + n;
+    x = myrand(e - w) + w;
+    if (map_get_continent(x,y) == isleindex &&
+               map_get_terrain(x,y) == T_GRASSLAND) {
+      if (myrand(100) < coast || !is_terrain_near_tile(x, y, T_OCEAN))
+        if (cold1 != T_RIVER)
+          if (y * 5 < map.ysize || y * 5 > map.ysize * 4)
+            map_set_terrain(x, y, myrand(3) ? cold0 : cold1);
+          else
+            map_set_terrain(x, y, myrand(3) ? warm0 : warm1);
+        else
+          if (is_water_adjacent_to_tile(x, y) &&
+            count_terrain_near_tile(x, y, T_RIVER) < 3)
+              map_set_terrain(x, y, T_RIVER);
+      if (map_get_terrain(x,y) != T_GRASSLAND) i--;
+    }
+  }
+}
+
+static long int checkmass;
+
+/**************************************************************************
+  finds a place and drop the island created when called with islemass != 0
+**************************************************************************/
+static int placeisland()
+{
+  int x, y, xo, yo, i=0;
+  yo = myrand(map.ysize)+n-s;
+  xo = myrand(map.xsize)+w-e;
+  y = n + s / 2;
+  x = w + e / 2;
+
+  /* this helps a lot for maps with high landmass */
+  for (y = n, x = w ; y < s && x < e ; y++, x++)
+    if (*hmap(x, y) && is_coastline(x + xo - w, y + yo - n))
+      return 0;
+                      
+  for (y = n ; y < s ; y++)
+    for (x = w ; x < e ; x++)
+      if (*hmap(x, y) && is_coastline(x + xo - w, y + yo - n))
+        return 0;
+
+  for (y = n ; y < s ; y++) 
+    for (x = w ; x < e ; x++) {
+      if (*hmap(x, y)) {
+
+       checkmass--; 
+       if(checkmass<=0) 
+        { flog(LOG_NORMAL,"mapgen.c: mass doesn't sum up."); return i; }
+
+        map_set_terrain(xo + x - w, yo + y - n, T_GRASSLAND);
+        map_set_continent(xo + x - w, yo + y - n, isleindex);
+        i++;
+      }
+    }
+  s += yo - n;
+  e += xo - w;
+  n = yo;
+  w = xo;
+  return i;
+}
+
+/**************************************************************************
+  finds a place and drop the island created when called with islemass != 0
+**************************************************************************/
+static int createisland(int islemass)
+{
+  int x, y, i;
+  long int tries=islemass*(2+islemass/20)+99;
+
+  memset(hmap(0,0), '\0', sizeof(int) * map.xsize * map.ysize);
+  y = map.ysize / 2;
+  x = map.xsize / 2;
+  *hmap(x, y) = 1;
+  n = y - 1; w = x - 1;
+  s = y + 2; e = x + 2;
+  i = islemass - 1;
+  while (i && tries-->0) {
+    y = myrand(s - n) + n;
+    x = myrand(e - w) + w;
+    if ((!*hmap(x, y)) && (
+               *hmap(x+1, y) || *hmap(x-1, y) ||
+               *hmap(x, y+1) || *hmap(x, y-1) )) {
+      *hmap(x, y) = 1;
+      i--;
+      if (y >= s - 1 && s < map.ysize - 2) s++;
+      if (x >= e - 1 && e < map.xsize - 2) e++;
+      if (y <= n && n > 2) n--;
+      if (x <= w && w > 2) w--;
+    }
+    if (i < islemass / 10) {
+      for (y = n ; y < s ; y++)
+        for (x = w ; x < e ; x++)
+          if ((!*hmap(x, y)) && i && (
+               *hmap(x+1, y) && *hmap(x-1, y) &&
+               *hmap(x, y+1) && *hmap(x, y-1) )) {
+            *hmap(x, y) = 1;
+            i--; 
+          }
+    }
+  }
+  if(tries<=0)
+    flog(LOG_NORMAL,"createisland ended early with 
%d/%d.",islemass-i,islemass);
+
+  
+  tries= map.xsize*(long int)map.ysize/4;/* on a 40x60 map, there are 2400 
places */
+  while (!(i = placeisland()) && --tries);
+  return i;
+}
+
+static long int totalweight;
+/**************************************************************************
+  make an island, fill every tile type except plains
+**************************************************************************/
+static void makeisland(int islemass, int starters)
+{
+  static long int tilefactor, balance, lastplaced;/* int may be only 2 byte ! 
*/
+  static long int riverbuck, mountbuck, desertbuck, forestbuck, swampbuck;
+  int spares= 1; 
+  /* constant that makes up that an island actually needs additional space */
+
+  int x, y, i;
+
+  if (!islemass) {
+                                       /* setup initial static parameters */
+    balance = 0;
+    isleindex = 3;
+    totalmass = ( (map.ysize-6-spares) * map.landpercent * (map.xsize-spares) 
) / 100;
+    checkmass= totalmass;
+
+    /* caveat: this should really be sent to all players */
+    if(totalmass>3000)
+      flog(LOG_NORMAL,"high landmass - this may take a few seconds");
+
+    i = map.riverlength + map.mountains
+               + map.deserts + map.forestsize + map.swampsize;
+    i = i <= 90 ? 100 : i * 11 / 10;
+    tilefactor = totalmass / i;
+    riverbuck = -myrand(totalmass);
+    mountbuck = -myrand(totalmass);
+    desertbuck = -myrand(totalmass);
+    forestbuck = -myrand(totalmass);
+    swampbuck = -myrand(totalmass);
+    lastplaced = totalmass;
+  } else {
+                                       /* makes the islands here */
+    islemass = ( islemass * totalmass )/ totalweight - balance;
+
+    if(islemass>2*lastplaced) /* don't create big isles we can't place */
+      islemass= 2*lastplaced;
+
+    i = islemass;
+    if (i <= 0) return;
+    islands[isleindex].starters = starters;
+    while (!createisland(i--) && i*10>islemass );
+    i++;
+    lastplaced= i;
+    if(i*10>islemass){
+      balance = i - islemass;
+    }else{
+      balance = 0;
+    }
+
+    flog(LOG_DEBUG,"ini=%d,plc=%d,bal=%d,tot=%d",islemass,i,balance,checkmass);
+
+    i *= tilefactor;
+    riverbuck += map.riverlength / 10 * i;
+    fillisland(1, &riverbuck,
+               T_RIVER, T_RIVER, T_RIVER, T_RIVER);
+    mountbuck += map.mountains * i;
+    fillisland(20, &mountbuck,
+               T_HILLS, T_MOUNTAINS, T_HILLS, T_MOUNTAINS);
+    desertbuck += map.deserts * i;
+    fillisland(40, &desertbuck,
+               T_DESERT, T_DESERT, T_DESERT, T_TUNDRA);
+    forestbuck += map.forestsize * i;
+    fillisland(60, &forestbuck,
+               T_FOREST, T_JUNGLE, T_FOREST, T_TUNDRA);
+    swampbuck += map.swampsize * i;
+    fillisland(80, &swampbuck,
+               T_SWAMP, T_SWAMP, T_SWAMP, T_SWAMP);
+    isleindex++;
+  }
+}
+
+/**************************************************************************
+  fill ocean and make polar
+**************************************************************************/
+static void initworld()
+{
+  int x, y;
+  height_map =(int *) malloc (sizeof(int) * map.ysize * map.xsize);
+  for (y = 0 ; y < map.ysize ; y++) 
+    for (x = 0 ; x < map.xsize ; x++) {
+      map_set_terrain(x, y, T_OCEAN);
+      map_set_continent(x, y, 0);
+    }
+  for (x = 0 ; x < map.xsize; x++) {
+    map_set_terrain(x, 0, myrand(9) ? T_ARCTIC : T_TUNDRA);
+    map_set_continent(x, 0, 1);
+    if (!myrand(9)) {
+      map_set_terrain(x, 1, myrand(9) ? T_TUNDRA : T_ARCTIC);
+      map_set_continent(x, 1, 1);
+    }
+    map_set_terrain(x, map.ysize-1, myrand(9) ? T_ARCTIC : T_TUNDRA);
+    map_set_continent(x, map.ysize-1, 2);
+    if (!myrand(9)) {
+      map_set_terrain(x, map.ysize-2, myrand(9) ? T_TUNDRA : T_ARCTIC);
+      map_set_continent(x, map.ysize-2, 2);
+    }
+  }
+  makeisland(0, 0);
+  islands[2].starters = 0;
+  islands[1].starters = 0;
+  islands[0].starters = 0;
+}  
+
+/**************************************************************************
+  island base map generators
+**************************************************************************/
+void mapgenerator2()
+{
+  int i;
+
+  if (map.landpercent > 95) {
+    map.generator = 1;
+    return;
+  }
+
+  adjust_terrain_param();
+
+  /*!PS: The weights NEED to sum up to totalweight (dammit) */
+  /* copying the flow of the makeisland loops is the safest way */
+  totalweight= 0;
+  for (i = game.nplayers ; i ; i--)
+    totalweight+= 70;
+  for (i = game.nplayers ; i ; i--)
+    totalweight+= 20;
+  for (i = game.nplayers ; i ; i--)
+    totalweight+= 10;
+
+  initworld();
+
+  for (i = game.nplayers ; i ; i--)
+    makeisland(70, 2);
+  for (i = game.nplayers ; i ; i--)
+    makeisland(20, 0);
+  for (i = game.nplayers ; i ; i--)
+    makeisland(10, 0);
+  make_plains();  
+  free(height_map);
+
+  if(checkmass>map.xsize+map.ysize+totalweight)
+    flog(LOG_DEBUG,"%ld mass left unplaced",checkmass);
+}
+
+void mapgenerator3()
+{
+  int i;
+
+  i = game.nplayers / 2;
+  if (!i || map.landpercent > 90) {
+    map.generator = 2;
+    return;
+  }
+
+  adjust_terrain_param();
+
+  /*!PS: The weights NEED to sum up to totalweight (dammit) */
+  totalweight= 0;
+  if (game.nplayers % 2)
+    totalweight+= 210;
+  else
+    i++;
+  while (--i)
+    totalweight+= 140;
+  for (i = game.nplayers ; i ; i--)
+    totalweight+= 20;
+  for (i = game.nplayers ; i ; i--)
+    totalweight+= 10;
+
+  initworld();
+
+  i = game.nplayers / 2;
+  if (game.nplayers % 2)
+    makeisland(210, 3);
+  else
+    i++;
+  while (--i)
+    makeisland(140, 2);
+  for (i = game.nplayers ; i ; i--)
+    makeisland(20, 0);
+  for (i = game.nplayers ; i ; i--)
+    makeisland(10, 0);
+  make_plains();  
+  free(height_map);
+
+  if(checkmass>map.xsize+map.ysize+totalweight)
+    flog(LOG_DEBUG,"%ld mass left unplaced",checkmass);
+}

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] mapgen, Peter Schaefer <=