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

2009/5/4 Marko Lindqvist <cazf...@gmail.com>:
> 2008/8/12 jacobn+freeci...@chiark.greenend.org.uk
> <jacobn+freeci...@chiark.greenend.org.uk>:
>>
>> In June, I wrote:
>>> Madeline Book writes:
>>> > and for 2.2+ to expand the effect system to allow support for
>>> > auto-irrigation and auto-farmland of the city center.
>>>
>>> I'll see if I can find time to have a go at this.
>>
>> I've finally found a bit of time. Draft attached. It continues to be a
>> can of worms.
>
>  Since no better alternative has shown up, we are going forward with
> this patch. I did some updates and fixes.
>
>  - Updated against svn
>  - Renamed is_terrain_alteration_in_range() as
> is_terrain_alter_possible_in_range()
>  - Renamed VUT_CITYCENTER as VUT_CITYTILE and it now has type telling
> which kind of citytile is required. Currently only "Center" is
> supported
>  - Target city to VUT_CITYTILE requirement is now optional
>  - Added effect to civ2 ruleset also

 - Updated against svn
 - Fixed comparison of CityTile requirements
 - Corrected documentation (README.effects)


 - ML

diff -Nurd -X.diff_ignore freeciv/client/helpdata.c freeciv/client/helpdata.c
--- freeciv/client/helpdata.c   2009-01-25 16:51:10.000000000 +0200
+++ freeciv/client/helpdata.c   2009-05-12 03:05:47.000000000 +0300
@@ -234,6 +234,13 @@
      cat_snprintf(buf, bufsz, _("Requires %s terrain.\n\n"),
                   
terrain_class_name_translation(req->source.value.terrainclass));
      return;
