[Freeciv-Dev] (PR#11539) requirements, part 2
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://bugs.freeciv.org/Ticket/Display.html?id=11539 >
At Per's request, RQR_* is renamed as REQ_RANGE_*.
-jason
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.183
diff -u -r1.183 aicity.c
--- ai/aicity.c 11 Dec 2004 10:34:45 -0000 1.183
+++ ai/aicity.c 15 Dec 2004 22:35:54 -0000
@@ -59,11 +59,11 @@
{ \
Continent_id continent = map_get_continent(city_here->tile); \
city_list_iterate(list, city) { \
- if ((range == EFR_CITY && city == city_here) \
- || (range == EFR_LOCAL && city == city_here) \
- || (range == EFR_CONTINENT \
+ if ((range == REQ_RANGE_CITY && city == city_here) \
+ || (range == REQ_RANGE_LOCAL && city == city_here) \
+ || (range == REQ_RANGE_CONTINENT \
&& map_get_continent(city->tile) == continent) \
- || (range == EFR_PLAYER)) {
+ || (range == REQ_RANGE_PLAYER)) {
#define city_range_iterate_end \
} } city_list_iterate_end; }
@@ -228,7 +228,7 @@
struct player *pplayer = city_owner(pcity);
struct impr_type *pimpr = get_improvement_type(id);
int v = 0;
- int cities[EFR_LAST];
+ int cities[REQ_RANGE_LAST];
int nplayers = game.nplayers
- game.nbarbarians
- team_count_members_alive(pplayer->team);
@@ -245,13 +245,13 @@
}
/* Find number of cities per range. */
- cities[EFR_PLAYER] = city_list_size(&pplayer->cities);
- cities[EFR_WORLD] = cities[EFR_PLAYER]; /* kludge. */
+ cities[REQ_RANGE_PLAYER] = city_list_size(&pplayer->cities);
+ cities[REQ_RANGE_WORLD] = cities[REQ_RANGE_PLAYER]; /* kludge. */
- cities[EFR_CONTINENT] = ai->stats.cities[ptile->continent];
+ cities[REQ_RANGE_CONTINENT] = ai->stats.cities[ptile->continent];
- cities[EFR_CITY] = 1;
- cities[EFR_LOCAL] = 0;
+ cities[REQ_RANGE_CITY] = 1;
+ cities[REQ_RANGE_LOCAL] = 0;
/* Calculate desire value. */
effect_type_vector_iterate(get_building_effect_types(id), ptype) {
Index: ai/aidata.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v
retrieving revision 1.20
diff -u -r1.20 aidata.h
--- ai/aidata.h 15 Dec 2004 03:59:21 -0000 1.20
+++ ai/aidata.h 15 Dec 2004 22:35:54 -0000
@@ -58,7 +58,7 @@
struct ai_data {
/* Precalculated info about city improvements */
enum ai_improvement_status impr_calc[MAX_NUM_ITEMS];
- enum effect_range impr_range[MAX_NUM_ITEMS];
+ enum req_range impr_range[MAX_NUM_ITEMS];
/* AI diplomacy and opinions on other players */
struct {
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.448
diff -u -r1.448 packhand.c
--- client/packhand.c 15 Dec 2004 19:28:43 -0000 1.448
+++ client/packhand.c 15 Dec 2004 22:35:55 -0000
@@ -1380,8 +1380,8 @@
/* Only add in the improvement if it's in a "foreign" (i.e. unknown) city
and has equiv_range==World - otherwise we deal with it in its home
city anyway */
- if (is_wonder(i) && improvement_types[i].equiv_range==EFR_WORLD &&
- !find_city_by_id(game.global_wonders[i])) {
+ if (is_wonder(i) && improvement_types[i].equiv_range == REQ_RANGE_WORLD
+ && !find_city_by_id(game.global_wonders[i])) {
if (game.global_wonders[i] <= 0 && game.improvements[i] != I_NONE) {
game.improvements[i] = I_NONE;
need_effect_update = TRUE;
@@ -2879,13 +2879,8 @@
**************************************************************************/
void handle_ruleset_cache_effect(struct packet_ruleset_cache_effect *packet)
{
- struct requirement req;
-
- req.type = packet->req_type;
- if (req.type < 0 || req.type >= REQ_LAST) {
- req.type = REQ_NONE;
- }
- req_set_value(&req, packet->req_value);
+ struct requirement req = req_from_values(packet->req_type, REQ_RANGE_CITY,
+ FALSE, packet->req_value);
ruleset_cache_add(packet->id, packet->effect_type, packet->range,
packet->survives, packet->eff_value,
Index: common/effects.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/effects.c,v
retrieving revision 1.18
diff -u -r1.18 effects.c
--- common/effects.c 15 Dec 2004 19:28:44 -0000 1.18
+++ common/effects.c 15 Dec 2004 22:35:55 -0000
@@ -34,17 +34,6 @@
#include "player.h"
#include "tech.h"
-/* Names of effect ranges.
- * (These must correspond to enum effect_range_id in effects.h.)
- * do not change these unless you know what you're doing! */
-static const char *effect_range_names[EFR_LAST] = {
- "Local",
- "City",
- "Continent",
- "Player",
- "World"
-};
-
/* Names of effect types.
* (These must correspond to enum effect_type_id in effects.h.) */
static const char *effect_type_names[EFT_LAST] = {
@@ -132,42 +121,6 @@
};
/**************************************************************************
- Convert an effect range names to an enumerated value. This is the
- inverse of effect_range_name.
-
- The check is case insensitive and returns EFR_LAST if no match is found.
-**************************************************************************/
-enum effect_range effect_range_from_str(const char *str)
-{
- enum effect_range effect_range;
-
- assert(ARRAY_SIZE(effect_range_names) == EFR_LAST);
-
- for (effect_range = 0; effect_range < EFR_LAST; effect_range++) {
- if (0 == mystrcasecmp(effect_range_names[effect_range], str)) {
- return effect_range;
- }
- }
-
- return EFR_LAST;
-}
-
-/**************************************************************************
- Return the name for an effect range enumeration. Returns NULL if the
- effect_range is invalid. This is the inverse of effect_range_from_str.
-**************************************************************************/
-const char *effect_range_name(enum effect_range effect_range)
-{
- assert(ARRAY_SIZE(effect_range_names) == EFR_LAST);
- if (effect_range >= 0 && effect_range < EFR_LAST) {
- return effect_range_names[effect_range];
- } else {
- assert(0);
- return NULL;
- }
-}
-
-/**************************************************************************
Convert effect type names to enum; case insensitive;
returns EFT_LAST if can't match.
**************************************************************************/
@@ -276,7 +229,7 @@
*/
struct effect_group_element {
Impr_Type_id source_building;
- enum effect_range range;
+ enum req_range range;
bool survives;
};
@@ -375,7 +328,7 @@
**************************************************************************/
void effect_group_add_element(struct effect_group *group,
Impr_Type_id source_building,
- enum effect_range range, bool survives)
+ enum req_range range, bool survives)
{
struct effect_group_element *elt;
@@ -461,7 +414,7 @@
Add effect to ruleset cache.
**************************************************************************/
void ruleset_cache_add(Impr_Type_id source, enum effect_type effect_type,
- enum effect_range range, bool survives, int eff_value,
+ enum req_range range, bool survives, int eff_value,
struct requirement *req,
int group_id)
{
@@ -565,6 +518,9 @@
building_vector_iterate(get_buildings_with_effect(effect_type),
building) {
+ int dummy_type, dummy_range;
+ bool dummy_survives;
+
packet.id = *building;
effect_list_iterate(*get_building_effects(*building, effect_type),
@@ -580,7 +536,8 @@
packet.group_id = -1;
}
- packet.req_value = req_get_value(&peffect->req);
+ req_get_values(&peffect->req, &dummy_type,
+ &dummy_range, &dummy_survives, &packet.req_value);
lsend_packet_ruleset_cache_effect(dest, &packet);
} effect_list_iterate_end;
@@ -643,178 +600,6 @@
}
/**************************************************************************
- Returns the number of total world buildings (this includes buildings
- that have been destroyed).
-**************************************************************************/
-static int num_world_buildings_total(Impr_Type_id building)
-{
- if (is_wonder(building)) {
- return (game.global_wonders[building] != 0) ? 1 : 0;
- } else {
- freelog(LOG_ERROR,
- /* TRANS: Obscure ruleset error. */
- _("World-ranged effects are only supported for wonders."));
- return 0;
- }
-}
-
-/**************************************************************************
- Returns the number of buildings of a certain type in the world.
-**************************************************************************/
-static int num_world_buildings(Impr_Type_id id)
-{
- if (is_wonder(id)) {
- return find_city_by_id(game.global_wonders[id]) ? 1 : 0;
- } else {
- freelog(LOG_ERROR,
- /* TRANS: Obscure ruleset error. */
- _("World-ranged effects are only supported for wonders."));
- return 0;
- }
-}
-
-/**************************************************************************
- Returns the number of buildings of a certain type owned by plr.
-**************************************************************************/
-static int num_player_buildings(const struct player *pplayer,
- Impr_Type_id building)
-{
- if (is_wonder(building)) {
- if (player_find_city_by_id(pplayer, game.global_wonders[building])) {
- return 1;
- } else {
- return 0;
- }
- } else {
- freelog(LOG_ERROR,
- /* TRANS: Obscure ruleset error. */
- _("Player-ranged effects are only supported for wonders."));
- return 0;
- }
-}
-
-/**************************************************************************
- Returns the number of buildings of a certain type on a continent.
-**************************************************************************/
-static int num_continent_buildings(const struct player *pplayer,
- int continent, Impr_Type_id building)
-{
- if (is_wonder(building)) {
- const struct city *pcity;
-
- pcity = player_find_city_by_id(pplayer, game.global_wonders[building]);
- if (pcity && map_get_continent(pcity->tile) == continent) {
- return 1;
- }
- } else {
- freelog(LOG_ERROR,
- /* TRANS: Obscure ruleset error. */
- _("Island-ranged effects are only supported for wonders."));
- }
- return 0;
-}
-
-/**************************************************************************
- Returns the number of buildings of a certain type in a city.
-**************************************************************************/
-static int num_city_buildings(const struct city *pcity, Impr_Type_id id)
-{
- return (city_got_building(pcity, id) ? 1 : 0);
-}
-
-/**************************************************************************
- Is this target possible for the range involved?
-
- For instance a city-ranged effect can't have a player as it's target.
- See the comment at enum target_type.
-**************************************************************************/
-static bool is_target_possible(enum target_type target,
- enum effect_range range)
-{
- switch (target) {
- case TARGET_PLAYER:
- return (range >= EFR_PLAYER);
- case TARGET_CITY:
- return (range >= EFR_CITY);
- case TARGET_BUILDING:
- return (range >= EFR_LOCAL);
- }
- assert(0);
- return FALSE;
-}
-
-/**************************************************************************
- How many of the source building are there within range of the target?
-
- The target gives the type of the target. The exact target is a player,
- city, or building specified by the target_xxx arguments.
-
- The range gives the range of the effect.
-
- "Survives" specifies whether the effect is surviving. If set then all
- source buildings ever built are counted; if not then only living
- buildings are counted.
-
- source gives the building type of the source in question.
-
- Note that this function does a lookup into the source caches to find
- the number of available sources. However not all source caches exist: if
- the cache doesn't exist then we return 0.
-**************************************************************************/
-int count_sources_in_range(enum target_type target,
- const struct player *target_player,
- const struct city *target_city,
- Impr_Type_id target_building,
- enum effect_range range, bool survives,
- Impr_Type_id source)
-{
- if (!is_target_possible(target, range)) {
- return 0;
- }
-
- if (improvement_obsolete(target_player, source)) {
- return 0;
- }
-
- if (survives) {
- if (range == EFR_WORLD) {
- return num_world_buildings_total(source);
- } else {
- /* There is no sources cache for this. */
- freelog(LOG_ERROR,
- /* TRANS: Obscure ruleset error. */
- _("Surviving effects are only supported at world range."));
- return 0;
- }
- }
-
- switch (range) {
- case EFR_WORLD:
- return num_world_buildings(source);
- case EFR_PLAYER:
- return num_player_buildings(target_player, source);
- case EFR_CONTINENT:
- {
- int continent = map_get_continent(target_city->tile);
-
- return num_continent_buildings(target_player, continent, source);
- }
- case EFR_CITY:
- return num_city_buildings(target_city, source);
- case EFR_LOCAL:
- if (target_building == source) {
- return num_city_buildings(target_city, source);
- } else {
- return 0;
- }
- case EFR_LAST:
- break;
- }
- assert(0);
- return 0;
-}
-
-/**************************************************************************
Is the effect from the source building redundant on the given target
(i.e. are its effects replaced by other sources in the group)?
@@ -841,9 +626,9 @@
if (elt->source_building == source) {
return FALSE;
} else {
- if (count_sources_in_range(target, target_player, target_city,
- target_building, elt->range,
- elt->survives, elt->source_building) > 0) {
+ if (count_buildings_in_range(target, target_player, target_city,
+ target_building, elt->range,
+ elt->survives, elt->source_building) > 0) {
/* The effect from this source in the group makes peffect
* redundant. Note this causes the redundancy even if the
* elt->source_building has no effects actually in the group! */
@@ -920,8 +705,8 @@
Impr_Type_id source,
const struct effect *peffect)
{
- if (count_sources_in_range(target, plr, pcity, building, peffect->range,
- peffect->survives, source) == 0) {
+ if (count_buildings_in_range(target, plr, pcity, building, peffect->range,
+ peffect->survives, source) == 0) {
return FALSE;
}
return is_effect_useful(target, plr, pcity, building,
Index: common/effects.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/effects.h,v
retrieving revision 1.12
diff -u -r1.12 effects.h
--- common/effects.h 15 Dec 2004 19:28:44 -0000 1.12
+++ common/effects.h 15 Dec 2004 22:35:55 -0000
@@ -21,17 +21,6 @@
#include "tech.h"
#include "terrain.h"
-/* Range of effects (used in equiv_range and effect.range fields)
- * These must correspond to effect_range_names[] in improvement.c. */
-enum effect_range {
- EFR_LOCAL,
- EFR_CITY,
- EFR_CONTINENT,
- EFR_PLAYER,
- EFR_WORLD,
- EFR_LAST /* keep this last */
-};
-
/* Type of effects. (Used in effect.type field)
* These must correspond to effect_type_names[] in effects.c. */
enum effect_type {
@@ -120,8 +109,6 @@
};
/* lookups */
-enum effect_range effect_range_from_str(const char *str);
-const char *effect_range_name(enum effect_range effect_range);
enum effect_type effect_type_from_str(const char *str);
const char *effect_type_name(enum effect_type effect_type);
@@ -152,7 +139,7 @@
/* The range the effect applies to, relative to the source. For instance
* if the source is a building an effect with range "city" will apply to
* everything in that city. */
- enum effect_range range;
+ enum req_range range;
/* The "value" of the effect. The meaning of this varies between
* effects. When get_xxx_bonus() is called the value of all applicable
@@ -196,7 +183,7 @@
void ruleset_cache_init(void);
void ruleset_cache_free(void);
void ruleset_cache_add(Impr_Type_id source, enum effect_type effect_type,
- enum effect_range range, bool survives, int eff_value,
+ enum req_range range, bool survives, int eff_value,
struct requirement *req,
int group_id);
void send_ruleset_cache(struct conn_list *dest);
@@ -205,7 +192,7 @@
struct effect_group *effect_group_new(const char *name);
void effect_group_add_element(struct effect_group *group,
Impr_Type_id source_building,
- enum effect_range range, bool survives);
+ enum req_range range, bool survives);
int find_effect_group_id(const char *name);
bool is_effect_useful(enum target_type target,
@@ -243,12 +230,6 @@
Impr_Type_id ai_find_source_building(struct player *pplayer,
enum effect_type effect_type);
Impr_Type_id get_building_for_effect(enum effect_type effect_type);
-int count_sources_in_range(enum target_type target,
- const struct player *target_player,
- const struct city *target_city,
- Impr_Type_id target_building,
- enum effect_range range, bool survives,
- Impr_Type_id source);
#endif /* FC__EFFECTS_H */
Index: common/packets.def
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v
retrieving revision 1.77
diff -u -r1.77 packets.def
--- common/packets.def 15 Dec 2004 19:28:44 -0000 1.77
+++ common/packets.def 15 Dec 2004 22:35:56 -0000
@@ -181,10 +181,8 @@
type ORDERS = uint8(enum unit_orders)
type SSET_TYPE = uint8(enum sset_type)
type REQ_TYPE = uint8(enum req_type)
-
-# typedefs for effects
+type REQ_RANGE = uint8(enum req_range)
type EFFECT_TYPE = uint8(enum effect_type)
-type EFFECT_RANGE = uint8(enum effect_range)
# typedefs for IDs
type PLAYER = UINT8
@@ -1271,14 +1269,14 @@
UINT8 num_elements;
IMPROVEMENT source_buildings[255:num_elements];
- EFFECT_RANGE ranges[255:num_elements];
+ REQ_RANGE ranges[255:num_elements];
BOOL survives[255:num_elements];
end
PACKET_RULESET_CACHE_EFFECT=121;sc,lsend
IMPROVEMENT id;
EFFECT_TYPE effect_type;
- EFFECT_RANGE range;
+ REQ_RANGE range;
BOOL survives;
SINT32 eff_value;
REQ_TYPE req_type;
Index: common/packets_gen.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets_gen.h,v
retrieving revision 1.69
diff -u -r1.69 packets_gen.h
--- common/packets_gen.h 15 Dec 2004 19:28:44 -0000 1.69
+++ common/packets_gen.h 15 Dec 2004 22:35:58 -0000
@@ -982,14 +982,14 @@
char name[MAX_LEN_NAME];
int num_elements;
Impr_Type_id source_buildings[255];
- enum effect_range ranges[255];
+ enum req_range ranges[255];
bool survives[255];
};
struct packet_ruleset_cache_effect {
Impr_Type_id id;
enum effect_type effect_type;
- enum effect_range range;
+ enum req_range range;
bool survives;
int eff_value;
enum req_type req_type;
Index: common/requirements.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/requirements.c,v
retrieving revision 1.1
diff -u -r1.1 requirements.c
--- common/requirements.c 15 Dec 2004 19:28:44 -0000 1.1
+++ common/requirements.c 15 Dec 2004 22:35:58 -0000
@@ -16,6 +16,8 @@
#include <assert.h>
+#include "fcintl.h"
+#include "log.h"
#include "support.h"
#include "government.h"
@@ -23,6 +25,9 @@
#include "map.h"
#include "requirements.h"
+/* Names of requirement types.
+ * (These must correspond to enum req_type in requirements.h.)
+ * do not change these unless you know what you're doing! */
static const char *req_type_names[] = {
"None",
"Tech",
@@ -32,25 +37,95 @@
"Terrain"
};
+/* Names of requirement ranges.
+ * (These must correspond to enum req_range in requirements.h.)
+ * do not change these unless you know what you're doing! */
+static const char *req_range_names[REQ_RANGE_LAST] = {
+ "Local",
+ "City",
+ "Continent",
+ "Player",
+ "World"
+};
+
+/**************************************************************************
+ Convert a range name to an enumerated value.
+
+ The check is case insensitive and returns REQ_RANGE_LAST if no match
+ is found.
+**************************************************************************/
+enum req_range req_range_from_str(const char *str)
+{
+ enum req_range range;
+
+ assert(ARRAY_SIZE(req_range_names) == REQ_RANGE_LAST);
+
+ for (range = 0; range < REQ_RANGE_LAST; range++) {
+ if (0 == mystrcasecmp(req_range_names[range], str)) {
+ return range;
+ }
+ }
+
+ return REQ_RANGE_LAST;
+}
+
+#if 0
+/**************************************************************************
+ Return the name for an effect range enumeration. Returns NULL if the
+ effect_range is invalid. This is the inverse of effect_range_from_str.
+**************************************************************************/
+const char *effect_range_name(enum effect_range effect_range)
+{
+ assert(ARRAY_SIZE(effect_range_names) == EFR_LAST);
+ if (effect_range >= 0 && effect_range < EFR_LAST) {
+ return effect_range_names[effect_range];
+ } else {
+ assert(0);
+ return NULL;
+ }
+}
+#endif
+
/****************************************************************************
Parse a requirement type and value string into a requrement structure.
Returns REQ_LAST on error.
Pass this some values like "Building", "Factory".
****************************************************************************/
-struct requirement req_from_str(const char *type, const char *value)
+struct requirement req_from_str(const char *type,
+ const char *range, bool survives,
+ const char *value)
{
struct requirement req;
const struct government *pgov;
assert(ARRAY_SIZE(req_type_names) == REQ_LAST);
-
for (req.type = 0; req.type < ARRAY_SIZE(req_type_names); req.type++) {
if (0 == mystrcasecmp(req_type_names[req.type], type)) {
break;
}
}
+ req.range = req_range_from_str(range);
+ if (req.range == REQ_RANGE_LAST) {
+ switch (req.type) {
+ case REQ_NONE:
+ case REQ_LAST:
+ break;
+ case REQ_BUILDING:
+ case REQ_SPECIAL:
+ case REQ_TERRAIN:
+ req.range = REQ_RANGE_CITY;
+ break;
+ case REQ_GOV:
+ case REQ_TECH:
+ req.range = REQ_RANGE_PLAYER;
+ break;
+ }
+ }
+
+ req.survives = survives;
+
switch (req.type) {
case REQ_NONE:
return req;
@@ -98,58 +173,251 @@
Return the value of a req as a serializable integer. This is the opposite
of req_set_value.
****************************************************************************/
-int req_get_value(struct requirement *req)
+void req_get_values(struct requirement *req,
+ int *type, int *range, bool *survives, int *value)
{
+ *type = req->type;
+ *range = req->range;
+ *survives = req->survives;
+
switch (req->type) {
case REQ_NONE:
- return 0;
+ *value = 0;
+ return;
case REQ_TECH:
- return req->value.tech;
+ *value = req->value.tech;
+ return;
case REQ_GOV:
- return req->value.gov;
+ *value = req->value.gov;
+ return;
case REQ_BUILDING:
- return req->value.building;
+ *value = req->value.building;
+ return;
case REQ_SPECIAL:
- return req->value.special;
+ *value = req->value.special;
+ return;
case REQ_TERRAIN:
- return req->value.terrain;
+ *value = req->value.terrain;
+ return;
case REQ_LAST:
break;
}
assert(0);
- return 0;
+ *value = 0;
}
/****************************************************************************
Set the value of a req from a serializable integer. This is the opposite
of req_get_value.
****************************************************************************/
-void req_set_value(struct requirement *req, int value)
+struct requirement req_from_values(int type, int range,
+ bool survives, int value)
{
- switch (req->type) {
+ struct requirement req;
+
+ req.type = type;
+ req.range = range;
+ req.survives = survives;
+
+ switch (req.type) {
case REQ_NONE:
- return;
+ return req;
case REQ_TECH:
- req->value.tech = value;
- return;
+ req.value.tech = value;
+ return req;
case REQ_GOV:
- req->value.gov = value;
- return;
+ req.value.gov = value;
+ return req;
case REQ_BUILDING:
- req->value.building = value;
- return;
+ req.value.building = value;
+ return req;
case REQ_SPECIAL:
- req->value.special = value;
- return;
+ req.value.special = value;
+ return req;
case REQ_TERRAIN:
- req->value.terrain = value;
- return;
+ req.value.terrain = value;
+ return req;
case REQ_LAST:
- return;
+ return req;
+ }
+
+ req.type = REQ_LAST;
+ assert(0);
+ return req;
+}
+
+/**************************************************************************
+ Is this target possible for the range involved?
+
+ For instance a city-ranged effect can't have a player as it's target.
+ See the comment at enum target_type.
+**************************************************************************/
+static bool is_target_possible(enum target_type target,
+ enum req_range range)
+{
+ switch (target) {
+ case TARGET_PLAYER:
+ return (range >= REQ_RANGE_PLAYER);
+ case TARGET_CITY:
+ return (range >= REQ_RANGE_CITY);
+ case TARGET_BUILDING:
+ return (range >= REQ_RANGE_LOCAL);
+ }
+ assert(0);
+ return FALSE;
+}
+
+/**************************************************************************
+ Returns the number of total world buildings (this includes buildings
+ that have been destroyed).
+**************************************************************************/
+static int num_world_buildings_total(Impr_Type_id building)
+{
+ if (is_wonder(building)) {
+ return (game.global_wonders[building] != 0) ? 1 : 0;
+ } else {
+ freelog(LOG_ERROR,
+ /* TRANS: Obscure ruleset error. */
+ _("World-ranged requirements are only supported for wonders."));
+ return 0;
+ }
+}
+
+/**************************************************************************
+ Returns the number of buildings of a certain type in the world.
+**************************************************************************/
+static int num_world_buildings(Impr_Type_id id)
+{
+ if (is_wonder(id)) {
+ return find_city_by_id(game.global_wonders[id]) ? 1 : 0;
+ } else {
+ freelog(LOG_ERROR,
+ /* TRANS: Obscure ruleset error. */
+ _("World-ranged requirements are only supported for wonders."));
+ return 0;
+ }
+}
+
+/**************************************************************************
+ Returns the number of buildings of a certain type owned by plr.
+**************************************************************************/
+static int num_player_buildings(const struct player *pplayer,
+ Impr_Type_id building)
+{
+ if (is_wonder(building)) {
+ if (player_find_city_by_id(pplayer, game.global_wonders[building])) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ freelog(LOG_ERROR,
+ /* TRANS: Obscure ruleset error. */
+ _("Player-ranged requirements are only supported for wonders."));
+ return 0;
+ }
+}
+
+/**************************************************************************
+ Returns the number of buildings of a certain type on a continent.
+**************************************************************************/
+static int num_continent_buildings(const struct player *pplayer,
+ int continent, Impr_Type_id building)
+{
+ if (is_wonder(building)) {
+ const struct city *pcity;
+
+ pcity = player_find_city_by_id(pplayer, game.global_wonders[building]);
+ if (pcity && map_get_continent(pcity->tile) == continent) {
+ return 1;
+ }
+ } else {
+ freelog(LOG_ERROR,
+ /* TRANS: Obscure ruleset error. */
+ _("Island-ranged requirements are only supported for wonders."));
}
+ return 0;
+}
+
+/**************************************************************************
+ Returns the number of buildings of a certain type in a city.
+**************************************************************************/
+static int num_city_buildings(const struct city *pcity, Impr_Type_id id)
+{
+ return (city_got_building(pcity, id) ? 1 : 0);
+}
+
+/**************************************************************************
+ How many of the source building are there within range of the target?
+
+ The target gives the type of the target. The exact target is a player,
+ city, or building specified by the target_xxx arguments.
+
+ The range gives the range of the requirement.
+ "Survives" specifies whether the requirement allows destroyed sources.
+ If set then all source buildings ever built are counted; if not then only
+ living buildings are counted.
+
+ source gives the building type of the source in question.
+
+ Note that this function does a lookup into the source caches to find
+ the number of available sources. However not all source caches exist: if
+ the cache doesn't exist then we return 0.
+**************************************************************************/
+int count_buildings_in_range(enum target_type target,
+ const struct player *target_player,
+ const struct city *target_city,
+ Impr_Type_id target_building,
+ enum req_range range, bool survives,
+ Impr_Type_id source)
+{
+ if (!is_target_possible(target, range)) {
+ return 0;
+ }
+
+ if (improvement_obsolete(target_player, source)) {
+ return 0;
+ }
+
+ if (survives) {
+ if (range == REQ_RANGE_WORLD) {
+ return num_world_buildings_total(source);
+ } else {
+ /* There is no sources cache for this. */
+ freelog(LOG_ERROR,
+ /* TRANS: Obscure ruleset error. */
+ _("Surviving requirements are only "
+ "supported at world range."));
+ return 0;
+ }
+ }
+
+ switch (range) {
+ case REQ_RANGE_WORLD:
+ return num_world_buildings(source);
+ case REQ_RANGE_PLAYER:
+ return num_player_buildings(target_player, source);
+ case REQ_RANGE_CONTINENT:
+ {
+ int continent = map_get_continent(target_city->tile);
+
+ return num_continent_buildings(target_player, continent, source);
+ }
+ case REQ_RANGE_CITY:
+ return num_city_buildings(target_city, source);
+ case REQ_RANGE_LOCAL:
+ if (target_building == source) {
+ return num_city_buildings(target_city, source);
+ } else {
+ return 0;
+ }
+ case REQ_RANGE_LAST:
+ break;
+ }
assert(0);
+ return 0;
}
/****************************************************************************
@@ -157,8 +425,7 @@
target gives the type of the target
(player,city,building,tile) give the exact target
- source gives the source type of the effect
- peffect gives the exact effect value
+ req gives the requirement itself
Make sure you give all aspects of the target when calling this function:
for instance if you have TARGET_CITY pass the city's owner as the target
@@ -189,9 +456,9 @@
/* The requirement is filled if there's at least one of the building
* in the city. (This is a slightly nonstandard use of
* count_sources_in_range.) */
- return (count_sources_in_range(target, target_player, target_city,
- target_building, EFR_CITY, FALSE,
- req->value.building) > 0);
+ return (count_buildings_in_range(target, target_player, target_city,
+ target_building, REQ_RANGE_CITY, FALSE,
+ req->value.building) > 0);
case REQ_SPECIAL:
/* The requirement is filled if the tile has the special. */
return target_tile && tile_has_special(target_tile, req->value.special);
Index: common/requirements.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/requirements.h,v
retrieving revision 1.1
diff -u -r1.1 requirements.h
--- common/requirements.h 15 Dec 2004 19:28:44 -0000 1.1
+++ common/requirements.h 15 Dec 2004 22:35:58 -0000
@@ -17,7 +17,8 @@
#include "fc_types.h"
#include "tech.h"
-/* The type of a requirement. */
+/* The type of a requirement. This must correspond to req_type_names[]
+ * in requirements.c. */
enum req_type {
REQ_NONE,
REQ_TECH,
@@ -28,6 +29,17 @@
REQ_LAST
};
+/* Range of requirements. This must correspond to req_range_names[]
+ * in requirements.c. */
+enum req_range {
+ REQ_RANGE_LOCAL,
+ REQ_RANGE_CITY,
+ REQ_RANGE_CONTINENT,
+ REQ_RANGE_PLAYER,
+ REQ_RANGE_WORLD,
+ REQ_RANGE_LAST /* keep this last */
+};
+
/* An requirement is targeted at a certain target type. For building and
* unit reqs the target will be a city; for tech reqs it will be a player;
* for effect reqs it may be anything. */
@@ -44,6 +56,8 @@
* active. */
struct requirement {
enum req_type type; /* requirement type */
+ enum req_range range; /* requirement range */
+ bool survives; /* set if destroyed sources satisfy the req*/
union {
Tech_Type_id tech; /* requirement tech */
@@ -54,10 +68,14 @@
} value; /* requirement value */
};
-struct requirement req_from_str(const char *type, const char *value);
-
-int req_get_value(struct requirement *req);
-void req_set_value(struct requirement *req, int value);
+enum req_range req_range_from_str(const char *str);
+struct requirement req_from_str(const char *type, const char *range,
+ bool survives, const char *value);
+
+void req_get_values(struct requirement *req,
+ int *type, int *range, bool *survives, int *value);
+struct requirement req_from_values(int type, int range,
+ bool survives, int value);
bool is_req_active(enum target_type target,
const struct player *target_player,
@@ -66,4 +84,11 @@
const struct tile *target_tile,
const struct requirement *req);
+int count_buildings_in_range(enum target_type target,
+ const struct player *target_player,
+ const struct city *target_city,
+ Impr_Type_id target_building,
+ enum req_range range, bool survives,
+ Impr_Type_id source);
+
#endif /* FC__REQUIREMENTS_H */
Index: po/POTFILES.in
===================================================================
RCS file: /home/freeciv/CVS/freeciv/po/POTFILES.in,v
retrieving revision 1.81
diff -u -r1.81 POTFILES.in
--- po/POTFILES.in 22 Nov 2004 04:02:07 -0000 1.81
+++ po/POTFILES.in 15 Dec 2004 22:35:58 -0000
@@ -5,6 +5,7 @@
common/map.c
common/packets.c
common/player.c
+common/requirements.c
common/tech.c
common/unit.c
common/unittype.c
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.217
diff -u -r1.217 ruleset.c
--- server/ruleset.c 15 Dec 2004 19:28:44 -0000 1.217
+++ server/ruleset.c 15 Dec 2004 22:36:00 -0000
@@ -1186,7 +1186,7 @@
sec[i], j));
j++) {
Impr_Type_id id;
- enum effect_range range;
+ enum req_range range;
bool survives;
if ((id = find_improvement_by_name(item)) == B_LAST) {
@@ -1200,7 +1200,7 @@
item = secfile_lookup_str_default(file, NULL, "%s.elements%d.range",
sec[i], j);
if (item) {
- if ((range = effect_range_from_str(item)) == EFR_LAST) {
+ if ((range = req_range_from_str(item)) == REQ_RANGE_LAST) {
freelog(LOG_ERROR,
/* TRANS: Obscure ruleset error */
_("Group %s lists bad range: \"%s\" (%s)"),
@@ -1208,7 +1208,7 @@
continue;
}
} else {
- range = EFR_CITY;
+ range = REQ_RANGE_CITY;
}
survives
@@ -1333,7 +1333,7 @@
j++) {
int value;
enum effect_type eff;
- enum effect_range range;
+ enum req_range range;
bool survives;
struct requirement req;
char *req_type, *req_value;
@@ -1350,7 +1350,7 @@
item = secfile_lookup_str_default(file, NULL, "%s.effect%d.range",
sec[i], j);
if (item) {
- if ((range = effect_range_from_str(item)) == EFR_LAST) {
+ if ((range = req_range_from_str(item)) == REQ_RANGE_LAST) {
freelog(LOG_ERROR,
/* TRANS: Obscure ruleset error */
_("Building %s lists bad range: \"%s\" (%s)"),
@@ -1358,7 +1358,7 @@
continue;
}
} else {
- range = EFR_CITY;
+ range = REQ_RANGE_CITY;
}
survives = secfile_lookup_bool_default(file, FALSE,
"%s.effect%d.survives",
@@ -1387,7 +1387,7 @@
sec[i], j);
req_value = secfile_lookup_str_default(file, "", "%s.effect%d.req",
sec[i], j);
- req = req_from_str(req_type, req_value);
+ req = req_from_str(req_type, "", FALSE, req_value);
if (req.type == REQ_LAST) {
/* Error. Log it, clear the req and continue. */
freelog(LOG_ERROR,
|
|