Complete.Org: Mailing Lists: Archives: freeciv-dev: December 2004:
[Freeciv-Dev] (PR#11506) generalized requirements, part 1
Home

[Freeciv-Dev] (PR#11506) generalized requirements, part 1

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#11506) generalized requirements, part 1
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 13 Dec 2004 13:35:55 -0800
Reply-to: bugs@xxxxxxxxxxx

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

See PR#10703 for a full explanation of the design.

This patch takes effect requirements and extracts them into 
requirements.[ch].  Thus we just have a "requirement".  Requirements do 
not have ranges yet (the range is implicit).  I've taken a different 
approach than Marko did in his years-old patch: instead of unifying all 
the reqs of buildings, units, and techs, I've just generalized the reqs 
of effects (which were already pretty generalized).  So one of the next 
steps will be to use these reqs in buildings, units, and techs - which 
should be easy and should give incredible flexibility.

requirements.h shows the basic interface.  It is pretty simple and more 
elegant than the old interface (in effects.h) was.

You might ask why it gets a new file.  Well, there are several reasons. 
  One reason is that none of the existing files is appropriate to put 
this stuff in: unit.c, unittype.c, improvement.c, tech.c, and effects.c 
will probably all use it.  Another reason is that the amount of code in 
this file will grow.  Currently it's only 280 lines but req ranges will 
add greatly to this.  Eventually count_sources_in_range and all of its 
subfunctions should be added here.  Separating all this from the effects 
code is probably a good goal in itself since effects are complicated 
enough as it is - being able to separate this design into layers should 
help people to understand what's going on.

This patch is intended to be committed to the dev branch.

-jason

Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.445
diff -u -r1.445 packhand.c
--- client/packhand.c   13 Dec 2004 16:20:52 -0000      1.445
+++ client/packhand.c   13 Dec 2004 21:20:53 -0000
@@ -2892,8 +2892,16 @@
 **************************************************************************/
 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);
+
   ruleset_cache_add(packet->id, packet->effect_type, packet->range,
                    packet->survives, packet->eff_value,
-                   packet->req_type, packet->req_value, packet->group_id);
+                   &req, packet->group_id);
 }
 
Index: common/Makefile.am
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/Makefile.am,v
retrieving revision 1.53
diff -u -r1.53 Makefile.am
--- common/Makefile.am  5 Sep 2004 20:02:17 -0000       1.53
+++ common/Makefile.am  13 Dec 2004 21:20:53 -0000
@@ -45,6 +45,8 @@
                packets.def     \
                player.c        \
                player.h        \
+               requirements.c  \
+               requirements.h  \
                spaceship.c     \
                spaceship.h     \
                tech.c          \
Index: common/effects.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/effects.c,v
retrieving revision 1.17
diff -u -r1.17 effects.c
--- common/effects.c    28 Nov 2004 15:51:37 -0000      1.17
+++ common/effects.c    13 Dec 2004 21:20:54 -0000
@@ -259,15 +259,6 @@
   number of possible sources increases.
 **************************************************************************/
 
-static const char *req_type_names[] = {
-  "None",
-  "Tech",
-  "Gov",
-  "Building",
-  "Special",
-  "Terrain"
-};
-
 /*
  * A group lists which sources are in it and at what range.
  * Each effect also lists which group it is in.  So an effect is in the
@@ -361,25 +352,6 @@
 }
 
 /**************************************************************************
-  Get requirements type from string.  This is used when loading the
-  ruleset.  REQ_LAST is returned if no other match is found.
-**************************************************************************/
-enum effect_req_type effect_req_type_from_str(const char *str)
-{
-  enum effect_req_type req_type;
-
-  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], str)) {
-      return req_type;
-    }
-  }
-
-  return REQ_LAST;
-}
-
-/**************************************************************************
   Create a new effects group.
 **************************************************************************/
 struct effect_group *effect_group_new(const char *name)