+  case VUT_TERRAINALTER:
+     cat_snprintf(buf, bufsz, _("Requires terrain on which %s can be 
built.\n\n"),
+                  
terrain_alteration_name_translation(req->source.value.terrainalter));
+     return;
+  case VUT_CITYTILE:
+     cat_snprintf(buf, bufsz, _("Applies only to city centers.\n\n"));
+     return;
   case VUT_LAST:
   default:
     break;
diff -Nurd -X.diff_ignore freeciv/common/city.c freeciv/common/city.c
--- freeciv/common/city.c       2008-11-09 00:26:56.000000000 +0200
+++ freeciv/common/city.c       2009-05-12 03:05:47.000000000 +0300
@@ -710,7 +710,6 @@
 int city_tile_output(const struct city *pcity, const struct tile *ptile,
                     bool is_celebrating, Output_type_id otype)
 {
-  struct tile tile;
   int prod;
   struct terrain *pterrain = tile_terrain(ptile);
 
@@ -727,38 +726,27 @@
     prod += tile_resource(ptile)->output[otype];
   }
 
-  /* create dummy tile which has the city center bonuses. */
-  tile.terrain = pterrain;
-  tile.special = tile_specials(ptile);
-
-  if (NULL != pcity
-      && is_city_center(pcity, ptile)
-      && pterrain == pterrain->irrigation_result
-      && terrain_control.may_irrigate) {
-    /* The center tile is auto-irrigated. */
-    tile_set_special(&tile, S_IRRIGATION);
-
-    if (player_knows_techs_with_flag(city_owner(pcity), TF_FARMLAND)) {
-      tile_set_special(&tile, S_FARMLAND);
-    }
-  }
-
   switch (otype) {
   case O_SHIELD:
-    if (contains_special(tile.special, S_MINE)) {
+    if (tile_has_special(ptile, S_MINE)) {
       prod += pterrain->mining_shield_incr;
     }
     break;
   case O_FOOD:
-    if (contains_special(tile.special, S_IRRIGATION)) {
+    /* The city center tile is auto-irrigated. */
+    if (tile_has_special(ptile, S_IRRIGATION)
+        || (NULL != pcity
+            && is_city_center(pcity, ptile)
+            && pterrain == pterrain->irrigation_result
+            && terrain_control.may_irrigate)) {
       prod += pterrain->irrigation_food_incr;
     }
     break;
   case O_TRADE:
-    if (contains_special(tile.special, S_RIVER) && !is_ocean(tile.terrain)) {
+    if (tile_has_special(ptile, S_RIVER) && !is_ocean_tile(ptile)) {
       prod += terrain_control.river_trade_incr;
     }
-    if (contains_special(tile.special, S_ROAD)) {
+    if (tile_has_special(ptile, S_ROAD)) {
       prod += pterrain->road_trade_incr;
     }
     break;
@@ -769,7 +757,7 @@
     break;
   }
 
-  if (contains_special(tile.special, S_RAILROAD)) {
+  if (tile_has_special(ptile, S_RAILROAD)) {
     prod += (prod * terrain_control.rail_tile_bonus[otype]) / 100;
   }
 
@@ -799,11 +787,11 @@
     }
   }
 
-  if (contains_special(tile.special, S_POLLUTION)) {
+  if (tile_has_special(ptile, S_POLLUTION)) {
     prod -= (prod * terrain_control.pollution_tile_penalty[otype]) / 100;
   }
 
-  if (contains_special(tile.special, S_FALLOUT)) {
+  if (tile_has_special(ptile, S_FALLOUT)) {
     prod -= (prod * terrain_control.fallout_tile_penalty[otype]) / 100;
   }
 
@@ -2633,3 +2621,15 @@
 
   return pcity != game_find_city_by_number(pcity->id);
 }
+
+/**************************************************************************
+  Return citytile type for a given rule name
+**************************************************************************/
+enum citytile_type find_citytile_by_rule_name(const char *name)
+{
+  if (!mystrcasecmp(name, "center")) {
+    return CITYT_CENTER;
+  }
+
+  return CITYT_LAST;
+}
diff -Nurd -X.diff_ignore freeciv/common/city.h freeciv/common/city.h
--- freeciv/common/city.h       2009-03-19 18:05:43.000000000 +0200
+++ freeciv/common/city.h       2009-05-12 03:05:47.000000000 +0300
@@ -679,4 +679,6 @@
        (CITY_MAP_RADIUS == city_x && CITY_MAP_RADIUS == city_y)
 #define FREE_WORKED_TILES (1)
 
+enum citytile_type find_citytile_by_rule_name(const char *name);
+
 #endif  /* FC__CITY_H */
diff -Nurd -X.diff_ignore freeciv/common/fc_types.h freeciv/common/fc_types.h
--- freeciv/common/fc_types.h   2009-05-07 23:43:31.000000000 +0300
+++ freeciv/common/fc_types.h   2009-05-12 03:07:31.000000000 +0300
@@ -200,6 +200,14 @@
   SEA_BARBARIAN = 2
 };
 
+/*
+ * Citytile requirement types. 
+ */
+enum citytile_type {
+  CITYT_CENTER,
+  CITYT_LAST
+};
+
 /* Sometimes we don't know (or don't care) if some requirements for effect
  * are currently fulfilled or not. This enum tells lower level functions
  * how to handle uncertain requirements.
@@ -236,10 +244,12 @@
   struct base_type *base;
 
   enum ai_level ai_level;
+  enum citytile_type citytile;
   int minsize;
   int minyear;
   Output_type_id outputtype;
   int terrainclass;                    /* enum terrain_class */
+  int terrainalter;                     /* enum terrain_alteration */
   int special;                         /* enum tile_special_type */
   int unitclassflag;                   /* enum unit_class_flag_id */
   int unitflag;                                /* enum unit_flag_id */
@@ -267,6 +277,8 @@
   VUT_TERRAINCLASS,    /* More generic terrain type, currently "Land" or 
"Ocean" */
   VUT_BASE,
   VUT_MINYEAR,
+  VUT_TERRAINALTER,     /* Terrain alterations that are possible */
+  VUT_CITYTILE,         /* Target tile is used by city */
   VUT_LAST
 };
 
diff -Nurd -X.diff_ignore freeciv/common/requirements.c 
freeciv/common/requirements.c
--- freeciv/common/requirements.c       2009-05-07 23:43:31.000000000 +0300
+++ freeciv/common/requirements.c       2009-05-12 03:09:28.000000000 +0300
@@ -48,7 +48,9 @@
   "AI",
   "TerrainClass",
   "Base",
-  "MinYear"
+  "MinYear",
+  "TerrainAlter",
+  "CityTile"
 };
 
 /* Names of requirement ranges. These must correspond to enum req_range in
@@ -214,6 +216,18 @@
       return source;
     }
     break;
+  case VUT_TERRAINALTER:
+    source.value.terrainalter = find_terrain_alteration_by_rule_name(value);
+    if (source.value.terrainalter != TA_LAST) {
+      return source;
+    }
+    break;
+  case VUT_CITYTILE:
+    source.value.citytile = find_citytile_by_rule_name(value);
+    if (source.value.citytile != CITYT_LAST) {
+      return source;
+    }
+    break;
   case VUT_LAST:
   default:
     break;
@@ -311,6 +325,12 @@
   case VUT_MINYEAR:
     source.value.minyear = value;
     return source;
+  case VUT_TERRAINALTER:
+    source.value.terrainalter = value;
+    return source;
+  case VUT_CITYTILE:
+    source.value.citytile = value;
+    return source;
   case VUT_LAST:
     return source;
   default:
@@ -376,6 +396,10 @@
     return base_number(source->value.base);
   case VUT_MINYEAR:
     return source->value.minyear;
+  case VUT_TERRAINALTER:
+    return source->value.terrainalter;
+  case VUT_CITYTILE:
+    return source->value.citytile;
   case VUT_LAST:
   default:
     break;
@@ -421,6 +445,8 @@
     case VUT_SPECIALIST:
     case VUT_TERRAINCLASS:
     case VUT_BASE:
+    case VUT_TERRAINALTER:
+    case VUT_CITYTILE:
       req.range = REQ_RANGE_LOCAL;
       break;
     case VUT_MINSIZE:
@@ -477,6 +503,8 @@
   case VUT_UCFLAG:
   case VUT_OTYPE:
   case VUT_SPECIALIST:
+  case VUT_TERRAINALTER: /* XXX could in principle support ADJACENT */
+  case VUT_CITYTILE:
     invalid = (req.range != REQ_RANGE_LOCAL);
     break;
   case VUT_MINYEAR:
@@ -859,6 +887,35 @@
 }
 
 /****************************************************************************
+  Is there a terrain which can support the specified infrastructure
+  within range of the target?
+****************************************************************************/
+static bool is_terrain_alter_possible_in_range(const struct tile *target_tile,
+                                           enum req_range range, bool survives,
+                                           enum terrain_alteration alteration)
+{
+  if (!target_tile) {
+    return FALSE;
+  }
+
+  switch (range) {
+  case REQ_RANGE_LOCAL:
+    return terrain_can_support_alteration(tile_terrain(target_tile),
+                                          alteration);
+  case REQ_RANGE_ADJACENT: /* XXX Could in principle support ADJACENT. */
+  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,
@@ -1070,6 +1127,27 @@
   case VUT_MINYEAR:
     eval = game.info.year >= req->source.value.minyear;
     break;
+  case VUT_TERRAINALTER:
+    eval = is_terrain_alter_possible_in_range(target_tile,
+                                              req->range, req->survives,
+                                              req->source.value.terrainalter);
+    break;
+  case VUT_CITYTILE:
+    if (target_tile) {
+      if (req->source.value.citytile == CITYT_CENTER) {
+        if (target_city) {
+          eval = is_city_center(target_city, target_tile);
+        } else {
+          eval = tile_city(target_tile) != NULL;
+        }
+      } else {
+        /* Not implemented */
+        assert(FALSE);
+      }
+    } else {
+      eval = FALSE;
+    }
+    break;
   case VUT_LAST:
     assert(0);
     return FALSE;
@@ -1134,6 +1212,7 @@
   case VUT_OTYPE:
   case VUT_SPECIALIST: /* Only so long as it's at local range only */
   case VUT_AI_LEVEL:
+  case VUT_CITYTILE:
     return TRUE;
   case VUT_ADVANCE:
   case VUT_GOVERNMENT:
@@ -1147,6 +1226,7 @@
   case VUT_SPECIAL:
   case VUT_TERRAIN:
   case VUT_TERRAINCLASS:
+  case VUT_TERRAINALTER:
   case VUT_BASE:
     /* Terrains, specials and bases aren't really unchanging; in fact they're
      * practically guaranteed to change.  We return TRUE here for historical
@@ -1210,6 +1290,10 @@
     return psource1->value.base == psource2->value.base;
   case VUT_MINYEAR:
     return psource1->value.minyear == psource2->value.minyear;
+  case VUT_TERRAINALTER:
+    return psource1->value.terrainalter == psource2->value.terrainalter;
+  case VUT_CITYTILE:
+    return psource1->value.citytile == psource2->value.citytile;
   case VUT_LAST:
     break;
   }
@@ -1235,6 +1319,7 @@
 {
   switch (psource->kind) {
   case VUT_NONE:
+  case VUT_CITYTILE:
     /* TRANS: missing value */
     return N_("(none)");
   case VUT_ADVANCE:
@@ -1269,6 +1354,8 @@
     return terrain_class_rule_name(psource->value.terrainclass);
   case VUT_BASE:
     return base_rule_name(psource->value.base);
+  case VUT_TERRAINALTER:
+    return terrain_alteration_rule_name(psource->value.terrainalter);
   case VUT_LAST:
   default:
     assert(0);
@@ -1355,6 +1442,14 @@
     cat_snprintf(buf, bufsz, _("After %s"),
                  textyear(psource->value.minyear));
     break;
+  case VUT_TERRAINALTER:
+    /* TRANS: "Irrigation possible" */
+    cat_snprintf(buf, bufsz, _("%s possible"),
+                 
terrain_alteration_name_translation(psource->value.terrainalter));
+    break;
+  case VUT_CITYTILE:
+    mystrlcat(buf, _("City center tile"), bufsz);
+    break;
   case VUT_LAST:
     assert(0);
     break;
diff -Nurd -X.diff_ignore freeciv/common/terrain.c freeciv/common/terrain.c
--- freeciv/common/terrain.c    2008-10-27 04:13:31.000000000 +0200
+++ freeciv/common/terrain.c    2009-05-12 03:05:47.000000000 +0300
@@ -46,6 +46,12 @@
   N_("Oceanic")
 };
 
+static const char *terrain_alteration_names[] = {
+  N_("CanIrrigate"),
+  N_("CanMine"),
+  N_("CanRoad")
+};
+
 /* T_UNKNOWN isn't allowed here. */
 #define SANITY_CHECK_TERRAIN(pterrain)                                 \
   assert((pterrain)->item_number >= 0                                  \
@@ -879,3 +885,76 @@
 
   return _(terrain_class_names[tclass]);
 }
+
+/****************************************************************************
+  Can terrain support given infrastructure?
+****************************************************************************/
+bool terrain_can_support_alteration(const struct terrain *pterrain,
+                                    enum terrain_alteration alter)
+{
+  switch (alter) {
+   case TA_CAN_IRRIGATE:
+     return (terrain_control.may_irrigate
+          && (pterrain == pterrain->irrigation_result));
+   case TA_CAN_MINE:
+     return (terrain_control.may_mine
+          && (pterrain == pterrain->mining_result));
+   case TA_CAN_ROAD:
+     return (terrain_control.may_road && (pterrain->road_time > 0));
+   case TA_LAST:
+   default:
+     break;
+  }
+
+  assert(FALSE);
+  return FALSE;
+}
+
+/****************************************************************************
+  Return the terrain alteration possibility value matching name, or TA_LAST
+  if none matches.
+****************************************************************************/
+enum terrain_alteration find_terrain_alteration_by_rule_name(const char *name)
+{
+  int i;
+
+  for (i = 0; i < TA_LAST; i++) {
+    if (0 == strcmp(terrain_alteration_names[i], name)) {
+      return i;
+    }
+  }
+
+  return TA_LAST;
+}
+
+/****************************************************************************
+  Return the (untranslated) rule name of the given terrain alteration.
+  You don't have to free the return pointer.
+****************************************************************************/
+const char *terrain_alteration_rule_name(enum terrain_alteration talter)
+{
+  if (talter < 0 || talter >= TA_LAST) {
+    return NULL;
+  }
+
+  return terrain_alteration_names[talter];
+}
+
+/****************************************************************************
+  Return the (translated) name of the infrastructure (e.g., "Irrigation").
+  You don't have to free the return pointer.
+****************************************************************************/
+const char *terrain_alteration_name_translation(enum terrain_alteration talter)
+{
+  switch(talter) {
+   case TA_CAN_IRRIGATE:
+     return special_name_translation(S_IRRIGATION);
+   case TA_CAN_MINE:
+     return special_name_translation(S_MINE);
+   case TA_CAN_ROAD:
+     return special_name_translation(S_ROAD);
+   case TA_LAST:
+   default:
+     return NULL;
+  }
+}
diff -Nurd -X.diff_ignore freeciv/common/terrain.h freeciv/common/terrain.h
--- freeciv/common/terrain.h    2008-10-27 04:13:31.000000000 +0200
+++ freeciv/common/terrain.h    2009-05-12 03:05:47.000000000 +0300
@@ -140,6 +140,16 @@
   MG_LAST
 };
 
+/* Types of alterations available to terrain.
+ * This enum is only used in the effects system; the relevant information
+ * is encoded in other members of the terrain structure. */
+enum terrain_alteration {
+  TA_CAN_IRRIGATE,     /* Can build irrigation without changing terrain */
+  TA_CAN_MINE,         /* Can build mine without changing terrain */
+  TA_CAN_ROAD,         /* Can build roads and/or railroads */
+  TA_LAST
+};
+
 /*
  * This struct gives data about each terrain type.  There are many ways
  * it could be extended.
@@ -302,6 +312,13 @@
                               enum terrain_class tclass);
 bool is_terrain_class_near_tile(const struct tile *ptile, enum terrain_class 
tclass);
 
+/* Functions to deal with possible terrain alterations. */
+enum terrain_alteration find_terrain_alteration_by_rule_name(const char *name);
+const char *terrain_alteration_rule_name(enum terrain_alteration talter);
+const char *terrain_alteration_name_translation(enum terrain_alteration 
talter);
+bool terrain_can_support_alteration(const struct terrain *pterrain,
+                                    enum terrain_alteration talter);
+
 /* Initialization and iteration */
 struct resource *resource_array_first(void);
 const struct resource *resource_array_last(void);
diff -Nurd -X.diff_ignore freeciv/data/civ2/effects.ruleset 
freeciv/data/civ2/effects.ruleset
--- freeciv/data/civ2/effects.ruleset   2009-05-12 00:37:18.000000000 +0300
+++ freeciv/data/civ2/effects.ruleset   2009-05-12 03:05:47.000000000 +0300
@@ -1581,6 +1581,17 @@
       "OutputType", "food", "local"
     }
 
