Complete.Org: Mailing Lists: Archives: freeciv-dev: September 2004:
[Freeciv-Dev] (PR#10201) PATCH: generator characteristics evolution, bes
Home

[Freeciv-Dev] (PR#10201) PATCH: generator characteristics evolution, bes

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#10201) PATCH: generator characteristics evolution, best handled temperature and relief.
From: "Marcelo Burda" <mburda@xxxxxxxxx>
Date: Fri, 24 Sep 2004 03:36:50 -0700
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=10201 >

LASTCHAGE: 
clean ups to be more clear. 
diff -ruN -Xfreeciv/diff_ignore freeciv/common/map.h freeciv_/common/map.h
--- freeciv/common/map.h        2004-09-20 18:42:30.000000000 +0200
+++ freeciv_/common/map.h       2004-09-23 23:09:20.000000000 +0200
@@ -536,6 +536,30 @@
 
 #define cardinal_adjc_dir_iterate_end adjc_dirlist_iterate_end
 
+/****************************************************************************
+  This iterator behaves like adjc_iterate or cardinal_adjc_iterate depending
+  on the value of card_only.
+****************************************************************************/
+#define variable_adjc_iterate(center_x, center_y, x_itr, y_itr, card_only)  \
+{                                                                          \
+  enum direction8 *_dirlist;                                               \
+  int _total;                                                              \
+                                                                           \
+  if (card_only) {                                                         \
+    _dirlist = map.cardinal_dirs;                                          \
+    _total = map.num_cardinal_dirs;                                        \
+  } else {                                                                 \
+    _dirlist = map.valid_dirs;                                             \
+    _total = map.num_valid_dirs;                                           \
+  }                                                                        \
+                                                                           \
+  adjc_dirlist_iterate(center_x, center_y, x_itr, y_itr,                   \
+                      _dir, _dirlist, _total) {
+
+#define variable_adjc_iterate_end                                          \
+  } adjc_dirlist_iterate_end;                                              \
+}
+
 /* Iterate through all tiles adjacent to a tile using the given list of
  * directions.  dir_itr is the directional value, (center_x, center_y) is
  * the center tile (which must be normalized), and (x_itr, y_itr) is the
diff -ruN -Xfreeciv/diff_ignore freeciv/common/terrain.c 
freeciv_/common/terrain.c
--- freeciv/common/terrain.c    2004-09-09 23:32:20.000000000 +0200
+++ freeciv_/common/terrain.c   2004-09-23 23:09:20.000000000 +0200
@@ -131,31 +131,6 @@
 }
 
 /****************************************************************************
-  This iterator behaves like adjc_iterate or cardinal_adjc_iterate depending
-  on the value of card_only.
-****************************************************************************/
-#define variable_adjc_iterate(center_x, center_y, x_itr, y_itr, card_only)  \
-{                                                                          \
-  enum direction8 *_dirlist;                                               \
-  int _total;                                                              \
-                                                                           \
-  if (card_only) {                                                         \
-    _dirlist = map.cardinal_dirs;                                          \
-    _total = map.num_cardinal_dirs;                                        \
-  } else {                                                                 \
-    _dirlist = map.valid_dirs;                                             \
-    _total = map.num_valid_dirs;                                           \
-  }                                                                        \
-                                                                           \
-  adjc_dirlist_iterate(center_x, center_y, x_itr, y_itr,                   \
-                      _dir, _dirlist, _total) {
-
-#define variable_adjc_iterate_end                                          \
-  } adjc_dirlist_iterate_end;                                              \
-}
-
-
-/****************************************************************************
   Returns TRUE iff any adjacent tile contains the given terrain.
 ****************************************************************************/
 bool is_terrain_near_tile(int map_x, int map_y, Terrain_type_id t)
Les fichiers binaires freeciv/manual/civmanual et freeciv_/manual/civmanual 
sont différents.
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/characteristics.c 
freeciv_/server/generator/characteristics.c
--- freeciv/server/generator/characteristics.c  1970-01-01 01:00:00.000000000 
+0100
+++ freeciv_/server/generator/characteristics.c 2004-09-24 11:58:33.000000000 
+0200
@@ -0,0 +1,947 @@
+/********************************************************************** 
+   Copyright (C) 1996-2004  The Freeciv Project Team
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+***********************************************************************/
+#include "config.h"
+#include "log.h"
+#include "map.h"
+#include "rand.h"
+
+#include "utilities.h"
+#include "characteristics.h"
+#include "height_map.h"
+#include "mapgen_topology.h"
+
+#define RIVERS_MAXTRIES 32767
+enum river_map_type {RS_BLOCKED = 0, RS_RIVER = 1};
+
+static characteristic_type *characteristic_map;
+
+characteristic_type CM_TRUE, CM_FALSE;
+characteristic_type CM_FLAT, CM_HILLY, CM_ABRUPT,
+                    CM_NFLAT;
+characteristic_type CM_FROZEN, CM_COLD, CM_TEMPERATE, CM_TROPICAL,
+                    CM_NFROZEN,  CM_ALL, CM_NHOT, CM_HOT;
+characteristic_type CM_OCEANIC,  CM_WET, CM_MEDIUM, CM_DRY,
+                    CM_NWET, CM_NDRY;
+characteristic_type CM_RIVER;
+
+void characteristics_initialize_shores(void);
+void characteristics_initialize_extra_polar_land(void);
+void characteristics_initialize_relief(void);
+void characteristics_initialize_temperature(bool real);
+void characteristics_initialize_wetness(void);
+
+/**************************************************************************
+ return TRUE if initialized
+*************************************************************************/ 
+bool characteristics_are_initialized(void)
+{
+  return characteristic_map != NULL;
+}
+
+/****************************************************************************
+ create the map and initialize CM_XXX
+ call other inizialize methodes
+ if has_height_map is FALSE only initialize temperature with not height map
+ (hack for gen 2-4, and for loaded maps with not hut or spetials)
+****************************************************************************/
+void create_characteristics(bool has_height_map)                               
+{                                                          
+  assert( !characteristics_are_initialized());                              
+  characteristic_map = fc_malloc (sizeof(characteristic_type) * MAX_MAP_INDEX);
+  whole_map_iterate_index(i) {
+    BV_CLR_ALL(characteristic_map[i]);
+    BV_SET(characteristic_map[i], CB_TRUE);
+  }whole_map_iterate_index_end;
+
+  
+  BV_CLR_ALL(CM_TRUE);
+  BV_SET(CM_TRUE, CB_TRUE);
+  BV_CLR_ALL(CM_FALSE);
+
+  /* initialize constant values of relief */
+  BV_CLR_ALL(CM_FLAT);
+  BV_SET(CM_FLAT, CB_FLAT);
+  BV_CLR_ALL(CM_HILLY);
+  BV_SET(CM_HILLY, CB_HILLY);
+  BV_CLR_ALL(CM_ABRUPT);
+  BV_SET(CM_ABRUPT, CB_ABRUPT);
+  BV_CLR_ALL(CM_NFLAT);
+  BV_SET(CM_NFLAT, CB_HILLY);
+  BV_SET(CM_NFLAT, CB_ABRUPT);
+
+  /* inizialize constant value of temperature */
+  BV_CLR_ALL(CM_FROZEN);
+  BV_SET(CM_FROZEN, CB_FROZEN);
+  BV_CLR_ALL(CM_COLD);
+  BV_SET(CM_COLD, CB_COLD);
+  BV_CLR_ALL(CM_TEMPERATE);
+  BV_SET(CM_TEMPERATE, CB_TEMPERATE);
+  BV_CLR_ALL(CM_TROPICAL);
+  BV_SET(CM_TROPICAL, CB_TROPICAL);
+
+  BV_CLR_ALL(CM_NFROZEN);
+  BV_SET(CM_NFROZEN, CB_COLD);
+  BV_SET(CM_NFROZEN, CB_TEMPERATE);
+  BV_SET(CM_NFROZEN, CB_TROPICAL);
+
+  BV_CLR_ALL(CM_ALL);
+  BV_SET(CM_ALL, CB_FROZEN);
+  BV_SET(CM_ALL, CB_COLD);
+  BV_SET(CM_ALL, CB_TEMPERATE);
+  BV_SET(CM_ALL, CB_TROPICAL);
+
+  BV_CLR_ALL(CM_NHOT);
+  BV_SET(CM_NHOT, CB_FROZEN);
+  BV_SET(CM_NHOT, CB_COLD);
+ 
+  BV_CLR_ALL(CM_HOT);
+  BV_SET(CM_HOT, CB_TEMPERATE);
+  BV_SET(CM_HOT, CB_TROPICAL);
+
+  BV_CLR_ALL(CM_OCEANIC);
+  BV_SET(CM_OCEANIC, CB_OCEANIC);
+  BV_CLR_ALL(CM_WET);
+  BV_SET(CM_WET, CB_WET);
+  BV_CLR_ALL(CM_MEDIUM);
+  BV_SET(CM_MEDIUM, CB_MEDIUM);
+  BV_CLR_ALL(CM_DRY);
+  BV_SET(CM_DRY, CB_DRY);
+
+  BV_CLR_ALL(CM_NWET);
+  BV_SET(CM_NWET, CB_MEDIUM);
+  BV_SET(CM_NWET, CB_DRY);
+
+  BV_CLR_ALL(CM_NDRY);
+  BV_SET(CM_NDRY, CB_MEDIUM);
+  BV_SET(CM_NDRY, CB_WET);
+  
+  BV_CLR_ALL(CM_RIVER);
+  BV_SET(CM_RIVER, CB_RIVER);
+  
+
+  if (has_height_map) {
+    /* now initialize the oceanic tiles and the shore_level */
+    characteristics_initialize_shores();
+    /* this is a hack to terrains-set with not frozen oceans*/
+    if (HAS_POLES) { 
+      characteristics_initialize_extra_polar_land();
+    }
+    /*
+      initialize the temperature and relief characteristics, these call
+      need, other the height map and colatitude, to known the oceanics
+      tiles and the shore_level
+    */ 
+    characteristics_initialize_relief();
+    characteristics_initialize_temperature(TRUE);
+    
+    /*
+      now initialize wetness, this call need other characteristics to be
+      initilaized.
+    */
+    characteristics_initialize_wetness(); /* and rivers */
+    
+  } else {
+      characteristics_initialize_temperature(FALSE);
+  }
+}
+
+/**************************************************************************** 
+  Free the map
+****************************************************************************/
+void destroy_characteristics(void)   
+{                              
+  assert(characteristics_are_initialized()); 
+  free(characteristic_map);            
+  characteristic_map = NULL;           
+}
+/***************************************************************************
+ Test the characteristic of a index position on map
+ ***************************************************************************/
+
+bool is_characteristic(int i, characteristic_type mask )
+{
+  return BV_CHECK_MASK(characteristic_map[i], mask);
+}
+
+/******************************************************************
+ Return the number of tiles adjacent to the given place with the right
+ characteristic mask.
+ ******************************************************************/
+int count_characteristic_near(int i, bool cardinal_only, bool percentage
+                             ,characteristic_type mask)
+{
+  int count = 0, total = 0, x, y;
+
+  index_to_map_pos(&x, &y, i);
+  variable_adjc_iterate(x, y, x1, y1, cardinal_only) {
+    if (is_characteristic(map_pos_to_index(x1,y1), mask)) {
+      count++;
+    }
+    total++;
+  } variable_adjc_iterate_end;
+
+  if (percentage) {
+    count = count * 100 / total;
+  }
+  return count;
+}
+/**************************************************************************** 
+  set all tiles in placed_map when this has the right CM_XXX mask
+****************************************************************************/
+static void set_all_mask_placed(characteristic_type mask) 
+{                               
+  whole_map_iterate(x, y) {     
+    if (is_characteristic(map_pos_to_index(x,y),mask)) { 
+      map_set_placed(x, y);     
+    }                           
+  } whole_map_iterate_end;      
+}
+
+/*************************************************************************
+ set CB_OCEANIC in thiles will be oceans
+ ************************************************************************/
+void characteristics_initialize_shores(void)
+{
+  if (HAS_POLES) {
+    normalize_hmap_poles();
+  }
+  hmap_shore_level = (hmap_max_level * (100 - map.landpercent)) / 100;
+  whole_map_iterate_index(i) {
+    if (height_map[i] < hmap_shore_level) {
+      BV_SET(characteristic_map[i], CB_OCEANIC);
+    }
+  } whole_map_iterate_index_end;
+  if (HAS_POLES) {
+    renormalize_hmap_poles();
+  } 
+}
+
+/*************************************************************************
+ if separatepoles is set, return false if this tile has to keep ocean
+************************************************************************/
+static bool ok_for_separate_poles(int index) 
+{
+  int x, y;
+  if (!map.separatepoles) {
+    return TRUE;
+  }
+  index_to_map_pos(&x, &y, index);
+  adjc_iterate(x, y, x1, y1) {
+    if(!is_characteristic(map_pos_to_index(x1, y1), CM_OCEANIC) &&
+       (map_colatitude(x1, y1) > 2 * ICE_BASE_LEVEL)) {
+      return FALSE;
+    }
+  } adjc_iterate_end;
+  return TRUE;
+}
+
+/****************************************************************************
+  Place untextured land at the poles.  This is used by generators 1 and 5
+  on tiles-sets with not forzen oceans
+****************************************************************************/
+void characteristics_initialize_extra_polar_land(void)
+{
+  whole_map_iterate_index(i) {
+    if ((colatitude(i) <=  2 * ICE_BASE_LEVEL) &&
+         ok_for_separate_poles(i)) {
+      BV_CLR(characteristic_map[i], CB_OCEANIC);
+    } 
+  } whole_map_iterate_index_end;
+}
+
+/**************************************************************************
+  we don't want huge flat areas, 
+  so we put in a hill here and there, where it gets too flat 
+
+  Return TRUE if the terrain at the given map position is too flat.  This
+  means that all the terrain for 2 squares around it are only flat.
+****************************************************************************/
+static bool terrain_is_too_flat(int index, int thill, int my_height)
+{
+  int higher_than_me = 0, x, y;
+
+  index_to_map_pos(&x, &y, index);
+  square_iterate(x, y, 2, x1, y1) {
+    if (hmap(x1, y1) > thill) {
+      return FALSE;
+    }
+    if (hmap(x1, y1) > my_height) {
+      if (map_distance(x, y, x1, y1) == 1) {
+       return FALSE;
+      }
+      if (++higher_than_me > 2) {
+       return FALSE;
+      }
+    }
+  } square_iterate_end;
+
+  if ((thill - hmap_shore_level) * higher_than_me  > 
+      (my_height - hmap_shore_level) * 4) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**************************************************************************
+  we don't want huge areas of hill/mountains, 
+  so we put in a plains here and there, where it gets too heigh 
+
+  Return TRUE if the terrain at the given map position is too heigh.
+****************************************************************************/
+static bool terrain_is_too_high(int index, int thill, int my_height)
+{
+  int x, y;
+
+  index_to_map_pos(&x, &y, index);
+  square_iterate(x, y, 1, x1, y1) {
+    if (hmap(x1, y1) + (hmap_max_level - hmap_mountain_level) / 5 < thill) {
+      return FALSE;
+    }
+  } square_iterate_end;
+  return TRUE;
+}
+
+/**************************************************************************
+  make_relief() will convert all squares that are higher than thill to
+  mountains and hills. Note that thill will be adjusted according to
+  the map.steepness value, so increasing map.steepness will result in
+  more hilly and abrupts maps.
+**************************************************************************/
+void characteristics_initialize_relief(void)
+{
+  /* Calculate the mountain level.  map.mountains specifies the percentage
+   * of land that is turned into hills and mountains. */
+  hmap_mountain_level = ((hmap_max_level - hmap_shore_level)
+                        * (100 - map.steepness)) / 100 + hmap_shore_level;
+
+  whole_map_iterate_index(i) {
+    if (!is_characteristic(i, CM_OCEANIC) &&
+       ((hmap_mountain_level < height_map[i] && 
+         (myrand(10) > 5 
+          || !terrain_is_too_high(i, hmap_mountain_level, height_map[i])))
+        || terrain_is_too_flat(i, hmap_mountain_level, height_map[i]))) {
+      /* Randomly place hills and mountains on "high" tiles. */
+      if (myrand(100) > 70) {
+       BV_SET(characteristic_map[i], CB_ABRUPT);
+      } else {
+       BV_SET(characteristic_map[i], CB_HILLY);
+      }
+    } else {
+       BV_SET(characteristic_map[i], CB_FLAT);
+    }
+  } whole_map_iterate_index_end;
+}
+
+/***************************************************************************
+ * create_tmap initialize the temperature_map
+ * if arg is FALSE, create a dumy tmap == map_colattitude
+ * to be used if hmap or oceans are not placed gen 2-4
+ ***************************************************************************/
+void characteristics_initialize_temperature(bool real)
+{
+  int temperature[MAX_MAP_INDEX];
+
+  whole_map_iterate_index(i) {
+  
+     /* the base temperature is equal to base map_colatitude */
+    int t = colatitude(i) ;
+    if (!real) {
+      temperature[i] =  t;
+    } else {
+      /* height land can be 30% collest */
+      float height = - 0.3 * MAX(0, height_map[i] - hmap_shore_level) 
+         / (hmap_max_level - hmap_shore_level); 
+      /* near ocean temperature can be 15 % more "temperate" */
+      float temperate = 0.15 * (map.temperature / 100 - t / MAX_COLATITUDE) * 
+         2 * MIN (50 ,
+                  count_characteristic_near(i, FALSE, TRUE, CM_OCEANIC)) /
+         100;
+      
+      temperature[i] = t * (1.0 + temperate) * (1.0 + height);
+    }
+  } whole_map_iterate_index_end;
+  /* adjust to get well sizes frequencies */
+  /* Notice: if colatitude is load from a scenario never call adjust has
+             scenario maybe has a odd colatitude ditribution and adjust will
+            brack it */
+  if (!map.alltemperate) {
+    adjust_int_map(temperature, MAX_COLATITUDE);
+  }
+  /* now simplify to 4 base values */ 
+  whole_map_iterate_index(i) {
+    int t = temperature[i];
+
+    /* first if is a hack to avoid some ugly effect,
+       TODO: think if there is a best way, veriffy off by one in colatitude */ 
+    if (colatitude(i) < 2 * ICE_BASE_LEVEL) {
+      BV_SET(characteristic_map[i], CB_FROZEN);
+    } 
+
+    else if (t >= TROPICAL_LEVEL ) {
+      BV_SET(characteristic_map[i], CB_TROPICAL);
+    } else if (t >= COLD_LEVEL) {
+      BV_SET(characteristic_map[i], CB_TEMPERATE);
+    } else if (t >= 2 * ICE_BASE_LEVEL) {
+      BV_SET(characteristic_map[i], CB_COLD);
+    } else {
+      BV_SET(characteristic_map[i], CB_FROZEN);
+    }
+  }  whole_map_iterate_index_end;
+}
+/***************************************************************************
+  Passed as data to rand_map_pos_filtered() by rand_map_pos_characteristic()
+***************************************************************************/
+struct DataFilter {
+    characteristic_type c1, c2, c3;
+};
+
+/****************************************************************************
+  A filter function to be passed to rand_map_pos_filtered().  See
+  rand_map_pos_characteristic for more explanation.
+****************************************************************************/
+static bool condition_filter(int x, int y, void *data)
+{
+  struct DataFilter *filter = data;
+  int index = map_pos_to_index(x, y);
+
+  return  not_placed(index) 
+       && is_characteristic(index, filter->c1) 
+       && is_characteristic(index, filter->c2) 
+       && is_characteristic(index, filter->c3);
+}
+
+/****************************************************************************
+  Return random map coordinates which have some conditions and which are
+  not yet placed on pmap.
+  Returns FALSE if there is no such position.
+****************************************************************************/
+bool rand_index_characteristic(int *index, characteristic_type c1,
+                              characteristic_type c2, characteristic_type c3 )
+{
+  struct DataFilter filter;
+  int x, y;
+
+  filter.c1 = c1;
+  filter.c2 = c2;
+  filter.c3 = c3;
+  if (rand_map_pos_filtered(&x, &y, &filter, condition_filter)) {
+    *index = map_pos_to_index(x, y);
+    return TRUE;
+  } else {
+    return FALSE;
+  } 
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_blocked(int index, int *river_map)
+{
+  if (TEST_BIT(river_map[index], RS_BLOCKED))
+    return 1;
+
+  /* any un-blocked? */
+  index_cardinal_adjc_dir_iterate(index, index1, dir) {
+    if (!TEST_BIT(river_map[index1], RS_BLOCKED))
+      return 0;
+  } index_cardinal_adjc_dir_iterate_end;
+
+  return 1; /* none non-blocked |- all blocked */
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_rivergrid(int index,int *river_map)
+{
+  return (count_characteristic_near(index, TRUE, FALSE, CM_RIVER) 
+         > 1) ? 1 : 0;
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_highlands(int index,int *river_map)
+{
+  return ((is_characteristic(index, CM_HILLY)  ? 1 : 0) +
+         (is_characteristic(index, CM_ABRUPT) ? 2 : 0));
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_adjacent_ocean(int index,int *river_map)
+{
+  return 100 - count_characteristic_near(index, TRUE, TRUE, CM_OCEANIC);
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_adjacent_river(int index,int *river_map)
+{
+  return 100 - count_characteristic_near(index, TRUE, TRUE, CM_RIVER);
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_adjacent_highlands(int index,int *river_map)
+{
+  return (count_characteristic_near(index, TRUE, TRUE, CM_HILLY)
+         + 2 * count_characteristic_near(index, TRUE, TRUE, CM_ABRUPT));
+}
+
+/*********************************************************************
+ Help function used in make_river(). See the help there.
+*********************************************************************/
+static int river_test_height_map(int index,int *river_map)
+{
+  return height_map[index];
+}
+
+/*********************************************************************
+ Called from make_river. Marks all directions as blocked.  -Erik Sigra
+*********************************************************************/
+static void river_blockmark(int index,int *river_map)
+{
+  freelog(LOG_DEBUG, "Blockmarking (%d) and adjacent tiles.",
+         index);
+
+  river_map[index] |= (1u << RS_BLOCKED);
+
+  index_cardinal_adjc_dir_iterate(index, index1, dir) {
+    river_map[index1] |= (1u << RS_BLOCKED);
+  } index_cardinal_adjc_dir_iterate_end;
+}
+
+struct test_func {
+  int (*func)(int, int*);
+  bool fatal;
+};
+
+#define NUM_TEST_FUNCTIONS 7
+static struct test_func test_funcs[NUM_TEST_FUNCTIONS] = {
+  {river_test_blocked,            TRUE},
+  {river_test_rivergrid,          TRUE},
+  {river_test_highlands,          FALSE},
+  {river_test_adjacent_ocean,     FALSE},
+  {river_test_adjacent_river,     FALSE},
+  {river_test_adjacent_highlands, FALSE},
+  {river_test_height_map,         FALSE}
+};
+
+/********************************************************************
+ Makes a river starting at (x, y). Returns 1 if it succeeds.
+ Return 0 if it fails. The river is stored in river_map.
+ 
+ How to make a river path look natural
+ =====================================
+ Rivers always flow down. Thus rivers are best implemented on maps
+ where every tile has an explicit height value. However, Freeciv has a
+ flat map. But there are certain things that help the user imagine
+ differences in height between tiles. The selection of direction for
+ rivers should confirm and even amplify the user's image of the map's
+ topology.
+ 
+ To decide which direction the river takes, the possible directions
+ are tested in a series of test until there is only 1 direction
+ left. Some tests are fatal. This means that they can sort away all
+ remaining directions. If they do so, the river is aborted. Here
+ follows a description of the test series.
+ 
+ * Falling into itself: fatal
+     (river_test_blocked)
+     This is tested by looking up in the river_map array if a tile or
+     every tile surrounding the tile is marked as blocked. A tile is
+     marked as blocked if it belongs to the current river or has been
+     evaluated in a previous iteration in the creation of the current
+     river.
+     
+     Possible values:
+     0: Is not falling into itself.
+     1: Is falling into itself.
+     
+ * Forming a 4-river-grid: optionally fatal
+     (river_test_rivergrid)
+     A minimal 4-river-grid is formed when an intersection in the map
+     grid is surrounded by 4 river tiles. There can be larger river
+     grids consisting of several overlapping minimal 4-river-grids.
+     
+     Possible values:
+     0: Is not forming a 4-river-grid.
+     1: Is forming a 4-river-grid.
+
+ * Highlands:
+     (river_test_highlands)
+     Rivers must not flow up in mountains or hills if there are
+     alternatives.
+     
+     Possible values:
+     0: Is not hills and not mountains.
+     1: Is hills.
+     2: Is mountains.
+
+ * Adjacent ocean:
+     (river_test_adjacent_ocean)
+     Rivers must flow down to coastal areas when possible:
+
+     Possible values: 0-100
+
+ * Adjacent river:
+     (river_test_adjacent_river)
+     Rivers must flow down to areas near other rivers when possible:
+
+     Possible values: 0-100
+                                       
+ * Adjacent highlands:
+     (river_test_adjacent_highlands)
+     Rivers must not flow towards highlands if there are alternatives. 
+     
+ * height_map:
+     (river_test_height_map)
+     Rivers must flow in the direction which takes it to the tile with
+     the lowest value on the height_map.
+     
+     Possible values:
+     n: height_map[...]
+     
+ If these rules haven't decided the direction, the random number
+ generator gets the desicion.                              -Erik Sigra
+*********************************************************************/
+static bool make_river(int index, int *river_map)
+{
+  /* Comparison value for each tile surrounding the current tile.  It is
+   * the suitability to continue a river to the tile in that direction;
+   * lower is better.  However rivers may only run in cardinal directions;
+   * the other directions are ignored entirely. */
+  int rd_comparison_val[8];
+
+  bool rd_direction_is_valid[8];
+  int num_valid_directions, func_num, direction;
+
+  while (TRUE) {
+    /* Mark the current tile as river. */
+    river_map[index] |= (1u << RS_RIVER);
+    freelog(LOG_DEBUG,
+           "The tile at (%d) has been marked as river in river_map.\n",
+           index);
+
+    /* Test if the river is done. */
+    /* We arbitrarily make rivers end at the poles. */
+    if (count_characteristic_near(index, TRUE, TRUE, CM_RIVER)
+       + count_characteristic_near(index, TRUE, TRUE, CM_OCEANIC) > 0
+        || (is_characteristic(index, CM_FROZEN) 
+           &&  is_characteristic(index, CM_FLAT))) { 
+
+      freelog(LOG_DEBUG,
+             "The river ended at (%d).\n", index);
+      return TRUE;
+    }
+
+    /* Else choose a direction to continue the river. */
+    freelog(LOG_DEBUG,
+           "The river did not end at (%d). Evaluating directions...\n",
+           index);
+
+    /* Mark all available cardinal directions as available. */
+    memset(rd_direction_is_valid, 0, sizeof(rd_direction_is_valid));
+    index_cardinal_adjc_dir_iterate(index, index1, dir) {
+      rd_direction_is_valid[dir] = TRUE;
+      if (0 == index1) continue; /* silence warning */
+    } index_cardinal_adjc_dir_iterate_end;
+
+    /* Test series that selects a direction for the river. */
+    for (func_num = 0; func_num < NUM_TEST_FUNCTIONS; func_num++) {
+      int best_val = -1;
+
+      /* first get the tile values for the function */
+      index_cardinal_adjc_dir_iterate(index, index1, dir) {
+
+       if (rd_direction_is_valid[dir]) {
+         rd_comparison_val[dir] = 
+             (test_funcs[func_num].func) (index1 , river_map);
+         if (best_val == -1) {
+           best_val = rd_comparison_val[dir];
+         } else {
+           best_val = MIN(rd_comparison_val[dir], best_val);
+         }
+       }
+      } index_cardinal_adjc_dir_iterate_end;
+      assert(best_val != -1);
+
+      /* should we abort? */
+      if (best_val > 0 && test_funcs[func_num].fatal) {
+       return FALSE;
+      }
+
+      /* mark the less attractive directions as invalid */
+      index_cardinal_adjc_dir_iterate(index, index1, dir) {
+       if (rd_direction_is_valid[dir]) {
+         if (rd_comparison_val[dir] != best_val) {
+           rd_direction_is_valid[dir] = FALSE;
+         }
+       }
+       if (index == index1) continue; /* silence warning */
+      } index_cardinal_adjc_dir_iterate_end;
+    }
+
+    /* Directions evaluated with all functions. Now choose the best
+       direction before going to the next iteration of the while loop */
+    num_valid_directions = 0;
+    index_cardinal_adjc_dir_iterate(index, index1, dir) {
+      if (rd_direction_is_valid[dir]) {
+       num_valid_directions++;
+      }
+      if (index == index1) continue; /* silence warning */
+    } index_cardinal_adjc_dir_iterate_end;
+
+    if (num_valid_directions == 0) {
+      return FALSE; /* river aborted */
+    }
+
+    /* One or more valid directions: choose randomly. */
+    freelog(LOG_DEBUG, "mapgen.c: Had to let the random number"
+           " generator select a direction for a river.");
+    direction = myrand(num_valid_directions);
+    freelog(LOG_DEBUG, "mapgen.c: direction: %d", direction);
+
+    /* Find the direction that the random number generator selected. */
+    index_cardinal_adjc_dir_iterate(index, index1, dir) {
+
+      if (rd_direction_is_valid[dir]) {
+       if (direction > 0) {
+         direction--;
+       } else {
+         river_blockmark(index1, river_map);
+         index = index1;
+         break;
+       }
+      }
+    } index_cardinal_adjc_dir_iterate_end;
+    assert(direction == 0);
+
+  } /* end while; (Make a river.) */
+}
+
+/**************************************************************************
+  Calls make_river until there are enough river tiles on the map. It stops
+  when it has tried to create RIVERS_MAXTRIES rivers.           -Erik Sigra
+**************************************************************************/
+static void make_rivers(int *river_probability)
+{
+  int river_map[MAX_MAP_INDEX], index;
+  int polar = 2 * ICE_BASE_LEVEL * map.landpercent / MAX_COLATITUDE ;
+  /* magic math to evaluater river_pct  3 - 11 % */
+  int river_pct =  (100 - polar) * (3 + map.wetness / 12) / 100;
+
+  /* Formula to make the river density similar om different sized maps. Avoids
+     too few rivers on large maps and too many rivers on small maps. */
+  int desirable_riverlength =
+      
+    river_pct *
+      /* The size of the map (poles counted in river_pct). */
+      map_num_tiles() *
+      /* Rivers need to be on land only. */
+      map.landpercent /
+      /* Adjustment value. Tested by me. Gives no rivers with 'set
+        rivers 0', gives a reasonable amount of rivers with default
+        settings and as many rivers as possible with 'set rivers 100'. */
+      5325;
+
+  /* The number of river tiles that have been set. */
+  int current_riverlength = 0;
+
+  /* Counts the number of iterations (should increase with 1 during
+     every iteration of the main loop in this function).
+     Is needed to stop a potentially infinite loop. */
+  int iteration_counter = 0;
+
+  create_placed_map(); /* needed bu rand_map_characteristic */
+  set_all_mask_placed(CM_OCEANIC);
+
+  /* The main loop in this function. */
+  while (current_riverlength < desirable_riverlength
+        && iteration_counter < RIVERS_MAXTRIES) {
+
+    if (!rand_index_characteristic(&index, 
+                                     CM_NFROZEN, CM_TRUE, CM_TRUE)) {
+       break; /* mo more spring places */
+    }
+
+    /* Check if it is suitable to start a river on the current tile.
+     */
+    if ((myrand(100) < river_probability[index])
+       /* Don't start a river on a tile is surrounded by > 1 river +
+          ocean tile. */
+       && (count_characteristic_near(index, TRUE, FALSE, CM_RIVER)
+          + count_characteristic_near(index, TRUE, FALSE, CM_OCEANIC) <= 1)
+
+       /* Don't start a river on a tile that is surrounded by hills or
+          mountains unless it is hard to find somewhere else to start
+          it. */
+       && (count_characteristic_near(index,TRUE, TRUE, CM_ABRUPT)
+         + count_characteristic_near(index, TRUE, TRUE, CM_HILLY) < 90
+           || (iteration_counter > RIVERS_MAXTRIES / 10 * 5))
+
+       /* Don't start a river on hills unless it is hard to find
+          somewhere else to start it. */
+       && (!is_characteristic(index, CM_HILLY)
+           || (iteration_counter > RIVERS_MAXTRIES / 10 * 6))
+
+       /* Don't start a river on mountains unless it is hard to find
+          somewhere else to start it. */
+       && (!is_characteristic(index, CM_ABRUPT)
+           || (iteration_counter > RIVERS_MAXTRIES / 10 * 7))
+       ) {
+
+      /* Reset river_map before making a new river. */
+      whole_map_iterate_index(i) {
+       river_map[i] = 0;
+      } whole_map_iterate_index_end;
+
+      freelog(LOG_DEBUG,
+             "Found a suitable starting tile for a river at (%d)."
+             " Starting to make it.",
+             index);
+
+      /* Try to make a river. If it is OK, apply it to the map. */
+      if (make_river(index, river_map)) {
+       whole_map_iterate(x1, y1) {
+         if (TEST_BIT(river_map[map_pos_to_index(x1, y1)], RS_RIVER)) {
+           BV_SET(characteristic_map[map_pos_to_index(x1, y1)], CB_RIVER);
+           current_riverlength++;
+           map_set_placed(x1, y1);
+           /* reduce probability near a river */
+           circle_iterate(x1, y1, 4, x2, y2) {
+               river_probability[map_pos_to_index(x2, y2)] *= 0.9;
+           } circle_iterate_end;
+           freelog(LOG_DEBUG, "Applied a river to (%d).",
+                   map_pos_to_index(x1, y1));
+         }
+       } whole_map_iterate_end;
+      }
+      else {
+       freelog(LOG_DEBUG,
+       "mapgen.c: A river failed. It might have gotten stuck in a helix.");
+      }
+    } /* end if; */
+    iteration_counter++;
+    freelog(LOG_DEBUG,
+    "current_riverlength: %d; desirable_riverlength: %d; iteration_counter: 
%d",
+           current_riverlength, desirable_riverlength, iteration_counter);
+  } /* end while; */
+
+  destroy_placed_map();
+}
+
+/**************************************************************************
+  Change the values of the integer map, so that they contain ranking of each 
+  tile scaled to [0 .. int_map_max]. on tiles with the right characteristics
+**************************************************************************/
+static void adjust_int_map_masks(int *int_map, int int_map_max,
+                         characteristic_type mask,characteristic_type Nmask )
+{
+  int minval = 1000000000, maxval = -1000000000, total = 0;
+
+  /* Determine minimum and maximum value. */
+  whole_map_iterate_masks_index(j, mask, Nmask) {
+    maxval = MAX(maxval, int_map[j]);
+    minval = MIN(minval, int_map[j]);
+    total++;
+  } whole_map_iterate_masks_index_end;
+
+  {
+    int const size = 1 + maxval - minval;
+    int i, count = 0, frequencies[size];
+
+    INITIALIZE_ARRAY(frequencies, size, 0);
+
+    /* Translate value so the minimum value is 0
+       and count the number of occurencies of all values to initialize the 
+       frequencies[] */
+    whole_map_iterate_masks_index(j, mask, Nmask) {
+      int_map[j] = (int_map[j] - minval);
+      frequencies[int_map[j]]++;
+    } whole_map_iterate_masks_index_end ;
+
+    /* create the linearize function as "incremental" frequencies */
+    for(i =  0; i < size; i++) {
+      count += frequencies[i]; 
+      frequencies[i] = (count * int_map_max) / total;
+    }
+
+    /* apply the linearize function */
+    whole_map_iterate_masks_index(j, mask, Nmask) {
+      int_map[j] = frequencies[int_map[j]];
+    } whole_map_iterate_masks_index_end;
+  }
+}
+
+
+#define colatitude_is_dry(i)                           \
+  (colatitude((i)) <= DRY_MAX_LEVEL                    \
+   && colatitude((i)) > DRY_MIN_LEVEL)
+
+void characteristics_initialize_wetness()
+{
+  int wetness[MAX_MAP_INDEX];
+  /* there wetness[]  means the probability to start a river*/
+  whole_map_iterate_index(i) {
+    if (colatitude_is_dry(i)) {
+      wetness[i] = 70;
+    } else {
+      wetness[i] = 100;
+    }
+  } whole_map_iterate_index_end;
+
+  make_rivers(wetness);
+
+  /* now wetness[] means amount of water */
+  whole_map_iterate_index(i) {
+    float dry_bonus = colatitude_is_dry(i) ? 1 : 0;
+    float tropical_bonus = (colatitude(i) > TROPICAL_LEVEL) ? 1 : 0;
+    float height_bonus = MAX(0, (height_map[i] -  hmap_shore_level))
+                            / (hmap_max_level - hmap_shore_level);
+    float river_bonus = is_characteristic(i, CM_RIVER) ? 1 : 0;
+    float ocean_bonus = is_characteristic(i, CM_OCEANIC) ? 1 : 0;
+
+    wetness[i] = (100 - 10 * dry_bonus + 5 * tropical_bonus)
+       * (100 + 30 * river_bonus + 20 * ocean_bonus)
+       * (100 + 30 * height_bonus) / 100;
+  } whole_map_iterate_index_end;
+
+  smooth_int_map(wetness, FALSE);
+  {
+      characteristic_type CM_AVOID;
+    BV_CLR_ALL(CM_AVOID);
+    BV_SET(CM_AVOID, CB_FROZEN);
+    BV_SET(CM_AVOID, CB_OCEANIC);
+    adjust_int_map_masks(wetness, 1000, CM_FROZEN, CM_OCEANIC);
+    adjust_int_map_masks(wetness, 1000, CM_FLAT, CM_AVOID);
+    adjust_int_map_masks(wetness, 1000, CM_HILLY, CM_AVOID);
+    adjust_int_map_masks(wetness, 1000, CM_ABRUPT, CM_AVOID);
+  }
+  whole_map_iterate_index(i) {
+    if (is_characteristic(i, CM_OCEANIC)) {
+      continue;
+    }
+    if (wetness[i] < 300) {
+      BV_SET(characteristic_map[i], CB_DRY);
+    } else if(wetness[i] < 700){
+      BV_SET(characteristic_map[i], CB_MEDIUM);
+    } else  {
+      BV_SET(characteristic_map[i], CB_WET);
+    } 
+  } whole_map_iterate_index_end;
+}
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/characteristics.h 
freeciv_/server/generator/characteristics.h
--- freeciv/server/generator/characteristics.h  1970-01-01 01:00:00.000000000 
+0100
+++ freeciv_/server/generator/characteristics.h 2004-09-24 11:15:02.000000000 
+0200
@@ -0,0 +1,78 @@
+/********************************************************************** 
+   Copyright (C) 1996-2004 - The Freeciv Project Team,
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+***********************************************************************/
+#ifndef FC__CHARACTERISTICS_H
+#define FC__CHARACTERISTICS_H
+
+BV_DEFINE(characteristic_type, 13);
+typedef enum  {CB_TRUE = 0, 
+              CB_RIVER,
+              CB_FROZEN , CB_COLD , CB_TEMPERATE, CB_TROPICAL,
+               CB_OCEANIC,  CB_WET , CB_MEDIUM , CB_DRY ,
+               CB_FLAT, CB_HILLY, CB_ABRUPT} characteristic_bits;
+
+/* test for CM_TRUE mask is all the time TRUE, 
+ * test for CM_FALSE mask is FALSE! 
+ */
+extern characteristic_type CM_TRUE, CM_FALSE;
+extern characteristic_type CM_FLAT, CM_HILLY, CM_ABRUPT,
+                           CM_NFLAT;
+extern characteristic_type CM_FROZEN, CM_COLD, CM_TEMPERATE, CM_TROPICAL,
+                           CM_NFROZEN,  CM_ALL, CM_NHOT, CM_HOT;
+/*
+ CM_NFROZEN == (CM_COLD | CM_TEMPERATE | CM_TROPICAL)
+ CM_ALL     == (CM_FROZEN | CM_NFROZEN)
+ CM_NHOT    == (CM_FROZEN | CM_COLD)
+ CM_HOT     == (CM_TEMPERATE, CM_TROPICAL)
+ */
+                          
+extern characteristic_type CM_OCEANIC,  CM_WET, CM_MEDIUM, CM_DRY,
+                           CM_NWET, CM_NDRY;
+extern characteristic_type CM_RIVER;
+
+bool characteristics_are_initialized(void);
+void create_characteristics(bool has_height_map);
+void destroy_characteristics(void);  
+
+bool is_characteristic(int index, characteristic_type mask );
+int count_characteristic_near(int index , bool cardinal_only, bool percentage,
+                             characteristic_type mask);
+
+bool rand_index_characteristic(int *index, characteristic_type c1,
+                              characteristic_type c2,characteristic_type c3 );
+
+/*
+ * little iterator on indexes
+ */
+#define index_cardinal_adjc_dir_iterate(index, index1, dir) \
+  { \
+    int _x, _y; \
+    index_to_map_pos(&_x, &_y, (index)); \
+    cardinal_adjc_dir_iterate(_x, _y, _x1, _y1, dir) { \
+      const int index1 = map_pos_to_index(_x1, _y1);
+ 
+#define index_cardinal_adjc_dir_iterate_end \
+        } cardinal_adjc_dir_iterate_end; }
+
+/*
+ iterate on tile with the right mask and with not the Nmask
+*/
+
+#define  whole_map_iterate_masks_index(i, mask, Nmask) \
+   whole_map_iterate_index(i) { \
+   if(is_characteristic(i, Nmask) || !is_characteristic(i, mask)) { \
+     continue; \
+   }
+
+#define  whole_map_iterate_masks_index_end } whole_map_iterate_index_end
+
+#endif  /* FC__CHARACTERISTICS_H */
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/Makefile.am 
freeciv_/server/generator/Makefile.am
--- freeciv/server/generator/Makefile.am        2004-09-16 11:53:11.000000000 
+0200
+++ freeciv_/server/generator/Makefile.am       2004-09-23 23:09:20.000000000 
+0200
@@ -14,5 +14,5 @@
        height_map.h \
        startpos.c \
        startpos.h \
-       temperature_map.c \
-       temperature_map.h
+       characteristics.h \
+       characteristics.c
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/mapgen.c 
freeciv_/server/generator/mapgen.c
--- freeciv/server/generator/mapgen.c   2004-09-22 08:39:29.000000000 +0200
+++ freeciv_/server/generator/mapgen.c  2004-09-24 12:29:45.000000000 +0200
@@ -36,9 +36,8 @@
 #include "height_map.h"
 #include "mapgen_topology.h"
 #include "startpos.h"
-#include "temperature_map.h"
 #include "utilities.h"
-
+#include "characteristics.h"
 
 /* Old-style terrain enumeration: deprecated. */
 enum {
@@ -56,17 +55,6 @@
 static void mapgenerator4(void);
 static void adjust_terrain_param(void);
 
-#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.
-   A value of 2 means river.                            -Erik Sigra */
-static int *river_map;
-
-#define HAS_POLES (map.temperature < 70 && !map.alltemperate  )
-
 /* These are the old parameters of terrains types in %
    TODO: they depend on the hardcoded terrains */
 static int forest_pct = 0;
@@ -76,272 +64,45 @@
 static int jungle_pct = 0;
 static int river_pct = 0;
  
-/****************************************************************************
- * Conditions used mainly in rand_map_pos_characteristic()
- ****************************************************************************/
-/* WETNESS */
-
-/* necessary condition of deserts placement */
-#define map_pos_is_dry(x, y)                                           \
-  (map_colatitude((x), (y)) <= DRY_MAX_LEVEL                           \
-   && map_colatitude((x), (y)) > DRY_MIN_LEVEL                         \
-   && count_ocean_near_tile((x), (y), FALSE, TRUE) <= 35)
-typedef enum { WC_ALL = 200, WC_DRY, WC_NDRY } wetness_c;
-
-/* MISCELANEOUS (OTHER CONDITIONS) */
-
-/* necessary condition of swamp placement */
-static int hmap_low_level = 0;
-#define ini_hmap_low_level() \
-{ \
-hmap_low_level = (4 * swamp_pct  * \
-     (hmap_max_level - hmap_shore_level)) / 100 + hmap_shore_level; \
-}
-/* should be used after having hmap_low_level initialized */
-#define map_pos_is_low(x, y) ((hmap((x), (y)) < hmap_low_level))
-
-typedef enum { MC_NONE, MC_LOW, MC_NLOW } miscellaneous_c;
-
-/***************************************************************************
- These functions test for conditions used in rand_map_pos_characteristic 
-***************************************************************************/
-
-/***************************************************************************
-  Checks if the given location satisfy some wetness condition
-***************************************************************************/
-static bool test_wetness(int x, int y, wetness_c c)
-{
-  switch(c) {
-  case WC_ALL:
-    return TRUE;
-  case WC_DRY:
-    return map_pos_is_dry(x, y);
-  case WC_NDRY:
-    return !map_pos_is_dry(x, y);
-  }
-  assert(0);
-  return FALSE;
-}
-
-/***************************************************************************
-  Checks if the given location satisfy some miscellaneous condition
-***************************************************************************/
-static bool test_miscellaneous(int x, int y, miscellaneous_c c)
-{
-  switch(c) {
-  case MC_NONE:
-    return TRUE;
-  case MC_LOW:
-    return map_pos_is_low(x, y);
-  case MC_NLOW:
-    return !map_pos_is_low(x, y);
-  }
-  assert(0);
-  return FALSE;
-}
-
-/***************************************************************************
-  Passed as data to rand_map_pos_filtered() by rand_map_pos_characteristic()
-***************************************************************************/
-struct DataFilter {
-  wetness_c wc;
-  temperature_type tc;
-  miscellaneous_c mc;
-};
-
-/****************************************************************************
-  A filter function to be passed to rand_map_pos_filtered().  See
-  rand_map_pos_characteristic for more explanation.
-****************************************************************************/
-static bool condition_filter(int map_x, int map_y, void *data)
-{
-  struct DataFilter *filter = data;
-
-  return  not_placed(map_x, map_y) 
-       && tmap_is(map_x, map_y, filter->tc) 
-       && test_wetness(map_x, map_y, filter->wc) 
-       && test_miscellaneous(map_x, map_y, filter->mc) ;
-}
-
-/****************************************************************************
-  Return random map coordinates which have some conditions and which are
-  not yet placed on pmap.
-  Returns FALSE if there is no such position.
-****************************************************************************/
-static bool rand_map_pos_characteristic(int *map_x, int *map_y,
-                                       wetness_c wc,
-                                       temperature_type tc,
-                                       miscellaneous_c mc )
-{
-  struct DataFilter filter;
-
-  filter.wc = wc;
-  filter.tc = tc;
-  filter.mc = mc;
-  return rand_map_pos_filtered(map_x, map_y, &filter, condition_filter);
-}
 
 /**************************************************************************
-  we don't want huge areas of grass/plains, 
-  so we put in a hill here and there, where it gets too 'clean' 
-
-  Return TRUE if the terrain at the given map position is "clean".  This
-  means that all the terrain for 2 squares around it is not mountain or hill.
-****************************************************************************/
-static bool terrain_is_too_flat(int map_x, int map_y,int thill, int my_height)
-{
-  int higher_than_me = 0;
-  square_iterate(map_x, map_y, 2, x1, y1) {
-    if (hmap(x1, y1) > thill) {
-      return FALSE;
-    }
-    if (hmap(x1, y1) > my_height) {
-      if (map_distance(map_x, map_y, x1, y1) == 1) {
-       return FALSE;
-      }
-      if (++higher_than_me > 2) {
-       return FALSE;
-      }
-    }
-  } square_iterate_end;
-
-  if ((thill - hmap_shore_level) * higher_than_me  > 
-      (my_height - hmap_shore_level) * 4) {
-    return FALSE;
-  }
-  return TRUE;
-}
-
-/**************************************************************************
-  we don't want huge areas of hill/mountains, 
-  so we put in a plains here and there, where it gets too 'heigh' 
-
-  Return TRUE if the terrain at the given map position is too heigh.
-****************************************************************************/
-static bool terrain_is_too_high(int map_x, int map_y,int thill, int my_height)
-{
-  square_iterate(map_x, map_y, 1, x1, y1) {
-    if (hmap(x1, y1) + (hmap_max_level - hmap_mountain_level) / 5 < thill) {
-      return FALSE;
-    }
-  } square_iterate_end;
-  return TRUE;
-}
-
-/**************************************************************************
-  make_relief() will convert all squares that are higher than thill to
-  mountains and hills. Note that thill will be adjusted according to
-  the map.steepness value, so increasing map.mountains will result in
-  more hills and mountains.
+  Recursively generate terrains.
 **************************************************************************/
-static void make_relief(void)
+static void place_terrain(int index, int diff, 
+                         Terrain_type_id ter, int *to_be_placed,
+                         characteristic_type wcm,
+                         characteristic_type tcm,
+                         characteristic_type mcm)
 {
-  /* Calculate the mountain level.  map.mountains specifies the percentage
-   * of land that is turned into hills and mountains. */
-  hmap_mountain_level = ((hmap_max_level - hmap_shore_level)
-                        * (100 - map.steepness)) / 100 + hmap_shore_level;
 
-  whole_map_iterate(x, y) {
-    if (not_placed(x,y) &&
-       ((hmap_mountain_level < hmap(x, y) && 
-         (myrand(10) > 5 
-          || !terrain_is_too_high(x, y, hmap_mountain_level, hmap(x, y))))
-        || terrain_is_too_flat(x, y, hmap_mountain_level, hmap(x, y)))) {
-      /* Randomly place hills and mountains on "high" tiles.  But don't
-       * put hills near the poles (they're too green). */
-      if (myrand(100) > 70 || tmap_is(x, y, TT_NHOT)) {
-       map_set_terrain(x, y, T_MOUNTAINS);
-       map_set_placed(x, y);
-      } else {
-       map_set_terrain(x, y, T_HILLS);
-       map_set_placed(x, y);
-      }
-    }
-  } whole_map_iterate_end;
-}
+  int x, y;
 
-/****************************************************************************
-  Add arctic and tundra squares in the arctic zone (that is, the coolest
-  10% of the map).  We also texture the pole (adding arctic, tundra, and
-  mountains).  This is used in generators 2-4.
-****************************************************************************/
-static void make_polar(void)
-{
-  whole_map_iterate(map_x, map_y) {  
-    if (tmap_is(map_x, map_y, TT_FROZEN )
-       ||
-       (tmap_is(map_x, map_y, TT_COLD ) &&
-        (myrand(10) > 7) &&
-        is_temperature_type_near(map_x, map_y, TT_FROZEN))) { 
-      map_set_terrain(map_x, map_y, T_ARCTIC);
-    }
-  } whole_map_iterate_end;
-}
-
-/*************************************************************************
- if separatepoles is set, return false if this tile has to keep ocean
-************************************************************************/
-static bool ok_for_separate_poles(int x, int y) 
-{
-  if (!map.separatepoles) {
-    return TRUE;
-  }
-  adjc_iterate(x, y, x1, y1) {
-    if (!is_ocean(map_get_terrain(x1, y1)) && 
-        map_get_continent(x1, y1 ) != 0) {
-      return FALSE;
-    }
-  } adjc_iterate_end;
-  return TRUE;
-}
-
-/****************************************************************************
-  Place untextured land at the poles.  This is used by generators 1 and 5.
-****************************************************************************/
-static void make_polar_land(void)
-{
-  assign_continent_numbers();
-  whole_map_iterate(map_x, map_y) {
-    if ((tmap_is(map_x, map_y, TT_FROZEN ) &&
-       ok_for_separate_poles(map_x, map_y))
-       ||
-       (tmap_is(map_x, map_y, TT_COLD ) &&
-        (myrand(10) > 7) &&
-        is_temperature_type_near(map_x, map_y, TT_FROZEN) &&
-        ok_for_separate_poles(map_x, map_y))) {
-       map_set_terrain(map_x, map_y, T_UNKNOWN);
-       map_set_continent(map_x, map_y, 0);
-    } 
-  } whole_map_iterate_end;
-}
-
-/**************************************************************************
-  Recursively generate terrains.
-**************************************************************************/
-static void place_terrain(int x, int y, int diff, 
-                           Terrain_type_id ter, int *to_be_placed,
-                          wetness_c        wc,
-                          temperature_type tc,
-                          miscellaneous_c  mc)
-{
+  index_to_map_pos(&x, &y, index);
   if (*to_be_placed <= 0) {
     return;
   }
-  assert(not_placed(x, y));
+  assert(map_not_placed(x, y));
   map_set_terrain(x, y, ter);
+  if (is_characteristic(index, CM_RIVER)) {
+    map_set_special(x, y, S_RIVER);
+  }
   map_set_placed(x, y);
   (*to_be_placed)--;
   
   cardinal_adjc_iterate(x, y, x1, y1) {
-    int Delta = abs(map_colatitude(x1, y1) - map_colatitude(x, y)) / L_UNIT
-       + abs(hmap(x1, y1) - (hmap(x, y))) /  H_UNIT;
-    if (not_placed(x1, y1) 
-       && tmap_is(x1, y1, tc) 
-       && test_wetness(x1, y1, wc)
-       && test_miscellaneous(x1, y1, mc)
+    int index1 = map_pos_to_index(x1, y1); 
+    int Delta = abs(colatitude(index1) - colatitude(index)) / L_UNIT
+       + abs(height_map[index1] - (height_map[index])) /  H_UNIT;
+    if (not_placed(index1) 
+       && is_characteristic(index1, tcm) 
+       && is_characteristic(index1, wcm)
+       && is_characteristic(index1, mcm)
+       && (is_characteristic(index1, CM_RIVER) 
+           ? terrain_has_flag(ter, TER_CAN_HAVE_RIVER) : TRUE)
        && Delta < diff 
        && myrand(10) > 4) {
-       place_terrain(x1, y1, diff - 1 - Delta, ter, to_be_placed, wc, tc, mc);
+       place_terrain(index1, diff - 1 - Delta, ter,
+                     to_be_placed, wcm, tcm, mcm);
     }
   } cardinal_adjc_iterate_end;
 }
@@ -350,12 +111,18 @@
   a simple function that adds plains grassland or tundra to the 
   current location.
 **************************************************************************/
-static void make_plain(int x, int y, int *to_be_placed )
+static void make_plain(int index, int *to_be_placed )
 {
+  int x, y;
+
+  index_to_map_pos(&x, &y, index);
   /* in cold place we get tundra instead */
-  if (tmap_is(x, y, TT_FROZEN)) {
+  if (!not_placed(index)) {
+    return;
+  }
+  if (is_characteristic(index, CM_FROZEN)) {
     map_set_terrain(x, y, T_ARCTIC); 
-  } else if (tmap_is(x, y, TT_COLD)) {
+  } else if (is_characteristic(index, CM_COLD)) {
     map_set_terrain(x, y, T_TUNDRA); 
   } else {
     if (myrand(100) > 50) {
@@ -364,6 +131,9 @@
       map_set_terrain(x, y, T_PLAINS);
     }
   }
+  if (is_characteristic(index, CM_RIVER)) {
+      map_set_special(x, y, S_RIVER);
+  }
   map_set_placed(x, y);
   (*to_be_placed)--;
 }
@@ -375,22 +145,23 @@
 static void make_plains(void)
 {
   int to_be_placed;
-  whole_map_iterate(x, y) {
-    if (not_placed(x, y)) {
+  whole_map_iterate_index(i) {
+    if (not_placed(i)) {
       to_be_placed = 1;
-      make_plain(x, y, &to_be_placed);
+      make_plain(i, &to_be_placed);
     }
-  } whole_map_iterate_end;
+  } whole_map_iterate_index_end;
 }
+
 /**************************************************************************
  This place randomly a cluster of terrains with some characteristics
  **************************************************************************/
 #define PLACE_ONE_TYPE(count, alternate, ter, wc, tc, mc, weight) \
   if((count) > 0) {                                       \
-    int x, y; \
+    int index; \
     /* Place some terrains */                             \
-    if (rand_map_pos_characteristic(&x, &y, (wc), (tc), (mc))) {  \
-      place_terrain(x, y, (weight), (ter), &(count), (wc),(tc), (mc));   \
+    if (rand_index_characteristic(&index, (wc), (tc), (mc))) {  \
+      place_terrain(index, (weight), (ter), &(count), (wc),(tc), (mc));   \
     } else {                                                             \
       /* If rand_map_pos_temperature returns FALSE we may as well stop*/ \
       /* looking for this time and go to alternate type. */              \
@@ -412,21 +183,44 @@
   int forests_count = 0;
   int jungles_count = 0;
   int deserts_count = 0;
-  int alt_deserts_count = 0;
   int plains_count = 0;
   int swamps_count = 0;
 
+  create_placed_map();
+
   whole_map_iterate(x, y) {
-    if (not_placed(x,y)) {
-     total++;
+    int index = map_pos_to_index(x, y);
+
+    if (is_characteristic(index, CM_OCEANIC)) {
+      map_set_placed(x, y);
+      map_set_terrain(x, y, T_OCEAN);
+    } else {
+      if (is_characteristic(index, CM_HILLY)) {
+       map_set_placed(x, y);
+       map_set_terrain(x, y, T_HILLS);
+      /* hack for terrains-set, where hills are too green */
+       if (is_characteristic(index, CM_FROZEN)) {
+         map_set_placed(x, y);
+         map_set_terrain(x, y, T_MOUNTAINS);
+       }
+      } else  if (is_characteristic(index, CM_ABRUPT)) {
+       map_set_placed(x, y);
+       map_set_terrain(x, y, T_MOUNTAINS);
+      } 
     }
   } whole_map_iterate_end;
 
+  whole_map_iterate_index(i) {
+    if (not_placed(i)) {
+     total++;
+    }
+  } whole_map_iterate_index_end;
+
   forests_count = total * forest_pct / (100 - mountain_pct);
   jungles_count = total * jungle_pct / (100 - mountain_pct);
  
   deserts_count = total * desert_pct / (100 - mountain_pct); 
-  swamps_count = total * swamp_pct  / (100 - mountain_pct);
+  swamps_count =   total * swamp_pct  / (100 - mountain_pct);
 
   /* grassland, tundra,arctic and plains is counted in plains_count */
   plains_count = total - forests_count - deserts_count
@@ -436,23 +230,22 @@
   do {
     
     PLACE_ONE_TYPE(forests_count , plains_count, T_FOREST,
-                  WC_ALL, TT_NFROZEN, MC_NONE, 60);
+                  CM_NDRY, CM_NFROZEN, CM_FLAT, 60);
     PLACE_ONE_TYPE(jungles_count, forests_count , T_JUNGLE,
-                  WC_ALL, TT_TROPICAL, MC_NONE, 50);
+                  CM_NDRY, CM_TROPICAL, CM_FLAT, 50);
     PLACE_ONE_TYPE(swamps_count, forests_count , T_SWAMP,
-                  WC_NDRY, TT_HOT, MC_LOW, 50);
-    PLACE_ONE_TYPE(deserts_count, alt_deserts_count , T_DESERT,
-                  WC_DRY, TT_NFROZEN, MC_NLOW, 80);
-    PLACE_ONE_TYPE(alt_deserts_count, plains_count , T_DESERT,
-                  WC_ALL, TT_NFROZEN, MC_NLOW, 40);
+                  CM_WET, CM_HOT, CM_FLAT, 30);
+    PLACE_ONE_TYPE(deserts_count, plains_count , T_DESERT,
+                  CM_DRY, CM_HOT, CM_FLAT, 80);
+   
  
   /* make the plains and tundras */
     if (plains_count > 0) {
-      int x, y;
+      int index;
 
       /* Don't use any restriction here ! */
-      if (rand_map_pos_characteristic(&x, &y,  WC_ALL, TT_ALL, MC_NONE)){
-       make_plain(x,y, &plains_count);
+      if (rand_index_characteristic(&index,  CM_ALL, CM_ALL, CM_ALL)){
+       make_plain(index, &plains_count);
       } else {
        /* If rand_map_pos_temperature returns FALSE we may as well stop
         * looking for plains. */
@@ -460,493 +253,10 @@
       }
     }
   } while (forests_count > 0 || jungles_count > 0 
-          || deserts_count > 0 || alt_deserts_count > 0 
+          || deserts_count > 0
           || plains_count > 0 || swamps_count > 0 );
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_blocked(int x, int y)
-{
-  if (TEST_BIT(rmap(x, y), RS_BLOCKED))
-    return 1;
-
-  /* any un-blocked? */
-  cardinal_adjc_iterate(x, y, x1, y1) {
-    if (!TEST_BIT(rmap(x1, y1), RS_BLOCKED))
-      return 0;
-  } cardinal_adjc_iterate_end;
-
-  return 1; /* none non-blocked |- all blocked */
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_rivergrid(int x, int y)
-{
-  return (count_special_near_tile(x, y, TRUE, FALSE, S_RIVER) > 1) ? 1 : 0;
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_highlands(int x, int y)
-{
-  return (((map_get_terrain(x, y) == T_HILLS) ? 1 : 0) +
-         ((map_get_terrain(x, y) == T_MOUNTAINS) ? 2 : 0));
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_ocean(int x, int y)
-{
-  return 100 - count_ocean_near_tile(x, y, TRUE, TRUE);
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_river(int x, int y)
-{
-  return 100 - count_special_near_tile(x, y, TRUE, TRUE, S_RIVER);
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_highlands(int x, int y)
-{
-  return (count_terrain_near_tile(x, y, TRUE, TRUE, T_HILLS)
-         + 2 * count_terrain_near_tile(x, y, TRUE, TRUE, T_MOUNTAINS));
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_swamp(int x, int y)
-{
-  return (map_get_terrain(x, y) != T_SWAMP) ? 1 : 0;
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_adjacent_swamp(int x, int y)
-{
-  return 100 - count_terrain_near_tile(x, y, TRUE, TRUE, T_SWAMP);
-}
-
-/*********************************************************************
- Help function used in make_river(). See the help there.
-*********************************************************************/
-static int river_test_height_map(int x, int y)
-{
-  return hmap(x, y);
-}
 
-/*********************************************************************
- Called from make_river. Marks all directions as blocked.  -Erik Sigra
-*********************************************************************/
-static void river_blockmark(int x, int y)
-{
-  freelog(LOG_DEBUG, "Blockmarking (%d, %d) and adjacent tiles.",
-         x, y);
-
-  rmap(x, y) |= (1u << RS_BLOCKED);
-
-  cardinal_adjc_iterate(x, y, x1, y1) {
-    rmap(x1, y1) |= (1u << RS_BLOCKED);
-  } cardinal_adjc_iterate_end;
-}
-
-struct test_func {
-  int (*func)(int, int);
-  bool fatal;
-};
-
-#define NUM_TEST_FUNCTIONS 9
-static struct test_func test_funcs[NUM_TEST_FUNCTIONS] = {
-  {river_test_blocked,            TRUE},
-  {river_test_rivergrid,          TRUE},
-  {river_test_highlands,          FALSE},
-  {river_test_adjacent_ocean,     FALSE},
-  {river_test_adjacent_river,     FALSE},
-  {river_test_adjacent_highlands, FALSE},
-  {river_test_swamp,              FALSE},
-  {river_test_adjacent_swamp,     FALSE},
-  {river_test_height_map,         FALSE}
-};
-
-/********************************************************************
- Makes a river starting at (x, y). Returns 1 if it succeeds.
- Return 0 if it fails. The river is stored in river_map.
- 
- How to make a river path look natural
- =====================================
- Rivers always flow down. Thus rivers are best implemented on maps
- where every tile has an explicit height value. However, Freeciv has a
- flat map. But there are certain things that help the user imagine
- differences in height between tiles. The selection of direction for
- rivers should confirm and even amplify the user's image of the map's
- topology.
- 
- To decide which direction the river takes, the possible directions
- are tested in a series of test until there is only 1 direction
- left. Some tests are fatal. This means that they can sort away all
- remaining directions. If they do so, the river is aborted. Here
- follows a description of the test series.
- 
- * Falling into itself: fatal
-     (river_test_blocked)
-     This is tested by looking up in the river_map array if a tile or
-     every tile surrounding the tile is marked as blocked. A tile is
-     marked as blocked if it belongs to the current river or has been
-     evaluated in a previous iteration in the creation of the current
-     river.
-     
-     Possible values:
-     0: Is not falling into itself.
-     1: Is falling into itself.
-     
- * Forming a 4-river-grid: optionally fatal
-     (river_test_rivergrid)
-     A minimal 4-river-grid is formed when an intersection in the map
-     grid is surrounded by 4 river tiles. There can be larger river
-     grids consisting of several overlapping minimal 4-river-grids.
-     
-     Possible values:
-     0: Is not forming a 4-river-grid.
-     1: Is forming a 4-river-grid.
-
- * Highlands:
-     (river_test_highlands)
-     Rivers must not flow up in mountains or hills if there are
-     alternatives.
-     
-     Possible values:
-     0: Is not hills and not mountains.
-     1: Is hills.
-     2: Is mountains.
-
- * Adjacent ocean:
-     (river_test_adjacent_ocean)
-     Rivers must flow down to coastal areas when possible:
-
-     Possible values: 0-100
-
- * Adjacent river:
-     (river_test_adjacent_river)
-     Rivers must flow down to areas near other rivers when possible:
-
-     Possible values: 0-100
-                                       
- * Adjacent highlands:
-     (river_test_adjacent_highlands)
-     Rivers must not flow towards highlands if there are alternatives. 
-     
- * Swamps:
-     (river_test_swamp)
-     Rivers must flow down in swamps when possible.
-     
-     Possible values:
-     0: Is swamps.
-     1: Is not swamps.
-     
- * Adjacent swamps:
-     (river_test_adjacent_swamp)
-     Rivers must flow towards swamps when possible.
-
- * height_map:
-     (river_test_height_map)
-     Rivers must flow in the direction which takes it to the tile with
-     the lowest value on the height_map.
-     
-     Possible values:
-     n: height_map[...]
-     
- If these rules haven't decided the direction, the random number
- generator gets the desicion.                              -Erik Sigra
-*********************************************************************/
-static bool make_river(int x, int y)
-{
-  /* Comparison value for each tile surrounding the current tile.  It is
-   * the suitability to continue a river to the tile in that direction;
-   * lower is better.  However rivers may only run in cardinal directions;
-   * the other directions are ignored entirely. */
-  int rd_comparison_val[8];
-
-  bool rd_direction_is_valid[8];
-  int num_valid_directions, func_num, direction;
-
-  while (TRUE) {
-    /* Mark the current tile as river. */
-    rmap(x, y) |= (1u << RS_RIVER);
-    freelog(LOG_DEBUG,
-           "The tile at (%d, %d) has been marked as river in river_map.\n",
-           x, y);
-
-    /* Test if the river is done. */
-    /* We arbitrarily make rivers end at the poles. */
-    if (count_special_near_tile(x, y, TRUE, TRUE, S_RIVER) > 0
-       || count_ocean_near_tile(x, y, TRUE, TRUE) > 0
-        || (map_get_terrain(x, y) == T_ARCTIC 
-           && map_colatitude(x, y) < 0.8 * COLD_LEVEL)) { 
-
-      freelog(LOG_DEBUG,
-             "The river ended at (%d, %d).\n", x, y);
-      return TRUE;
-    }
-
-    /* Else choose a direction to continue the river. */
-    freelog(LOG_DEBUG,
-           "The river did not end at (%d, %d). Evaluating directions...\n",
-           x, y);
-
-    /* Mark all available cardinal directions as available. */
-    memset(rd_direction_is_valid, 0, sizeof(rd_direction_is_valid));
-    cardinal_adjc_dir_iterate(x, y, x1, y1, dir) {
-      rd_direction_is_valid[dir] = TRUE;
-    } cardinal_adjc_dir_iterate_end;
-
-    /* Test series that selects a direction for the river. */
-    for (func_num = 0; func_num < NUM_TEST_FUNCTIONS; func_num++) {
-      int best_val = -1;
-
-      /* first get the tile values for the function */
-      cardinal_adjc_dir_iterate(x, y, x1, y1, dir) {
-       if (rd_direction_is_valid[dir]) {
-         rd_comparison_val[dir] = (test_funcs[func_num].func) (x1, y1);
-         if (best_val == -1) {
-           best_val = rd_comparison_val[dir];
-         } else {
-           best_val = MIN(rd_comparison_val[dir], best_val);
-         }
-       }
-      } cardinal_adjc_dir_iterate_end;
-      assert(best_val != -1);
-
-      /* should we abort? */
-      if (best_val > 0 && test_funcs[func_num].fatal) {
-       return FALSE;
-      }
-
-      /* mark the less attractive directions as invalid */
-      cardinal_adjc_dir_iterate(x, y, x1, y1, dir) {
-       if (rd_direction_is_valid[dir]) {
-         if (rd_comparison_val[dir] != best_val) {
-           rd_direction_is_valid[dir] = FALSE;
-         }
-       }
-      } cardinal_adjc_dir_iterate_end;
-    }
-
-    /* Directions evaluated with all functions. Now choose the best
-       direction before going to the next iteration of the while loop */
-    num_valid_directions = 0;
-    cardinal_adjc_dir_iterate(x, y, x1, y1, dir) {
-      if (rd_direction_is_valid[dir]) {
-       num_valid_directions++;
-      }
-    } cardinal_adjc_dir_iterate_end;
-
-    if (num_valid_directions == 0) {
-      return FALSE; /* river aborted */
-    }
-
-    /* One or more valid directions: choose randomly. */
-    freelog(LOG_DEBUG, "mapgen.c: Had to let the random number"
-           " generator select a direction for a river.");
-    direction = myrand(num_valid_directions);
-    freelog(LOG_DEBUG, "mapgen.c: direction: %d", direction);
-
-    /* Find the direction that the random number generator selected. */
-    cardinal_adjc_dir_iterate(x, y, x1, y1, dir) {
-      if (rd_direction_is_valid[dir]) {
-       if (direction > 0) {
-         direction--;
-       } else {
-         river_blockmark(x, y);
-         x = x1;
-         y = y1;
-         break;
-       }
-      }
-    } cardinal_adjc_dir_iterate_end;
-    assert(direction == 0);
-
-  } /* end while; (Make a river.) */
-}
-
-/**************************************************************************
-  Calls make_river until there are enough river tiles on the map. It stops
-  when it has tried to create RIVERS_MAXTRIES rivers.           -Erik Sigra
-**************************************************************************/
-static void make_rivers(void)
-{
-  int x, y; /* The coordinates. */
-
-  /* Formula to make the river density similar om different sized maps. Avoids
-     too few rivers on large maps and too many rivers on small maps. */
-  int desirable_riverlength =
-    river_pct *
-      /* The size of the map (poles counted in river_pct). */
-      map_num_tiles() *
-      /* Rivers need to be on land only. */
-      map.landpercent /
-      /* Adjustment value. Tested by me. Gives no rivers with 'set
-        rivers 0', gives a reasonable amount of rivers with default
-        settings and as many rivers as possible with 'set rivers 100'. */
-      5325;
-
-  /* The number of river tiles that have been set. */
-  int current_riverlength = 0;
-
-  int i; /* Loop variable. */
-
-  /* Counts the number of iterations (should increase with 1 during
-     every iteration of the main loop in this function).
-     Is needed to stop a potentially infinite loop. */
-  int iteration_counter = 0;
-
-  create_placed_map(); /* needed bu rand_map_characteristic */
-  set_all_ocean_tiles_placed();
-
-  river_map = fc_malloc(sizeof(int) * MAX_MAP_INDEX);
-
-  /* The main loop in this function. */
-  while (current_riverlength < desirable_riverlength
-        && iteration_counter < RIVERS_MAXTRIES) {
-
-    if (!rand_map_pos_characteristic(&x, &y, 
-                                     WC_ALL, TT_NFROZEN, MC_NLOW)) {
-       break; /* mo more spring places */
-    }
-
-    /* Check if it is suitable to start a river on the current tile.
-     */
-    if (
-       /* Don't start a river on ocean. */
-       !is_ocean(map_get_terrain(x, y))
-
-       /* Don't start a river on river. */
-       && !map_has_special(x, y, S_RIVER)
-
-       /* Don't start a river on a tile is surrounded by > 1 river +
-          ocean tile. */
-       && (count_special_near_tile(x, y, TRUE, FALSE, S_RIVER)
-           + count_ocean_near_tile(x, y, TRUE, FALSE) <= 1)
-
-       /* Don't start a river on a tile that is surrounded by hills or
-          mountains unless it is hard to find somewhere else to start
-          it. */
-       && (count_terrain_near_tile(x, y, TRUE, TRUE, T_HILLS)
-           + count_terrain_near_tile(x, y, TRUE, TRUE, T_MOUNTAINS) < 90
-           || iteration_counter == RIVERS_MAXTRIES / 10 * 5)
-
-       /* Don't start a river on hills unless it is hard to find
-          somewhere else to start it. */
-       && (map_get_terrain(x, y) != T_HILLS
-           || iteration_counter == RIVERS_MAXTRIES / 10 * 6)
-
-       /* Don't start a river on mountains unless it is hard to find
-          somewhere else to start it. */
-       && (map_get_terrain(x, y) != T_MOUNTAINS
-           || iteration_counter == RIVERS_MAXTRIES / 10 * 7)
-
-       /* Don't start a river on arctic unless it is hard to find
-          somewhere else to start it. */
-       && (map_get_terrain(x, y) != T_ARCTIC
-           || iteration_counter == RIVERS_MAXTRIES / 10 * 8)
-
-       /* Don't start a river on desert unless it is hard to find
-          somewhere else to start it. */
-       && (map_get_terrain(x, y) != T_DESERT
-           || iteration_counter == RIVERS_MAXTRIES / 10 * 9)) {
-
-      /* Reset river_map before making a new river. */
-      for (i = 0; i < map.xsize * map.ysize; i++) {
-       river_map[i] = 0;
-      }
-
-      freelog(LOG_DEBUG,
-             "Found a suitable starting tile for a river at (%d, %d)."
-             " Starting to make it.",
-             x, y);
-
-      /* Try to make a river. If it is OK, apply it to the map. */
-      if (make_river(x, y)) {
-       whole_map_iterate(x1, y1) {
-         if (TEST_BIT(rmap(x1, y1), RS_RIVER)) {
-           Terrain_type_id t = map_get_terrain(x1, y1);
-
-           if (!terrain_has_flag(t, TER_CAN_HAVE_RIVER)) {
-             /* We have to change the terrain to put a river here. */
-             t = get_flag_terrain(TER_CAN_HAVE_RIVER);
-             map_set_terrain(x1, y1, t);
-           }
-           map_set_special(x1, y1, S_RIVER);
-           current_riverlength++;
-           map_set_placed(x1, y1);
-           freelog(LOG_DEBUG, "Applied a river to (%d, %d).", x1, y1);
-         }
-       } whole_map_iterate_end;
-      }
-      else {
-       freelog(LOG_DEBUG,
-               "mapgen.c: A river failed. It might have gotten stuck in a 
helix.");
-      }
-    } /* end if; */
-    iteration_counter++;
-    freelog(LOG_DEBUG,
-           "current_riverlength: %d; desirable_riverlength: %d; 
iteration_counter: %d",
-           current_riverlength, desirable_riverlength, iteration_counter);
-  } /* end while; */
-  free(river_map);
-  destroy_placed_map();
-  river_map = NULL;
-}
-
-/**************************************************************************
-  make land simply does it all based on a generated heightmap
-  1) with map.landpercent it generates a ocean/grassland map 
-  2) it then calls the above functions to generate the different terrains
-**************************************************************************/
-static void make_land(void)
-{
-  
-  if (HAS_POLES) {
-    normalize_hmap_poles();
-  }
-  hmap_shore_level = (hmap_max_level * (100 - map.landpercent)) / 100;
-  ini_hmap_low_level();
-  whole_map_iterate(x, y) {
-    map_set_terrain(x, y, T_UNKNOWN); /* set as oceans count is used */
-    if (hmap(x, y) < hmap_shore_level) {
-      map_set_terrain(x, y, T_OCEAN);
-    }
-  } whole_map_iterate_end;
-  if (HAS_POLES) {
-    renormalize_hmap_poles();
-  } 
-
-  create_tmap(TRUE); /* base temperature map, need hmap and oceans */
-  
-  if (HAS_POLES) { /* this is a hack to terrains set with not frizzed oceans*/
-    make_polar_land(); /* make extra land at poles*/
-  }
-
-  create_placed_map(); /* here it means land terrains to be placed */
-  set_all_ocean_tiles_placed();
-  make_relief(); /* base relief on map */
-  make_terrains(); /* place all exept mountains and hill */
   destroy_placed_map();
-
-  make_rivers(); /* use a new placed_map. destroy older before call */
-
-  assign_continent_numbers();
 }
 
 /**************************************************************************
@@ -986,6 +296,32 @@
 }
 
 /**************************************************************************
+ Convert parameters from the server into terrains percents parameters for
+ the generators, this is primary used has a hack for gen 2-4
+**************************************************************************/
+static void adjust_terrain_param(void)
+{
+  int polar = 2 * ICE_BASE_LEVEL * map.landpercent / MAX_COLATITUDE ;
+  float factor = (100.0 - polar - map.steepness * 0.8 ) / 10000;
+
+
+  mountain_pct = factor * map.steepness * 90;
+
+  /* 40 % if wetness == 50 & */
+  forest_pct = factor * (map.wetness * 60 + 1000) ; 
+  jungle_pct = forest_pct * (MAX_COLATITUDE - TROPICAL_LEVEL) /
+               (MAX_COLATITUDE * 2);
+  forest_pct -= jungle_pct;
+
+  /* 3 - 11 % */
+  river_pct = (100 - polar) * (3 + map.wetness / 12) / 100;
+
+  /* 6 %  if wetness == 50 && temperature == 50 */
+  swamp_pct = factor * (map.wetness * 6 + map.temperature * 6);
+  desert_pct = factor * (map.temperature * 10 + (100 - map.wetness) * 10) ;
+}
+
+/**************************************************************************
   See stdinhand.c for information on map generation methods.
 
 FIXME: Some continent numbers are unused at the end of this function, fx
@@ -1032,23 +368,45 @@
       make_random_hmap(1 + SQSIZE);
     }
 
-    /* if hmap only generator make anything else */
-    if (map.generator == 1 || map.generator == 5) {
-      make_land();
+    /* 
+     *   if height_map only generator make anything else 
+     */
+    if ((map.generator == 1) || (map.generator == 5)) {
+    
+     /************************************************************
+      * 2d step, Initialize generalized terrains characteristics *
+      ************************************************************/
+      create_characteristics(TRUE);
+     
+      /****************************
+       * 3th step, place terrians *
+       ****************************/
+      make_terrains(); /* and rivers */
+      
+      assign_continent_numbers();
+
       free(height_map);
       height_map = NULL;
     }
+    /*
+     * some old option
+     */
     if (!map.tinyisles) {
       remove_tiny_islands();
     }
+
   } else {
     assign_continent_numbers();
   }
-
-  if (!temperature_is_initialized()) {
-    create_tmap(FALSE);
-  }
-  
+  /*
+   * 4 Place specials and huts
+   */
+
+  /* initialize needed characteristics if not yet done, */
+  if (!characteristics_are_initialized()) {
+      create_characteristics(FALSE); 
+  } 
+ 
   /* some scenarios already provide specials */
   if (!map.have_specials) {
     add_specials(map.riches);
@@ -1058,35 +416,9 @@
     make_huts(map.huts); 
   }
 
+  destroy_characteristics();
   /* restore previous random state: */
   set_myrand_state(rstate);
-  destroy_tmap();
-}
-
-/**************************************************************************
- Convert parameters from the server into terrains percents parameters for
- the generators
-**************************************************************************/
-static void adjust_terrain_param(void)
-{
-  int polar = 2 * ICE_BASE_LEVEL * map.landpercent / MAX_COLATITUDE ;
-  float factor = (100.0 - polar - map.steepness * 0.8 ) / 10000;
-
-
-  mountain_pct = factor * map.steepness * 90;
-
-  /* 40 % if wetness == 50 & */
-  forest_pct = factor * (map.wetness * 60 + 1000) ; 
-  jungle_pct = forest_pct * (MAX_COLATITUDE - TROPICAL_LEVEL) /
-               (MAX_COLATITUDE * 2);
-  forest_pct -= jungle_pct;
-
-  /* 3 - 11 % */
-  river_pct = (100 - polar) * (3 + map.wetness / 12) / 100;
-
-  /* 6 %  if wetness == 50 && temperature == 50 */
-  swamp_pct = factor * (map.wetness * 6 + map.temperature * 6);
-  desert_pct = factor * (map.temperature * 10 + (100 - map.wetness) * 10) ;
 }
 
 /****************************************************************************
@@ -1110,7 +442,7 @@
 **************************************************************************/
 static void make_huts(int number)
 {
-  int x, y, count = 0;
+  int x, y, index, count = 0;
 
   create_placed_map(); /* here it means placed huts */
 
@@ -1118,7 +450,8 @@
 
     /* Add a hut.  But not on a polar area, on an ocean, or too close to
      * another hut. */
-    if (rand_map_pos_characteristic(&x, &y, WC_ALL, TT_NFROZEN, MC_NONE)) {
+    if (rand_index_characteristic(&index, CM_ALL, CM_NFROZEN, CM_ALL)) {
+      index_to_map_pos(&x, &y, index);
       if (is_ocean(map_get_terrain(x, y))) {
        map_set_placed(x, y); /* not good for a hut */
       } else {
@@ -1184,6 +517,20 @@
   map.have_specials = TRUE;
 }
 
+/****************************************************************************
+  Add arctic and tundra squares in the arctic zone (that is, the coolest
+  10% of the map).  We also texture the pole (adding arctic, tundra, and
+  mountains).  This is used in generators 2-4.
+****************************************************************************/
+static void make_polar(void)
+{
+  whole_map_iterate(x, y) {  
+  if (is_characteristic(map_pos_to_index(x, y), CM_FROZEN )) { 
+      map_set_terrain(x, y, T_ARCTIC);
+    }
+  } whole_map_iterate_end;
+}
+
 /**************************************************************************
   common variables for generator 2, 3 and 4
 **************************************************************************/
@@ -1249,7 +596,7 @@
     get_random_map_position_from_state(&x, &y, pstate);
 
     if (map_get_continent(x, y) == pstate->isleindex &&
-       not_placed(x, y)) {
+       map_not_placed(x, y)) {
 
       /* the first condition helps make terrain more contiguous,
         the second lets it avoid the coast: */
@@ -1273,7 +620,7 @@
          map_set_placed(x, y);
        }
       }
-      if (!not_placed(x,y)) i--;
+      if (!map_not_placed(x,y)) i--;
     }
   }
 }
@@ -1304,7 +651,7 @@
   while (i > 0 && (failsafe--) > 0) {
     get_random_map_position_from_state(&x, &y, pstate);
     if (map_get_continent(x, y) == pstate->isleindex
-       && not_placed(x, y)) {
+       && map_not_placed(x, y)) {
 
       /* the first condition helps make terrain more contiguous,
         the second lets it avoid the coast: */
@@ -1632,7 +979,7 @@
   height_map = fc_malloc(sizeof(int) * map.ysize * map.xsize);
   islands = fc_malloc((MAP_NCONT+1)*sizeof(struct isledata));
   create_placed_map(); /* land tiles which aren't placed yet */
-  create_tmap(FALSE);
+  create_characteristics(FALSE);
   
   whole_map_iterate(x, y) {
     map_set_terrain(x, y, T_OCEAN);
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/mapgen_topology.c 
freeciv_/server/generator/mapgen_topology.c
--- freeciv/server/generator/mapgen_topology.c  2004-09-17 11:14:01.000000000 
+0200
+++ freeciv_/server/generator/mapgen_topology.c 2004-09-23 23:09:20.000000000 
+0200
@@ -29,6 +29,14 @@
   functions instead (x,y) coordinate to place terrains
   colatitude is 0 at poles and MAX_COLATITUDE at equator
 ****************************************************************************/
+int colatitude (int index)
+{
+    int x, y;
+ 
+    index_to_map_pos( &x, &y, index);
+    return map_colatitude(x, y);
+}
+
 int map_colatitude(int map_x, int map_y)
 {
   double x, y;
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/mapgen_topology.h 
freeciv_/server/generator/mapgen_topology.h
--- freeciv/server/generator/mapgen_topology.h  2004-09-16 11:53:11.000000000 
+0200
+++ freeciv_/server/generator/mapgen_topology.h 2004-09-23 23:09:20.000000000 
+0200
@@ -45,6 +45,9 @@
 extern int ice_base_colatitude;
 #define ICE_BASE_LEVEL ice_base_colatitude
 
+#define HAS_POLES (map.temperature < 70 && !map.alltemperate)
+
+int colatitude (int index);
 int map_colatitude(int map_x, int map_y);
 bool near_singularity(int map_x, int map_y);
 void generator_init_topology(bool autosize);
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/utilities.c 
freeciv_/server/generator/utilities.c
--- freeciv/server/generator/utilities.c        2004-09-22 08:39:29.000000000 
+0200
+++ freeciv_/server/generator/utilities.c       2004-09-23 23:09:20.000000000 
+0200
@@ -57,11 +57,16 @@
 #define pmap(x, y) (placed_map[map_pos_to_index(x, y)])
 
 /* Checks if land has not yet been placed on pmap at (x, y) */
-bool not_placed(int x, int y)
+bool map_not_placed(int x, int y)
 {
   return !pmap((x), (y));
 }
 
+bool not_placed(int index)
+{
+  return !placed_map[index];
+}
+
 /* set has placed or not placed position in the pmap */
 void map_set_placed(int x, int y)
 {
@@ -137,6 +142,7 @@
     } whole_map_iterate_index_end;
   }
 }
+
 bool normalize_nat_pos(int *x, int  *y) 
 {
     int map_x, map_y;
diff -ruN -Xfreeciv/diff_ignore freeciv/server/generator/utilities.h 
freeciv_/server/generator/utilities.h
--- freeciv/server/generator/utilities.h        2004-09-22 08:39:29.000000000 
+0200
+++ freeciv_/server/generator/utilities.h       2004-09-23 23:09:20.000000000 
+0200
@@ -81,11 +81,13 @@
 void destroy_placed_map(void);
 void map_set_placed(int x, int y);
 void map_unset_placed(int x, int y);
-bool not_placed(int x, int y);
+bool map_not_placed(int x, int y);
+bool not_placed(int index);
 bool placed_map_is_initialized(void);
 void set_all_ocean_tiles_placed(void) ;
 void set_placed_near_pos(int map_x, int map_y, int dist);
 
 
 
+
 #endif  /* FC__UTILITIES_H */

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