@@ -444,8 +416,6 @@
 {
   int i, j;
 
-  assert(ARRAY_SIZE(req_type_names) == REQ_LAST);
-
   effect_group_list_init(&groups);
   next_group_id = 0;
 
@@ -488,76 +458,11 @@
 }
 
 /**************************************************************************
-  Parse the effect requirement.
-
-  In the effect
-
-    { "name", "value", "equiv", "req_type", "req"
-      "Prod_Bonus", 25, "Generators", "Building", "Factory"
-    }
-
-  the req_type "Building" has already been parsed by req_type_from_str,
-  and the req "Factory" is passed as the req variable here.
-**************************************************************************/
-int parse_effect_requirement(Impr_Type_id source,
-                            enum effect_req_type req_type,
-                            const char *req_value)
-{
-  bool problem;
-  int data = -1;
-  const struct government *pgov;
-
-  switch (req_type) {
-  case REQ_NONE:
-    problem = FALSE;
-    data = 0;
-    break;
-  case REQ_TECH:
-    data = find_tech_by_name(req_value);
-    problem = (A_LAST == data);
-    break;
-  case REQ_GOV:
-    pgov = find_government_by_name(req_value);
-    problem = (NULL == pgov);
-    if (pgov) {
-      data = pgov->index;
-    }
-    break;
-  case REQ_BUILDING:
-    data = find_improvement_by_name(req_value);
-    problem = (B_LAST == data);
-    break;
-  case REQ_SPECIAL:
-    data = get_special_by_name(req_value);
-    problem = (S_NO_SPECIAL == data);
-    break;
-  case REQ_TERRAIN:
-    data = get_terrain_by_name(req_value);
-    problem = (T_UNKNOWN == data);
-    break;
-  default:
-    die("for %s: unimplemented requirement type '%d'",
-       get_improvement_name(source), req_type);
-    return -1;
-  }
-
-  if (problem) {
-    freelog(LOG_ERROR,
-           /* TRANS: Obscure ruleset error. */
-           _("for building %s: bad effect requirement data '%s'"),
-           get_improvement_name(source), req_value);
-    return -1;
-  } else {
-    return data;
-  }
-}
-
-/**************************************************************************
   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 effect_req_type req_type, int req_value,
+                      struct requirement *req,
                       int group_id)
 {
   struct effect *peffect;
@@ -569,29 +474,7 @@
   peffect->value = eff_value;
 
   /* Set effect's requirement data. */
-  peffect->req.type = req_type;
-  switch (req_type) {
-  case REQ_NONE:
-    break;
-  case REQ_TECH:
-    peffect->req.value.tech = req_value;
-    break;
-  case REQ_GOV:
-    peffect->req.value.gov = req_value;
-    break;
-  case REQ_BUILDING:
-    peffect->req.value.building = req_value;
-    break;
-  case REQ_SPECIAL:
-    peffect->req.value.special = req_value;
-    break;
-  case REQ_TERRAIN:
-    peffect->req.value.terrain = req_value;
-    break;
-  case REQ_LAST:
-    assert(0);
-    break;
-  }
+  peffect->req = *req;
 
   /* Find the effect's group. */
   if (group_id >= 0) {
@@ -697,29 +580,7 @@
          packet.group_id = -1;
        }
 
-       switch (packet.req_type) {
-       case REQ_NONE:
-         packet.req_value = 0;
-         break;
-       case REQ_TECH:
-         packet.req_value = peffect->req.value.tech;
-         break;
-       case REQ_GOV:
-         packet.req_value = peffect->req.value.gov;
-         break;
-       case REQ_BUILDING:
-         packet.req_value = peffect->req.value.building;
-         break;
-       case REQ_SPECIAL:
-         packet.req_value = peffect->req.value.special;
-         break;
-       case REQ_TERRAIN:
-         packet.req_value = peffect->req.value.terrain;
-         break;
-       case REQ_LAST:
-         assert(0);
-         break;
-       }
+       packet.req_value = req_get_value(&peffect->req);
 
        lsend_packet_ruleset_cache_effect(dest, &packet);
       } effect_list_iterate_end;
@@ -900,12 +761,12 @@
   the number of available sources.  However not all source caches exist: if
   the cache doesn't exist then we return 0.
 **************************************************************************/
-static 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)
+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;
@@ -998,15 +859,6 @@
   Checks the requirements of the effect to see if it is active on the
   given target. (If the requirements are not met the effect should be
   ignored.)
