<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40207 >
2008/8/12 [email protected]
<[email protected]>:
>
> 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
- 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-04 13:26:04.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-04 13:57:04.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-04 13:57:13.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-03 18:59:38.000000000 +0300
+++ freeciv/common/fc_types.h 2009-05-04 13:56:32.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,9 +244,11 @@
struct base_type *base;
enum ai_level ai_level;
+ enum citytile_type citytile;
int minsize;
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 */
@@ -265,6 +275,8 @@
VUT_AI_LEVEL, /* AI level of the player */
VUT_TERRAINCLASS, /* More generic terrain type, currently "Land" or "Ocean" */
VUT_BASE,
+ 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 2008-10-27 04:13:31.000000000 +0200
+++ freeciv/common/requirements.c 2009-05-04 14:02:38.000000000 +0300
@@ -47,7 +47,9 @@
"MinSize",
"AI",
"TerrainClass",
- "Base"
+ "Base",
+ "TerrainAlter",
+ "CityTile"
};
/* Names of requirement ranges. These must correspond to enum req_range in
@@ -207,6 +209,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;
@@ -301,6 +315,12 @@
case VUT_BASE:
source.value.base = base_by_number(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:
@@ -364,6 +384,10 @@
return source->value.terrainclass;
case VUT_BASE:
return base_number(source->value.base);
+ case VUT_TERRAINALTER:
+ return source->value.terrainalter;
+ case VUT_CITYTILE:
+ return source->value.citytile;
case VUT_LAST:
default:
break;
@@ -409,6 +433,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:
@@ -462,6 +488,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_NONE:
@@ -841,6 +869,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,
@@ -1049,6 +1106,27 @@
req->range, req->survives,
req->source.value.base);
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;
@@ -1113,6 +1191,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:
@@ -1126,6 +1205,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
@@ -1184,6 +1264,10 @@
return psource1->value.terrainclass == psource2->value.terrainclass;
case VUT_BASE:
return psource1->value.base == psource2->value.base;
+ case VUT_TERRAINALTER:
+ return psource1->value.terrainalter == psource2->value.terrainalter;
+ case VUT_CITYTILE:
+ return TRUE;
case VUT_LAST:
break;
}
@@ -1209,6 +1293,7 @@
{
switch (psource->kind) {
case VUT_NONE:
+ case VUT_CITYTILE:
/* TRANS: missing value */
return N_("(none)");
case VUT_ADVANCE:
@@ -1243,6 +1328,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);
@@ -1325,6 +1412,14 @@
cat_snprintf(buf, bufsz, _("%s base"),
base_name_translation(psource->value.base));
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-04 13:12:29.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-04 13:12:29.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 2008-10-27 04:13:56.000000000 +0200
+++ freeciv/data/civ2/effects.ruleset 2009-05-04 14:03:27.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 2008-10-27 04:13:56.000000000 +0200
+++ freeciv/data/default/effects.ruleset 2009-05-04 14:02:59.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 2007-08-04 18:36:17.000000000 +0300
+++ freeciv/doc/README.effects 2009-05-04 13:12:29.000000000 +0300
@@ -40,9 +40,11 @@
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", "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", "MinSize", "AI",
+"TerrainClass", "TerrainAlter", or "CityCenter". MinSize is the minimum
+size of a city required. AI is ai player difficulty level. TerrainClass
+is either "Land" or "Oceanic". CityCenter takes no argument and is true
+if the target city is on the target tile.
Effect types
============
diff -Nurd -X.diff_ignore freeciv/server/cityturn.c freeciv/server/cityturn.c
--- freeciv/server/cityturn.c 2009-04-29 20:40:45.000000000 +0300
+++ freeciv/server/cityturn.c 2009-05-04 13:29:12.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-04-29 20:40:45.000000000 +0300
+++ freeciv/server/ruleset.c 2009-05-04 13:29:47.000000000 +0300
@@ -3809,6 +3809,8 @@
case VUT_MINSIZE: /* Breaks nothing, but has no sense either */
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
[email protected]
https://mail.gna.org/listinfo/freeciv-dev