+[effect_supermarket_2]
+name   = "Output_Per_Tile"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "CityTile", "Center", "Local"
+      "TerrainAlter", "CanIrrigate", "Local"
+      "Building", "Supermarket", "City"
+      "OutputType", "Food", "Local"
+    }
+
 [effect_temple]
 name   = "Make_Content"
 value  = 1
diff -Nurd -X.diff_ignore freeciv/data/default/effects.ruleset 
freeciv/data/default/effects.ruleset
--- freeciv/data/default/effects.ruleset        2009-05-12 00:37:18.000000000 
+0300
+++ freeciv/data/default/effects.ruleset        2009-05-12 03:05:47.000000000 
+0300
@@ -1543,6 +1543,17 @@
       "OutputType", "Food", "Local"
     }
 
+[effect_supermarket_2]
+name   = "Output_Per_Tile"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "CityTile", "Center", "Local"
+      "TerrainAlter", "CanIrrigate", "Local"
+      "Building", "Supermarket", "City"
+      "OutputType", "Food", "Local"
+    }
+
 [effect_temple]
 name   = "Make_Content"
 value  = 1
diff -Nurd -X.diff_ignore freeciv/doc/README.effects freeciv/doc/README.effects
--- freeciv/doc/README.effects  2009-05-12 00:37:18.000000000 +0300
+++ freeciv/doc/README.effects  2009-05-12 03:12:12.000000000 +0300
@@ -40,9 +40,10 @@
 
 A requirement type is the type of the requirement and can be one of "None" 
 (default), "Tech", "Gov", "Building", "Special", "Terrain", "UnitType", 
