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

 We have a problem with several ocean types and buildings that can be
built only to coastal cities. We don't have OR -requirement, so those
buildings can depend on one terrain type only.

 This patch adds requirement type "TerrainClass" that can have value
"Land" or "Oceanic".


 - ML

diff -Nurd -X.diff_ignore freeciv/client/helpdata.c freeciv/client/helpdata.c
--- freeciv/client/helpdata.c	2007-03-01 14:48:17.000000000 +0200
+++ freeciv/client/helpdata.c	2007-03-01 19:19:56.000000000 +0200
@@ -214,6 +214,10 @@
     cat_snprintf(buf, bufsz, _("Requires AI player of level %s.\n\n"),
                  ai_level_name(req->source.value.level));
     return;
+   case REQ_TERRAINCLASS:
+     cat_snprintf(buf, bufsz, _("Requires %s terrain.\n\n"),
+                  terrain_class_name(req->source.value.terrainclass));
+     return;
   }
   assert(0);
 }
diff -Nurd -X.diff_ignore freeciv/common/requirements.c freeciv/common/requirements.c
--- freeciv/common/requirements.c	2007-03-01 14:48:16.000000000 +0200
+++ freeciv/common/requirements.c	2007-03-01 19:07:27.000000000 +0200
@@ -42,7 +42,8 @@
   "OutputType",
   "Specialist",
   "MinSize",
-  "AI"
+  "AI",
+  "TerrainClass"
 };
 
 /* Names of requirement ranges. These must correspond to enum req_range in
@@ -181,6 +182,12 @@
       return source;
     }
     break;
+  case REQ_TERRAINCLASS:
+    source.value.terrainclass = get_terrain_class_by_name(value);
+    if (source.value.terrainclass != TC_LAST) {
+      return source;
+    }
+    break;
   case REQ_LAST:
     break;
   }
@@ -242,6 +249,9 @@
   case REQ_AI:
     source.value.level = value;
     return source;
+  case REQ_TERRAINCLASS:
+    source.value.terrainclass = value;
+    return source;
   case REQ_LAST:
     return source;
   }
@@ -304,6 +314,9 @@
   case REQ_AI:
     *value = source->value.level;
     return;
+  case REQ_TERRAINCLASS:
+    *value = source->value.terrainclass;
+    return;
   case REQ_LAST:
     break;
   }
@@ -344,6 +357,7 @@
     case REQ_UNITCLASS:
     case REQ_OUTPUTTYPE:
     case REQ_SPECIALIST:
+    case REQ_TERRAINCLASS:
       req.range = REQ_RANGE_LOCAL;
       break;
     case REQ_MINSIZE:
@@ -366,6 +380,7 @@
   switch (req.source.type) {
   case REQ_SPECIAL:
   case REQ_TERRAIN:
+  case REQ_TERRAINCLASS:
     invalid = (req.range != REQ_RANGE_LOCAL
 	       && req.range != REQ_RANGE_ADJACENT);
     break;
@@ -712,6 +727,35 @@
 }
 
 /****************************************************************************
+  Is there a source terrain class within range of the target?
+****************************************************************************/
+static bool is_terrain_class_in_range(const struct tile *target_tile,
+                                      enum req_range range, bool survives,
+                                      enum terrain_class class)
+{
+  if (!target_tile) {
+    return FALSE;
+  }
+
+  switch (range) {
+  case REQ_RANGE_LOCAL:
+    /* The requirement is filled if the tile has the terrain of correct class. */
+    return terrain_belongs_to_class(target_tile->terrain, class);
+  case REQ_RANGE_ADJACENT:
+    return is_terrain_class_near_tile(target_tile, class);
+  case REQ_RANGE_CITY:
+  case REQ_RANGE_CONTINENT:
+  case REQ_RANGE_PLAYER:
+  case REQ_RANGE_WORLD:
+  case REQ_RANGE_LAST:
+    break;
+  }
+
+  assert(0);
+  return FALSE;
+}
+
+/****************************************************************************
   Is there a nation within range of the target?
 ****************************************************************************/
 static bool is_nation_in_range(const struct player *target_player,
@@ -880,6 +924,11 @@
       && target_player->ai.control
       && target_player->ai.skill_level == req->source.value.level;
     break;
+  case REQ_TERRAINCLASS:
+    eval = is_terrain_class_in_range(target_tile,
+                                     req->range, req->survives,
+                                     req->source.value.terrainclass);
+    break;
   case REQ_LAST:
     assert(0);
     return FALSE;
@@ -954,6 +1003,7 @@
     return FALSE;
   case REQ_SPECIAL:
   case REQ_TERRAIN:
+  case REQ_TERRAINCLASS:
     /* Terrains and specials aren't really unchanging; in fact they're
      * practically guaranteed to change.  We return TRUE here for historical
      * reasons and so that the AI doesn't get confused (since the AI
@@ -1005,6 +1055,8 @@
     return psource1->value.minsize == psource2->value.minsize;
   case REQ_AI:
     return psource1->value.level == psource2->value.level;
+  case REQ_TERRAINCLASS:
+    return psource1->value.terrainclass == psource2->value.terrainclass;
   case REQ_LAST:
     break;
   }
@@ -1068,6 +1120,10 @@
     cat_snprintf(buf, bufsz, _("%s AI"),
                  ai_level_name(psource->value.level));
     break;
+   case REQ_TERRAINCLASS:
+     cat_snprintf(buf, bufsz, _("%s terrain"),
+                  terrain_class_name(psource->value.terrainclass));
+     break;
   case REQ_LAST:
     assert(0);
     break;
diff -Nurd -X.diff_ignore freeciv/common/requirements.h freeciv/common/requirements.h
--- freeciv/common/requirements.h	2007-03-01 14:48:16.000000000 +0200
+++ freeciv/common/requirements.h	2007-03-01 18:36:07.000000000 +0200
@@ -34,8 +34,9 @@
   REQ_UNITCLASS,
   REQ_OUTPUTTYPE,
   REQ_SPECIALIST,
-  REQ_MINSIZE, /* Minimum size: at city range means city size */
-  REQ_AI,      /* AI level of the player */
+  REQ_MINSIZE,      /* Minimum size: at city range means city size */
+  REQ_AI,           /* AI level of the player */
+  REQ_TERRAINCLASS, /* More generic terrain type, currently "Land" or "Ocean" */
   REQ_LAST
 };
 
