<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
[email protected]
https://mail.gna.org/listinfo/freeciv-dev