Complete.Org: Mailing Lists: Archives: freeciv-dev: April 2005:
[Freeciv-Dev] Re: (PR#9787) RFC: generalized terrain
Home

[Freeciv-Dev] Re: (PR#9787) RFC: generalized terrain

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: mburda@xxxxxxxxx
Subject: [Freeciv-Dev] Re: (PR#9787) RFC: generalized terrain
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 24 Apr 2005 11:44:43 -0700
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=9787 >

Jason Short wrote:
> <URL: http://bugs.freeciv.org/Ticket/Display.html?id=9787 >
> 
> Currently gen-terrain is complete except for the mapgen bits.
> 
> This patch attempts to complete gen-terrain.  Rather than mess too much
> with the logic of mapgen I tried to assign "properties" to each terrain
> type that correspond to the logic mapgen already follows.  mapgen then
> chooses a terrain based on its internal calculations and the properties
> each terrain type has.
> 
> This patch is workable but not ready to be committed.
> 
> 1.  It doesn't place very much swamp.
> 2.  It puts jungle near the poles.
> 3.  The rest is probably just as good as what we have now...
> 
> Also one missing feature is placement of ocean based on depth (needed to
> have multiple types of ocean terrain).

And, here's a new patch.

1.  I fixed a bug causing swamp and jungle placement to overlap. This
caused jungles to be placed instead of swamps, causing both errors above.

2.  I added an ocean_depth parameter.  With multiple ocean types the
ocean chosen will be the one with the closest-matching depth.  With this
you can have civ3-like ocean terrains, for instance see
http://freeciv.org/~jdorje/ocean.png (in this screenshot I just hacked
trident to show the deep terrains a little differently, so it's not very
pretty).  Note this feature doesn't work with gen3 since it has no ocean
depths (in this case we probably want to choose the depth solely based
on distance from land).

I think it's in a workable form now.  I haven't gone over it closely though.

-jason

Index: common/terrain.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/terrain.c,v
retrieving revision 1.19
diff -u -r1.19 terrain.c
--- common/terrain.c    23 Apr 2005 17:40:27 -0000      1.19
+++ common/terrain.c    24 Apr 2005 18:41:19 -0000
@@ -192,6 +192,28 @@
   return count;
 }
 
+/****************************************************************************
+  Return the number of adjacent tiles that have the given terrain property.
+****************************************************************************/
+int count_terrain_property_near_tile(const struct tile *ptile,
+                                    bool cardinal_only, bool percentage,
+                                    enum mapgen_terrain_property prop)
+{
+  int count = 0, total = 0;
+
+  variable_adjc_iterate(ptile, adjc_tile, cardinal_only) {
+    if (get_tile_type(adjc_tile->terrain)->property[prop] > 0) {
+      count++;
+    }
+    total++;
+  } variable_adjc_iterate_end;
+
+  if (percentage) {
+    count = count * 100 / total;
+  }
+  return count;
+}
+
 /* Names of specials.
  * (These must correspond to enum tile_special_type.)
  */
Index: common/terrain.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/terrain.h,v
retrieving revision 1.31
diff -u -r1.31 terrain.h
--- common/terrain.h    19 Apr 2005 17:07:14 -0000      1.31
+++ common/terrain.h    24 Apr 2005 18:41:19 -0000
@@ -96,6 +96,24 @@
 
 BV_DEFINE(bv_terrain_flags, TER_MAX);
 
+enum mapgen_terrain_property {
+  MG_MOUNTAINOUS,
+  MG_GREEN,
+  MG_FOLIAGE,
+
+  MG_TROPICAL,
+  MG_TEMPERATE,
+  MG_COLD,
+  MG_FROZEN,
+
+  MG_WET,
+  MG_DRY,
+
+  MG_OCEAN_DEPTH,
+
+  MG_LAST
+};
+
 /*
  * This struct gives data about each terrain type.  There are many ways
  * it could be extended.
@@ -146,6 +164,15 @@
   Terrain_type_id warmer_wetter_result, warmer_drier_result;
   Terrain_type_id cooler_wetter_result, cooler_drier_result;
 
+  /* These are special properties of the terrain used by mapgen.  Generally
+   * for each property, if a tile is deemed to have that property then
+   * the value gives the wieghted amount of tiles that will be assigned
+   * this terrain.
+   *
+   * For instance if mountains have 70 and hills have 30 of MG_MOUNTAINOUS
+   * then 70% of 'mountainous' tiles will be given mountains. */
+  int property[MG_LAST];
+
   bv_terrain_flags flags;
 
   char *helptext;
@@ -167,6 +194,9 @@
 int count_terrain_near_tile(const struct tile *ptile,
                            bool cardinal_only, bool percentage,
                            Terrain_type_id t);
+int count_terrain_property_near_tile(const struct tile *ptile,
+                                    bool cardinal_only, bool percentage,
+                                    enum mapgen_terrain_property prop);
 
 /* General special accessor functions. */
 enum tile_special_type get_special_by_name(const char * name);
Index: data/civ1/terrain.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/civ1/terrain.ruleset,v
retrieving revision 1.31
diff -u -r1.31 terrain.ruleset
--- data/civ1/terrain.ruleset   8 Nov 2004 15:15:53 -0000       1.31
+++ data/civ1/terrain.ruleset   24 Apr 2005 18:41:19 -0000
@@ -201,6 +201,7 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "NoBarbs"
+property_frozen      = 100
 helptext            = _("\
 Arctic squares are found only in the most northerly or southerly\
  reaches of the world.  They are very cold, and hence difficult to\
@@ -243,6 +244,8 @@
 warmer_drier_result  = "no"
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
+property_dry         = 100
+property_tropical    = 50
 helptext            = _("\
 Deserts are regions of extreme dryness, making agriculture and\
  trade very difficult.\
@@ -285,6 +288,8 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "Starter"
+property_temperate   = 50
+property_foliage     = 50
 helptext            = _("\
 Forests are densely wooded, making agriculture somewhat\
  problematic.\
@@ -327,6 +332,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "Starter", "CanHaveRiver"
+property_temperate   = 50
+property_green       = 50
 helptext            = _("\
 Grasslands afford exceptional agricultural opportunities.\
 ")
@@ -368,6 +375,8 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "Starter"
+property_mountainous = 30
+property_green       = 10
 helptext            = _("\
 In addition to being amenable to agriculture, Hills are frequently\
  rich in resources.\
@@ -409,6 +418,8 @@
 warmer_drier_result  = "no"
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
+property_tropical    = 50
+property_foliage     = 50
 helptext            = _("\
 Jungles are densely overgrown, making agriculture somewhat\
  problematic.\
@@ -450,6 +461,7 @@
 warmer_drier_result  = "no"
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
+property_mountainous = 70
 helptext            = _("\
 Mountains are regions of extreme altitude, making agriculture and\
  trade very difficult.\
@@ -536,6 +548,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "Starter"
+property_temperate   = 50
+property_green       = 50
 helptext            = _("\
 Plains are very broad, sparse regions, which makes trade slightly\
  inconvenient.\
@@ -577,6 +591,8 @@
 warmer_drier_result  = "no"
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
+property_wet         = 100
+property_foliage     = 10
 helptext            = _("\
 Swamps suffer from an over-abundance of water, making agriculture\
  somewhat problematic.\
@@ -619,6 +635,7 @@
 cooler_wetter_result = "Arctic"
 cooler_drier_result  = "Arctic"
 flags                = "Starter", "NoBarbs"
+property_cold        = 50
 helptext            = _("\
 Tundra are broad, cold regions, fit for some agriculture and little\
  else.\
Index: data/civ2/terrain.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/civ2/terrain.ruleset,v
retrieving revision 1.33
diff -u -r1.33 terrain.ruleset
--- data/civ2/terrain.ruleset   8 Nov 2004 15:15:53 -0000       1.33
+++ data/civ2/terrain.ruleset   24 Apr 2005 18:41:19 -0000
@@ -209,6 +209,7 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "NoBarbs", "CanHaveRiver"
+property_frozen      = 100
 helptext            = _("\
 Glaciers are found only in the most northerly or southerly\
  reaches of the world.  They are very cold, and hence difficult to\
@@ -252,6 +253,8 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "CanHaveRiver"
+property_dry         = 100
+property_tropical    = 50
 helptext            = _("\
 Deserts are regions of extreme dryness, making agriculture and\
  trade very difficult.\
@@ -294,6 +297,8 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "Starter", "CanHaveRiver"
+property_temperate   = 50
+property_foliage     = 50
 helptext            = _("\
 Forests are densely wooded, making agriculture somewhat\
  problematic.\
@@ -336,6 +341,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "Starter", "CanHaveRiver"
+property_temperate   = 50
+property_green       = 50
 helptext            = _("\
 Grasslands afford exceptional agricultural opportunities.\
 ")
@@ -377,6 +384,8 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "Starter", "CanHaveRiver"
+property_green       = 50
+property_mountainous = 30
 helptext            = _("\
 In addition to being amenable to agriculture, Hills are frequently\
  rich in resources.\
@@ -420,6 +429,9 @@
 cooler_drier_result  = "Tundra"
 flags                = "CanHaveRiver"
 flags                = "CanHaveRiver"
+property_tropical    = 50
+property_foliage     = 50
+property_wet         = 50
 helptext            = _("\
 Jungles are densely overgrown, making agriculture somewhat\
  problematic.\
@@ -462,6 +474,7 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "CanHaveRiver"
+property_mountainous = 70
 helptext            = _("\
 Mountains are regions of extreme altitude, making agriculture and\
  trade very difficult.\
@@ -548,6 +561,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "Starter", "CanHaveRiver"
+property_green       = 50
+property_temperate   = 50
 helptext            = _("\
 Plains are very broad, sparse regions, which makes trade slightly\
  inconvenient.\
@@ -590,6 +605,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "CanHaveRiver"
+property_wet         = 100
+property_foliage     = 10
 helptext            = _("\
 Swamps suffer from an over-abundance of water, making agriculture\
  somewhat problematic.\
@@ -632,6 +649,7 @@
 cooler_wetter_result = "Glacier"
 cooler_drier_result  = "Glacier"
 flags                = "Starter", "NoBarbs", "CanHaveRiver"
+property_cold        = 50
 helptext            = _("\
 Tundra are broad, cold regions, fit for some agriculture and little\
  else.\
Index: data/default/terrain.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/default/terrain.ruleset,v
retrieving revision 1.37
diff -u -r1.37 terrain.ruleset
--- data/default/terrain.ruleset        21 Mar 2005 13:05:21 -0000      1.37
+++ data/default/terrain.ruleset        24 Apr 2005 18:41:19 -0000
@@ -180,6 +180,18 @@
 ;                        units.  Most terrain improvements can only be built
 ;                        on land.  Oceanic terrain has no zones of control.
 ;                        The list goes on.
+; property_*           = specific property % values used by mapgen.  Most
+;                        terrains will have 0 for most values.
+;  - mountainous       = degree to which this terrain is mountainous
+;  - green             = how much life this terrain has
+;  - foliage           = how much thick undergrowth the terrain has 
+;  - tropical          = how "tropical" the terrain is (high temperature)
+;  - temperate         = how "temperate" the terrain is (med temperature)
+;  - cold              = how "cold" the terrain is (low temperature)
+;  - frozen            = how "frozen" the terrain is (very low temperature)
+;  - wet               = how "wet" the terrain is (moisture)
+;  - dry               = how "dry" the terrain is (moisture)
+;  - ocean_depth       = the depth of an ocean, as a percentage
 ; helptext            = optional help text string; should escape all raw 
 ;                       newlines so that xgettext parsing works
 
@@ -225,6 +237,7 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "NoBarbs", "CanHaveRiver", "UnsafeCoast", "Unsafe"
+property_frozen      = 100
 helptext            = _("\
 Glaciers are found only in the most northerly or southerly\
  reaches of the world.  They are very cold, and hence difficult to\
@@ -273,6 +286,8 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "CanHaveRiver"
+property_dry         = 100
+property_tropical    = 50
 helptext            = _("\
 Deserts are regions of extreme dryness, making agriculture and\
  trade very difficult.\
@@ -320,6 +335,8 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "Starter","CanHaveRiver"
+property_temperate   = 50
+property_foliage     = 50
 helptext            = _("\
 Forests are densely wooded, making agriculture somewhat\
  problematic.\
@@ -367,6 +384,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "Starter", "CanHaveRiver"
+property_temperate   = 50
+property_green       = 50
 helptext            = _("\
 Grasslands afford exceptional agricultural opportunities.\
 ")
@@ -413,6 +432,8 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "Starter", "CanHaveRiver"
+property_green       = 50
+property_mountainous = 30
 helptext            = _("\
 In addition to being amenable to agriculture, Hills are frequently\
  rich in resources.\
@@ -460,6 +481,9 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "CanHaveRiver"
+property_tropical    = 50
+property_foliage     = 50
+property_wet         = 50
 helptext            = _("\
 Jungles are densely overgrown, making agriculture somewhat\
  problematic.\
@@ -507,6 +531,7 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "CanHaveRiver"
+property_mountainous = 70
 helptext            = _("\
 Mountains are regions of extreme altitude, making agriculture and\
  trade very difficult.\
@@ -554,6 +579,7 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "Oceanic", "NoPollution", "UnsafeCoast", "NoCities"
+property_ocean_depth = 10
 helptext            = _("\
 Oceans cover much of the world, and only sea units (Triremes and\
  other boats) can travel on them.\
@@ -603,6 +629,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "Starter", "CanHaveRiver"
+property_green       = 50
+property_temperate   = 50
 helptext            = _("\
 Plains are very broad, sparse regions, which makes trade slightly\
  inconvenient.\
@@ -650,6 +678,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "CanHaveRiver"
+property_wet         = 100
+property_foliage     = 10
 helptext            = _("\
 Swamps suffer from an over-abundance of water, making agriculture\
  somewhat problematic.\
@@ -697,6 +727,7 @@
 cooler_wetter_result = "Glacier"
 cooler_drier_result  = "Glacier"
 flags                = "Starter", "NoBarbs", "CanHaveRiver"
+property_cold        = 50
 helptext            = _("\
 Tundra are broad, cold regions, fit for some agriculture and little\
  else.\
Index: data/history/terrain.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/history/terrain.ruleset,v
retrieving revision 1.15
diff -u -r1.15 terrain.ruleset
--- data/history/terrain.ruleset        14 Sep 2004 00:01:35 -0000      1.15
+++ data/history/terrain.ruleset        24 Apr 2005 18:41:20 -0000
@@ -214,6 +214,7 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "NoBarbs", "CanHaveRiver", "UnsafeCoast", "Unsafe"
+property_frozen      = 100
 helptext            = _("\
 Glaciers are found only in the most northerly or southerly\
  reaches of the world.  They are very cold, and hence difficult to\
@@ -262,6 +263,8 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "CanHaveRiver"
+property_dry         = 100
+property_tropical    = 50
 helptext            = _("\
 Deserts are regions of extreme dryness, making agriculture and\
  trade very difficult.\
@@ -309,6 +312,8 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "CanHaveRiver"
+property_temperate   = 50
+property_foliage     = 50
 helptext            = _("\
 Forests are densely wooded, making agriculture somewhat\
  problematic.\
@@ -356,6 +361,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "Starter", "CanHaveRiver"
+property_temperate   = 50
+property_green       = 50
 helptext            = _("\
 Grasslands afford exceptional agricultural opportunities.\
 ")
@@ -402,6 +409,7 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "CanHaveRiver"
+property_mountainous = 30
 helptext            = _("\
 In addition to being amenable to agriculture, Hills are frequently\
  rich in resources.\
@@ -449,6 +457,9 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "CanHaveRiver"
+property_tropical    = 50
+property_foliage     = 50
+property_wet         = 50
 helptext            = _("\
 Jungles are densely overgrown, making agriculture somewhat\
  problematic.\
@@ -496,6 +507,7 @@
 cooler_wetter_result = "no"
 cooler_drier_result  = "no"
 flags                = "CanHaveRiver"
+property_mountainous = 70
 helptext            = _("\
 Mountains are regions of extreme altitude, making agriculture and\
  trade very difficult.\
@@ -592,6 +604,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "Starter", "CanHaveRiver"
+property_green       = 50
+property_temperate   = 50
 helptext            = _("\
 Plains are very broad, sparse regions, which makes trade slightly\
  inconvenient.\
@@ -639,6 +653,8 @@
 cooler_wetter_result = "Desert"
 cooler_drier_result  = "Tundra"
 flags                = "CanHaveRiver"
+property_wet         = 100
+property_foliage     = 10
 helptext            = _("\
 Swamps suffer from an over-abundance of water, making agriculture\
  somewhat problematic.\
@@ -686,6 +702,7 @@
 cooler_wetter_result = "Glacier"
 cooler_drier_result  = "Glacier"
 flags                = "NoBarbs", "CanHaveRiver"
+property_cold        = 50
 helptext            = _("\
 Tundra are broad, cold regions, fit for some agriculture and little\
  else.\
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.245
diff -u -r1.245 ruleset.c
--- server/ruleset.c    21 Apr 2005 00:28:28 -0000      1.245
+++ server/ruleset.c    24 Apr 2005 18:41:20 -0000
@@ -1560,6 +1560,19 @@
        }
       }
       free(slist);
+
+      for (j = 0; j < MG_LAST; j++) {
+       const char *mg_names[] = {
+         "mountainous", "green", "foliage",
+         "tropical", "temperate", "cold", "frozen",
+         "wet", "dry", "ocean_depth"
+       };
+       assert(ARRAY_SIZE(mg_names) == MG_LAST);
+
+       t->property[j] = secfile_lookup_int_default(file, 0,
+                                                   "%s.property_%s",
+                                                   sec[i], mg_names[j]);
+      }
       
       t->helptext = lookup_helptext(file, sec[i]);
   } terrain_type_iterate_end;
Index: server/generator/mapgen.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/generator/mapgen.c,v
retrieving revision 1.23
diff -u -r1.23 mapgen.c
--- server/generator/mapgen.c   23 Apr 2005 17:40:29 -0000      1.23
+++ server/generator/mapgen.c   24 Apr 2005 18:41:21 -0000
@@ -39,12 +39,6 @@
 #include "utilities.h"
 
 
-/* Old-style terrain enumeration: deprecated. */
-enum {
-  T_ARCTIC, T_DESERT, T_FOREST, T_GRASSLAND, T_HILLS, T_JUNGLE,
-  T_MOUNTAINS, T_OCEAN, T_PLAINS, T_SWAMP, T_TUNDRA,
-};
-
 /* Wrappers for easy access.  They are a macros so they can be a lvalues.*/
 #define rmap(ptile) (river_map[ptile->index])
 
@@ -228,6 +222,101 @@
   return TRUE;
 }
 
+/****************************************************************************
+  Pick a terrain based on the target property and a property to avoid.
+
+  If the target property is given, then all terrains with that property
+  will be considered and one will be picked at random based on the amount
+  of the property each terrain has.  If no target property is given all
+  terrains will be assigned equal likelihood.
+
+  If the preferred property is given, only terrains with (some of) that
+  property will be chosen.
+
+  If the avoid property is given, then any terrain with (any of) that
+  property will be avoided.
+****************************************************************************/
+static Terrain_type_id pick_terrain(enum mapgen_terrain_property target,
+                                   enum mapgen_terrain_property prefer,
+                                   enum mapgen_terrain_property avoid)
+{
+  int sum = 0;
+
+  /* Find the total weight. */
+  terrain_type_iterate(terrain) {
+    if (avoid != MG_LAST && get_tile_type(terrain)->property[avoid] > 0) {
+      continue;
+    }
+    if (prefer != MG_LAST && get_tile_type(terrain)->property[prefer] == 0) {
+      continue;
+    }
+
+    if (target != MG_LAST) {
+      sum += get_tile_type(terrain)->property[target];
+    } else {
+      sum++;
+    }
+  } terrain_type_iterate_end;
+
+  /* Now pick. */
+  sum = myrand(sum);
+
+  /* Finally figure out which one we picked. */
+  terrain_type_iterate(terrain) {
+    int property;
+
+    if (avoid != MG_LAST && get_tile_type(terrain)->property[avoid] > 0) {
+      continue;
+    }
+    if (prefer != MG_LAST && get_tile_type(terrain)->property[prefer] == 0) {
+      continue;
+    }
+
+    if (target != MG_LAST) {
+      property = get_tile_type(terrain)->property[target];
+    } else {
+      property = 1;
+    }
+    if (sum < property) {
+      return terrain;
+    }
+    sum -= property;
+  } terrain_type_iterate_end;
+
+  /* This can happen with sufficient quantities of preferred and avoided
+   * characteristics.  Drop a requirement and try again. */
+  if (prefer != MG_LAST) {
+    return pick_terrain(target, MG_LAST, avoid);
+  } else if (avoid != MG_LAST) {
+    return pick_terrain(target, prefer, MG_LAST);
+  } else {
+    return pick_terrain(MG_LAST, prefer, avoid);
+  }
+}
+
+/**************************************************************************
+  Picks an ocean terrain to match the given depth (as a percentage).
+**************************************************************************/
+static Terrain_type_id pick_ocean(int depth)
+{
+  Terrain_type_id best_terrain = get_flag_terrain(TER_OCEANIC);
+  int best_match
+    = abs(depth - get_tile_type(best_terrain)->property[MG_OCEAN_DEPTH]);
+
+  terrain_type_iterate(t) {
+    if (terrain_has_flag(t, TER_OCEANIC)) {
+      int match = abs(depth - get_tile_type(t)->property[MG_OCEAN_DEPTH]);
+
+      if (match < best_match) {
+       best_match = match;
+       best_terrain = t;
+      }
+    }
+  } terrain_type_iterate_end;
+
+  return best_terrain;
+}
+
 /**************************************************************************
   make_relief() will convert all squares that are higher than thill to
   mountains and hills. Note that thill will be adjusted according to
@@ -247,15 +336,13 @@
          (myrand(10) > 5 
           || !terrain_is_too_high(ptile, hmap_mountain_level, hmap(ptile))))
         || terrain_is_too_flat(ptile, hmap_mountain_level, hmap(ptile)))) {
-      /* 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(ptile, TT_NHOT)) {
-       tile_set_terrain(ptile, T_MOUNTAINS);
-       map_set_placed(ptile);
-      } else {
-       tile_set_terrain(ptile, T_HILLS);
-       map_set_placed(ptile);
-      }
+      Terrain_type_id terrain
+       = pick_terrain(MG_MOUNTAINOUS,
+                      MG_LAST,
+                      (tmap_is(ptile, TT_NHOT) ? MG_GREEN : MG_LAST));
+
+      tile_set_terrain(ptile, terrain);
+      map_set_placed(ptile);
     }
   } whole_map_iterate_end;
 }
@@ -272,7 +359,7 @@
        || (tmap_is(ptile, TT_COLD)
            && (myrand(10) > 7)
            && is_temperature_type_near(ptile, TT_FROZEN))) { 
-      tile_set_terrain(ptile, T_ARCTIC);
+      tile_set_terrain(ptile, pick_terrain(MG_FROZEN, MG_LAST, MG_LAST));
     }
   } whole_map_iterate_end;
 }
@@ -353,15 +440,14 @@
 {
   /* in cold place we get tundra instead */
   if (tmap_is(ptile, TT_FROZEN)) {
-    tile_set_terrain(ptile, T_ARCTIC); 
+    tile_set_terrain(ptile,
+                    pick_terrain(MG_FROZEN, MG_LAST, MG_MOUNTAINOUS));
   } else if (tmap_is(ptile, TT_COLD)) {
-    tile_set_terrain(ptile, T_TUNDRA); 
+    tile_set_terrain(ptile,
+                    pick_terrain(MG_COLD, MG_LAST, MG_MOUNTAINOUS)); 
   } else {
-    if (myrand(100) > 50) {
-      tile_set_terrain(ptile, T_GRASSLAND);
-    } else {
-      tile_set_terrain(ptile, T_PLAINS);
-    }
+    tile_set_terrain(ptile,
+                    pick_terrain(MG_TEMPERATE, MG_GREEN, MG_MOUNTAINOUS));
   }
   map_set_placed(ptile);
   (*to_be_placed)--;
@@ -434,15 +520,20 @@
   /* the placement loop */
   do {
     
-    PLACE_ONE_TYPE(forests_count , plains_count, T_FOREST,
+    PLACE_ONE_TYPE(forests_count , plains_count,
+                  pick_terrain(MG_FOLIAGE, MG_TEMPERATE, MG_LAST),
                   WC_ALL, TT_NFROZEN, MC_NONE, 60);
-    PLACE_ONE_TYPE(jungles_count, forests_count , T_JUNGLE,
+    PLACE_ONE_TYPE(jungles_count, forests_count,
+                  pick_terrain(MG_FOLIAGE, MG_TROPICAL, MG_COLD),
                   WC_ALL, TT_TROPICAL, MC_NONE, 50);
-    PLACE_ONE_TYPE(swamps_count, forests_count , T_SWAMP,
+    PLACE_ONE_TYPE(swamps_count, forests_count,
+                  pick_terrain(MG_FOLIAGE, MG_WET, MG_TROPICAL),
                   WC_NDRY, TT_HOT, MC_LOW, 50);
-    PLACE_ONE_TYPE(deserts_count, alt_deserts_count , T_DESERT,
+    PLACE_ONE_TYPE(deserts_count, alt_deserts_count,
+                  pick_terrain(MG_DRY, MG_TROPICAL, MG_COLD),
                   WC_DRY, TT_NFROZEN, MC_NLOW, 80);
-    PLACE_ONE_TYPE(alt_deserts_count, plains_count , T_DESERT,
+    PLACE_ONE_TYPE(alt_deserts_count, plains_count,
+                  pick_terrain(MG_DRY, MG_TROPICAL, MG_COLD),
                   WC_ALL, TT_NFROZEN, MC_NLOW, 40);
  
   /* make the plains and tundras */
@@ -493,8 +584,7 @@
 *********************************************************************/
 static int river_test_highlands(struct tile *ptile)
 {
-  return (((tile_get_terrain(ptile) == T_HILLS) ? 1 : 0) +
-         ((tile_get_terrain(ptile) == T_MOUNTAINS) ? 2 : 0));
+  return get_tile_type(ptile->terrain)->property[MG_MOUNTAINOUS];
 }
 
 /*********************************************************************
@@ -518,8 +608,13 @@
 *********************************************************************/
 static int river_test_adjacent_highlands(struct tile *ptile)
 {
-  return (count_terrain_near_tile(ptile, TRUE, TRUE, T_HILLS)
-         + 2 * count_terrain_near_tile(ptile, TRUE, TRUE, T_MOUNTAINS));
+  int sum = 0;
+
+  adjc_iterate(ptile, ptile2) {
+    sum += get_tile_type(ptile2->terrain)->property[MG_MOUNTAINOUS];
+  } adjc_iterate_end;
+
+  return sum;
 }
 
 /*********************************************************************
@@ -527,7 +622,7 @@
 *********************************************************************/
 static int river_test_swamp(struct tile *ptile)
 {
-  return (tile_get_terrain(ptile) != T_SWAMP) ? 1 : 0;
+  return FC_INFINITY - get_tile_type(ptile->terrain)->property[MG_WET];
 }
 
 /*********************************************************************
@@ -535,7 +630,13 @@
 *********************************************************************/
 static int river_test_adjacent_swamp(struct tile *ptile)
 {
-  return 100 - count_terrain_near_tile(ptile, TRUE, TRUE, T_SWAMP);
+  int sum = 0;
+
+  adjc_iterate(ptile, ptile2) {
+    sum += get_tile_type(ptile2->terrain)->property[MG_WET];
+  } adjc_iterate_end;
+
+  return FC_INFINITY - sum;
 }
 
 /*********************************************************************
@@ -691,7 +792,7 @@
     /* We arbitrarily make rivers end at the poles. */
     if (count_special_near_tile(ptile, TRUE, TRUE, S_RIVER) > 0
        || count_ocean_near_tile(ptile, TRUE, TRUE) > 0
-        || (tile_get_terrain(ptile) == T_ARCTIC 
+        || (get_tile_type(ptile->terrain)->property[MG_FROZEN] > 0
            && map_colatitude(ptile) < 0.8 * COLD_LEVEL)) { 
 
       freelog(LOG_DEBUG,
@@ -838,28 +939,23 @@
        /* 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(ptile, TRUE, TRUE, T_HILLS)
-           + count_terrain_near_tile(ptile, TRUE, TRUE, T_MOUNTAINS) < 90
+       && (count_terrain_property_near_tile(ptile, TRUE, TRUE,
+                                            MG_MOUNTAINOUS) < 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. */
-       && (tile_get_terrain(ptile) != T_HILLS
+       && (get_tile_type(ptile->terrain)->property[MG_MOUNTAINOUS] > 0
            || iteration_counter == RIVERS_MAXTRIES / 10 * 6)
 
-       /* Don't start a river on mountains unless it is hard to find
-          somewhere else to start it. */
-       && (tile_get_terrain(ptile) != 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. */
-       && (tile_get_terrain(ptile) != T_ARCTIC
+       && (get_tile_type(ptile->terrain)->property[MG_FROZEN] > 0
            || iteration_counter == RIVERS_MAXTRIES / 10 * 8)
 
        /* Don't start a river on desert unless it is hard to find
           somewhere else to start it. */
-       && (tile_get_terrain(ptile) != T_DESERT
+       && (get_tile_type(ptile->terrain)->property[MG_DRY] > 0
            || iteration_counter == RIVERS_MAXTRIES / 10 * 9)) {
 
       /* Reset river_map before making a new river. */
@@ -920,7 +1016,9 @@
   whole_map_iterate(ptile) {
     tile_set_terrain(ptile, T_UNKNOWN); /* set as oceans count is used */
     if (hmap(ptile) < hmap_shore_level) {
-      tile_set_terrain(ptile, T_OCEAN);
+      int depth = (hmap_shore_level - hmap(ptile)) * 100 / hmap_shore_level;
+
+      tile_set_terrain(ptile, pick_ocean(depth));
     }
   } whole_map_iterate_end;
   if (HAS_POLES) {
@@ -949,7 +1047,7 @@
 {
   Terrain_type_id t = tile_get_terrain(ptile);
 
-  if (is_ocean(t) || t == T_ARCTIC) {
+  if (is_ocean(t) || get_tile_type(t)->property[MG_FROZEN] > 0) {
     /* The arctic check is needed for iso-maps: the poles may not have
      * any cardinally adjacent land tiles, but that's okay. */
     return FALSE;
@@ -971,7 +1069,7 @@
 {
   whole_map_iterate(ptile) {
     if (is_tiny_island(ptile)) {
-      tile_set_terrain(ptile, T_OCEAN);
+      tile_set_terrain(ptile, pick_ocean(0));
       tile_clear_special(ptile, S_RIVER);
       tile_set_continent(ptile, 0);
     }
@@ -1652,22 +1750,34 @@
     mountbuck += mountain_pct * i;
     fill_island(20, &mountbuck,
                3, 1, 3,1,
-               T_HILLS, T_MOUNTAINS, T_HILLS, T_MOUNTAINS,
+               pick_terrain(MG_MOUNTAINOUS, MG_GREEN, MG_LAST),
+               pick_terrain(MG_MOUNTAINOUS, MG_LAST, MG_GREEN),
+               pick_terrain(MG_MOUNTAINOUS, MG_GREEN, MG_LAST),
+               pick_terrain(MG_MOUNTAINOUS, MG_LAST, MG_GREEN),
                pstate);
     desertbuck += desert_pct * i;
     fill_island(40, &desertbuck,
                1, 1, 1, 1,
-               T_DESERT, T_DESERT, T_DESERT, T_TUNDRA,
+               pick_terrain(MG_DRY, MG_TROPICAL, MG_LAST),
+               pick_terrain(MG_DRY, MG_TROPICAL, MG_LAST),
+               pick_terrain(MG_DRY, MG_TROPICAL, MG_LAST),
+               pick_terrain(MG_COLD, MG_LAST, MG_LAST),
                pstate);
     forestbuck += forest_pct * i;
     fill_island(60, &forestbuck,
                forest_pct, swamp_pct, forest_pct, swamp_pct,
-               T_FOREST, T_JUNGLE, T_FOREST, T_TUNDRA,
+               pick_terrain(MG_FOLIAGE, MG_TEMPERATE, MG_LAST),
+               pick_terrain(MG_FOLIAGE, MG_TROPICAL, MG_COLD),
+               pick_terrain(MG_FOLIAGE, MG_TEMPERATE, MG_LAST),
+               pick_terrain(MG_FOLIAGE, MG_TROPICAL, MG_COLD),
                pstate);
     swampbuck += swamp_pct * i;
     fill_island(80, &swampbuck,
                1, 1, 1, 1,
-               T_SWAMP, T_SWAMP, T_SWAMP, T_SWAMP,
+               pick_terrain(MG_WET, MG_LAST, MG_FOLIAGE),
+               pick_terrain(MG_WET, MG_LAST, MG_FOLIAGE),
+               pick_terrain(MG_WET, MG_LAST, MG_FOLIAGE),
+               pick_terrain(MG_WET, MG_LAST, MG_FOLIAGE),
                pstate);
 
     pstate->isleindex++;
@@ -1686,7 +1796,7 @@
   create_tmap(FALSE);
   
   whole_map_iterate(ptile) {
-    tile_set_terrain(ptile, T_OCEAN);
+    tile_set_terrain(ptile, pick_ocean(100));
     tile_set_continent(ptile, 0);
     map_set_placed(ptile); /* not a land tile */
     tile_clear_all_specials(ptile);

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] Re: (PR#9787) RFC: generalized terrain, Jason Short <=