-
-  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
-
-  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
-  player as well as the city itself as the target city.
 **************************************************************************/
 static bool are_effect_reqs_active(enum target_type target,
                                   const struct player *target_player,
@@ -1016,49 +868,8 @@
                                   Impr_Type_id source,
                                   const struct effect *peffect)
 {
-  /* Note the target may actually not exist.  In particular, effects that
-   * have a REQ_SPECIAL or REQ_TERRAIN may often be passed to this function
-   * with a city as their target.  In this case the requirement is simply
-   * not met. */
-  switch (peffect->req.type) {
-  case REQ_NONE:
-    return TRUE;
-    break;
-  case REQ_TECH:
-    /* The requirement is filled if the player owns the tech. */
-    return target_player && (get_invention(target_player,
-                                          peffect->req.value.tech)
-                            == TECH_KNOWN);
-    break;
-  case REQ_GOV:
-    /* The requirement is filled if the player is using the government. */
-    return target_player && (target_player->government
-                            == peffect->req.value.gov);
-    break;
-  case REQ_BUILDING:
-    /* 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,
-                                  peffect->req.value.building) > 0);
-    break;
-  case REQ_SPECIAL:
-    /* The requirement is filled if the tile has the special. */
-    return target_tile && tile_has_special(target_tile,
-                                          peffect->req.value.special);
-    break;
-  case REQ_TERRAIN:
-    /* The requirement is filled if the tile has the terrain. */
-    return target_tile && (target_tile->terrain
-                          == peffect->req.value.terrain);
-    break;
-  case REQ_LAST:
-    break;
-  }
-
-  assert(0);
-  return FALSE;
+  return is_req_active(target, target_player, target_city, target_building,
+                      target_tile, &peffect->req);
 }
 
 /**************************************************************************
Index: common/effects.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/effects.h,v
retrieving revision 1.11
diff -u -r1.11 effects.h
--- common/effects.h    28 Nov 2004 15:51:38 -0000      1.11
+++ common/effects.h    13 Dec 2004 21:20:55 -0000
@@ -17,6 +17,7 @@
 
 #include "connection.h"
 #include "fc_types.h"
+#include "requirements.h"
 #include "tech.h"
 #include "terrain.h"
 
@@ -140,17 +141,6 @@
   TYPED_VECTOR_ITERATE(enum effect_type, vector, ptype)
 #define effect_type_vector_iterate_end VECTOR_ITERATE_END
 
-/* Effect requirement type. */
-enum effect_req_type {
-  REQ_NONE,
-  REQ_TECH,
-  REQ_GOV,
-  REQ_BUILDING,
-  REQ_SPECIAL,
-  REQ_TERRAIN,
-  REQ_LAST
-};
-
 struct effect_group;
 
 /* An effect is provided by a source.  If the source is present, and the
@@ -178,17 +168,7 @@
 
   /* An effect can have a single requirement.  The effect will only be
    * active if this requirement is met.  The req is one of several types. */
-  struct {
-    enum effect_req_type type;                 /* requirement type */
-
-    union {
-      Tech_Type_id tech;                       /* requirement tech */
-      int gov;                                 /* requirement government */
-      Impr_Type_id building;                   /* requirement building */
-      enum tile_special_type special;          /* requirement special */
-      Terrain_type_id terrain;                 //* requirement terrain type */
-    } value;                                   /* requirement value */
-  } req;
+  struct requirement req;
 };
 
 /* An effect_vector is an array of effects. */
@@ -217,7 +197,7 @@
 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 effect_req_type req_type, int req_value,
+                      struct requirement *req,
                       int group_id);
 void send_ruleset_cache(struct conn_list *dest);
 
@@ -228,24 +208,6 @@
                              enum effect_range range, bool survives);
 int find_effect_group_id(const char *name);
 
