Complete.Org: Mailing Lists: Archives: freeciv-dev: June 2003:
[Freeciv-Dev] Re: (PR#3489) Patch to add new generator
Home

[Freeciv-Dev] Re: (PR#3489) Patch to add new generator

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] Re: (PR#3489) Patch to add new generator
From: "jjc@xxxxxxxxxxxxxxxxxx" <jjc@xxxxxxxxxxxxxxxxxx>
Date: Sun, 15 Jun 2003 16:20:32 -0700
Reply-to: rt@xxxxxxxxxxxxxx

Attached below is the current incarnation of the generator 6 patch. 
This patch adds a new generator that creates one  peninsulas for each
player as well as other random land.  It also creates an isthmus between 
the north and the south pole.  Roads are automatically created on the 
isthmus and around the north and south pole.

The goal of this patch is to greatly decrease the freeciv solitaire 
portion of the game since all players can be met by purely land 
routes, thus researching ships is not required.  The roads further decrease
the time to get armys to the other players.  

The changes that come with this patch is that the peninsula's now have 
semi random width and height and placement.  Also, small islands are 
sometimes generated as well.

See some screenshots at:
http://www.honors.montana.edu/~jjc/gen_6_upload/

Tell me what you think of it.

-- 
Josh Cogliati


Index: common/map.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/map.h,v
retrieving revision 1.146
diff -U9 -r1.146 map.h
--- common/map.h        2003/05/15 12:38:11     1.146
+++ common/map.h        2003/06/15 22:53:24
@@ -644,19 +644,19 @@
 #define MAP_MIN_RIVERS           0
 #define MAP_MAX_RIVERS           100
 
 #define MAP_DEFAULT_FORESTS      20
 #define MAP_MIN_FORESTS          0
 #define MAP_MAX_FORESTS          100
 
 #define MAP_DEFAULT_GENERATOR    1
 #define MAP_MIN_GENERATOR        1
-#define MAP_MAX_GENERATOR        5
+#define MAP_MAX_GENERATOR        6
 
 #define MAP_DEFAULT_TINYISLES    FALSE
 #define MAP_MIN_TINYISLES        FALSE
 #define MAP_MAX_TINYISLES        TRUE
 
 #define MAP_DEFAULT_SEPARATE_POLES   TRUE
 #define MAP_MIN_SEPARATE_POLES       FALSE
 #define MAP_MAX_SEPARATE_POLES       TRUE
 
Index: server/mapgen.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/mapgen.c,v
retrieving revision 1.110
diff -U9 -r1.110 mapgen.c
--- server/mapgen.c     2003/02/20 09:45:22     1.110
+++ server/mapgen.c     2003/06/15 22:53:49
@@ -36,18 +36,19 @@
 #define rmap(x, y) (river_map[map_pos_to_index(x, y)])
 
 static void make_huts(int number);
 static void add_specials(int prob);
 static void mapgenerator1(void);
 static void mapgenerator2(void);
 static void mapgenerator3(void);
 static void mapgenerator4(void);
 static void mapgenerator5(void);
+static void mapgenerator6(void);
 static void smooth_map(void);
 static void adjust_map(int minval);
 
 #define RIVERS_MAXTRIES 32767
 enum river_map_type {RS_BLOCKED = 0, RS_RIVER = 1};
 
 /* Array needed to mark tiles as blocked to prevent a river from
    falling into itself, and for storing rivers temporarly.
    A value of 1 means blocked.
@@ -1151,18 +1152,20 @@
 
   mysrand(map.seed);
   
   /* don't generate tiles with mapgen==0 as we've loaded them from file */
   /* also, don't delete (the handcrafted!) tiny islands in a scenario */
   if (map.generator != 0) {
     map_allocate();
     /* if one mapgenerator fails, it will choose another mapgenerator */
     /* with a lower number to try again */
+    if (map.generator == 6 )
+      mapgenerator6();
     if (map.generator == 5 )
       mapgenerator5();
     if (map.generator == 4 )
       mapgenerator4();
     if (map.generator == 3 )
       mapgenerator3();
     if( map.generator == 2 )
       mapgenerator2();
     if( map.generator == 1 )
@@ -2133,10 +2136,468 @@
     if (hmap(x, y) < minval)
       minval = hmap(x, y);
   } whole_map_iterate_end;
   maxval -= minval;
   adjust_map(minval);
   
   make_land();
   free(height_map);
   height_map = NULL;
+}
+
+enum gen6_terrain { T6_PERM_LAND = T_GRASSLAND, T6_TEMP_LAND = T_SWAMP, 
+                   T6_PERM_OCEAN = T_OCEAN, T6_TEMP_OCEAN = T_ARCTIC, 
+                   T6_ERODE_LAND = T_DESERT, T6_DILATE_LAND = T_JUNGLE};
+
+/****************************************************************************
+ returns true if the terrain is generator 6 ocean. 
+****************************************************************************/
+static int g6_ocean(int terrain) 
+{
+  return terrain == T6_PERM_OCEAN || terrain == T6_TEMP_OCEAN;
+}
+
+/****************************************************************************
+ returns true if the terrain at point x,y is land. 
+****************************************************************************/
+static int land_terrain(int x, int y)
+{
+  int terrain = map_get_terrain(x, y);
+  return !g6_ocean(terrain);
+}
+
+/****************************************************************************
+ returns true if a neighboring point should be eroded. 
+****************************************************************************/
+static int erode_terrain(int x, int y)
+{
+  int terrain = map_get_terrain(x, y);
+  return g6_ocean(terrain);
+}
+
+/****************************************************************************
+ returns true if the terrain at point x,y should be eroded.  
+****************************************************************************/
+static int should_erode(int x, int y)
+{
+  int terrain = map_get_terrain(x, y);
+  if(g6_ocean(terrain) || terrain == T6_PERM_LAND) {
+    return FALSE;
+  }
+  if (erode_terrain(x - 1, y) 
+      || erode_terrain(x + 1, y)
+      || erode_terrain(x, y - 1)
+      || erode_terrain(x, y + 1)) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/****************************************************************************
+ removes all temporary shores.      (I.e. shrink the land by one tile.)
+****************************************************************************/
+static void erode_map(int polar_height) 
+{
+  int x, y;
+  for (x = 0; x < map.xsize; x++) {
+    for (y = polar_height; y < map.ysize - polar_height; y++) {
+      if (should_erode(x, y)) {
+       map_set_terrain(x, y, T6_ERODE_LAND);
+      }
+    }
+  }
+  
+  for (x = 0; x < map.xsize; x++) {
+    for (y = polar_height; y < map.ysize - polar_height; y++) {
+      if (map_get_terrain(x, y) == T6_ERODE_LAND) {
+       map_set_terrain(x, y, T6_TEMP_OCEAN);
+      }
+    }
+  }
+}
+
+/****************************************************************************
+ returns true if a neighboring point should be dilated. 
+****************************************************************************/
+static int dilate_terrain(int x, int y)
+{
+  int terrain = map_get_terrain(x, y);
+  return !g6_ocean(terrain) && terrain != T6_DILATE_LAND;
+}
+
+/****************************************************************************
+ returns true if the terrain at point x,y should be dilated.  
+****************************************************************************/
+static int should_dilate(int x, int y)
+{
+  int terrain = map_get_terrain(x, y);
+  if(!g6_ocean(terrain) || terrain == T6_PERM_OCEAN) {
+    return FALSE;
+  }
+  if (dilate_terrain(x - 1, y) 
+      || dilate_terrain(x + 1, y)
+      || dilate_terrain(x, y - 1)
+      || dilate_terrain(x, y + 1)) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/****************************************************************************
+ removes all temporary beaches.   (I.e. shrink the ocean by one tile.) 
+****************************************************************************/
+static void dilate_map(int polar_height) 
+{
+  int x, y;
+  for (x = 0; x < map.xsize; x++) {
+    for (y = polar_height; y < map.ysize - polar_height; y++) {
+      if (should_dilate(x, y)) {
+       map_set_terrain(x, y, T6_DILATE_LAND);
+      }
+    }
+  }
+  
+  for (x = 0; x < map.xsize; x++) {
+    for (y = polar_height; y < map.ysize - polar_height; y++) {
+      if (map_get_terrain(x, y) == T6_DILATE_LAND) {
+       map_set_terrain(x, y, T6_TEMP_LAND);
+      }
+    }
+  }
+}
+
+
+/****************************************************************************
+ returns a score based on the amount of land surrounding the point x,y. 
+ No land is 0.  All eight neighbors is 12
+ ***************************************************************************/
+static int border_score(int x, int y)
+{
+  int adj_score = 2;
+  int diag_score = 1;
+  int score = 0;
+  score += land_terrain(x - 1, y) ? adj_score : 0;
+  score += land_terrain(x + 1, y) ? adj_score : 0;
+  score += land_terrain(x, y - 1) ? adj_score : 0;
+  score += land_terrain(x, y + 1) ? adj_score : 0;
+  score += land_terrain(x - 1, y - 1) ? diag_score : 0;
+  score += land_terrain(x + 1, y - 1) ? diag_score : 0;
+  score += land_terrain(x - 1, y + 1) ? diag_score : 0;
+  score += land_terrain(x + 1, y + 1) ? diag_score : 0;
+  return score;
+}
+
+enum terrain_status { TS_OCEAN, TS_LAND, TS_NEW_LAND};
+
+/*************************************************************************
+  Returns TS_NEW_LAND if the point is not already land and 
+  the random number is less than the border score.
+  More likely to return TS_NEW_LAND on a location that has
+  more land around it.  Will never return TS_NEW_LAND on a
+  location that has no land in any of the eight neighbors.
+ *************************************************************************/
+static int random_new_land(int x, int y)
+{
+  int score;
+  int random;
+  if (land_terrain(x, y)) {
+    return TS_LAND;
+  }
+  if (map_get_terrain(x, y) == T6_PERM_OCEAN) {
+    return TS_OCEAN;
+  }
+  score = border_score(x, y);
+  random = myrand(4 * 2 + 4 * 1);
+  return random + 1 > score ? TS_OCEAN : TS_NEW_LAND;
+
+}
+
+/*************************************************************************
+ Creates a peninsula and put the player's starting position
+ on it. The direction is either +1 or -1 depending on which 
+ direction the peninsula should go from the y position.
+ The remaining_count is the number of tiles to  fill with 
+ land.
+ *************************************************************************/
+static void create_peninsula(int x, int y, int player_number,
+                            int width, int height, int direction,
+                            int neck_height,int neck_width,
+                            int neck_displacement)
+{
+  int cx, cy;
+  int head_height = height-neck_height;
+  int neck_start = x + neck_displacement;
+  int ocean_distance = neck_height / 2;
+
+  /* make perm ocean */
+  { 
+    int top_location = y - (ocean_distance + 1) * direction;
+    int bottom_location = y + (height - ocean_distance) * direction;
+    int left_location = x - ocean_distance - 1;
+    int right_location = x + width + ocean_distance;
+    
+    /* top and bottom */
+    for (cx = left_location; cx < right_location + 1; cx++) {
+      map_set_terrain(cx, top_location, T6_PERM_OCEAN);
+      map_set_terrain(cx, bottom_location, T6_PERM_OCEAN);
+    }
+
+    /* left and right */
+    for (cy = top_location; cy != bottom_location + direction;
+        cy += direction) {
+      map_set_terrain(left_location, cy, T6_PERM_OCEAN);
+      map_set_terrain(right_location, cy, T6_PERM_OCEAN);
+    }
+
+    /* connect to central ocean */
+    for (cy = map.ysize / 2; cy != top_location; cy += direction) {
+      map_set_terrain(x + width / 2, cy, T6_PERM_OCEAN);
+    }
+  }
+
+  /* make head */
+  for (cx = x; cx < x + width; cx++) {
+    for (cy = y; cy != y + (head_height + 1) * direction; cy += direction) {
+      map_set_terrain(cx, cy, T6_PERM_LAND);
+      hmap(cx, cy) = myrand(7000) - 2000;
+    }
+  }
+
+  /* make neck */
+  for (cx = neck_start; cx < neck_start + neck_width; cx++) {
+    for (cy = y + (head_height + 1) * direction; 
+        cy != y + (height + 1) * direction; cy += direction ) {
+      map_set_terrain(cx, cy, T6_PERM_LAND);
+      hmap(cx, cy) = myrand(7000) - 2000;
+    }
+  }
+
+  map.start_positions[player_number].x = x + width / 2;
+  map.start_positions[player_number].y = y;
+}
+
+/*************************************************************************
+  This generator creates a map with one penisula for each 
+   player and an isthmus between.  It creates a central
+   ocean and puts the peninsulas around the edges.  It is 
+   intented for quicker games. Should look something like this:
+   *****************************
+   ****  *****  *****  *****    
+    **    ***    ***    ***     
+    **                          
+    **                           
+    **       ***    ***             
+   ****     *****  *****           
+   *****************************
+
+ *************************************************************************/
+static void mapgenerator6(void)
+{
+  int peninsulas = game.nplayers;
+  int peninsulas_on_one_side = (peninsulas + 1) / 2;
+  int isthmus_width = 10;
+  int neck_height = (map.ysize / 8) | 1; 
+  int polar_height = 3;
+  int peninsula_separation = neck_height;
+  int max_peninsula_width = (map.xsize - isthmus_width - peninsula_separation)
+    / (peninsulas_on_one_side) - peninsula_separation;
+  int max_peninsula_height = map.ysize / 2 - polar_height - neck_height;
+  int neck_width = MIN(6,max_peninsula_width - 1);
+  int min_peninsula_width = neck_width;
+  int min_peninsula_height = neck_height;
+  int peninsula_area = MAX((max_peninsula_width * max_peninsula_height * 
+                           map.landpercent) / 100, 
+                          min_peninsula_width * min_peninsula_height);
+  int i, x, y;
+  int isle = 1;
+
+  if(min_peninsula_width > max_peninsula_width 
+     || min_peninsula_height > max_peninsula_height
+     || min_peninsula_width < 2 || min_peninsula_height < 2)
+  {
+    freelog(LOG_NORMAL, 
+           "mapgen.c: unable to use generator 6. "\
+           "mw %d Mw %d mh %d Mh %d area %d",
+           min_peninsula_width,max_peninsula_width,
+           min_peninsula_height,max_peninsula_height,peninsula_area);
+    map.generator = 5;
+    return;
+  }
+
+  height_map = fc_malloc(sizeof(int) * map.xsize * map.ysize);
+
+  /* initialize everything to temp ocean */
+  for (y = 0; y < map.ysize; y++)
+    for (x = 0; x < map.xsize; x++) {
+      map_set_terrain(x, y, T6_TEMP_OCEAN);
+      hmap(x, y) = 0;
+    }
+
+  /* create central perm ocean */
+  y = map.ysize / 2;
+  for (x = isthmus_width; x < map.xsize; x++) {
+    map_set_terrain(x, y, T6_PERM_OCEAN);
+    hmap(x, y) = 0;
+  }
+
+  /* create polar regions */
+  for (x = 0; x < map.xsize; x++) {
+    for (y = 0; y < polar_height; y++) {
+      int rand_num = myrand(9);
+      map_set_terrain(x, y, rand_num > 7 ? T_ARCTIC :
+                     (rand_num < 2 ? T_MOUNTAINS : T_TUNDRA));
+      rand_num = myrand(9);
+      map_set_terrain(x, map.ysize - 1 - y, rand_num > 7 ? T_ARCTIC :
+                     (rand_num < 2 ? T_MOUNTAINS : T_TUNDRA));
+    }
+  }
+
+  /* build polar regions road */
+  for (x = 0; x < map.xsize; x++) {
+    y = polar_height - 1;
+    if (map_build_road_time(x, y - 1) < map_build_road_time(x, y)) {
+      map_set_special(x, y - 1, S_ROAD);
+    } else {
+      map_set_special(x, y, S_ROAD);
+    }
+    y = map.ysize - polar_height;
+    if (map_build_road_time(x, y + 1) < map_build_road_time(x, y)) {
+      map_set_special(x, y + 1, S_ROAD);
+    } else {
+      map_set_special(x, y, S_ROAD);
+    }
+  }
+
+  map.num_continents = 1;
+
+  /* create isthmus centeral strip */
+  x = isthmus_width / 2;
+  for (y = polar_height; y < map.ysize - polar_height; y++) {
+    map_set_terrain(x, y, T6_PERM_LAND);
+    hmap(x, y) = 100 * x * (isthmus_width - x) + (myrand(400) - 200);
+  }
+
+  /* setup peninsulas */
+  for (i = 0; i < game.nplayers; i++) {
+    /* direction is the direction to increment from the x and y location */
+    int direction = (i < peninsulas_on_one_side) ? -1 : 1;
+    int index = (direction == -1) ? i : i - peninsulas_on_one_side;
+    int width = min_peninsula_width + 
+      myrand(max_peninsula_width - min_peninsula_width);
+    int height = CLIP(min_peninsula_height,
+                     peninsula_area / width + neck_height,
+                     max_peninsula_height);
+    int neck_displacement = myrand(width - neck_width);
+    int x_displacement = myrand(max_peninsula_width - width);
+    if(index == 0) {
+      x = peninsula_separation + isthmus_width;
+      if(direction == 1 && game.nplayers & 1) {
+       /* center the thing */
+       x = x + max_peninsula_width / 2;
+      } 
+    } 
+    y = (direction == -1)
+       ? height + polar_height : map.ysize - 1 - height - polar_height;
+    create_peninsula(x + x_displacement, y, i, width, height, direction,
+                    neck_height,neck_width,neck_displacement);
+    x = x + peninsula_separation + max_peninsula_width;
+  }
+
+  map.num_start_positions = game.nplayers;
+
+  { 
+    int consider_height = map.ysize - 2 * polar_height;
+    int desired_squares = 
+      (consider_height * map.xsize * map.landpercent) / 200;
+    int bailout_number = desired_squares * 30;
+    int seed = MIN(20, desired_squares / 20); /* seed islands */
+    desired_squares = MAX(0, desired_squares - seed);
+    while (bailout_number > 0 && seed > 0) {
+      x = myrand(map.xsize);
+      y = myrand(consider_height) + polar_height;
+      if (map_get_terrain(x, y) == T6_TEMP_OCEAN) {
+       map_set_terrain(x, y, T6_TEMP_LAND);
+       hmap(x, y) = myrand(7000) - 2000;
+       seed--;
+      }
+      bailout_number--;
+    }
+    while (bailout_number > 0 && desired_squares > 0) {
+      x = myrand(map.xsize);
+      y = myrand(consider_height) + polar_height;
+      if (random_new_land(x, y) == TS_NEW_LAND) {
+       map_set_terrain(x, y, T6_TEMP_LAND);
+       hmap(x, y) = myrand(7000) - 2000;
+       desired_squares--;
+      }
+      bailout_number--;
+    }
+  }
+
+  /* remove small oceans  */
+  dilate_map(polar_height);
+  erode_map(polar_height);
+  /* remove small islands */
+  erode_map(polar_height);
+  dilate_map(polar_height);
+
+  /* translate to real terrain */
+  for (x = 0; x < map.xsize; x++) {
+    for (y = polar_height; y < map.ysize - polar_height; y++) {
+      int terrain = map_get_terrain(x, y);
+      if (terrain == T6_TEMP_LAND) {
+       map_set_terrain(x, y, T_GRASSLAND);
+      } else if(terrain == T6_TEMP_OCEAN) {
+       map_set_terrain(x, y, T_OCEAN);
+      }
+    }
+  }
+
+  whole_map_iterate(x, y) {
+    map_set_continent(x, y, 0);
+  } whole_map_iterate_end;
+  
+  assign_continent_flood(0, 0, isle++);
+
+  whole_map_iterate(x, y) {
+    if (map_get_continent(x, y) == 0 
+        && !is_ocean(map_get_terrain(x, y))) {
+      assign_continent_flood(x, y, isle++);
+    }
+  } whole_map_iterate_end;
+
+  map.num_continents = isle-1;
+
+  /* setup terrain */
+  smooth_map();
+  make_mountains(1600);
+  make_swamps();
+  make_forests();
+  make_deserts();
+  make_plains();
+  make_fair();
+  make_rivers();
+
+  /* create isthmus road */
+  {
+    int last_x, middle_x = isthmus_width / 2;
+    last_x = middle_x;
+    for (y = polar_height - 1; y < map.ysize - polar_height + 1; y++) {
+      int best_x = middle_x;
+      int min_build = map_build_road_time(middle_x, y);
+      for (x = MAX(last_x - 1, middle_x - 1);
+          x != MIN(last_x + 1, middle_x + 1) + 1; x++) {
+       if (land_terrain(x, y) && map_build_road_time(x, y) < min_build) {
+         best_x = x;
+         min_build = map_build_road_time(x, y);
+       }
+      }
+      map_set_special(best_x, y, S_ROAD);
+      last_x = best_x;
+    }
+  }
+
+  free(height_map);
+
 }
Index: server/stdinhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v
retrieving revision 1.280
diff -U9 -r1.280 stdinhand.c
--- server/stdinhand.c  2003/05/15 12:26:53     1.280
+++ server/stdinhand.c  2003/06/15 22:54:14
@@ -237,19 +237,21 @@
        "3 = equally sized large islands with one player each, and "
        "a number of other\n"
        "    islands of similar size;\n"
        "4 = equally sized large islands with two players on every "
        "island (or one\n"
        "    with three players for an odd number of players), and "
        "additional\n"
        "    smaller islands;\n"
        "5 = one or more large earthlike continents with some scatter.\n"
-       "Note: values 2,3 and 4 generate \"fairer\" (but more boring) "
+       "6 = equally sized peninsulas with one player each surrounding  \n"
+       "    an inland sea.\n"
+       "Note: values 2,3,4 and 6 generate \"fairer\" (but more boring) "
        "maps.\n"
        "(Zero indicates a scenario map.)"), NULL,
          MAP_MIN_GENERATOR, MAP_MAX_GENERATOR, MAP_DEFAULT_GENERATOR)
 
   GEN_BOOL("tinyisles", map.tinyisles, SSET_MAP_GEN, SSET_TO_CLIENT,
           N_("Presence or absence of 1x1 islands"),
           N_("0 = no 1x1 islands; 1 = some 1x1 islands"), NULL,
           MAP_DEFAULT_TINYISLES)
 

[Prev in Thread] Current Thread [Next in Thread]