Complete.Org: Mailing Lists: Archives: freeciv-dev: March 2005:
[Freeciv-Dev] Re: (PR#12615) requirements for city styles
Home

[Freeciv-Dev] Re: (PR#12615) requirements for city styles

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] Re: (PR#12615) requirements for city styles
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 24 Mar 2005 11:13:57 -0800
Reply-to: bugs@xxxxxxxxxxx

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

Jason Short wrote:
> <URL: http://bugs.freeciv.org/Ticket/Display.html?id=12615 >
> 
> This patch changes city styles to use requirements (instead of a single 
> tech_req).  This partially fulfills a request by the artists (CapTVK 
> wanted to be able to specialize city styles more).  However since the 
> city style is done per-player only player and world-range requirements 
> may be checked.

Oops, fixed typo.

-jason

Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.480
diff -u -r1.480 packhand.c
--- client/packhand.c   24 Mar 2005 16:41:41 -0000      1.480
+++ client/packhand.c   24 Mar 2005 19:13:04 -0000
@@ -2502,7 +2502,7 @@
 **************************************************************************/
 void handle_ruleset_city(struct packet_ruleset_city *packet)
 {
-  int id;
+  int id, j;
   struct citystyle *cs;
 
   id = packet->style_id;
@@ -2513,7 +2513,12 @@
   }
   cs = &city_styles[id];
   
-  cs->techreq = packet->techreq;
+  for (j = 0; j < MAX_NUM_REQS; j++) {
+    cs->req[j] = req_from_values(packet->req_type[j],
+                                packet->req_range[j],
+                                packet->req_survives[j],
+                                packet->req_value[j]);
+  }
   cs->replaced_by = packet->replaced_by;
 
   sz_strlcpy(cs->name_orig, packet->name);
Index: client/gui-gtk-2.0/dialogs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/dialogs.c,v
retrieving revision 1.93
diff -u -r1.93 dialogs.c
--- client/gui-gtk-2.0/dialogs.c        21 Mar 2005 16:37:52 -0000      1.93
+++ client/gui-gtk-2.0/dialogs.c        24 Mar 2005 19:13:04 -0000
@@ -1756,7 +1756,7 @@
     SPRITE *s;
     GtkTreeIter it;
 
-    if (city_styles[i].techreq != A_NONE) {
+    if (city_style_has_requirements(&city_styles[i])) {
       continue;
     }
 
@@ -2010,7 +2010,7 @@
       /* Select city style for chosen nation. */
       cs = get_nation_city_style(selected_nation);
       for (i = 0, j = 0; i < game.styles_count; i++) {
-        if (city_styles[i].techreq != A_NONE) {
+        if (city_style_has_requirements(&city_styles[i])) {
          continue;
        }
 
Index: common/city.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.c,v
retrieving revision 1.320
diff -u -r1.320 city.c
--- common/city.c       24 Mar 2005 16:41:41 -0000      1.320
+++ common/city.c       24 Mar 2005 19:13:05 -0000
@@ -663,24 +663,12 @@
 bool city_can_use_specialist(const struct city *pcity,
                             Specialist_type_id type)
 {
-  int i;
-
   if (pcity->size < game.rgame.specialists[type].min_size) {
     return FALSE;
   }
 
-  for (i = 0; i < MAX_NUM_REQS; i++) {
-    struct requirement *req = &game.rgame.specialists[type].req[i];
-
-    if (req->source.type == REQ_NONE) {
-      break; /* Short-circuit any more checks. */
-    } else if (!is_req_active(TARGET_CITY, city_owner(pcity), pcity,
-                             B_LAST, NULL, req)) {
-      return FALSE;
-    }
-  }
-
-  return TRUE;
+  return are_reqs_active(TARGET_CITY, city_owner(pcity), pcity, B_LAST, NULL,
+                        game.rgame.specialists[type].req, MAX_NUM_REQS);
 }
 
 /**************************************************************************
@@ -1257,7 +1245,8 @@
 
   while ((replace = city_styles[prev].replaced_by) != -1) {
     prev = replace;
-    if (get_invention(plr, city_styles[replace].techreq) == TECH_KNOWN) {
+    if (are_reqs_active(TARGET_PLAYER, plr, NULL, B_LAST, NULL,
+                       city_styles[replace].req, MAX_NUM_REQS)) {
       style = replace;
     }
   }
@@ -1319,6 +1308,15 @@
    return city_styles[style].name_orig;
 }
 
+/****************************************************************************
+  Return whether the style has any requirements.  Styles without requirements
+  are special cases since only these may be used as starting city styles.
+****************************************************************************/
+bool city_style_has_requirements(const struct citystyle *style)
+{
+  return style->req[0].source.type != REQ_NONE;
+}
+
 /**************************************************************************
  Compute and optionally apply the change-production penalty for the given
  production change (to target,is_unit) in the given city (pcity).
Index: common/city.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.h,v
retrieving revision 1.202
diff -u -r1.202 city.h
--- common/city.h       8 Mar 2005 00:43:26 -0000       1.202
+++ common/city.h       24 Mar 2005 19:13:05 -0000
@@ -321,7 +321,7 @@
   char graphic_alt[MAX_LEN_NAME];
   char citizens_graphic[MAX_LEN_NAME];
   char citizens_graphic_alt[MAX_LEN_NAME];
-  int techreq;                  /* tech required to use a style      */
+  struct requirement req[MAX_NUM_REQS];
   int replaced_by;              /* index to replacing style          */
                                 /* client side-only:                 */
   int tresh[MAX_CITY_TILES];    /* treshholds - what city size to use a tile */
@@ -469,6 +469,7 @@
 int get_style_by_name_orig(const char *);
 const char *get_city_style_name(int style);
 char* get_city_style_name_orig(int style);
+bool city_style_has_requirements(const struct citystyle *style);
 
 struct city *is_enemy_city_tile(const struct tile *ptile,
                                const struct player *pplayer);
Index: common/packets.def
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v
retrieving revision 1.98
diff -u -r1.98 packets.def
--- common/packets.def  24 Mar 2005 16:41:41 -0000      1.98
+++ common/packets.def  24 Mar 2005 19:13:05 -0000
@@ -1123,10 +1123,13 @@
 
 PACKET_RULESET_CITY=103;sc,lsend
   UINT8 style_id; 
-  UINT8 techreq;
   STRING name[MAX_LEN_NAME];
   STRING citizens_graphic[MAX_LEN_NAME];
   STRING citizens_graphic_alt[MAX_LEN_NAME];
+  UINT8 req_type[MAX_NUM_REQS];
+  UINT8 req_range[MAX_NUM_REQS];
+  UINT8 req_value[MAX_NUM_REQS];
+  BOOL req_survives[MAX_NUM_REQS];
   STRING graphic[MAX_LEN_NAME];
   STRING graphic_alt[MAX_LEN_NAME];
   SINT8 replaced_by;
Index: common/requirements.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/requirements.c,v
retrieving revision 1.6
diff -u -r1.6 requirements.c
--- common/requirements.c       23 Mar 2005 02:07:44 -0000      1.6
+++ common/requirements.c       24 Mar 2005 19:13:05 -0000
@@ -614,3 +614,39 @@
   assert(0);
   return FALSE;
 }
+
+/****************************************************************************
+  Checks the requirement(s) to see if they are active on the given target.
+
+  target gives the type of the target
+  (player,city,building,tile) give the exact target
+
+  reqs gives the requirement array; num_reqs is the size of the array.  This
+  array may be REQ_NONE-terminated, otherwise all requirements in it will
+  be checked.  The function returns TRUE only if all requirements are active.
+
+  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 are_reqs_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 *reqs, int num_reqs)
+{
+  int i;
+
+  for (i = 0; i < num_reqs; i++) {
+    if (reqs[i].source.type == REQ_NONE) {
+      break; /* Short-circuit any more checks. */
+    } else if (!is_req_active(target, target_player, target_city,
+                             target_building, target_tile,
+                             &reqs[i])) {
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
Index: common/requirements.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/requirements.h,v
retrieving revision 1.4
diff -u -r1.4 requirements.h
--- common/requirements.h       23 Mar 2005 02:07:44 -0000      1.4
+++ common/requirements.h       24 Mar 2005 19:13:05 -0000
@@ -81,6 +81,13 @@
   TYPED_LIST_ITERATE(struct requirement, req_list, preq)
 #define requirement_list_iterate_end LIST_ITERATE_END
 
+#define SPECVEC_TAG requirement
+#define SPECVEC_TYPE struct requirement
+#include "specvec.h"
+#define requirement_vector_iterate(req_vec, preq) \
+  TYPED_VECTOR_ITERATE(struct requirement, req_vec, preq)
+#define requirement_vector_iterate_end VECTOR_ITERATE_END
+
 struct req_source req_source_from_str(const char *type, const char *value);
 struct req_source req_source_from_values(int type, int value);
 void req_source_get_values(struct req_source *source, int *type, int *value);
@@ -100,6 +107,12 @@
                   Impr_Type_id target_building,
                   const struct tile *target_tile,
                   const struct requirement *req);
+bool are_reqs_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 *reqs, int num_reqs);
 
 int count_buildings_in_range(enum target_type target,
                             const struct player *target_player,
Index: data/default/cities.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/default/cities.ruleset,v
retrieving revision 1.14
diff -u -r1.14 cities.ruleset
--- data/default/cities.ruleset 8 Dec 2004 16:53:53 -0000       1.14
+++ data/default/cities.ruleset 24 Mar 2005 19:13:05 -0000
@@ -48,7 +48,7 @@
 ;               more info on city tiles
 ; citizens_graphic     = group of citizens tiles to use, see citizens/small
 ;                        spec for more info on citizens tiles
-; tech        = technology required for style to be used
+; reqs        = requirements for this city style (see README.effects)
 ; replaced_by = which style replaced this one
 
 [citystyle_european]
@@ -57,7 +57,7 @@
 graphic_alt = "-"
 citizens_graphic     = "ancient"
 citizens_graphic_alt = "generic"
-tech        = "None"
+; No reqs
 replaced_by = "Renaissance"
 
 [citystyle_classical]
@@ -66,7 +66,7 @@
 graphic_alt = "-"
 citizens_graphic     = "ancient"
 citizens_graphic_alt = "generic"
-tech        = "None"
+; No reqs
 replaced_by = "Renaissance"
 
 [citystyle_tropical]
@@ -75,7 +75,7 @@
 graphic_alt = "city.european"
 citizens_graphic     = "ancient"
 citizens_graphic_alt = "generic"
-tech        = "None"
+; No reqs
 replaced_by = "Renaissance"
 
 [citystyle_asian]
@@ -84,7 +84,7 @@
 graphic_alt = "city.classical"
 citizens_graphic     = "ancient"
 citizens_graphic_alt = "generic"
-tech        = "None"
+; No reqs
 replaced_by = "Renaissance"
 
 [citystyle_renaissance]
@@ -93,7 +93,9 @@
 graphic_alt = "-"
 citizens_graphic     = "renaissance"
 citizens_graphic_alt = "generic"
-tech        = "University"
+reqs = { "type", "name", "range"
+         "tech", "University", "Player"
+       }
 replaced_by = "Industrial"
 
 [citystyle_industrial]
@@ -102,7 +104,9 @@
 graphic_alt = "-"
 citizens_graphic     = "industrial"
 citizens_graphic_alt = "generic"
-tech        = "Railroad"
+reqs = { "type", "name", "range"
+         "tech", "Railroad", "Player"
+       }
 replaced_by = "Modern"
 
 [citystyle_modern]
@@ -111,7 +115,9 @@
 graphic_alt = "-"
 citizens_graphic     = "modern"
 citizens_graphic_alt = "generic"
-tech        = "Automobile"
+reqs = { "type", "name", "range"
+         "tech", "Automobile", "Player"
+       }
 replaced_by = "PostModern"
 
 [citystyle_postmodern]
@@ -120,5 +126,7 @@
 graphic_alt = "-"
 citizens_graphic     = "postmodern"
 citizens_graphic_alt = "generic"
-tech        = "Superconductors"
+reqs = { "type", "name", "range"
+         "tech", "Superconductors", "Player"
+       }
 replaced_by = "-"
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.235
diff -u -r1.235 ruleset.c
--- server/ruleset.c    24 Mar 2005 16:41:42 -0000      1.235
+++ server/ruleset.c    24 Mar 2005 19:13:06 -0000
@@ -195,6 +195,52 @@
   return datafile_options;
 }
 
+/**************************************************************************
+  Load a requirement list.  The list is returned as a static vector
+  (callers need not worry about freeing anything).
+**************************************************************************/
+static struct requirement_vector *lookup_req_list(struct section_file *file,
+                                                 const char *sec,
+                                                 const char *sub)
+{
+  char *type, *name;
+  int j;
+  const char *filename;
+  static struct requirement_vector list;
+
+  filename = secfile_filename(file);
+
+  requirement_vector_reserve(&list, 0);
+
+  for (j = 0;
+      (type = secfile_lookup_str_default(file, NULL, "%s.%s%d.type",
+                                        sec, sub, j));
+      j++) {
+    char *range;
+    bool survives;
+    struct requirement req;
+
+    name = secfile_lookup_str(file, "%s.%s%d.name", sec, sub, j);
+    range = secfile_lookup_str(file, "%s.%s%d.range", sec, sub, j);
+
+    survives = secfile_lookup_bool_default(file, FALSE,
+       "%s.%s%d.survives", sec, sub, j);
+
+    req = req_from_str(type, range, survives, name);
+    if (req.source.type == REQ_LAST) {
+      /* Error.  Log it, clear the req and continue. */
+      freelog(LOG_ERROR,
+         /* TRANS: Obscure ruleset error */
+         _("Section %s has unknown req: \"%s\" \"%s\" (%s)"),
+         sec, type, name, filename);
+      req.source.type = REQ_NONE;
+    }
+
+    requirement_vector_append(&list, &req);
+  }
+
+  return &list;
+}
 
 /**************************************************************************
  Lookup a string prefix.entry in the file and return the corresponding
@@ -2097,7 +2143,7 @@
       pl->city_style = 0;
     }
 
-    while (city_styles[pl->city_style].techreq != A_NONE) {
+    while (city_styles[pl->city_style].req[0].source.type != REQ_NONE) {
       if (pl->city_style == 0) {
        freelog(LOG_FATAL,
               "Nation %s: the default city style is not available "
@@ -2223,7 +2269,7 @@
 static void load_ruleset_cities(struct section_file *file)
 {
   char **styles, *replacement;
-  int i, nval;
+  int i, nval, j;
   const char *filename = secfile_filename(file);
   char **specialist_names;
 
@@ -2320,6 +2366,8 @@
 
   /* Get rest: */
   for( i=0; i<game.styles_count; i++) {
+    struct requirement_vector *reqs;
+
     sz_strlcpy(city_styles[i].graphic, 
               secfile_lookup_str(file, "%s.graphic", styles[i]));
     sz_strlcpy(city_styles[i].graphic_alt, 
@@ -2330,9 +2378,17 @@
     sz_strlcpy(city_styles[i].citizens_graphic_alt, 
               secfile_lookup_str_default(file, "generic", 
                        "%s.citizens_graphic_alt", styles[i]));
-    city_styles[i].techreq = lookup_tech(file, styles[i], "tech", TRUE,
-                                         filename, city_styles[i].name);
-    
+
+    reqs = lookup_req_list(file, styles[i], "reqs");
+    for (j = 0; j < MAX_NUM_REQS; j++) {
+      if (reqs->size > j) {
+       city_styles[i].req[j] = reqs->p[j];
+      } else {
+       city_styles[i].req[j].source.type = REQ_NONE;
+       memset(&city_styles[i].req[j], 0, sizeof(city_styles[i].req[j]));
+      }
+    }
+
     replacement = secfile_lookup_str(file, "%s.replaced_by", styles[i]);
     if( strcmp(replacement, "-") == 0) {
       city_styles[i].replaced_by = -1;
@@ -2352,52 +2408,6 @@
 }
 
 /**************************************************************************
-Load effects requirement list.
-**************************************************************************/
-static void load_req_list(struct section_file *file,
-                         const char *sec, const char *sub,
-                         bool neg, struct effect *peffect)
-{
-  char *type, *name;
-  int j;
-  const char *filename;
-
-  filename = secfile_filename(file);
-
-  for (j = 0;
-      (type = secfile_lookup_str_default(file, NULL, "%s.%s%d.type",
-                                        sec, sub, j));
-      j++) {
-    char *range;
-    bool survives;
-    struct requirement req;
-
-    name = secfile_lookup_str(file, "%s.%s%d.name", sec, sub, j);
-    range = secfile_lookup_str(file, "%s.%s%d.range", sec, sub, j);
-
-    survives = secfile_lookup_bool_default(file, FALSE,
-       "%s.%s%d.survives", sec, sub, j);
-
-    req = req_from_str(type, range, survives, name);
-    if (req.source.type == REQ_LAST) {
-      /* Error.  Log it, clear the req and continue. */
-      freelog(LOG_ERROR,
-         /* TRANS: Obscure ruleset error */
-         _("Section %s has unknown req: \"%s\" \"%s\" (%s)"),
-         sec, type, name, filename);
-      req.source.type = REQ_NONE;
-    } else {
-      struct requirement *preq;
-
-      preq = fc_malloc(sizeof(*preq));
-      *preq = req;
-
-      effect_req_append(peffect, neg, preq);
-    }
-  }
-}
-
-/**************************************************************************
 Load effects.ruleset file
 **************************************************************************/
 static void load_ruleset_effects(struct section_file *file)
@@ -2431,8 +2441,18 @@
 
     peffect = effect_new(eff, value);
 
-    load_req_list(file, sec[i], "reqs", FALSE, peffect);
-    load_req_list(file, sec[i], "nreqs", TRUE, peffect);
+    requirement_vector_iterate(lookup_req_list(file, sec[i], "reqs"), req) {
+      struct requirement *preq = fc_malloc(sizeof(*preq));
+
+      *preq = *req;
+      effect_req_append(peffect, FALSE, preq);
+    } requirement_vector_iterate_end;
+    requirement_vector_iterate(lookup_req_list(file, sec[i], "nreqs"), req) {
+      struct requirement *preq = fc_malloc(sizeof(*preq));
+
+      *preq = *req;
+      effect_req_append(peffect, TRUE, preq);
+    } requirement_vector_iterate_end;
   }
   free(sec);
 
@@ -2933,13 +2953,20 @@
 static void send_ruleset_cities(struct conn_list *dest)
 {
   struct packet_ruleset_city city_p;
-  int k;
+  int k, j;
 
   for( k=0; k<game.styles_count; k++) {
     city_p.style_id = k;
-    city_p.techreq = city_styles[k].techreq;
     city_p.replaced_by = city_styles[k].replaced_by;
 
+    for (j = 0; j < MAX_NUM_REQS; j++) {
+      req_get_values(&city_styles[k].req[j],
+                    &city_p.req_type[j],
+                    &city_p.req_range[j],
+                    &city_p.req_survives[j],
+                    &city_p.req_value[j]);
+    }
+
     sz_strlcpy(city_p.name, city_styles[k].name_orig);
     sz_strlcpy(city_p.graphic, city_styles[k].graphic);
     sz_strlcpy(city_p.graphic_alt, city_styles[k].graphic_alt);
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.236
diff -u -r1.236 srv_main.c
--- server/srv_main.c   22 Mar 2005 04:03:35 -0000      1.236
+++ server/srv_main.c   24 Mar 2005 19:13:06 -0000
@@ -1166,8 +1166,8 @@
   
   /* check sanity of the packet sent by client */
   if (nation_no < 0 || nation_no >= game.nation_count ||
-      city_style < 0 || city_style >= game.styles_count ||
-      city_styles[city_style].techreq != A_NONE
+      city_style < 0 || city_style >= game.styles_count
+      || city_style_has_requirements(&city_styles[city_style])
       || !nations_available[nation_no]) {
     return;
   }

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] Re: (PR#12615) requirements for city styles, Jason Short <=