Complete.Org: Mailing Lists: Archives: freeciv-dev: May 2004:
[Freeciv-Dev] (PR#8754) effects patch v3
Home

[Freeciv-Dev] (PR#8754) effects patch v3

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#8754) effects patch v3
From: "Vasco Alexandre da Silva Costa" <vasc@xxxxxxxxxxxxxx>
Date: Fri, 21 May 2004 15:36:23 -0700
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=8754 >

Here is the latest version of the effects patch, plus the changes
necessary to implement several building effects for reference, all in one.

diff -Nurd -X diff_ignore freecvs/client/packhand.c freeciv/client/packhand.c
--- freecvs/client/packhand.c   2004-05-21 20:28:19.960223568 +0100
+++ freeciv/client/packhand.c   2004-05-21 23:34:43.750029088 +0100
@@ -25,6 +25,7 @@
 
 #include "capability.h"
 #include "capstr.h"
+#include "eff.h"
 #include "events.h"
 #include "fcintl.h"
 #include "game.h"
@@ -2098,6 +2099,8 @@
   tilespec_free_city_tiles(game.styles_count);
   ruleset_data_free();
 
+  eff_hash_init();
+
   game.aqueduct_size = packet->aqueduct_size;
   game.sewer_size = packet->sewer_size;
   game.add_to_size_limit = packet->add_to_size_limit;
@@ -2934,3 +2937,31 @@
 {
   freelog(LOG_VERBOSE, "server shutdown");
 }
+
+/**************************************************************************
+...
+**************************************************************************/
+void handle_eff_hash_group(char *name, enum effect_type eff,
+                          int num_buildings, Impr_Type_id *buildings)
+{
+  struct eff_group *pgroup;
+  int i;
+
+  pgroup = eff_group_new(name, eff);
+
+  for (i = 0; i < num_buildings; i++) {
+    struct impr_type *bldg = get_improvement_type(buildings[i]);
+
+    eff_group_add(pgroup, bldg->name);
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void handle_eff_hash_effect(struct packet_eff_hash_effect *packet)
+{
+  eff_hash_add(packet->id, packet->eff, packet->op, packet->value,
+              packet->req, packet->arg, packet->group);
+}
+
diff -Nurd -X diff_ignore freecvs/common/city.c freeciv/common/city.c
--- freecvs/common/city.c       2004-05-21 20:28:20.452148784 +0100
+++ freeciv/common/city.c       2004-05-21 23:34:44.370934696 +0100
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <string.h>
 
+#include "eff.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
@@ -49,7 +50,7 @@
 /* end helper functions for generic_city_refresh */
 
 static int improvement_upkeep_asmiths(struct city *pcity, Impr_Type_id i,
-                                     bool asmiths);
+                                     int asmiths);
 
 /* Iterate a city map, from the center (the city) outwards */
 
@@ -491,8 +492,8 @@
     return 0;
   if (is_wonder(i))
     return 0;
-  if (improvement_types[i].upkeep == 1 &&
-      city_affected_by_wonder(pcity, B_ASMITHS)) 
+  if (improvement_types[i].upkeep <=
+      get_city_bonus(pcity, EFT_UPKEEP_FREE))
     return 0;
   if (government_has_flag(get_gov_pcity(pcity), G_CONVERT_TITHES_TO_MONEY)
       && (i == B_TEMPLE || i == B_COLOSSEUM || i == B_CATHEDRAL)) {
@@ -506,13 +507,13 @@
   Caller to pass asmiths = city_affected_by_wonder(pcity, B_ASMITHS)
 **************************************************************************/
 static int improvement_upkeep_asmiths(struct city *pcity, Impr_Type_id i,
-                                     bool asmiths)
+                                     int asmiths)
 {
   if (!improvement_exists(i))
     return 0;
   if (is_wonder(i))
     return 0;
-  if (asmiths && improvement_types[i].upkeep == 1) 
+  if (improvement_types[i].upkeep <= asmiths) 
     return 0;
   if (government_has_flag(get_gov_pcity(pcity), G_CONVERT_TITHES_TO_MONEY)
       && (i == B_TEMPLE || i == B_COLOSSEUM || i == B_CATHEDRAL)) {
@@ -531,6 +532,7 @@
 {
   enum tile_special_type spec_t = map_get_special(map_x, map_y);
   enum tile_terrain_type tile_t = map_get_terrain(map_x, map_y);
+  struct tile *ptile = map_get_tile(map_x, map_y);
   int s;
 
   if (contains_special(spec_t, S_SPECIAL_1)) {
@@ -554,12 +556,7 @@
     int before_penalty = (is_celebrating ? g->celeb_shields_before_penalty
                          : g->shields_before_penalty);
 
-    if (city_affected_by_wonder(pcity, B_RICHARDS)) {
-      s++;
-    }
-    if (is_ocean(tile_t) && city_got_building(pcity, B_OFFSHORE)) {
-      s++;
-    }
+    s += get_city_tile_bonus(pcity, ptile, EFT_PROD_ADD_TILE);
 
     /* government shield bonus & penalty */
     if (s > 0) {
@@ -635,6 +632,7 @@
 {
   enum tile_special_type spec_t = map_get_special(map_x, map_y);
   enum tile_terrain_type tile_t = map_get_terrain(map_x, map_y);
+  struct tile *ptile = map_get_tile(map_x, map_y);
   int t;
 
   if (contains_special(spec_t, S_SPECIAL_1)) {
@@ -667,14 +665,8 @@
        t += (is_celebrating ? g->celeb_trade_bonus : g->trade_bonus);
       }
 
-      if (city_affected_by_wonder(pcity, B_COLLOSSUS)) {
-       t++;
-      }
-
-      if (contains_special(spec_t, S_ROAD)
-         && city_got_building(pcity, B_SUPERHIGHWAYS)) {
-       t += (t * terrain_control.road_superhighway_trade_bonus) / 100;
-      }
+      t += get_city_bonus(pcity, EFT_TRADE_INC_TILE);
+      t += (t * get_city_tile_bonus(pcity, ptile, EFT_TRADE_PER_TILE)) / 100;
 
       /* government trade penalty -- SKi */
       if (before_penalty > 0 && t > before_penalty) {
@@ -749,6 +741,7 @@
   const enum tile_special_type spec_t = map_get_special(map_x, map_y);
   const enum tile_terrain_type tile_t = map_get_terrain(map_x, map_y);
   struct tile_type *type = get_tile_type(tile_t);
+  struct tile *ptile = map_get_tile(map_x, map_y);
   int f;
   const bool auto_water = (pcity && is_city_center(city_x, city_y)
                           && tile_t == type->irrigation_result
@@ -787,9 +780,7 @@
     int before_penalty = (is_celebrating ? g->celeb_food_before_penalty
                          : g->food_before_penalty);
 
-    if (is_ocean(tile_t) && city_got_building(pcity, B_HARBOUR)) {
-      f++;
-    }
+    f += get_city_tile_bonus(pcity, ptile, EFT_FOOD_ADD_TILE);
 
     if (f > 0) {
       f += (is_celebrating ? g->celeb_food_bonus : g->food_bonus);
@@ -1044,11 +1035,11 @@
 *************************************************************************/
 int city_gold_surplus(struct city *pcity)
 {
-  bool asmiths = city_affected_by_wonder(pcity, B_ASMITHS);
   int cost = 0;
 
   built_impr_iterate(pcity, i) {
-    cost += improvement_upkeep_asmiths(pcity, i, asmiths);
+    cost += improvement_upkeep_asmiths(pcity, i,
+       get_city_bonus(pcity, EFT_UPKEEP_FREE));
   } built_impr_iterate_end;
 
   unit_list_iterate(pcity->units_supported, punit) {
@@ -1104,47 +1095,18 @@
    * Otherwise the player who owns the city needs to have it to
    * get the effect.
    */
-  if (id==B_MANHATTEN) 
-    return (game.global_wonders[id] != 0);
-  
   tmp = player_find_city_by_id(city_owner(pcity), game.global_wonders[id]);
   if (!tmp)
     return FALSE;
-  switch (id) {
-  case B_ASMITHS:
-  case B_APOLLO:
-  case B_CURE:
-  case B_GREAT:
-  case B_WALL:
-  case B_HANGING:
-  case B_ORACLE:
-  case B_UNITED:
-  case B_WOMENS:
-  case B_DARWIN:
-  case B_LIGHTHOUSE:
-  case B_MAGELLAN:
-  case B_MICHELANGELO:
-  case B_SETI:
-  case B_PYRAMIDS:
-  case B_LIBERTY:
-  case B_SUNTZU:
-    return TRUE;
-  case B_ISAAC:
-  case B_COPERNICUS:
-  case B_SHAKESPEARE:
-  case B_COLLOSSUS:
-  case B_RICHARDS:
-    return FALSE;
-  case B_HOOVER:
-  case B_BACH:
-    if (improvement_variant(id)==1) {
+
+  switch (get_improvement_type(id)->equiv_range) {
+    case IR_PLAYER:
+      return TRUE;
+    case IR_ISLAND:
       return (map_get_continent(tmp->x, tmp->y) ==
              map_get_continent(pcity->x, pcity->y));
-    } else {
-      return TRUE;
-    }
-  default:
-    return FALSE;
+    default:
+      return FALSE;
   }
 }
 
@@ -1619,23 +1581,7 @@
 **************************************************************************/
 int get_city_shield_bonus(struct city *pcity)
 {
-  int shield_bonus = 100;
-
-  if (city_got_building(pcity, B_FACTORY)) {
-    shield_bonus += 50;
-    if (city_got_building(pcity, B_MFG)) {
-      shield_bonus += 50;
-    }
-
-    if (city_affected_by_wonder(pcity, B_HOOVER) ||
-       city_got_building(pcity, B_POWER) ||
-       city_got_building(pcity, B_HYDRO) ||
-       city_got_building(pcity, B_NUCLEAR)) {
-      shield_bonus = 100 + (3 * (shield_bonus - 100)) / 2;
-    }
-  }
-
-  return shield_bonus;
+  return (100 + get_city_bonus(pcity, EFT_PROD_BONUS));
 }
 
 /**************************************************************************
@@ -1644,19 +1590,7 @@
 **************************************************************************/
 int get_city_tax_bonus(struct city *pcity)
 {
-  int tax_bonus = 100;
-
-  if (city_got_building(pcity, B_MARKETPLACE)) {
-    tax_bonus += 50;
-    if (city_got_building(pcity, B_BANK)) {
-      tax_bonus += 50;
-      if (city_got_building(pcity, B_STOCK)) {
-       tax_bonus += 50;
-      }
-    }
-  }
-
-  return tax_bonus;
+  return (100 + get_city_bonus(pcity, EFT_TAX_BONUS));
 }
 
 /**************************************************************************
@@ -1690,23 +1624,10 @@
 **************************************************************************/
 int get_city_science_bonus(struct city *pcity)
 {
-  int science_bonus = 100;
+  int science_bonus;
+
+  science_bonus = 100 + get_city_bonus(pcity, EFT_SCIENCE_BONUS);
 
-  if (city_got_building(pcity, B_LIBRARY)) {
-    science_bonus += 50;
-    if (city_got_building(pcity, B_UNIVERSITY)) {
-      science_bonus += 50;
-    }
-    if (city_got_effect(pcity, B_RESEARCH)) {
-      science_bonus += 50;
-    }
-  }
-  if (city_affected_by_wonder(pcity, B_COPERNICUS)) {
-    science_bonus += 50;
-  }
-  if (city_affected_by_wonder(pcity, B_ISAAC)) {
-    science_bonus += 100;
-  }
   if (government_has_flag(get_gov_pcity(pcity), G_REDUCED_RESEARCH)) {
     science_bonus /= 2;
   }
@@ -1957,21 +1878,11 @@
 **************************************************************************/
 static void citizen_happy_buildings(struct city *pcity)
 {
-  struct government *g = get_gov_pcity(pcity);
   int faces = 0;
   happy_copy(pcity, 1);
 
-  if (city_got_building(pcity, B_TEMPLE)) {
-    faces += get_temple_power(pcity);
-  }
-  if (city_got_building(pcity, B_COURTHOUSE) && g->corruption_level == 0) {
-    faces++;
-  }
+  faces += get_city_bonus(pcity, EFT_MAKE_CONTENT);
 
-  if (city_got_building(pcity, B_COLOSSEUM))
-    faces += get_colosseum_power(pcity);
-  if (city_got_effect(pcity, B_CATHEDRAL))
-    faces += get_cathedral_power(pcity);
   /* make people content (but not happy):
      get rid of angry first, then make unhappy content. */
   while (faces > 0 && pcity->ppl_angry[2] > 0) {
@@ -2001,14 +1912,13 @@
 **************************************************************************/
 static void citizen_happy_wonders(struct city *pcity)
 {
-  int bonus = 0;
+  int bonus = 0, mod;
 
   happy_copy(pcity, 3);
 
-  if (city_affected_by_wonder(pcity, B_HANGING)) {
-    bonus += 1;
-    if (city_got_building(pcity, B_HANGING))
-      bonus += 2;
+  if ((mod = get_city_bonus(pcity, EFT_MAKE_HAPPY)) > 0) {
+    bonus += mod;
+
     while (bonus > 0 && pcity->ppl_content[4] > 0) {
       pcity->ppl_content[4]--;
       pcity->ppl_happy[4]++;
@@ -2017,10 +1927,9 @@
          will let it make unhappy content */
     }
   }
-  if (city_affected_by_wonder(pcity, B_BACH))
-    bonus += 2;
-  if (city_affected_by_wonder(pcity, B_CURE))
-    bonus += 1;
+
+  bonus += get_city_bonus(pcity, EFT_FORCE_CONTENT);
+
   /* get rid of angry first, then make unhappy content */
   while (bonus > 0 && pcity->ppl_angry[4] > 0) {
     pcity->ppl_angry[4]--;
diff -Nurd -X diff_ignore freecvs/common/eff.c freeciv/common/eff.c
--- freecvs/common/eff.c        1970-01-01 01:00:00.000000000 +0100
+++ freeciv/common/eff.c        2004-05-21 23:33:09.496357824 +0100
@@ -0,0 +1,977 @@
+/**********************************************************************
+ Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
+   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 <ctype.h>
+
+#include "eff.h"
+
+#include "log.h"
+
+#include "map.h"
+#include "shared.h"
+#include "support.h"
+#include "improvement.h"
+#include "city.h"
+#include "player.h"
+#include "government.h"
+ 
+#include "packets.h"
+
+
+/**************************************************************************
+  The code creates an effects hash on ruleset load. This constant effects
+  hash is used to speed up all effects queries. There is no further memory
+  allocation or de-allocation by any of the code after hash creation.
+
+  Since the hash is constant, the server only needs to send effects data to
+  the client upon connect. It also means that an AI can do fast searches in
+  the effects space by trying the possible combinations of addition or
+  removal of buildings with the effects it cares about, like is done in the
+  existing code.
+
+
+  To know how much a target is being affected, simply use the convenience
+  functions:
+
+  * get_player_everlasting_bonus
+  * get_player_bonus
+  * get_city_bonus
+  * get_city_building_bonus
+  * get_city_tile_bonus
+
+  These functions require as arguments the target and the effect type to be
+  queried.
+
+  Improvements and wonders are unique and in a well known place in the
+  data structures. This allows lots of optimizations in the code.
+
+
+  === Future extensions:
+  The uniqueness aspect of a building is not as important as it being in a
+  well known place. Since a wonder is in a well known place, i.e.
+  game.global_wonders[], it is easy to find out if something is affected by
+  it or not.
+
+  This could easily be extended by turning game.global_wonders[] into a list
+  of lists of pointers to places of buildings, i.e. game.buildings[].
+
+  To add small wonder and satellite support, you can simply add a similar
+  player.buildings[] list.
+
+  These extensions would allow buildings with global and player range
+  without hard limitations in uniqueness, or type whatsoever.
+
+  The actual range of a building is separate.
+
+  Since this means one always knows where to look for a building, we
+  can have very fast queries on effects that will scale well with complex
+  effects.
+**************************************************************************/
+struct effect {
+  enum op_type op;
+  int value;
+
+  enum req_type type;
+  union {
+    Tech_Type_id tech;
+    struct government *gov;
+    Impr_Type_id building;
+    Impr_Type_id wonder;
+    enum tile_special_type special;
+    enum tile_terrain_type terrain;
+  } req;
+};
+
+#define SPECLIST_TAG eff
+#define SPECLIST_TYPE struct effect
+#include "speclist.h"
+
+#define eff_list_iterate(list, elt) \
+TYPED_LIST_ITERATE(struct effect, list, elt)
+#define eff_list_iterate_end  LIST_ITERATE_END
+
+/**************************************************************************
+...
+**************************************************************************/
+#define SPECVEC_TAG building
+#define SPECVEC_TYPE Impr_Type_id
+#include "specvec.h"
+
+#define building_vector_iterate(vector, elt) \
+TYPED_VECTOR_ITERATE(Impr_Type_id, vector, elt)
+#define building_vector_iterate_end  VECTOR_ITERATE_END
+
+/**************************************************************************
+...
+**************************************************************************/
+struct eff_group {
+  char *name;
+  enum effect_type eff;
+  int id;
+  struct building_vector buildings;
+};
+
+#define SPECLIST_TAG eff_group
+#define SPECLIST_TYPE struct eff_group
+#include "speclist.h"
+
+#define eff_group_list_iterate(list, elt) \
+TYPED_LIST_ITERATE(struct eff_group, list, elt)
+#define eff_group_list_iterate_end  LIST_ITERATE_END
+
+
+/**************************************************************************
+  Effects hash. The hash is created during ruleset loading and the data
+  is organized to enable fast queries.
+**************************************************************************/
+static struct {
+  struct building_vector buildings;
+  struct eff_list buckets[B_LAST];
+
+  struct eff_group *groups[B_LAST];
+} eff_hash[EFT_LAST];
+
+struct eff_group_list groups;
+int groups_id;
+
+/**************************************************************************
+  Wrappers for access to effects hash data.
+**************************************************************************/
+static inline
+struct building_vector *get_effect_buildings(enum effect_type eff)
+{
+  return &eff_hash[eff].buildings;
+}
+
+static inline
+struct eff_list *get_building_effects(Impr_Type_id id, enum effect_type eff)
+{
+  return &eff_hash[eff].buckets[id];
+}
+
+static inline
+struct eff_group **get_building_eff_group(Impr_Type_id id,
+                                         enum effect_type eff)
+{
+  return &eff_hash[eff].groups[id];
+}
+
+
+/**************************************************************************
+...
+**************************************************************************/
+static const char *req_type_names[] = {
+  "Unknown",
+
+  "None",
+  "Tech",
+  "Gov",
+  "Building",
+  "Wonder",
+  "Special",
+  "Terrain"
+};
+
+/**************************************************************************
+...
+**************************************************************************/
+enum req_type req_type_from_str(const char *str)
+{
+  enum req_type id;
+
+  for (id = 1; id < ARRAY_SIZE(req_type_names); id++) {
+    if (0 == mystrcasecmp(req_type_names[id], str)) {
+      return id;
+    }
+  }
+
+  return REQ_UNKNOWN;
+}
+
+
+/**************************************************************************
+...
+**************************************************************************/
+struct eff_group *eff_group_new(const char *name, enum effect_type eff)
+{
+  struct eff_group *group;
+
+  group = fc_malloc(sizeof(*group));
+  group->name = mystrdup(name);
+  group->eff = eff;
+  group->id = groups_id++;
+  building_vector_init(&group->buildings);
+
+  eff_group_list_insert_back(&groups, group);
+  return group;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void eff_group_add(struct eff_group *group, const char *building)
+{
+  Impr_Type_id id;
+
+  if ((id = find_improvement_by_name(building)) != B_LAST) {
+    building_vector_append(&group->buildings, &id);
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+int find_eff_group(const char *name, enum effect_type eff)
+{
+  int i = 0;
+
+  eff_group_list_iterate(groups, pgroup) {
+    if (0 == strcasecmp(pgroup->name, name) && pgroup->eff == eff) {
+      return i;
+    }
+    i++;
+  } eff_group_list_iterate_end;
+
+  return -1;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void eff_hash_init(void)
+{
+  int i, j;
+
+  assert(ARRAY_SIZE(req_type_names) == REQ_LAST);
+
+  eff_group_list_init(&groups);
+  groups_id = 0;
+
+  for (i = 0; i < ARRAY_SIZE(eff_hash); i++) {
+    building_vector_init(get_effect_buildings(i));
+
+    for (j = 0; j < ARRAY_SIZE(eff_hash[i].groups); j++) {
+      eff_hash[i].groups[j] = NULL;
+    }
+    for (j = 0; j < ARRAY_SIZE(eff_hash[i].buckets); j++) {
+      eff_list_init(get_building_effects(j, i));
+    }
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+enum op_type parse_value(const char *str, int *value)
+{
+  const char *pch = str;
+  int num;
+  enum op_type op;
+
+  while (isspace(*pch)) {
+    pch++;
+  }
+
+  /* binary operators. the operation executed will be accum = accum OP b. */
+  switch (*pch) {
+    case '+':
+      op = OP_PLUS;
+      pch++;
+      break;
+    case '-':
+      op = OP_MINUS;
+      pch++;
+      break;
+    case '*':
+      op = OP_TIMES;
+      pch++;
+      break;
+    case '/':
+      op = OP_DIVIDE;
+      pch++;
+      break;
+    default:
+      op = OP_PLUS;
+      break;
+  }
+
+  num = 0;
+  for (; *pch != '\0'; pch++) {
+    if (isdigit(*pch)) {
+      num *= 10;
+      num += *pch - '0';
+    } else {
+      return OP_NONE;
+    }
+  }
+  *value = num;
+  return op;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+int parse_req(Impr_Type_id id, enum req_type type, const char *arg)
+{
+  bool problem;
+  int data;
+  struct government *pgov;
+
+  switch (type) {
+    case REQ_NONE:
+      problem = FALSE;
+      data = 0;
+      break;
+    case REQ_TECH:
+      problem =
+       (A_LAST == (data = find_tech_by_name(arg)));
+      break;
+    case REQ_GOV:
+       if (!(pgov = find_government_by_name(arg))) {
+         problem = TRUE;
+       } else {
+         problem = FALSE;
+         data = pgov->index;
+       }
+      break;
+    case REQ_BUILDING:
+      problem =
+       (B_LAST == (data = find_improvement_by_name(arg)));
+      break;
+    case REQ_WONDER:
+      problem =
+       (B_LAST == (data = find_improvement_by_name(arg)));
+      break;
+    case REQ_SPECIAL:
+      problem =
+       (S_NO_SPECIAL == (data = get_special_by_name(arg)));
+      break;
+    case REQ_TERRAIN:
+      problem =
+       (T_LAST == (data = get_terrain_by_name(arg)));
+      break;
+    default:
+      freelog(LOG_ERROR, "for %s: unimplemented requirement type '%d'",
+             get_improvement_name(id), type);
+      return -1;
+  }
+
+  if (problem) {
+    freelog(LOG_ERROR, "for %s: bad requirement data '%s'",
+           get_improvement_name(id), arg);
+    return -1;
+  } else {
+    return data;
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void eff_hash_add(Impr_Type_id id, enum effect_type eff,
+                 enum op_type op, int value,
+                 enum req_type req, int arg,
+                 int group)
+{
+  struct effect *peff;
+
+  peff = fc_malloc(sizeof(*peff));
+
+  peff->op = op;
+  peff->value = value;
+
+  peff->type = req;
+
+  switch (req) {
+    case REQ_NONE:
+      break;
+    case REQ_TECH:
+       peff->req.tech = arg;
+      break;
+    case REQ_GOV:
+       peff->req.gov = get_government(arg);
+      break;
+    case REQ_BUILDING:
+       peff->req.building = arg;
+      break;
+    case REQ_WONDER:
+       peff->req.wonder = arg;
+      break;
+    case REQ_SPECIAL:
+       peff->req.special = arg;
+      break;
+    case REQ_TERRAIN:
+       peff->req.terrain = arg;
+      break;
+    default:
+      freelog(LOG_ERROR, "for %s: unimplemented requirement type '%d'",
+             get_improvement_name(id), req);
+      free(peff);
+      return;
+  }
+
+  eff_list_insert_back(get_building_effects(id, eff), peff);
+
+  if (group >= 0 && group < eff_group_list_size(&groups)) {
+    *get_building_eff_group(id, eff) = eff_group_list_get(&groups, group);
+  }
+
+  {
+    struct building_vector *vec;
+    Impr_Type_id *pid;
+
+    vec = get_effect_buildings(eff);
+
+    if (!(pid = building_vector_get(vec, -1)) || *pid != id) {
+      building_vector_append(vec, &id);
+    }
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static void send_eff_hash_groups(struct conn_list *dest)
+{
+  struct packet_eff_hash_group packet;
+  int i;
+
+  eff_group_list_iterate(groups, pgroup) {
+    sz_strlcpy(packet.name, pgroup->name);
+    packet.eff = pgroup->eff;
+
+    packet.num_buildings = building_vector_size(&pgroup->buildings);
+    for (i = 0; i < packet.num_buildings; i++) {
+      Impr_Type_id *pid = building_vector_get(&pgroup->buildings, i);
+
+      packet.buildings[i] = *pid;
+    }
+
+    lsend_packet_eff_hash_group(dest, &packet);
+  } eff_group_list_iterate_end;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static void send_eff_hash_effects(struct conn_list *dest)
+{
+  struct packet_eff_hash_effect packet;
+  enum effect_type eff;
+
+  for (eff = 0; eff < EFT_LAST; eff++) {
+    packet.eff = eff;
+
+    building_vector_iterate(get_effect_buildings(eff), id) {
+      struct eff_group *pgroup;
+
+      packet.id = *id;
+
+      if ((pgroup = *get_building_eff_group(*id, eff))) {
+       packet.group = find_eff_group(pgroup->name, eff);
+      } else {
+       packet.group = -1;
+      }
+
+      eff_list_iterate(*get_building_effects(*id, eff), elt) {
+       packet.op = elt->op;
+        packet.value = elt->value;
+       packet.req = elt->type;
+
+       switch (packet.req) {
+         case REQ_NONE:
+           packet.arg = 0;
+           break;
+         case REQ_TECH:
+           packet.arg = elt->req.tech;
+           break;
+         case REQ_GOV:
+           packet.arg = (elt->req.gov ? elt->req.gov->index : -1);
+           break;
+         case REQ_BUILDING:
+           packet.arg = elt->req.building;
+           break;
+         case REQ_WONDER:
+           packet.arg = elt->req.wonder;
+           break;
+         case REQ_SPECIAL:
+           packet.arg = elt->req.special;
+           break;
+         case REQ_TERRAIN:
+           packet.arg = elt->req.terrain;
+           break;
+         default:
+           freelog(LOG_ERROR, "send_eff_hash_effects: %d", packet.req);
+           break;
+       }
+
+       lsend_packet_eff_hash_effect(dest, &packet);
+      } eff_list_iterate_end;
+    } building_vector_iterate_end;
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void send_eff_hash(struct conn_list *dest)
+{
+  send_eff_hash_groups(dest);
+  send_eff_hash_effects(dest);
+}
+
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline bool player_knows_tech(struct player *plr, Tech_Type_id tech) {
+  return (get_invention(plr, tech) == TECH_KNOWN);
+}
+
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline void operate(enum op_type op, int *accum, int value)
+{
+  switch (op) {
+    case OP_PLUS:
+      *accum += value;
+      break;
+    case OP_MINUS:
+      *accum -= value;
+      break;
+    case OP_TIMES:
+      *accum *= value;
+      break;
+    case OP_DIVIDE:
+      *accum /= value;
+      break;
+    default:
+      freelog(LOG_ERROR, "operate: %d", op);
+      break;
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline void player_power_func(struct player *plr, struct effect *eff,
+                                    int *power)
+{
+  bool active = FALSE;
+
+  switch (eff->type) {
+    case REQ_NONE:
+      active = TRUE;
+      break;
+    case REQ_TECH:
+      active = player_knows_tech(plr, eff->req.tech);
+      break;
+    case REQ_GOV:
+      active = (get_gov_pplayer(plr) == eff->req.gov);
+      break;
+    default:
+      freelog(LOG_ERROR, "player_power_func: %d", eff->type);
+      break;
+  }
+
+  if (active) {
+    operate(eff->op, power, eff->value);
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline void city_power_func(struct city *pcity, struct effect *eff,
+                                  int *power)
+{
+  bool active = FALSE;
+
+  switch (eff->type) {
+    case REQ_NONE:
+      active = TRUE;
+      break;
+    case REQ_TECH:
+      active = player_knows_tech(city_owner(pcity), eff->req.tech);
+      break;
+    case REQ_GOV:
+      active = (get_gov_pcity(pcity) == eff->req.gov);
+      break;
+    case REQ_BUILDING:
+      active = city_got_building(pcity, eff->req.building);
+      break;
+    case REQ_WONDER:
+      active = city_affected_by_wonder(pcity, eff->req.wonder);
+      break;
+    default:
+      freelog(LOG_ERROR, "city_power_func: %d", eff->type);
+      break;
+  }
+
+  if (active) {
+    operate(eff->op, power, eff->value);
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline void city_building_power_func(struct city *pcity,
+                                           Impr_Type_id id,
+                                           struct effect *eff, int *power)
+{
+  bool active = FALSE;
+
+  switch (eff->type) {
+    case REQ_NONE:
+      active = TRUE;
+      break;
+    case REQ_TECH:
+      active = player_knows_tech(city_owner(pcity), eff->req.tech);
+      break;
+    case REQ_GOV:
+      active = (get_gov_pcity(pcity) == eff->req.gov);
+      break;
+    case REQ_BUILDING:
+      active = city_got_building(pcity, eff->req.building);
+      break;
+    case REQ_WONDER:
+      active = city_affected_by_wonder(pcity, eff->req.wonder);
+      break;
+    default:
+      freelog(LOG_ERROR, "city_building_power_func: %d", eff->type);
+      break;
+  }
+
+  if (active) {
+    operate(eff->op, power, eff->value);
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline void city_tile_power_func(struct city *pcity,
+                                       struct tile *ptile,
+                                       struct effect *eff, int *power)
+{
+  bool active = FALSE;
+
+  switch (eff->type) {
+    case REQ_NONE:
+      active = TRUE;
+      break;
+    case REQ_TECH:
+      active = player_knows_tech(city_owner(pcity), eff->req.tech);
+      break;
+    case REQ_GOV:
+      active = (get_gov_pcity(pcity) == eff->req.gov);
+      break;
+    case REQ_BUILDING:
+      active = city_got_building(pcity, eff->req.building);
+      break;
+    case REQ_WONDER:
+      active = city_affected_by_wonder(pcity, eff->req.wonder);
+      break;
+    case REQ_SPECIAL:
+      active = tile_has_special(ptile, eff->req.special);
+      break;
+    case REQ_TERRAIN:
+      active = (ptile->terrain == eff->req.terrain);
+      break;
+    default:
+      freelog(LOG_ERROR, "city_tile_power_func: %d", eff->type);
+      break;
+  }
+
+  if (active) {
+    operate(eff->op, power, eff->value);
+  }
+}
+
+
+/**************************************************************************
+...
+**************************************************************************/
+static int get_player_power(struct player *plr, Impr_Type_id bldg,
+                           enum effect_type eff)
+{
+  int power = 0;
+
+  eff_list_iterate(*get_building_effects(bldg, eff), elt) {
+    player_power_func(plr, elt, &power);
+  } eff_list_iterate_end;
+
+  return power;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static int get_city_power(struct city *pcity, Impr_Type_id bldg,
+                         enum effect_type eff)
+{
+  int power = 0;
+
+  eff_list_iterate(*get_building_effects(bldg, eff), elt) {
+    city_power_func(pcity, elt, &power);
+  } eff_list_iterate_end;
+
+  return power;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static int get_city_building_power(struct city *pcity, Impr_Type_id bldg,
+                                  enum effect_type eff)
+{
+  int power = 0;
+
+  eff_list_iterate(*get_building_effects(bldg, eff), elt) {
+    city_building_power_func(pcity, bldg, elt, &power);
+  } eff_list_iterate_end;
+
+  return power;
+}
+
+
+/**************************************************************************
+...
+**************************************************************************/
+static int get_city_tile_power(struct city *pcity, struct tile *ptile,
+                              Impr_Type_id bldg, enum effect_type eff)
+{
+  int power = 0;
+
+  eff_list_iterate(*get_building_effects(bldg, eff), elt) {
+    city_tile_power_func(pcity, ptile, elt, &power);
+  } eff_list_iterate_end;
+
+  return power;
+}
+
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline bool wonder_active(Impr_Type_id id)
+{
+  return (improvement_exists(id)
+          && is_wonder(id)
+          && (!wonder_obsolete(id))
+          && game.global_wonders[id] != 0);
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static int inline active_player_everlasting_building(struct player *plr,
+                                                    Impr_Type_id id,           
                                                    enum effect_type eff)
+{
+  struct eff_group *group;
+
+  if (!(group = *get_building_eff_group(id, eff))) {
+    /* unique. */
+    if (wonder_active(id)) {
+      return id;
+    }
+
+    return -1;
+  } else {
+    /* got more than one building in the same equiv group?
+     * first in the group that exists wins. */
+    building_vector_iterate(&group->buildings, elt) {
+      if (wonder_active(*elt)) {
+       return *elt;
+      }
+    } building_vector_iterate_end;
+
+    return -1;
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+int get_player_everlasting_bonus(struct player *plr, enum effect_type eff)
+{
+  int bonus = 0;
+
+  building_vector_iterate(get_effect_buildings(eff), elt) {
+    int active;
+
+    active = active_player_everlasting_building(plr, *elt, eff);
+
+    if (active == *elt) {
+      bonus += get_player_power(plr, active, eff);
+    }
+  } building_vector_iterate_end;
+
+  return bonus;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static int inline active_player_building(struct player *plr, Impr_Type_id id,  
                                        enum effect_type eff)
+{
+  struct eff_group *group;
+
+  if (!(group = *get_building_eff_group(id, eff))) {
+    /* unique. */
+    if (player_owns_active_wonder(plr, id)) {
+      return id;
+    }
+
+    return -1;
+  } else {
+    /* got more than one building in the same equiv group?
+     * first in the group that exists wins. */
+    building_vector_iterate(&group->buildings, elt) {
+      if (player_owns_active_wonder(plr, *elt)) {
+       return *elt;
+      }
+    } building_vector_iterate_end;
+
+    return -1;
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+int get_player_bonus(struct player *plr, enum effect_type eff)
+{
+  int bonus = 0;
+
+  building_vector_iterate(get_effect_buildings(eff), elt) {
+    int active;
+
+    active = active_player_building(plr, *elt, eff);
+
+    if (active == *elt) {
+      bonus += get_player_power(plr, active, eff);
+    }
+  } building_vector_iterate_end;
+
+  return bonus;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static int inline active_city_building(struct city *pcity, Impr_Type_id id,
+                                      enum effect_type eff)
+{
+  struct eff_group *group;
+
+  if (!(group = *get_building_eff_group(id, eff))) {
+    /* unique. */
+    if (is_wonder(id)) {
+      if (city_affected_by_wonder(pcity, id)) {
+       return id;
+      }
+    } else {
+      if (city_got_building(pcity, id)) {
+       return id;
+      }
+    }
+
+    return -1;
+  } else {
+    /* got more than one building in the same equiv group?
+     * first in the group that exists wins. */
+    building_vector_iterate(&group->buildings, elt) {
+      if (is_wonder(*elt)) {
+       if (city_affected_by_wonder(pcity, *elt)) {
+         return *elt;
+       }
+      } else {
+       if (city_got_building(pcity, *elt)) {
+         return *elt;
+       }
+      }
+    } building_vector_iterate_end;
+
+    return -1;
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+int get_city_bonus(struct city *pcity, enum effect_type eff)
+{
+  int bonus = 0;
+
+  /* get bonus effect from improvements and wonders. */
+  building_vector_iterate(get_effect_buildings(eff), elt) {
+    int active;
+
+    active = active_city_building(pcity, *elt, eff);
+
+    if (active == *elt) {
+      bonus += get_city_power(pcity, active, eff);
+    }
+  } building_vector_iterate_end;
+
+  return bonus;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+int get_city_building_bonus(struct city *pcity, Impr_Type_id id,
+                           enum effect_type eff)
+{
+  int bonus = 0;
+ 
+  if (pcity) {
+    building_vector_iterate(get_effect_buildings(eff), elt) {
+      if (city_got_building(pcity, id)) {
+       bonus += get_city_building_power(pcity, id, eff);
+      }
+    } building_vector_iterate_end;
+  }
+
+  return bonus;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+int get_city_tile_bonus(struct city *pcity, struct tile *ptile,
+                       enum effect_type eff)
+{
+  int bonus = 0;
+ 
+  if (pcity) {
+    building_vector_iterate(get_effect_buildings(eff), elt) {
+      int active;
+
+      active = active_city_building(pcity, *elt, eff);
+
+      if (active == *elt) {
+       bonus += get_city_tile_power(pcity, ptile, active, eff);
+      }
+    } building_vector_iterate_end;
+  }
+
+  return bonus;
+}
diff -Nurd -X diff_ignore freecvs/common/eff.h freeciv/common/eff.h
--- freecvs/common/eff.h        1970-01-01 01:00:00.000000000 +0100
+++ freeciv/common/eff.h        2004-05-21 19:05:27.637131576 +0100
@@ -0,0 +1,60 @@
+#ifndef FC__EFF_H
+#define FC__EFF_H
+
+#include "improvement.h"
+#include "effects.h"
+
+#include "map.h"
+
+/* Effect operator type.  */
+enum op_type {
+  OP_NONE, OP_PLUS, OP_MINUS, OP_TIMES, OP_DIVIDE
+};
+
+/* Effect requirement type. */
+enum req_type {
+  REQ_UNKNOWN,
+
+  REQ_NONE,
+  REQ_TECH,
+  REQ_GOV,
+  REQ_BUILDING,
+  REQ_WONDER,
+  REQ_SPECIAL,
+  REQ_TERRAIN,
+  REQ_LAST
+};
+
+struct eff_group;
+struct conn_list;
+
+/* Effects Hash creation and communication functions. */
+void eff_hash_init(void);
+
+void eff_hash_add(Impr_Type_id id, enum effect_type eff,
+    enum op_type op, int value,
+    enum req_type req, int arg, int equiv);
+
+void send_eff_hash(struct conn_list *dest);
+
+/* Equivalent effect group. */
+struct eff_group *eff_group_new(const char *name, enum effect_type eff);
+void eff_group_add(struct eff_group *group, const char *building);
+int find_eff_group(const char *name, enum effect_type eff);
+
+/* Name string to value functions. */
+enum op_type parse_value(const char *str, int *value);
+enum req_type req_type_from_str(const char *str);
+int parse_req(Impr_Type_id id, enum req_type req, const char *arg);
+
+/* Functions to know the bonuses a certain effect is granting. */
+int get_player_everlasting_bonus(struct player *plr, enum effect_type eff);
+int get_player_bonus(struct player *plr, enum effect_type eff);
+
+int get_city_bonus(struct city *pcity, enum effect_type eff);
+int get_city_building_bonus(struct city *pcity, Impr_Type_id id,
+                           enum effect_type eff);
+int get_city_tile_bonus(struct city *city, struct tile *ptile,
+                       enum effect_type eff);
+#endif
+
diff -Nurd -X diff_ignore freecvs/common/Makefile.am freeciv/common/Makefile.am
--- freecvs/common/Makefile.am  2004-05-02 13:13:51.000000000 +0100
+++ freeciv/common/Makefile.am  2004-05-10 13:31:36.000000000 +0100
@@ -23,6 +23,8 @@
                diptreaty.h     \
                effects.c       \
                effects.h       \
+               eff.c           \
+               eff.h           \
                events.h        \
                game.c          \
                game.h          \
diff -Nurd -X diff_ignore freecvs/common/packets.def freeciv/common/packets.def
--- freecvs/common/packets.def  2004-05-21 20:28:20.507140424 +0100
+++ freeciv/common/packets.def  2004-05-21 23:34:44.599899888 +0100
@@ -174,6 +174,11 @@
 type ORDERS            = uint8(enum unit_orders)
 type SSET_TYPE         = uint8(enum sset_type)
 
+# typedefs for effects
+type EFF               = uint8(enum effect_type)
+type OP                        = uint8(enum op_type)
+type REQ               = uint8(enum req_type)
+
 # typedefs for IDs
 type PLAYER            = UINT8
 type CITY              = UINT16
@@ -1284,3 +1289,24 @@
 
   UINT8 category;                              /* which category this is in */
 end
+
+/************** Effects hash packets **********************/
+
+PACKET_EFF_HASH_GROUP=120;sc,lsend
+  STRING name[MAX_LEN_NAME];
+  EFF eff;
+
+  UINT8 num_buildings;
+  IMPROVEMENT buildings[255:num_buildings];
+end
+
+PACKET_EFF_HASH_EFFECT=121;sc,lsend
+  IMPROVEMENT id;
+  EFF eff;
+  OP op;
+  SINT32 value;
+  REQ req;
+  SINT32 arg;
+  SINT32 group;
+end
+
diff -Nurd -X diff_ignore freecvs/common/packets.h freeciv/common/packets.h
--- freecvs/common/packets.h    2004-01-14 11:58:12.000000000 +0000
+++ freeciv/common/packets.h    2004-05-16 01:21:39.000000000 +0100
@@ -26,6 +26,7 @@
 #include "spaceship.h"
 #include "unittype.h"
 #include "worklist.h"
+#include "eff.h"
 
 
 #define MAX_LEN_USERNAME        10        /* see below */
diff -Nurd -X diff_ignore freecvs/common/unit.c freeciv/common/unit.c
--- freecvs/common/unit.c       2004-05-19 21:14:58.000000000 +0100
+++ freeciv/common/unit.c       2004-05-19 21:07:06.000000000 +0100
@@ -18,6 +18,7 @@
 #include <assert.h>
 
 #include "fcintl.h"
+#include "eff.h"
 #include "game.h"
 #include "log.h"
 #include "map.h"
@@ -53,15 +54,8 @@
   case SEA_MOVING:
     move_rate = (base_move_rate * punit->hp) / unit_type(punit)->hp;
 
-    if (player_owns_active_wonder(unit_owner(punit), B_LIGHTHOUSE)) {
-      move_rate += SINGLE_MOVE;
-    }
- 
-    if (player_owns_active_wonder(unit_owner(punit), B_MAGELLAN)) {
-      move_rate += (improvement_variant(B_MAGELLAN) == 1) 
-                     ? SINGLE_MOVE : 2 * SINGLE_MOVE;
-    }
- 
+    move_rate += get_player_bonus(unit_owner(punit), EFT_UNIT_MOVE) * 
SINGLE_MOVE;
+
     if (player_knows_techs_with_flag(unit_owner(punit), TF_BOAT_FAST)) {
       move_rate += SINGLE_MOVE;
     }
diff -Nurd -X diff_ignore freecvs/data/default/buildings.ruleset 
freeciv/data/default/buildings.ruleset
--- freecvs/data/default/buildings.ruleset      2004-05-13 19:17:37.000000000 
+0100
+++ freeciv/data/default/buildings.ruleset      2004-05-20 01:20:09.000000000 
+0100
@@ -69,8 +69,42 @@
 ; helptext     = optional help text string; should escape all raw
 ;                newlines so that xgettext parsing works
 ;
+; affect {     = list of effects; parameters are:
+;   eff                = effect name; e.g. "Tax_Bonus"
+;   value       = modifier value of effect; by ommission "+1".
+;                it is possible to use several operators: +, -, *, /.
+;   type        = requirement type; one of:
+;                "None", "Tech", "Gov", "Building", "Wonder", "Special",
+;                "Terrain".
+;   req                = requirement data; varies with requirement type.
+;
+; }              the effects in the list are cumulative.
+;
 ; */ <-- avoid gettext warnings
 
+;
+; Effect groups are a convenience mechanism to handle
+; equivalent effects which may be done by one of several buildings.
+; The first building in the 'buildings' list of the group which
+; exists wins.
+;
+
+[group_cathedrals]
+name           = "Cathedrals"
+eff            = "Make_Content"
+buildings      = "Michelangelo's Chapel", "Cathedral" 
+
+[group_labs]
+name           = "Labs"
+eff            = "Science_Bonus"
+buildings      = "SETI Program", "Research Lab" 
+
+[group_generators]
+name           = "Generators"
+eff            = "Prod_Bonus"
+buildings      = "Hoover Dam", "Nuclear Plant", "Hydro Plant",
+                 "Power Plant"
+
 [building_airport]
 name           = _("Airport")
 tech_req       = "Radio"
@@ -152,6 +186,11 @@
 build_cost     = 80
 upkeep         = 2
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+      "Tax_Bonus", "50", "Building", "Marketplace"
+      "Luxury_Bonus", "50", "Building", "Marketplace"
+    }
 effect         =
     { "type", "range", "amount", "cond_bldg"
        "Tax_Bonus", "City", 50, "Marketplace"
@@ -274,6 +313,12 @@
 build_cost     = 80
 upkeep         = 3
 sabotage       = 100
++affect                =
+    { "eff", "value", "equiv", "type", "req"
+      "Make_Content", "3", "Cathedrals"
+      "Make_Content", "1", "Cathedrals", "Tech", "Theology"
+      "Make_Content", "-1", "Cathedrals", "Tech", "Communism"
+    }
 effect         =
     { "type", "range", "amount", "cond_adv"
        "Make_Content", "City", 3
@@ -367,6 +412,11 @@
 build_cost     = 70
 upkeep         = 4
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+      "Make_Content", "3"
+      "Make_Content", "1", "Tech", "Electricity"
+    }
 effect         =
     { "type", "range", "amount", "cond_adv"
        "Make_Content", "City", 3
@@ -397,6 +447,12 @@
 build_cost     = 60
 upkeep         = 1
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+       "Corrupt_Pct", "50"
+       "Make_Content", "1", "Gov", "Democracy"
+       "Revolt_Dist_Pct", "50"
+    }
 effect         =
     { "type", "range", "amount", "cond_gov"
        "Corrupt_Pct", "City", 50
@@ -428,6 +484,10 @@
 build_cost     = 140
 upkeep         = 4
 sabotage       = 100
+affect         =
+    { "eff", "value"
+      "Prod_Bonus", "50"
+    }
 effect         =
     { "type", "range", "amount"
        "Prod_Bonus", "City", 50
@@ -486,6 +546,10 @@
 build_cost     = 40
 upkeep         = 1
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+       "Food_Add_Tile", "1", "Terrain", "Ocean"
+    }
 effect         =
     { "type", "range", "amount", "aff_terr", "aff_spec"
        "Food_Add_Tile", "City", 1, "Ocean", "None"
@@ -556,6 +620,10 @@
 build_cost     = 60
 upkeep         = 1
 sabotage       = 100
+affect         =
+    { "eff", "value"
+      "Science_Bonus", "50"
+    }
 effect         =
     { "type", "range", "amount"
        "Science_Bonus", "City", 50
@@ -583,6 +651,11 @@
 build_cost     = 60
 upkeep         = 0
 sabotage       = 100
+affect         =
+    { "eff", "value"
+      "Tax_Bonus", "50"
+      "Luxury_Bonus", "50"
+    }
 effect         =
     { "type", "range", "amount"
        "Tax_Bonus", "City", 50
@@ -611,6 +684,10 @@
 build_cost     = 120
 upkeep         = 4
 sabotage       = 100
+affect         =
+    { "eff", "value"
+      "Pollu_Pop_Pct", "100"
+    }
 effect         =
     { "type", "range", "amount"
        "Pollu_Pop_Pct", "City", 0
@@ -639,6 +716,10 @@
 build_cost     = 220
 upkeep         = 6
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+      "Prod_Bonus", "50", "Building", "Factory"
+    }
 effect         =
     { "type", "range", "amount", "cond_bldg"
        "Prod_Bonus", "City", 50, "Factory"
@@ -667,6 +748,11 @@
 build_cost     = 120
 upkeep         = 2
 sabotage       = 100
+affect         =
+    { "eff", "value", "equiv", "type", "req"
+      "Prod_Bonus", "25", "Generators", "Building", "Factory"
+      "Prod_Bonus", "25", "Generators", "Building", "Mfg. Plant"
+    }
 effect         =
     { "type", "range", "amount", "cond_bldg"
        "Prod_Bonus", "City", 25, "Factory"
@@ -711,6 +797,10 @@
 build_cost     = 120
 upkeep         = 3
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+       "Prod_Add_Tile", "1", "Terrain", "Ocean"
+    }
 effect         =
     { "type", "range", "amount", "aff_terr", "aff_spec"
        "Prod_Add_Tile", "City", 1, "Ocean", "None"
@@ -836,6 +926,11 @@
 build_cost     = 130
 upkeep         = 4
 sabotage       = 100
+affect         =
+    { "eff", "value", "equiv", "type", "req"
+      "Prod_Bonus", "25", "Generators", "Building", "Factory"
+      "Prod_Bonus", "25", "Generators", "Building", "Mfg. Plant"
+    }
 effect         =
     { "type", "range", "amount", "cond_bldg"
        "Prod_Bonus", "City", 25, "Factory"
@@ -902,6 +997,10 @@
 build_cost     = 120
 upkeep         = 3
 sabotage       = 100
+affect         =
+    { "eff", "value", "equiv", "type", "req"
+       "Science_Bonus", "50", "Labs", "Building", "Library"
+    }
 effect         =
     { "type", "range", "amount", "cond_bldg"
        "Science_Bonus", "City", 50, "Library"
@@ -1165,6 +1264,11 @@
 build_cost     = 120
 upkeep         = 3
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+      "Tax_Bonus", "50", "Building", "Bank"
+      "Luxury_Bonus", "50", "Building", "Bank"
+    }
 effect         =
     { "type", "range", "amount", "cond_bldg"
        "Tax_Bonus", "City", 50, "Bank"
@@ -1194,6 +1298,10 @@
 build_cost     = 120
 upkeep         = 3
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+       "Trade_Per_Tile", "50", "Special", "Road"
+    }
 effect         =
     { "type", "range", "amount", "aff_terr", "aff_spec"
        "Trade_Per_Tile", "City", 50, "None", "Road"
@@ -1224,6 +1332,10 @@
 build_cost     = 80
 upkeep         = 3
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+       "Food_Per_Tile", "50", "Special", "Farmland"
+    }
 effect         =
     { "type", "range", "amount", "aff_terr", "aff_spec"
        "Food_Per_Tile", "City", 50, "None", "Farmland"
@@ -1253,6 +1365,12 @@
 build_cost     = 30
 upkeep         = 1
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+      "Make_Content", "1"
+      "Make_Content", "1", "Tech", "Mysticism"
+      "Make_Content", "*2", "Wonder", "Oracle"
+    }
 effect         =
     { "type", "range", "amount", "cond_adv"
        "Make_Content", "City", 1
@@ -1282,6 +1400,10 @@
 build_cost     = 120
 upkeep         = 3
 sabotage       = 100
+affect         =
+    { "eff", "value", "type", "req"
+      "Science_Bonus", "50", "Building", "Library"
+    }
 effect         =
     { "type", "range", "amount", "cond_bldg"
        "Science_Bonus", "City", 50, "Library"
@@ -1339,6 +1461,10 @@
 build_cost     = 400
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value"
+      "Upkeep_Free", "1"
+    }
 effect         =
     { "type", "range", "amount"
        "Upkeep_Free", "Player", 1
@@ -1366,6 +1492,10 @@
 build_cost     = 100
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value"
+      "Trade_Inc_Tile", "1"
+    }
 effect         =
     { "type", "range", "amount"
        "Trade_Inc_Tile", "City", 1
@@ -1393,6 +1523,10 @@
 build_cost     = 200
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value"
+      "Science_Bonus", "50"
+    }
 effect         =
     { "type", "range", "amount"
        "Science_Bonus", "City", 50
@@ -1420,6 +1554,10 @@
 build_cost     = 600
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value"
+      "Force_Content", "1"
+    }
 effect         =
     { "type", "range", "amount"
        "Make_Content", "Player", 1
@@ -1507,6 +1645,10 @@
 build_cost     = 300
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value"
+      "Adv_Parasite", "2"
+    }
 effect         =
     { "type", "range", "amount"
        "Adv_Parasite", "Player", 2
@@ -1564,6 +1706,11 @@
 build_cost     = 200
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value", "type", "req"
+      "Make_Happy", "1"
+      "Make_Happy", "2", "Building", "Hanging Gardens"
+    }
 effect         =
     { "type", "range", "amount"
        "Make_Happy", "Player", 1
@@ -1595,6 +1742,11 @@
 build_cost     = 600
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value", "equiv", "type", "req"
+      "Prod_Bonus", "25", "Generators", "Building", "Factory"
+      "Prod_Bonus", "25", "Generators", "Building", "Mfg. Plant"
+    }
 effect         =
     { "type", "range", "amount", "cond_bldg"
        "Prod_Bonus", "Player", 25, "Factory"
@@ -1625,6 +1777,10 @@
 build_cost     = 300
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value"
+      "Science_Bonus", "100"
+    }
 effect         =
     { "type", "range", "amount"
        "Science_Bonus", "City", 100
@@ -1652,6 +1808,10 @@
 build_cost     = 400
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value"
+      "Force_Content", "2"
+    }
 effect         =
     { "type", "range", "amount"
        "Make_Content", "Player", 2
@@ -1678,6 +1838,10 @@
 build_cost     = 150
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value"
+       "Prod_Add_Tile", "1"
+    }
 effect         =
     { "type", "range", "amount"
        "Prod_Add_Tile", "City", 1
@@ -1697,7 +1861,7 @@
 graphic_alt    = "-"
 ;terr_gate     =
 ;spec_gate     =
-equiv_range    = "Player"
+equiv_range    = "None"
 ;equiv_dupl    =
 ;equiv_repl    =
 obsolete_by    = "Automobile"
@@ -1731,6 +1895,10 @@
 build_cost     = 200
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value"
+      "Unit_Move", "1"
+    }
 effect         =
     { "type", "range", "amount", "aff_unit"
        "Unit_Move", "Player", 1, "Sea"
@@ -1753,7 +1921,7 @@
 graphic_alt    = "-"
 ;terr_gate     =
 ;spec_gate     =
-equiv_range    = "Player"
+equiv_range    = "None"
 ;equiv_dupl    =
 ;equiv_repl    =
 obsolete_by    = "None"
@@ -1761,6 +1929,10 @@
 build_cost     = 400
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value"
+      "Unit_Move", "2"
+    }
 effect         =
     { "type", "range", "amount", "aff_unit"
        "Unit_Move", "Player", 2, "Sea"
@@ -1838,6 +2010,12 @@
 build_cost     = 400
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value", "equiv", "type", "req"
+      "Make_Content", "3", "Cathedrals"
+      "Make_Content", "1", "Cathedrals", "Tech", "Theology"
+      "Make_Content", "-1", "Cathedrals", "Tech", "Communism"
+    }
 effect         =
     { "type", "range", "amount", "cond_adv"
        "Make_Content", "Player", 3
@@ -1924,6 +2102,10 @@
 build_cost     = 600
 upkeep         = 0
 sabotage       = 0
+affect         =
+    { "eff", "value", "equiv", "type", "req"
+       "Science_Bonus", "50", "Labs", "Building", "Library"
+    }
 effect         =
     { "type", "range", "amount", "cond_bldg"
        "Science_Bonus", "Player", 50, "Library"
diff -Nurd -X diff_ignore freecvs/server/plrhand.c freeciv/server/plrhand.c
--- freecvs/server/plrhand.c    2004-05-11 18:59:34.000000000 +0100
+++ freeciv/server/plrhand.c    2004-05-16 18:15:52.000000000 +0100
@@ -19,6 +19,7 @@
 #include <stdarg.h>
 
 #include "diptreaty.h"
+#include "eff.h"
 #include "events.h"
 #include "fcintl.h"
 #include "government.h"
@@ -128,31 +129,29 @@
 **************************************************************************/
 void great_library(struct player *pplayer)
 {
-  if (wonder_obsolete(B_GREAT)) 
-    return;
-  if (find_city_wonder(B_GREAT)) {
-    if (pplayer->player_no==find_city_wonder(B_GREAT)->owner) {
-      tech_type_iterate(i) {
-       if (get_invention(pplayer, i) != TECH_KNOWN
-           && tech_is_available(pplayer, i)
-           && game.global_advances[i]>=2) {
-         notify_player_ex(pplayer, -1, -1, E_TECH_GAIN,
-                          _("Game: %s acquired from The Great Library!"),
-                          advances[i].name);
-         gamelog(GAMELOG_TECH, _("%s discover %s (Library)"),
-                 get_nation_name_plural(pplayer->nation), advances[i].name);
-         notify_embassies(pplayer, NULL,
-                          _("Game: The %s have acquired %s"
-                            " from the Great Library."),
-                          get_nation_name_plural(pplayer->nation),
-                          advances[i].name);
+  int mod;
 
-         do_free_cost(pplayer);
-         found_new_tech(pplayer, i, FALSE, FALSE, A_NONE);
-         break;
-       }
-      } tech_type_iterate_end;
-    }
+  if ((mod = get_player_bonus(pplayer, EFT_ADV_PARASITE)) > 0) {
+    tech_type_iterate(i) {
+      if (get_invention(pplayer, i) != TECH_KNOWN
+         && tech_is_available(pplayer, i)
+         && game.global_advances[i] >= mod) {
+       notify_player_ex(pplayer, -1, -1, E_TECH_GAIN,
+           _("Game: %s acquired from The Great Library!"),
+           advances[i].name);
+       gamelog(GAMELOG_TECH, _("%s discover %s (Library)"),
+           get_nation_name_plural(pplayer->nation), advances[i].name);
+       notify_embassies(pplayer, NULL,
+           _("Game: The %s have acquired %s"
+             " from the Great Library."),
+           get_nation_name_plural(pplayer->nation),
+           advances[i].name);
+
+       do_free_cost(pplayer);
+       found_new_tech(pplayer, i, FALSE, FALSE, A_NONE);
+       break;
+      }
+    } tech_type_iterate_end;
   }
 }
 
diff -Nurd -X diff_ignore freecvs/server/ruleset.c freeciv/server/ruleset.c
--- freecvs/server/ruleset.c    2004-05-21 20:28:22.423849040 +0100
+++ freeciv/server/ruleset.c    2004-05-21 23:34:47.866403304 +0100
@@ -42,6 +42,8 @@
 
 #include "ruleset.h"
 
+#include "eff.h"
+
 static const char name_too_long[] = "Name \"%s\" too long; truncating.";
 #define check_name(name) (check_strlen(name, MAX_LEN_NAME, name_too_long))
 #define name_strlcpy(dst, src) ((void) sz_loud_strlcpy(dst, src, 
name_too_long))
@@ -1109,6 +1111,8 @@
     improvement_types[i].name_orig[0] = 0;
   } impr_type_iterate_end;
 
+  eff_hash_init();
+
   free(sec);
 }
 
@@ -1126,6 +1130,32 @@
 
   (void) check_ruleset_capabilities(file, "+1.10.1", filename);
 
+  /* Parse effect equivalence building groups. */
+  sec = secfile_get_secnames_prefix(file, "group_", &nval);
+  for (i = 0; i < nval; i++) {
+    struct eff_group *group;
+    enum effect_type eff;
+    char name[MAX_LEN_NAME];
+
+    item = secfile_lookup_str(file, "%s.name", sec[i]);
+    sz_strlcpy(name, item);
+
+    item = secfile_lookup_str(file, "%s.eff", sec[i]);
+    if ((eff = effect_type_from_str(item)) == IR_LAST) {
+      freelog(LOG_ERROR, "for group %s unknown effect type: \"%s\" (%s)",
+             name, item, filename);
+      continue;
+    }
+    group = eff_group_new(name, eff);
+
+    list = secfile_lookup_str_vec(file, &count, "%s.buildings", sec[i]);
+    for (j = 0; j < count; j++) {
+      eff_group_add(group, list[j]);
+    }
+    free(list);
+  }
+  free(sec);
+
   sec = secfile_get_secnames_prefix(file, "building_", &nval);
 
   for (i = 0; i < nval; i++) {
@@ -1387,6 +1417,77 @@
     }
     b->effect[k].type = EFT_LAST;
 
+    /* Parse building effects and add them to the effects hash. */
+    {
+      for (j = 0;
+         (item = secfile_lookup_str_default(file, NULL, "%s.affect%d.eff",
+                                           sec[i], j));
+         j++) {
+       enum op_type op;
+       int value;
+       enum effect_type eff;
+       enum req_type type;
+       int req, equiv;
+
+       if ((eff = effect_type_from_str(item)) == IR_LAST) {
+         freelog(LOG_ERROR, "for %s unknown effect type: \"%s\" (%s)",
+                 b->name, item, filename);
+         continue;
+       }
+
+       item = secfile_lookup_str_default(file, NULL, "%s.affect%d.value",
+                                         sec[i], j);
+       if (item) {
+         if ((op = parse_value(item, &value)) == OP_NONE) {
+           freelog(LOG_ERROR, "for %s bad value: \"%s\" (%s)",
+                   b->name, item, filename);
+           continue;
+         }
+       } else {
+         op = OP_PLUS;
+         value = 1;
+       }
+
+       item = secfile_lookup_str_default(file, NULL, "%s.affect%d.equiv",
+                                         sec[i], j);
+       if (item) {
+         if ((equiv = find_eff_group(item, eff)) == -1) {
+           freelog(LOG_ERROR, "for %s bad group: \"%s\" (%s)",
+                   b->name, item, filename);
+           continue;
+         }
+       } else {
+         equiv = -1;
+       }
+
+       item = secfile_lookup_str_default(file, NULL, "%s.affect%d.type",
+                                         sec[i], j);
+       if (item) {
+         if ((type = req_type_from_str(item)) == REQ_UNKNOWN) {
+           freelog(LOG_ERROR, "for %s unknown requirement type: \"%s\" (%s)",
+                   b->name, item, filename);
+           continue;
+          }
+
+         item = secfile_lookup_str_default(file, NULL, "%s.affect%d.req",
+                                           sec[i], j);
+
+         if (!item) {
+           freelog(LOG_ERROR, "for %s missing requirement data (%s)",
+               b->name, filename);
+           continue;
+         } else {
+           req = parse_req(i, type, item);
+         }
+        } else {
+          type = REQ_NONE;
+          req = 0;
+        }
+
+       eff_hash_add(i, eff, op, value, type, req, equiv);
+      }
+    }
+
     /* FIXME: remove when gen-impr obsoletes */
     b->variant = secfile_lookup_int_default(file, 0, "%s.variant", sec[i]);
     
@@ -3193,6 +3294,9 @@
   send_ruleset_nations(dest);
   send_ruleset_cities(dest);
 
+  send_eff_hash(dest);
+
   lsend_packet_thaw_hint(dest);
   conn_list_do_unbuffer(dest);
 }
+

[Prev in Thread] Current Thread [Next in Thread]