@@ -69,6 +70,7 @@
     Specialist_type_id specialist;      /* specialist type */
     int minsize;                        /* source minsize type */
     enum ai_level level;                /* source AI level */
+    enum terrain_class terrainclass;    /* source generic terrain type */
   } value;                              /* source value */
 };
 
diff -Nurd -X.diff_ignore freeciv/common/terrain.c freeciv/common/terrain.c
--- freeciv/common/terrain.c	2007-02-28 23:02:38.000000000 +0200
+++ freeciv/common/terrain.c	2007-03-01 19:08:22.000000000 +0200
@@ -41,6 +41,9 @@
   S_LAST
 };
 
+static const char *terrain_class_names[] = {
+  N_("Land"), N_("Oceanic") };
+
 /* T_UNKNOWN isn't allowed here. */
 #define SANITY_CHECK_TERRAIN(pterrain)					    \
   assert((pterrain)->index >= 0						    \
@@ -547,3 +550,79 @@
   }
   return S_LAST;
 }
+
+/****************************************************************************
+  Does terrain type belong to terrain class?
+****************************************************************************/
+bool terrain_belongs_to_class(const struct terrain *pterrain,
+                              enum terrain_class class)
+{
+  switch(class) {
+   case TC_LAND:
+     return !is_ocean(pterrain);
+   case TC_OCEAN:
+     return is_ocean(pterrain);
+   case TC_LAST:
+     return FALSE;
+  }
+
+  assert(FALSE);
+  return FALSE;
+}
+
+/****************************************************************************
+  Is there terrain of the given class near tile?
+****************************************************************************/
+bool is_terrain_class_near_tile(const struct tile *ptile, enum terrain_class class)
+{
+  switch(class) {
+   case TC_LAND:
+     adjc_iterate(ptile, adjc_tile) {
+       struct terrain* pterrain = tile_get_terrain(adjc_tile);
+       if (pterrain == NULL) {
+         continue;
+       }
+    
+       if (!is_ocean(pterrain)) {
+         return TRUE;
+       }
+     } adjc_iterate_end;
+     return FALSE;
+   case TC_OCEAN:
+     return is_ocean_near_tile(ptile);
+   case TC_LAST:
+     return FALSE;
+  }
+
+  assert(FALSE);
+  return FALSE;
+}
+
+
+/****************************************************************************
+  Return the terrain class value matching name, or TC_LAST if none matches.
+****************************************************************************/
+enum terrain_class get_terrain_class_by_name(const char *name)
+{
+  int i;
+
+  for (i = 0; i < TC_LAST; i++) {
+    if (!strcmp(terrain_class_names[i], name)) {
+      return i;
+    }
+  }
+
+  return TC_LAST;
+}
+
+/****************************************************************************
+  Return localized name of the terrain class
+****************************************************************************/
+const char *terrain_class_name(enum terrain_class class)
+{
+  if (class < 0 || class >= TC_LAST) {
+    return NULL;
+  }
+
+  return _(terrain_class_names[class]);
+}
diff -Nurd -X.diff_ignore freeciv/common/terrain.h freeciv/common/terrain.h
--- freeciv/common/terrain.h	2007-02-12 15:27:43.000000000 +0200
+++ freeciv/common/terrain.h	2007-03-01 19:05:07.000000000 +0200
@@ -39,6 +39,8 @@
   S_LAST
 };
 
