<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