-/* name string to value functions */
-enum effect_req_type effect_req_type_from_str(const char *str);
-int parse_effect_requirement(Impr_Type_id source,
-                            enum effect_req_type req_type,
-                            const char *req_value);
-
-/* An effect is targeted at a certain target type.  For instance a
- * production bonus applies to a city (or a tile within a city: same thing).
- * In this case the target is TARGET_CITY.  Note the effect has a range as
- * well: the effect applies to all targets within that range.  So for a
- * TARGET_CITY, EFR_PLAYER effect it applies to all cities owned by the
- * player. */
-enum target_type {
-  TARGET_PLAYER,
-  TARGET_CITY,
-  TARGET_BUILDING 
-};
-
 bool is_effect_useful(enum target_type target,
                      const struct player *target_player,
                      const struct city *target_pcity,
@@ -281,6 +243,12 @@
 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.75
diff -u -r1.75 packets.def
--- common/packets.def  13 Dec 2004 16:20:53 -0000      1.75
+++ common/packets.def  13 Dec 2004 21:20:55 -0000
@@ -180,11 +180,11 @@
 type DIRECTION         = uint8(enum direction8)
 type ORDERS            = uint8(enum unit_orders)
 type SSET_TYPE         = uint8(enum sset_type)
+type REQ_TYPE          = uint8(enum req_type)
 
 # typedefs for effects
 type EFFECT_TYPE       = uint8(enum effect_type)
 type EFFECT_RANGE      = uint8(enum effect_range)
-type EFFECT_REQ_TYPE   = uint8(enum effect_req_type)
 
 # typedefs for IDs
 type PLAYER            = UINT8
@@ -1283,7 +1283,7 @@
   EFFECT_RANGE range;
   BOOL survives;
   SINT32 eff_value;
-  EFFECT_REQ_TYPE req_type;
+  REQ_TYPE req_type;
   SINT32 req_value;
   SINT32 group_id;
 end
Index: common/requirements.c
===================================================================
RCS file: common/requirements.c
diff -N common/requirements.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ common/requirements.c       13 Dec 2004 21:20:55 -0000
@@ -0,0 +1,209 @@
+/********************************************************************** 
+ Freeciv - Copyright (C) 1996-2004 - The Freeciv Project
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+***********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "support.h"
+
+#include "government.h"
+#include "improvement.h"
+#include "map.h"
+#include "requirements.h"
+
+static const char *req_type_names[] = {
+  "None",
+  "Tech",
+  "Gov",
+  "Building",
+  "Special",
+  "Terrain"
+};
+
+/****************************************************************************
+  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;
+  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;
+    }
+  }
+
+  switch (req.type) {
+  case REQ_NONE:
+    return req;
+  case REQ_TECH:
+    req.value.tech = find_tech_by_name(value);
+    if (req.value.tech != A_LAST) {
+      return req;
+    }
+    break;
+  case REQ_GOV:
+    pgov = find_government_by_name(value);
+    if (pgov != NULL) {
+      req.value.gov = pgov->index;
+      return req;
+    }
+    break;
+  case REQ_BUILDING:
+    req.value.building = find_improvement_by_name(value);
+    if (req.value.building != B_LAST) {
+      return req;
+    }
+    break;
+  case REQ_SPECIAL:
+    req.value.special = get_special_by_name(value);
+    if (req.value.special != S_NO_SPECIAL) {
+      return req;
+    }
+    break;
+  case REQ_TERRAIN:
+    req.value.terrain = get_terrain_by_name(value);
+    if (req.value.terrain != T_UNKNOWN) {
+      return req;
+    }
+    break;
+  case REQ_LAST:
+    break;
+  }
+
+  /* If we reach here there's been an error. */
+  req.type = REQ_LAST;
+  return req;
+}
+
+/****************************************************************************
+  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)
+{
+  switch (req->type) {
+  case REQ_NONE:
+    return 0;
+  case REQ_TECH:
+    return req->value.tech;
+  case REQ_GOV:
+    return req->value.gov;
+  case REQ_BUILDING:
+    return req->value.building;
+  case REQ_SPECIAL:
+    return req->value.special;
+  case REQ_TERRAIN:
+    return req->value.terrain;
+  case REQ_LAST:
+    break;
+  }
+
+  assert(0);
+  return 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)
+{
+  switch (req->type) {
+  case REQ_NONE:
+    return;
+  case REQ_TECH:
+    req->value.tech = value;
+    return;
+  case REQ_GOV:
+    req->value.gov = value;
+    return;
+  case REQ_BUILDING:
+    req->value.building = value;
+    return;
+  case REQ_SPECIAL:
+    req->value.special = value;
+    return;
+  case REQ_TERRAIN:
+    req->value.terrain = value;
+    return;
+  case REQ_LAST:
+    return;
+  }
+
+  assert(0);
+}
+
+/****************************************************************************
+  Checks the requirement to see if it is active on the given target.
+
+  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
+
+  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
+  player as well as the city itself as the target city.
+****************************************************************************/
+bool is_req_active(enum target_type target,
+                  const struct player *target_player,
+                  const struct city *target_city,
+                  Impr_Type_id target_building,
+                  const struct tile *target_tile,
+                  const struct requirement *req)
+{
+  /* Note the target may actually not exist.  In particular, effects that
+   * have a REQ_SPECIAL or REQ_TERRAIN may often be passed to this function
+   * with a city as their target.  In this case the requirement is simply
+   * not met. */
+  switch (req->type) {
+  case REQ_NONE:
+    return TRUE;
+  case REQ_TECH:
+    /* The requirement is filled if the player owns the tech. */
+    return target_player && (get_invention(target_player, req->value.tech)
+                            == TECH_KNOWN);
+  case REQ_GOV:
+    /* The requirement is filled if the player is using the government. */
+    return target_player && (target_player->government == req->value.gov);
+  case REQ_BUILDING:
+    /* 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);
+  case REQ_SPECIAL:
+    /* The requirement is filled if the tile has the special. */
+    return target_tile && tile_has_special(target_tile,
+                                          req->value.special);
+  case REQ_TERRAIN:
+    /* The requirement is filled if the tile has the terrain. */
+    return target_tile && (target_tile->terrain
+                          == req->value.terrain);
+  case REQ_LAST:
+    break;
+  }
+
+  assert(0);
+  return FALSE;
+}
Index: common/requirements.h
===================================================================
RCS file: common/requirements.h
diff -N common/requirements.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ common/requirements.h       13 Dec 2004 21:20:55 -0000
@@ -0,0 +1,69 @@
+/********************************************************************** 
+ Freeciv - Copyright (C) 1996-2004 - The Freeciv Project
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+***********************************************************************/
+
+#ifndef FC__REQUIREMENTS_H
+#define FC__REQUIREMENTS_H
+
+#include "fc_types.h"
+#include "tech.h"
+
+/* The type of a requirement. */
+enum req_type {
+  REQ_NONE,
+  REQ_TECH,
+  REQ_GOV,
+  REQ_BUILDING,
+  REQ_SPECIAL,
+  REQ_TERRAIN,
+  REQ_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. */
+enum target_type {
+  TARGET_PLAYER,
+  TARGET_CITY,
+  TARGET_BUILDING 
+};
+
+/* A requirement. This requirement is basically a conditional; it may or
+ * may not be active on a target.  If it is active then something happens.
+ * For instance units and buildings have requirements to be built, techs
+ * have requirements to be researched, and effects have requirements to be
+ * active. */
+struct requirement {
+  enum req_type type;                  /* requirement type */
+
+  union {
+    Tech_Type_id tech;                 /* requirement tech */
+    int gov;                           /* requirement government */
+    Impr_Type_id building;             /* requirement building */
+    enum tile_special_type special;    /* requirement special */
+    Terrain_type_id terrain;           /* requirement terrain type */
+  } 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);
+
+bool is_req_active(enum target_type target,
+                  const struct player *target_player,
+                  const struct city *target_city,
+                  Impr_Type_id target_building,
+                  const struct tile *target_tile,
+                  const struct requirement *req);
+
+#endif  /* FC__REQUIREMENTS_H */
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.215
diff -u -r1.215 ruleset.c
--- server/ruleset.c    8 Dec 2004 16:53:53 -0000       1.215
+++ server/ruleset.c    13 Dec 2004 21:20:57 -0000
@@ -1335,8 +1335,9 @@
        enum effect_type eff;
        enum effect_range range;
        bool survives;
-       enum effect_req_type type;
-       int req, equiv;
+       struct requirement req;
+       char *req_type, *req_value;
+       int equiv;
 
        if ((eff = effect_type_from_str(item)) == EFT_LAST) {
          freelog(LOG_ERROR,
@@ -1382,35 +1383,21 @@
        }
 
        /* Sometimes the ruleset will have to list "" here. */
-       item = secfile_lookup_str_default(file, "", "%s.effect%d.req_type",
-                                         sec[i], j);
-       if (item[0] != '\0') {
-         if ((type = effect_req_type_from_str(item)) == REQ_LAST) {
-           freelog(LOG_ERROR,
-                   /* TRANS: Obscure ruleset error */
-                   _("Building %s has unknown req type: \"%s\" (%s)"),
-                   b->name, item, filename);
-           continue;
-          }
-
-         item = secfile_lookup_str_default(file, NULL, "%s.effect%d.req",
-                                           sec[i], j);
-
-         if (!item) {
-           freelog(LOG_ERROR,
-                   /* TRANS: Obscure ruleset error */
-                   _("Building %s has missing requirement data (%s)"),
-                   b->name, filename);
-           continue;
-         } else {
-           req = parse_effect_requirement(i, type, item);
-         }
-        } else {
-          type = REQ_NONE;
-          req = 0;
-        }
+       req_type = secfile_lookup_str_default(file, "", "%s.effect%d.req_type",
+                                             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);
+       if (req.type == REQ_LAST) {
+         /* Error.  Log it, clear the req and continue. */
+         freelog(LOG_ERROR,
+                 /* TRANS: Obscure ruleset error */
+                 _("Building %s has unknown req: \"%s\" \"%s\" (%s)"),
+                 b->name, req_type, req_value, filename);
+         req.type = REQ_NONE;
+       }
 
-       ruleset_cache_add(i, eff, range, survives, value, type, req, equiv);
+       ruleset_cache_add(i, eff, range, survives, value, &req, equiv);
       }
     }
 

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#11506) generalized requirements, part 1, Jason Short <=