+enum terrain_class { TC_LAND, TC_OCEAN, TC_LAST };
+
 /* S_LAST-terminated */
 extern enum tile_special_type infrastructure_specials[];
 
@@ -234,6 +236,13 @@
 				 bool cardinal_only, bool percentage,
 				 enum terrain_flag_id flag);
 
+/* Functions to operate on a terrain class. */
+bool terrain_belongs_to_class(const struct terrain *pterrain,
+                              enum terrain_class class);
+bool is_terrain_class_near_tile(const struct tile *ptile, enum terrain_class class);
+enum terrain_class get_terrain_class_by_name(const char *name);
+const char *terrain_class_name(enum terrain_class class);
+
 /* Special helper functions */
 const char *get_infrastructure_text(bv_special pset);
 enum tile_special_type get_infrastructure_prereq(enum tile_special_type spe);
diff -Nurd -X.diff_ignore freeciv/data/civ2/buildings.ruleset freeciv/data/civ2/buildings.ruleset
--- freeciv/data/civ2/buildings.ruleset	2006-07-17 23:56:23.000000000 +0300
+++ freeciv/data/civ2/buildings.ruleset	2007-03-01 19:10:05.000000000 +0200
@@ -215,7 +215,7 @@
 reqs	=
     { "type", "name", "range"
       "Tech", "Metallurgy", "Player"
-      "Terrain", "Ocean", "Adjacent"
+      "TerrainClass", "Oceanic", "Adjacent"
     }
 graphic		= "b.coastal_defense"
 graphic_alt	= "-"
@@ -322,7 +322,7 @@
 reqs	=
     { "type", "name", "range"
       "Tech", "Seafaring", "Player"
-      "Terrain", "Ocean", "Adjacent"
+      "TerrainClass", "Oceanic", "Adjacent"
     }
 graphic		= "b.harbour"
 graphic_alt	= "-"
@@ -333,7 +333,7 @@
 sound		= "b_harbour"
 sound_alt	= "b_generic"
 helptext	= _("\
-Gives one extra food resource on all Ocean squares.  The city needs\
+Gives one extra food resource on all Oceanic squares.  The city needs\
  to be coastal to build this improvement.\
 ")
 
@@ -490,7 +490,7 @@
 reqs	=
     { "type", "name", "range"
       "Tech", "Miniaturization", "Player"
-      "Terrain", "Ocean", "Adjacent"
+      "TerrainClass", "Oceanic", "Adjacent"
     }
 graphic		= "b.offshore_platform"
 graphic_alt	= "-"
@@ -501,7 +501,7 @@
 sound		= "b_offshore_platform"
 sound_alt	= "b_generic"
 helptext	= _("\
-Adds 1 extra shield resource on all Ocean squares in a city.  The\
+Adds 1 extra shield resource on all Oceanic squares in a city.  The\
  city needs to be coastal to build this improvement.\
 ")
 
@@ -561,7 +561,7 @@
 reqs	=
     { "type", "name", "range"
       "Tech", "Amphibious Warfare", "Player"
-      "Terrain", "Ocean", "Adjacent"
+      "TerrainClass", "Oceanic", "Adjacent"
     }
 graphic		= "b.port_facility"
 graphic_alt	= "-"
diff -Nurd -X.diff_ignore freeciv/data/civ2/effects.ruleset freeciv/data/civ2/effects.ruleset
--- freeciv/data/civ2/effects.ruleset	2007-02-26 14:15:35.000000000 +0200
+++ freeciv/data/civ2/effects.ruleset	2007-03-01 19:18:11.000000000 +0200
@@ -1092,7 +1092,7 @@
 value	= 1
 reqs	=
     { "type", "name", "range"
-      "Terrain", "Ocean", "Local"
+      "TerrainClass", "Oceanic", "Local"
       "Building", "Harbour", "City"
       "OutputType", "food", "local"
     }
@@ -1232,7 +1232,7 @@
 value	= 1
 reqs	=
     { "type", "name", "range"
-      "Terrain", "Ocean", "Local"
+      "TerrainClass", "Oceanic", "Local"
       "Building", "Offshore Platform", "City"
       "OutputType", "shield", "local"
     }