-"UnitFlag", "UnitClass", "Nation", "OutputType", "MinYear", "MinSize", "AI"
-and "TerrainClass". MinSize is the minimum size of a city required. AI is ai
-player difficulty level. TerrainClass is either "Land" or "Oceanic".
+"UnitFlag", "UnitClass", "Nation", "OutputType", "MinYear", "MinSize", "AI",
+"TerrainClass", "TerrainAlter", or "CityTile". MinSize is the minimum size
+of a city required. AI is ai player difficulty level. TerrainClass is either
+"Land" or "Oceanic". Only "Center" is supported as CityTile type.
 
 Effect types 
 ============
diff -Nurd -X.diff_ignore freeciv/server/cityturn.c freeciv/server/cityturn.c
--- freeciv/server/cityturn.c   2009-05-07 23:43:31.000000000 +0300
+++ freeciv/server/cityturn.c   2009-05-12 03:05:47.000000000 +0300
@@ -1118,6 +1118,8 @@
            case VUT_UCFLAG:
            case VUT_OTYPE:
            case VUT_SPECIALIST:
+           case VUT_TERRAINALTER: /* XXX could do this in principle */
+           case VUT_CITYTILE:
              /* Will only happen with a bogus ruleset. */
              freelog(LOG_ERROR, "worklist_change_build_target()"
                      " has bogus preq");
diff -Nurd -X.diff_ignore freeciv/server/ruleset.c freeciv/server/ruleset.c
--- freeciv/server/ruleset.c    2009-05-12 03:04:01.000000000 +0300
+++ freeciv/server/ruleset.c    2009-05-12 03:05:47.000000000 +0300
@@ -3824,6 +3824,8 @@
      case VUT_MINYEAR:
      case VUT_AI_LEVEL:
      case VUT_TERRAINCLASS:
+     case VUT_TERRAINALTER: /* Local range only */
+     case VUT_CITYTILE:
        /* There can be only one requirement of these types (with current
         * range limitations)
         * Requirements might be identical, but we consider multiple
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to