diff -Nurd -X.diff_ignore freeciv/data/default/buildings.ruleset freeciv/data/default/buildings.ruleset
--- freeciv/data/default/buildings.ruleset	2006-07-17 23:56:23.000000000 +0300
+++ freeciv/data/default/buildings.ruleset	2007-03-01 19:10:22.000000000 +0200
@@ -235,7 +235,7 @@
 reqs	=
     { "type", "name", "range"
       "Tech", "Metallurgy", "Player"
-      "Terrain", "Ocean", "Adjacent"
+      "TerrainClass", "Oceanic", "Adjacent"
     }
 graphic	= "b.coastal_defense"
 graphic_alt	= "-"
@@ -343,7 +343,7 @@
 reqs	=
     { "type", "name", "range"
       "Tech", "Seafaring", "Player"
-      "Terrain", "Ocean", "Adjacent"
+      "TerrainClass", "Oceanic", "Adjacent"
     }
 graphic	= "b.harbour"
 graphic_alt	= "-"
@@ -354,7 +354,7 @@
 sound		= "b_harbour"
 sound_alt	= "b_generic"
 helptext	= _("\
-Gives one extra food resource on all Ocean squares.  The city needs\
+Gives one extra food resource on all Oceanic squares.  The city needs\
  to be coastal to build this improvement.\
 ")
 
@@ -517,7 +517,7 @@
 reqs	=
     { "type", "name", "range"
       "Tech", "Miniaturization", "Player"
-      "Terrain", "Ocean", "Adjacent"
+      "TerrainClass", "Oceanic", "Adjacent"
     }
 graphic	= "b.offshore_platform"
 graphic_alt	= "-"
@@ -528,7 +528,7 @@
 sound		= "b_offshore_platform"
 sound_alt	= "b_generic"
 helptext	= _("\
-Adds 1 extra shield resource on all Ocean squares in a city.  The\
+Adds 1 extra shield resource on all Oceanic squares in a city.  The\
  city needs to be coastal to build this improvement.\
 ")
 
@@ -595,7 +595,7 @@
 reqs	=
     { "type", "name", "range"
       "Tech", "Amphibious Warfare", "Player"
-      "Terrain", "Ocean", "Adjacent"
+      "TerrainClass", "Oceanic", "Adjacent"
     }
 graphic	= "b.port_facility"
 graphic_alt	= "-"
diff -Nurd -X.diff_ignore freeciv/data/default/effects.ruleset freeciv/data/default/effects.ruleset
--- freeciv/data/default/effects.ruleset	2007-02-26 14:15:37.000000000 +0200
+++ freeciv/data/default/effects.ruleset	2007-03-01 19:17:50.000000000 +0200
@@ -967,7 +967,7 @@
 value	= 1
 reqs	=
     { "type", "name", "range"
-      "Terrain", "Ocean", "Local"
+      "TerrainClass", "Oceanic", "Local"
       "Building", "Harbour", "City"
       "OutputType", "Food", "Local"
     }
@@ -1138,7 +1138,7 @@
 value	= 1
 reqs	=
     { "type", "name", "range"
-      "Terrain", "Ocean", "Local"
+      "TerrainClass", "Oceanic", "Local"
       "Building", "Offshore Platform", "City"
       "OutputType", "Shield", "Local"
     }
diff -Nurd -X.diff_ignore freeciv/server/cityturn.c freeciv/server/cityturn.c
--- freeciv/server/cityturn.c	2007-03-01 14:48:16.000000000 +0200
+++ freeciv/server/cityturn.c	2007-03-01 19:13:03.000000000 +0200
@@ -850,6 +850,18 @@
                                  API_TYPE_CITY, pcity,
                                  API_TYPE_STRING, "need_ai_level");
 	      break;
+	    case REQ_TERRAINCLASS:
+	      notify_player(pplayer, pcity->tile, E_CITY_CANTBUILD,
+			       _("%s can't build %s from the worklist; "
+				 "%s terrain class is required.  Postponing..."),
+			       pcity->name,
+			       get_impr_name_ex(pcity, building->index),
+			       terrain_class_name(preq->source.value.terrainclass));
+	      script_signal_emit("building_cant_be_built", 3,
+				 API_TYPE_BUILDING_TYPE, building,
+				 API_TYPE_CITY, pcity,
+				 API_TYPE_STRING, "need_terrainclass");
+	      break;
 	    case REQ_NONE:
 	    case REQ_LAST:
 	      assert(0);
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to